summaryrefslogtreecommitdiffstats
path: root/sd/source
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sd/source
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sd/source')
-rw-r--r--sd/source/core/CustomAnimationCloner.cxx307
-rw-r--r--sd/source/core/CustomAnimationEffect.cxx3559
-rw-r--r--sd/source/core/CustomAnimationPreset.cxx514
-rw-r--r--sd/source/core/EffectMigration.cxx1439
-rw-r--r--sd/source/core/PageListWatcher.cxx217
-rw-r--r--sd/source/core/PageListWatcher.hxx87
-rw-r--r--sd/source/core/TransitionPreset.cxx385
-rw-r--r--sd/source/core/anminfo.cxx128
-rw-r--r--sd/source/core/annotations/Annotation.cxx480
-rw-r--r--sd/source/core/annotations/AnnotationEnumeration.cxx85
-rw-r--r--sd/source/core/cusshow.cxx101
-rw-r--r--sd/source/core/drawdoc.cxx1206
-rw-r--r--sd/source/core/drawdoc2.cxx1382
-rw-r--r--sd/source/core/drawdoc3.cxx1873
-rw-r--r--sd/source/core/drawdoc4.cxx1399
-rw-r--r--sd/source/core/drawdoc_animations.cxx54
-rw-r--r--sd/source/core/pglink.cxx128
-rw-r--r--sd/source/core/sdiocmpt.cxx117
-rw-r--r--sd/source/core/sdpage.cxx3157
-rw-r--r--sd/source/core/sdpage2.cxx651
-rw-r--r--sd/source/core/sdpage_animations.cxx160
-rw-r--r--sd/source/core/shapelist.cxx140
-rw-r--r--sd/source/core/stlfamily.cxx513
-rw-r--r--sd/source/core/stlpool.cxx1395
-rw-r--r--sd/source/core/stlsheet.cxx1459
-rw-r--r--sd/source/core/text/textapi.cxx278
-rw-r--r--sd/source/core/typemap.cxx143
-rw-r--r--sd/source/core/undo/undofactory.cxx55
-rw-r--r--sd/source/core/undo/undomanager.cxx58
-rw-r--r--sd/source/core/undo/undoobjects.cxx392
-rw-r--r--sd/source/core/undoanim.cxx280
-rw-r--r--sd/source/filter/cgm/sdcgmfilter.cxx137
-rw-r--r--sd/source/filter/eppt/eppt.cxx1464
-rw-r--r--sd/source/filter/eppt/eppt.hxx232
-rw-r--r--sd/source/filter/eppt/epptbase.hxx412
-rw-r--r--sd/source/filter/eppt/epptdef.hxx145
-rw-r--r--sd/source/filter/eppt/epptooxml.hxx189
-rw-r--r--sd/source/filter/eppt/epptso.cxx3361
-rw-r--r--sd/source/filter/eppt/escherex.cxx266
-rw-r--r--sd/source/filter/eppt/escherex.hxx64
-rw-r--r--sd/source/filter/eppt/grouptable.hxx69
-rw-r--r--sd/source/filter/eppt/pptexanimations.cxx2150
-rw-r--r--sd/source/filter/eppt/pptexanimations.hxx134
-rw-r--r--sd/source/filter/eppt/pptexsoundcollection.cxx213
-rw-r--r--sd/source/filter/eppt/pptexsoundcollection.hxx71
-rw-r--r--sd/source/filter/eppt/pptx-animations.cxx1539
-rw-r--r--sd/source/filter/eppt/pptx-animations.hxx25
-rw-r--r--sd/source/filter/eppt/pptx-epptbase.cxx1000
-rw-r--r--sd/source/filter/eppt/pptx-epptooxml.cxx2594
-rw-r--r--sd/source/filter/eppt/pptx-grouptable.cxx85
-rw-r--r--sd/source/filter/eppt/pptx-stylesheet.cxx489
-rw-r--r--sd/source/filter/eppt/pptx-text.cxx1400
-rw-r--r--sd/source/filter/eppt/text.hxx254
-rw-r--r--sd/source/filter/grf/sdgrffilter.cxx304
-rw-r--r--sd/source/filter/html/HtmlOptionsDialog.cxx203
-rw-r--r--sd/source/filter/html/buttonset.cxx290
-rw-r--r--sd/source/filter/html/buttonset.hxx46
-rw-r--r--sd/source/filter/html/htmlattr.cxx72
-rw-r--r--sd/source/filter/html/htmlattr.hxx40
-rw-r--r--sd/source/filter/html/htmlex.cxx3186
-rw-r--r--sd/source/filter/html/htmlex.hxx237
-rw-r--r--sd/source/filter/html/htmlpublishmode.hxx31
-rw-r--r--sd/source/filter/html/pubdlg.cxx1539
-rw-r--r--sd/source/filter/html/sdhtmlfilter.cxx51
-rw-r--r--sd/source/filter/pdf/sdpdffilter.cxx201
-rw-r--r--sd/source/filter/ppt/ppt97animations.cxx682
-rw-r--r--sd/source/filter/ppt/ppt97animations.hxx156
-rw-r--r--sd/source/filter/ppt/pptanimations.hxx209
-rw-r--r--sd/source/filter/ppt/pptatom.cxx104
-rw-r--r--sd/source/filter/ppt/pptatom.hxx106
-rw-r--r--sd/source/filter/ppt/pptin.cxx2821
-rw-r--r--sd/source/filter/ppt/pptin.hxx92
-rw-r--r--sd/source/filter/ppt/pptinanimations.cxx3294
-rw-r--r--sd/source/filter/ppt/pptinanimations.hxx115
-rw-r--r--sd/source/filter/ppt/propread.cxx615
-rw-r--r--sd/source/filter/ppt/propread.hxx151
-rw-r--r--sd/source/filter/sdfilter.cxx108
-rw-r--r--sd/source/filter/sdpptwrp.cxx377
-rw-r--r--sd/source/filter/xml/sdtransform.cxx368
-rw-r--r--sd/source/filter/xml/sdtransform.hxx28
-rw-r--r--sd/source/filter/xml/sdxmlwrp.cxx1056
-rw-r--r--sd/source/helper/simplereferencecomponent.cxx72
-rw-r--r--sd/source/ui/accessibility/AccessibleDocumentViewBase.cxx773
-rw-r--r--sd/source/ui/accessibility/AccessibleDrawDocumentView.cxx777
-rw-r--r--sd/source/ui/accessibility/AccessibleOutlineEditSource.cxx199
-rw-r--r--sd/source/ui/accessibility/AccessibleOutlineView.cxx238
-rw-r--r--sd/source/ui/accessibility/AccessiblePageShape.cxx261
-rw-r--r--sd/source/ui/accessibility/AccessiblePresentationGraphicShape.cxx76
-rw-r--r--sd/source/ui/accessibility/AccessiblePresentationOLEShape.cxx84
-rw-r--r--sd/source/ui/accessibility/AccessiblePresentationShape.cxx146
-rw-r--r--sd/source/ui/accessibility/AccessibleSlideSorterObject.cxx429
-rw-r--r--sd/source/ui/accessibility/AccessibleSlideSorterView.cxx950
-rw-r--r--sd/source/ui/accessibility/AccessibleViewForwarder.cxx104
-rw-r--r--sd/source/ui/accessibility/SdShapeTypes.cxx132
-rw-r--r--sd/source/ui/animations/CustomAnimationDialog.cxx2090
-rw-r--r--sd/source/ui/animations/CustomAnimationDialog.hxx141
-rw-r--r--sd/source/ui/animations/CustomAnimationList.cxx1231
-rw-r--r--sd/source/ui/animations/CustomAnimationPane.cxx2578
-rw-r--r--sd/source/ui/animations/STLPropertySet.cxx113
-rw-r--r--sd/source/ui/animations/STLPropertySet.hxx73
-rw-r--r--sd/source/ui/animations/SlideTransitionPane.cxx1155
-rw-r--r--sd/source/ui/animations/motionpathtag.cxx1200
-rw-r--r--sd/source/ui/animations/motionpathtag.hxx114
-rw-r--r--sd/source/ui/annotations/annotationmanager.cxx1220
-rw-r--r--sd/source/ui/annotations/annotationmanagerimpl.hxx141
-rw-r--r--sd/source/ui/annotations/annotationtag.cxx662
-rw-r--r--sd/source/ui/annotations/annotationtag.hxx89
-rw-r--r--sd/source/ui/annotations/annotationwindow.cxx802
-rw-r--r--sd/source/ui/annotations/annotationwindow.hxx143
-rw-r--r--sd/source/ui/app/optsitem.cxx1407
-rw-r--r--sd/source/ui/app/scalectrl.cxx108
-rw-r--r--sd/source/ui/app/sddll.cxx269
-rw-r--r--sd/source/ui/app/sdmod.cxx216
-rw-r--r--sd/source/ui/app/sdmod1.cxx638
-rw-r--r--sd/source/ui/app/sdmod2.cxx809
-rw-r--r--sd/source/ui/app/sdpopup.cxx318
-rw-r--r--sd/source/ui/app/sdxfer.cxx807
-rw-r--r--sd/source/ui/app/tmplctrl.cxx110
-rw-r--r--sd/source/ui/controller/displaymodecontroller.cxx264
-rw-r--r--sd/source/ui/controller/slidelayoutcontroller.cxx380
-rw-r--r--sd/source/ui/controller/slidelayoutcontroller.hxx47
-rw-r--r--sd/source/ui/dlg/AnimationChildWindow.cxx50
-rw-r--r--sd/source/ui/dlg/BulletAndPositionDlg.cxx1293
-rw-r--r--sd/source/ui/dlg/LayerTabBar.cxx437
-rw-r--r--sd/source/ui/dlg/NavigatorChildWindow.cxx100
-rw-r--r--sd/source/ui/dlg/PaneChildWindows.cxx107
-rw-r--r--sd/source/ui/dlg/PaneDockingWindow.cxx127
-rw-r--r--sd/source/ui/dlg/PaneShells.cxx79
-rw-r--r--sd/source/ui/dlg/PhotoAlbumDialog.cxx775
-rw-r--r--sd/source/ui/dlg/PhotoAlbumDialog.hxx91
-rw-r--r--sd/source/ui/dlg/RemoteDialog.cxx49
-rw-r--r--sd/source/ui/dlg/RemoteDialog.hxx32
-rw-r--r--sd/source/ui/dlg/RemoteDialogClientBox.cxx134
-rw-r--r--sd/source/ui/dlg/RemoteDialogClientBox.hxx85
-rw-r--r--sd/source/ui/dlg/SpellDialogChildWindow.cxx172
-rw-r--r--sd/source/ui/dlg/TemplateScanner.cxx342
-rw-r--r--sd/source/ui/dlg/animobjs.cxx1134
-rw-r--r--sd/source/ui/dlg/assclass.cxx160
-rw-r--r--sd/source/ui/dlg/brkdlg.cxx156
-rw-r--r--sd/source/ui/dlg/copydlg.cxx263
-rw-r--r--sd/source/ui/dlg/custsdlg.cxx478
-rw-r--r--sd/source/ui/dlg/diactrl.cxx185
-rw-r--r--sd/source/ui/dlg/dlgchar.cxx70
-rw-r--r--sd/source/ui/dlg/dlgfield.cxx301
-rw-r--r--sd/source/ui/dlg/dlgolbul.cxx172
-rw-r--r--sd/source/ui/dlg/dlgpage.cxx116
-rw-r--r--sd/source/ui/dlg/dlgsnap.cxx185
-rw-r--r--sd/source/ui/dlg/filedlg.cxx267
-rw-r--r--sd/source/ui/dlg/gluectrl.cxx200
-rw-r--r--sd/source/ui/dlg/headerfooterdlg.cxx759
-rw-r--r--sd/source/ui/dlg/ins_paste.cxx34
-rw-r--r--sd/source/ui/dlg/inspagob.cxx126
-rw-r--r--sd/source/ui/dlg/layeroptionsdlg.cxx62
-rw-r--r--sd/source/ui/dlg/masterlayoutdlg.cxx133
-rw-r--r--sd/source/ui/dlg/morphdlg.cxx107
-rw-r--r--sd/source/ui/dlg/navigatr.cxx735
-rw-r--r--sd/source/ui/dlg/paragr.cxx169
-rw-r--r--sd/source/ui/dlg/present.cxx323
-rw-r--r--sd/source/ui/dlg/prltempl.cxx305
-rw-r--r--sd/source/ui/dlg/prntopts.cxx235
-rw-r--r--sd/source/ui/dlg/sdabstdlg.cxx55
-rw-r--r--sd/source/ui/dlg/sddlgfact.cxx739
-rw-r--r--sd/source/ui/dlg/sddlgfact.hxx448
-rw-r--r--sd/source/ui/dlg/sdpreslt.cxx267
-rw-r--r--sd/source/ui/dlg/sdtreelb.cxx1206
-rw-r--r--sd/source/ui/dlg/sduiexp.cxx33
-rw-r--r--sd/source/ui/dlg/tabtempl.cxx160
-rw-r--r--sd/source/ui/dlg/titledockwin.cxx261
-rw-r--r--sd/source/ui/dlg/tpaction.cxx801
-rw-r--r--sd/source/ui/dlg/tpoption.cxx618
-rw-r--r--sd/source/ui/dlg/unchss.cxx119
-rw-r--r--sd/source/ui/dlg/vectdlg.cxx336
-rw-r--r--sd/source/ui/docshell/docshel2.cxx416
-rw-r--r--sd/source/ui/docshell/docshel3.cxx443
-rw-r--r--sd/source/ui/docshell/docshel4.cxx1002
-rw-r--r--sd/source/ui/docshell/docshell.cxx515
-rw-r--r--sd/source/ui/docshell/grdocsh.cxx61
-rw-r--r--sd/source/ui/docshell/sdclient.cxx184
-rw-r--r--sd/source/ui/framework/configuration/ChangeRequestQueue.cxx28
-rw-r--r--sd/source/ui/framework/configuration/ChangeRequestQueue.hxx48
-rw-r--r--sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx180
-rw-r--r--sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx126
-rw-r--r--sd/source/ui/framework/configuration/Configuration.cxx311
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationClassifier.cxx167
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationClassifier.hxx165
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationController.cxx541
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx192
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx138
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx303
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx141
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationTracer.cxx73
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationTracer.hxx58
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationUpdater.cxx376
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationUpdater.hxx209
-rw-r--r--sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx81
-rw-r--r--sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx98
-rw-r--r--sd/source/ui/framework/configuration/ResourceFactoryManager.cxx197
-rw-r--r--sd/source/ui/framework/configuration/ResourceFactoryManager.hxx120
-rw-r--r--sd/source/ui/framework/configuration/ResourceId.cxx503
-rw-r--r--sd/source/ui/framework/configuration/UpdateRequest.cxx47
-rw-r--r--sd/source/ui/framework/configuration/UpdateRequest.hxx70
-rw-r--r--sd/source/ui/framework/configuration/debugtrace.hxx15
-rw-r--r--sd/source/ui/framework/factories/BasicPaneFactory.cxx432
-rw-r--r--sd/source/ui/framework/factories/BasicPaneFactory.hxx131
-rw-r--r--sd/source/ui/framework/factories/BasicToolBarFactory.cxx161
-rw-r--r--sd/source/ui/framework/factories/BasicToolBarFactory.hxx84
-rw-r--r--sd/source/ui/framework/factories/BasicViewFactory.cxx518
-rw-r--r--sd/source/ui/framework/factories/BasicViewFactory.hxx129
-rw-r--r--sd/source/ui/framework/factories/ChildWindowPane.cxx219
-rw-r--r--sd/source/ui/framework/factories/ChildWindowPane.hxx101
-rw-r--r--sd/source/ui/framework/factories/FrameWindowPane.cxx39
-rw-r--r--sd/source/ui/framework/factories/FrameWindowPane.hxx50
-rw-r--r--sd/source/ui/framework/factories/FullScreenPane.cxx226
-rw-r--r--sd/source/ui/framework/factories/FullScreenPane.hxx85
-rw-r--r--sd/source/ui/framework/factories/Pane.cxx178
-rw-r--r--sd/source/ui/framework/factories/PresentationFactory.cxx192
-rw-r--r--sd/source/ui/framework/factories/ViewShellWrapper.cxx252
-rw-r--r--sd/source/ui/framework/module/CenterViewFocusModule.cxx151
-rw-r--r--sd/source/ui/framework/module/CenterViewFocusModule.hxx90
-rw-r--r--sd/source/ui/framework/module/DrawModule.cxx41
-rw-r--r--sd/source/ui/framework/module/ImpressModule.cxx51
-rw-r--r--sd/source/ui/framework/module/ModuleController.cxx244
-rw-r--r--sd/source/ui/framework/module/PresentationModule.cxx36
-rw-r--r--sd/source/ui/framework/module/ShellStackGuard.cxx150
-rw-r--r--sd/source/ui/framework/module/ShellStackGuard.hxx94
-rw-r--r--sd/source/ui/framework/module/SlideSorterModule.cxx313
-rw-r--r--sd/source/ui/framework/module/SlideSorterModule.hxx97
-rw-r--r--sd/source/ui/framework/module/ToolBarModule.cxx191
-rw-r--r--sd/source/ui/framework/module/ToolBarModule.hxx81
-rw-r--r--sd/source/ui/framework/module/ViewTabBarModule.cxx180
-rw-r--r--sd/source/ui/framework/module/ViewTabBarModule.hxx83
-rw-r--r--sd/source/ui/framework/tools/FrameworkHelper.cxx952
-rw-r--r--sd/source/ui/func/bulmaper.cxx104
-rw-r--r--sd/source/ui/func/fuarea.cxx99
-rw-r--r--sd/source/ui/func/fubullet.cxx330
-rw-r--r--sd/source/ui/func/fuchar.cxx139
-rw-r--r--sd/source/ui/func/fucon3d.cxx474
-rw-r--r--sd/source/ui/func/fuconarc.cxx254
-rw-r--r--sd/source/ui/func/fuconbez.cxx556
-rw-r--r--sd/source/ui/func/fuconcs.cxx261
-rw-r--r--sd/source/ui/func/fuconnct.cxx71
-rw-r--r--sd/source/ui/func/fuconrec.cxx1096
-rw-r--r--sd/source/ui/func/fuconstr.cxx414
-rw-r--r--sd/source/ui/func/fuconuno.cxx150
-rw-r--r--sd/source/ui/func/fucopy.cxx288
-rw-r--r--sd/source/ui/func/fucushow.cxx91
-rw-r--r--sd/source/ui/func/fudraw.cxx820
-rw-r--r--sd/source/ui/func/fudspord.cxx131
-rw-r--r--sd/source/ui/func/fuediglu.cxx471
-rw-r--r--sd/source/ui/func/fuexecuteinteraction.cxx237
-rw-r--r--sd/source/ui/func/fuexpand.cxx256
-rw-r--r--sd/source/ui/func/fuformatpaintbrush.cxx276
-rw-r--r--sd/source/ui/func/fuhhconv.cxx256
-rw-r--r--sd/source/ui/func/fuinsert.cxx767
-rw-r--r--sd/source/ui/func/fuinsfil.cxx725
-rw-r--r--sd/source/ui/func/fuline.cxx109
-rw-r--r--sd/source/ui/func/fulinend.cxx154
-rw-r--r--sd/source/ui/func/fulink.cxx65
-rw-r--r--sd/source/ui/func/fumeasur.cxx72
-rw-r--r--sd/source/ui/func/fumorph.cxx508
-rw-r--r--sd/source/ui/func/funavig.cxx154
-rw-r--r--sd/source/ui/func/fuoaprms.cxx800
-rw-r--r--sd/source/ui/func/fuolbull.cxx340
-rw-r--r--sd/source/ui/func/fuoltext.cxx305
-rw-r--r--sd/source/ui/func/fupage.cxx648
-rw-r--r--sd/source/ui/func/fuparagr.cxx162
-rw-r--r--sd/source/ui/func/fupoor.cxx1135
-rw-r--r--sd/source/ui/func/fuprlout.cxx277
-rw-r--r--sd/source/ui/func/fuprobjs.cxx154
-rw-r--r--sd/source/ui/func/fuscale.cxx179
-rw-r--r--sd/source/ui/func/fusearch.cxx140
-rw-r--r--sd/source/ui/func/fusel.cxx1328
-rw-r--r--sd/source/ui/func/fusldlg.cxx226
-rw-r--r--sd/source/ui/func/fusnapln.cxx196
-rw-r--r--sd/source/ui/func/fusumry.cxx229
-rw-r--r--sd/source/ui/func/futempl.cxx638
-rw-r--r--sd/source/ui/func/futext.cxx1464
-rw-r--r--sd/source/ui/func/futhes.cxx132
-rw-r--r--sd/source/ui/func/futransf.cxx132
-rw-r--r--sd/source/ui/func/futxtatt.cxx80
-rw-r--r--sd/source/ui/func/fuvect.cxx87
-rw-r--r--sd/source/ui/func/fuzoom.cxx219
-rw-r--r--sd/source/ui/func/sdundogr.cxx66
-rw-r--r--sd/source/ui/func/smarttag.cxx333
-rw-r--r--sd/source/ui/func/undoback.cxx105
-rw-r--r--sd/source/ui/func/undoheaderfooter.cxx53
-rw-r--r--sd/source/ui/func/undolayer.cxx78
-rw-r--r--sd/source/ui/func/undopage.cxx99
-rw-r--r--sd/source/ui/func/unmovss.cxx95
-rw-r--r--sd/source/ui/func/unoaprms.cxx96
-rw-r--r--sd/source/ui/func/unprlout.cxx73
-rw-r--r--sd/source/ui/inc/AccessibleDocumentViewBase.hxx324
-rw-r--r--sd/source/ui/inc/AccessibleDrawDocumentView.hxx165
-rw-r--r--sd/source/ui/inc/AccessibleOutlineEditSource.hxx90
-rw-r--r--sd/source/ui/inc/AccessibleOutlineView.hxx119
-rw-r--r--sd/source/ui/inc/AccessiblePageShape.hxx117
-rw-r--r--sd/source/ui/inc/AccessiblePresentationGraphicShape.hxx60
-rw-r--r--sd/source/ui/inc/AccessiblePresentationOLEShape.hxx57
-rw-r--r--sd/source/ui/inc/AccessiblePresentationShape.hxx61
-rw-r--r--sd/source/ui/inc/AccessibleSlideSorterObject.hxx189
-rw-r--r--sd/source/ui/inc/AccessibleSlideSorterView.hxx255
-rw-r--r--sd/source/ui/inc/AccessibleViewForwarder.hxx92
-rw-r--r--sd/source/ui/inc/AnimationChildWindow.hxx45
-rw-r--r--sd/source/ui/inc/BezierObjectBar.hxx51
-rw-r--r--sd/source/ui/inc/BreakDlg.hxx64
-rw-r--r--sd/source/ui/inc/BulletAndPositionDlg.hxx157
-rw-r--r--sd/source/ui/inc/Client.hxx45
-rw-r--r--sd/source/ui/inc/ClientView.hxx43
-rw-r--r--sd/source/ui/inc/CustomAnimationList.hxx169
-rw-r--r--sd/source/ui/inc/CustomAnimationPane.hxx179
-rw-r--r--sd/source/ui/inc/DocumentRenderer.hxx63
-rw-r--r--sd/source/ui/inc/DrawController.hxx327
-rw-r--r--sd/source/ui/inc/DrawDocShell.hxx235
-rw-r--r--sd/source/ui/inc/DrawSubController.hxx46
-rw-r--r--sd/source/ui/inc/DrawViewShell.hxx513
-rw-r--r--sd/source/ui/inc/EventMultiplexer.hxx172
-rw-r--r--sd/source/ui/inc/FormShellManager.hxx139
-rw-r--r--sd/source/ui/inc/FrameView.hxx213
-rw-r--r--sd/source/ui/inc/GraphicDocShell.hxx54
-rw-r--r--sd/source/ui/inc/GraphicObjectBar.hxx54
-rw-r--r--sd/source/ui/inc/GraphicViewShell.hxx72
-rw-r--r--sd/source/ui/inc/GraphicViewShellBase.hxx50
-rw-r--r--sd/source/ui/inc/ImpressViewShellBase.hxx50
-rw-r--r--sd/source/ui/inc/LayerTabBar.hxx108
-rw-r--r--sd/source/ui/inc/MasterPageObserver.hxx119
-rw-r--r--sd/source/ui/inc/MediaObjectBar.hxx56
-rw-r--r--sd/source/ui/inc/NavigatorChildWindow.hxx40
-rw-r--r--sd/source/ui/inc/OutlineBulletDlg.hxx51
-rw-r--r--sd/source/ui/inc/OutlineView.hxx230
-rw-r--r--sd/source/ui/inc/OutlineViewShell.hxx163
-rw-r--r--sd/source/ui/inc/OutlineViewShellBase.hxx43
-rw-r--r--sd/source/ui/inc/OutlinerIteratorImpl.hxx239
-rw-r--r--sd/source/ui/inc/PaneChildWindows.hxx65
-rw-r--r--sd/source/ui/inc/PaneDockingWindow.hxx66
-rw-r--r--sd/source/ui/inc/PaneShells.hxx63
-rw-r--r--sd/source/ui/inc/PresentationViewShell.hxx70
-rw-r--r--sd/source/ui/inc/PresentationViewShellBase.hxx46
-rw-r--r--sd/source/ui/inc/PreviewRenderer.hxx141
-rw-r--r--sd/source/ui/inc/RemoteServer.hxx88
-rw-r--r--sd/source/ui/inc/Ruler.hxx62
-rw-r--r--sd/source/ui/inc/SdUnoDrawView.hxx116
-rw-r--r--sd/source/ui/inc/SdUnoOutlineView.hxx82
-rw-r--r--sd/source/ui/inc/SdUnoSlideView.hxx82
-rw-r--r--sd/source/ui/inc/ShellFactory.hxx52
-rw-r--r--sd/source/ui/inc/SlideSorter.hxx248
-rw-r--r--sd/source/ui/inc/SlideSorterViewShell.hxx232
-rw-r--r--sd/source/ui/inc/SlideSorterViewShellBase.hxx43
-rw-r--r--sd/source/ui/inc/SlideTransitionPane.hxx137
-rw-r--r--sd/source/ui/inc/SpellDialogChildWindow.hxx86
-rw-r--r--sd/source/ui/inc/TabControl.hxx107
-rw-r--r--sd/source/ui/inc/TableDesignPane.hxx118
-rw-r--r--sd/source/ui/inc/TemplateScanner.hxx175
-rw-r--r--sd/source/ui/inc/TextObjectBar.hxx58
-rw-r--r--sd/source/ui/inc/ToolBarManager.hxx273
-rw-r--r--sd/source/ui/inc/View.hxx300
-rw-r--r--sd/source/ui/inc/ViewClipboard.hxx78
-rw-r--r--sd/source/ui/inc/ViewShell.hxx559
-rw-r--r--sd/source/ui/inc/ViewShellBase.hxx246
-rw-r--r--sd/source/ui/inc/ViewShellHint.hxx57
-rw-r--r--sd/source/ui/inc/ViewShellImplementation.hxx150
-rw-r--r--sd/source/ui/inc/ViewShellManager.hxx195
-rw-r--r--sd/source/ui/inc/ViewTabBar.hxx184
-rw-r--r--sd/source/ui/inc/Window.hxx213
-rw-r--r--sd/source/ui/inc/WindowUpdater.hxx124
-rw-r--r--sd/source/ui/inc/animobjs.hxx163
-rw-r--r--sd/source/ui/inc/annotationmanager.hxx46
-rw-r--r--sd/source/ui/inc/assclass.hxx68
-rw-r--r--sd/source/ui/inc/bulmaper.hxx37
-rw-r--r--sd/source/ui/inc/copydlg.hxx67
-rw-r--r--sd/source/ui/inc/createtableobjectbar.hxx37
-rw-r--r--sd/source/ui/inc/custsdlg.hxx91
-rw-r--r--sd/source/ui/inc/diactrl.hxx68
-rw-r--r--sd/source/ui/inc/dlg_char.hxx41
-rw-r--r--sd/source/ui/inc/dlgfield.hxx56
-rw-r--r--sd/source/ui/inc/dlgpage.hxx48
-rw-r--r--sd/source/ui/inc/dlgsnap.hxx66
-rw-r--r--sd/source/ui/inc/drawview.hxx72
-rw-r--r--sd/source/ui/inc/filedlg.hxx57
-rw-r--r--sd/source/ui/inc/framework/Configuration.hxx181
-rw-r--r--sd/source/ui/inc/framework/ConfigurationController.hxx180
-rw-r--r--sd/source/ui/inc/framework/DrawModule.hxx46
-rw-r--r--sd/source/ui/inc/framework/FrameworkHelper.hxx340
-rw-r--r--sd/source/ui/inc/framework/ImpressModule.hxx46
-rw-r--r--sd/source/ui/inc/framework/ModuleController.hxx114
-rw-r--r--sd/source/ui/inc/framework/Pane.hxx141
-rw-r--r--sd/source/ui/inc/framework/PresentationFactory.hxx77
-rw-r--r--sd/source/ui/inc/framework/PresentationModule.hxx46
-rw-r--r--sd/source/ui/inc/framework/ResourceId.hxx213
-rw-r--r--sd/source/ui/inc/framework/ViewShellWrapper.hxx131
-rw-r--r--sd/source/ui/inc/fuarea.hxx48
-rw-r--r--sd/source/ui/inc/fubullet.hxx54
-rw-r--r--sd/source/ui/inc/fuchar.hxx49
-rw-r--r--sd/source/ui/inc/fucon3d.hxx61
-rw-r--r--sd/source/ui/inc/fuconarc.hxx54
-rw-r--r--sd/source/ui/inc/fuconbez.hxx76
-rw-r--r--sd/source/ui/inc/fuconcs.hxx64
-rw-r--r--sd/source/ui/inc/fuconnct.hxx46
-rw-r--r--sd/source/ui/inc/fuconrec.hxx71
-rw-r--r--sd/source/ui/inc/fuconstr.hxx64
-rw-r--r--sd/source/ui/inc/fuconuno.hxx64
-rw-r--r--sd/source/ui/inc/fucopy.hxx47
-rw-r--r--sd/source/ui/inc/fucushow.hxx45
-rw-r--r--sd/source/ui/inc/fudraw.hxx85
-rw-r--r--sd/source/ui/inc/fudspord.hxx62
-rw-r--r--sd/source/ui/inc/fuediglu.hxx64
-rw-r--r--sd/source/ui/inc/fuexecuteinteraction.hxx44
-rw-r--r--sd/source/ui/inc/fuexpand.hxx45
-rw-r--r--sd/source/ui/inc/fuformatpaintbrush.hxx61
-rw-r--r--sd/source/ui/inc/fuhhconv.hxx58
-rw-r--r--sd/source/ui/inc/fuinsert.hxx112
-rw-r--r--sd/source/ui/inc/fuinsfil.hxx60
-rw-r--r--sd/source/ui/inc/fuline.hxx49
-rw-r--r--sd/source/ui/inc/fulinend.hxx49
-rw-r--r--sd/source/ui/inc/fulink.hxx46
-rw-r--r--sd/source/ui/inc/fumeasur.hxx46
-rw-r--r--sd/source/ui/inc/fumorph.hxx90
-rw-r--r--sd/source/ui/inc/funavig.hxx46
-rw-r--r--sd/source/ui/inc/fuoaprms.hxx46
-rw-r--r--sd/source/ui/inc/fuolbull.hxx62
-rw-r--r--sd/source/ui/inc/fuoltext.hxx76
-rw-r--r--sd/source/ui/inc/fupage.hxx73
-rw-r--r--sd/source/ui/inc/fuparagr.hxx48
-rw-r--r--sd/source/ui/inc/fupoor.hxx180
-rw-r--r--sd/source/ui/inc/fuprlout.hxx51
-rw-r--r--sd/source/ui/inc/fuprobjs.hxx51
-rw-r--r--sd/source/ui/inc/fuscale.hxx45
-rw-r--r--sd/source/ui/inc/fusearch.hxx56
-rw-r--r--sd/source/ui/inc/fusel.hxx104
-rw-r--r--sd/source/ui/inc/fusldlg.hxx45
-rw-r--r--sd/source/ui/inc/fusnapln.hxx48
-rw-r--r--sd/source/ui/inc/fusumry.hxx45
-rw-r--r--sd/source/ui/inc/futempl.hxx48
-rw-r--r--sd/source/ui/inc/futext.hxx97
-rw-r--r--sd/source/ui/inc/futhes.hxx45
-rw-r--r--sd/source/ui/inc/futransf.hxx45
-rw-r--r--sd/source/ui/inc/futxtatt.hxx45
-rw-r--r--sd/source/ui/inc/fuvect.hxx46
-rw-r--r--sd/source/ui/inc/fuzoom.hxx64
-rw-r--r--sd/source/ui/inc/gluectrl.hxx68
-rw-r--r--sd/source/ui/inc/headerfooterdlg.hxx70
-rw-r--r--sd/source/ui/inc/ins_paste.hxx37
-rw-r--r--sd/source/ui/inc/inspagob.hxx57
-rw-r--r--sd/source/ui/inc/layeroptionsdlg.hxx48
-rw-r--r--sd/source/ui/inc/masterlayoutdlg.hxx61
-rw-r--r--sd/source/ui/inc/morphdlg.hxx49
-rw-r--r--sd/source/ui/inc/navigatr.hxx205
-rw-r--r--sd/source/ui/inc/optsitem.hxx580
-rw-r--r--sd/source/ui/inc/paragr.hxx36
-rw-r--r--sd/source/ui/inc/pgjump.hxx31
-rw-r--r--sd/source/ui/inc/present.hxx90
-rw-r--r--sd/source/ui/inc/prltempl.hxx64
-rw-r--r--sd/source/ui/inc/prntopts.hxx69
-rw-r--r--sd/source/ui/inc/pubdlg.hxx205
-rw-r--r--sd/source/ui/inc/registerinterfaces.hxx30
-rw-r--r--sd/source/ui/inc/scalectrl.hxx39
-rw-r--r--sd/source/ui/inc/sdpopup.hxx47
-rw-r--r--sd/source/ui/inc/sdpreslt.hxx70
-rw-r--r--sd/source/ui/inc/sdtreelb.hxx395
-rw-r--r--sd/source/ui/inc/sdundogr.hxx46
-rw-r--r--sd/source/ui/inc/sdxfer.hxx148
-rw-r--r--sd/source/ui/inc/slideshow.hxx216
-rw-r--r--sd/source/ui/inc/smarttag.hxx171
-rw-r--r--sd/source/ui/inc/tablefunction.hxx32
-rw-r--r--sd/source/ui/inc/tabtempl.hxx57
-rw-r--r--sd/source/ui/inc/titledockwin.hxx94
-rw-r--r--sd/source/ui/inc/tmplctrl.hxx40
-rw-r--r--sd/source/ui/inc/tools/AsynchronousCall.hxx77
-rw-r--r--sd/source/ui/inc/tools/AsynchronousTask.hxx49
-rw-r--r--sd/source/ui/inc/tools/ConfigurationAccess.hxx144
-rw-r--r--sd/source/ui/inc/tools/GraphicSizeCheck.hxx116
-rw-r--r--sd/source/ui/inc/tools/IconCache.hxx70
-rw-r--r--sd/source/ui/inc/tools/IdleDetection.hxx89
-rw-r--r--sd/source/ui/inc/tools/PropertySet.hxx114
-rw-r--r--sd/source/ui/inc/tools/SdGlobalResourceContainer.hxx105
-rw-r--r--sd/source/ui/inc/tools/SlotStateListener.hxx138
-rw-r--r--sd/source/ui/inc/tools/TimerBasedTaskExecution.hxx89
-rw-r--r--sd/source/ui/inc/tpaction.hxx104
-rw-r--r--sd/source/ui/inc/tpoption.hxx144
-rw-r--r--sd/source/ui/inc/uiobject.hxx35
-rw-r--r--sd/source/ui/inc/unchss.hxx47
-rw-r--r--sd/source/ui/inc/undoback.hxx58
-rw-r--r--sd/source/ui/inc/undoheaderfooter.hxx45
-rw-r--r--sd/source/ui/inc/undolayer.hxx56
-rw-r--r--sd/source/ui/inc/undopage.hxx161
-rw-r--r--sd/source/ui/inc/unmodpg.hxx74
-rw-r--r--sd/source/ui/inc/unmovss.hxx44
-rw-r--r--sd/source/ui/inc/unoaprms.hxx148
-rw-r--r--sd/source/ui/inc/unokywds.hxx119
-rw-r--r--sd/source/ui/inc/unomodel.hxx406
-rw-r--r--sd/source/ui/inc/unopage.hxx304
-rw-r--r--sd/source/ui/inc/unoprnms.hxx73
-rw-r--r--sd/source/ui/inc/unosrch.hxx134
-rw-r--r--sd/source/ui/inc/unprlout.hxx55
-rw-r--r--sd/source/ui/inc/vectdlg.hxx81
-rw-r--r--sd/source/ui/inc/view/viewoverlaymanager.hxx71
-rw-r--r--sd/source/ui/inc/zoomlist.hxx50
-rw-r--r--sd/source/ui/presenter/CanvasUpdateRequester.cxx131
-rw-r--r--sd/source/ui/presenter/CanvasUpdateRequester.hxx72
-rw-r--r--sd/source/ui/presenter/PresenterCanvas.cxx790
-rw-r--r--sd/source/ui/presenter/PresenterCanvas.hxx320
-rw-r--r--sd/source/ui/presenter/PresenterHelper.cxx466
-rw-r--r--sd/source/ui/presenter/PresenterHelper.hxx93
-rw-r--r--sd/source/ui/presenter/PresenterPreviewCache.cxx360
-rw-r--r--sd/source/ui/presenter/PresenterPreviewCache.hxx97
-rw-r--r--sd/source/ui/presenter/PresenterTextView.cxx466
-rw-r--r--sd/source/ui/presenter/PresenterTextView.hxx71
-rw-r--r--sd/source/ui/presenter/SlideRenderer.cxx201
-rw-r--r--sd/source/ui/presenter/SlideRenderer.hxx94
-rw-r--r--sd/source/ui/remotecontrol/AvahiNetworkService.cxx209
-rw-r--r--sd/source/ui/remotecontrol/AvahiNetworkService.hxx25
-rw-r--r--sd/source/ui/remotecontrol/BluetoothServer.cxx1521
-rw-r--r--sd/source/ui/remotecontrol/BluetoothServer.hxx61
-rw-r--r--sd/source/ui/remotecontrol/BluetoothServer.mm1
-rw-r--r--sd/source/ui/remotecontrol/BluetoothServiceRecord.hxx75
-rw-r--r--sd/source/ui/remotecontrol/BufferedStreamSocket.cxx130
-rw-r--r--sd/source/ui/remotecontrol/BufferedStreamSocket.hxx66
-rw-r--r--sd/source/ui/remotecontrol/Communicator.cxx154
-rw-r--r--sd/source/ui/remotecontrol/Communicator.hxx52
-rw-r--r--sd/source/ui/remotecontrol/DiscoveryService.cxx186
-rw-r--r--sd/source/ui/remotecontrol/DiscoveryService.hxx40
-rw-r--r--sd/source/ui/remotecontrol/DiscoveryService.mm1
-rw-r--r--sd/source/ui/remotecontrol/IBluetoothSocket.hxx42
-rw-r--r--sd/source/ui/remotecontrol/ImagePreparer.cxx255
-rw-r--r--sd/source/ui/remotecontrol/ImagePreparer.hxx45
-rw-r--r--sd/source/ui/remotecontrol/Listener.cxx133
-rw-r--r--sd/source/ui/remotecontrol/Listener.hxx62
-rw-r--r--sd/source/ui/remotecontrol/OSXBluetooth.h30
-rw-r--r--sd/source/ui/remotecontrol/OSXBluetooth.mm53
-rw-r--r--sd/source/ui/remotecontrol/OSXBluetoothWrapper.hxx38
-rw-r--r--sd/source/ui/remotecontrol/OSXNetworkService.h30
-rw-r--r--sd/source/ui/remotecontrol/OSXNetworkService.hxx43
-rw-r--r--sd/source/ui/remotecontrol/OSXNetworkService.mm43
-rw-r--r--sd/source/ui/remotecontrol/Receiver.cxx207
-rw-r--r--sd/source/ui/remotecontrol/Receiver.hxx37
-rw-r--r--sd/source/ui/remotecontrol/Server.cxx373
-rw-r--r--sd/source/ui/remotecontrol/Transmitter.cxx86
-rw-r--r--sd/source/ui/remotecontrol/Transmitter.hxx55
-rw-r--r--sd/source/ui/remotecontrol/WINNetworkService.cxx19
-rw-r--r--sd/source/ui/remotecontrol/WINNetworkService.hxx23
-rw-r--r--sd/source/ui/remotecontrol/ZeroconfService.hxx49
-rw-r--r--sd/source/ui/sidebar/AllMasterPagesSelector.cxx180
-rw-r--r--sd/source/ui/sidebar/AllMasterPagesSelector.hxx80
-rw-r--r--sd/source/ui/sidebar/CurrentMasterPagesSelector.cxx263
-rw-r--r--sd/source/ui/sidebar/CurrentMasterPagesSelector.hxx77
-rw-r--r--sd/source/ui/sidebar/DocumentHelper.cxx536
-rw-r--r--sd/source/ui/sidebar/DocumentHelper.hxx108
-rw-r--r--sd/source/ui/sidebar/IDisposable.hxx31
-rw-r--r--sd/source/ui/sidebar/ISidebarReceiver.hxx31
-rw-r--r--sd/source/ui/sidebar/LayoutMenu.cxx728
-rw-r--r--sd/source/ui/sidebar/LayoutMenu.hxx157
-rw-r--r--sd/source/ui/sidebar/MasterPageContainer.cxx958
-rw-r--r--sd/source/ui/sidebar/MasterPageContainer.hxx199
-rw-r--r--sd/source/ui/sidebar/MasterPageContainerFiller.cxx168
-rw-r--r--sd/source/ui/sidebar/MasterPageContainerFiller.hxx92
-rw-r--r--sd/source/ui/sidebar/MasterPageContainerProviders.cxx205
-rw-r--r--sd/source/ui/sidebar/MasterPageContainerProviders.hxx175
-rw-r--r--sd/source/ui/sidebar/MasterPageContainerQueue.cxx263
-rw-r--r--sd/source/ui/sidebar/MasterPageContainerQueue.hxx131
-rw-r--r--sd/source/ui/sidebar/MasterPageDescriptor.cxx341
-rw-r--r--sd/source/ui/sidebar/MasterPageDescriptor.hxx231
-rw-r--r--sd/source/ui/sidebar/MasterPageObserver.cxx317
-rw-r--r--sd/source/ui/sidebar/MasterPagesSelector.cxx620
-rw-r--r--sd/source/ui/sidebar/MasterPagesSelector.hxx180
-rw-r--r--sd/source/ui/sidebar/NavigatorWrapper.cxx49
-rw-r--r--sd/source/ui/sidebar/NavigatorWrapper.hxx57
-rw-r--r--sd/source/ui/sidebar/PageMarginUtils.hxx159
-rw-r--r--sd/source/ui/sidebar/PanelFactory.cxx141
-rw-r--r--sd/source/ui/sidebar/PanelFactory.hxx49
-rw-r--r--sd/source/ui/sidebar/PreviewValueSet.cxx127
-rw-r--r--sd/source/ui/sidebar/PreviewValueSet.hxx59
-rw-r--r--sd/source/ui/sidebar/RecentMasterPagesSelector.cxx138
-rw-r--r--sd/source/ui/sidebar/RecentMasterPagesSelector.hxx71
-rw-r--r--sd/source/ui/sidebar/RecentlyUsedMasterPages.cxx366
-rw-r--r--sd/source/ui/sidebar/RecentlyUsedMasterPages.hxx125
-rw-r--r--sd/source/ui/sidebar/SlideBackground.cxx1286
-rw-r--r--sd/source/ui/sidebar/SlideBackground.hxx180
-rw-r--r--sd/source/ui/slideshow/PaneHider.cxx99
-rw-r--r--sd/source/ui/slideshow/PaneHider.hxx66
-rw-r--r--sd/source/ui/slideshow/SlideShowRestarter.cxx156
-rw-r--r--sd/source/ui/slideshow/SlideShowRestarter.hxx88
-rw-r--r--sd/source/ui/slideshow/showwin.cxx629
-rw-r--r--sd/source/ui/slideshow/showwindow.hxx110
-rw-r--r--sd/source/ui/slideshow/slideshow.cxx1191
-rw-r--r--sd/source/ui/slideshow/slideshowimpl.cxx3349
-rw-r--r--sd/source/ui/slideshow/slideshowimpl.hxx342
-rw-r--r--sd/source/ui/slideshow/slideshowviewimpl.cxx626
-rw-r--r--sd/source/ui/slideshow/slideshowviewimpl.hxx182
-rw-r--r--sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx550
-rw-r--r--sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx208
-rw-r--r--sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx197
-rw-r--r--sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx138
-rw-r--r--sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx71
-rw-r--r--sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx46
-rw-r--r--sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx189
-rw-r--r--sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx87
-rw-r--r--sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx144
-rw-r--r--sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx68
-rw-r--r--sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx278
-rw-r--r--sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx152
-rw-r--r--sd/source/ui/slidesorter/cache/SlsPageCache.cxx109
-rw-r--r--sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx420
-rw-r--r--sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx176
-rw-r--r--sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx98
-rw-r--r--sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx50
-rw-r--r--sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx36
-rw-r--r--sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx44
-rw-r--r--sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx275
-rw-r--r--sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx122
-rw-r--r--sd/source/ui/slidesorter/controller/SlideSorterController.cxx910
-rw-r--r--sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx129
-rw-r--r--sd/source/ui/slidesorter/controller/SlsAnimator.cxx280
-rw-r--r--sd/source/ui/slidesorter/controller/SlsClipboard.cxx918
-rw-r--r--sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx256
-rw-r--r--sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx120
-rw-r--r--sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx68
-rw-r--r--sd/source/ui/slidesorter/controller/SlsFocusManager.cxx245
-rw-r--r--sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx243
-rw-r--r--sd/source/ui/slidesorter/controller/SlsListener.cxx597
-rw-r--r--sd/source/ui/slidesorter/controller/SlsListener.hxx164
-rw-r--r--sd/source/ui/slidesorter/controller/SlsPageSelector.cxx386
-rw-r--r--sd/source/ui/slidesorter/controller/SlsProperties.cxx106
-rw-r--r--sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx608
-rw-r--r--sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx1485
-rw-r--r--sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx309
-rw-r--r--sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx139
-rw-r--r--sd/source/ui/slidesorter/controller/SlsSlotManager.cxx1284
-rw-r--r--sd/source/ui/slidesorter/controller/SlsTransferableData.cxx86
-rw-r--r--sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx234
-rw-r--r--sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx98
-rw-r--r--sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx141
-rw-r--r--sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx155
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx327
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsAnimationFunction.hxx77
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx122
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx208
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx112
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx211
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsInsertionIndicatorHandler.hxx138
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx219
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx125
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx248
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx145
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx139
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsSelectionObserver.hxx77
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx98
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsTransferableData.hxx78
-rw-r--r--sd/source/ui/slidesorter/inc/controller/SlsVisibleAreaManager.hxx90
-rw-r--r--sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx227
-rw-r--r--sd/source/ui/slidesorter/inc/model/SlsEnumeration.hxx44
-rw-r--r--sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx144
-rw-r--r--sd/source/ui/slidesorter/inc/model/SlsPageEnumeration.hxx95
-rw-r--r--sd/source/ui/slidesorter/inc/model/SlsPageEnumerationProvider.hxx51
-rw-r--r--sd/source/ui/slidesorter/inc/model/SlsSharedPageDescriptor.hxx32
-rw-r--r--sd/source/ui/slidesorter/inc/model/SlsVisualState.hxx47
-rw-r--r--sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx225
-rw-r--r--sd/source/ui/slidesorter/inc/view/SlsILayerPainter.hxx53
-rw-r--r--sd/source/ui/slidesorter/inc/view/SlsInsertAnimator.hxx59
-rw-r--r--sd/source/ui/slidesorter/inc/view/SlsInsertionIndicatorOverlay.hxx101
-rw-r--r--sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx237
-rw-r--r--sd/source/ui/slidesorter/inc/view/SlsPageObjectLayouter.hxx144
-rw-r--r--sd/source/ui/slidesorter/inc/view/SlsPageObjectPainter.hxx119
-rw-r--r--sd/source/ui/slidesorter/inc/view/SlsTheme.hxx135
-rw-r--r--sd/source/ui/slidesorter/inc/view/SlsToolTip.hxx75
-rw-r--r--sd/source/ui/slidesorter/model/SlideSorterModel.cxx676
-rw-r--r--sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx226
-rw-r--r--sd/source/ui/slidesorter/model/SlsPageEnumeration.cxx202
-rw-r--r--sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx81
-rw-r--r--sd/source/ui/slidesorter/model/SlsVisualState.cxx40
-rw-r--r--sd/source/ui/slidesorter/shell/SlideSorter.cxx456
-rw-r--r--sd/source/ui/slidesorter/shell/SlideSorterService.cxx412
-rw-r--r--sd/source/ui/slidesorter/shell/SlideSorterService.hxx153
-rw-r--r--sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx924
-rw-r--r--sd/source/ui/slidesorter/view/SlideSorterView.cxx856
-rw-r--r--sd/source/ui/slidesorter/view/SlsFramePainter.cxx225
-rw-r--r--sd/source/ui/slidesorter/view/SlsFramePainter.hxx109
-rw-r--r--sd/source/ui/slidesorter/view/SlsInsertAnimator.cxx428
-rw-r--r--sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx360
-rw-r--r--sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx491
-rw-r--r--sd/source/ui/slidesorter/view/SlsLayeredDevice.hxx84
-rw-r--r--sd/source/ui/slidesorter/view/SlsLayouter.cxx1225
-rw-r--r--sd/source/ui/slidesorter/view/SlsPageObjectLayouter.cxx259
-rw-r--r--sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx442
-rw-r--r--sd/source/ui/slidesorter/view/SlsTheme.cxx239
-rw-r--r--sd/source/ui/slidesorter/view/SlsToolTip.cxx160
-rw-r--r--sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx117
-rw-r--r--sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx61
-rw-r--r--sd/source/ui/table/TableDesignPane.cxx763
-rw-r--r--sd/source/ui/table/tablefunction.cxx292
-rw-r--r--sd/source/ui/table/tableobjectbar.cxx224
-rw-r--r--sd/source/ui/table/tableobjectbar.hxx56
-rw-r--r--sd/source/ui/tools/AsynchronousCall.cxx56
-rw-r--r--sd/source/ui/tools/ConfigurationAccess.cxx173
-rw-r--r--sd/source/ui/tools/EventMultiplexer.cxx661
-rw-r--r--sd/source/ui/tools/GraphicSizeCheck.cxx221
-rw-r--r--sd/source/ui/tools/IconCache.cxx106
-rw-r--r--sd/source/ui/tools/IdleDetection.cxx103
-rw-r--r--sd/source/ui/tools/PreviewRenderer.cxx532
-rw-r--r--sd/source/ui/tools/PropertySet.cxx158
-rw-r--r--sd/source/ui/tools/SdGlobalResourceContainer.cxx197
-rw-r--r--sd/source/ui/tools/SlotStateListener.cxx153
-rw-r--r--sd/source/ui/tools/TimerBasedTaskExecution.cxx130
-rw-r--r--sd/source/ui/uitest/uiobject.cxx183
-rw-r--r--sd/source/ui/unoidl/DrawController.cxx815
-rw-r--r--sd/source/ui/unoidl/SdUnoDrawView.cxx548
-rw-r--r--sd/source/ui/unoidl/SdUnoOutlineView.cxx156
-rw-r--r--sd/source/ui/unoidl/SdUnoSlideView.cxx172
-rw-r--r--sd/source/ui/unoidl/UnoDocumentSettings.cxx1431
-rw-r--r--sd/source/ui/unoidl/UnoDocumentSettings.hxx37
-rw-r--r--sd/source/ui/unoidl/randomnode.cxx573
-rw-r--r--sd/source/ui/unoidl/sddetect.cxx160
-rw-r--r--sd/source/ui/unoidl/sddetect.hxx48
-rw-r--r--sd/source/ui/unoidl/unocpres.cxx450
-rw-r--r--sd/source/ui/unoidl/unocpres.hxx147
-rw-r--r--sd/source/ui/unoidl/unodoc.cxx73
-rw-r--r--sd/source/ui/unoidl/unolayer.cxx707
-rw-r--r--sd/source/ui/unoidl/unolayer.hxx169
-rw-r--r--sd/source/ui/unoidl/unomodel.cxx3491
-rw-r--r--sd/source/ui/unoidl/unomodule.cxx132
-rw-r--r--sd/source/ui/unoidl/unomodule.hxx57
-rw-r--r--sd/source/ui/unoidl/unoobj.cxx1627
-rw-r--r--sd/source/ui/unoidl/unoobj.hxx100
-rw-r--r--sd/source/ui/unoidl/unopage.cxx3056
-rw-r--r--sd/source/ui/unoidl/unopback.cxx410
-rw-r--r--sd/source/ui/unoidl/unopback.hxx89
-rw-r--r--sd/source/ui/unoidl/unopool.cxx89
-rw-r--r--sd/source/ui/unoidl/unopool.hxx29
-rw-r--r--sd/source/ui/unoidl/unosrch.cxx778
-rw-r--r--sd/source/ui/unoidl/unowcntr.cxx99
-rw-r--r--sd/source/ui/unoidl/unowcntr.hxx47
-rw-r--r--sd/source/ui/view/DocumentRenderer.cxx2256
-rw-r--r--sd/source/ui/view/FormShellManager.cxx319
-rw-r--r--sd/source/ui/view/GraphicObjectBar.cxx141
-rw-r--r--sd/source/ui/view/GraphicViewShellBase.cxx93
-rw-r--r--sd/source/ui/view/ImpressViewShellBase.cxx97
-rw-r--r--sd/source/ui/view/MediaObjectBar.cxx77
-rw-r--r--sd/source/ui/view/OutlineViewShellBase.cxx66
-rw-r--r--sd/source/ui/view/Outliner.cxx2066
-rw-r--r--sd/source/ui/view/OutlinerIterator.cxx798
-rw-r--r--sd/source/ui/view/PresentationViewShellBase.cxx94
-rw-r--r--sd/source/ui/view/SlideSorterViewShellBase.cxx68
-rw-r--r--sd/source/ui/view/ToolBarManager.cxx1375
-rw-r--r--sd/source/ui/view/ViewClipboard.cxx240
-rw-r--r--sd/source/ui/view/ViewShellBase.cxx1456
-rw-r--r--sd/source/ui/view/ViewShellHint.cxx31
-rw-r--r--sd/source/ui/view/ViewShellImplementation.cxx379
-rw-r--r--sd/source/ui/view/ViewShellManager.cxx1168
-rw-r--r--sd/source/ui/view/ViewTabBar.cxx561
-rw-r--r--sd/source/ui/view/WindowUpdater.cxx131
-rw-r--r--sd/source/ui/view/clview.cxx62
-rw-r--r--sd/source/ui/view/drawview.cxx634
-rw-r--r--sd/source/ui/view/drbezob.cxx320
-rw-r--r--sd/source/ui/view/drtxtob.cxx625
-rw-r--r--sd/source/ui/view/drtxtob1.cxx865
-rw-r--r--sd/source/ui/view/drviews1.cxx1360
-rw-r--r--sd/source/ui/view/drviews2.cxx4004
-rw-r--r--sd/source/ui/view/drviews3.cxx1106
-rw-r--r--sd/source/ui/view/drviews4.cxx982
-rw-r--r--sd/source/ui/view/drviews5.cxx650
-rw-r--r--sd/source/ui/view/drviews6.cxx339
-rw-r--r--sd/source/ui/view/drviews7.cxx1991
-rw-r--r--sd/source/ui/view/drviews8.cxx135
-rw-r--r--sd/source/ui/view/drviews9.cxx886
-rw-r--r--sd/source/ui/view/drviewsa.cxx848
-rw-r--r--sd/source/ui/view/drviewsb.cxx205
-rw-r--r--sd/source/ui/view/drviewsc.cxx72
-rw-r--r--sd/source/ui/view/drviewsd.cxx193
-rw-r--r--sd/source/ui/view/drviewse.cxx1701
-rw-r--r--sd/source/ui/view/drviewsf.cxx826
-rw-r--r--sd/source/ui/view/drviewsg.cxx232
-rw-r--r--sd/source/ui/view/drviewsh.cxx203
-rw-r--r--sd/source/ui/view/drviewsi.cxx165
-rw-r--r--sd/source/ui/view/drviewsj.cxx567
-rw-r--r--sd/source/ui/view/drviewsk.cxx37
-rw-r--r--sd/source/ui/view/drvwshrg.cxx110
-rw-r--r--sd/source/ui/view/frmview.cxx916
-rw-r--r--sd/source/ui/view/grviewsh.cxx88
-rw-r--r--sd/source/ui/view/outlnvs2.cxx636
-rw-r--r--sd/source/ui/view/outlnvsh.cxx1883
-rw-r--r--sd/source/ui/view/outlview.cxx1720
-rw-r--r--sd/source/ui/view/presvish.cxx172
-rw-r--r--sd/source/ui/view/sdruler.cxx148
-rw-r--r--sd/source/ui/view/sdview.cxx1395
-rw-r--r--sd/source/ui/view/sdview2.cxx908
-rw-r--r--sd/source/ui/view/sdview3.cxx1596
-rw-r--r--sd/source/ui/view/sdview4.cxx645
-rw-r--r--sd/source/ui/view/sdview5.cxx118
-rw-r--r--sd/source/ui/view/sdwindow.cxx1097
-rw-r--r--sd/source/ui/view/tabcontr.cxx358
-rw-r--r--sd/source/ui/view/unmodpg.cxx210
-rw-r--r--sd/source/ui/view/viewoverlaymanager.cxx546
-rw-r--r--sd/source/ui/view/viewshe2.cxx958
-rw-r--r--sd/source/ui/view/viewshe3.cxx383
-rw-r--r--sd/source/ui/view/viewshel.cxx1634
-rw-r--r--sd/source/ui/view/zoomlist.cxx94
794 files changed, 258337 insertions, 0 deletions
diff --git a/sd/source/core/CustomAnimationCloner.cxx b/sd/source/core/CustomAnimationCloner.cxx
new file mode 100644
index 000000000..ea42e3bac
--- /dev/null
+++ b/sd/source/core/CustomAnimationCloner.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 <com/sun/star/animations/XAnimate.hpp>
+#include <com/sun/star/animations/XAnimationNode.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/XCommand.hpp>
+#include <com/sun/star/animations/XIterateContainer.hpp>
+#include <com/sun/star/animations/XAudio.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/ValuePair.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+
+#include <map>
+
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <animations/animationnodehelper.hxx>
+
+#include <svx/svditer.hxx>
+
+#include <CustomAnimationCloner.hxx>
+#include <sdpage.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::container;
+
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::beans::NamedValue;
+
+namespace sd
+{
+ namespace {
+
+ class CustomAnimationClonerImpl
+ {
+ public:
+ CustomAnimationClonerImpl();
+ Reference< XAnimationNode > Clone( const Reference< XAnimationNode >& xSourceNode, const SdPage* pSource, const SdPage* pTarget );
+
+ private:
+ void transformNode( const Reference< XAnimationNode >& xNode );
+ Any transformValue( const Any& rValue );
+
+ Reference< XShape > getClonedShape( const Reference< XShape >& xSource ) const;
+ Reference< XAnimationNode > getClonedNode( const Reference< XAnimationNode >& xSource ) const;
+
+ mutable ::std::map< Reference< XShape >, Reference< XShape > > maShapeMap;
+ std::vector< Reference< XAnimationNode > > maSourceNodeVector;
+ std::vector< Reference< XAnimationNode > > maCloneNodeVector;
+ };
+
+ }
+
+ CustomAnimationClonerImpl::CustomAnimationClonerImpl()
+ {
+ }
+
+ Reference< XAnimationNode > Clone( const Reference< XAnimationNode >& xSourceNode, const SdPage* pSource, const SdPage* pTarget )
+ {
+ CustomAnimationClonerImpl aCloner;
+ return aCloner.Clone( xSourceNode, pSource, pTarget );
+ }
+
+ Reference< XAnimationNode > CustomAnimationClonerImpl::Clone( const Reference< XAnimationNode >& xSourceNode, const SdPage* pSourcePage, const SdPage* pTargetPage )
+ {
+ try
+ {
+ // clone animation hierarchy
+ Reference< css::util::XCloneable > xClonable( xSourceNode, UNO_QUERY_THROW );
+ Reference< XAnimationNode > xCloneNode( xClonable->createClone(), UNO_QUERY_THROW );
+
+ // create a dictionary to map source to cloned shapes
+ if( pSourcePage && pTargetPage )
+ {
+ SdrObjListIter aSourceIter( pSourcePage, SdrIterMode::DeepWithGroups );
+ SdrObjListIter aTargetIter( pTargetPage, SdrIterMode::DeepWithGroups );
+
+ while( aSourceIter.IsMore() && aTargetIter.IsMore() )
+ {
+ SdrObject* pSource = aSourceIter.Next();
+ SdrObject* pTarget = aTargetIter.Next();
+
+ if( pSource && pTarget)
+ {
+ Reference< XShape > xSource( pSource->getUnoShape(), UNO_QUERY );
+ Reference< XShape > xTarget( pTarget->getUnoShape(), UNO_QUERY );
+ if( xSource.is() && xTarget.is() )
+ {
+ maShapeMap[xSource] = xTarget;
+ }
+ }
+ }
+ }
+
+ // create a dictionary to map source to cloned nodes
+ ::anim::create_deep_vector( xSourceNode, maSourceNodeVector );
+ ::anim::create_deep_vector( xCloneNode, maCloneNodeVector );
+
+ transformNode( xCloneNode );
+
+ return xCloneNode;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationClonerImpl::Clone()" );
+ Reference< XAnimationNode > xEmpty;
+ return xEmpty;
+ }
+ }
+
+ void CustomAnimationClonerImpl::transformNode( const Reference< XAnimationNode >& xNode )
+ {
+ try
+ {
+ xNode->setBegin( transformValue( xNode->getBegin() ) );
+ xNode->setEnd( transformValue( xNode->getEnd() ) );
+
+ sal_Int16 nNodeType( xNode->getType() );
+ switch( nNodeType )
+ {
+ case AnimationNodeType::ITERATE:
+ {
+ Reference< XIterateContainer > xIter( xNode, UNO_QUERY_THROW );
+ xIter->setTarget( transformValue( xIter->getTarget() ) );
+ [[fallthrough]];
+ }
+ case AnimationNodeType::PAR:
+ case AnimationNodeType::SEQ:
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+ transformNode( xChildNode );
+ }
+ }
+ break;
+
+ case AnimationNodeType::ANIMATE:
+ case AnimationNodeType::SET:
+ case AnimationNodeType::ANIMATEMOTION:
+ case AnimationNodeType::ANIMATEPHYSICS:
+ case AnimationNodeType::ANIMATECOLOR:
+ case AnimationNodeType::ANIMATETRANSFORM:
+ case AnimationNodeType::TRANSITIONFILTER:
+ {
+ Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW );
+ xAnimate->setTarget( transformValue( xAnimate->getTarget() ) );
+ }
+ break;
+
+ case AnimationNodeType::COMMAND:
+ {
+ Reference< XCommand > xCommand( xNode, UNO_QUERY_THROW );
+ xCommand->setTarget( transformValue( xCommand->getTarget() ) );
+ }
+ break;
+
+ case AnimationNodeType::AUDIO:
+ {
+ Reference< XAudio > xAudio( xNode, UNO_QUERY_THROW );
+ xAudio->setSource( transformValue( xAudio->getSource() ) );
+ }
+ break;
+ }
+
+ Sequence< NamedValue > aUserData( xNode->getUserData() );
+ if( aUserData.hasElements() )
+ {
+ for( NamedValue & namedValue : asNonConstRange(aUserData) )
+ {
+ namedValue.Value = transformValue( namedValue.Value );
+ }
+
+ xNode->setUserData( aUserData );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationClonerImpl::transformNode()" );
+ }
+ }
+
+ Any CustomAnimationClonerImpl::transformValue( const Any& rValue )
+ {
+ if( rValue.hasValue() ) try
+ {
+ if( rValue.getValueType() == cppu::UnoType<ValuePair>::get() )
+ {
+ ValuePair aValuePair;
+ rValue >>= aValuePair;
+
+ aValuePair.First = transformValue( aValuePair.First );
+ aValuePair.Second = transformValue( aValuePair.Second );
+
+ return Any( aValuePair );
+ }
+ else if( rValue.getValueType() == cppu::UnoType< Sequence<Any> >::get() )
+ {
+ Sequence<Any> aSequence;
+ rValue >>= aSequence;
+
+ for( Any& rAny : asNonConstRange(aSequence) )
+ rAny = transformValue( rAny );
+
+ return Any( aSequence );
+ }
+ else if( rValue.getValueTypeClass() == TypeClass_INTERFACE )
+ {
+ Reference< XShape > xShape;
+ rValue >>= xShape;
+ if( xShape.is() )
+ {
+ return Any( getClonedShape( xShape ) );
+ }
+ else
+ {
+ Reference< XAnimationNode > xNode;
+ rValue >>= xNode;
+ if( xNode.is() )
+ return Any( getClonedNode( xNode ) );
+ }
+ }
+ else if( rValue.getValueType() == cppu::UnoType<ParagraphTarget>::get() )
+ {
+ ParagraphTarget aParaTarget;
+ rValue >>= aParaTarget;
+
+ aParaTarget.Shape = getClonedShape( aParaTarget.Shape );
+
+ return Any( aParaTarget );
+ }
+ else if( rValue.getValueType() == cppu::UnoType<Event>::get() )
+ {
+ Event aEvent;
+ rValue >>= aEvent;
+
+ aEvent.Source = transformValue( aEvent.Source );
+
+ return Any( aEvent );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationClonerImpl::transformValue()" );
+ }
+
+ return rValue;
+ }
+
+ Reference< XShape > CustomAnimationClonerImpl::getClonedShape( const Reference< XShape >& xSource ) const
+ {
+ if( xSource.is() )
+ {
+ if( maShapeMap.find(xSource) != maShapeMap.end() )
+ {
+ return maShapeMap[xSource];
+ }
+
+ DBG_ASSERT( maShapeMap.empty(), "sd::CustomAnimationClonerImpl::getClonedShape() failed!" );
+ }
+ return xSource;
+ }
+
+ Reference< XAnimationNode > CustomAnimationClonerImpl::getClonedNode( const Reference< XAnimationNode >& xSource ) const
+ {
+ std::size_t nNodeCount = maSourceNodeVector.size();
+ std::size_t nCloneNodeCount = maCloneNodeVector.size();
+
+ if (nNodeCount != nCloneNodeCount)
+ SAL_WARN("sd.core", "Sizes of maSourceNodeVector and maCloneNodeVector mismatch!");
+
+ for( std::size_t nNode = 0; nNode < nNodeCount && nNode < nCloneNodeCount; ++nNode )
+ {
+ if( maSourceNodeVector[nNode] == xSource )
+ return maCloneNodeVector[nNode];
+ }
+
+ OSL_FAIL( "sd::CustomAnimationClonerImpl::getClonedNode() failed!" );
+ return xSource;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/CustomAnimationEffect.cxx b/sd/source/core/CustomAnimationEffect.cxx
new file mode 100644
index 000000000..b1816784f
--- /dev/null
+++ b/sd/source/core/CustomAnimationEffect.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 <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/AnimateColor.hpp>
+#include <com/sun/star/animations/AnimateMotion.hpp>
+#include <com/sun/star/animations/AnimateSet.hpp>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/animations/Audio.hpp>
+#include <com/sun/star/animations/Command.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/animations/IterateContainer.hpp>
+#include <com/sun/star/animations/ParallelTimeContainer.hpp>
+#include <com/sun/star/animations/SequenceTimeContainer.hpp>
+#include <com/sun/star/animations/XCommand.hpp>
+#include <com/sun/star/animations/XIterateContainer.hpp>
+#include <com/sun/star/animations/XAnimateTransform.hpp>
+#include <com/sun/star/animations/XAnimateMotion.hpp>
+#include <com/sun/star/animations/XAnimate.hpp>
+#include <com/sun/star/animations/AnimationRestart.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/EffectCommands.hpp>
+#include <com/sun/star/presentation/EffectPresetClass.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/util/XChangesNotifier.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/i18n/BreakIterator.hpp>
+#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <algorithm>
+#include <deque>
+#include <numeric>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <o3tl/safeint.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpage.hxx>
+#include <CustomAnimationEffect.hxx>
+#include <CustomAnimationPreset.hxx>
+#include <animations.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::animations;
+
+using ::com::sun::star::container::XEnumerationAccess;
+using ::com::sun::star::container::XEnumeration;
+using ::com::sun::star::beans::NamedValue;
+using ::com::sun::star::container::XChild;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::lang::XInitialization;
+using ::com::sun::star::text::XText;
+using ::com::sun::star::text::XTextRange;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::util::XCloneable;
+using ::com::sun::star::lang::Locale;
+using ::com::sun::star::util::XChangesNotifier;
+using ::com::sun::star::util::XChangesListener;
+
+namespace sd
+{
+class MainSequenceChangeGuard
+{
+public:
+ explicit MainSequenceChangeGuard( EffectSequenceHelper* pSequence )
+ {
+ mpMainSequence = dynamic_cast< MainSequence* >( pSequence );
+ if( mpMainSequence == nullptr )
+ {
+ InteractiveSequence* pI = dynamic_cast< InteractiveSequence* >( pSequence );
+ if( pI )
+ mpMainSequence = pI->mpMainSequence;
+ }
+ DBG_ASSERT( mpMainSequence, "sd::MainSequenceChangeGuard::MainSequenceChangeGuard(), no main sequence to guard!" );
+
+ if( mpMainSequence )
+ mpMainSequence->mbIgnoreChanges++;
+ }
+
+ ~MainSequenceChangeGuard()
+ {
+ if( mpMainSequence )
+ mpMainSequence->mbIgnoreChanges++;
+ }
+
+private:
+ MainSequence* mpMainSequence;
+};
+
+CustomAnimationEffect::CustomAnimationEffect( const css::uno::Reference< css::animations::XAnimationNode >& xNode )
+: mnNodeType(-1),
+ mnPresetClass(-1),
+ mnFill(AnimationFill::HOLD),
+ mfBegin(-1.0),
+ mfDuration(-1.0),
+ mfAbsoluteDuration(-1.0),
+ mnGroupId(-1),
+ mnIterateType(0),
+ mfIterateInterval(0.0),
+ mnParaDepth( -1 ),
+ mbHasText(false),
+ mfAcceleration( 1.0 ),
+ mfDecelerate( 1.0 ),
+ mbAutoReverse(false),
+ mnTargetSubItem(0),
+ mnCommand(0),
+ mpEffectSequence( nullptr ),
+ mbHasAfterEffect(false),
+ mbAfterEffectOnNextEffect(false)
+{
+ setNode( xNode );
+}
+
+void CustomAnimationEffect::setNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode )
+{
+ mxNode = xNode;
+ mxAudio.clear();
+ mnCommand = 0;
+
+ const Sequence< NamedValue > aUserData( mxNode->getUserData() );
+
+ for( const NamedValue& rProp : aUserData )
+ {
+ if ( rProp.Name == "node-type" )
+ {
+ rProp.Value >>= mnNodeType;
+ }
+ else if ( rProp.Name == "preset-id" )
+ {
+ rProp.Value >>= maPresetId;
+ }
+ else if ( rProp.Name == "preset-sub-type" )
+ {
+ rProp.Value >>= maPresetSubType;
+ }
+ else if ( rProp.Name == "preset-class" )
+ {
+ rProp.Value >>= mnPresetClass;
+ }
+ else if ( rProp.Name == "preset-property" )
+ {
+ rProp.Value >>= maProperty;
+ }
+ else if ( rProp.Name == "group-id" )
+ {
+ rProp.Value >>= mnGroupId;
+ }
+ }
+
+ // get effect start time
+ mxNode->getBegin() >>= mfBegin;
+
+ mfAcceleration = mxNode->getAcceleration();
+ mfDecelerate = mxNode->getDecelerate();
+ mbAutoReverse = mxNode->getAutoReverse();
+
+ mnFill = mxNode->getFill();
+
+ // get iteration data
+ Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
+ if( xIter.is() )
+ {
+ mfIterateInterval = xIter->getIterateInterval();
+ mnIterateType = xIter->getIterateType();
+ maTarget = xIter->getTarget();
+ mnTargetSubItem = xIter->getSubItem();
+ }
+ else
+ {
+ mfIterateInterval = 0.0f;
+ mnIterateType = 0;
+ }
+
+ // calculate effect duration and get target shape
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( !xChildNode.is() )
+ continue;
+
+ if( xChildNode->getType() == AnimationNodeType::AUDIO )
+ {
+ mxAudio.set( xChildNode, UNO_QUERY );
+ }
+ else if( xChildNode->getType() == AnimationNodeType::COMMAND )
+ {
+ Reference< XCommand > xCommand( xChildNode, UNO_QUERY );
+ if( xCommand.is() )
+ {
+ mnCommand = xCommand->getCommand();
+ if( !maTarget.hasValue() )
+ maTarget = xCommand->getTarget();
+ }
+ }
+ else
+ {
+ double fBegin = 0.0;
+ double fDuration = 0.0;
+ xChildNode->getBegin() >>= fBegin;
+ xChildNode->getDuration() >>= fDuration;
+
+ fDuration += fBegin;
+ if( fDuration > mfDuration )
+ mfDuration = fDuration;
+
+ // no target shape yet?
+ if( !maTarget.hasValue() )
+ {
+ // go get it boys!
+ Reference< XAnimate > xAnimate( xChildNode, UNO_QUERY );
+ if( xAnimate.is() )
+ {
+ maTarget = xAnimate->getTarget();
+ mnTargetSubItem = xAnimate->getSubItem();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ mfAbsoluteDuration = mfDuration;
+ double fRepeatCount = 1.0;
+ if( (mxNode->getRepeatCount()) >>= fRepeatCount )
+ mfAbsoluteDuration *= fRepeatCount;
+
+ checkForText();
+}
+
+sal_Int32 CustomAnimationEffect::getNumberOfSubitems( const Any& aTarget, sal_Int16 nIterateType )
+{
+ sal_Int32 nSubItems = 0;
+
+ try
+ {
+ // first get target text
+ sal_Int32 nOnlyPara = -1;
+
+ Reference< XText > xShape;
+ aTarget >>= xShape;
+ if( !xShape.is() )
+ {
+ ParagraphTarget aParaTarget;
+ if( aTarget >>= aParaTarget )
+ {
+ xShape.set( aParaTarget.Shape, UNO_QUERY );
+ nOnlyPara = aParaTarget.Paragraph;
+ }
+ }
+
+ // now use the break iterator to iterate over the given text
+ // and count the sub items
+
+ if( xShape.is() )
+ {
+ // TODO/LATER: Optimize this, don't create a break iterator each time
+ Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference < i18n::XBreakIterator > xBI = i18n::BreakIterator::create(xContext);
+
+ Reference< XEnumerationAccess > xEA( xShape, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_SET_THROW );
+ css::lang::Locale aLocale;
+ static const OUStringLiteral aStrLocaleName( u"CharLocale" );
+ Reference< XTextRange > xParagraph;
+
+ sal_Int32 nPara = 0;
+ while( xEnumeration->hasMoreElements() )
+ {
+ xEnumeration->nextElement() >>= xParagraph;
+
+ // skip this if it's not the only paragraph we want to count
+ if( (nOnlyPara != -1) && (nOnlyPara != nPara ) )
+ continue;
+
+ if( nIterateType == TextAnimationType::BY_PARAGRAPH )
+ {
+ nSubItems++;
+ }
+ else
+ {
+ const OUString aText( xParagraph->getString() );
+ Reference< XPropertySet > xSet( xParagraph, UNO_QUERY_THROW );
+ xSet->getPropertyValue( aStrLocaleName ) >>= aLocale;
+
+ sal_Int32 nPos;
+ const sal_Int32 nEndPos = aText.getLength();
+
+ if( nIterateType == TextAnimationType::BY_WORD )
+ {
+ for( nPos = 0; nPos < nEndPos; nPos++ )
+ {
+ nPos = xBI->getWordBoundary(aText, nPos, aLocale, i18n::WordType::ANY_WORD, true).endPos;
+ nSubItems++;
+ }
+ break;
+ }
+ else
+ {
+ sal_Int32 nDone;
+ for( nPos = 0; nPos < nEndPos; nPos++ )
+ {
+ nPos = xBI->nextCharacters(aText, nPos, aLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone);
+ nSubItems++;
+ }
+ }
+ }
+
+ if( nPara == nOnlyPara )
+ break;
+
+ nPara++;
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ nSubItems = 0;
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::getNumberOfSubitems(), exception caught!" );
+ }
+
+ return nSubItems;
+}
+
+CustomAnimationEffect::~CustomAnimationEffect()
+{
+}
+
+CustomAnimationEffectPtr CustomAnimationEffect::clone() const
+{
+ Reference< XCloneable > xCloneable( mxNode, UNO_QUERY_THROW );
+ Reference< XAnimationNode > xNode( xCloneable->createClone(), UNO_QUERY_THROW );
+ CustomAnimationEffectPtr pEffect = std::make_shared<CustomAnimationEffect>( xNode );
+ pEffect->setEffectSequence( getEffectSequence() );
+ return pEffect;
+}
+
+sal_Int32 CustomAnimationEffect::get_node_type( const Reference< XAnimationNode >& xNode )
+{
+ sal_Int16 nNodeType = -1;
+
+ if( xNode.is() )
+ {
+ const Sequence< NamedValue > aUserData( xNode->getUserData() );
+ if( aUserData.hasElements() )
+ {
+ const NamedValue* pProp = std::find_if(aUserData.begin(), aUserData.end(),
+ [](const NamedValue& rProp) { return rProp.Name == "node-type"; });
+ if (pProp != aUserData.end())
+ pProp->Value >>= nNodeType;
+ }
+ }
+
+ return nNodeType;
+}
+
+void CustomAnimationEffect::setPresetClassAndId( sal_Int16 nPresetClass, const OUString& rPresetId )
+{
+ if( mnPresetClass == nPresetClass && maPresetId == rPresetId )
+ return;
+
+ mnPresetClass = nPresetClass;
+ maPresetId = rPresetId;
+ if( !mxNode.is() )
+ return;
+
+ // first try to find a "preset-class" entry in the user data
+ // and change it
+ Sequence< NamedValue > aUserData( mxNode->getUserData() );
+ sal_Int32 nLength = aUserData.getLength();
+ bool bFoundPresetClass = false;
+ bool bFoundPresetId = false;
+ if( nLength )
+ {
+ auto [begin, end] = asNonConstRange(aUserData);
+ NamedValue* pProp = std::find_if(begin, end,
+ [](const NamedValue& rProp) { return rProp.Name == "preset-class"; });
+ if (pProp != end)
+ {
+ pProp->Value <<= mnPresetClass;
+ bFoundPresetClass = true;
+ }
+
+ pProp = std::find_if(begin, end,
+ [](const NamedValue& rProp) { return rProp.Name == "preset-id"; });
+ if (pProp != end)
+ {
+ pProp->Value <<= mnPresetClass;
+ bFoundPresetId = true;
+ }
+ }
+
+ // no "preset-class" entry inside user data, so add it
+ if( !bFoundPresetClass )
+ {
+ aUserData.realloc( nLength + 1);
+ auto& el = aUserData.getArray()[nLength];
+ el.Name = "preset-class";
+ el.Value <<= mnPresetClass;
+ ++nLength;
+ }
+
+ if( !bFoundPresetId && maPresetId.getLength() > 0 )
+ {
+ aUserData.realloc( nLength + 1);
+ auto& el = aUserData.getArray()[nLength];
+ el.Name = "preset-id";
+ el.Value <<= maPresetId;
+ }
+
+ mxNode->setUserData( aUserData );
+}
+
+void CustomAnimationEffect::setNodeType( sal_Int16 nNodeType )
+{
+ if( mnNodeType == nNodeType )
+ return;
+
+ mnNodeType = nNodeType;
+ if( !mxNode.is() )
+ return;
+
+ // first try to find a "node-type" entry in the user data
+ // and change it
+ Sequence< NamedValue > aUserData( mxNode->getUserData() );
+ sal_Int32 nLength = aUserData.getLength();
+ bool bFound = false;
+ if( nLength )
+ {
+ auto [begin, end] = asNonConstRange(aUserData);
+ NamedValue* pProp = std::find_if(begin, end,
+ [](const NamedValue& rProp) { return rProp.Name == "node-type"; });
+ if (pProp != end)
+ {
+ pProp->Value <<= mnNodeType;
+ bFound = true;
+ }
+ }
+
+ // no "node-type" entry inside user data, so add it
+ if( !bFound )
+ {
+ aUserData.realloc( nLength + 1);
+ auto& el = aUserData.getArray()[nLength];
+ el.Name = "node-type";
+ el.Value <<= mnNodeType;
+ }
+
+ mxNode->setUserData( aUserData );
+}
+
+void CustomAnimationEffect::setGroupId( sal_Int32 nGroupId )
+{
+ mnGroupId = nGroupId;
+ if( !mxNode.is() )
+ return;
+
+ // first try to find a "group-id" entry in the user data
+ // and change it
+ Sequence< NamedValue > aUserData( mxNode->getUserData() );
+ sal_Int32 nLength = aUserData.getLength();
+ bool bFound = false;
+ if( nLength )
+ {
+ auto [begin, end] = asNonConstRange(aUserData);
+ NamedValue* pProp = std::find_if(begin, end,
+ [](const NamedValue& rProp) { return rProp.Name == "group-id"; });
+ if (pProp != end)
+ {
+ pProp->Value <<= mnGroupId;
+ bFound = true;
+ }
+ }
+
+ // no "group-id" entry inside user data, so add it
+ if( !bFound )
+ {
+ aUserData.realloc( nLength + 1);
+ auto& el = aUserData.getArray()[nLength];
+ el.Name = "group-id";
+ el.Value <<= mnGroupId;
+ }
+
+ mxNode->setUserData( aUserData );
+}
+
+/** checks if the text for this effect has changed and updates internal flags.
+ returns true if something changed.
+*/
+bool CustomAnimationEffect::checkForText( const std::vector<sal_Int32>* paragraphNumberingLevel )
+{
+ bool bChange = false;
+
+ Reference< XText > xText;
+
+ if( maTarget.getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ // calc para depth
+ ParagraphTarget aParaTarget;
+ maTarget >>= aParaTarget;
+
+ xText.set( aParaTarget.Shape, UNO_QUERY );
+
+ // get paragraph
+ if( xText.is() )
+ {
+ sal_Int32 nPara = aParaTarget.Paragraph;
+
+ bool bHasText = false;
+ sal_Int32 nParaDepth = 0;
+
+ if ( paragraphNumberingLevel )
+ {
+ bHasText = !paragraphNumberingLevel->empty();
+ if (nPara >= 0 && o3tl::make_unsigned(nPara) < paragraphNumberingLevel->size())
+ nParaDepth = paragraphNumberingLevel->at(nPara);
+ }
+ else
+ {
+ Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
+ if( xEA.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEA->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ bHasText = xEnumeration->hasMoreElements();
+
+ while( xEnumeration->hasMoreElements() && nPara-- )
+ xEnumeration->nextElement();
+
+ if( xEnumeration->hasMoreElements() )
+ {
+ Reference< XPropertySet > xParaSet;
+ xEnumeration->nextElement() >>= xParaSet;
+ if( xParaSet.is() )
+ {
+ xParaSet->getPropertyValue( "NumberingLevel" ) >>= nParaDepth;
+ }
+ }
+ }
+ }
+ }
+
+ if( bHasText )
+ {
+ bChange |= bHasText != mbHasText;
+ mbHasText = bHasText;
+
+ bChange |= nParaDepth != mnParaDepth;
+ mnParaDepth = nParaDepth;
+ }
+ }
+ }
+ else
+ {
+ maTarget >>= xText;
+ bool bHasText = xText.is() && !xText->getString().isEmpty();
+ bChange |= bHasText != mbHasText;
+ mbHasText = bHasText;
+ }
+
+ bChange |= calculateIterateDuration();
+ return bChange;
+}
+
+bool CustomAnimationEffect::calculateIterateDuration()
+{
+ bool bChange = false;
+
+ // if we have an iteration, we must also calculate the
+ // 'true' container duration, that is
+ // ( ( is form animated ) ? [contained effects duration] : 0 ) +
+ // ( [number of animated children] - 1 ) * [interval-delay] + [contained effects duration]
+ Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
+ if( xIter.is() )
+ {
+ double fDuration = mfDuration;
+ const double fSubEffectDuration = mfDuration;
+
+ if( mnTargetSubItem != ShapeAnimationSubType::ONLY_BACKGROUND ) // does not make sense for iterate container but better check
+ {
+ const sal_Int32 nSubItems = getNumberOfSubitems( maTarget, mnIterateType );
+ if( nSubItems )
+ {
+ const double f = (nSubItems-1) * mfIterateInterval;
+ fDuration += f;
+ }
+ }
+
+ // if we also animate the form first, we have to add the
+ // sub effect duration to the whole effect duration
+ if( mnTargetSubItem == ShapeAnimationSubType::AS_WHOLE )
+ fDuration += fSubEffectDuration;
+
+ bChange |= fDuration != mfAbsoluteDuration;
+ mfAbsoluteDuration = fDuration;
+ }
+
+ return bChange;
+}
+
+void CustomAnimationEffect::setTarget( const css::uno::Any& rTarget )
+{
+ try
+ {
+ maTarget = rTarget;
+
+ // first, check special case for random node
+ Reference< XInitialization > xInit( mxNode, UNO_QUERY );
+ if( xInit.is() )
+ {
+ const Sequence< Any > aArgs( &maTarget, 1 );
+ xInit->initialize( aArgs );
+ }
+ else
+ {
+ Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
+ if( xIter.is() )
+ {
+ xIter->setTarget(maTarget);
+ }
+ else
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ const Any aElem( xEnumeration->nextElement() );
+ Reference< XAnimate > xAnimate( aElem, UNO_QUERY );
+ if( xAnimate.is() )
+ xAnimate->setTarget( rTarget );
+ else
+ {
+ Reference< XCommand > xCommand( aElem, UNO_QUERY );
+ if( xCommand.is() )
+ xCommand->setTarget( rTarget );
+ }
+ }
+ }
+ }
+ }
+ }
+ checkForText();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setTarget()" );
+ }
+}
+
+void CustomAnimationEffect::setTargetSubItem( sal_Int16 nSubItem )
+{
+ try
+ {
+ mnTargetSubItem = nSubItem;
+
+ Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
+ if( xIter.is() )
+ {
+ xIter->setSubItem(mnTargetSubItem);
+ }
+ else
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
+ if( xAnimate.is() )
+ xAnimate->setSubItem( mnTargetSubItem );
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setTargetSubItem()" );
+ }
+}
+
+void CustomAnimationEffect::setDuration( double fDuration )
+{
+ if( (mfDuration == -1.0) || (mfDuration == fDuration) )
+ return;
+
+ try
+ {
+ double fScale = fDuration / mfDuration;
+ mfDuration = fDuration;
+ double fRepeatCount = 1.0;
+ getRepeatCount() >>= fRepeatCount;
+ mfAbsoluteDuration = mfDuration * fRepeatCount;
+
+ // calculate effect duration and get target shape
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( !xChildNode.is() )
+ continue;
+
+ double fChildBegin = 0.0;
+ xChildNode->getBegin() >>= fChildBegin;
+ if( fChildBegin != 0.0 )
+ {
+ fChildBegin *= fScale;
+ xChildNode->setBegin( Any( fChildBegin ) );
+ }
+
+ double fChildDuration = 0.0;
+ xChildNode->getDuration() >>= fChildDuration;
+ if( fChildDuration != 0.0 )
+ {
+ fChildDuration *= fScale;
+ xChildNode->setDuration( Any( fChildDuration ) );
+ }
+ }
+ }
+ }
+ calculateIterateDuration();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setDuration()" );
+ }
+}
+
+void CustomAnimationEffect::setBegin( double fBegin )
+{
+ if( mxNode.is() ) try
+ {
+ mfBegin = fBegin;
+ mxNode->setBegin( Any( fBegin ) );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setBegin()" );
+ }
+}
+
+void CustomAnimationEffect::setAcceleration( double fAcceleration )
+{
+ if( mxNode.is() ) try
+ {
+ mfAcceleration = fAcceleration;
+ mxNode->setAcceleration( fAcceleration );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setAcceleration()" );
+ }
+}
+
+void CustomAnimationEffect::setDecelerate( double fDecelerate )
+{
+ if( mxNode.is() ) try
+ {
+ mfDecelerate = fDecelerate;
+ mxNode->setDecelerate( fDecelerate );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setDecelerate()" );
+ }
+}
+
+void CustomAnimationEffect::setAutoReverse( bool bAutoReverse )
+{
+ if( mxNode.is() ) try
+ {
+ mbAutoReverse = bAutoReverse;
+ mxNode->setAutoReverse( bAutoReverse );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setAutoReverse()" );
+ }
+}
+
+void CustomAnimationEffect::replaceNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode )
+{
+ sal_Int16 nNodeType = mnNodeType;
+ Any aTarget = maTarget;
+
+ sal_Int16 nFill = mnFill;
+ double fBegin = mfBegin;
+ double fDuration = mfDuration;
+ double fAcceleration = mfAcceleration;
+ double fDecelerate = mfDecelerate ;
+ bool bAutoReverse = mbAutoReverse;
+ Reference< XAudio > xAudio( mxAudio );
+ sal_Int16 nIterateType = mnIterateType;
+ double fIterateInterval = mfIterateInterval;
+ sal_Int16 nSubItem = mnTargetSubItem;
+
+ setNode( xNode );
+
+ setAudio( xAudio );
+ setNodeType( nNodeType );
+ setTarget( aTarget );
+ setTargetSubItem( nSubItem );
+ setDuration( fDuration );
+ setBegin( fBegin );
+ setFill( nFill );
+
+ setAcceleration( fAcceleration );
+ setDecelerate( fDecelerate );
+ setAutoReverse( bAutoReverse );
+
+ if( nIterateType != mnIterateType )
+ setIterateType( nIterateType );
+
+ if( mnIterateType && ( fIterateInterval != mfIterateInterval ) )
+ setIterateInterval( fIterateInterval );
+}
+
+Reference< XShape > CustomAnimationEffect::getTargetShape() const
+{
+ Reference< XShape > xShape;
+ maTarget >>= xShape;
+ if( !xShape.is() )
+ {
+ ParagraphTarget aParaTarget;
+ if( maTarget >>= aParaTarget )
+ xShape = aParaTarget.Shape;
+ }
+
+ return xShape;
+}
+
+Any CustomAnimationEffect::getRepeatCount() const
+{
+ if( mxNode.is() )
+ {
+ return mxNode->getRepeatCount();
+ }
+ else
+ {
+ Any aAny;
+ return aAny;
+ }
+}
+
+Any CustomAnimationEffect::getEnd() const
+{
+ if( mxNode.is() )
+ {
+ return mxNode->getEnd();
+ }
+ else
+ {
+ Any aAny;
+ return aAny;
+ }
+}
+
+void CustomAnimationEffect::setRepeatCount( const Any& rRepeatCount )
+{
+ if( mxNode.is() )
+ {
+ mxNode->setRepeatCount( rRepeatCount );
+ double fRepeatCount = 1.0;
+ rRepeatCount >>= fRepeatCount;
+ mfAbsoluteDuration = mfDuration * fRepeatCount;
+ }
+}
+
+void CustomAnimationEffect::setEnd( const Any& rEnd )
+{
+ if( mxNode.is() )
+ mxNode->setEnd( rEnd );
+}
+
+void CustomAnimationEffect::setFill( sal_Int16 nFill )
+{
+ if (mxNode.is())
+ {
+ mnFill = nFill;
+ mxNode->setFill( nFill );
+ }
+}
+
+Reference< XAnimationNode > CustomAnimationEffect::createAfterEffectNode() const
+{
+ DBG_ASSERT( mbHasAfterEffect, "sd::CustomAnimationEffect::createAfterEffectNode(), this node has no after effect!" );
+
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+
+ Reference< XAnimate > xAnimate;
+ if( maDimColor.hasValue() )
+ xAnimate = AnimateColor::create( xContext );
+ else
+ xAnimate = AnimateSet::create( xContext );
+
+ Any aTo;
+ OUString aAttributeName;
+
+ if( maDimColor.hasValue() )
+ {
+ aTo = maDimColor;
+ aAttributeName = "DimColor";
+ }
+ else
+ {
+ aTo <<= false;
+ aAttributeName = "Visibility";
+ }
+
+ Any aBegin;
+ if( !mbAfterEffectOnNextEffect ) // sameClick
+ {
+ Event aEvent;
+
+ aEvent.Source <<= getNode();
+ aEvent.Trigger = EventTrigger::END_EVENT;
+ aEvent.Repeat = 0;
+
+ aBegin <<= aEvent;
+ }
+ else
+ {
+ aBegin <<= 0.0;
+ }
+
+ xAnimate->setBegin( aBegin );
+ xAnimate->setTo( aTo );
+ xAnimate->setAttributeName( aAttributeName );
+
+ xAnimate->setDuration( Any( 0.001 ) );
+ xAnimate->setFill( AnimationFill::HOLD );
+ xAnimate->setTarget( maTarget );
+
+ return xAnimate;
+}
+
+void CustomAnimationEffect::setIterateType( sal_Int16 nIterateType )
+{
+ if( mnIterateType == nIterateType )
+ return;
+
+ try
+ {
+ // do we need to exchange the container node?
+ if( (mnIterateType == 0) || (nIterateType == 0) )
+ {
+ sal_Int16 nTargetSubItem = mnTargetSubItem;
+
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference< XTimeContainer > xNewContainer;
+ if(nIterateType)
+ {
+ xNewContainer.set( IterateContainer::create( xContext ) );
+ }
+ else
+ xNewContainer.set( ParallelTimeContainer::create( xContext ), UNO_QUERY_THROW );
+
+ Reference< XTimeContainer > xOldContainer( mxNode, UNO_QUERY_THROW );
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+ xOldContainer->removeChild( xChildNode );
+ xNewContainer->appendChild( xChildNode );
+ }
+
+ xNewContainer->setBegin( mxNode->getBegin() );
+ xNewContainer->setDuration( mxNode->getDuration() );
+ xNewContainer->setEnd( mxNode->getEnd() );
+ xNewContainer->setEndSync( mxNode->getEndSync() );
+ xNewContainer->setRepeatCount( mxNode->getRepeatCount() );
+ xNewContainer->setFill( mxNode->getFill() );
+ xNewContainer->setFillDefault( mxNode->getFillDefault() );
+ xNewContainer->setRestart( mxNode->getRestart() );
+ xNewContainer->setRestartDefault( mxNode->getRestartDefault() );
+ xNewContainer->setAcceleration( mxNode->getAcceleration() );
+ xNewContainer->setDecelerate( mxNode->getDecelerate() );
+ xNewContainer->setAutoReverse( mxNode->getAutoReverse() );
+ xNewContainer->setRepeatDuration( mxNode->getRepeatDuration() );
+ xNewContainer->setEndSync( mxNode->getEndSync() );
+ xNewContainer->setRepeatCount( mxNode->getRepeatCount() );
+ xNewContainer->setUserData( mxNode->getUserData() );
+
+ mxNode = xNewContainer;
+
+ Any aTarget;
+ if( nIterateType )
+ {
+ Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
+ xIter->setTarget(maTarget);
+ xIter->setSubItem( nTargetSubItem );
+ }
+ else
+ {
+ aTarget = maTarget;
+ }
+
+ Reference< XEnumerationAccess > xEA( mxNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_SET_THROW );
+ while( xE->hasMoreElements() )
+ {
+ Reference< XAnimate > xAnimate( xE->nextElement(), UNO_QUERY );
+ if( xAnimate.is() )
+ {
+ xAnimate->setTarget( aTarget );
+ xAnimate->setSubItem( nTargetSubItem );
+ }
+ }
+ }
+
+ mnIterateType = nIterateType;
+
+ // if we have an iteration container, we must set its type
+ if( mnIterateType )
+ {
+ Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
+ xIter->setIterateType( nIterateType );
+ }
+
+ checkForText();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setIterateType()" );
+ }
+}
+
+void CustomAnimationEffect::setIterateInterval( double fIterateInterval )
+{
+ if( mfIterateInterval == fIterateInterval )
+ return;
+
+ Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
+
+ DBG_ASSERT( xIter.is(), "sd::CustomAnimationEffect::setIterateInterval(), not an iteration node" );
+ if( xIter.is() )
+ {
+ mfIterateInterval = fIterateInterval;
+ xIter->setIterateInterval( fIterateInterval );
+ }
+
+ calculateIterateDuration();
+}
+
+OUString CustomAnimationEffect::getPath() const
+{
+ OUString aPath;
+
+ if( mxNode.is() ) try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
+ if( xMotion.is() )
+ {
+ xMotion->getPath() >>= aPath;
+ break;
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::getPath()" );
+ }
+
+ return aPath;
+}
+
+void CustomAnimationEffect::setPath( const OUString& rPath )
+{
+ if( !mxNode.is() )
+ return;
+
+ try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
+ if( xMotion.is() )
+ {
+
+ MainSequenceChangeGuard aGuard( mpEffectSequence );
+ xMotion->setPath( Any( rPath ) );
+ break;
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setPath()" );
+ }
+}
+
+Any CustomAnimationEffect::getProperty( sal_Int32 nNodeType, std::u16string_view rAttributeName, EValue eValue )
+{
+ Any aProperty;
+ if( mxNode.is() ) try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
+ {
+ Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
+ if( !xAnimate.is() )
+ continue;
+
+ if( xAnimate->getType() == nNodeType )
+ {
+ if( xAnimate->getAttributeName() == rAttributeName )
+ {
+ switch( eValue )
+ {
+ case EValue::To: aProperty = xAnimate->getTo(); break;
+ case EValue::By: aProperty = xAnimate->getBy(); break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::getProperty()" );
+ }
+
+ return aProperty;
+}
+
+bool CustomAnimationEffect::setProperty( sal_Int32 nNodeType, std::u16string_view rAttributeName, EValue eValue, const Any& rValue )
+{
+ bool bChanged = false;
+ if( mxNode.is() ) try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
+ if( !xAnimate.is() )
+ continue;
+
+ if( xAnimate->getType() == nNodeType )
+ {
+ if( xAnimate->getAttributeName() == rAttributeName )
+ {
+ switch( eValue )
+ {
+ case EValue::To:
+ if( xAnimate->getTo() != rValue )
+ {
+ xAnimate->setTo( rValue );
+ bChanged = true;
+ }
+ break;
+ case EValue::By:
+ if( xAnimate->getTo() != rValue )
+ {
+ xAnimate->setBy( rValue );
+ bChanged = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setProperty()" );
+ }
+
+ return bChanged;
+}
+
+static bool implIsColorAttribute( std::u16string_view rAttributeName )
+{
+ return rAttributeName == u"FillColor" || rAttributeName == u"LineColor" || rAttributeName == u"CharColor";
+}
+
+Any CustomAnimationEffect::getColor( sal_Int32 nIndex )
+{
+ Any aColor;
+ if( mxNode.is() ) try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() && !aColor.hasValue() )
+ {
+ Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
+ if( !xAnimate.is() )
+ continue;
+
+ switch( xAnimate->getType() )
+ {
+ case AnimationNodeType::SET:
+ case AnimationNodeType::ANIMATE:
+ if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
+ break;
+ [[fallthrough]];
+ case AnimationNodeType::ANIMATECOLOR:
+ Sequence<Any> aValues( xAnimate->getValues() );
+ if( aValues.hasElements() )
+ {
+ if( aValues.getLength() > nIndex )
+ aColor = aValues[nIndex];
+ }
+ else if( nIndex == 0 )
+ aColor = xAnimate->getFrom();
+ else
+ aColor = xAnimate->getTo();
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::getColor()" );
+ }
+
+ return aColor;
+}
+
+void CustomAnimationEffect::setColor( sal_Int32 nIndex, const Any& rColor )
+{
+ if( !mxNode.is() )
+ return;
+
+ try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
+ if( !xAnimate.is() )
+ continue;
+
+ switch( xAnimate->getType() )
+ {
+ case AnimationNodeType::SET:
+ case AnimationNodeType::ANIMATE:
+ if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
+ break;
+ [[fallthrough]];
+ case AnimationNodeType::ANIMATECOLOR:
+ {
+ Sequence<Any> aValues( xAnimate->getValues() );
+ if( aValues.hasElements() )
+ {
+ if( aValues.getLength() > nIndex )
+ {
+ aValues.getArray()[nIndex] = rColor;
+ xAnimate->setValues( aValues );
+ }
+ }
+ else if( (nIndex == 0) && xAnimate->getFrom().hasValue() )
+ xAnimate->setFrom(rColor);
+ else if( (nIndex == 1) && xAnimate->getTo().hasValue() )
+ xAnimate->setTo(rColor);
+ }
+ break;
+
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setColor()" );
+ }
+}
+
+Any CustomAnimationEffect::getTransformationProperty( sal_Int32 nTransformType, EValue eValue )
+{
+ Any aProperty;
+ if( mxNode.is() ) try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
+ {
+ Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
+ if( !xTransform.is() )
+ continue;
+
+ if( xTransform->getTransformType() == nTransformType )
+ {
+ switch( eValue )
+ {
+ case EValue::To: aProperty = xTransform->getTo(); break;
+ case EValue::By: aProperty = xTransform->getBy(); break;
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::getTransformationProperty()" );
+ }
+
+ return aProperty;
+}
+
+bool CustomAnimationEffect::setTransformationProperty( sal_Int32 nTransformType, EValue eValue, const Any& rValue )
+{
+ bool bChanged = false;
+ if( mxNode.is() ) try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
+ if( !xTransform.is() )
+ continue;
+
+ if( xTransform->getTransformType() == nTransformType )
+ {
+ switch( eValue )
+ {
+ case EValue::To:
+ if( xTransform->getTo() != rValue )
+ {
+ xTransform->setTo( rValue );
+ bChanged = true;
+ }
+ break;
+ case EValue::By:
+ if( xTransform->getBy() != rValue )
+ {
+ xTransform->setBy( rValue );
+ bChanged = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setTransformationProperty()" );
+ }
+
+ return bChanged;
+}
+
+void CustomAnimationEffect::createAudio( const css::uno::Any& rSource )
+{
+ DBG_ASSERT( !mxAudio.is(), "sd::CustomAnimationEffect::createAudio(), node already has an audio!" );
+
+ if( mxAudio.is() )
+ return;
+
+ try
+ {
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference< XAudio > xAudio( Audio::create( xContext ) );
+ xAudio->setSource( rSource );
+ xAudio->setVolume( 1.0 );
+ setAudio( xAudio );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::createAudio()" );
+ }
+}
+
+static Reference< XCommand > findCommandNode( const Reference< XAnimationNode >& xRootNode )
+{
+ Reference< XCommand > xCommand;
+
+ if( xRootNode.is() ) try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( !xCommand.is() && xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( xNode.is() && (xNode->getType() == AnimationNodeType::COMMAND) )
+ xCommand.set( xNode, UNO_QUERY_THROW );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::findCommandNode()" );
+ }
+
+ return xCommand;
+}
+
+void CustomAnimationEffect::removeAudio()
+{
+ try
+ {
+ Reference< XAnimationNode > xChild;
+
+ if( mxAudio.is() )
+ {
+ xChild = mxAudio;
+ mxAudio.clear();
+ }
+ else if( mnCommand == EffectCommands::STOPAUDIO )
+ {
+ xChild = findCommandNode( mxNode );
+ mnCommand = 0;
+ }
+
+ if( xChild.is() )
+ {
+ Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
+ if( xContainer.is() )
+ xContainer->removeChild( xChild );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::removeAudio()" );
+ }
+
+}
+
+void CustomAnimationEffect::setAudio( const Reference< css::animations::XAudio >& xAudio )
+{
+ if( mxAudio == xAudio )
+ return;
+
+ try
+ {
+ removeAudio();
+ mxAudio = xAudio;
+ Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
+ if( xContainer.is() && mxAudio.is() )
+ xContainer->appendChild( mxAudio );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setAudio()" );
+ }
+}
+
+void CustomAnimationEffect::setStopAudio()
+{
+ if( mnCommand == EffectCommands::STOPAUDIO )
+ return;
+
+ try
+ {
+ if( mxAudio.is() )
+ removeAudio();
+
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference< XCommand > xCommand( Command::create( xContext ) );
+
+ xCommand->setCommand( EffectCommands::STOPAUDIO );
+
+ Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY_THROW );
+ xContainer->appendChild( xCommand );
+
+ mnCommand = EffectCommands::STOPAUDIO;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationEffect::setStopAudio()" );
+ }
+}
+
+bool CustomAnimationEffect::getStopAudio() const
+{
+ return mnCommand == EffectCommands::STOPAUDIO;
+}
+
+SdrPathObj* CustomAnimationEffect::createSdrPathObjFromPath(SdrModel& rTargetModel)
+{
+ SdrPathObj * pPathObj = new SdrPathObj(rTargetModel, SdrObjKind::PathLine);
+ updateSdrPathObjFromPath( *pPathObj );
+ return pPathObj;
+}
+
+void CustomAnimationEffect::updateSdrPathObjFromPath( SdrPathObj& rPathObj )
+{
+ ::basegfx::B2DPolyPolygon aPolyPoly;
+ if( ::basegfx::utils::importFromSvgD( aPolyPoly, getPath(), true, nullptr ) )
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(getTargetShape());
+ if( pObj )
+ {
+ SdrPage* pPage = pObj->getSdrPageFromSdrObject();
+ if( pPage )
+ {
+ const Size aPageSize( pPage->GetSize() );
+ aPolyPoly.transform(basegfx::utils::createScaleB2DHomMatrix(static_cast<double>(aPageSize.Width()), static_cast<double>(aPageSize.Height())));
+ }
+
+ const ::tools::Rectangle aBoundRect( pObj->GetCurrentBoundRect() );
+ const Point aCenter( aBoundRect.Center() );
+ aPolyPoly.transform(basegfx::utils::createTranslateB2DHomMatrix(aCenter.X(), aCenter.Y()));
+ }
+ }
+
+ rPathObj.SetPathPoly( aPolyPoly );
+}
+
+void CustomAnimationEffect::updatePathFromSdrPathObj( const SdrPathObj& rPathObj )
+{
+ ::basegfx::B2DPolyPolygon aPolyPoly( rPathObj.GetPathPoly() );
+
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(getTargetShape());
+ if( pObj )
+ {
+ ::tools::Rectangle aBoundRect(0,0,0,0);
+
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitives;
+ pObj->GetViewContact().getViewIndependentPrimitive2DContainer(xPrimitives);
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D));
+
+ if(!aRange.isEmpty())
+ {
+ aBoundRect = ::tools::Rectangle(
+ static_cast<sal_Int32>(floor(aRange.getMinX())), static_cast<sal_Int32>(floor(aRange.getMinY())),
+ static_cast<sal_Int32>(ceil(aRange.getMaxX())), static_cast<sal_Int32>(ceil(aRange.getMaxY())));
+ }
+
+ const Point aCenter( aBoundRect.Center() );
+
+ aPolyPoly.transform(basegfx::utils::createTranslateB2DHomMatrix(-aCenter.X(), -aCenter.Y()));
+
+ SdrPage* pPage = pObj->getSdrPageFromSdrObject();
+ if( pPage )
+ {
+ const Size aPageSize( pPage->GetSize() );
+ aPolyPoly.transform(basegfx::utils::createScaleB2DHomMatrix(
+ 1.0 / static_cast<double>(aPageSize.Width()), 1.0 / static_cast<double>(aPageSize.Height())));
+ }
+ }
+
+ setPath( ::basegfx::utils::exportToSvgD( aPolyPoly, true, true, true) );
+}
+
+EffectSequenceHelper::EffectSequenceHelper()
+: mnSequenceType( EffectNodeType::DEFAULT )
+{
+}
+
+EffectSequenceHelper::EffectSequenceHelper( const css::uno::Reference< css::animations::XTimeContainer >& xSequenceRoot )
+: mxSequenceRoot( xSequenceRoot ), mnSequenceType( EffectNodeType::DEFAULT )
+{
+ Reference< XAnimationNode > xNode( mxSequenceRoot, UNO_QUERY_THROW );
+ create( xNode );
+}
+
+EffectSequenceHelper::~EffectSequenceHelper()
+{
+ reset();
+}
+
+void EffectSequenceHelper::reset()
+{
+ for( CustomAnimationEffectPtr& pEffect : maEffects )
+ {
+ pEffect->setEffectSequence(nullptr);
+ }
+ maEffects.clear();
+}
+
+Reference< XAnimationNode > EffectSequenceHelper::getRootNode()
+{
+ return mxSequenceRoot;
+}
+
+void EffectSequenceHelper::append( const CustomAnimationEffectPtr& pEffect )
+{
+ pEffect->setEffectSequence( this );
+ maEffects.push_back(pEffect);
+ rebuild();
+}
+
+CustomAnimationEffectPtr EffectSequenceHelper::append( const CustomAnimationPresetPtr& pPreset, const Any& rTarget, double fDuration /* = -1.0 */ )
+{
+ CustomAnimationEffectPtr pEffect;
+
+ if( pPreset )
+ {
+ Reference< XAnimationNode > xNode( pPreset->create( "" ) );
+ if( xNode.is() )
+ {
+ // first, filter all only ui relevant user data
+ std::vector< NamedValue > aNewUserData;
+ Sequence< NamedValue > aUserData( xNode->getUserData() );
+
+ std::copy_if(std::cbegin(aUserData), std::cend(aUserData), std::back_inserter(aNewUserData),
+ [](const NamedValue& rProp) { return rProp.Name != "text-only" && rProp.Name != "preset-property"; });
+
+ if( !aNewUserData.empty() )
+ {
+ aUserData = ::comphelper::containerToSequence( aNewUserData );
+ xNode->setUserData( aUserData );
+ }
+
+ // check target, maybe we need to force it to text
+ sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
+
+ if( rTarget.getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ nSubItem = ShapeAnimationSubType::ONLY_TEXT;
+ }
+ else if( pPreset->isTextOnly() )
+ {
+ Reference< XShape > xShape;
+ rTarget >>= xShape;
+ if( xShape.is() )
+ {
+ // that's bad, we target a shape here but the effect is only for text
+ // so change subitem
+ nSubItem = ShapeAnimationSubType::ONLY_TEXT;
+ }
+ }
+
+ // now create effect from preset
+ pEffect = std::make_shared<CustomAnimationEffect>( xNode );
+ pEffect->setEffectSequence( this );
+ pEffect->setTarget( rTarget );
+ pEffect->setTargetSubItem( nSubItem );
+ if( fDuration != -1.0 )
+ pEffect->setDuration( fDuration );
+
+ maEffects.push_back(pEffect);
+
+ rebuild();
+ }
+ }
+
+ DBG_ASSERT( pEffect, "sd::EffectSequenceHelper::append(), failed!" );
+ return pEffect;
+}
+
+CustomAnimationEffectPtr EffectSequenceHelper::append( const SdrPathObj& rPathObj, const Any& rTarget, double fDuration /* = -1.0 */, const OUString& rPresetId )
+{
+ CustomAnimationEffectPtr pEffect;
+
+ if( fDuration <= 0.0 )
+ fDuration = 2.0;
+
+ try
+ {
+ Reference< XTimeContainer > xEffectContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW );
+ Reference< XAnimationNode > xAnimateMotion( AnimateMotion::create( ::comphelper::getProcessComponentContext() ) );
+
+ xAnimateMotion->setDuration( Any( fDuration ) );
+ xAnimateMotion->setFill( AnimationFill::HOLD );
+ xEffectContainer->appendChild( xAnimateMotion );
+
+ sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
+
+ if( rTarget.getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ nSubItem = ShapeAnimationSubType::ONLY_TEXT;
+
+ pEffect = std::make_shared<CustomAnimationEffect>( xEffectContainer );
+ pEffect->setEffectSequence( this );
+ pEffect->setTarget( rTarget );
+ pEffect->setTargetSubItem( nSubItem );
+ pEffect->setNodeType( css::presentation::EffectNodeType::ON_CLICK );
+ pEffect->setPresetClassAndId( css::presentation::EffectPresetClass::MOTIONPATH, rPresetId );
+ pEffect->setAcceleration( 0.5 );
+ pEffect->setDecelerate( 0.5 );
+ pEffect->setFill( AnimationFill::HOLD );
+ pEffect->setBegin( 0.0 );
+ pEffect->updatePathFromSdrPathObj( rPathObj );
+ if( fDuration != -1.0 )
+ pEffect->setDuration( fDuration );
+
+ maEffects.push_back(pEffect);
+
+ rebuild();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::EffectSequenceHelper::append()" );
+ }
+
+ return pEffect;
+}
+
+void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, const OUString& rPresetSubType, double fDuration /* = -1.0 */ )
+{
+ if( !(pEffect && pPreset) )
+ return;
+
+ try
+ {
+ Reference< XAnimationNode > xNewNode( pPreset->create( rPresetSubType ) );
+ if( xNewNode.is() )
+ {
+ pEffect->replaceNode( xNewNode );
+ if( fDuration != -1.0 )
+ pEffect->setDuration( fDuration );
+ }
+
+ rebuild();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::EffectSequenceHelper::replace()" );
+ }
+}
+
+void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, double fDuration /* = -1.0 */ )
+{
+ replace( pEffect, pPreset, "", fDuration );
+}
+
+void EffectSequenceHelper::remove( const CustomAnimationEffectPtr& pEffect )
+{
+ if( pEffect )
+ {
+ pEffect->setEffectSequence( nullptr );
+ maEffects.remove( pEffect );
+ }
+
+ rebuild();
+}
+
+void EffectSequenceHelper::moveToBeforeEffect( const CustomAnimationEffectPtr& pEffect, const CustomAnimationEffectPtr& pInsertBefore)
+{
+ if ( pEffect )
+ {
+ maEffects.remove( pEffect );
+ EffectSequence::iterator aInsertIter( find( pInsertBefore ) );
+
+ // aInsertIter being end() is OK: pInsertBefore could be null, so put at end.
+ maEffects.insert( aInsertIter, pEffect );
+
+ rebuild();
+ }
+}
+
+void EffectSequenceHelper::rebuild()
+{
+ implRebuild();
+}
+
+void EffectSequenceHelper::implRebuild()
+{
+ try
+ {
+ // first we delete all time containers on the first two levels
+ Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+ Reference< XTimeContainer > xChildContainer( xChildNode, UNO_QUERY_THROW );
+
+ Reference< XEnumerationAccess > xChildEnumerationAccess( xChildNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xChildEnumeration( xChildEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( xChildEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xNode( xChildEnumeration->nextElement(), UNO_QUERY_THROW );
+ xChildContainer->removeChild( xNode );
+ }
+
+ mxSequenceRoot->removeChild( xChildNode );
+ }
+
+ // second, rebuild main sequence
+ EffectSequence::iterator aIter( maEffects.begin() );
+ EffectSequence::iterator aEnd( maEffects.end() );
+ if( aIter != aEnd )
+ {
+ std::vector< sd::AfterEffectNode > aAfterEffects;
+
+ CustomAnimationEffectPtr pEffect = *aIter++;
+
+ bool bFirst = true;
+ do
+ {
+ // create a par container for the next click node and all following with and after effects
+ Reference< XTimeContainer > xOnClickContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW );
+
+ Event aEvent;
+ if( mxEventSource.is() )
+ {
+ aEvent.Source <<= mxEventSource;
+ aEvent.Trigger = EventTrigger::ON_CLICK;
+ }
+ else
+ {
+ aEvent.Trigger = EventTrigger::ON_NEXT;
+ }
+ aEvent.Repeat = 0;
+
+ Any aBegin( aEvent );
+ if( bFirst )
+ {
+ // if the first node is not a click action, this click container
+ // must not have INDEFINITE begin but start at 0s
+ bFirst = false;
+ if( pEffect->getNodeType() != EffectNodeType::ON_CLICK )
+ aBegin <<= 0.0;
+ }
+
+ xOnClickContainer->setBegin( aBegin );
+
+ mxSequenceRoot->appendChild( xOnClickContainer );
+
+ double fBegin = 0.0;
+
+ do
+ {
+ // create a par container for the current click or after effect node and all following with effects
+ Reference< XTimeContainer > xWithContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW );
+ xWithContainer->setBegin( Any( fBegin ) );
+ xOnClickContainer->appendChild( xWithContainer );
+
+ double fDuration = 0.0;
+ do
+ {
+ Reference< XAnimationNode > xEffectNode( pEffect->getNode() );
+ xWithContainer->appendChild( xEffectNode );
+
+ if( pEffect->hasAfterEffect() )
+ {
+ Reference< XAnimationNode > xAfterEffect( pEffect->createAfterEffectNode() );
+ AfterEffectNode a( xAfterEffect, xEffectNode, pEffect->IsAfterEffectOnNext() );
+ aAfterEffects.push_back( a );
+ }
+
+ double fTemp = pEffect->getBegin() + pEffect->getAbsoluteDuration();
+ if( fTemp > fDuration )
+ fDuration = fTemp;
+
+ if( aIter != aEnd )
+ pEffect = *aIter++;
+ else
+ pEffect.reset();
+ }
+ while( pEffect && (pEffect->getNodeType() == EffectNodeType::WITH_PREVIOUS) );
+
+ fBegin += fDuration;
+ }
+ while( pEffect && (pEffect->getNodeType() != EffectNodeType::ON_CLICK) );
+ }
+ while( pEffect );
+
+ // process after effect nodes
+ std::for_each( aAfterEffects.begin(), aAfterEffects.end(), stl_process_after_effect_node_func );
+
+ updateTextGroups();
+
+ // reset duration, might have been altered (see below)
+ mxSequenceRoot->setDuration( Any() );
+ }
+ else
+ {
+ // empty sequence, set duration to 0.0 explicitly
+ // (otherwise, this sequence will never end)
+ mxSequenceRoot->setDuration( Any(0.0) );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::EffectSequenceHelper::rebuild()" );
+ }
+}
+
+stl_CustomAnimationEffect_search_node_predict::stl_CustomAnimationEffect_search_node_predict( const css::uno::Reference< css::animations::XAnimationNode >& xSearchNode )
+: mxSearchNode( xSearchNode )
+{
+}
+
+bool stl_CustomAnimationEffect_search_node_predict::operator()( const CustomAnimationEffectPtr& pEffect ) const
+{
+ return pEffect->getNode() == mxSearchNode;
+}
+
+/// @throws Exception
+static bool implFindNextContainer( Reference< XTimeContainer > const & xParent, Reference< XTimeContainer > const & xCurrent, Reference< XTimeContainer >& xNext )
+{
+ Reference< XEnumerationAccess > xEnumerationAccess( xParent, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration() );
+ if( xEnumeration.is() )
+ {
+ Reference< XInterface > x;
+ while( xEnumeration->hasMoreElements() && !xNext.is() )
+ {
+ if( (xEnumeration->nextElement() >>= x) && (x == xCurrent) )
+ {
+ if( xEnumeration->hasMoreElements() )
+ xEnumeration->nextElement() >>= xNext;
+ }
+ }
+ }
+ return xNext.is();
+}
+
+void stl_process_after_effect_node_func(AfterEffectNode const & rNode)
+{
+ try
+ {
+ if( rNode.mxNode.is() && rNode.mxMaster.is() )
+ {
+ // set master node
+ Reference< XAnimationNode > xMasterNode( rNode.mxMaster, UNO_SET_THROW );
+ Sequence< NamedValue > aUserData( rNode.mxNode->getUserData() );
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "master-element";
+ pUserData[nSize].Value <<= xMasterNode;
+ rNode.mxNode->setUserData( aUserData );
+
+ // insert after effect node into timeline
+ Reference< XTimeContainer > xContainer( rNode.mxMaster->getParent(), UNO_QUERY_THROW );
+
+ if( !rNode.mbOnNextEffect ) // sameClick
+ {
+ // insert the aftereffect after its effect is animated
+ xContainer->insertAfter( rNode.mxNode, rNode.mxMaster );
+ }
+ else // nextClick
+ {
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ // insert the aftereffect in the next group
+
+ Reference< XTimeContainer > xClickContainer( xContainer->getParent(), UNO_QUERY_THROW );
+ Reference< XTimeContainer > xSequenceContainer( xClickContainer->getParent(), UNO_QUERY_THROW );
+
+ Reference< XTimeContainer > xNextContainer;
+
+ // first try if we have an after effect container
+ if( !implFindNextContainer( xClickContainer, xContainer, xNextContainer ) )
+ {
+ Reference< XTimeContainer > xNextClickContainer;
+ // if not, try to find the next click effect container
+ if( implFindNextContainer( xSequenceContainer, xClickContainer, xNextClickContainer ) )
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( xNextClickContainer, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ if( xEnumeration->hasMoreElements() )
+ {
+ // the next container is the first child container
+ xEnumeration->nextElement() >>= xNextContainer;
+ }
+ else
+ {
+ // this does not yet have a child container, create one
+ xNextContainer.set( ParallelTimeContainer::create(xContext), UNO_QUERY_THROW );
+
+ xNextContainer->setBegin( Any( 0.0 ) );
+ xNextClickContainer->appendChild( xNextContainer );
+ }
+ DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not find/create container!" );
+ }
+ }
+
+ // if we don't have a next container, we add one to the sequence container
+ if( !xNextContainer.is() )
+ {
+ Reference< XTimeContainer > xNewClickContainer( ParallelTimeContainer::create( xContext ), UNO_QUERY_THROW );
+
+ Event aEvent;
+ aEvent.Trigger = EventTrigger::ON_NEXT;
+ aEvent.Repeat = 0;
+ xNewClickContainer->setBegin( Any( aEvent ) );
+
+ xSequenceContainer->insertAfter( xNewClickContainer, xClickContainer );
+
+ xNextContainer.set( ParallelTimeContainer::create( xContext ), UNO_QUERY_THROW );
+
+ xNextContainer->setBegin( Any( 0.0 ) );
+ xNewClickContainer->appendChild( xNextContainer );
+ }
+
+ if( xNextContainer.is() )
+ {
+ // find begin time of first element
+ Reference< XEnumerationAccess > xEnumerationAccess( xNextContainer, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ if( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChild;
+ // the next container is the first child container
+ xEnumeration->nextElement() >>= xChild;
+ if( xChild.is() )
+ {
+ Any aBegin( xChild->getBegin() );
+ double fBegin = 0.0;
+ if( (aBegin >>= fBegin) && (fBegin >= 0.0))
+ rNode.mxNode->setBegin( aBegin );
+ }
+ }
+
+ xNextContainer->appendChild( rNode.mxNode );
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "ppt::stl_process_after_effect_node_func::operator()" );
+ }
+}
+
+EffectSequence::iterator EffectSequenceHelper::find( const CustomAnimationEffectPtr& pEffect )
+{
+ return std::find( maEffects.begin(), maEffects.end(), pEffect );
+}
+
+CustomAnimationEffectPtr EffectSequenceHelper::findEffect( const css::uno::Reference< css::animations::XAnimationNode >& xNode ) const
+{
+ CustomAnimationEffectPtr pEffect;
+
+ EffectSequence::const_iterator aIter = std::find_if(maEffects.begin(), maEffects.end(),
+ [&xNode](const CustomAnimationEffectPtr& rxEffect) { return rxEffect->getNode() == xNode; });
+ if (aIter != maEffects.end())
+ pEffect = *aIter;
+
+ return pEffect;
+}
+
+sal_Int32 EffectSequenceHelper::getOffsetFromEffect( const CustomAnimationEffectPtr& xEffect ) const
+{
+ auto aIter = std::find(maEffects.begin(), maEffects.end(), xEffect);
+ if (aIter != maEffects.end())
+ return static_cast<sal_Int32>(std::distance(maEffects.begin(), aIter));
+
+ return -1;
+}
+
+CustomAnimationEffectPtr EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset ) const
+{
+ EffectSequence::const_iterator aIter( maEffects.begin() );
+ nOffset = std::min(nOffset, static_cast<sal_Int32>(maEffects.size()));
+ std::advance(aIter, nOffset);
+
+ CustomAnimationEffectPtr pEffect;
+ if( aIter != maEffects.end() )
+ pEffect = *aIter;
+
+ return pEffect;
+}
+
+bool EffectSequenceHelper::disposeShape( const Reference< XShape >& xShape )
+{
+ bool bChanges = false;
+
+ EffectSequence::iterator aIter( maEffects.begin() );
+ while( aIter != maEffects.end() )
+ {
+ if( (*aIter)->getTargetShape() == xShape )
+ {
+ (*aIter)->setEffectSequence( nullptr );
+ bChanges = true;
+ aIter = maEffects.erase( aIter );
+ }
+ else
+ {
+ ++aIter;
+ }
+ }
+
+ return bChanges;
+}
+
+bool EffectSequenceHelper::hasEffect( const css::uno::Reference< css::drawing::XShape >& xShape )
+{
+ return std::any_of(maEffects.begin(), maEffects.end(),
+ [&xShape](const CustomAnimationEffectPtr& rxEffect) { return rxEffect->getTargetShape() == xShape; });
+}
+
+bool EffectSequenceHelper::getParagraphNumberingLevels( const Reference< XShape >& xShape, std::vector< sal_Int32 >& rParagraphNumberingLevel )
+{
+ rParagraphNumberingLevel.clear();
+
+ if( !hasEffect( xShape ) )
+ return false;
+
+ Reference< XText > xText( xShape, UNO_QUERY );
+ if( xText.is() )
+ {
+ Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
+ if( xEA.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEA->createEnumeration();
+
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XPropertySet > xParaSet;
+ xEnumeration->nextElement() >>= xParaSet;
+
+ sal_Int32 nParaDepth = 0;
+ if( xParaSet.is() )
+ {
+ xParaSet->getPropertyValue( "NumberingLevel" ) >>= nParaDepth;
+ }
+
+ rParagraphNumberingLevel.push_back( nParaDepth );
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+void EffectSequenceHelper::insertTextRange( const css::uno::Any& aTarget )
+{
+ ParagraphTarget aParaTarget;
+ if( !(aTarget >>= aParaTarget ) )
+ return;
+
+ // get map [paragraph index] -> [NumberingLevel]
+ // for following reusage inside all animation effects
+ std::vector< sal_Int32 > paragraphNumberingLevel;
+ std::vector< sal_Int32 >* paragraphNumberingLevelParam = nullptr;
+ if ( getParagraphNumberingLevels( aParaTarget.Shape, paragraphNumberingLevel ) )
+ paragraphNumberingLevelParam = &paragraphNumberingLevel;
+
+ // update internal flags for each animation effect
+ const bool bChanges = std::accumulate(maEffects.begin(), maEffects.end(), false,
+ [&aParaTarget, &paragraphNumberingLevelParam](const bool bCheck, const CustomAnimationEffectPtr& rxEffect) {
+ bool bRes = bCheck;
+ if (rxEffect->getTargetShape() == aParaTarget.Shape)
+ bRes |= rxEffect->checkForText( paragraphNumberingLevelParam );
+ return bRes;
+ });
+
+ if( bChanges )
+ rebuild();
+}
+
+static bool isParagraphTargetTextEmpty( ParagraphTarget aParaTarget )
+{
+ // get paragraph
+ Reference< XText > xText ( aParaTarget.Shape, UNO_QUERY );
+ if( xText.is() )
+ {
+ Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
+ if( xEA.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEA->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ // advance to the Nth paragraph
+ sal_Int32 nPara = aParaTarget.Paragraph;
+ while( xEnumeration->hasMoreElements() && nPara-- )
+ xEnumeration->nextElement();
+
+ // get Nth paragraph's text and check if it's empty
+ if( xEnumeration->hasMoreElements() )
+ {
+ Reference< XTextRange > xRange( xEnumeration->nextElement(), UNO_QUERY );
+ if( xRange.is() )
+ {
+ OUString text = xRange->getString();
+ return text.isEmpty();
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void EffectSequenceHelper::disposeTextRange( const css::uno::Any& aTarget )
+{
+ ParagraphTarget aParaTarget;
+ if( !(aTarget >>= aParaTarget ) )
+ return;
+
+ bool bChanges = false;
+
+ // building list of effects for target shape; process effects not on target shape
+ EffectSequence aTargetParagraphEffects;
+ for( const auto &pEffect : maEffects )
+ {
+ Any aIterTarget( pEffect->getTarget() );
+ if( aIterTarget.getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ ParagraphTarget aIterParaTarget;
+ if( (aIterTarget >>= aIterParaTarget) && (aIterParaTarget.Shape == aParaTarget.Shape) )
+ {
+ aTargetParagraphEffects.push_back(pEffect);
+ }
+ }
+ else if( pEffect->getTargetShape() == aParaTarget.Shape )
+ {
+ bChanges |= pEffect->checkForText();
+ }
+ }
+
+ // select effect to delete:
+ // if paragraph before target is blank, then delete its animation effect (if any) instead
+ ParagraphTarget aPreviousParagraph = aParaTarget;
+ --aPreviousParagraph.Paragraph;
+ bool bIsPreviousParagraphEmpty = isParagraphTargetTextEmpty( aPreviousParagraph );
+ sal_Int16 anParaNumToDelete = bIsPreviousParagraphEmpty ? aPreviousParagraph.Paragraph : aParaTarget.Paragraph;
+
+ // update effects
+ for( const auto &pEffect : aTargetParagraphEffects )
+ {
+ Any aIterTarget( pEffect->getTarget() );
+
+ ParagraphTarget aIterParaTarget;
+ aIterTarget >>= aIterParaTarget;
+
+ // delete effect for target paragraph (may have effects in more than one text group)
+ if( aIterParaTarget.Paragraph == anParaNumToDelete )
+ {
+ auto aItr = find( pEffect );
+ DBG_ASSERT( aItr != maEffects.end(), "sd::EffectSequenceHelper::disposeTextRange(), Expected effect missing.");
+ if( aItr != maEffects.end() )
+ {
+ (*aItr)->setEffectSequence( nullptr );
+ maEffects.erase(aItr);
+ bChanges = true;
+ }
+ }
+
+ // shift all paragraphs after disposed paragraph
+ if( aIterParaTarget.Paragraph > anParaNumToDelete )
+ {
+ --aIterParaTarget.Paragraph;
+ pEffect->setTarget( Any( aIterParaTarget ) );
+ bChanges = true;
+ }
+ }
+
+ if( bChanges )
+ {
+ rebuild();
+ }
+}
+
+CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference< XShape >& rTarget, sal_Int32 nGroupId )
+: maTarget( rTarget ),
+ mnGroupId( nGroupId )
+{
+ reset();
+}
+
+void CustomAnimationTextGroup::reset()
+{
+ mnTextGrouping = -1;
+ mbAnimateForm = false;
+ mbTextReverse = false;
+ mfGroupingAuto = -1.0;
+ mnLastPara = -1; // used to check for TextReverse
+
+ for (sal_Int8 & rn : mnDepthFlags)
+ {
+ rn = 0;
+ }
+
+ maEffects.clear();
+}
+
+void CustomAnimationTextGroup::addEffect( CustomAnimationEffectPtr const & pEffect )
+{
+ maEffects.push_back( pEffect );
+
+ Any aTarget( pEffect->getTarget() );
+ if( aTarget.getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ // now look at the paragraph
+ ParagraphTarget aParaTarget;
+ aTarget >>= aParaTarget;
+
+ if( mnLastPara != -1 )
+ mbTextReverse = mnLastPara > aParaTarget.Paragraph;
+
+ mnLastPara = aParaTarget.Paragraph;
+
+ const sal_Int32 nParaDepth = pEffect->getParaDepth();
+
+ // only look at the first PARA_LEVELS levels
+ if( nParaDepth < PARA_LEVELS )
+ {
+ // our first paragraph with this level?
+ if( mnDepthFlags[nParaDepth] == 0 )
+ {
+ // so set it to the first found
+ mnDepthFlags[nParaDepth] = static_cast<sal_Int8>(pEffect->getNodeType());
+ }
+ else if( mnDepthFlags[nParaDepth] != pEffect->getNodeType() )
+ {
+ mnDepthFlags[nParaDepth] = -1;
+ }
+
+ if( pEffect->getNodeType() == EffectNodeType::AFTER_PREVIOUS )
+ mfGroupingAuto = pEffect->getBegin();
+
+ mnTextGrouping = PARA_LEVELS;
+ while( (mnTextGrouping > 0)
+ && (mnDepthFlags[mnTextGrouping - 1] <= 0) )
+ --mnTextGrouping;
+ }
+ }
+ else
+ {
+ // if we have an effect with the shape as a target, we animate the background
+ mbAnimateForm = pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_TEXT;
+ }
+}
+
+CustomAnimationTextGroupPtr EffectSequenceHelper::findGroup( sal_Int32 nGroupId )
+{
+ CustomAnimationTextGroupPtr aPtr;
+
+ CustomAnimationTextGroupMap::iterator aIter( maGroupMap.find( nGroupId ) );
+ if( aIter != maGroupMap.end() )
+ aPtr = (*aIter).second;
+
+ return aPtr;
+}
+
+void EffectSequenceHelper::updateTextGroups()
+{
+ maGroupMap.clear();
+
+ // first create all the groups
+ for( const CustomAnimationEffectPtr& pEffect : maEffects )
+ {
+ const sal_Int32 nGroupId = pEffect->getGroupId();
+
+ if( nGroupId == -1 )
+ continue; // trivial case, no group
+
+ CustomAnimationTextGroupPtr pGroup = findGroup( nGroupId );
+ if( !pGroup )
+ {
+ pGroup = std::make_shared<CustomAnimationTextGroup>( pEffect->getTargetShape(), nGroupId );
+ maGroupMap[nGroupId] = pGroup;
+ }
+
+ pGroup->addEffect( pEffect );
+ }
+
+ // Now that all the text groups have been cleared up and rebuilt, we need to update its
+ // text grouping. addEffect() already make mnTextGrouping the last possible level,
+ // so just continue to find the last level that is not EffectNodeType::WITH_PREVIOUS.
+ for(const auto &rGroupMapItem: maGroupMap)
+ {
+ const CustomAnimationTextGroupPtr &pGroup = rGroupMapItem.second;
+ while(pGroup->mnTextGrouping > 0 && pGroup->mnDepthFlags[pGroup->mnTextGrouping - 1] == EffectNodeType::WITH_PREVIOUS)
+ --pGroup->mnTextGrouping;
+ }
+}
+
+CustomAnimationTextGroupPtr
+EffectSequenceHelper::createTextGroup(const CustomAnimationEffectPtr& pEffect,
+ sal_Int32 nTextGrouping, double fTextGroupingAuto,
+ bool bAnimateForm, bool bTextReverse)
+{
+ // first find a free group-id
+ sal_Int32 nGroupId = 0;
+
+ CustomAnimationTextGroupMap::iterator aIter( maGroupMap.begin() );
+ const CustomAnimationTextGroupMap::iterator aEnd( maGroupMap.end() );
+ while( aIter != aEnd )
+ {
+ if( (*aIter).first == nGroupId )
+ {
+ nGroupId++;
+ aIter = maGroupMap.begin();
+ }
+ else
+ {
+ ++aIter;
+ }
+ }
+
+ Reference< XShape > xTarget( pEffect->getTargetShape() );
+
+ CustomAnimationTextGroupPtr pTextGroup = std::make_shared<CustomAnimationTextGroup>( xTarget, nGroupId );
+ maGroupMap[nGroupId] = pTextGroup;
+
+ bool bUsed = false;
+
+ // do we need to target the shape?
+ if( (nTextGrouping == 0) || bAnimateForm )
+ {
+ sal_Int16 nSubItem;
+ if( nTextGrouping == 0)
+ nSubItem = bAnimateForm ? ShapeAnimationSubType::AS_WHOLE : ShapeAnimationSubType::ONLY_TEXT;
+ else
+ nSubItem = ShapeAnimationSubType::ONLY_BACKGROUND;
+
+ pEffect->setTarget( Any( xTarget ) );
+ pEffect->setTargetSubItem( nSubItem );
+ pEffect->setEffectSequence( this );
+ pEffect->setGroupId( nGroupId );
+
+ pTextGroup->addEffect( pEffect );
+ bUsed = true;
+ }
+
+ pTextGroup->mnTextGrouping = nTextGrouping;
+ pTextGroup->mfGroupingAuto = fTextGroupingAuto;
+ pTextGroup->mbTextReverse = bTextReverse;
+
+ // now add an effect for each paragraph
+ createTextGroupParagraphEffects( pTextGroup, pEffect, bUsed );
+
+ notify_listeners();
+
+ return pTextGroup;
+}
+
+void EffectSequenceHelper::createTextGroupParagraphEffects( const CustomAnimationTextGroupPtr& pTextGroup, const CustomAnimationEffectPtr& pEffect, bool bUsed )
+{
+ Reference< XShape > xTarget( pTextGroup->maTarget );
+
+ sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
+ double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
+ bool bTextReverse = pTextGroup->mbTextReverse;
+
+ // now add an effect for each paragraph
+ if( nTextGrouping < 0 )
+ return;
+
+ try
+ {
+ EffectSequence::iterator aInsertIter( find( pEffect ) );
+
+ Reference< XEnumerationAccess > xText( xTarget, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_SET_THROW );
+
+ std::deque< sal_Int16 > aParaList;
+ sal_Int16 nPara;
+
+ // fill the list with all valid paragraphs
+ for( nPara = 0; xEnumeration->hasMoreElements(); nPara++ )
+ {
+ Reference< XTextRange > xRange( xEnumeration->nextElement(), UNO_QUERY );
+ if( xRange.is() && !xRange->getString().isEmpty() )
+ {
+ if( bTextReverse ) // sort them
+ aParaList.push_front( nPara );
+ else
+ aParaList.push_back( nPara );
+ }
+ }
+
+ ParagraphTarget aTarget;
+ aTarget.Shape = xTarget;
+
+ for( const auto i : aParaList )
+ {
+ aTarget.Paragraph = i;
+
+ CustomAnimationEffectPtr pNewEffect;
+ if( bUsed )
+ {
+ // clone a new effect from first effect
+ pNewEffect = pEffect->clone();
+ ++aInsertIter;
+ aInsertIter = maEffects.insert( aInsertIter, pNewEffect );
+ }
+ else
+ {
+ // reuse first effect if it's not yet used
+ pNewEffect = pEffect;
+ bUsed = true;
+ aInsertIter = find( pNewEffect );
+ }
+
+ // set target and group-id
+ pNewEffect->setTarget( Any( aTarget ) );
+ pNewEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
+ pNewEffect->setGroupId( pTextGroup->mnGroupId );
+ pNewEffect->setEffectSequence( this );
+
+ // set correct node type
+ if( pNewEffect->getParaDepth() < nTextGrouping )
+ {
+ if( fTextGroupingAuto == -1.0 )
+ {
+ pNewEffect->setNodeType( EffectNodeType::ON_CLICK );
+ pNewEffect->setBegin( 0.0 );
+ }
+ else
+ {
+ pNewEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
+ pNewEffect->setBegin( fTextGroupingAuto );
+ }
+ }
+ else
+ {
+ pNewEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
+ pNewEffect->setBegin( 0.0 );
+ }
+
+ pTextGroup->addEffect( pNewEffect );
+ }
+ notify_listeners();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::EffectSequenceHelper::createTextGroup()" );
+ }
+}
+
+void EffectSequenceHelper::setTextGrouping( const CustomAnimationTextGroupPtr& pTextGroup, sal_Int32 nTextGrouping )
+{
+ if( pTextGroup->mnTextGrouping == nTextGrouping )
+ {
+ // first case, trivial case, do nothing
+ }
+ else if( (pTextGroup->mnTextGrouping == -1) && (nTextGrouping >= 0) )
+ {
+ // second case, we need to add new effects for each paragraph
+
+ CustomAnimationEffectPtr pEffect( pTextGroup->maEffects.front() );
+
+ pTextGroup->mnTextGrouping = nTextGrouping;
+ createTextGroupParagraphEffects( pTextGroup, pEffect, true );
+ notify_listeners();
+ }
+ else if( (pTextGroup->mnTextGrouping >= 0) && (nTextGrouping == -1 ) )
+ {
+ // third case, we need to remove effects for each paragraph
+
+ EffectSequence aEffects( pTextGroup->maEffects );
+ pTextGroup->reset();
+
+ for( const CustomAnimationEffectPtr& pEffect : aEffects )
+ {
+ if( pEffect->getTarget().getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ remove( pEffect );
+ else
+ pTextGroup->addEffect( pEffect );
+ }
+ notify_listeners();
+ }
+ else
+ {
+ // fourth case, we need to change the node types for the text nodes
+ double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
+
+ EffectSequence aEffects( pTextGroup->maEffects );
+ pTextGroup->reset();
+
+ for( CustomAnimationEffectPtr& pEffect : aEffects )
+ {
+ if( pEffect->getTarget().getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ // set correct node type
+ if( pEffect->getParaDepth() < nTextGrouping )
+ {
+ if( fTextGroupingAuto == -1.0 )
+ {
+ pEffect->setNodeType( EffectNodeType::ON_CLICK );
+ pEffect->setBegin( 0.0 );
+ }
+ else
+ {
+ pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
+ pEffect->setBegin( fTextGroupingAuto );
+ }
+ }
+ else
+ {
+ pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
+ pEffect->setBegin( 0.0 );
+ }
+ }
+
+ pTextGroup->addEffect( pEffect );
+
+ }
+ notify_listeners();
+ }
+}
+
+void EffectSequenceHelper::setAnimateForm( const CustomAnimationTextGroupPtr& pTextGroup, bool bAnimateForm )
+{
+ if( pTextGroup->mbAnimateForm == bAnimateForm )
+ {
+ // trivial case, do nothing
+ }
+ else
+ {
+ EffectSequence aEffects( pTextGroup->maEffects );
+ pTextGroup->reset();
+
+ SAL_WARN_IF(aEffects.empty(), "sd", "EffectSequenceHelper::setAnimateForm effects empty" );
+
+ if (aEffects.empty())
+ return;
+
+ EffectSequence::iterator aIter( aEffects.begin() );
+ const EffectSequence::iterator aEnd( aEffects.end() );
+
+ // first insert if we have to
+ if( bAnimateForm )
+ {
+ EffectSequence::iterator aInsertIter( find( *aIter ) );
+
+ CustomAnimationEffectPtr pEffect;
+ if( (aEffects.size() == 1) && ((*aIter)->getTarget().getValueType() != ::cppu::UnoType<ParagraphTarget>::get() ) )
+ {
+ // special case, only one effect and that targets whole text,
+ // convert this to target whole shape
+ pEffect = *aIter++;
+ pEffect->setTargetSubItem( ShapeAnimationSubType::AS_WHOLE );
+ }
+ else
+ {
+ pEffect = (*aIter)->clone();
+ pEffect->setTarget( Any( (*aIter)->getTargetShape() ) );
+ pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_BACKGROUND );
+ maEffects.insert( aInsertIter, pEffect );
+ }
+
+ pTextGroup->addEffect( pEffect );
+ }
+
+ if( !bAnimateForm && (aEffects.size() == 1) )
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ pEffect->setTarget( Any( (*aIter)->getTargetShape() ) );
+ pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
+ pTextGroup->addEffect( pEffect );
+ }
+ else
+ {
+ // read the rest to the group again
+ while( aIter != aEnd )
+ {
+ CustomAnimationEffectPtr pEffect( *aIter++ );
+
+ if( pEffect->getTarget().getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ pTextGroup->addEffect( pEffect );
+ }
+ else
+ {
+ DBG_ASSERT( !bAnimateForm, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" );
+ remove( pEffect );
+ }
+ }
+ }
+ notify_listeners();
+ }
+}
+
+void EffectSequenceHelper::setTextGroupingAuto( const CustomAnimationTextGroupPtr& pTextGroup, double fTextGroupingAuto )
+{
+ sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
+
+ EffectSequence aEffects( pTextGroup->maEffects );
+ pTextGroup->reset();
+
+ for( CustomAnimationEffectPtr& pEffect : aEffects )
+ {
+ if( pEffect->getTarget().getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ // set correct node type
+ if( pEffect->getParaDepth() < nTextGrouping )
+ {
+ if( fTextGroupingAuto == -1.0 )
+ {
+ pEffect->setNodeType( EffectNodeType::ON_CLICK );
+ pEffect->setBegin( 0.0 );
+ }
+ else
+ {
+ pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
+ pEffect->setBegin( fTextGroupingAuto );
+ }
+ }
+ else
+ {
+ pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
+ pEffect->setBegin( 0.0 );
+ }
+ }
+
+ pTextGroup->addEffect( pEffect );
+
+ }
+ notify_listeners();
+}
+
+namespace {
+
+struct ImplStlTextGroupSortHelper
+{
+ explicit ImplStlTextGroupSortHelper( bool bReverse ) : mbReverse( bReverse ) {};
+ bool operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 );
+ bool mbReverse;
+ sal_Int32 getTargetParagraph( const CustomAnimationEffectPtr& p1 );
+};
+
+}
+
+sal_Int32 ImplStlTextGroupSortHelper::getTargetParagraph( const CustomAnimationEffectPtr& p1 )
+{
+ const Any aTarget(p1->getTarget());
+ if( aTarget.hasValue() && aTarget.getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ ParagraphTarget aParaTarget;
+ aTarget >>= aParaTarget;
+ return aParaTarget.Paragraph;
+ }
+ else
+ {
+ return mbReverse ? 0x7fffffff : -1;
+ }
+}
+
+bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 )
+{
+ if( mbReverse )
+ {
+ return getTargetParagraph( p2 ) < getTargetParagraph( p1 );
+ }
+ else
+ {
+ return getTargetParagraph( p1 ) < getTargetParagraph( p2 );
+ }
+}
+
+void EffectSequenceHelper::setTextReverse( const CustomAnimationTextGroupPtr& pTextGroup, bool bTextReverse )
+{
+ if( pTextGroup->mbTextReverse == bTextReverse )
+ {
+ // do nothing
+ }
+ else
+ {
+ std::vector< CustomAnimationEffectPtr > aSortedVector( pTextGroup->maEffects.begin(), pTextGroup->maEffects.end() );
+ ImplStlTextGroupSortHelper aSortHelper( bTextReverse );
+ std::sort( aSortedVector.begin(), aSortedVector.end(), aSortHelper );
+
+ pTextGroup->reset();
+
+ std::vector< CustomAnimationEffectPtr >::iterator aIter( aSortedVector.begin() );
+ const std::vector< CustomAnimationEffectPtr >::iterator aEnd( aSortedVector.end() );
+
+ if( aIter != aEnd )
+ {
+ pTextGroup->addEffect( *aIter );
+ EffectSequence::iterator aInsertIter( find( *aIter++ ) );
+ while( aIter != aEnd )
+ {
+ CustomAnimationEffectPtr pEffect( *aIter++ );
+ maEffects.erase( find( pEffect ) );
+ aInsertIter = maEffects.insert( ++aInsertIter, pEffect );
+ pTextGroup->addEffect( pEffect );
+ }
+ }
+ notify_listeners();
+ }
+}
+
+void EffectSequenceHelper::addListener( ISequenceListener* pListener )
+{
+ if( std::find( maListeners.begin(), maListeners.end(), pListener ) == maListeners.end() )
+ maListeners.push_back( pListener );
+}
+
+void EffectSequenceHelper::removeListener( ISequenceListener* pListener )
+{
+ maListeners.remove( pListener );
+}
+
+namespace {
+
+struct stl_notify_listeners_func
+{
+ stl_notify_listeners_func() {}
+ void operator()(ISequenceListener* pListener) { pListener->notify_change(); }
+};
+
+}
+
+void EffectSequenceHelper::notify_listeners()
+{
+ stl_notify_listeners_func aFunc;
+ std::for_each( maListeners.begin(), maListeners.end(), aFunc );
+}
+
+void EffectSequenceHelper::create( const css::uno::Reference< css::animations::XAnimationNode >& xNode )
+{
+ DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::create(), illegal argument" );
+
+ if( !xNode.is() )
+ return;
+
+ try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+ createEffectsequence( xChildNode );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::EffectSequenceHelper::create()" );
+ }
+}
+
+void EffectSequenceHelper::createEffectsequence( const Reference< XAnimationNode >& xNode )
+{
+ DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffectsequence(), illegal argument" );
+
+ if( !xNode.is() )
+ return;
+
+ try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+
+ createEffects( xChildNode );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::EffectSequenceHelper::createEffectsequence()" );
+ }
+}
+
+void EffectSequenceHelper::createEffects( const Reference< XAnimationNode >& xNode )
+{
+ DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffects(), illegal argument" );
+
+ if( !xNode.is() )
+ return;
+
+ try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+
+ switch( xChildNode->getType() )
+ {
+ // found an effect
+ case AnimationNodeType::PAR:
+ case AnimationNodeType::ITERATE:
+ {
+ CustomAnimationEffectPtr pEffect = std::make_shared<CustomAnimationEffect>( xChildNode );
+
+ if( pEffect->mnNodeType != -1 )
+ {
+ pEffect->setEffectSequence( this );
+ maEffects.push_back(pEffect);
+ }
+ }
+ break;
+
+ // found an after effect
+ case AnimationNodeType::SET:
+ case AnimationNodeType::ANIMATECOLOR:
+ {
+ processAfterEffect( xChildNode );
+ }
+ break;
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::EffectSequenceHelper::createEffects()" );
+ }
+}
+
+void EffectSequenceHelper::processAfterEffect( const Reference< XAnimationNode >& xNode )
+{
+ try
+ {
+ Reference< XAnimationNode > xMaster;
+
+ const Sequence< NamedValue > aUserData( xNode->getUserData() );
+ const NamedValue* pProp = std::find_if(aUserData.begin(), aUserData.end(),
+ [](const NamedValue& rProp) { return rProp.Name == "master-element"; });
+
+ if (pProp != aUserData.end())
+ pProp->Value >>= xMaster;
+
+ // only process if this is a valid after effect
+ if( xMaster.is() )
+ {
+ CustomAnimationEffectPtr pMasterEffect;
+
+ // find the master effect
+ stl_CustomAnimationEffect_search_node_predict aSearchPredict( xMaster );
+ EffectSequence::iterator aIter( std::find_if( maEffects.begin(), maEffects.end(), aSearchPredict ) );
+ if( aIter != maEffects.end() )
+ pMasterEffect = *aIter;
+
+ if( pMasterEffect )
+ {
+ pMasterEffect->setHasAfterEffect( true );
+
+ // find out what kind of after effect this is
+ if( xNode->getType() == AnimationNodeType::ANIMATECOLOR )
+ {
+ // it's a dim
+ Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW );
+ pMasterEffect->setDimColor( xAnimate->getTo() );
+ pMasterEffect->setAfterEffectOnNext( true );
+ }
+ else
+ {
+ // it's a hide
+ pMasterEffect->setAfterEffectOnNext( xNode->getParent() != xMaster->getParent() );
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::EffectSequenceHelper::processAfterEffect()" );
+ }
+}
+
+namespace {
+
+class AnimationChangeListener : public cppu::WeakImplHelper< XChangesListener >
+{
+public:
+ explicit AnimationChangeListener( MainSequence* pMainSequence ) : mpMainSequence( pMainSequence ) {}
+
+ virtual void SAL_CALL changesOccurred( const css::util::ChangesEvent& Event ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+private:
+ MainSequence* mpMainSequence;
+};
+
+}
+
+void SAL_CALL AnimationChangeListener::changesOccurred( const css::util::ChangesEvent& )
+{
+ if( mpMainSequence )
+ mpMainSequence->startRecreateTimer();
+}
+
+void SAL_CALL AnimationChangeListener::disposing( const css::lang::EventObject& )
+{
+}
+
+MainSequence::MainSequence()
+ : mxTimingRootNode(SequenceTimeContainer::create(::comphelper::getProcessComponentContext()))
+ , maTimer("sd MainSequence maTimer")
+ , mbTimerMode(false)
+ , mbRebuilding( false )
+ , mnRebuildLockGuard( 0 )
+ , mbPendingRebuildRequest( false )
+ , mbIgnoreChanges( 0 )
+{
+ if( mxTimingRootNode.is() )
+ {
+ Sequence< css::beans::NamedValue > aUserData
+ { { "node-type", css::uno::Any(css::presentation::EffectNodeType::MAIN_SEQUENCE) } };
+ mxTimingRootNode->setUserData( aUserData );
+ }
+ init();
+}
+
+MainSequence::MainSequence( const css::uno::Reference< css::animations::XAnimationNode >& xNode )
+ : mxTimingRootNode( xNode, UNO_QUERY )
+ , maTimer("sd MainSequence maTimer")
+ , mbTimerMode( false )
+ , mbRebuilding( false )
+ , mnRebuildLockGuard( 0 )
+ , mbPendingRebuildRequest( false )
+ , mbIgnoreChanges( 0 )
+{
+ init();
+}
+
+MainSequence::~MainSequence()
+{
+ reset();
+}
+
+void MainSequence::init()
+{
+ mnSequenceType = EffectNodeType::MAIN_SEQUENCE;
+
+ maTimer.SetInvokeHandler( LINK(this, MainSequence, onTimerHdl) );
+ maTimer.SetTimeout(50);
+
+ mxChangesListener.set( new AnimationChangeListener( this ) );
+
+ createMainSequence();
+}
+
+void MainSequence::reset( const css::uno::Reference< css::animations::XAnimationNode >& xTimingRootNode )
+{
+ reset();
+
+ mxTimingRootNode.set( xTimingRootNode, UNO_QUERY );
+
+ createMainSequence();
+}
+
+Reference< css::animations::XAnimationNode > MainSequence::getRootNode()
+{
+ DBG_ASSERT( mnRebuildLockGuard == 0, "MainSequence::getRootNode(), rebuild is locked, is this really what you want?" );
+
+ if( maTimer.IsActive() && mbTimerMode )
+ {
+ // force a rebuild NOW if one is pending
+ maTimer.Stop();
+ implRebuild();
+ }
+
+ return EffectSequenceHelper::getRootNode();
+}
+
+void MainSequence::createMainSequence()
+{
+ if( mxTimingRootNode.is() ) try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxTimingRootNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+ sal_Int32 nNodeType = CustomAnimationEffect::get_node_type( xChildNode );
+ if( nNodeType == EffectNodeType::MAIN_SEQUENCE )
+ {
+ mxSequenceRoot.set( xChildNode, UNO_QUERY );
+ EffectSequenceHelper::create( xChildNode );
+ }
+ else if( nNodeType == EffectNodeType::INTERACTIVE_SEQUENCE )
+ {
+ Reference< XTimeContainer > xInteractiveRoot( xChildNode, UNO_QUERY_THROW );
+ InteractiveSequencePtr pIS = std::make_shared<InteractiveSequence>( xInteractiveRoot, this );
+ pIS->addListener( this );
+ maInteractiveSequenceVector.push_back( pIS );
+ }
+ }
+
+ // see if we have a mainsequence at all. if not, create one...
+ if( !mxSequenceRoot.is() )
+ {
+ mxSequenceRoot = SequenceTimeContainer::create( ::comphelper::getProcessComponentContext() );
+
+ uno::Sequence< css::beans::NamedValue > aUserData
+ { { "node-type", css::uno::Any(css::presentation::EffectNodeType::MAIN_SEQUENCE) } };
+ mxSequenceRoot->setUserData( aUserData );
+
+ // empty sequence until now, set duration to 0.0
+ // explicitly (otherwise, this sequence will never
+ // end)
+ mxSequenceRoot->setDuration( Any(0.0) );
+
+ Reference< XAnimationNode > xMainSequenceNode( mxSequenceRoot, UNO_QUERY_THROW );
+ mxTimingRootNode->appendChild( xMainSequenceNode );
+ }
+
+ updateTextGroups();
+
+ notify_listeners();
+
+ Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
+ if( xNotifier.is() )
+ xNotifier->addChangesListener( mxChangesListener );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::MainSequence::create()" );
+ return;
+ }
+
+ DBG_ASSERT( mxSequenceRoot.is(), "sd::MainSequence::create(), found no main sequence!" );
+}
+
+void MainSequence::reset()
+{
+ EffectSequenceHelper::reset();
+
+ for (auto const& interactiveSequence : maInteractiveSequenceVector)
+ interactiveSequence->reset();
+ maInteractiveSequenceVector.clear();
+
+ try
+ {
+ Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
+ if( xNotifier.is() )
+ xNotifier->removeChangesListener( mxChangesListener );
+ }
+ catch( Exception& )
+ {
+
+ }
+}
+
+InteractiveSequencePtr MainSequence::createInteractiveSequence( const css::uno::Reference< css::drawing::XShape >& xShape )
+{
+ InteractiveSequencePtr pIS;
+
+ // create a new interactive sequence container
+ Reference< XTimeContainer > xISRoot = SequenceTimeContainer::create( ::comphelper::getProcessComponentContext() );
+
+ uno::Sequence< css::beans::NamedValue > aUserData
+ { { "node-type", css::uno::Any(css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE) } };
+ xISRoot->setUserData( aUserData );
+ xISRoot->setRestart( css::animations::AnimationRestart::WHEN_NOT_ACTIVE );
+
+ Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
+ Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
+ xParent->appendChild( xISRoot );
+
+ pIS = std::make_shared<InteractiveSequence>( xISRoot, this);
+ pIS->setTriggerShape( xShape );
+ pIS->addListener( this );
+ maInteractiveSequenceVector.push_back( pIS );
+ return pIS;
+}
+
+CustomAnimationEffectPtr MainSequence::findEffect( const css::uno::Reference< css::animations::XAnimationNode >& xNode ) const
+{
+ CustomAnimationEffectPtr pEffect = EffectSequenceHelper::findEffect( xNode );
+
+ if( !pEffect )
+ {
+ for (auto const& interactiveSequence : maInteractiveSequenceVector)
+ {
+ pEffect = interactiveSequence->findEffect( xNode );
+ if (pEffect)
+ break;
+ }
+ }
+ return pEffect;
+}
+
+sal_Int32 MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr& pEffect ) const
+{
+ sal_Int32 nOffset = EffectSequenceHelper::getOffsetFromEffect( pEffect );
+
+ if( nOffset != -1 )
+ return nOffset;
+
+ nOffset = EffectSequenceHelper::getCount();
+
+ for (auto const& interactiveSequence : maInteractiveSequenceVector)
+ {
+ sal_Int32 nTemp = interactiveSequence->getOffsetFromEffect( pEffect );
+ if( nTemp != -1 )
+ return nOffset + nTemp;
+
+ nOffset += interactiveSequence->getCount();
+ }
+
+ return -1;
+}
+
+CustomAnimationEffectPtr MainSequence::getEffectFromOffset( sal_Int32 nOffset ) const
+{
+ if( nOffset >= 0 )
+ {
+ if( nOffset < getCount() )
+ return EffectSequenceHelper::getEffectFromOffset( nOffset );
+
+ nOffset -= getCount();
+
+ auto aIter( maInteractiveSequenceVector.begin() );
+
+ while( (aIter != maInteractiveSequenceVector.end()) && (nOffset > (*aIter)->getCount()) )
+ nOffset -= (*aIter++)->getCount();
+
+ if( (aIter != maInteractiveSequenceVector.end()) && (nOffset >= 0) )
+ return (*aIter)->getEffectFromOffset( nOffset );
+ }
+
+ CustomAnimationEffectPtr pEffect;
+ return pEffect;
+}
+
+bool MainSequence::disposeShape( const Reference< XShape >& xShape )
+{
+ bool bChanges = EffectSequenceHelper::disposeShape( xShape );
+
+ for (auto const& iterativeSequence : maInteractiveSequenceVector)
+ {
+ bChanges |= iterativeSequence->disposeShape( xShape );
+ }
+
+ if( bChanges )
+ startRebuildTimer();
+
+ return bChanges;
+}
+
+bool MainSequence::hasEffect( const css::uno::Reference< css::drawing::XShape >& xShape )
+{
+ if( EffectSequenceHelper::hasEffect( xShape ) )
+ return true;
+
+ for (auto const& iterativeSequence : maInteractiveSequenceVector)
+ {
+ if( iterativeSequence->getTriggerShape() == xShape )
+ return true;
+
+ if( iterativeSequence->hasEffect( xShape ) )
+ return true;
+ }
+
+ return false;
+}
+
+void MainSequence::insertTextRange( const css::uno::Any& aTarget )
+{
+ EffectSequenceHelper::insertTextRange( aTarget );
+
+ for (auto const& iterativeSequence : maInteractiveSequenceVector)
+ {
+ iterativeSequence->insertTextRange( aTarget );
+ }
+}
+
+void MainSequence::disposeTextRange( const css::uno::Any& aTarget )
+{
+ EffectSequenceHelper::disposeTextRange( aTarget );
+
+ for (auto const& iterativeSequence : maInteractiveSequenceVector)
+ {
+ iterativeSequence->disposeTextRange( aTarget );
+ }
+}
+
+/** callback from the sd::View when an object just left text edit mode */
+void MainSequence::onTextChanged( const Reference< XShape >& xShape )
+{
+ EffectSequenceHelper::onTextChanged( xShape );
+
+ for (auto const& iterativeSequence : maInteractiveSequenceVector)
+ {
+ iterativeSequence->onTextChanged( xShape );
+ }
+}
+
+void EffectSequenceHelper::onTextChanged( const Reference< XShape >& xShape )
+{
+ // get map [paragraph index] -> [NumberingLevel]
+ // for following reusage inside all animation effects
+ std::vector< sal_Int32 > paragraphNumberingLevel;
+ std::vector< sal_Int32 >* paragraphNumberingLevelParam = nullptr;
+ if ( getParagraphNumberingLevels( xShape, paragraphNumberingLevel ) )
+ paragraphNumberingLevelParam = &paragraphNumberingLevel;
+
+ // update internal flags for each animation effect
+ const bool bChanges = std::accumulate(maEffects.begin(), maEffects.end(), false,
+ [&xShape, &paragraphNumberingLevelParam](const bool bCheck, const CustomAnimationEffectPtr& rxEffect) {
+ bool bRes = bCheck;
+ if (rxEffect->getTargetShape() == xShape)
+ bRes |= rxEffect->checkForText( paragraphNumberingLevelParam );
+ return bRes;
+ });
+
+ if( bChanges )
+ rebuild();
+}
+
+void MainSequence::rebuild()
+{
+ startRebuildTimer();
+}
+
+void MainSequence::lockRebuilds()
+{
+ mnRebuildLockGuard++;
+}
+
+void MainSequence::unlockRebuilds()
+{
+ DBG_ASSERT( mnRebuildLockGuard, "sd::MainSequence::unlockRebuilds(), no corresponding lockRebuilds() call!" );
+ if( mnRebuildLockGuard )
+ mnRebuildLockGuard--;
+
+ if( (mnRebuildLockGuard == 0) && mbPendingRebuildRequest )
+ {
+ mbPendingRebuildRequest = false;
+ startRebuildTimer();
+ }
+}
+
+void MainSequence::implRebuild()
+{
+ if( mnRebuildLockGuard )
+ {
+ mbPendingRebuildRequest = true;
+ return;
+ }
+
+ mbRebuilding = true;
+
+ EffectSequenceHelper::implRebuild();
+
+ auto aIter( maInteractiveSequenceVector.begin() );
+ while( aIter != maInteractiveSequenceVector.end() )
+ {
+ InteractiveSequencePtr pIS( *aIter );
+ if( pIS->maEffects.empty() )
+ {
+ // remove empty interactive sequences
+ aIter = maInteractiveSequenceVector.erase( aIter );
+
+ Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
+ Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
+ Reference< XAnimationNode > xISNode( pIS->mxSequenceRoot, UNO_QUERY_THROW );
+ xParent->removeChild( xISNode );
+ }
+ else
+ {
+ pIS->implRebuild();
+ ++aIter;
+ }
+ }
+
+ notify_listeners();
+ mbRebuilding = false;
+}
+
+void MainSequence::notify_change()
+{
+ notify_listeners();
+}
+
+bool MainSequence::setTrigger( const CustomAnimationEffectPtr& pEffect, const css::uno::Reference< css::drawing::XShape >& xTriggerShape )
+{
+ EffectSequenceHelper* pOldSequence = pEffect->getEffectSequence();
+
+ EffectSequenceHelper* pNewSequence = nullptr;
+ if( xTriggerShape.is() )
+ {
+ for (InteractiveSequencePtr const& pIS : maInteractiveSequenceVector)
+ {
+ if( pIS->getTriggerShape() == xTriggerShape )
+ {
+ pNewSequence = pIS.get();
+ break;
+ }
+ }
+
+ if( !pNewSequence )
+ pNewSequence = createInteractiveSequence( xTriggerShape ).get();
+ }
+ else
+ {
+ pNewSequence = this;
+ }
+
+ if( pOldSequence != pNewSequence )
+ {
+ if( pOldSequence )
+ pOldSequence->maEffects.remove( pEffect );
+ if( pNewSequence )
+ pNewSequence->maEffects.push_back( pEffect );
+ pEffect->setEffectSequence( pNewSequence );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+}
+
+IMPL_LINK_NOARG(MainSequence, onTimerHdl, Timer *, void)
+{
+ if( mbTimerMode )
+ {
+ implRebuild();
+ }
+ else
+ {
+ reset();
+ createMainSequence();
+ }
+}
+
+/** starts a timer that recreates the internal structure from the API core */
+void MainSequence::startRecreateTimer()
+{
+ if( !mbRebuilding && (mbIgnoreChanges == 0) )
+ {
+ mbTimerMode = false;
+ maTimer.Start();
+ }
+}
+
+/**
+ * starts a timer that rebuilds the API core from the internal structure
+ * This is used to reduce the number of screen redraws due to animation changes.
+*/
+void MainSequence::startRebuildTimer()
+{
+ mbTimerMode = true;
+ maTimer.Start();
+}
+
+InteractiveSequence::InteractiveSequence( const Reference< XTimeContainer >& xSequenceRoot, MainSequence* pMainSequence )
+: EffectSequenceHelper( xSequenceRoot ), mpMainSequence( pMainSequence )
+{
+ mnSequenceType = EffectNodeType::INTERACTIVE_SEQUENCE;
+
+ try
+ {
+ if( mxSequenceRoot.is() )
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
+ while( !mxEventSource.is() && xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+
+ Event aEvent;
+ if( (xChildNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::ON_CLICK) )
+ aEvent.Source >>= mxEventSource;
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::InteractiveSequence::InteractiveSequence()" );
+ return;
+ }
+}
+
+void InteractiveSequence::rebuild()
+{
+ mpMainSequence->rebuild();
+}
+
+void InteractiveSequence::implRebuild()
+{
+ EffectSequenceHelper::implRebuild();
+}
+
+MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr& pMainSequence )
+: mpMainSequence( pMainSequence )
+{
+ if( mpMainSequence )
+ mpMainSequence->lockRebuilds();
+}
+
+MainSequenceRebuildGuard::~MainSequenceRebuildGuard()
+{
+ if( mpMainSequence )
+ mpMainSequence->unlockRebuilds();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/CustomAnimationPreset.cxx b/sd/source/core/CustomAnimationPreset.cxx
new file mode 100644
index 000000000..d7c19401d
--- /dev/null
+++ b/sd/source/core/CustomAnimationPreset.cxx
@@ -0,0 +1,514 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/xml/sax/XFastParser.hpp>
+#include <com/sun/star/presentation/EffectPresetClass.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <unotools/streamwrap.hxx>
+#include <comphelper/getexpandeduri.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/random.hxx>
+#include <comphelper/lok.hxx>
+#include <unotools/syslocaleoptions.hxx>
+#include <tools/stream.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/string_view.hxx>
+
+#include <vcl/svapp.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <CustomAnimationPreset.hxx>
+
+#include <algorithm>
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::presentation;
+
+using ::com::sun::star::io::XInputStream;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::util::XCloneable;
+using ::com::sun::star::beans::NamedValue;
+
+namespace sd {
+
+static Reference< XNameAccess > getNodeAccess( const Reference< XMultiServiceFactory >& xConfigProvider, const OUString& rNodePath )
+{
+ Reference< XNameAccess > xConfigAccess;
+
+ try
+ {
+ Sequence<Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", uno::Any(rNodePath)}
+ }));
+
+ xConfigAccess.set(
+ xConfigProvider->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", aArgs ),
+ UNO_QUERY);
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::getNodeAccess()" );
+ }
+
+ return xConfigAccess;
+}
+
+void implImportLabels( const Reference< XMultiServiceFactory >& xConfigProvider, const OUString& rNodePath, UStringMap& rStringMap )
+{
+ try
+ {
+ Reference< XNameAccess > xConfigAccess( getNodeAccess( xConfigProvider, rNodePath ) );
+ if( xConfigAccess.is() )
+ {
+ Reference< XNameAccess > xNameAccess;
+ const Sequence< OUString > aNames( xConfigAccess->getElementNames() );
+ for(const OUString& rName : aNames)
+ {
+ xConfigAccess->getByName( rName ) >>= xNameAccess;
+ if( xNameAccess.is() )
+ {
+ OUString aUIName;
+ xNameAccess->getByName( "Label" ) >>= aUIName;
+ if( !aUIName.isEmpty() )
+ {
+ rStringMap[ rName ] = aUIName;
+ }
+ }
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::implImportLabels()" );
+ }
+}
+
+CustomAnimationPreset::CustomAnimationPreset( const CustomAnimationEffectPtr& pEffect )
+{
+ maPresetId = pEffect->getPresetId();
+ maProperty = pEffect->getProperty();
+
+ add( pEffect );
+
+ mfDuration = pEffect->getDuration();
+ maDefaultSubTyp = pEffect->getPresetSubType();
+
+ const Sequence< NamedValue > aUserData( pEffect->getNode()->getUserData() );
+
+ mbIsTextOnly = std::any_of(aUserData.begin(), aUserData.end(),
+ [](const NamedValue& rProp) { return rProp.Name == "text-only"; });
+}
+
+void CustomAnimationPreset::add( const CustomAnimationEffectPtr& pEffect )
+{
+ maSubTypes[ pEffect->getPresetSubType() ] = pEffect;
+}
+
+std::vector<OUString> CustomAnimationPreset::getSubTypes()
+{
+ std::vector<OUString> aSubTypes;
+
+ if( maSubTypes.size() > 1 )
+ {
+ std::transform(maSubTypes.begin(), maSubTypes.end(), std::back_inserter(aSubTypes),
+ [](EffectsSubTypeMap::value_type& rEntry) -> OUString { return rEntry.first; });
+ }
+
+ return aSubTypes;
+}
+
+Reference< XAnimationNode > CustomAnimationPreset::create( const OUString& rstrSubType )
+{
+ try
+ {
+ OUString strSubType( rstrSubType );
+ if( strSubType.isEmpty() )
+ strSubType = maDefaultSubTyp;
+
+ CustomAnimationEffectPtr pEffect = maSubTypes[strSubType];
+ if( pEffect )
+ {
+ Reference< XCloneable > xCloneable( pEffect->getNode(), UNO_QUERY_THROW );
+ Reference< XAnimationNode > xNode( xCloneable->createClone(), UNO_QUERY_THROW );
+ return xNode;
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::create()" );
+ }
+
+ Reference< XAnimationNode > xNode;
+ return xNode;
+}
+
+std::vector<OUString> CustomAnimationPreset::getProperties() const
+{
+ std::vector<OUString> aPropertyList;
+ if (!maProperty.isEmpty())
+ {
+ sal_Int32 nPos = 0;
+ do
+ {
+ aPropertyList.push_back(maProperty.getToken(0, ';', nPos));
+ }
+ while (nPos >= 0);
+ }
+ return aPropertyList;
+}
+
+bool CustomAnimationPreset::hasProperty( std::u16string_view rProperty )const
+{
+ if (maProperty.isEmpty())
+ return false;
+
+ sal_Int32 nPos = 0;
+ do
+ {
+ if (o3tl::getToken(maProperty, 0, ';', nPos) == rProperty)
+ return true;
+ }
+ while (nPos >= 0);
+
+ return false;
+}
+
+CustomAnimationPresets::CustomAnimationPresets()
+{
+}
+
+CustomAnimationPresets::~CustomAnimationPresets()
+{
+}
+
+Reference< XAnimationNode > implImportEffects( const Reference< XMultiServiceFactory >& xServiceFactory, const OUString& rPath )
+{
+ Reference< XAnimationNode > xRootNode;
+
+ try
+ {
+ // create stream
+ std::unique_ptr<SvStream> pIStm = ::utl::UcbStreamHelper::CreateStream( rPath, StreamMode::READ );
+ Reference<XInputStream> xInputStream( new utl::OInputStreamWrapper( std::move(pIStm) ) );
+
+ // prepare ParserInputSource
+ xml::sax::InputSource aParserInput;
+ aParserInput.sSystemId = rPath;
+ aParserInput.aInputStream = xInputStream;
+
+ // get filter
+ Reference< xml::sax::XFastParser > xFilter( xServiceFactory->createInstance("com.sun.star.comp.Xmloff.AnimationsImport" ), UNO_QUERY_THROW );
+
+ xFilter->parseStream( aParserInput );
+
+ Reference< XAnimationNodeSupplier > xAnimationNodeSupplier( xFilter, UNO_QUERY_THROW );
+ xRootNode = xAnimationNodeSupplier->getAnimationNode();
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sd", "");
+ }
+
+ return xRootNode;
+}
+
+void CustomAnimationPresets::importEffects()
+{
+ try
+ {
+ uno::Reference< uno::XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+ Reference< XMultiServiceFactory > xServiceFactory(
+ xContext->getServiceManager(), UNO_QUERY_THROW );
+
+ Reference< XMultiServiceFactory > xConfigProvider =
+ configuration::theDefaultProvider::get( xContext );
+
+ // read path to transition effects files from config
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", uno::Any(OUString("/org.openoffice.Office.Impress/Misc"))}
+ }));
+ Reference<container::XNameAccess> xNameAccess(
+ xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArgs ), UNO_QUERY_THROW );
+ uno::Sequence< OUString > aFiles;
+ xNameAccess->getByName( "EffectFiles" ) >>= aFiles;
+
+ for( const auto& rFile : std::as_const(aFiles) )
+ {
+ OUString aURL = comphelper::getExpandedUri(xContext, rFile);
+
+ mxRootNode = implImportEffects( xServiceFactory, aURL );
+
+ if( mxRootNode.is() )
+ {
+ Reference< XTimeContainer > xRootContainer( mxRootNode, UNO_QUERY_THROW );
+ EffectSequenceHelper aSequence( xRootContainer );
+
+ EffectSequence::iterator aIter( aSequence.getBegin() );
+ const EffectSequence::iterator aEnd( aSequence.getEnd() );
+
+ while( aIter != aEnd )
+ {
+ CustomAnimationEffectPtr pEffect = *aIter;
+
+ const OUString aPresetId( pEffect->getPresetId() );
+ CustomAnimationPresetPtr pDescriptor = getEffectDescriptor( aPresetId );
+ if( pDescriptor )
+ pDescriptor->add( pEffect );
+ else
+ {
+ pDescriptor = std::make_shared<CustomAnimationPreset>( pEffect );
+ pDescriptor->maLabel = getUINameForPresetId( pEffect->getPresetId() );
+ maEffectDescriptorMap[aPresetId] = pDescriptor;
+ }
+
+ ++aIter;
+ }
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::importEffects()" );
+ }
+}
+
+void CustomAnimationPresets::importResources()
+{
+ try
+ {
+ // Get service factory
+ Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
+
+ Reference< XMultiServiceFactory > xConfigProvider =
+ configuration::theDefaultProvider::get( xContext );
+
+ implImportLabels( xConfigProvider, "/org.openoffice.Office.UI.Effects/UserInterface/Properties", maPropertyNameMap );
+
+ implImportLabels( xConfigProvider, "/org.openoffice.Office.UI.Effects/UserInterface/Effects", maEffectNameMap );
+
+ importEffects();
+
+ importPresets( xConfigProvider, "/org.openoffice.Office.UI.Effects/Presets/Entrance", maEntrancePresets );
+
+ importPresets( xConfigProvider, "/org.openoffice.Office.UI.Effects/Presets/Emphasis", maEmphasisPresets );
+
+ importPresets( xConfigProvider, "/org.openoffice.Office.UI.Effects/Presets/Exit", maExitPresets );
+
+ importPresets( xConfigProvider, "/org.openoffice.Office.UI.Effects/Presets/MotionPaths", maMotionPathsPresets );
+
+ importPresets( xConfigProvider, "/org.openoffice.Office.UI.Effects/Presets/Misc", maMiscPresets );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::importResources()" );
+ }
+}
+
+void CustomAnimationPresets::importPresets( const Reference< XMultiServiceFactory >& xConfigProvider, const OUString& rNodePath, PresetCategoryList& rPresetMap )
+{
+#ifdef DEBUG
+ OUString aMissedPresetIds;
+#endif
+
+ try
+ {
+ Reference< XNameAccess > xTypeAccess( getNodeAccess( xConfigProvider, rNodePath ) );
+ if( xTypeAccess.is() )
+ {
+ Reference< XNameAccess > xCategoryAccess;
+
+ const Sequence< OUString > aNames( xTypeAccess->getElementNames() );
+ for(const OUString& rName : aNames)
+ {
+ xTypeAccess->getByName( rName ) >>= xCategoryAccess;
+
+ if( xCategoryAccess.is() && xCategoryAccess->hasByName( "Label" ) && xCategoryAccess->hasByName( "Effects" ) )
+ {
+ OUString aLabel;
+ xCategoryAccess->getByName( "Label" ) >>= aLabel;
+
+ Sequence< OUString > aEffects;
+ xCategoryAccess->getByName( "Effects" ) >>= aEffects;
+
+ EffectDescriptorList aEffectsList;
+
+ for( const OUString& rEffectName : std::as_const(aEffects) )
+ {
+ CustomAnimationPresetPtr pEffect = getEffectDescriptor( rEffectName );
+ if( pEffect )
+ {
+ aEffectsList.push_back( pEffect );
+ }
+#ifdef DEBUG
+ else
+ {
+ aMissedPresetIds += OUString(rEffectName);
+ aMissedPresetIds += "\n";
+ }
+#endif
+ }
+ rPresetMap.push_back( std::make_shared<PresetCategory>( aLabel, std::move(aEffectsList) ) );
+ }
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::importPresets()" );
+ }
+
+#ifdef DEBUG
+ SAL_WARN_IF(!aMissedPresetIds.isEmpty(), "sd", "sd::CustomAnimationPresets::importPresets(), invalid preset id: "
+ << aMissedPresetIds);
+#endif
+}
+
+CustomAnimationPresetPtr CustomAnimationPresets::getEffectDescriptor( const OUString& rPresetId ) const
+{
+ EffectDescriptorMap::const_iterator aIter( maEffectDescriptorMap.find( rPresetId ) );
+
+ if( aIter != maEffectDescriptorMap.end() )
+ {
+ return (*aIter).second;
+ }
+ else
+ {
+ return CustomAnimationPresetPtr(nullptr);
+ }
+}
+
+const OUString& CustomAnimationPresets::getUINameForPresetId( const OUString& rPresetId ) const
+{
+ return translateName( rPresetId, maEffectNameMap );
+}
+
+const OUString& CustomAnimationPresets::getUINameForProperty( const OUString& rPresetId ) const
+{
+ return translateName( rPresetId, maPropertyNameMap );
+}
+
+const OUString& CustomAnimationPresets::translateName( const OUString& rId, const UStringMap& rNameMap )
+{
+ UStringMap::const_iterator aIter( rNameMap.find( rId ) );
+
+ if( aIter != rNameMap.end() )
+ {
+ return (*aIter).second;
+ }
+ else
+ {
+ return rId;
+ }
+}
+void CustomAnimationPresets::changePresetSubType( const CustomAnimationEffectPtr& pEffect, const OUString& rPresetSubType ) const
+{
+ if( pEffect && pEffect->getPresetSubType() != rPresetSubType )
+ {
+ CustomAnimationPresetPtr pDescriptor( getEffectDescriptor( pEffect->getPresetId() ) );
+
+ if( pDescriptor )
+ {
+ Reference< XAnimationNode > xNewNode( pDescriptor->create( rPresetSubType ) );
+ if( xNewNode.is() )
+ pEffect->replaceNode( xNewNode );
+ }
+ }
+}
+
+std::map<OUString, CustomAnimationPresets> CustomAnimationPresets::mPresetsMap;
+
+const CustomAnimationPresets& CustomAnimationPresets::getCustomAnimationPresets()
+{
+ // Support localization per-view. Currently not useful for Desktop
+ // but very much critical for LOK. The cache now is per-language.
+ const OUString aLang = comphelper::LibreOfficeKit::isActive()
+ ? comphelper::LibreOfficeKit::getLanguageTag().getBcp47()
+ : SvtSysLocaleOptions().GetLanguageTag().getBcp47();
+
+ SolarMutexGuard aGuard;
+ const auto it = mPresetsMap.find(aLang);
+ if (it != mPresetsMap.end())
+ return it->second;
+
+ CustomAnimationPresets& rPresets = mPresetsMap[aLang];
+ rPresets.importResources();
+ return rPresets;
+}
+
+Reference< XAnimationNode > CustomAnimationPresets::getRandomPreset( sal_Int16 nPresetClass ) const
+{
+ Reference< XAnimationNode > xNode;
+
+ const PresetCategoryList* pCategoryList = nullptr;
+ switch( nPresetClass )
+ {
+ case EffectPresetClass::ENTRANCE: pCategoryList = &maEntrancePresets; break;
+ case EffectPresetClass::EXIT: pCategoryList = &maExitPresets; break;
+ case EffectPresetClass::EMPHASIS: pCategoryList = &maEmphasisPresets; break;
+ case EffectPresetClass::MOTIONPATH: pCategoryList = &maMotionPathsPresets; break;
+ default:
+ pCategoryList = nullptr;
+ }
+
+ if( pCategoryList && !pCategoryList->empty() )
+ {
+ sal_Int32 nCategory = comphelper::rng::uniform_size_distribution(0, pCategoryList->size()-1);
+
+ PresetCategoryPtr pCategory = (*pCategoryList)[nCategory];
+ if( pCategory && !pCategory->maEffects.empty() )
+ {
+ sal_Int32 nDescriptor = comphelper::rng::uniform_size_distribution(0, pCategory->maEffects.size()-1);
+ CustomAnimationPresetPtr pPreset = pCategory->maEffects[nDescriptor];
+ if( pPreset )
+ {
+ std::vector<OUString> aSubTypes = pPreset->getSubTypes();
+
+ OUString aSubType;
+ if( !aSubTypes.empty() )
+ {
+ size_t nSubType = comphelper::rng::uniform_size_distribution(0, aSubTypes.size()-1);
+ aSubType = aSubTypes[nSubType];
+ }
+ xNode = pPreset->create( aSubType );
+ }
+ }
+ }
+
+ return xNode;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/EffectMigration.cxx b/sd/source/core/EffectMigration.cxx
new file mode 100644
index 000000000..8dd9d0905
--- /dev/null
+++ b/sd/source/core/EffectMigration.cxx
@@ -0,0 +1,1439 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/animations/XAnimate.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <o3tl/string_view.hxx>
+#include <tools/debug.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svditer.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <CustomAnimationPreset.hxx>
+#include <TransitionPreset.hxx>
+#include <EffectMigration.hxx>
+#include <anminfo.hxx>
+
+using namespace ::sd;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::presentation;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::beans::NamedValue;
+
+namespace {
+
+struct deprecated_FadeEffect_conversion_table_entry
+{
+ FadeEffect meFadeEffect;
+ const char* mpPresetId;
+};
+
+}
+
+deprecated_FadeEffect_conversion_table_entry const deprecated_FadeEffect_conversion_table[] =
+{
+// OOo 1.x transitions
+ { FadeEffect_FADE_FROM_LEFT, "wipe-right" },
+ { FadeEffect_FADE_FROM_TOP, "wipe-down" },
+ { FadeEffect_FADE_FROM_RIGHT, "wipe-left" },
+ { FadeEffect_FADE_FROM_BOTTOM, "wipe-up" },
+
+ { FadeEffect_CLOCKWISE, "wheel-clockwise-1-spoke" },
+
+ { FadeEffect_UNCOVER_TO_LEFT, "uncover-left" },
+ { FadeEffect_UNCOVER_TO_UPPERLEFT, "uncover-left-up" },
+ { FadeEffect_UNCOVER_TO_TOP, "uncover-up" },
+ { FadeEffect_UNCOVER_TO_UPPERRIGHT, "uncover-right-up" },
+ { FadeEffect_UNCOVER_TO_RIGHT, "uncover-right" },
+ { FadeEffect_UNCOVER_TO_LOWERRIGHT, "uncover-right-down" },
+ { FadeEffect_UNCOVER_TO_BOTTOM, "uncover-down" },
+ { FadeEffect_UNCOVER_TO_LOWERLEFT, "uncover-left-down" },
+
+ { FadeEffect_VERTICAL_LINES, "random-bars-vertical" },
+ { FadeEffect_HORIZONTAL_LINES, "random-bars-horizontal" },
+
+ { FadeEffect_VERTICAL_CHECKERBOARD, "checkerboard-down" },
+ { FadeEffect_HORIZONTAL_CHECKERBOARD, "checkerboard-across" },
+
+ { FadeEffect_FADE_TO_CENTER, "box-in" },
+ { FadeEffect_FADE_FROM_CENTER, "box-out" },
+
+ { FadeEffect_VERTICAL_STRIPES, "venetian-blinds-vertical" },
+ { FadeEffect_HORIZONTAL_STRIPES, "venetian-blinds-horizontal" },
+
+ { FadeEffect_MOVE_FROM_LEFT, "cover-right" },
+ { FadeEffect_MOVE_FROM_TOP, "cover-down" },
+ { FadeEffect_MOVE_FROM_RIGHT, "cover-left" },
+ { FadeEffect_MOVE_FROM_BOTTOM, "cover-up" },
+ { FadeEffect_MOVE_FROM_UPPERLEFT, "cover-right-down" },
+ { FadeEffect_MOVE_FROM_UPPERRIGHT, "cover-left-down" },
+ { FadeEffect_MOVE_FROM_LOWERRIGHT, "cover-left-up" },
+ { FadeEffect_MOVE_FROM_LOWERLEFT, "cover-right-up" },
+
+ { FadeEffect_DISSOLVE, "dissolve" },
+
+ { FadeEffect_RANDOM, "random-transition" },
+
+ { FadeEffect_ROLL_FROM_LEFT, "push-right" },
+ { FadeEffect_ROLL_FROM_TOP, "push-down" },
+ { FadeEffect_ROLL_FROM_RIGHT, "push-left" },
+ { FadeEffect_ROLL_FROM_BOTTOM, "push-up" },
+
+ { FadeEffect_CLOSE_VERTICAL, "split-horizontal-in" },
+ { FadeEffect_CLOSE_HORIZONTAL, "split-vertical-in" },
+ { FadeEffect_OPEN_VERTICAL, "split-horizontal-out" },
+ { FadeEffect_OPEN_HORIZONTAL, "split-vertical-out" },
+
+ { FadeEffect_FADE_FROM_UPPERLEFT, "diagonal-squares-right-down" },
+ { FadeEffect_FADE_FROM_UPPERRIGHT, "diagonal-squares-left-down" },
+ { FadeEffect_FADE_FROM_LOWERLEFT, "diagonal-squares-right-up" },
+ { FadeEffect_FADE_FROM_LOWERRIGHT, "diagonal-squares-left-up" },
+
+// OOo 1.x transitions not in OOo 2.x
+ { FadeEffect_CLOCKWISE, "clock-wipe-twelve" },
+ { FadeEffect_COUNTERCLOCKWISE, "reverse-clock-wipe-twelve" },
+ { FadeEffect_SPIRALIN_LEFT, "spiral-wipe-top-left-clockwise" },
+ { FadeEffect_SPIRALIN_RIGHT, "spiral-wipe-top-right-counter-clockwise" },
+ { FadeEffect_SPIRALOUT_LEFT, "spiral-wipe-out-to-bottom-right-clockwise" },
+ { FadeEffect_SPIRALOUT_RIGHT, "spiral-wipe-out-to-bottom-left-counter-clockwise" },
+ { FadeEffect_WAVYLINE_FROM_LEFT, "snake-wipe-top-left-vertical" },
+ { FadeEffect_WAVYLINE_FROM_TOP, "snake-wipe-top-left-horizontal" },
+ { FadeEffect_WAVYLINE_FROM_RIGHT, "snake-wipe-bottom-right-vertical" },
+ { FadeEffect_WAVYLINE_FROM_BOTTOM, "snake-wipe-bottom-right-horizontal" },
+ { FadeEffect_STRETCH_FROM_LEFT, "wipe-right" }, // todo
+ { FadeEffect_STRETCH_FROM_TOP, "wipe-down" }, // todo
+ { FadeEffect_STRETCH_FROM_RIGHT, "wipe-left" }, // todo
+ { FadeEffect_STRETCH_FROM_BOTTOM, "wipe-up" }, // todo
+
+// OOo 1.x not available transitions
+
+ { FadeEffect_CLOCKWISE, "wheel-clockwise-2-spokes" },
+ { FadeEffect_CLOCKWISE, "wheel-clockwise-3-spokes" },
+ { FadeEffect_CLOCKWISE, "wheel-clockwise-4-spokes" },
+ { FadeEffect_CLOCKWISE, "wheel-clockwise-8-spokes" },
+
+ { FadeEffect_FADE_FROM_CENTER, "shape-circle" },
+ { FadeEffect_FADE_FROM_CENTER, "shape-diamond" },
+ { FadeEffect_FADE_FROM_CENTER, "shape-plus" },
+
+ { FadeEffect_CLOCKWISE, "wedge" },
+
+ { FadeEffect_DISSOLVE, "fade-through-black" },
+
+ { FadeEffect_CLOCKWISE, "zoom-rotate-in" },
+
+ { FadeEffect_HORIZONTAL_LINES, "comb-horizontal" },
+ { FadeEffect_VERTICAL_LINES, "comb-vertical" },
+
+ { FadeEffect_DISSOLVE, "fade-smoothly" },
+
+ { FadeEffect_NONE, nullptr }
+};
+
+/* todo
+cut cut (same as NONE?)
+cut-through-black cut toBlack
+wedge wedge
+*/
+
+void EffectMigration::SetFadeEffect( SdPage* pPage, css::presentation::FadeEffect eNewEffect)
+{
+ deprecated_FadeEffect_conversion_table_entry const * pEntry = deprecated_FadeEffect_conversion_table;
+ while( (pEntry->meFadeEffect != FadeEffect_NONE) && (pEntry->meFadeEffect != eNewEffect) )
+ pEntry++;
+
+ if( pEntry->mpPresetId )
+ {
+ const OUString aPresetId( OUString::createFromAscii( pEntry->mpPresetId ) );
+
+ const TransitionPresetList& rPresetList = TransitionPreset::getTransitionPresetList();
+
+ auto aIt = std::find_if(rPresetList.begin(), rPresetList.end(),
+ [&aPresetId](const TransitionPresetPtr& rxPreset) { return rxPreset->getPresetId() == aPresetId; });
+ if (aIt != rPresetList.end())
+ {
+ pPage->setTransitionType( (*aIt)->getTransition() );
+ pPage->setTransitionSubtype( (*aIt)->getSubtype() );
+ pPage->setTransitionDirection( (*aIt)->getDirection() );
+ pPage->setTransitionFadeColor( (*aIt)->getFadeColor() );
+ }
+ }
+ else
+ {
+ pPage->setTransitionType( 0 );
+ pPage->setTransitionSubtype( 0 );
+ pPage->setTransitionDirection( false );
+ pPage->setTransitionFadeColor( 0 );
+ }
+}
+
+FadeEffect EffectMigration::GetFadeEffect( const SdPage* pPage )
+{
+ const TransitionPresetList & rPresetList = TransitionPreset::getTransitionPresetList();
+ auto aIt = std::find_if(rPresetList.begin(), rPresetList.end(),
+ [&pPage](const TransitionPresetPtr& rxPreset) {
+ return (rxPreset->getTransition() == pPage->getTransitionType())
+ && (rxPreset->getSubtype() == pPage->getTransitionSubtype())
+ && (rxPreset->getDirection() == pPage->getTransitionDirection())
+ && (rxPreset->getFadeColor() == pPage->getTransitionFadeColor());
+ });
+ if (aIt != rPresetList.end())
+ {
+ const OUString& aPresetId = (*aIt)->getPresetId();
+
+ deprecated_FadeEffect_conversion_table_entry const * pEntry = deprecated_FadeEffect_conversion_table;
+ while( (pEntry->meFadeEffect != FadeEffect_NONE) && (!aPresetId.equalsAscii( pEntry->mpPresetId ) ) )
+ pEntry++;
+
+ return pEntry->meFadeEffect;
+ }
+ return FadeEffect_NONE;
+}
+
+namespace {
+
+struct deprecated_AnimationEffect_conversion_table_entry
+{
+ AnimationEffect meEffect;
+ const char* mpPresetId;
+ const char* mpPresetSubType;
+};
+
+}
+
+deprecated_AnimationEffect_conversion_table_entry const deprecated_AnimationEffect_conversion_table[] =
+{
+// OOo 1.x entrance effects
+ { AnimationEffect_APPEAR, "ooo-entrance-appear",nullptr },
+
+ { AnimationEffect_FADE_TO_CENTER, "ooo-entrance-box","in" },
+ { AnimationEffect_FADE_FROM_CENTER, "ooo-entrance-box","out" },
+
+ { AnimationEffect_VERTICAL_CHECKERBOARD, "ooo-entrance-checkerboard","downward" },
+ { AnimationEffect_HORIZONTAL_CHECKERBOARD, "ooo-entrance-checkerboard","across" },
+
+ { AnimationEffect_FADE_FROM_UPPERLEFT, "ooo-entrance-diagonal-squares","right-to-bottom" },
+ { AnimationEffect_FADE_FROM_UPPERRIGHT, "ooo-entrance-diagonal-squares","left-to-bottom" },
+ { AnimationEffect_FADE_FROM_LOWERLEFT, "ooo-entrance-diagonal-squares","right-to-top" },
+ { AnimationEffect_FADE_FROM_LOWERRIGHT, "ooo-entrance-diagonal-squares","left-to-top" },
+
+ { AnimationEffect_DISSOLVE, "ooo-entrance-dissolve-in",nullptr },
+
+ { AnimationEffect_MOVE_FROM_LEFT, "ooo-entrance-fly-in","from-left" },
+ { AnimationEffect_MOVE_FROM_TOP, "ooo-entrance-fly-in","from-top" },
+ { AnimationEffect_MOVE_FROM_RIGHT, "ooo-entrance-fly-in","from-right" },
+ { AnimationEffect_MOVE_FROM_BOTTOM, "ooo-entrance-fly-in","from-bottom" },
+ { AnimationEffect_MOVE_FROM_UPPERLEFT, "ooo-entrance-fly-in","from-top-left" },
+ { AnimationEffect_MOVE_FROM_UPPERRIGHT, "ooo-entrance-fly-in","from-top-right" },
+ { AnimationEffect_MOVE_FROM_LOWERRIGHT, "ooo-entrance-fly-in","from-bottom-right" },
+ { AnimationEffect_MOVE_FROM_LOWERLEFT, "ooo-entrance-fly-in","from-bottom-left" },
+
+ { AnimationEffect_MOVE_FROM_BOTTOM, "ooo-entrance-fly-in-slow", "from-bottom" },
+ { AnimationEffect_MOVE_FROM_LEFT, "ooo-entrance-fly-in-slow", "from-left" },
+ { AnimationEffect_MOVE_FROM_RIGHT, "ooo-entrance-fly-in-slow", "from-right" },
+ { AnimationEffect_MOVE_FROM_TOP, "ooo-entrance-fly-in-slow", "from-top" },
+
+ { AnimationEffect_MOVE_SHORT_FROM_LEFT, "ooo-entrance-peek-in","from-left" },
+ { AnimationEffect_MOVE_SHORT_FROM_TOP, "ooo-entrance-peek-in","from-top" },
+ { AnimationEffect_MOVE_SHORT_FROM_RIGHT, "ooo-entrance-peek-in","from-right" },
+ { AnimationEffect_MOVE_SHORT_FROM_BOTTOM, "ooo-entrance-peek-in","from-bottom" },
+
+ { AnimationEffect_VERTICAL_LINES, "ooo-entrance-random-bars","horizontal" },
+ { AnimationEffect_HORIZONTAL_LINES, "ooo-entrance-random-bars","vertical" },
+
+ { AnimationEffect_RANDOM, "ooo-entrance-random",nullptr },
+
+ { AnimationEffect_CLOSE_VERTICAL, "ooo-entrance-split","horizontal-in" },
+ { AnimationEffect_CLOSE_HORIZONTAL, "ooo-entrance-split","vertical-in" },
+ { AnimationEffect_OPEN_VERTICAL, "ooo-entrance-split","horizontal-out" },
+ { AnimationEffect_OPEN_HORIZONTAL, "ooo-entrance-split","vertical-out" },
+
+ { AnimationEffect_VERTICAL_STRIPES, "ooo-entrance-venetian-blinds","horizontal" },
+ { AnimationEffect_HORIZONTAL_STRIPES, "ooo-entrance-venetian-blinds","vertical" },
+
+ { AnimationEffect_FADE_FROM_LEFT, "ooo-entrance-wipe","from-left" },
+ { AnimationEffect_FADE_FROM_TOP, "ooo-entrance-wipe","from-bottom" },
+ { AnimationEffect_FADE_FROM_RIGHT, "ooo-entrance-wipe","from-right" },
+ { AnimationEffect_FADE_FROM_BOTTOM, "ooo-entrance-wipe","from-top" },
+
+ { AnimationEffect_HORIZONTAL_ROTATE, "ooo-entrance-swivel","vertical" },
+ { AnimationEffect_VERTICAL_ROTATE, "ooo-entrance-swivel","horizontal" },
+
+ { AnimationEffect_STRETCH_FROM_LEFT, "ooo-entrance-stretchy","from-left" },
+ { AnimationEffect_STRETCH_FROM_UPPERLEFT, "ooo-entrance-stretchy","from-top-left" },
+ { AnimationEffect_STRETCH_FROM_TOP, "ooo-entrance-stretchy","from-top" },
+ { AnimationEffect_STRETCH_FROM_UPPERRIGHT, "ooo-entrance-stretchy","from-top-right" },
+ { AnimationEffect_STRETCH_FROM_RIGHT, "ooo-entrance-stretchy","from-right" },
+ { AnimationEffect_STRETCH_FROM_LOWERRIGHT, "ooo-entrance-stretchy","from-bottom-right" },
+ { AnimationEffect_STRETCH_FROM_BOTTOM, "ooo-entrance-stretchy","from-bottom" },
+ { AnimationEffect_STRETCH_FROM_LOWERLEFT, "ooo-entrance-stretchy","from-bottom-left" },
+
+ { AnimationEffect_HORIZONTAL_STRETCH, "ooo-entrance-expand", nullptr },
+
+ { AnimationEffect_CLOCKWISE, "ooo-entrance-wheel","1" },
+ { AnimationEffect_COUNTERCLOCKWISE, "ooo-entrance-clock-wipe","counter-clockwise" },
+
+ { AnimationEffect_SPIRALIN_LEFT, "ooo-entrance-spiral-wipe", "from-top-left-clockwise" },
+ { AnimationEffect_SPIRALIN_RIGHT, "ooo-entrance-spiral-wipe", "from-top-right-counter-clockwise" },
+ { AnimationEffect_SPIRALOUT_LEFT, "ooo-entrance-spiral-wipe", "from-center-clockwise" },
+ { AnimationEffect_SPIRALOUT_RIGHT, "ooo-entrance-spiral-wipe", "from-center-counter-clockwise" },
+
+ { AnimationEffect_WAVYLINE_FROM_LEFT, "ooo-entrance-snake-wipe","from-top-left-vertical" },
+ { AnimationEffect_WAVYLINE_FROM_TOP, "ooo-entrance-snake-wipe","from-top-left-horizontal" },
+ { AnimationEffect_WAVYLINE_FROM_RIGHT, "ooo-entrance-snake-wipe","from-bottom-right-vertical" },
+ { AnimationEffect_WAVYLINE_FROM_BOTTOM, "ooo-entrance-snake-wipe","from-bottom-right-horizontal" },
+
+// ooo 1.x exit effects
+ { AnimationEffect_HIDE, "ooo-exit-disappear",nullptr },
+ { AnimationEffect_MOVE_TO_LEFT, "ooo-exit-fly-out", "from-right" },
+ { AnimationEffect_MOVE_TO_TOP, "ooo-exit-fly-out", "from-bottom" },
+ { AnimationEffect_MOVE_TO_RIGHT, "ooo-exit-fly-out", "from-left" },
+ { AnimationEffect_MOVE_TO_BOTTOM, "ooo-exit-fly-out", "from-top" },
+ { AnimationEffect_MOVE_TO_UPPERLEFT, "ooo-exit-fly-out", "from-top-right" },
+ { AnimationEffect_MOVE_TO_UPPERRIGHT, "ooo-exit-fly-out", "from-top-left" },
+ { AnimationEffect_MOVE_TO_LOWERRIGHT, "ooo-exit-fly-out", "from-bottom-left" },
+ { AnimationEffect_MOVE_TO_LOWERLEFT, "ooo-exit-fly-out", "from-bottom-right" },
+ { AnimationEffect_MOVE_SHORT_TO_LEFT, "ooo-exit-peek-out", "from-right" },
+ { AnimationEffect_MOVE_SHORT_TO_UPPERLEFT, "ooo-exit-peek-out", "from-right" },
+ { AnimationEffect_MOVE_SHORT_TO_TOP, "ooo-exit-peek-out", "from-bottom" },
+ { AnimationEffect_MOVE_SHORT_TO_UPPERRIGHT, "ooo-exit-peek-out", "from-bottom" },
+ { AnimationEffect_MOVE_SHORT_TO_RIGHT, "ooo-exit-peek-out", "from-left" },
+ { AnimationEffect_MOVE_SHORT_TO_LOWERRIGHT, "ooo-exit-peek-out","from-left" },
+ { AnimationEffect_MOVE_SHORT_TO_BOTTOM, "ooo-exit-peek-out", "from-top" },
+ { AnimationEffect_MOVE_SHORT_TO_LOWERLEFT, "ooo-exit-peek-out", "from-top" },
+
+// no matching in OOo 2.x
+ { AnimationEffect_MOVE_SHORT_FROM_UPPERLEFT, "ooo-entrance-peek-in","from-left" },
+ { AnimationEffect_MOVE_SHORT_FROM_UPPERRIGHT, "ooo-entrance-peek-in","from-top" },
+ { AnimationEffect_MOVE_SHORT_FROM_LOWERRIGHT, "ooo-entrance-peek-in","from-right" },
+ { AnimationEffect_MOVE_SHORT_FROM_LOWERLEFT, "ooo-entrance-peek-in","from-bottom" },
+ { AnimationEffect_LASER_FROM_LEFT, "ooo-entrance-fly-in","from-left" },
+ { AnimationEffect_LASER_FROM_TOP, "ooo-entrance-fly-in","from-top" },
+ { AnimationEffect_LASER_FROM_RIGHT, "ooo-entrance-fly-in","from-right" },
+ { AnimationEffect_LASER_FROM_BOTTOM, "ooo-entrance-fly-in","from-bottom" },
+ { AnimationEffect_LASER_FROM_UPPERLEFT, "ooo-entrance-fly-in","from-top-left" },
+ { AnimationEffect_LASER_FROM_UPPERRIGHT, "ooo-entrance-fly-in","from-top-right" },
+ { AnimationEffect_LASER_FROM_LOWERLEFT, "ooo-entrance-fly-in","from-bottom-left" },
+ { AnimationEffect_LASER_FROM_LOWERRIGHT, "ooo-entrance-fly-in","from-bottom-right" },
+
+// no matching in OOo 1.x
+
+ { AnimationEffect_FADE_TO_CENTER, "ooo-entrance-circle", "in" },
+ { AnimationEffect_FADE_FROM_CENTER, "ooo-entrance-circle", "out" },
+ { AnimationEffect_FADE_TO_CENTER, "ooo-entrance-diamond", "in" },
+ { AnimationEffect_FADE_FROM_CENTER, "ooo-entrance-diamond", "out" },
+ { AnimationEffect_FADE_TO_CENTER, "ooo-entrance-plus", "in" },
+ { AnimationEffect_FADE_FROM_CENTER, "ooo-entrance-plus", "out" },
+ { AnimationEffect_CLOCKWISE, "ooo-entrance-wedge", nullptr },
+ { AnimationEffect_CLOCKWISE, "ooo-entrance-wheel", "2" },
+ { AnimationEffect_CLOCKWISE, "ooo-entrance-wheel", "3" },
+ { AnimationEffect_CLOCKWISE, "ooo-entrance-wheel", "4" },
+ { AnimationEffect_CLOCKWISE, "ooo-entrance-wheel", "8" },
+
+ { AnimationEffect_MOVE_FROM_RIGHT, "ooo-entrance-boomerang", nullptr },
+ { AnimationEffect_MOVE_FROM_UPPERRIGHT, "ooo-entrance-bounce", nullptr },
+ { AnimationEffect_MOVE_FROM_BOTTOM, "ooo-entrance-curve-up", nullptr },
+ { AnimationEffect_MOVE_FROM_TOP, "ooo-entrance-float", nullptr },
+ { AnimationEffect_MOVE_FROM_LEFT, "ooo-entrance-glide", nullptr },
+ { AnimationEffect_MOVE_FROM_BOTTOM, "ooo-entrance-magnify", nullptr },
+ { AnimationEffect_HORIZONTAL_ROTATE, "ooo-entrance-pinwheel", nullptr },
+ { AnimationEffect_MOVE_FROM_LEFT, "ooo-entrance-breaks", nullptr },
+ { AnimationEffect_MOVE_FROM_LEFT, "ooo-entrance-sling", nullptr },
+ { AnimationEffect_MOVE_FROM_LEFT, "ooo-entrance-spiral-in", nullptr },
+ { AnimationEffect_MOVE_FROM_LEFT, "ooo-entrance-thread", nullptr },
+ { AnimationEffect_MOVE_FROM_BOTTOM, "ooo-entrance-ascend", nullptr },
+ { AnimationEffect_MOVE_FROM_BOTTOM, "ooo-entrance-center-revolve", nullptr },
+ { AnimationEffect_APPEAR, "ooo-entrance-compress", nullptr },
+ { AnimationEffect_MOVE_SHORT_FROM_TOP, "ooo-entrance-descend", nullptr },
+ { AnimationEffect_MOVE_SHORT_FROM_LEFT, "ooo-entrance-ease-in", nullptr },
+ { AnimationEffect_MOVE_FROM_BOTTOM, "ooo-entrance-rise-up", nullptr },
+ { AnimationEffect_HORIZONTAL_ROTATE, "ooo-entrance-spin-in", nullptr },
+ { AnimationEffect_STRETCH_FROM_LEFT, "ooo-entrance-stretchy", "across" },
+ { AnimationEffect_STRETCH_FROM_TOP, "ooo-entrance-stretchy", "downward" },
+
+ { AnimationEffect_FADE_FROM_CENTER, "ooo-entrance-zoom","in" },
+ { AnimationEffect_FADE_FROM_CENTER, "ooo-entrance-zoom","in-slightly" },
+ { AnimationEffect_FADE_FROM_CENTER, "ooo-entrance-zoom","in-from-screen-center" },
+ { AnimationEffect_FADE_TO_CENTER, "ooo-entrance-zoom","out" },
+ { AnimationEffect_FADE_TO_CENTER, "ooo-entrance-zoom","out-slightly" },
+ { AnimationEffect_FADE_TO_CENTER, "ooo-entrance-zoom","out-from-screen-center" },
+
+ { AnimationEffect_DISSOLVE, "ooo-entrance-fade-in", nullptr },
+ { AnimationEffect_DISSOLVE, "ooo-entrance-fade-in-and-zoom", nullptr },
+ { AnimationEffect_DISSOLVE, "ooo-entrance-fade-in-and-swivel", nullptr },
+
+ // still open (no matching effect: AnimationEffect_ZOOM_IN_FROM_*,
+ // AnimationEffect_ZOOM_OUT_FROM_*, AnimationEffect_PATH
+
+ { AnimationEffect_NONE, nullptr, nullptr }
+};
+
+static EffectSequence::iterator ImplFindEffect( MainSequencePtr const & pMainSequence, const Reference< XShape >& rShape, sal_Int16 nSubItem )
+{
+ return std::find_if(pMainSequence->getBegin(), pMainSequence->getEnd(),
+ [&rShape, &nSubItem](const CustomAnimationEffectPtr& pEffect) {
+ return (pEffect->getTargetShape() == rShape)
+ && (pEffect->getTargetSubItem() == nSubItem);
+ });
+}
+
+static bool implIsInsideGroup( SdrObject const * pObj )
+{
+ // TTTT for current state of transition, SdrObject has a parent*
+ // to a SdrObjList. That may be a SdrPage or a SdrObjGroup, both
+ // are already derived from SdrObjList. To finally check, use
+ // the method 'getSdrObjectFromSdrObjList' - if it's not a SdrPage,
+ // it will return SdrObjGroup or E3dScene -> SdrObject.
+ // For future states, test for SdrObject. Trying to get the SdrPage
+ // will in the future depend on the Object(this) to be inserted to a
+ // SdrPage, regardless of e.g. being a group member.
+ if(nullptr == pObj)
+ {
+ return false;
+ }
+
+ SdrObjList* pSdrObjList(pObj->getParentSdrObjListFromSdrObject());
+
+ if(nullptr == pSdrObjList)
+ {
+ return false;
+ }
+
+ return (nullptr != pSdrObjList->getSdrObjectFromSdrObjList());
+}
+
+void EffectMigration::SetAnimationEffect( SvxShape* pShape, AnimationEffect eEffect )
+{
+ DBG_ASSERT( pShape && pShape->GetSdrObject() && pShape->GetSdrObject()->getSdrPageFromSdrObject(),
+ "sd::EffectMigration::SetAnimationEffect(), invalid argument!" );
+ if( !pShape || !pShape->GetSdrObject() || !pShape->GetSdrObject()->getSdrPageFromSdrObject() )
+ return;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( implIsInsideGroup( pObj ) )
+ return;
+
+ OUString aPresetId;
+ OUString aPresetSubType;
+
+ if( !ConvertAnimationEffect( eEffect, aPresetId, aPresetSubType ) )
+ {
+ OSL_FAIL( "sd::EffectMigration::SetAnimationEffect(), no mapping for given AnimationEffect value" );
+ return;
+ }
+
+ const CustomAnimationPresets& rPresets = CustomAnimationPresets::getCustomAnimationPresets();
+
+ CustomAnimationPresetPtr pPreset( rPresets.getEffectDescriptor( aPresetId ) );
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ if( !(pPreset && pMainSequence) )
+ return;
+
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIterOnlyBackground( ImplFindEffect( pMainSequence, xShape, ShapeAnimationSubType::ONLY_BACKGROUND ) );
+ EffectSequence::iterator aIterAsWhole( ImplFindEffect( pMainSequence, xShape, ShapeAnimationSubType::AS_WHOLE ) );
+ const EffectSequence::iterator aEnd( pMainSequence->getEnd() );
+
+ if( (aIterOnlyBackground == aEnd) && (aIterAsWhole == aEnd) )
+ {
+ bool bEffectCreated = false;
+
+ // check if there is already a text effect for this shape
+ EffectSequence::iterator aIterOnlyText( ImplFindEffect( pMainSequence, xShape, ShapeAnimationSubType::ONLY_TEXT ) );
+ if( aIterOnlyText != aEnd )
+ {
+ // check if this is an animation text group
+ sal_Int32 nGroupId = (*aIterOnlyText)->getGroupId();
+ if( nGroupId >= 0 )
+ {
+ CustomAnimationTextGroupPtr pGroup = pMainSequence->findGroup( nGroupId );
+ if( pGroup )
+ {
+ // add an effect to animate the shape
+ pMainSequence->setAnimateForm( pGroup, true );
+
+ // find this effect
+ EffectSequence::iterator aIter( ImplFindEffect( pMainSequence, xShape, ShapeAnimationSubType::ONLY_BACKGROUND ) );
+
+ if( aIter != aEnd )
+ {
+ if( ((*aIter)->getPresetId() != aPresetId) ||
+ ((*aIter)->getPresetSubType() != aPresetSubType) )
+ {
+ (*aIter)->replaceNode( pPreset->create( aPresetSubType ) );
+ pMainSequence->rebuild();
+ bEffectCreated = true;
+ }
+ }
+ }
+ }
+ }
+
+ if( !bEffectCreated )
+ {
+ // if there is not yet an effect that target this shape, we generate one
+ // we insert the shape effect before it
+ Reference< XAnimationNode > xNode( pPreset->create( aPresetSubType ) );
+ DBG_ASSERT( xNode.is(), "EffectMigration::SetAnimationEffect(), could not create preset!" );
+ if( xNode.is() )
+ {
+ CustomAnimationEffectPtr pEffect = std::make_shared<CustomAnimationEffect>( xNode );
+ pEffect->setTarget( Any( xShape ) );
+ SdPage* pPage = dynamic_cast< SdPage* >( pObj->getSdrPageFromSdrObject() );
+ const bool bManual = (pPage == nullptr) || (pPage->GetPresChange() == PresChange::Manual);
+ if( !bManual )
+ pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
+
+ pMainSequence->append( pEffect );
+
+ if( ( pObj->GetObjInventor() == SdrInventor::Default ) && ( pObj->GetObjIdentifier() == SdrObjKind::OutlineText ) )
+ {
+ // special case for outline text, effects are always mapped to text group effect
+ pMainSequence->
+ createTextGroup( pEffect, 10, bManual ? -1 : 0.0, false, false );
+ }
+ }
+ }
+ }
+ else
+ {
+ // if there is already an effect targeting this shape
+ // just replace it
+ CustomAnimationEffectPtr pEffect;
+ if( aIterAsWhole != aEnd )
+ {
+ pEffect = *aIterAsWhole;
+ }
+ else
+ {
+ pEffect = *aIterOnlyBackground;
+ }
+
+ if( pEffect )
+ {
+ if( (pEffect->getPresetId() != aPresetId) ||
+ (pEffect->getPresetSubType() != aPresetSubType) )
+ {
+ pMainSequence->replace( pEffect, pPreset, aPresetSubType, -1.0 );
+ }
+ }
+ }
+}
+
+AnimationEffect EffectMigration::GetAnimationEffect( SvxShape* pShape )
+{
+ OUString aPresetId;
+ OUString aPresetSubType;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ if( pMainSequence )
+ {
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIter = std::find_if(pMainSequence->getBegin(), pMainSequence->getEnd(),
+ [&xShape](const CustomAnimationEffectPtr& pEffect) {
+ return (pEffect->getTargetShape() == xShape)
+ && ((pEffect->getTargetSubItem() == ShapeAnimationSubType::ONLY_BACKGROUND)
+ || (pEffect->getTargetSubItem() == ShapeAnimationSubType::AS_WHOLE))
+ && (pEffect->getDuration() != 0.1); // ignore appear effects created from old text effect import
+ });
+
+ if (aIter != pMainSequence->getEnd())
+ {
+ aPresetId = (*aIter)->getPresetId();
+ aPresetSubType = (*aIter)->getPresetSubType();
+ }
+ }
+
+ // now find old effect
+ AnimationEffect eEffect = AnimationEffect_NONE;
+
+ if( !ConvertPreset( aPresetId, &aPresetSubType, eEffect ) )
+ ConvertPreset( aPresetId, nullptr, eEffect );
+
+ return eEffect;
+}
+
+void EffectMigration::SetTextAnimationEffect( SvxShape* pShape, AnimationEffect eEffect )
+{
+ DBG_ASSERT( pShape && pShape->GetSdrObject() && pShape->GetSdrObject()->getSdrPageFromSdrObject(),
+ "sd::EffectMigration::SetAnimationEffect(), invalid argument!" );
+ if( !pShape || !pShape->GetSdrObject() || !pShape->GetSdrObject()->getSdrPageFromSdrObject() )
+ return;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( implIsInsideGroup( pObj ) )
+ return;
+
+ // first map the deprecated AnimationEffect to a preset and subtype
+ OUString aPresetId;
+ OUString aPresetSubType;
+
+ if( !ConvertAnimationEffect( eEffect, aPresetId, aPresetSubType ) )
+ {
+ OSL_FAIL( "sd::EffectMigration::SetAnimationEffect(), no mapping for given AnimationEffect value" );
+ return;
+ }
+
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObj );
+
+ // ignore old text effects on shape without text
+ if( (pTextObj == nullptr) || (!pTextObj->HasText()) )
+ return;
+
+ const CustomAnimationPresets& rPresets = CustomAnimationPresets::getCustomAnimationPresets();
+
+ // create an effect from this preset
+ CustomAnimationPresetPtr pPreset( rPresets.getEffectDescriptor( aPresetId ) );
+
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ if( !(pPreset && pMainSequence) )
+ return;
+
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIterOnlyText( ImplFindEffect( pMainSequence, xShape, ShapeAnimationSubType::ONLY_TEXT ) );
+ const EffectSequence::iterator aEnd( pMainSequence->getEnd() );
+
+ CustomAnimationTextGroupPtr pGroup;
+
+ // is there already an animation text group for this shape?
+ if( aIterOnlyText != aEnd )
+ {
+ const sal_Int32 nGroupId = (*aIterOnlyText)->getGroupId();
+ if( nGroupId >= 0 )
+ pGroup = pMainSequence->findGroup( nGroupId );
+ }
+
+ // if there is not yet a group, create it
+ if( !pGroup )
+ {
+ CustomAnimationEffectPtr pShapeEffect;
+
+ EffectSequence::iterator aIterOnlyBackground( ImplFindEffect( pMainSequence, xShape, ShapeAnimationSubType::ONLY_BACKGROUND ) );
+ if( aIterOnlyBackground != aEnd )
+ {
+ pShapeEffect = *aIterOnlyBackground;
+ }
+ else
+ {
+ EffectSequence::iterator aIterAsWhole( ImplFindEffect( pMainSequence, xShape, ShapeAnimationSubType::AS_WHOLE ) );
+ if( aIterAsWhole != aEnd )
+ {
+ pShapeEffect = *aIterAsWhole;
+ }
+ else
+ {
+ Reference< XAnimationNode > xNode( pPreset->create( "" ) );
+ DBG_ASSERT( xNode.is(), "EffectMigration::SetTextAnimationEffect(), could not create preset!" );
+ if( xNode.is() )
+ {
+ pShapeEffect = std::make_shared<CustomAnimationEffect>( xNode );
+ pShapeEffect->setTarget( Any( xShape ) );
+ pShapeEffect->setDuration( 0.1 );
+ pMainSequence->append( pShapeEffect );
+
+ SdPage* pPage = dynamic_cast< SdPage* >( pObj->getSdrPageFromSdrObject() );
+ if( pPage && pPage->GetPresChange() != PresChange::Manual )
+ pShapeEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
+ }
+ }
+ }
+
+ if( pShapeEffect )
+ {
+ SdPage* pPage = dynamic_cast< SdPage* >( pObj->getSdrPageFromSdrObject() );
+ const bool bManual = (pPage == nullptr) || (pPage->GetPresChange() == PresChange::Manual);
+
+ // now create effects for each paragraph
+ pGroup =
+ pMainSequence->
+ createTextGroup( pShapeEffect, 10, bManual ? -1 : 0.0, true, false );
+ }
+ }
+
+ if( pGroup )
+ {
+ const bool bLaserEffect = (eEffect >= AnimationEffect_LASER_FROM_LEFT) && (eEffect <= AnimationEffect_LASER_FROM_LOWERRIGHT);
+
+ // now we have a group, so check if all effects are same as we like to have them
+ const EffectSequence& rEffects = pGroup->getEffects();
+
+ for( auto& rxEffect : rEffects )
+ {
+ // only work on paragraph targets
+ if( rxEffect->getTarget().getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ if( (rxEffect->getPresetId() != aPresetId) ||
+ (rxEffect->getPresetSubType() != aPresetSubType) )
+ {
+ rxEffect->replaceNode( pPreset->create( aPresetSubType ) );
+ }
+
+ if( bLaserEffect )
+ {
+ rxEffect->setIterateType( TextAnimationType::BY_LETTER );
+ rxEffect->setIterateInterval( 0.5 );// TODO:
+ // Determine
+ // interval
+ // according
+ // to
+ // total
+ // effect
+ // duration
+ }
+ }
+ }
+ }
+ pMainSequence->rebuild();
+}
+
+AnimationEffect EffectMigration::GetTextAnimationEffect( SvxShape* pShape )
+{
+ OUString aPresetId;
+ OUString aPresetSubType;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( pObj )
+ {
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ if( pMainSequence )
+ {
+ const Reference< XShape > xShape( pShape );
+ EffectSequence::iterator aIter( ImplFindEffect( pMainSequence, xShape, ShapeAnimationSubType::ONLY_TEXT ) );
+ if( aIter != pMainSequence->getEnd() )
+ {
+ aPresetId = (*aIter)->getPresetId();
+ aPresetSubType = (*aIter)->getPresetSubType();
+ }
+ }
+ }
+
+ // now find old effect
+ AnimationEffect eEffect = AnimationEffect_NONE;
+
+ if( !ConvertPreset( aPresetId, &aPresetSubType, eEffect ) )
+ ConvertPreset( aPresetId, nullptr, eEffect );
+
+ return eEffect;
+}
+
+bool EffectMigration::ConvertPreset( std::u16string_view rPresetId, const OUString* pPresetSubType, AnimationEffect& rEffect )
+{
+ rEffect = AnimationEffect_NONE;
+ if( !rPresetId.empty() )
+ {
+ // first try a match for preset id and subtype
+ deprecated_AnimationEffect_conversion_table_entry const * p = deprecated_AnimationEffect_conversion_table;
+ while( p->mpPresetId )
+ {
+ if( o3tl::equalsAscii( rPresetId, p->mpPresetId ) &&
+ (( p->mpPresetSubType == nullptr ) ||
+ ( pPresetSubType == nullptr) ||
+ ( pPresetSubType->equalsAscii( p->mpPresetSubType )) ) )
+ {
+ rEffect = p->meEffect;
+ return true;
+ }
+ p++;
+ }
+ return false;
+ }
+ else
+ {
+ // empty preset id means AnimationEffect_NONE
+ return true;
+ }
+}
+
+bool EffectMigration::ConvertAnimationEffect( const AnimationEffect& rEffect, OUString& rPresetId, OUString& rPresetSubType )
+{
+ deprecated_AnimationEffect_conversion_table_entry const * p = deprecated_AnimationEffect_conversion_table;
+ while( p->mpPresetId )
+ {
+ if( p->meEffect == rEffect )
+ {
+ rPresetId = OUString::createFromAscii( p->mpPresetId );
+ rPresetSubType = OUString::createFromAscii( p->mpPresetSubType );
+ return true;
+ }
+ p++;
+ }
+
+ return false;
+}
+
+double EffectMigration::ConvertAnimationSpeed( AnimationSpeed eSpeed )
+{
+ double fDuration;
+ switch( eSpeed )
+ {
+ case AnimationSpeed_SLOW: fDuration = 2.0; break;
+ case AnimationSpeed_FAST: fDuration = 0.5; break;
+ default:
+ fDuration = 1.0; break;
+ }
+ return fDuration;
+}
+
+void EffectMigration::SetAnimationSpeed( SvxShape* pShape, AnimationSpeed eSpeed )
+{
+ DBG_ASSERT( pShape && pShape->GetSdrObject() && pShape->GetSdrObject()->getSdrPageFromSdrObject(),
+ "sd::EffectMigration::SetAnimationEffect(), invalid argument!" );
+ if( !pShape || !pShape->GetSdrObject() || !pShape->GetSdrObject()->getSdrPageFromSdrObject() )
+ return;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( implIsInsideGroup( pObj ) )
+ return;
+
+ double fDuration = ConvertAnimationSpeed( eSpeed );
+
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIter;
+ bool bNeedRebuild = false;
+
+ for( aIter = pMainSequence->getBegin(); aIter != pMainSequence->getEnd(); ++aIter )
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ if( pEffect->getTargetShape() == xShape )
+ {
+ if( pEffect->getDuration() != 0.1 )
+ pEffect->setDuration( fDuration );
+ bNeedRebuild = true;
+ }
+ }
+
+ if( bNeedRebuild )
+ pMainSequence->rebuild();
+}
+
+AnimationSpeed EffectMigration::GetAnimationSpeed( SvxShape* pShape )
+{
+ SdrObject* pObj = pShape->GetSdrObject();
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ const Reference< XShape > xShape( pShape );
+
+ double fDuration = 1.0;
+
+ EffectSequence::iterator aIter = std::find_if(pMainSequence->getBegin(), pMainSequence->getEnd(),
+ [&xShape](const CustomAnimationEffectPtr& pEffect) {
+ return (pEffect->getTargetShape() == xShape)
+ && (pEffect->getDuration() != 0.1);
+ });
+ if (aIter != pMainSequence->getEnd())
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ fDuration = pEffect->getDuration();
+ }
+
+ return ConvertDuration( fDuration );
+}
+
+AnimationSpeed EffectMigration::ConvertDuration( double fDuration )
+{
+ AnimationSpeed eSpeed;
+
+ if( fDuration < 1.0 )
+ eSpeed = AnimationSpeed_FAST;
+ else if( fDuration > 1.5 )
+ eSpeed = AnimationSpeed_SLOW;
+ else
+ eSpeed = AnimationSpeed_MEDIUM;
+
+ return eSpeed;
+}
+
+void EffectMigration::SetDimColor( SvxShape* pShape, sal_Int32 nColor )
+{
+ DBG_ASSERT( pShape && pShape->GetSdrObject() && pShape->GetSdrObject()->getSdrPageFromSdrObject(),
+ "sd::EffectMigration::SetAnimationEffect(), invalid argument!" );
+ if( !pShape || !pShape->GetSdrObject() || !pShape->GetSdrObject()->getSdrPageFromSdrObject() )
+ return;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( implIsInsideGroup( pObj ) )
+ return;
+
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIter;
+ bool bNeedRebuild = false;
+
+ for( aIter = pMainSequence->getBegin(); aIter != pMainSequence->getEnd(); ++aIter )
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ if( pEffect->getTargetShape() == xShape )
+ {
+ pEffect->setHasAfterEffect( true );
+ pEffect->setDimColor( Any( nColor ) );
+ pEffect->setAfterEffectOnNext( true );
+ bNeedRebuild = true;
+ }
+ }
+
+ if( bNeedRebuild )
+ pMainSequence->rebuild();
+}
+
+sal_Int32 EffectMigration::GetDimColor( SvxShape* pShape )
+{
+ sal_Int32 nColor = 0;
+ if( pShape )
+ {
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( pObj && pObj->getSdrPageFromSdrObject() )
+ {
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ const Reference< XShape > xShape( pShape );
+ EffectSequence::iterator aIter = std::find_if(pMainSequence->getBegin(), pMainSequence->getEnd(),
+ [&xShape](const CustomAnimationEffectPtr& pEffect) {
+ return (pEffect->getTargetShape() == xShape)
+ && pEffect->getDimColor().hasValue()
+ && pEffect->hasAfterEffect();
+ });
+ if (aIter != pMainSequence->getEnd())
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ pEffect->getDimColor() >>= nColor;
+ }
+ }
+ }
+
+ return nColor;
+}
+
+void EffectMigration::SetDimHide( SvxShape* pShape, bool bDimHide )
+{
+ DBG_ASSERT( pShape && pShape->GetSdrObject() && pShape->GetSdrObject()->getSdrPageFromSdrObject(),
+ "sd::EffectMigration::SetAnimationEffect(), invalid argument!" );
+ if( !pShape || !pShape->GetSdrObject() || !pShape->GetSdrObject()->getSdrPageFromSdrObject() )
+ return;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( implIsInsideGroup( pObj ) )
+ return;
+
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIter;
+ bool bNeedRebuild = false;
+
+ for( aIter = pMainSequence->getBegin(); aIter != pMainSequence->getEnd(); ++aIter )
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ if( pEffect->getTargetShape() == xShape )
+ {
+ pEffect->setHasAfterEffect( bDimHide );
+ if( bDimHide ) {
+ Any aEmpty;
+ pEffect->setDimColor( aEmpty );
+ }
+ pEffect->setAfterEffectOnNext( false );
+ bNeedRebuild = true;
+ }
+ }
+
+ if( bNeedRebuild )
+ pMainSequence->rebuild();
+}
+
+bool EffectMigration::GetDimHide( SvxShape* pShape )
+{
+ bool bRet = false;
+ if( pShape )
+ {
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( pObj && pObj->getSdrPageFromSdrObject() )
+ {
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIter = std::find_if(pMainSequence->getBegin(), pMainSequence->getEnd(),
+ [&xShape](const CustomAnimationEffectPtr& pEffect) { return pEffect->getTargetShape() == xShape; });
+ if (aIter != pMainSequence->getEnd())
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ bRet = pEffect->hasAfterEffect() &&
+ !pEffect->getDimColor().hasValue() &&
+ (!pEffect->IsAfterEffectOnNext());
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void EffectMigration::SetDimPrevious( SvxShape* pShape, bool bDimPrevious )
+{
+ DBG_ASSERT( pShape && pShape->GetSdrObject() && pShape->GetSdrObject()->getSdrPageFromSdrObject(),
+ "sd::EffectMigration::SetAnimationEffect(), invalid argument!" );
+ if( !pShape || !pShape->GetSdrObject() || !pShape->GetSdrObject()->getSdrPageFromSdrObject() )
+ return;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( implIsInsideGroup( pObj ) )
+ return;
+
+ Any aColor;
+
+ if( bDimPrevious )
+ aColor <<= COL_LIGHTGRAY;
+
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIter;
+ bool bNeedRebuild = false;
+
+ for( aIter = pMainSequence->getBegin(); aIter != pMainSequence->getEnd(); ++aIter )
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ if( pEffect->getTargetShape() == xShape )
+ {
+ pEffect->setHasAfterEffect( bDimPrevious );
+ if( !bDimPrevious || !pEffect->getDimColor().hasValue() )
+ pEffect->setDimColor( aColor );
+ pEffect->setAfterEffectOnNext( true );
+ bNeedRebuild = true;
+ }
+ }
+
+ if( bNeedRebuild )
+ pMainSequence->rebuild();
+}
+
+bool EffectMigration::GetDimPrevious( SvxShape* pShape )
+{
+ bool bRet = false;
+ if( pShape )
+ {
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( pObj && pObj->getSdrPageFromSdrObject() )
+ {
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIter = std::find_if(pMainSequence->getBegin(), pMainSequence->getEnd(),
+ [&xShape](const CustomAnimationEffectPtr& pEffect) { return pEffect->getTargetShape() == xShape; });
+ if (aIter != pMainSequence->getEnd())
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ bRet = pEffect->hasAfterEffect() &&
+ pEffect->getDimColor().hasValue() &&
+ pEffect->IsAfterEffectOnNext();
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void EffectMigration::SetPresentationOrder( SvxShape* pShape, sal_Int32 nNewPos )
+{
+ if( !pShape || !pShape->GetSdrObject() || !pShape->GetSdrObject()->getSdrPageFromSdrObject() )
+ return;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ EffectSequence& rSequence = pMainSequence->getSequence();
+ sal_Int32 nPos;
+ sal_Int32 nCurrentPos = -1;
+ std::vector< std::vector< EffectSequence::iterator > > aEffectVector(1);
+
+ if( !rSequence.empty() )
+ {
+ Reference< XShape > xThis( pShape );
+ Reference< XShape > xCurrent;
+
+ EffectSequence::iterator aIter( rSequence.begin() );
+ EffectSequence::iterator aEnd( rSequence.end() );
+ for( nPos = 0; aIter != aEnd; ++aIter )
+ {
+ CustomAnimationEffectPtr pEffect = *aIter;
+
+ if( !xCurrent.is() )
+ {
+ xCurrent = pEffect->getTargetShape();
+ }
+ else if( pEffect->getTargetShape() != xCurrent )
+ {
+ nPos++;
+ xCurrent = pEffect->getTargetShape();
+ aEffectVector.resize( nPos+1 );
+ }
+
+ // is this the first effect for xThis shape?
+ if(( nCurrentPos == -1 ) && ( xCurrent == xThis ) )
+ {
+ nCurrentPos = nPos;
+ }
+
+ aEffectVector[nPos].push_back( aIter );
+ }
+ }
+
+ // check if there is at least one effect for xThis
+ if( nCurrentPos == -1 )
+ {
+ OSL_FAIL("sd::EffectMigration::SetPresentationOrder() failed cause this shape has no effect" );
+ return;
+ }
+
+ // check trivial case
+ if( nCurrentPos == nNewPos )
+ return;
+
+ std::vector< CustomAnimationEffectPtr > aEffects;
+
+ for( const auto& rIter : aEffectVector[nCurrentPos] )
+ {
+ aEffects.push_back( *rIter );
+ rSequence.erase( rIter );
+ }
+
+ if( nNewPos > nCurrentPos )
+ nNewPos++;
+
+ if( nNewPos == static_cast<sal_Int32>(aEffectVector.size()) )
+ {
+ rSequence.insert( rSequence.end(), aEffects.begin(), aEffects.end() );
+ }
+ else
+ {
+ EffectSequence::iterator aPos( aEffectVector[nNewPos][0] );
+ for( const auto& rEffect : aEffects )
+ {
+ rSequence.insert( aPos, rEffect );
+ }
+ }
+}
+
+/** Returns the position of the given SdrObject in the Presentation order.
+ * This function returns -1 if the SdrObject is not in the Presentation order
+ * or if it's the path-object.
+ */
+sal_Int32 EffectMigration::GetPresentationOrder( SvxShape* pShape )
+{
+ sal_Int32 nPos = -1, nFound = -1;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ EffectSequence& rSequence = pMainSequence->getSequence();
+
+ Reference< XShape > xThis( pShape );
+ Reference< XShape > xCurrent;
+
+ for( const CustomAnimationEffectPtr& pEffect : rSequence )
+ {
+ if( !xCurrent.is() || pEffect->getTargetShape() != xCurrent )
+ {
+ nPos++;
+ xCurrent = pEffect->getTargetShape();
+
+ // is this the first effect for xThis shape?
+ if( xCurrent == xThis )
+ {
+ nFound = nPos;
+ break;
+ }
+ }
+ }
+
+ return nFound;
+}
+
+void EffectMigration::UpdateSoundEffect( SvxShape* pShape, SdAnimationInfo const * pInfo )
+{
+ if( !pInfo )
+ return;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIter;
+ bool bNeedRebuild = false;
+
+ OUString aSoundFile;
+ if( pInfo->mbSoundOn )
+ aSoundFile = pInfo->maSoundFile;
+
+ for( aIter = pMainSequence->getBegin(); aIter != pMainSequence->getEnd(); ++aIter )
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ if( pEffect->getTargetShape() == xShape )
+ {
+ if( !aSoundFile.isEmpty() )
+ {
+ pEffect->createAudio( Any( aSoundFile ) );
+ }
+ else
+ {
+ pEffect->removeAudio();
+ }
+ bNeedRebuild = true;
+ }
+ }
+
+ if( bNeedRebuild )
+ pMainSequence->rebuild();
+}
+
+OUString EffectMigration::GetSoundFile( SvxShape* pShape )
+{
+ OUString aSoundFile;
+
+ if( pShape )
+ {
+ SdrObject* pObj = pShape->GetSdrObject();
+ if( pObj && pObj->getSdrPageFromSdrObject() )
+ {
+ sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+
+ const Reference< XShape > xShape( pShape );
+
+ EffectSequence::iterator aIter;
+
+ for( aIter = pMainSequence->getBegin();
+ (aSoundFile.isEmpty()) && (aIter != pMainSequence->getEnd());
+ ++aIter )
+ {
+ CustomAnimationEffectPtr pEffect( *aIter );
+ if( pEffect->getTargetShape() == xShape )
+ {
+ if( pEffect->getAudio().is() )
+ pEffect->getAudio()->getSource() >>= aSoundFile;
+ }
+ }
+ }
+ }
+ return aSoundFile;
+}
+
+bool EffectMigration::GetSoundOn( SvxShape* pShape )
+{
+ return !GetSoundFile( pShape ).isEmpty();
+}
+
+void EffectMigration::SetAnimationPath( SvxShape* pShape, SdrPathObj const * pPathObj )
+{
+ if( !(pShape && pPathObj) )
+ return;
+
+ SdrObject* pObj = pShape->GetSdrObject();
+
+ if( pObj )
+ {
+ const Reference< XShape > xShape( pShape );
+ SdPage* pPage = dynamic_cast< SdPage* >(pPathObj->getSdrPageFromSdrObject());
+ if( pPage )
+ {
+ std::shared_ptr< sd::MainSequence > pMainSequence( pPage->getMainSequence() );
+ if( pMainSequence )
+ pMainSequence->append( *pPathObj, Any( xShape ), -1.0, "" );
+ }
+ }
+}
+
+// #i42894# helper which creates the needed XAnimate for changing visibility and all the (currently) needed embeddings
+static void createVisibilityOnOffNode(Reference< XTimeContainer > const & rxParentContainer, SdrObject& rCandidate, bool bVisible, bool bOnClick, double fDuration)
+{
+ Reference< XMultiServiceFactory > xMsf(::comphelper::getProcessServiceFactory());
+
+ // create par container node
+ Reference< XAnimationNode > xOuterSeqTimeContainer(xMsf->createInstance("com.sun.star.animations.ParallelTimeContainer"), UNO_QUERY_THROW);
+
+ // set begin
+ xOuterSeqTimeContainer->setBegin(Any(0.0));
+
+ // set fill
+ xOuterSeqTimeContainer->setFill(AnimationFill::HOLD);
+
+ // set named values
+ Sequence< NamedValue > aUserDataSequence{
+ { /* Name */ "node-type",
+ /* Value */ Any(bOnClick ? EffectNodeType::ON_CLICK : EffectNodeType::AFTER_PREVIOUS) }
+ };
+
+ xOuterSeqTimeContainer->setUserData(aUserDataSequence);
+
+ // create animate set to change visibility for rCandidate
+ Reference< XAnimationNode > xAnimateSetForLast(xMsf->createInstance("com.sun.star.animations.AnimateSet"), UNO_QUERY_THROW);
+
+ // set begin
+ xAnimateSetForLast->setBegin(Any(0.0));
+
+ // set duration
+ xAnimateSetForLast->setDuration(Any(fDuration));
+
+ // set fill
+ xAnimateSetForLast->setFill(AnimationFill::HOLD);
+
+ // set target
+ Reference< XAnimate > xAnimate(xAnimateSetForLast, UNO_QUERY);
+ Reference< XShape > xTargetShape(rCandidate.getUnoShape(), UNO_QUERY);
+ xAnimate->setTarget(Any(xTargetShape));
+
+ // set AttributeName
+ xAnimate->setAttributeName("Visibility");
+
+ // set attribute value
+ xAnimate->setTo(Any(bVisible));
+
+ // ad set node to par node
+ Reference< XTimeContainer > xParentContainer(xOuterSeqTimeContainer, UNO_QUERY_THROW);
+ xParentContainer->appendChild(xAnimateSetForLast);
+
+ // add node
+ rxParentContainer->appendChild(xOuterSeqTimeContainer);
+}
+
+// #i42894# older native formats supported animated group objects, that means all members of the group
+// were shown animated by showing one after the other. This is no longer supported, but the following
+// fallback will create the needed SMIL animation stuff. Unfortunately the members of the group
+// have to be moved directly to the page, else the (explained to be generic, thus I expected this to
+// work) animations will not work in slideshow
+void EffectMigration::CreateAnimatedGroup(SdrObjGroup const & rGroupObj, SdPage& rPage)
+{
+ // aw080 will give a vector immediately
+ SdrObjListIter aIter(rGroupObj);
+
+ if(!aIter.Count())
+ return;
+
+ std::shared_ptr< sd::MainSequence > pMainSequence(rPage.getMainSequence());
+
+ if(!pMainSequence)
+ return;
+
+ std::vector< SdrObject* > aObjects;
+ aObjects.reserve(aIter.Count());
+
+ while(aIter.IsMore())
+ {
+ // do move to page rough with old/current stuff, will be different in aw080 anyways
+ SdrObject* pCandidate = aIter.Next();
+ rGroupObj.GetSubList()->NbcRemoveObject(pCandidate->GetOrdNum());
+ rPage.NbcInsertObject(pCandidate);
+ aObjects.push_back(pCandidate);
+ }
+
+ // create main node
+ Reference< XMultiServiceFactory > xMsf(::comphelper::getProcessServiceFactory());
+ Reference< XAnimationNode > xOuterSeqTimeContainer(xMsf->createInstance("com.sun.star.animations.ParallelTimeContainer"), UNO_QUERY_THROW);
+
+ // set begin
+ xOuterSeqTimeContainer->setBegin(Any(0.0));
+
+ // prepare parent container
+ Reference< XTimeContainer > xParentContainer(xOuterSeqTimeContainer, UNO_QUERY_THROW);
+
+ // prepare loop over objects
+ SdrObject* pNext = nullptr;
+ const double fDurationShow(0.2);
+ const double fDurationHide(0.001);
+
+ for(size_t a(0); a < aObjects.size(); a++)
+ {
+ SdrObject* pLast = pNext;
+ pNext = aObjects[a];
+
+ // create node
+ if(pLast)
+ {
+ createVisibilityOnOffNode(xParentContainer, *pLast, false, false, fDurationHide);
+ }
+
+ if(pNext)
+ {
+ createVisibilityOnOffNode(xParentContainer, *pNext, true, !a, fDurationShow);
+ }
+ }
+
+ // create end node
+ if(pNext)
+ {
+ createVisibilityOnOffNode(xParentContainer, *pNext, false, false, fDurationHide);
+ }
+
+ // add to main sequence and rebuild
+ pMainSequence->createEffects(xOuterSeqTimeContainer);
+ pMainSequence->rebuild();
+}
+
+void EffectMigration::DocumentLoaded(SdDrawDocument & rDoc)
+{
+ if (DocumentType::Draw == rDoc.GetDocumentType())
+ return; // no animations in Draw
+ for (sal_uInt16 n = 0; n < rDoc.GetSdPageCount(PageKind::Standard); ++n)
+ {
+ SdPage *const pPage = rDoc.GetSdPage(n, PageKind::Standard);
+ if (pPage->hasAnimationNode())
+ {
+ // this will force the equivalent of the MainSequence::onTimerHdl
+ // so that the animations are present in export-able representation
+ // *before* the import is finished
+ pPage->getMainSequence()->getRootNode();
+ }
+ }
+ for (sal_uInt16 n = 0; n < rDoc.GetMasterSdPageCount(PageKind::Standard); ++n)
+ {
+ SdPage *const pPage = rDoc.GetMasterSdPage(n, PageKind::Standard);
+ if (pPage->hasAnimationNode())
+ {
+ pPage->getMainSequence()->getRootNode();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/PageListWatcher.cxx b/sd/source/core/PageListWatcher.cxx
new file mode 100644
index 000000000..c3d8846fc
--- /dev/null
+++ b/sd/source/core/PageListWatcher.cxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PageListWatcher.hxx"
+
+#include <sdpage.hxx>
+#include <tools/debug.hxx>
+#include <svx/svdmodel.hxx>
+#include <sal/log.hxx>
+
+void ImpPageListWatcher::ImpRecreateSortedPageListOnDemand()
+{
+ // clear vectors
+ maPageVectorStandard.clear();
+ maPageVectorNotes.clear();
+ mpHandoutPage = nullptr;
+
+ // build up vectors again
+ const sal_uInt32 nPageCount(ImpGetPageCount());
+
+ for(sal_uInt32 a(0); a < nPageCount; a++)
+ {
+ SdPage* pCandidate = ImpGetPage(a);
+ DBG_ASSERT(pCandidate, "ImpPageListWatcher::ImpRecreateSortedPageListOnDemand: Invalid PageList in Model (!)");
+
+ switch(pCandidate->GetPageKind())
+ {
+ case PageKind::Standard:
+ {
+ maPageVectorStandard.push_back(pCandidate);
+ break;
+ }
+ case PageKind::Notes:
+ {
+ maPageVectorNotes.push_back(pCandidate);
+ break;
+ }
+ case PageKind::Handout:
+ {
+ DBG_ASSERT(!mpHandoutPage, "ImpPageListWatcher::ImpRecreateSortedPageListOnDemand: Two Handout pages in PageList of Model (!)");
+ mpHandoutPage = pCandidate;
+ break;
+ }
+ }
+ }
+
+ // set to valid
+ mbPageListValid = true;
+}
+
+ImpPageListWatcher::ImpPageListWatcher(const SdrModel& rModel)
+ : mrModel(rModel)
+ , mpHandoutPage(nullptr)
+ , mbPageListValid(false)
+{
+}
+
+ImpPageListWatcher::~ImpPageListWatcher()
+{
+}
+
+SdPage* ImpPageListWatcher::GetSdPage(PageKind ePgKind, sal_uInt32 nPgNum)
+{
+ SdPage* pRetval(nullptr);
+
+ if(!mbPageListValid)
+ {
+ ImpRecreateSortedPageListOnDemand();
+ }
+
+ switch(ePgKind)
+ {
+ case PageKind::Standard:
+ {
+ if( nPgNum < static_cast<sal_uInt32>(maPageVectorStandard.size()) )
+ pRetval = maPageVectorStandard[nPgNum];
+ else
+ {
+ SAL_INFO( "sd.core",
+ "ImpPageListWatcher::GetSdPage(PageKind::Standard): page number " << nPgNum << " >= " << maPageVectorStandard.size() );
+ }
+ break;
+ }
+ case PageKind::Notes:
+ {
+ if( nPgNum < static_cast<sal_uInt32>(maPageVectorNotes.size()) )
+ pRetval = maPageVectorNotes[nPgNum];
+ else
+ {
+ SAL_INFO( "sd.core",
+ "ImpPageListWatcher::GetSdPage(PageKind::Notes): page number " << nPgNum << " >= " << maPageVectorNotes.size() );
+ }
+ break;
+ }
+ case PageKind::Handout:
+ {
+ // #11420# for models used to transfer drawing shapes via clipboard it's ok to not have a handout page
+ DBG_ASSERT(nPgNum == 0, "ImpPageListWatcher::GetSdPage: access to non existing handout page (!)");
+ if (nPgNum == 0)
+ pRetval = mpHandoutPage;
+ else
+ {
+ DBG_ASSERT(nPgNum == 0,
+ "ImpPageListWatcher::GetSdPage: access to non existing handout page (!)");
+ }
+ break;
+ }
+ }
+
+ return pRetval;
+}
+
+sal_uInt32 ImpPageListWatcher::GetSdPageCount(PageKind ePgKind)
+{
+ sal_uInt32 nRetval(0);
+
+ if(!mbPageListValid)
+ {
+ ImpRecreateSortedPageListOnDemand();
+ }
+
+ switch(ePgKind)
+ {
+ case PageKind::Standard:
+ {
+ nRetval = maPageVectorStandard.size();
+ break;
+ }
+ case PageKind::Notes:
+ {
+ nRetval = maPageVectorNotes.size();
+ break;
+ }
+ case PageKind::Handout:
+ {
+ if(mpHandoutPage)
+ {
+ nRetval = 1;
+ }
+
+ break;
+ }
+ }
+
+ return nRetval;
+}
+
+sal_uInt32 ImpPageListWatcher::GetVisibleSdPageCount() const
+{
+ sal_uInt32 nVisiblePageCount = 0;
+
+ // build up vectors again
+ const sal_uInt32 nPageCount(ImpGetPageCount());
+
+ for(sal_uInt32 a(0); a < nPageCount; a++)
+ {
+ SdPage* pCandidate = ImpGetPage(a);
+ if ((pCandidate->GetPageKind() == PageKind::Standard)&&(!pCandidate->IsExcluded())) nVisiblePageCount++;
+ }
+ return nVisiblePageCount;
+}
+
+sal_uInt32 ImpDrawPageListWatcher::ImpGetPageCount() const
+{
+ return static_cast<sal_uInt32>(mrModel.GetPageCount());
+}
+
+SdPage* ImpDrawPageListWatcher::ImpGetPage(sal_uInt32 nIndex) const
+{
+ return const_cast<SdPage*>(static_cast<const SdPage*>(mrModel.GetPage(static_cast<sal_uInt16>(nIndex))));
+}
+
+ImpDrawPageListWatcher::ImpDrawPageListWatcher(const SdrModel& rModel)
+: ImpPageListWatcher(rModel)
+{
+}
+
+ImpDrawPageListWatcher::~ImpDrawPageListWatcher()
+{
+}
+
+sal_uInt32 ImpMasterPageListWatcher::ImpGetPageCount() const
+{
+ return static_cast<sal_uInt32>(mrModel.GetMasterPageCount());
+}
+
+SdPage* ImpMasterPageListWatcher::ImpGetPage(sal_uInt32 nIndex) const
+{
+ return const_cast<SdPage*>(static_cast<const SdPage*>(mrModel.GetMasterPage(static_cast<sal_uInt16>(nIndex))));
+}
+
+ImpMasterPageListWatcher::ImpMasterPageListWatcher(const SdrModel& rModel)
+: ImpPageListWatcher(rModel)
+{
+}
+
+ImpMasterPageListWatcher::~ImpMasterPageListWatcher()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/PageListWatcher.hxx b/sd/source/core/PageListWatcher.hxx
new file mode 100644
index 000000000..252d18615
--- /dev/null
+++ b/sd/source/core/PageListWatcher.hxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <pres.hxx>
+#include <sal/types.h>
+#include <vector>
+
+class SdPage;
+class SdrModel;
+
+/** Maintain a map of page indices to page objects for faster access that
+ remains valid during deletions and insertions of pages (#109538#).
+*/
+class ImpPageListWatcher
+{
+protected:
+ // typedefs for a vector of SdPages
+ typedef ::std::vector< SdPage* > SdPageVector;
+
+ const SdrModel& mrModel;
+
+ SdPageVector maPageVectorStandard;
+ SdPageVector maPageVectorNotes;
+ SdPage* mpHandoutPage;
+
+ bool mbPageListValid;
+
+ void ImpRecreateSortedPageListOnDemand();
+ virtual sal_uInt32 ImpGetPageCount() const = 0;
+
+ /** Return the page with the given index.
+ @param nIndex
+ When given an invalid index then NULL is returned.
+ */
+ virtual SdPage* ImpGetPage (sal_uInt32 nIndex) const = 0;
+
+public:
+ explicit ImpPageListWatcher(const SdrModel& rModel);
+ virtual ~ImpPageListWatcher();
+
+ void Invalidate() { mbPageListValid = false; }
+ SdPage* GetSdPage(PageKind ePgKind, sal_uInt32 nPgNum);
+ sal_uInt32 GetSdPageCount(PageKind ePgKind);
+ sal_uInt32 GetVisibleSdPageCount() const;
+};
+
+class ImpDrawPageListWatcher : public ImpPageListWatcher
+{
+protected:
+ virtual sal_uInt32 ImpGetPageCount() const override;
+ virtual SdPage* ImpGetPage(sal_uInt32 nIndex) const override;
+
+public:
+ explicit ImpDrawPageListWatcher(const SdrModel& rModel);
+ virtual ~ImpDrawPageListWatcher() override;
+};
+
+class ImpMasterPageListWatcher : public ImpPageListWatcher
+{
+protected:
+ virtual sal_uInt32 ImpGetPageCount() const override;
+ virtual SdPage* ImpGetPage(sal_uInt32 nIndex) const override;
+
+public:
+ explicit ImpMasterPageListWatcher(const SdrModel& rModel);
+ virtual ~ImpMasterPageListWatcher() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/TransitionPreset.cxx b/sd/source/core/TransitionPreset.cxx
new file mode 100644
index 000000000..8d3a9d1d1
--- /dev/null
+++ b/sd/source/core/TransitionPreset.cxx
@@ -0,0 +1,385 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <set>
+
+#include <com/sun/star/animations/XTransitionFilter.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <unotools/configmgr.hxx>
+#include <comphelper/getexpandeduri.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/lok.hxx>
+#include <unotools/syslocaleoptions.hxx>
+#include <officecfg/Office/UI/Effects.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+
+#include <CustomAnimationPreset.hxx>
+#include <TransitionPreset.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::animations;
+
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::container::XEnumerationAccess;
+using ::com::sun::star::container::XEnumeration;
+using ::com::sun::star::beans::NamedValue;
+
+namespace sd {
+
+TransitionPreset::TransitionPreset( const css::uno::Reference< css::animations::XAnimationNode >& xNode )
+{
+ // first locate preset id
+ const Sequence< NamedValue > aUserData( xNode->getUserData() );
+ const NamedValue* pProp = std::find_if(aUserData.begin(), aUserData.end(),
+ [](const NamedValue& rProp) { return rProp.Name == "preset-id"; });
+ if (pProp != aUserData.end())
+ pProp->Value >>= maPresetId;
+
+ // second, locate transition filter element
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW );
+ Reference< XTransitionFilter > xTransition( xEnumeration->nextElement(), UNO_QUERY_THROW );
+
+ mnTransition = xTransition->getTransition();
+ mnSubtype = xTransition->getSubtype();
+ mbDirection = xTransition->getDirection();
+ mnFadeColor = xTransition->getFadeColor();
+}
+
+bool TransitionPreset::importTransitionsFile( TransitionPresetList& rList,
+ Reference< XMultiServiceFactory > const & xServiceFactory,
+ const OUString& aURL )
+{
+ SAL_INFO("sd.transitions", "Importing " << aURL);
+
+ Reference< container::XNameAccess > xTransitionSets( officecfg::Office::UI::Effects::UserInterface::TransitionSets::get() );
+ Reference< container::XNameAccess > xTransitionGroups( officecfg::Office::UI::Effects::UserInterface::TransitionGroups::get() );
+ Reference< container::XNameAccess > xTransitionVariants( officecfg::Office::UI::Effects::UserInterface::TransitionVariants::get() );
+ Reference< container::XNameAccess > xTransitions( officecfg::Office::UI::Effects::UserInterface::Transitions::get() );
+
+ // import transition presets
+ Reference< XAnimationNode > xAnimationNode;
+
+ const std::set<sal_Int16> LOKSupportedTransitionTypes = {
+ TransitionType::BARWIPE,
+ TransitionType::BOXWIPE,
+ TransitionType::FOURBOXWIPE,
+ TransitionType::ELLIPSEWIPE,
+ TransitionType::CLOCKWIPE,
+ TransitionType::PINWHEELWIPE,
+ TransitionType::PUSHWIPE,
+ TransitionType::SLIDEWIPE,
+ TransitionType::FADE,
+ TransitionType::RANDOMBARWIPE,
+ TransitionType::CHECKERBOARDWIPE,
+ TransitionType::DISSOLVE,
+ TransitionType::SNAKEWIPE,
+ TransitionType::PARALLELSNAKESWIPE,
+ TransitionType::IRISWIPE,
+ TransitionType::BARNDOORWIPE,
+ TransitionType::VEEWIPE,
+ TransitionType::ZIGZAGWIPE,
+ TransitionType::BARNZIGZAGWIPE,
+ TransitionType::FANWIPE,
+ TransitionType::SINGLESWEEPWIPE,
+ TransitionType::WATERFALLWIPE,
+ TransitionType::SPIRALWIPE,
+ TransitionType::MISCDIAGONALWIPE,
+ TransitionType::BOXSNAKESWIPE
+ };
+
+ const std::set<sal_Int16> LOKSupportedTransitionSubTypes = {
+ TransitionSubType::DEFAULT,
+ TransitionSubType::LEFTTORIGHT,
+ TransitionSubType::TOPTOBOTTOM,
+ TransitionSubType::CORNERSIN,
+ TransitionSubType::CORNERSOUT,
+ TransitionSubType::VERTICAL,
+ TransitionSubType::HORIZONTAL,
+ TransitionSubType::DOWN,
+ TransitionSubType::CIRCLE,
+ TransitionSubType::CLOCKWISETWELVE,
+ TransitionSubType::CLOCKWISETHREE,
+ TransitionSubType::CLOCKWISESIX,
+ TransitionSubType::CLOCKWISENINE,
+ TransitionSubType::TWOBLADEVERTICAL,
+ TransitionSubType::TWOBLADEHORIZONTAL,
+ TransitionSubType::FOURBLADE,
+ TransitionSubType::FROMLEFT,
+ TransitionSubType::FROMTOP,
+ TransitionSubType::FROMRIGHT,
+ TransitionSubType::FROMBOTTOM,
+ TransitionSubType::CROSSFADE,
+ TransitionSubType::FADETOCOLOR,
+ TransitionSubType::FADEFROMCOLOR,
+ TransitionSubType::FADEOVERCOLOR,
+ TransitionSubType::THREEBLADE,
+ TransitionSubType::EIGHTBLADE,
+ TransitionSubType::ONEBLADE,
+ TransitionSubType::ACROSS,
+ TransitionSubType::TOPLEFTVERTICAL,
+ TransitionSubType::TOPLEFTHORIZONTAL,
+ TransitionSubType::TOPLEFTDIAGONAL,
+ TransitionSubType::TOPRIGHTDIAGONAL,
+ TransitionSubType::BOTTOMRIGHTDIAGONAL,
+ TransitionSubType::BOTTOMLEFTDIAGONAL,
+ TransitionSubType::RECTANGLE,
+ TransitionSubType::DIAMOND,
+ TransitionSubType::TOPLEFT,
+ TransitionSubType::TOPRIGHT,
+ TransitionSubType::BOTTOMRIGHT,
+ TransitionSubType::BOTTOMLEFT,
+ TransitionSubType::TOPCENTER,
+ TransitionSubType::RIGHTCENTER,
+ TransitionSubType::BOTTOMCENTER,
+ TransitionSubType::LEFTCENTER,
+ TransitionSubType::LEFT,
+ TransitionSubType::UP,
+ TransitionSubType::RIGHT,
+ TransitionSubType::DIAGONALBOTTOMLEFT,
+ TransitionSubType::DIAGONALTOPLEFT,
+ TransitionSubType::CENTERTOP,
+ TransitionSubType::CENTERRIGHT,
+ TransitionSubType::TOP,
+ TransitionSubType::BOTTOM,
+ TransitionSubType::CLOCKWISETOP,
+ TransitionSubType::CLOCKWISERIGHT,
+ TransitionSubType::CLOCKWISEBOTTOM,
+ TransitionSubType::CLOCKWISELEFT,
+ TransitionSubType::CLOCKWISETOPLEFT,
+ TransitionSubType::COUNTERCLOCKWISEBOTTOMLEFT,
+ TransitionSubType::CLOCKWISEBOTTOMRIGHT,
+ TransitionSubType::COUNTERCLOCKWISETOPRIGHT,
+ TransitionSubType::VERTICALLEFT,
+ TransitionSubType::VERTICALRIGHT,
+ TransitionSubType::HORIZONTALLEFT,
+ TransitionSubType::HORIZONTALRIGHT,
+ TransitionSubType::TOPLEFTCLOCKWISE,
+ TransitionSubType::TOPRIGHTCLOCKWISE,
+ TransitionSubType::BOTTOMRIGHTCLOCKWISE,
+ TransitionSubType::BOTTOMLEFTCLOCKWISE,
+ TransitionSubType::TOPLEFTCOUNTERCLOCKWISE,
+ TransitionSubType::TOPRIGHTCOUNTERCLOCKWISE,
+ TransitionSubType::BOTTOMRIGHTCOUNTERCLOCKWISE,
+ TransitionSubType::BOTTOMLEFTCOUNTERCLOCKWISE,
+ TransitionSubType::DOUBLEBARNDOOR,
+ TransitionSubType::DOUBLEDIAMOND,
+ TransitionSubType::VERTICALTOPSAME,
+ TransitionSubType::VERTICALBOTTOMSAME,
+ TransitionSubType::VERTICALTOPLEFTOPPOSITE,
+ TransitionSubType::VERTICALBOTTOMLEFTOPPOSITE,
+ TransitionSubType::HORIZONTALLEFTSAME,
+ TransitionSubType::HORIZONTALRIGHTSAME,
+ TransitionSubType::HORIZONTALTOPLEFTOPPOSITE,
+ TransitionSubType::HORIZONTALTOPRIGHTOPPOSITE,
+ TransitionSubType::DIAGONALBOTTOMLEFTOPPOSITE,
+ TransitionSubType::DIAGONALTOPLEFTOPPOSITE,
+ TransitionSubType::TWOBOXTOP,
+ TransitionSubType::TWOBOXBOTTOM,
+ TransitionSubType::TWOBOXLEFT,
+ TransitionSubType::TWOBOXRIGHT,
+ TransitionSubType::FOURBOXVERTICAL,
+ TransitionSubType::FOURBOXHORIZONTAL
+ };
+
+ try {
+ xAnimationNode = implImportEffects( xServiceFactory, aURL );
+ Reference< XEnumerationAccess > xEnumerationAccess( xAnimationNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW );
+
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+ if( xChildNode->getType() == AnimationNodeType::PAR )
+ {
+ TransitionPresetPtr pPreset( new TransitionPreset( xChildNode ) );
+
+ if( comphelper::LibreOfficeKit::isActive() )
+ {
+ sal_Int16 eTransitionType = pPreset->getTransition();
+ sal_Int16 eTransitionSubType = pPreset->getSubtype();
+ if( LOKSupportedTransitionTypes.find(eTransitionType) == LOKSupportedTransitionTypes.end()
+ || LOKSupportedTransitionSubTypes.find(eTransitionSubType) == LOKSupportedTransitionSubTypes.end() )
+ {
+ continue;
+ }
+ }
+
+ OUString aPresetId( pPreset->getPresetId() );
+
+ if( !aPresetId.isEmpty() )
+ {
+ Reference< container::XNameAccess > xTransitionNode;
+
+ if (xTransitions->hasByName( aPresetId ) &&
+ (xTransitions->getByName( aPresetId ) >>= xTransitionNode) &&
+ xTransitionNode.is() )
+ {
+ OUString sSet;
+ OUString sVariant;
+
+ xTransitionNode->getByName( "Set" ) >>= sSet;
+ xTransitionNode->getByName( "Variant" ) >>= sVariant;
+
+ Reference< container::XNameAccess > xSetNode;
+
+ xTransitionSets->getByName( sSet ) >>= xSetNode;
+ if( xSetNode.is() )
+ {
+ pPreset->maSetId = sSet;
+ xSetNode->getByName( "Label" ) >>= sSet;
+ pPreset->maSetLabel = sSet;
+
+ OUString sGroup;
+
+ xSetNode->getByName( "Group" ) >>= sGroup;
+
+ Reference< container::XNameAccess > xGroupNode;
+ xTransitionGroups->getByName( sGroup ) >>= xGroupNode;
+
+ if( xGroupNode.is() )
+ {
+ xGroupNode->getByName( "Label" ) >>= sGroup;
+ if( !sVariant.isEmpty() )
+ {
+ Reference< container::XNameAccess > xVariantNode;
+ xTransitionVariants->getByName( sVariant ) >>= xVariantNode;
+ if( xVariantNode.is() )
+ {
+ xVariantNode->getByName( "Label" ) >>= sVariant;
+ pPreset->maVariantLabel = sVariant;
+ }
+ }
+
+ pPreset->maSetLabel = sSet;
+ SAL_INFO("sd.transitions", aPresetId << ": " << sGroup << "/" << sSet << (sVariant.isEmpty() ? OUString() : OUString("/" + sVariant)));
+
+ rList.push_back( pPreset );
+ }
+ else
+ SAL_WARN("sd.transitions", "group node " << sGroup << " not found");
+ }
+ else
+ SAL_WARN("sd.transitions", "set node " << sSet << " not found");
+ }
+ else
+ SAL_WARN("sd.transitions", "transition node " << aPresetId << " not found");
+ }
+ }
+ else
+ {
+ SAL_WARN("sd.transitions", " malformed xml configuration file " << aURL );
+ break;
+ }
+ }
+ } catch( Exception& ) {
+ return false;
+ }
+
+ return true;
+}
+
+bool TransitionPreset::importTransitionPresetList( TransitionPresetList& rList )
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return false;
+
+ bool bRet = false;
+
+ try
+ {
+ uno::Reference< uno::XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+ Reference< XMultiServiceFactory > xServiceFactory(
+ xContext->getServiceManager(), UNO_QUERY_THROW );
+
+ // import ui strings
+ Reference< XMultiServiceFactory > xConfigProvider =
+ configuration::theDefaultProvider::get( xContext );
+
+ // read path to transition effects files from config
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", uno::Any(OUString("/org.openoffice.Office.Impress/Misc"))}
+ }));
+ Reference<container::XNameAccess> xNameAccess(
+ xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArgs),
+ UNO_QUERY_THROW );
+ uno::Sequence< OUString > aFiles;
+ xNameAccess->getByName("TransitionFiles") >>= aFiles;
+
+ for( const auto& rFile : std::as_const(aFiles) )
+ {
+ OUString aURL = comphelper::getExpandedUri(xContext, rFile);
+
+ bRet |= importTransitionsFile( rList,
+ xServiceFactory,
+ aURL );
+ }
+
+ return bRet;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::TransitionPreset::importResources()" );
+ }
+
+ return bRet;
+}
+
+std::map<OUString, TransitionPresetList> sd::TransitionPreset::mPresetsMap;
+
+const TransitionPresetList& TransitionPreset::getTransitionPresetList()
+{
+ // Support localization per-view. Currently not useful for Desktop
+ // but very much critical for LOK. The cache now is per-language.
+ const OUString aLang = comphelper::LibreOfficeKit::isActive()
+ ? comphelper::LibreOfficeKit::getLanguageTag().getBcp47()
+ : SvtSysLocaleOptions().GetLanguageTag().getBcp47();
+
+ SolarMutexGuard aGuard;
+ const auto it = mPresetsMap.find(aLang);
+ if (it != mPresetsMap.end())
+ return it->second;
+
+ TransitionPresetList& rList = mPresetsMap[aLang];
+ sd::TransitionPreset::importTransitionPresetList(rList);
+ return rList;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/anminfo.cxx b/sd/source/core/anminfo.cxx
new file mode 100644
index 000000000..5f763708c
--- /dev/null
+++ b/sd/source/core/anminfo.cxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/flditem.hxx>
+#include <editeng/eeitem.hxx>
+#include <tools/debug.hxx>
+
+#include <anminfo.hxx>
+#include <glob.hxx>
+
+using namespace ::com::sun::star;
+
+SdAnimationInfo::SdAnimationInfo(SdrObject& rObject)
+ : SdrObjUserData(SdrInventor::StarDrawUserData, SD_ANIMATIONINFO_ID),
+ mePresObjKind (PresObjKind::NONE),
+ meEffect (presentation::AnimationEffect_NONE),
+ meTextEffect (presentation::AnimationEffect_NONE),
+ meSpeed (presentation::AnimationSpeed_SLOW),
+ mbActive (true),
+ mbDimPrevious (false),
+ mbIsMovie (false),
+ mbDimHide (false),
+ mbSoundOn (false),
+ mbPlayFull (false),
+ meClickAction (presentation::ClickAction_NONE),
+ meSecondEffect (presentation::AnimationEffect_NONE),
+ meSecondSpeed (presentation::AnimationSpeed_SLOW),
+ mbSecondSoundOn (false),
+ mbSecondPlayFull (false),
+ mnVerb (0),
+ mrObject (rObject)
+{
+ maBlueScreen = COL_LIGHTMAGENTA;
+ maDimColor = COL_LIGHTGRAY;
+}
+
+SdAnimationInfo::SdAnimationInfo(const SdAnimationInfo& rAnmInfo, SdrObject& rObject)
+ : SdrObjUserData (rAnmInfo),
+ mePresObjKind (PresObjKind::NONE),
+ meEffect (rAnmInfo.meEffect),
+ meTextEffect (rAnmInfo.meTextEffect),
+ meSpeed (rAnmInfo.meSpeed),
+ mbActive (rAnmInfo.mbActive),
+ mbDimPrevious (rAnmInfo.mbDimPrevious),
+ mbIsMovie (rAnmInfo.mbIsMovie),
+ mbDimHide (rAnmInfo.mbDimHide),
+ maBlueScreen (rAnmInfo.maBlueScreen),
+ maDimColor (rAnmInfo.maDimColor),
+ maSoundFile (rAnmInfo.maSoundFile),
+ mbSoundOn (rAnmInfo.mbSoundOn),
+ mbPlayFull (rAnmInfo.mbPlayFull),
+ meClickAction (rAnmInfo.meClickAction),
+ meSecondEffect (rAnmInfo.meSecondEffect),
+ meSecondSpeed (rAnmInfo.meSecondSpeed),
+ maSecondSoundFile (rAnmInfo.maSecondSoundFile),
+ mbSecondSoundOn (rAnmInfo.mbSecondSoundOn),
+ mbSecondPlayFull (rAnmInfo.mbSecondPlayFull),
+ mnVerb (rAnmInfo.mnVerb),
+ mrObject (rObject)
+{
+ // can not be copied
+ if(meEffect == presentation::AnimationEffect_PATH)
+ meEffect = presentation::AnimationEffect_NONE;
+}
+
+SdAnimationInfo::~SdAnimationInfo()
+{
+}
+
+std::unique_ptr<SdrObjUserData> SdAnimationInfo::Clone(SdrObject* pObject) const
+{
+ DBG_ASSERT( pObject, "SdAnimationInfo::Clone(), pObject must not be null!" );
+ if( pObject == nullptr )
+ pObject = &mrObject;
+
+ return std::unique_ptr<SdrObjUserData>(new SdAnimationInfo(*this, *pObject ));
+}
+
+void SdAnimationInfo::SetBookmark( const OUString& rBookmark )
+{
+ if( meClickAction == css::presentation::ClickAction_BOOKMARK )
+ {
+ OUString sURL = "#" + rBookmark;
+ SvxFieldItem aURLItem( SvxURLField( sURL, sURL ), EE_FEATURE_FIELD );
+ mrObject.SetMergedItem( aURLItem );
+ }
+ else
+ {
+ SvxFieldItem aURLItem( SvxURLField( rBookmark, rBookmark ), EE_FEATURE_FIELD );
+ mrObject.SetMergedItem( aURLItem );
+ }
+}
+
+OUString SdAnimationInfo::GetBookmark() const
+{
+ OUString sBookmark;
+
+ const SvxFieldItem* pFldItem = &mrObject.GetMergedItem( EE_FEATURE_FIELD );
+ if( pFldItem )
+ {
+ SvxURLField* pURLField = const_cast< SvxURLField* >( dynamic_cast<const SvxURLField*>( pFldItem->GetField() ) );
+ if( pURLField )
+ sBookmark = pURLField->GetURL();
+ }
+
+ if( (meClickAction == css::presentation::ClickAction_BOOKMARK) && sBookmark.startsWith("#") )
+ sBookmark = sBookmark.copy( 1 );
+
+ return sBookmark;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/annotations/Annotation.cxx b/sd/source/core/annotations/Annotation.cxx
new file mode 100644
index 000000000..991412f06
--- /dev/null
+++ b/sd/source/core/annotations/Annotation.cxx
@@ -0,0 +1,480 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <Annotation.hxx>
+#include <drawdoc.hxx>
+
+#include <com/sun/star/drawing/XDrawPage.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/lok.hxx>
+
+#include <unotools/datetime.hxx>
+
+#include <sfx2/viewsh.hxx>
+#include <svx/svdundo.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+#include <notifydocumentevent.hxx>
+
+#include <tools/json_writer.hxx>
+
+using namespace css;
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace sd {
+
+namespace {
+
+class UndoInsertOrRemoveAnnotation : public SdrUndoAction
+{
+public:
+ UndoInsertOrRemoveAnnotation( Annotation& rAnnotation, bool bInsert );
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+protected:
+ rtl::Reference< Annotation > mxAnnotation;
+ bool mbInsert;
+ int mnIndex;
+};
+
+struct AnnotationData
+{
+ geometry::RealPoint2D m_Position;
+ geometry::RealSize2D m_Size;
+ OUString m_Author;
+ OUString m_Initials;
+ util::DateTime m_DateTime;
+ OUString m_Text;
+
+ void get( const rtl::Reference< Annotation >& xAnnotation )
+ {
+ m_Position = xAnnotation->getPosition();
+ m_Size = xAnnotation->getSize();
+ m_Author = xAnnotation->getAuthor();
+ m_Initials = xAnnotation->getInitials();
+ m_DateTime = xAnnotation->getDateTime();
+ uno::Reference<text::XText> xText(xAnnotation->getTextRange());
+ m_Text = xText->getString();
+ }
+
+ void set( const rtl::Reference< Annotation >& xAnnotation )
+ {
+ xAnnotation->setPosition(m_Position);
+ xAnnotation->setSize(m_Size);
+ xAnnotation->setAuthor(m_Author);
+ xAnnotation->setInitials(m_Initials);
+ xAnnotation->setDateTime(m_DateTime);
+ uno::Reference<text::XText> xText(xAnnotation->getTextRange());
+ xText->setString(m_Text);
+ }
+};
+
+class UndoAnnotation : public SdrUndoAction
+{
+public:
+ explicit UndoAnnotation( Annotation& rAnnotation );
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+protected:
+ rtl::Reference< Annotation > mxAnnotation;
+ AnnotationData maUndoData;
+ AnnotationData maRedoData;
+};
+
+}
+
+void createAnnotation(uno::Reference<office::XAnnotation>& xAnnotation, SdPage* pPage )
+{
+ xAnnotation.set(
+ new Annotation(comphelper::getProcessComponentContext(), pPage));
+ pPage->addAnnotation(xAnnotation, -1);
+}
+
+sal_uInt32 Annotation::m_nLastId = 1;
+
+Annotation::Annotation( const uno::Reference<uno::XComponentContext>& context, SdPage* pPage )
+: ::cppu::WeakComponentImplHelper<office::XAnnotation>(m_aMutex)
+, ::cppu::PropertySetMixin<office::XAnnotation>(context, IMPLEMENTS_PROPERTY_SET, uno::Sequence<OUString>())
+, m_nId( m_nLastId++ )
+, mpPage( pPage )
+{
+}
+
+// override WeakComponentImplHelperBase::disposing()
+// This function is called upon disposing the component,
+// if your component needs special work when it becomes
+// disposed, do it here.
+void SAL_CALL Annotation::disposing()
+{
+ mpPage = nullptr;
+ if( m_TextRange.is() )
+ {
+ m_TextRange->dispose();
+ m_TextRange.clear();
+ }
+}
+
+uno::Any Annotation::queryInterface(css::uno::Type const & type)
+{
+ return ::cppu::WeakComponentImplHelper<office::XAnnotation>::queryInterface(type);
+}
+
+// com.sun.star.beans.XPropertySet:
+uno::Reference<beans::XPropertySetInfo> SAL_CALL Annotation::getPropertySetInfo()
+{
+ return ::cppu::PropertySetMixin<office::XAnnotation>::getPropertySetInfo();
+}
+
+void SAL_CALL Annotation::setPropertyValue(const OUString & aPropertyName, const uno::Any & aValue)
+{
+ ::cppu::PropertySetMixin<office::XAnnotation>::setPropertyValue(aPropertyName, aValue);
+}
+
+uno::Any SAL_CALL Annotation::getPropertyValue(const OUString & aPropertyName)
+{
+ return ::cppu::PropertySetMixin<office::XAnnotation>::getPropertyValue(aPropertyName);
+}
+
+void SAL_CALL Annotation::addPropertyChangeListener(const OUString & aPropertyName, const uno::Reference<beans::XPropertyChangeListener> & xListener)
+{
+ ::cppu::PropertySetMixin<office::XAnnotation>::addPropertyChangeListener(aPropertyName, xListener);
+}
+
+void SAL_CALL Annotation::removePropertyChangeListener(const OUString & aPropertyName, const uno::Reference<beans::XPropertyChangeListener> & xListener)
+{
+ ::cppu::PropertySetMixin<office::XAnnotation>::removePropertyChangeListener(aPropertyName, xListener);
+}
+
+void SAL_CALL Annotation::addVetoableChangeListener(const OUString & aPropertyName, const uno::Reference<beans::XVetoableChangeListener> & xListener)
+{
+ ::cppu::PropertySetMixin<office::XAnnotation>::addVetoableChangeListener(aPropertyName, xListener);
+}
+
+void SAL_CALL Annotation::removeVetoableChangeListener(const OUString & aPropertyName, const uno::Reference<beans::XVetoableChangeListener> & xListener)
+{
+ ::cppu::PropertySetMixin<office::XAnnotation>::removeVetoableChangeListener(aPropertyName, xListener);
+}
+
+uno::Any SAL_CALL Annotation::getAnchor()
+{
+ osl::MutexGuard g(m_aMutex);
+ uno::Any aRet;
+ if( mpPage )
+ {
+ uno::Reference<drawing::XDrawPage> xPage( mpPage->getUnoPage(), uno::UNO_QUERY );
+ aRet <<= xPage;
+ }
+ return aRet;
+}
+
+// css::office::XAnnotation:
+geometry::RealPoint2D SAL_CALL Annotation::getPosition()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_Position;
+}
+
+void SAL_CALL Annotation::setPosition(const geometry::RealPoint2D & the_value)
+{
+ prepareSet("Position", uno::Any(), uno::Any(), nullptr);
+ {
+ osl::MutexGuard g(m_aMutex);
+ createChangeUndo();
+ m_Position = the_value;
+ }
+}
+
+// css::office::XAnnotation:
+geometry::RealSize2D SAL_CALL Annotation::getSize()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_Size;
+}
+
+void SAL_CALL Annotation::setSize(const geometry::RealSize2D & the_value)
+{
+ prepareSet("Size", uno::Any(), uno::Any(), nullptr);
+ {
+ osl::MutexGuard g(m_aMutex);
+ createChangeUndo();
+ m_Size = the_value;
+ }
+}
+
+OUString SAL_CALL Annotation::getAuthor()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_Author;
+}
+
+void SAL_CALL Annotation::setAuthor(const OUString & the_value)
+{
+ prepareSet("Author", uno::Any(), uno::Any(), nullptr);
+ {
+ osl::MutexGuard g(m_aMutex);
+ createChangeUndo();
+ m_Author = the_value;
+ }
+}
+
+OUString SAL_CALL Annotation::getInitials()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_Initials;
+}
+
+void SAL_CALL Annotation::setInitials(const OUString & the_value)
+{
+ prepareSet("Initials", uno::Any(), uno::Any(), nullptr);
+ {
+ osl::MutexGuard g(m_aMutex);
+ createChangeUndo();
+ m_Initials = the_value;
+ }
+}
+
+util::DateTime SAL_CALL Annotation::getDateTime()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_DateTime;
+}
+
+void SAL_CALL Annotation::setDateTime(const util::DateTime & the_value)
+{
+ prepareSet("DateTime", uno::Any(), uno::Any(), nullptr);
+ {
+ osl::MutexGuard g(m_aMutex);
+ createChangeUndo();
+ m_DateTime = the_value;
+ }
+}
+
+void Annotation::createChangeUndo()
+{
+ SdrModel* pModel = GetModel(); // TTTT should use reference
+ if( pModel && pModel->IsUndoEnabled() )
+ pModel->AddUndo( std::make_unique<UndoAnnotation>( *this ) );
+
+ if( pModel )
+ {
+ pModel->SetChanged();
+ uno::Reference< XInterface > xSource( static_cast<uno::XWeak*>( this ) );
+ NotifyDocumentEvent(
+ static_cast< SdDrawDocument& >( *pModel ),
+ "OnAnnotationChanged" ,
+ xSource );
+ }
+}
+
+uno::Reference<text::XText> SAL_CALL Annotation::getTextRange()
+{
+ osl::MutexGuard g(m_aMutex);
+ if( !m_TextRange.is() && (mpPage != nullptr) )
+ {
+ m_TextRange = TextApiObject::create( static_cast< SdDrawDocument* >( &mpPage->getSdrModelFromSdrPage() ) );
+ }
+ return m_TextRange;
+}
+
+std::unique_ptr<SdrUndoAction> CreateUndoInsertOrRemoveAnnotation( const uno::Reference<office::XAnnotation>& xAnnotation, bool bInsert )
+{
+ Annotation* pAnnotation = dynamic_cast< Annotation* >( xAnnotation.get() );
+ if( pAnnotation )
+ {
+ return std::make_unique< UndoInsertOrRemoveAnnotation >( *pAnnotation, bInsert );
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+void CreateChangeUndo(const uno::Reference<office::XAnnotation>& xAnnotation)
+{
+ Annotation* pAnnotation = dynamic_cast<Annotation*>(xAnnotation.get());
+ if (pAnnotation)
+ pAnnotation->createChangeUndo();
+}
+
+sal_uInt32 getAnnotationId(const uno::Reference<office::XAnnotation>& xAnnotation)
+{
+ Annotation* pAnnotation = dynamic_cast<Annotation*>(xAnnotation.get());
+ sal_uInt32 nId = 0;
+ if (pAnnotation)
+ nId = pAnnotation->GetId();
+ return nId;
+}
+
+const SdPage* getAnnotationPage(const uno::Reference<office::XAnnotation>& xAnnotation)
+{
+ Annotation* pAnnotation = dynamic_cast<Annotation*>(xAnnotation.get());
+ if (pAnnotation)
+ return pAnnotation->GetPage();
+ return nullptr;
+}
+
+namespace
+{
+std::string lcl_LOKGetCommentPayload(CommentNotificationType nType, uno::Reference<office::XAnnotation> const & rxAnnotation)
+{
+ ::tools::JsonWriter aJsonWriter;
+ {
+ auto aCommentNode = aJsonWriter.startNode("comment");
+
+ aJsonWriter.put("action", (nType == CommentNotificationType::Add ? "Add" :
+ (nType == CommentNotificationType::Remove ? "Remove" :
+ (nType == CommentNotificationType::Modify ? "Modify" : "???"))));
+ aJsonWriter.put("id", sd::getAnnotationId(rxAnnotation));
+
+ if (nType != CommentNotificationType::Remove && rxAnnotation.is())
+ {
+ aJsonWriter.put("id", sd::getAnnotationId(rxAnnotation));
+ aJsonWriter.put("author", rxAnnotation->getAuthor());
+ aJsonWriter.put("dateTime", utl::toISO8601(rxAnnotation->getDateTime()));
+ uno::Reference<text::XText> xText(rxAnnotation->getTextRange());
+ aJsonWriter.put("text", xText->getString());
+ const SdPage* pPage = sd::getAnnotationPage(rxAnnotation);
+ aJsonWriter.put("parthash", pPage ? OString::number(pPage->GetHashCode()) : OString());
+ geometry::RealPoint2D const & rPoint = rxAnnotation->getPosition();
+ geometry::RealSize2D const & rSize = rxAnnotation->getSize();
+ ::tools::Rectangle aRectangle(Point(rPoint.X * 100.0, rPoint.Y * 100.0), Size(rSize.Width * 100.0, rSize.Height * 100.0));
+ aRectangle = OutputDevice::LogicToLogic(aRectangle, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
+ OString sRectangle = aRectangle.toString();
+ aJsonWriter.put("rectangle", sRectangle.getStr());
+ }
+ }
+ return aJsonWriter.extractData();
+}
+} // anonymous ns
+
+void LOKCommentNotify(CommentNotificationType nType, const SfxViewShell* pViewShell, uno::Reference<office::XAnnotation> const & rxAnnotation)
+{
+ // callbacks only if tiled annotations are explicitly turned off by LOK client
+ if (!comphelper::LibreOfficeKit::isActive() || comphelper::LibreOfficeKit::isTiledAnnotations())
+ return ;
+
+ std::string aPayload = lcl_LOKGetCommentPayload(nType, rxAnnotation);
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, aPayload.c_str());
+}
+
+void LOKCommentNotifyAll(CommentNotificationType nType, uno::Reference<office::XAnnotation> const & rxAnnotation)
+{
+ // callbacks only if tiled annotations are explicitly turned off by LOK client
+ if (!comphelper::LibreOfficeKit::isActive() || comphelper::LibreOfficeKit::isTiledAnnotations())
+ return ;
+
+ std::string aPayload = lcl_LOKGetCommentPayload(nType, rxAnnotation);
+
+ const SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, aPayload.c_str());
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+UndoInsertOrRemoveAnnotation::UndoInsertOrRemoveAnnotation( Annotation& rAnnotation, bool bInsert )
+: SdrUndoAction( *rAnnotation.GetModel() )
+, mxAnnotation( &rAnnotation )
+, mbInsert( bInsert )
+, mnIndex( 0 )
+{
+ SdPage* pPage = rAnnotation.GetPage();
+ if( pPage )
+ {
+ uno::Reference<office::XAnnotation> xAnnotation( &rAnnotation );
+
+ const AnnotationVector& rVec = pPage->getAnnotations();
+ auto iter = std::find(rVec.begin(), rVec.end(), xAnnotation);
+ mnIndex += std::distance(rVec.begin(), iter);
+ }
+}
+
+void UndoInsertOrRemoveAnnotation::Undo()
+{
+ SdPage* pPage = mxAnnotation->GetPage();
+ SdrModel* pModel = mxAnnotation->GetModel();
+ if( !(pPage && pModel) )
+ return;
+
+ uno::Reference<office::XAnnotation> xAnnotation( mxAnnotation );
+ if( mbInsert )
+ {
+ pPage->removeAnnotation( xAnnotation );
+ }
+ else
+ {
+ pPage->addAnnotation( xAnnotation, mnIndex );
+ LOKCommentNotifyAll( CommentNotificationType::Add, xAnnotation );
+ }
+}
+
+void UndoInsertOrRemoveAnnotation::Redo()
+{
+ SdPage* pPage = mxAnnotation->GetPage();
+ SdrModel* pModel = mxAnnotation->GetModel();
+ if( !(pPage && pModel) )
+ return;
+
+ uno::Reference<office::XAnnotation> xAnnotation( mxAnnotation );
+
+ if( mbInsert )
+ {
+ pPage->addAnnotation( xAnnotation, mnIndex );
+ LOKCommentNotifyAll( CommentNotificationType::Add, xAnnotation );
+ }
+ else
+ {
+ pPage->removeAnnotation( xAnnotation );
+ }
+}
+
+UndoAnnotation::UndoAnnotation( Annotation& rAnnotation )
+: SdrUndoAction( *rAnnotation.GetModel() )
+, mxAnnotation( &rAnnotation )
+{
+ maUndoData.get( mxAnnotation );
+}
+
+void UndoAnnotation::Undo()
+{
+ maRedoData.get( mxAnnotation );
+ maUndoData.set( mxAnnotation );
+ LOKCommentNotifyAll( CommentNotificationType::Modify, mxAnnotation );
+}
+
+void UndoAnnotation::Redo()
+{
+ maUndoData.get( mxAnnotation );
+ maRedoData.set( mxAnnotation );
+ LOKCommentNotifyAll( CommentNotificationType::Modify, mxAnnotation );
+}
+
+} // namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/annotations/AnnotationEnumeration.cxx b/sd/source/core/annotations/AnnotationEnumeration.cxx
new file mode 100644
index 000000000..5fae2422b
--- /dev/null
+++ b/sd/source/core/annotations/AnnotationEnumeration.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 <sal/config.h>
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/office/XAnnotationEnumeration.hpp>
+
+#include <AnnotationEnumeration.hxx>
+#include <sdpage.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::office;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+namespace sd {
+
+namespace {
+
+class AnnotationEnumeration: public ::cppu::WeakImplHelper< css::office::XAnnotationEnumeration >
+{
+public:
+ explicit AnnotationEnumeration( AnnotationVector&& rAnnotations );
+ AnnotationEnumeration(const AnnotationEnumeration&) = delete;
+ AnnotationEnumeration& operator=(const AnnotationEnumeration&) = delete;
+
+ // css::office::XAnnotationEnumeration:
+ virtual sal_Bool SAL_CALL hasMoreElements() override;
+ virtual css::uno::Reference< css::office::XAnnotation > SAL_CALL nextElement() override;
+
+private:
+ // destructor is private and will be called indirectly by the release call virtual ~AnnotationEnumeration() {}
+
+ AnnotationVector maAnnotations;
+ AnnotationVector::iterator maIter;
+};
+
+}
+
+Reference< XAnnotationEnumeration > createAnnotationEnumeration( sd::AnnotationVector&& rAnnotations )
+{
+ return new AnnotationEnumeration( std::move(rAnnotations) );
+}
+
+AnnotationEnumeration::AnnotationEnumeration( AnnotationVector&& rAnnotations )
+: maAnnotations(std::move(rAnnotations))
+{
+ maIter = maAnnotations.begin();
+}
+
+// css::office::XAnnotationEnumeration:
+sal_Bool SAL_CALL AnnotationEnumeration::hasMoreElements()
+{
+ return maIter != maAnnotations.end();
+}
+
+css::uno::Reference< css::office::XAnnotation > SAL_CALL AnnotationEnumeration::nextElement()
+{
+ if( maIter == maAnnotations.end() )
+ throw css::container::NoSuchElementException();
+
+ return (*maIter++);
+}
+
+} // namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/cusshow.cxx b/sd/source/core/cusshow.cxx
new file mode 100644
index 000000000..8b51a613d
--- /dev/null
+++ b/sd/source/core/cusshow.cxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/XComponent.hpp>
+
+#include <createunocustomshow.hxx>
+#include <cusshow.hxx>
+#include <customshowlist.hxx>
+
+using namespace ::com::sun::star;
+
+/*************************************************************************
+|*
+|* Ctor
+|*
+\************************************************************************/
+SdCustomShow::SdCustomShow()
+{
+}
+
+/*************************************************************************
+|*
+|* Copy-Ctor
+|*
+\************************************************************************/
+SdCustomShow::SdCustomShow( const SdCustomShow& rShow )
+ : maPages(rShow.maPages)
+{
+ aName = rShow.GetName();
+}
+
+SdCustomShow::SdCustomShow(css::uno::Reference< css::uno::XInterface > const & xShow )
+ : mxUnoCustomShow( xShow )
+{
+}
+
+/*************************************************************************
+|*
+|* Dtor
+|*
+\************************************************************************/
+SdCustomShow::~SdCustomShow()
+{
+ uno::Reference< uno::XInterface > xShow( mxUnoCustomShow );
+ uno::Reference< lang::XComponent > xComponent( xShow, uno::UNO_QUERY );
+ if( xComponent.is() )
+ xComponent->dispose();
+}
+
+uno::Reference< uno::XInterface > SdCustomShow::getUnoCustomShow()
+{
+ // try weak reference first
+ uno::Reference< uno::XInterface > xShow( mxUnoCustomShow );
+
+ if( !xShow.is() )
+ {
+ xShow = createUnoCustomShow( this );
+ }
+
+ return xShow;
+}
+
+void SdCustomShow::ReplacePage( const SdPage* pOldPage, const SdPage* pNewPage )
+{
+ if( !pNewPage )
+ {
+ maPages.erase(::std::remove(maPages.begin(), maPages.end(), pOldPage), maPages.end());
+ }
+ else
+ {
+ ::std::replace(maPages.begin(), maPages.end(), pOldPage, pNewPage);
+ }
+}
+
+void SdCustomShow::SetName(const OUString& rName)
+{
+ aName = rName;
+}
+
+void SdCustomShowList::erase(std::vector<std::unique_ptr<SdCustomShow>>::iterator it)
+{
+ mShows.erase(it);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/drawdoc.cxx b/sd/source/core/drawdoc.cxx
new file mode 100644
index 000000000..182ffe7f2
--- /dev/null
+++ b/sd/source/core/drawdoc.cxx
@@ -0,0 +1,1206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <libxml/xmlwriter.h>
+
+#include "PageListWatcher.hxx"
+#include <com/sun/star/document/PrinterIndependentLayout.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/beans/XPropertyContainer.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <editeng/forbiddencharacterstable.hxx>
+
+#include <svl/srchitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/scriptspaceitem.hxx>
+#include <tools/debug.hxx>
+
+#include <unotools/configmgr.hxx>
+#include <unotools/useroptions.hxx>
+#include <officecfg/Office/Impress.hxx>
+
+#include <sfx2/linkmgr.hxx>
+#include <Outliner.hxx>
+#include <sdmod.hxx>
+#include <editeng/editstat.hxx>
+#include <svx/svdotext.hxx>
+#include <editeng/unolingu.hxx>
+#include <svl/itempool.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <editeng/outlobj.hxx>
+#include <comphelper/getexpandeduri.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <unotools/charclass.hxx>
+#include <comphelper/processfactory.hxx>
+#include <unotools/lingucfg.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
+#include <com/sun/star/xml/dom/XDocument.hpp>
+#include <com/sun/star/xml/dom/XNodeList.hpp>
+#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <rtl/ustring.hxx>
+
+#include <editeng/outliner.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <strings.hrc>
+#include <glob.hxx>
+#include <stlpool.hxx>
+#include <sdresid.hxx>
+#include <customshowlist.hxx>
+#include <DrawDocShell.hxx>
+#include <GraphicDocShell.hxx>
+#include <sdxfer.hxx>
+#include <optsitem.hxx>
+#include <FrameView.hxx>
+#include <undo/undomanager.hxx>
+#include <sdundogr.hxx>
+#include <undopage.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <unokywds.hxx>
+
+namespace com::sun::star::linguistic2 { class XHyphenator; }
+namespace com::sun::star::linguistic2 { class XSpellChecker1; }
+
+using namespace ::sd;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::linguistic2;
+
+using namespace com::sun::star::xml::dom;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::lang::XMultiServiceFactory;
+
+
+SdDrawDocument* SdDrawDocument::s_pDocLockedInsertingLinks = nullptr;
+
+PresentationSettings::PresentationSettings()
+: mbAll( true ),
+ mbEndless( false ),
+ mbCustomShow(false),
+ mbManual( false ),
+ mbMouseVisible( false ),
+ mbMouseAsPen( false ),
+ mbLockedPages( false ),
+ mbAlwaysOnTop( false ),
+ mbFullScreen( true ),
+ mbAnimationAllowed( true ),
+ mnPauseTimeout( 0 ),
+ mbShowPauseLogo( false ),
+ mbStartCustomShow( false )
+{
+}
+
+SdDrawDocument::SdDrawDocument(DocumentType eType, SfxObjectShell* pDrDocSh)
+: FmFormModel(
+ nullptr,
+ pDrDocSh)
+, mpDocSh(static_cast< ::sd::DrawDocShell*>(pDrDocSh))
+, mpCreatingTransferable( nullptr )
+, mbHasOnlineSpellErrors(false)
+, mbInitialOnlineSpellingEnabled(true)
+, mbNewOrLoadCompleted(false)
+, mbOnlineSpell(false)
+, mbStartWithPresentation( false )
+, mbExitAfterPresenting( false )
+, meLanguage( LANGUAGE_SYSTEM )
+, meLanguageCJK( LANGUAGE_SYSTEM )
+, meLanguageCTL( LANGUAGE_SYSTEM )
+, mePageNumType(SVX_NUM_ARABIC)
+, mbAllocDocSh(false)
+, meDocType(eType)
+, mbEmbedFonts(false)
+, mbEmbedUsedFontsOnly(false)
+, mbEmbedFontScriptLatin(true)
+, mbEmbedFontScriptAsian(true)
+, mbEmbedFontScriptComplex(true)
+, mnImagePreferredDPI(0)
+{
+ mpDrawPageListWatcher.reset(new ImpDrawPageListWatcher(*this));
+ mpMasterPageListWatcher.reset(new ImpMasterPageListWatcher(*this));
+
+ InitLayoutVector();
+ InitObjectVector();
+ SetObjectShell(pDrDocSh); // for VCDrawModel
+
+ if (mpDocSh)
+ {
+ SetSwapGraphics();
+ }
+
+ // Set measuring unit (of the application) and scale (of SdMod)
+ sal_Int32 nX, nY;
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(meDocType);
+ pOptions->GetScale( nX, nY );
+
+ // Allow UI scale only for draw documents.
+ if( eType == DocumentType::Draw )
+ SetUIUnit( static_cast<FieldUnit>(pOptions->GetMetric()), Fraction( nX, nY ) ); // user-defined
+ else
+ SetUIUnit( static_cast<FieldUnit>(pOptions->GetMetric()), Fraction( 1, 1 ) ); // default
+
+ SetScaleUnit(MapUnit::Map100thMM);
+ SetScaleFraction(Fraction(1, 1));
+ SetDefaultFontHeight(o3tl::convert(24, o3tl::Length::pt, o3tl::Length::mm100));
+
+ m_pItemPool->SetDefaultMetric(MapUnit::Map100thMM);
+ m_pItemPool->FreezeIdRanges();
+ SetTextDefaults();
+
+ // DrawingEngine has to know where it is...
+ FmFormModel::SetStyleSheetPool( new SdStyleSheetPool( GetPool(), this ) );
+
+ // Set StyleSheetPool for DrawOutliner, so text objects can be read correctly.
+ // The link to the StyleRequest handler of the document is set later, in
+ // NewOrLoadCompleted, because only then do all the templates exist.
+ SdrOutliner& rOutliner = GetDrawOutliner();
+ rOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ SetCalcFieldValueHdl( &rOutliner );
+
+ // set linguistic options
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ const SvtLinguConfig aLinguConfig;
+ SvtLinguOptions aOptions;
+ aLinguConfig.GetOptions( aOptions );
+
+ SetLanguage( MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage,
+ css::i18n::ScriptType::LATIN), EE_CHAR_LANGUAGE );
+ SetLanguage( MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage_CJK,
+ css::i18n::ScriptType::ASIAN), EE_CHAR_LANGUAGE_CJK );
+ SetLanguage( MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage_CTL,
+ css::i18n::ScriptType::COMPLEX), EE_CHAR_LANGUAGE_CTL );
+
+ mbOnlineSpell = aOptions.bIsSpellAuto;
+ }
+
+ LanguageType eRealLanguage = MsLangId::getRealLanguage( meLanguage );
+ mpCharClass.reset(new CharClass( LanguageTag( eRealLanguage) ));
+
+ // If the current application language is a language that uses right-to-left text...
+ LanguageType eRealCTLLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
+
+ // for korean and japanese languages we have a different default for apply spacing between asian, latin and ctl text
+ if (MsLangId::isKorean(eRealCTLLanguage) || (LANGUAGE_JAPANESE == eRealCTLLanguage))
+ {
+ GetPool().GetSecondaryPool()->SetPoolDefaultItem( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
+ }
+
+ // Set DefTab and SpellOptions for the SD module
+ sal_uInt16 nDefTab = pOptions->GetDefTab();
+ SetDefaultTabulator( nDefTab );
+
+ try
+ {
+ Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() );
+ if ( xSpellChecker.is() )
+ rOutliner.SetSpeller( xSpellChecker );
+
+ Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() );
+ if( xHyphenator.is() )
+ rOutliner.SetHyphenator( xHyphenator );
+
+ SetForbiddenCharsTable(SvxForbiddenCharactersTable::makeForbiddenCharactersTable(::comphelper::getProcessComponentContext()));
+ }
+ catch(...)
+ {
+ OSL_FAIL("Can't get SpellChecker");
+ }
+
+ rOutliner.SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
+
+ if (mpDocSh)
+ {
+ SetLinkManager( new sfx2::LinkManager(mpDocSh) );
+ }
+
+ EEControlBits nCntrl = rOutliner.GetControlWord();
+ nCntrl |= EEControlBits::ALLOWBIGOBJS;
+
+ if (mbOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+
+ nCntrl &= ~ EEControlBits::ULSPACESUMMATION;
+ if ( meDocType != DocumentType::Impress )
+ SetSummationOfParagraphs( false );
+ else
+ {
+ SetSummationOfParagraphs( pOptions->IsSummationOfParagraphs() );
+ if ( pOptions->IsSummationOfParagraphs() )
+ nCntrl |= EEControlBits::ULSPACESUMMATION;
+ }
+ rOutliner.SetControlWord(nCntrl);
+
+ // Initialize the printer independent layout mode
+ SetPrinterIndependentLayout (pOptions->GetPrinterIndependentLayout());
+
+ // Set the StyleSheetPool for HitTestOutliner.
+ // The link to the StyleRequest handler of the document is set later, in
+ // NewOrLoadCompleted, because only then do all the templates exist.
+ m_pHitTestOutliner->SetStyleSheetPool( static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()) );
+
+ SetCalcFieldValueHdl( m_pHitTestOutliner.get() );
+
+ try
+ {
+ Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() );
+ if ( xSpellChecker.is() )
+ m_pHitTestOutliner->SetSpeller( xSpellChecker );
+
+ Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() );
+ if( xHyphenator.is() )
+ m_pHitTestOutliner->SetHyphenator( xHyphenator );
+ }
+ catch(...)
+ {
+ OSL_FAIL("Can't get SpellChecker");
+ }
+
+ m_pHitTestOutliner->SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
+
+ EEControlBits nCntrl2 = m_pHitTestOutliner->GetControlWord();
+ nCntrl2 |= EEControlBits::ALLOWBIGOBJS;
+ nCntrl2 &= ~EEControlBits::ONLINESPELLING;
+
+ nCntrl2 &= ~ EEControlBits::ULSPACESUMMATION;
+ if ( pOptions->IsSummationOfParagraphs() )
+ nCntrl2 |= EEControlBits::ULSPACESUMMATION;
+
+ m_pHitTestOutliner->SetControlWord( nCntrl2 );
+
+ /** Create layers
+ *
+ * We create the following default layers on all pages and master pages:
+ *
+ * sUNO_LayerName_layout; "layout": default layer for drawing objects of normal pages
+ * localized by SdResId(STR_LAYER_LAYOUT)
+ *
+ * sUNO_LayerName_background; "background": background of the master page
+ * localized by SdResId(STR_LAYER_BCKGRND)
+ * (currently unused within normal pages and not visible to users)
+ *
+ * sUNO_LayerName_background_objects; "backgroundobjects": objects on the background of master pages
+ * localized by SdResId(STR_LAYER_BCKGRNDOBJ)
+ * (currently unused within normal pages)
+ *
+ * sUNO_LayerName_controls; "controls": default layer for controls
+ * localized by SdResId(STR_LAYER_CONTROLS)
+ * (currently special handling in regard to z-order)
+ *
+ * sUNO_LayerName_measurelines; "measurelines" : default layer for measure lines
+ * localized by SdResId(STR_LAYER_MEASURELINES)
+ */
+
+ {
+ SdrLayerAdmin& rLayerAdmin = GetLayerAdmin();
+ rLayerAdmin.NewLayer( sUNO_LayerName_layout );
+ rLayerAdmin.NewLayer( sUNO_LayerName_background );
+ rLayerAdmin.NewLayer( sUNO_LayerName_background_objects );
+ rLayerAdmin.NewLayer( sUNO_LayerName_controls);
+ rLayerAdmin.NewLayer( sUNO_LayerName_measurelines );
+
+ rLayerAdmin.SetControlLayerName(sUNO_LayerName_controls);
+ }
+
+}
+
+// Destructor
+SdDrawDocument::~SdDrawDocument()
+{
+ Broadcast(SdrHint(SdrHintKind::ModelCleared));
+
+ if (mpWorkStartupTimer)
+ {
+ if ( mpWorkStartupTimer->IsActive() )
+ mpWorkStartupTimer->Stop();
+
+ mpWorkStartupTimer.reset();
+ }
+
+ StopOnlineSpelling();
+ mpOnlineSearchItem.reset();
+
+ CloseBookmarkDoc();
+ SetAllocDocSh(false);
+
+ ClearModel(true);
+
+ if (m_pLinkManager)
+ {
+ // Release BaseLinks
+ if ( !m_pLinkManager->GetLinks().empty() )
+ {
+ m_pLinkManager->Remove( 0, m_pLinkManager->GetLinks().size() );
+ }
+
+ delete m_pLinkManager;
+ m_pLinkManager = nullptr;
+ }
+
+ maFrameViewList.clear();
+ mpCustomShowList.reset();
+ mpOutliner.reset();
+ mpInternalOutliner.reset();
+ mpCharClass.reset();
+}
+
+void SdDrawDocument::adaptSizeAndBorderForAllPages(
+ const Size& rNewSize,
+ ::tools::Long nLeft,
+ ::tools::Long nRight,
+ ::tools::Long nUpper,
+ ::tools::Long nLower)
+{
+ const sal_uInt16 nMasterPageCnt(GetMasterSdPageCount(PageKind::Standard));
+ const sal_uInt16 nPageCnt(GetSdPageCount(PageKind::Standard));
+
+ if(0 == nMasterPageCnt && 0 == nPageCnt)
+ {
+ return;
+ }
+
+ SdPage* pPage(0 != nPageCnt ? GetSdPage(0, PageKind::Standard) : GetMasterSdPage(0, PageKind::Standard));
+
+ // call fully implemented local version, including getting
+ // some more information from one of the Pages (1st one)
+ AdaptPageSizeForAllPages(
+ rNewSize,
+ PageKind::Standard,
+ nullptr,
+ nLeft,
+ nRight,
+ nUpper,
+ nLower,
+ true,
+ pPage->GetOrientation(),
+ pPage->GetPaperBin(),
+ pPage->IsBackgroundFullSize());
+
+ // adjust handout page to new format of the standard page
+ if(0 != nPageCnt)
+ {
+ GetSdPage(0, PageKind::Handout)->CreateTitleAndLayout(true);
+ }
+}
+
+void SdDrawDocument::AdaptPageSizeForAllPages(
+ const Size& rNewSize,
+ PageKind ePageKind,
+ SdUndoGroup* pUndoGroup,
+ ::tools::Long nLeft,
+ ::tools::Long nRight,
+ ::tools::Long nUpper,
+ ::tools::Long nLower,
+ bool bScaleAll,
+ Orientation eOrientation,
+ sal_uInt16 nPaperBin,
+ bool bBackgroundFullSize)
+{
+ sal_uInt16 i;
+ const sal_uInt16 nMasterPageCnt(GetMasterSdPageCount(ePageKind));
+ const sal_uInt16 nPageCnt(GetSdPageCount(ePageKind));
+
+ if(0 == nMasterPageCnt && 0 == nPageCnt)
+ {
+ return;
+ }
+
+ for (i = 0; i < nMasterPageCnt; i++)
+ {
+ // first, handle all master pages
+ SdPage* pPage(GetMasterSdPage(i, ePageKind));
+
+ if(pUndoGroup)
+ {
+ SdUndoAction* pUndo(
+ new SdPageFormatUndoAction(
+ this,
+ pPage,
+ pPage->GetSize(),
+ pPage->GetLeftBorder(), pPage->GetRightBorder(),
+ pPage->GetUpperBorder(), pPage->GetLowerBorder(),
+ pPage->GetOrientation(),
+ pPage->GetPaperBin(),
+ pPage->IsBackgroundFullSize(),
+ rNewSize,
+ nLeft, nRight,
+ nUpper, nLower,
+ bScaleAll,
+ eOrientation,
+ nPaperBin,
+ bBackgroundFullSize));
+ pUndoGroup->AddAction(pUndo);
+ }
+
+ if (rNewSize.Width() > 0 || nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0)
+ {
+ ::tools::Rectangle aNewBorderRect(nLeft, nUpper, nRight, nLower);
+ pPage->ScaleObjects(rNewSize, aNewBorderRect, bScaleAll);
+
+ if (rNewSize.Width() > 0)
+ {
+ pPage->SetSize(rNewSize);
+ }
+ }
+
+ if( nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0 )
+ {
+ pPage->SetBorder(nLeft, nUpper, nRight, nLower);
+ }
+
+ pPage->SetOrientation(eOrientation);
+ pPage->SetPaperBin( nPaperBin );
+ pPage->SetBackgroundFullSize( bBackgroundFullSize );
+
+ if ( ePageKind == PageKind::Standard )
+ {
+ GetMasterSdPage(i, PageKind::Notes)->CreateTitleAndLayout();
+ }
+
+ pPage->CreateTitleAndLayout();
+ }
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ // then, handle all pages
+ SdPage* pPage(GetSdPage(i, ePageKind));
+
+ if(pUndoGroup)
+ {
+ SdUndoAction* pUndo(
+ new SdPageFormatUndoAction(
+ this,
+ pPage,
+ pPage->GetSize(),
+ pPage->GetLeftBorder(), pPage->GetRightBorder(),
+ pPage->GetUpperBorder(), pPage->GetLowerBorder(),
+ pPage->GetOrientation(),
+ pPage->GetPaperBin(),
+ pPage->IsBackgroundFullSize(),
+ rNewSize,
+ nLeft, nRight,
+ nUpper, nLower,
+ bScaleAll,
+ eOrientation,
+ nPaperBin,
+ bBackgroundFullSize));
+ pUndoGroup->AddAction(pUndo);
+ }
+
+ if (rNewSize.Width() > 0 || nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0)
+ {
+ ::tools::Rectangle aNewBorderRect(nLeft, nUpper, nRight, nLower);
+ pPage->ScaleObjects(rNewSize, aNewBorderRect, bScaleAll);
+
+ if (rNewSize.Width() > 0)
+ {
+ pPage->SetSize(rNewSize);
+ }
+ }
+
+ if( nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0 )
+ {
+ pPage->SetBorder(nLeft, nUpper, nRight, nLower);
+ }
+
+ pPage->SetOrientation(eOrientation);
+ pPage->SetPaperBin( nPaperBin );
+ pPage->SetBackgroundFullSize( bBackgroundFullSize );
+
+ if ( ePageKind == PageKind::Standard )
+ {
+ SdPage* pNotesPage = GetSdPage(i, PageKind::Notes);
+ pNotesPage->SetAutoLayout( pNotesPage->GetAutoLayout() );
+ }
+
+ pPage->SetAutoLayout( pPage->GetAutoLayout() );
+ }
+}
+
+SdrModel* SdDrawDocument::AllocModel() const
+{
+ return AllocSdDrawDocument();
+}
+
+namespace
+{
+
+/// Copies all user-defined properties from pSource to pDestination.
+void lcl_copyUserDefinedProperties(const SfxObjectShell* pSource, const SfxObjectShell* pDestination)
+{
+ if (!pSource || !pDestination)
+ return;
+
+ uno::Reference<document::XDocumentProperties> xSource = pSource->getDocProperties();
+ uno::Reference<document::XDocumentProperties> xDestination = pDestination->getDocProperties();
+ uno::Reference<beans::XPropertyContainer> xSourcePropertyContainer = xSource->getUserDefinedProperties();
+ uno::Reference<beans::XPropertyContainer> xDestinationPropertyContainer = xDestination->getUserDefinedProperties();
+ uno::Reference<beans::XPropertySet> xSourcePropertySet(xSourcePropertyContainer, uno::UNO_QUERY);
+ const uno::Sequence<beans::Property> aProperties = xSourcePropertySet->getPropertySetInfo()->getProperties();
+
+ for (const beans::Property& rProperty : aProperties)
+ {
+ const OUString& rKey = rProperty.Name;
+ uno::Any aValue = xSourcePropertySet->getPropertyValue(rKey);
+ // We know that pDestination was just created, so has no properties: addProperty() will never throw.
+ xDestinationPropertyContainer->addProperty(rKey, beans::PropertyAttribute::REMOVABLE, aValue);
+ }
+}
+
+}
+
+// This method creates a new document (SdDrawDocument) and returns a pointer to
+// said document. The drawing engine uses this method to put the document (or
+// parts of it) into the clipboard/DragServer.
+SdDrawDocument* SdDrawDocument::AllocSdDrawDocument() const
+{
+ SdDrawDocument* pNewModel = nullptr;
+
+ if( mpCreatingTransferable )
+ {
+ // Document is created for drag & drop/clipboard. To be able to
+ // do this, the document has to know a DocShell (SvPersist).
+ SfxObjectShell* pObj = nullptr;
+ ::sd::DrawDocShell* pNewDocSh = nullptr;
+
+ if( meDocType == DocumentType::Impress )
+ mpCreatingTransferable->SetDocShell( new ::sd::DrawDocShell(
+ SfxObjectCreateMode::EMBEDDED, true, meDocType ) );
+ else
+ mpCreatingTransferable->SetDocShell( new ::sd::GraphicDocShell(
+ SfxObjectCreateMode::EMBEDDED ) );
+
+ pObj = mpCreatingTransferable->GetDocShell().get();
+ pNewDocSh = static_cast< ::sd::DrawDocShell*>( pObj );
+ pNewDocSh->DoInitNew();
+ pNewModel = pNewDocSh->GetDoc();
+
+ // Only necessary for clipboard -
+ // for drag & drop this is handled by DragServer
+ SdStyleSheetPool* pOldStylePool = static_cast<SdStyleSheetPool*>( GetStyleSheetPool() );
+ SdStyleSheetPool* pNewStylePool = static_cast<SdStyleSheetPool*>( pNewModel->GetStyleSheetPool() );
+
+ pNewStylePool->CopyGraphicSheets(*pOldStylePool);
+ pNewStylePool->CopyCellSheets(*pOldStylePool);
+ pNewStylePool->CopyTableStyles(*pOldStylePool);
+
+ for (sal_uInt16 i = 0; i < GetMasterSdPageCount(PageKind::Standard); i++)
+ {
+ // Move with all of the master page's layouts
+ OUString aOldLayoutName(const_cast<SdDrawDocument*>(this)->GetMasterSdPage(i, PageKind::Standard)->GetLayoutName());
+ aOldLayoutName = aOldLayoutName.copy( 0, aOldLayoutName.indexOf( SD_LT_SEPARATOR ) );
+ StyleSheetCopyResultVector aCreatedSheets;
+ pNewStylePool->CopyLayoutSheets(aOldLayoutName, *pOldStylePool, aCreatedSheets );
+ }
+
+ lcl_copyUserDefinedProperties(GetDocSh(), pNewDocSh);
+
+ pNewModel->NewOrLoadCompleted( DocCreationMode::Loaded ); // loaded from source document
+ }
+ else if( mbAllocDocSh )
+ {
+ // Create a DocShell which is then returned with GetAllocedDocSh()
+ SdDrawDocument* pDoc = const_cast<SdDrawDocument*>(this);
+ pDoc->SetAllocDocSh(false);
+ pDoc->mxAllocedDocShRef = new ::sd::DrawDocShell(
+ SfxObjectCreateMode::EMBEDDED, true, meDocType);
+ pDoc->mxAllocedDocShRef->DoInitNew();
+ pNewModel = pDoc->mxAllocedDocShRef->GetDoc();
+ }
+ else
+ {
+ pNewModel = new SdDrawDocument(meDocType, nullptr);
+ }
+
+ return pNewModel;
+}
+
+rtl::Reference<SdPage> SdDrawDocument::AllocSdPage(bool bMasterPage)
+{
+ return new SdPage(*this, bMasterPage);
+}
+
+// This method creates a new page (SdPage) and returns a pointer to said page.
+// The drawing engine uses this method to create pages (whose types it does
+// not know, as they are _derivatives_ of SdrPage) when loading.
+rtl::Reference<SdrPage> SdDrawDocument::AllocPage(bool bMasterPage)
+{
+ return AllocSdPage(bMasterPage);
+}
+
+// When the model has changed
+void SdDrawDocument::SetChanged(bool bFlag)
+{
+ if (mpDocSh)
+ {
+ if (mbNewOrLoadCompleted && mpDocSh->IsEnableSetModified())
+ {
+ // Pass on to base class
+ FmFormModel::SetChanged(bFlag);
+
+ // Forward to ObjectShell
+ mpDocSh->SetModified(bFlag);
+ }
+ }
+ else
+ {
+ // Pass on to base class
+ FmFormModel::SetChanged(bFlag);
+ }
+}
+
+// The model changed, don't call anything else
+void SdDrawDocument::NbcSetChanged(bool bFlag)
+{
+ // forward to baseclass
+ FmFormModel::SetChanged(bFlag);
+}
+
+// NewOrLoadCompleted is called when the document is loaded, or when it is clear
+// it won't load any more.
+void SdDrawDocument::NewOrLoadCompleted(DocCreationMode eMode)
+{
+ if (eMode == DocCreationMode::New)
+ {
+ // New document:
+ // create slideshow and default templates,
+ // create pool for virtual controls
+ CreateLayoutTemplates();
+ CreateDefaultCellStyles();
+
+ static_cast< SdStyleSheetPool* >( mxStyleSheetPool.get() )->CreatePseudosIfNecessary();
+ }
+ else if (eMode == DocCreationMode::Loaded)
+ {
+ // Document has finished loading
+
+ CheckMasterPages();
+
+ if ( GetMasterSdPageCount(PageKind::Standard) > 1 )
+ RemoveUnnecessaryMasterPages( nullptr, true, false );
+
+ for ( sal_uInt16 i = 0; i < GetPageCount(); i++ )
+ {
+ // Check for correct layout names
+ SdPage* pPage = static_cast<SdPage*>( GetPage( i ) );
+
+ if(pPage->TRG_HasMasterPage())
+ {
+ SdPage& rMaster = static_cast<SdPage&>(pPage->TRG_GetMasterPage() );
+
+ if(rMaster.GetLayoutName() != pPage->GetLayoutName())
+ {
+ pPage->SetLayoutName(rMaster.GetLayoutName());
+ }
+ }
+ }
+
+ for ( sal_uInt16 nPage = 0; nPage < GetMasterPageCount(); nPage++)
+ {
+ // LayoutName and PageName must be the same
+ SdPage* pPage = static_cast<SdPage*>( GetMasterPage( nPage ) );
+
+ OUString aName( pPage->GetLayoutName() );
+ aName = aName.copy( 0, aName.indexOf( SD_LT_SEPARATOR ) );
+
+ if( aName != pPage->GetName() )
+ pPage->SetName( aName );
+ }
+
+ // Create names of the styles in the user's language
+ static_cast<SdStyleSheetPool*>(mxStyleSheetPool.get())->UpdateStdNames();
+
+ // Create any missing styles - eg. formerly, there was no Subtitle style
+ static_cast<SdStyleSheetPool*>(mxStyleSheetPool.get())->CreatePseudosIfNecessary();
+ }
+
+ // Set default style of Drawing Engine
+ OUString aName( SdResId(STR_STANDARD_STYLESHEET_NAME));
+ SetDefaultStyleSheet(static_cast<SfxStyleSheet*>(mxStyleSheetPool->Find(aName, SfxStyleFamily::Para)));
+
+ // #i119287# Set default StyleSheet for SdrGrafObj and SdrOle2Obj
+ SetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj(static_cast<SfxStyleSheet*>(mxStyleSheetPool->Find(SdResId(STR_POOLSHEET_OBJNOLINENOFILL), SfxStyleFamily::Para)));
+
+ // Initialize DrawOutliner and DocumentOutliner, but don't initialize the
+ // global outliner, as it is not document specific like StyleSheetPool and
+ // StyleRequestHandler are.
+ ::Outliner& rDrawOutliner = GetDrawOutliner();
+ rDrawOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ EEControlBits nCntrl = rDrawOutliner.GetControlWord();
+ if (mbOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+ rDrawOutliner.SetControlWord(nCntrl);
+
+ // Initialize HitTestOutliner and DocumentOutliner, but don't initialize the
+ // global outliner, as it is not document specific like StyleSheetPool and
+ // StyleRequestHandler are.
+ m_pHitTestOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+
+ if(mpOutliner)
+ {
+ mpOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ }
+ if(mpInternalOutliner)
+ {
+ mpInternalOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ }
+
+ if ( eMode == DocCreationMode::Loaded )
+ {
+ // Make presentation objects listeners of the appropriate styles
+ SdStyleSheetPool* pSPool = static_cast<SdStyleSheetPool*>( GetStyleSheetPool() );
+ sal_uInt16 nPage, nPageCount;
+
+ // create missing layout style sheets for broken documents
+ // that were created with the 5.2
+ nPageCount = GetMasterSdPageCount( PageKind::Standard );
+ for (nPage = 0; nPage < nPageCount; nPage++)
+ {
+ SdPage* pPage = GetMasterSdPage(nPage, PageKind::Standard);
+ pSPool->CreateLayoutStyleSheets( pPage->GetName(), true );
+ }
+
+ // Default and notes pages:
+ for (nPage = 0; nPage < GetPageCount(); nPage++)
+ {
+ SdPage* pPage = static_cast<SdPage*>(GetPage(nPage));
+ NewOrLoadCompleted( pPage, pSPool );
+ }
+
+ // Master pages:
+ for (nPage = 0; nPage < GetMasterPageCount(); nPage++)
+ {
+ SdPage* pPage = static_cast<SdPage*>(GetMasterPage(nPage));
+
+ NewOrLoadCompleted( pPage, pSPool );
+ }
+ }
+
+ mbNewOrLoadCompleted = true;
+ UpdateAllLinks();
+ SetChanged( false );
+}
+
+/** updates all links, only links in this document should by resolved */
+void SdDrawDocument::UpdateAllLinks()
+{
+ if (s_pDocLockedInsertingLinks || !m_pLinkManager || m_pLinkManager->GetLinks().empty())
+ return;
+
+ s_pDocLockedInsertingLinks = this; // lock inserting links. only links in this document should by resolved
+
+ if (mpDocSh)
+ {
+ comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = mpDocSh->getEmbeddedObjectContainer();
+ rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true);
+ }
+
+ m_pLinkManager->UpdateAllLinks(true, false, nullptr); // query box: update all links?
+
+ if (s_pDocLockedInsertingLinks == this)
+ s_pDocLockedInsertingLinks = nullptr; // unlock inserting links
+}
+
+/** this loops over the presentation objects of a page and repairs some new settings
+ from old binary files and resets all default strings for empty presentation objects.
+*/
+void SdDrawDocument::NewOrLoadCompleted( SdPage* pPage, SdStyleSheetPool* pSPool )
+{
+ sd::ShapeList& rPresentationShapes( pPage->GetPresentationShapeList() );
+ if(rPresentationShapes.isEmpty())
+ return;
+
+ // Create lists of title and outline styles
+ OUString aName = pPage->GetLayoutName();
+ aName = aName.copy( 0, aName.indexOf( SD_LT_SEPARATOR ) );
+
+ std::vector<SfxStyleSheetBase*> aOutlineList;
+ pSPool->CreateOutlineSheetList(aName,aOutlineList);
+
+ SfxStyleSheet* pTitleSheet = static_cast<SfxStyleSheet*>(pSPool->GetTitleSheet(aName));
+
+ SdrObject* pObj = nullptr;
+ rPresentationShapes.seekShape(0);
+
+ // Now look for title and outline text objects, then make those objects
+ // listeners.
+ while( (pObj = rPresentationShapes.getNextShape()) )
+ {
+ if (pObj->GetObjInventor() == SdrInventor::Default)
+ {
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+ SdrObjKind nId = pObj->GetObjIdentifier();
+
+ if (nId == SdrObjKind::TitleText)
+ {
+ if( pOPO && pOPO->GetOutlinerMode() == OutlinerMode::DontKnow )
+ pOPO->SetOutlinerMode( OutlinerMode::TitleObject );
+
+ // sal_True: don't delete "hard" attributes when doing this.
+ if (pTitleSheet)
+ pObj->SetStyleSheet(pTitleSheet, true);
+ }
+ else if (nId == SdrObjKind::OutlineText)
+ {
+ if( pOPO && pOPO->GetOutlinerMode() == OutlinerMode::DontKnow )
+ pOPO->SetOutlinerMode( OutlinerMode::OutlineObject );
+
+ std::vector<SfxStyleSheetBase*>::iterator iter;
+ for (iter = aOutlineList.begin(); iter != aOutlineList.end(); ++iter)
+ {
+ SfxStyleSheet* pSheet = static_cast<SfxStyleSheet*>(*iter);
+
+ if (pSheet)
+ {
+ pObj->StartListening(*pSheet);
+
+ if( iter == aOutlineList.begin())
+ // text frame listens to stylesheet of layer 1
+ pObj->NbcSetStyleSheet(pSheet, true);
+ }
+ }
+ }
+
+ if( auto pTextObj = dynamic_cast<SdrTextObj *>( pObj ) )
+ if (pTextObj->IsEmptyPresObj())
+ {
+ PresObjKind ePresObjKind = pPage->GetPresObjKind(pObj);
+ OUString aString( pPage->GetPresObjText(ePresObjKind) );
+
+ if (!aString.isEmpty())
+ {
+ SdOutliner* pInternalOutl = GetInternalOutliner();
+ pPage->SetObjText( pTextObj, pInternalOutl, ePresObjKind, aString );
+ pObj->NbcSetStyleSheet( pPage->GetStyleSheetForPresObj( ePresObjKind ), true );
+ pInternalOutl->Clear();
+ }
+ }
+ }
+ }
+}
+
+// Local outliner that is used for outline mode. In this outliner, OutlinerViews
+// may be inserted.
+SdOutliner* SdDrawDocument::GetOutliner(bool bCreateOutliner)
+{
+ if (!mpOutliner && bCreateOutliner)
+ {
+ mpOutliner.reset(new SdOutliner( this, OutlinerMode::TextObject ));
+
+ if (mpDocSh)
+ mpOutliner->SetRefDevice( SD_MOD()->GetVirtualRefDevice() );
+
+ mpOutliner->SetDefTab( m_nDefaultTabulator );
+ mpOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ }
+
+ return mpOutliner.get();
+}
+
+// Internal outliner that is used to create text objects. We don't insert any
+// OutlinerViews into this outliner!
+SdOutliner* SdDrawDocument::GetInternalOutliner(bool bCreateOutliner)
+{
+ if ( !mpInternalOutliner && bCreateOutliner )
+ {
+ mpInternalOutliner.reset( new SdOutliner( this, OutlinerMode::TextObject ) );
+
+ // This outliner is only used to create special text objects. As no
+ // information about portions is saved in this outliner, the update mode
+ // can/should always remain sal_False.
+ mpInternalOutliner->SetUpdateLayout( false );
+ mpInternalOutliner->EnableUndo( false );
+
+ if (mpDocSh)
+ mpInternalOutliner->SetRefDevice( SD_MOD()->GetVirtualRefDevice() );
+
+ mpInternalOutliner->SetDefTab( m_nDefaultTabulator );
+ mpInternalOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ }
+
+ DBG_ASSERT( !mpInternalOutliner || ( ! mpInternalOutliner->IsUpdateLayout() ) , "InternalOutliner: UpdateMode = sal_True !" );
+ DBG_ASSERT( !mpInternalOutliner || ( ! mpInternalOutliner->IsUndoEnabled() ), "InternalOutliner: Undo = sal_True !" );
+
+ // If you add stuff here, always clear it out.
+ // Advantages:
+ // a) no unnecessary Clear calls
+ // b) no wasted memory
+ DBG_ASSERT( !mpInternalOutliner || ( ( mpInternalOutliner->GetParagraphCount() == 1 ) && ( mpInternalOutliner->GetText( mpInternalOutliner->GetParagraph( 0 ) ).isEmpty() ) ), "InternalOutliner: not empty!" );
+
+ return mpInternalOutliner.get();
+}
+
+// OnlineSpelling on/off
+void SdDrawDocument::SetOnlineSpell(bool bIn)
+{
+ mbOnlineSpell = bIn;
+ EEControlBits nCntrl;
+
+ if(mpOutliner)
+ {
+ nCntrl = mpOutliner->GetControlWord();
+
+ if(mbOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+
+ mpOutliner->SetControlWord(nCntrl);
+ }
+
+ if (mpInternalOutliner)
+ {
+ nCntrl = mpInternalOutliner->GetControlWord();
+
+ if (mbOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+
+ mpInternalOutliner->SetControlWord(nCntrl);
+ }
+
+ ::Outliner& rOutliner = GetDrawOutliner();
+
+ nCntrl = rOutliner.GetControlWord();
+
+ if (mbOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+
+ rOutliner.SetControlWord(nCntrl);
+
+ if (mbOnlineSpell)
+ {
+ StartOnlineSpelling();
+ }
+ else
+ {
+ StopOnlineSpelling();
+ }
+}
+
+// OnlineSpelling: highlighting on/off
+uno::Reference< uno::XInterface > SdDrawDocument::createUnoModel()
+{
+ uno::Reference< uno::XInterface > xModel;
+
+ try
+ {
+ if ( mpDocSh )
+ xModel = mpDocSh->GetModel();
+ }
+ catch( uno::RuntimeException& )
+ {
+ }
+
+ return xModel;
+}
+
+SvxNumType SdDrawDocument::GetPageNumType() const
+{
+ return mePageNumType;
+}
+
+void SdDrawDocument::SetPrinterIndependentLayout (sal_Int32 nMode)
+{
+ switch (nMode)
+ {
+ case css::document::PrinterIndependentLayout::DISABLED:
+ case css::document::PrinterIndependentLayout::ENABLED:
+ // Just store supported modes and inform the doc shell
+ mnPrinterIndependentLayout = nMode;
+
+ // Since it is possible that a SdDrawDocument is constructed without a
+ // SdDrawDocShell the pointer member mpDocSh needs to be tested
+ // before the call is executed. This is e. g. used for copy/paste.
+ if(mpDocSh)
+ {
+ mpDocSh->UpdateRefDevice ();
+ }
+
+ break;
+
+ default:
+ // Ignore unknown values
+ break;
+ }
+}
+
+void SdDrawDocument::SetStartWithPresentation( bool bStartWithPresentation )
+{
+ mbStartWithPresentation = bStartWithPresentation;
+}
+
+void SdDrawDocument::SetExitAfterPresenting( bool bExitAfterPresenting )
+{
+ mbExitAfterPresenting = bExitAfterPresenting;
+}
+
+void SdDrawDocument::PageListChanged()
+{
+ mpDrawPageListWatcher->Invalidate();
+}
+
+void SdDrawDocument::MasterPageListChanged()
+{
+ mpMasterPageListWatcher->Invalidate();
+}
+
+void SdDrawDocument::SetCalcFieldValueHdl(::Outliner* pOutliner)
+{
+ pOutliner->SetCalcFieldValueHdl(LINK(SD_MOD(), SdModule, CalcFieldValueHdl));
+}
+
+sal_uInt16 SdDrawDocument::GetAnnotationAuthorIndex( const OUString& rAuthor )
+{
+ // force current user to have first color
+ if( maAnnotationAuthors.empty() )
+ {
+ SvtUserOptions aUserOptions;
+ maAnnotationAuthors.push_back( aUserOptions.GetFullName() );
+ }
+
+ auto iter = std::find(maAnnotationAuthors.begin(), maAnnotationAuthors.end(), rAuthor);
+ sal_uInt16 idx = static_cast<sal_uInt16>(std::distance(maAnnotationAuthors.begin(), iter));
+
+ if( idx == maAnnotationAuthors.size() )
+ {
+ maAnnotationAuthors.push_back( rAuthor );
+ }
+
+ return idx;
+}
+
+void SdDrawDocument::InitLayoutVector()
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return;
+
+ const Reference<css::uno::XComponentContext> xContext(
+ ::comphelper::getProcessComponentContext() );
+
+ // get file list from configuration
+ const Sequence< OUString > aFiles(
+ officecfg::Office::Impress::Misc::LayoutListFiles::get() );
+
+ if (aFiles.getLength() == 0)
+ return;
+ const Reference<XDocumentBuilder> xDocBuilder = DocumentBuilder::create( xContext );
+
+ for( const auto& rFile : aFiles )
+ {
+ OUString sFilename = comphelper::getExpandedUri(xContext, rFile);
+
+ // load layout file into DOM
+
+ try
+ {
+ // loop over every layout entry in current file
+ const Reference<XDocument> xDoc = xDocBuilder->parseURI( sFilename );
+ const Reference<XNodeList> layoutlist = xDoc->getElementsByTagName("layout");
+ const int nElements = layoutlist->getLength();
+ for(int index=0; index < nElements; index++)
+ maLayoutInfo.push_back( layoutlist->item(index) );
+ }
+ catch (const uno::Exception &)
+ {
+ // skip missing config. files
+ }
+ }
+}
+
+void SdDrawDocument::InitObjectVector()
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return;
+
+ const Reference<css::uno::XComponentContext> xContext(
+ ::comphelper::getProcessComponentContext() );
+
+ // get file list from configuration
+ const Sequence< OUString > aFiles(
+ officecfg::Office::Impress::Misc::PresObjListFiles::get() );
+
+ if (aFiles.getLength() == 0)
+ return;
+ const Reference<XDocumentBuilder> xDocBuilder = DocumentBuilder::create( xContext );
+ for( const auto& rFile : aFiles )
+ {
+ OUString sFilename = comphelper::getExpandedUri(xContext, rFile);
+
+ // load presentation object file into DOM
+
+ try
+ {
+ // loop over every object entry in current file
+ const Reference<XDocument> xDoc = xDocBuilder->parseURI( sFilename );
+ const Reference<XNodeList> objectlist = xDoc->getElementsByTagName("object");
+ const int nElements = objectlist->getLength();
+ for(int index=0; index < nElements; index++)
+ maPresObjectInfo.push_back( objectlist->item(index) );
+ }
+ catch (const uno::Exception &)
+ {
+ // skip missing config. files
+ }
+ }
+}
+
+void SdDrawDocument::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ bool bOwns = false;
+ if (!pWriter)
+ {
+ pWriter = xmlNewTextWriterFilename("model.xml", 0);
+ xmlTextWriterSetIndent(pWriter,1);
+ (void)xmlTextWriterSetIndentString(pWriter, BAD_CAST(" "));
+ (void)xmlTextWriterStartDocument(pWriter, nullptr, nullptr, nullptr);
+ bOwns = true;
+ }
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdDrawDocument"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+
+ if (mpOutliner)
+ mpOutliner->dumpAsXml(pWriter);
+ FmFormModel::dumpAsXml(pWriter);
+ if (GetUndoManager())
+ GetUndoManager()->dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+ if (bOwns)
+ {
+ (void)xmlTextWriterEndDocument(pWriter);
+ xmlFreeTextWriter(pWriter);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/drawdoc2.cxx b/sd/source/core/drawdoc2.cxx
new file mode 100644
index 000000000..d0187bab0
--- /dev/null
+++ b/sd/source/core/drawdoc2.cxx
@@ -0,0 +1,1382 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/settings.hxx>
+
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <sfx2/printer.hxx>
+#include <editeng/paperinf.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdundo.hxx>
+#include <vcl/svapp.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/langitem.hxx>
+#include <svl/itempool.hxx>
+#include <editeng/flditem.hxx>
+
+#include <sfx2/linkmgr.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdlayer.hxx>
+
+#include <svx/svditer.hxx>
+#include <comphelper/lok.hxx>
+#include <xmloff/autolayout.hxx>
+
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <strings.hrc>
+#include <glob.hxx>
+#include <stlpool.hxx>
+#include <anminfo.hxx>
+#include <undo/undomanager.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <unomodel.hxx>
+
+#include <DrawDocShell.hxx>
+
+#include "PageListWatcher.hxx"
+#include <unokywds.hxx>
+
+using namespace ::sd;
+
+const ::tools::Long PRINT_OFFSET = 30; // see /svx/source/dialog/page.cxx
+
+using namespace com::sun::star;
+
+// Looks up an object by name
+SdrObject* SdDrawDocument::GetObj(std::u16string_view rObjName) const
+{
+ SdrObject* pObj = nullptr;
+ SdrObject* pObjFound = nullptr;
+ const SdPage* pPage = nullptr;
+
+ // First search in all pages
+ sal_uInt16 nPage = 0;
+ const sal_uInt16 nMaxPages = GetPageCount();
+
+ while (nPage < nMaxPages && !pObjFound)
+ {
+ pPage = static_cast<const SdPage*>( GetPage(nPage) );
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
+
+ while (aIter.IsMore() && !pObjFound)
+ {
+ pObj = aIter.Next();
+
+ if( ( pObj->GetName() == rObjName ) ||
+ ( SdrInventor::Default == pObj->GetObjInventor() &&
+ SdrObjKind::OLE2 == pObj->GetObjIdentifier() &&
+ rObjName == static_cast< SdrOle2Obj* >( pObj )->GetPersistName() ) )
+ {
+ pObjFound = pObj;
+ }
+ }
+
+ nPage++;
+ }
+
+ // If it couldn't be found, look through all master pages
+ nPage = 0;
+ const sal_uInt16 nMaxMasterPages = GetMasterPageCount();
+
+ while (nPage < nMaxMasterPages && !pObjFound)
+ {
+ pPage = static_cast<const SdPage*>( GetMasterPage(nPage) );
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
+
+ while (aIter.IsMore() && !pObjFound)
+ {
+ pObj = aIter.Next();
+
+ if( ( pObj->GetName() == rObjName ) ||
+ ( SdrInventor::Default == pObj->GetObjInventor() &&
+ SdrObjKind::OLE2 == pObj->GetObjIdentifier() &&
+ rObjName == static_cast< SdrOle2Obj* >( pObj )->GetPersistName() ) )
+ {
+ pObjFound = pObj;
+ }
+ }
+
+ nPage++;
+ }
+
+ return pObjFound;
+}
+
+// Find SdPage by name
+sal_uInt16 SdDrawDocument::GetPageByName(std::u16string_view rPgName, bool& rbIsMasterPage) const
+{
+ SdPage* pPage = nullptr;
+ sal_uInt16 nPage = 0;
+ const sal_uInt16 nMaxPages = GetPageCount();
+ sal_uInt16 nPageNum = SDRPAGE_NOTFOUND;
+
+ rbIsMasterPage = false;
+
+ // Search all regular pages and all notes pages (handout pages are
+ // ignored)
+ while (nPage < nMaxPages && nPageNum == SDRPAGE_NOTFOUND)
+ {
+ pPage = const_cast<SdPage*>(static_cast<const SdPage*>(
+ GetPage(nPage)));
+
+ if (pPage != nullptr
+ && pPage->GetPageKind() != PageKind::Handout
+ && pPage->GetName() == rPgName)
+ {
+ nPageNum = nPage;
+ }
+
+ nPage++;
+ }
+
+ // Search all master pages when not found among non-master pages
+ const sal_uInt16 nMaxMasterPages = GetMasterPageCount();
+ nPage = 0;
+
+ while (nPage < nMaxMasterPages && nPageNum == SDRPAGE_NOTFOUND)
+ {
+ pPage = const_cast<SdPage*>(static_cast<const SdPage*>(
+ GetMasterPage(nPage)));
+
+ if (pPage && pPage->GetName() == rPgName)
+ {
+ nPageNum = nPage;
+ rbIsMasterPage = true;
+ }
+
+ nPage++;
+ }
+
+ return nPageNum;
+}
+
+bool SdDrawDocument::IsPageNameUnique( std::u16string_view rPgName ) const
+{
+ sal_uInt16 nCount = 0;
+ SdPage* pPage = nullptr;
+
+ // Search all regular pages and all notes pages (handout pages are ignored)
+ sal_uInt16 nPage = 0;
+ sal_uInt16 nMaxPages = GetPageCount();
+ while (nPage < nMaxPages)
+ {
+ pPage = const_cast<SdPage*>(static_cast<const SdPage*>(GetPage(nPage)));
+
+ if (pPage && pPage->GetName() == rPgName && pPage->GetPageKind() != PageKind::Handout)
+ nCount++;
+
+ nPage++;
+ }
+
+ // Search all master pages
+ nPage = 0;
+ nMaxPages = GetMasterPageCount();
+ while (nPage < nMaxPages)
+ {
+ pPage = const_cast<SdPage*>(static_cast<const SdPage*>(GetMasterPage(nPage)));
+
+ if (pPage && pPage->GetName() == rPgName)
+ nCount++;
+
+ nPage++;
+ }
+
+ return nCount == 1;
+}
+
+SdPage* SdDrawDocument::GetSdPage(sal_uInt16 nPgNum, PageKind ePgKind) const
+{
+ return mpDrawPageListWatcher->GetSdPage(ePgKind, sal_uInt32(nPgNum));
+}
+
+sal_uInt16 SdDrawDocument::GetSdPageCount(PageKind ePgKind) const
+{
+ return static_cast<sal_uInt16>(mpDrawPageListWatcher->GetSdPageCount(ePgKind));
+}
+
+SdPage* SdDrawDocument::GetMasterSdPage(sal_uInt16 nPgNum, PageKind ePgKind)
+{
+ return mpMasterPageListWatcher->GetSdPage(ePgKind, sal_uInt32(nPgNum));
+}
+
+sal_uInt16 SdDrawDocument::GetMasterSdPageCount(PageKind ePgKind) const
+{
+ return static_cast<sal_uInt16>(mpMasterPageListWatcher->GetSdPageCount(ePgKind));
+}
+
+sal_uInt16 SdDrawDocument::GetActiveSdPageCount() const
+{
+ return static_cast<sal_uInt16>(mpDrawPageListWatcher->GetVisibleSdPageCount());
+}
+
+// Adapt the page numbers that are registered in the page objects of the notes
+// pages
+void SdDrawDocument::UpdatePageObjectsInNotes(sal_uInt16 nStartPos)
+{
+ sal_uInt16 nPageCount = GetPageCount();
+ SdPage* pPage = nullptr;
+
+ for (sal_uInt16 nPage = nStartPos; nPage < nPageCount; nPage++)
+ {
+ pPage = static_cast<SdPage*>( GetPage(nPage) );
+
+ // If this is a notes page, find its page object and correct the page
+ // number
+ if (pPage && pPage->GetPageKind() == PageKind::Notes)
+ {
+ const size_t nObjCount = pPage->GetObjCount();
+ for (size_t nObj = 0; nObj < nObjCount; ++nObj)
+ {
+ SdrObject* pObj = pPage->GetObj(nObj);
+ if (pObj->GetObjIdentifier() == SdrObjKind::Page &&
+ pObj->GetObjInventor() == SdrInventor::Default)
+ {
+ // The page object is the preceding page (drawing page)
+ SAL_WARN_IF(!nStartPos, "sd", "Position of notes page must not be 0.");
+
+ SAL_WARN_IF(nPage <= 1, "sd", "Page object must not be a handout.");
+
+ if (nStartPos > 0 && nPage > 1)
+ static_cast<SdrPageObj*>(pObj)->SetReferencedPage(GetPage(nPage - 1));
+ }
+ }
+ }
+ }
+}
+
+void SdDrawDocument::UpdatePageRelativeURLs(const OUString& rOldName, std::u16string_view rNewName)
+{
+ if (rNewName.empty())
+ return;
+
+ SfxItemPool& rPool(GetPool());
+ for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(EE_FEATURE_FIELD))
+ {
+ const SvxFieldItem* pFldItem = dynamic_cast< const SvxFieldItem * > (pItem);
+
+ if(pFldItem)
+ {
+ SvxURLField* pURLField = const_cast< SvxURLField* >( dynamic_cast<const SvxURLField*>( pFldItem->GetField() ) );
+
+ if(pURLField)
+ {
+ OUString aURL = pURLField->GetURL();
+
+ if (!aURL.isEmpty() && (aURL[0] == 35) && (aURL.indexOf(rOldName, 1) == 1))
+ {
+ if (aURL.getLength() == rOldName.getLength() + 1) // standard page name
+ {
+ aURL = aURL.replaceAt(1, aURL.getLength() - 1, u"") +
+ rNewName;
+ pURLField->SetURL(aURL);
+ }
+ else
+ {
+ const OUString sNotes(SdResId(STR_NOTES));
+ if (aURL.getLength() == rOldName.getLength() + 2 + sNotes.getLength()
+ && aURL.indexOf(sNotes, rOldName.getLength() + 2) == rOldName.getLength() + 2)
+ {
+ aURL = aURL.replaceAt(1, aURL.getLength() - 1, u"") +
+ rNewName + " " + sNotes;
+ pURLField->SetURL(aURL);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void SdDrawDocument::UpdatePageRelativeURLs(SdPage const * pPage, sal_uInt16 nPos, sal_Int32 nIncrement)
+{
+ bool bNotes = (pPage->GetPageKind() == PageKind::Notes);
+
+ SfxItemPool& rPool(GetPool());
+ for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(EE_FEATURE_FIELD))
+ {
+ const SvxFieldItem* pFldItem;
+
+ if ((pFldItem = dynamic_cast< const SvxFieldItem * > (pItem)) != nullptr)
+ {
+ SvxURLField* pURLField = const_cast< SvxURLField* >( dynamic_cast<const SvxURLField*>( pFldItem->GetField() ) );
+
+ if(pURLField)
+ {
+ OUString aURL = pURLField->GetURL();
+
+ if (!aURL.isEmpty() && (aURL[0] == 35))
+ {
+ OUString aHashSlide = "#" + SdResId(STR_PAGE);
+
+ if (aURL.startsWith(aHashSlide))
+ {
+ OUString aURLCopy = aURL;
+ const OUString sNotes(SdResId(STR_NOTES));
+
+ aURLCopy = aURLCopy.replaceAt(0, aHashSlide.getLength(), u"");
+
+ bool bNotesLink = ( aURLCopy.getLength() >= sNotes.getLength() + 3
+ && aURLCopy.endsWith(sNotes) );
+
+ if (bNotesLink != bNotes)
+ continue; // no compatible link and page
+
+ if (bNotes)
+ aURLCopy = aURLCopy.replaceAt(aURLCopy.getLength() - sNotes.getLength(), sNotes.getLength(), u"");
+
+ sal_Int32 number = aURLCopy.toInt32();
+ sal_uInt16 realPageNumber = (nPos + 1)/ 2;
+
+ if ( number >= realPageNumber )
+ {
+ // update link page number
+ number += nIncrement;
+ aURL = aURL.replaceAt(aHashSlide.getLength() + 1, aURL.getLength() - aHashSlide.getLength() - 1, u"") +
+ OUString::number(number);
+ if (bNotes)
+ {
+ aURL += " " + sNotes;
+ }
+ pURLField->SetURL(aURL);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// Move page
+void SdDrawDocument::MovePage(sal_uInt16 nPgNum, sal_uInt16 nNewPos)
+{
+ FmFormModel::MovePage(nPgNum, nNewPos);
+
+ sal_uInt16 nMin = std::min(nPgNum, nNewPos);
+
+ UpdatePageObjectsInNotes(nMin);
+}
+
+// Insert page
+void SdDrawDocument::InsertPage(SdrPage* pPage, sal_uInt16 nPos)
+{
+ bool bLast = (nPos == GetPageCount());
+
+ FmFormModel::InsertPage(pPage, nPos);
+
+ static_cast<SdPage*>(pPage)->ConnectLink();
+
+ UpdatePageObjectsInNotes(nPos);
+
+ if (!bLast)
+ UpdatePageRelativeURLs(static_cast<SdPage*>( pPage ), nPos, 1);
+
+ if (comphelper::LibreOfficeKit::isActive() && static_cast<SdPage*>(pPage)->GetPageKind() == PageKind::Standard)
+ {
+ SdXImpressDocument* pDoc = comphelper::getFromUnoTunnel<SdXImpressDocument>(this->getUnoModel());
+ SfxLokHelper::notifyDocumentSizeChangedAllViews(pDoc);
+ }
+}
+
+// Delete page
+void SdDrawDocument::DeletePage(sal_uInt16 nPgNum)
+{
+ FmFormModel::DeletePage(nPgNum);
+
+ UpdatePageObjectsInNotes(nPgNum);
+}
+
+// Remove page
+rtl::Reference<SdrPage> SdDrawDocument::RemovePage(sal_uInt16 nPgNum)
+{
+ rtl::Reference<SdrPage> pPage = FmFormModel::RemovePage(nPgNum);
+
+ bool bLast = ((nPgNum+1)/2 == (GetPageCount()+1)/2);
+
+ auto pSdPage = static_cast<SdPage*>(pPage.get());
+ pSdPage->DisconnectLink();
+ ReplacePageInCustomShows( pSdPage, nullptr );
+ UpdatePageObjectsInNotes(nPgNum);
+
+ if (!bLast)
+ UpdatePageRelativeURLs(pSdPage, nPgNum, -1);
+
+ if (comphelper::LibreOfficeKit::isActive() && pSdPage->GetPageKind() == PageKind::Standard)
+ {
+ SdXImpressDocument* pDoc = comphelper::getFromUnoTunnel<SdXImpressDocument>(this->getUnoModel());
+ SfxLokHelper::notifyDocumentSizeChangedAllViews(pDoc);
+ }
+
+ return pPage;
+}
+
+// Warning: This is not called for new master pages created from SdrModel::Merge,
+// you also have to modify code in SdDrawDocument::Merge!
+void SdDrawDocument::InsertMasterPage(SdrPage* pPage, sal_uInt16 nPos )
+{
+ FmFormModel::InsertMasterPage( pPage, nPos );
+ if( pPage->IsMasterPage() && (static_cast<SdPage*>(pPage)->GetPageKind() == PageKind::Standard) )
+ {
+ // new master page created, add its style family
+ SdStyleSheetPool* pStylePool = static_cast<SdStyleSheetPool*>( GetStyleSheetPool() );
+ if( pStylePool )
+ pStylePool->AddStyleFamily( static_cast<SdPage*>(pPage) );
+ }
+}
+
+rtl::Reference<SdrPage> SdDrawDocument::RemoveMasterPage(sal_uInt16 nPgNum)
+{
+ SdPage* pPage = static_cast<SdPage*>(GetMasterPage(nPgNum ));
+ if( pPage && pPage->IsMasterPage() && (pPage->GetPageKind() == PageKind::Standard) )
+ {
+ // master page removed, remove its style family
+ SdStyleSheetPool* pStylePool = static_cast<SdStyleSheetPool*>( GetStyleSheetPool() );
+ if( pStylePool )
+ pStylePool->RemoveStyleFamily( pPage );
+ }
+
+ return FmFormModel::RemoveMasterPage(nPgNum);
+}
+
+//Select pages
+void SdDrawDocument::SetSelected(SdPage* pPage, bool bSelect)
+{
+ PageKind ePageKind = pPage->GetPageKind();
+
+ if (ePageKind == PageKind::Standard)
+ {
+ pPage->SetSelected(bSelect);
+
+ const sal_uInt16 nDestPageNum(pPage->GetPageNum() + 1);
+ SdPage* pNotesPage = nullptr;
+
+ if(nDestPageNum < GetPageCount())
+ {
+ pNotesPage = static_cast<SdPage*>(GetPage(nDestPageNum));
+ }
+
+ if (pNotesPage && pNotesPage->GetPageKind() == PageKind::Notes)
+ {
+ pNotesPage->SetSelected(bSelect);
+ }
+ }
+ else if (ePageKind == PageKind::Notes)
+ {
+ pPage->SetSelected(bSelect);
+ SdPage* pStandardPage = static_cast<SdPage*>( GetPage( pPage->GetPageNum() - 1 ) );
+
+ if (pStandardPage && pStandardPage->GetPageKind() == PageKind::Standard)
+ pStandardPage->SetSelected(bSelect);
+ }
+}
+
+// If no pages exist yet, create them now
+void SdDrawDocument::CreateFirstPages( SdDrawDocument const * pRefDocument /* = 0 */ )
+{
+ // If no page exists yet in the model, (File -> New), insert a page
+ sal_uInt16 nPageCount = GetPageCount();
+
+ if (nPageCount > 1)
+ return;
+
+ // #i57181# Paper size depends on Language, like in Writer
+ Size aDefSize = SvxPaperInfo::GetDefaultPaperSize( MapUnit::Map100thMM );
+
+ // Insert handout page
+ rtl::Reference<SdPage> pHandoutPage = AllocSdPage(false);
+
+ SdPage* pRefPage = nullptr;
+
+ if( pRefDocument )
+ pRefPage = pRefDocument->GetSdPage( 0, PageKind::Handout );
+
+ if( pRefPage )
+ {
+ pHandoutPage->SetSize(pRefPage->GetSize());
+ pHandoutPage->SetBorder( pRefPage->GetLeftBorder(), pRefPage->GetUpperBorder(), pRefPage->GetRightBorder(), pRefPage->GetLowerBorder() );
+ }
+ else
+ {
+ pHandoutPage->SetSize(aDefSize);
+ pHandoutPage->SetBorder(0, 0, 0, 0);
+ }
+
+ pHandoutPage->SetPageKind(PageKind::Handout);
+ pHandoutPage->SetName( SdResId(STR_HANDOUT) );
+ InsertPage(pHandoutPage.get(), 0);
+
+ // Insert master page and register this with the handout page
+ rtl::Reference<SdPage> pHandoutMPage = AllocSdPage(true);
+ pHandoutMPage->SetSize( pHandoutPage->GetSize() );
+ pHandoutMPage->SetPageKind(PageKind::Handout);
+ pHandoutMPage->SetBorder( pHandoutPage->GetLeftBorder(),
+ pHandoutPage->GetUpperBorder(),
+ pHandoutPage->GetRightBorder(),
+ pHandoutPage->GetLowerBorder() );
+ InsertMasterPage(pHandoutMPage.get(), 0);
+ pHandoutPage->TRG_SetMasterPage( *pHandoutMPage );
+
+ // Insert page
+ // If nPageCount==1 is, the model for the clipboard was created, thus a
+ // default page must already exist
+ rtl::Reference<SdPage> pPage;
+ bool bClipboard = false;
+
+ if( pRefDocument )
+ pRefPage = pRefDocument->GetSdPage( 0, PageKind::Standard );
+
+ if (nPageCount == 0)
+ {
+ pPage = AllocSdPage(false);
+
+ if( pRefPage )
+ {
+ pPage->SetSize( pRefPage->GetSize() );
+ pPage->SetBorder( pRefPage->GetLeftBorder(), pRefPage->GetUpperBorder(), pRefPage->GetRightBorder(), pRefPage->GetLowerBorder() );
+ }
+ else if (meDocType == DocumentType::Draw)
+ {
+ // Draw: always use default size with margins
+ pPage->SetSize(aDefSize);
+
+ SfxPrinter* pPrinter = mpDocSh->GetPrinter(false);
+ if (pPrinter && pPrinter->IsValid())
+ {
+ Size aOutSize(pPrinter->GetOutputSize());
+ Point aPageOffset(pPrinter->GetPageOffset());
+ aPageOffset -= pPrinter->PixelToLogic( Point() );
+ ::tools::Long nOffset = !aPageOffset.X() && !aPageOffset.Y() ? 0 : PRINT_OFFSET;
+
+ sal_uLong nTop = aPageOffset.Y();
+ sal_uLong nLeft = aPageOffset.X();
+ sal_uLong nBottom = std::max(::tools::Long(aDefSize.Height() - aOutSize.Height() - nTop + nOffset), ::tools::Long(0));
+ sal_uLong nRight = std::max(::tools::Long(aDefSize.Width() - aOutSize.Width() - nLeft + nOffset), ::tools::Long(0));
+
+ pPage->SetBorder(nLeft, nTop, nRight, nBottom);
+ }
+ else
+ {
+ // The printer is not available. Use a border of 10mm
+ // on each side instead.
+ // This has to be kept synchronized with the border
+ // width set in the
+ // SvxPageDescPage::PaperSizeSelect_Impl callback.
+ pPage->SetBorder(1000, 1000, 1000, 1000);
+ }
+ }
+ else
+ {
+ // Impress: always use screen format, landscape.
+ Size aSz( SvxPaperInfo::GetPaperSize(PAPER_SCREEN_16_9, MapUnit::Map100thMM) );
+ pPage->SetSize( Size( aSz.Height(), aSz.Width() ) );
+ pPage->SetBorder(0, 0, 0, 0);
+ }
+
+ InsertPage(pPage.get(), 1);
+ }
+ else
+ {
+ bClipboard = true;
+ pPage = static_cast<SdPage*>( GetPage(1) );
+ }
+
+ // Insert master page, then register this with the page
+ rtl::Reference<SdPage> pMPage = AllocSdPage(true);
+ pMPage->SetSize( pPage->GetSize() );
+ pMPage->SetBorder( pPage->GetLeftBorder(),
+ pPage->GetUpperBorder(),
+ pPage->GetRightBorder(),
+ pPage->GetLowerBorder() );
+ InsertMasterPage(pMPage.get(), 1);
+ pPage->TRG_SetMasterPage( *pMPage );
+ if( bClipboard )
+ pMPage->SetLayoutName( pPage->GetLayoutName() );
+
+ // Insert notes page
+ rtl::Reference<SdPage> pNotesPage = AllocSdPage(false);
+
+ if( pRefDocument )
+ pRefPage = pRefDocument->GetSdPage( 0, PageKind::Notes );
+
+ if( pRefPage )
+ {
+ pNotesPage->SetSize( pRefPage->GetSize() );
+ pNotesPage->SetBorder( pRefPage->GetLeftBorder(), pRefPage->GetUpperBorder(), pRefPage->GetRightBorder(), pRefPage->GetLowerBorder() );
+ }
+ else
+ {
+ // Always use portrait format
+ if (aDefSize.Height() >= aDefSize.Width())
+ {
+ pNotesPage->SetSize(aDefSize);
+ }
+ else
+ {
+ pNotesPage->SetSize( Size(aDefSize.Height(), aDefSize.Width()) );
+ }
+
+ pNotesPage->SetBorder(0, 0, 0, 0);
+ }
+ pNotesPage->SetPageKind(PageKind::Notes);
+ InsertPage(pNotesPage.get(), 2);
+ if( bClipboard )
+ pNotesPage->SetLayoutName( pPage->GetLayoutName() );
+
+ // Insert master page, then register this with the notes page
+ rtl::Reference<SdPage> pNotesMPage = AllocSdPage(true);
+ pNotesMPage->SetSize( pNotesPage->GetSize() );
+ pNotesMPage->SetPageKind(PageKind::Notes);
+ pNotesMPage->SetBorder( pNotesPage->GetLeftBorder(),
+ pNotesPage->GetUpperBorder(),
+ pNotesPage->GetRightBorder(),
+ pNotesPage->GetLowerBorder() );
+ InsertMasterPage(pNotesMPage.get(), 2);
+ pNotesPage->TRG_SetMasterPage( *pNotesMPage );
+ if( bClipboard )
+ pNotesMPage->SetLayoutName( pPage->GetLayoutName() );
+
+ if( !pRefPage && (meDocType != DocumentType::Draw) )
+ pPage->SetAutoLayout( AUTOLAYOUT_TITLE, true, true );
+
+ mpWorkStartupTimer.reset( new Timer("DrawWorkStartupTimer") );
+ mpWorkStartupTimer->SetInvokeHandler( LINK(this, SdDrawDocument, WorkStartupHdl) );
+ mpWorkStartupTimer->SetTimeout(2000);
+ mpWorkStartupTimer->Start();
+
+ SetChanged(false);
+}
+
+// Creates missing notes and handout pages (after PowerPoint import).
+// We assume that at least one default page and one default master page exist.
+
+bool SdDrawDocument::CreateMissingNotesAndHandoutPages()
+{
+ bool bOK = false;
+ sal_uInt16 nPageCount = GetPageCount();
+
+ if (nPageCount != 0)
+ {
+ // Set PageKind
+ SdPage* pHandoutMPage = static_cast<SdPage*>( GetMasterPage(0) );
+ pHandoutMPage->SetPageKind(PageKind::Handout);
+
+ SdPage* pHandoutPage = static_cast<SdPage*>( GetPage(0) );
+ pHandoutPage->SetPageKind(PageKind::Handout);
+ pHandoutPage->TRG_SetMasterPage( *pHandoutMPage );
+
+ for (sal_uInt16 i = 1; i < nPageCount; i = i + 2)
+ {
+ SdPage* pPage = static_cast<SdPage*>( GetPage(i) );
+
+ if(!pPage->TRG_HasMasterPage())
+ {
+ // No master page set -> use first default master page
+ // (If there was no default page in the PPT)
+ pPage->TRG_SetMasterPage(*GetMasterPage(1));
+ }
+
+ SdPage* pNotesPage = static_cast<SdPage*>( GetPage(i+1) );
+ pNotesPage->SetPageKind(PageKind::Notes);
+
+ // Set notes master page
+ sal_uInt16 nMasterPageAfterPagesMasterPage = pPage->TRG_GetMasterPage().GetPageNum() + 1;
+ pNotesPage->TRG_SetMasterPage(*GetMasterPage(nMasterPageAfterPagesMasterPage));
+ }
+
+ bOK = true;
+ StopWorkStartupDelay();
+ SetChanged(false);
+ }
+
+ return bOK;
+}
+
+void SdDrawDocument::UnselectAllPages()
+{
+ sal_uInt16 nNoOfPages = GetSdPageCount(PageKind::Standard);
+ for (sal_uInt16 nPage = 0; nPage < nNoOfPages; ++nPage)
+ {
+ SdPage* pPage = GetSdPage(nPage, PageKind::Standard);
+ pPage->SetSelected(false);
+ }
+}
+
+// + Move selected pages after said page
+// (nTargetPage = (sal_uInt16)-1 --> move before first page)
+// + Returns sal_True when the page has been moved
+bool SdDrawDocument::MovePages(sal_uInt16 nTargetPage)
+{
+ SdPage* pPage = nullptr;
+ sal_uInt16 nPage;
+ sal_uInt16 nNoOfPages = GetSdPageCount(PageKind::Standard);
+ bool bSomethingHappened = false;
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo(SdResId(STR_UNDO_MOVEPAGES));
+
+ // List of selected pages
+ std::vector<SdPage*> aPageList;
+ for (nPage = 0; nPage < nNoOfPages; nPage++)
+ {
+ pPage = GetSdPage(nPage, PageKind::Standard);
+
+ if (pPage->IsSelected()) {
+ aPageList.push_back(pPage);
+ }
+ }
+
+ // If necessary, look backwards, until we find a page that wasn't selected
+ nPage = nTargetPage;
+
+ if (nPage != sal_uInt16(-1))
+ {
+ pPage = GetSdPage(nPage, PageKind::Standard);
+ while (nPage > 0 && pPage->IsSelected())
+ {
+ nPage--;
+ pPage = GetSdPage(nPage, PageKind::Standard);
+ }
+
+ if (pPage->IsSelected())
+ {
+ nPage = sal_uInt16(-1);
+ }
+ }
+
+ // Insert before the first page
+ if (nPage == sal_uInt16(-1))
+ {
+ std::vector<SdPage*>::reverse_iterator iter;
+ for (iter = aPageList.rbegin(); iter != aPageList.rend(); ++iter)
+ {
+ nPage = (*iter)->GetPageNum();
+ if (nPage != 0)
+ {
+ SdrPage* pPg = GetPage(nPage);
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*pPg, nPage, 1));
+ MovePage(nPage, 1);
+ pPg = GetPage(nPage+1);
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*pPg, nPage+1, 2));
+ MovePage(nPage+1, 2);
+ bSomethingHappened = true;
+ }
+ }
+ }
+ // Insert after <nPage>
+ else
+ {
+ nTargetPage = 2 * nPage + 1; // PageKind::Standard --> absolute
+
+ for (const auto& rpPage : aPageList)
+ {
+ nPage = rpPage->GetPageNum();
+ if (nPage > nTargetPage)
+ {
+ nTargetPage += 2; // Insert _after_ the page
+
+ if (nPage != nTargetPage)
+ {
+ SdrPage* pPg = GetPage(nPage);
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*pPg, nPage, nTargetPage));
+ MovePage(nPage, nTargetPage);
+ pPg = GetPage(nPage+1);
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*pPg, nPage+1, nTargetPage+1));
+ MovePage(nPage+1, nTargetPage+1);
+ bSomethingHappened = true;
+ }
+ }
+ else
+ {
+ if (nPage != nTargetPage)
+ {
+ SdrPage* pPg = GetPage(nPage+1);
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*pPg, nPage+1, nTargetPage+1));
+ MovePage(nPage+1, nTargetPage+1);
+ pPg = GetPage(nPage);
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*pPg, nPage, nTargetPage));
+ MovePage(nPage, nTargetPage);
+ bSomethingHappened = true;
+ }
+ }
+ nTargetPage = rpPage->GetPageNum();
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+
+ return bSomethingHappened;
+}
+
+// Return number of links in sfx2::LinkManager
+sal_uLong SdDrawDocument::GetLinkCount() const
+{
+ return m_pLinkManager->GetLinks().size();
+}
+
+// Set Language
+void SdDrawDocument::SetLanguage( const LanguageType eLang, const sal_uInt16 nId )
+{
+ bool bChanged = false;
+
+ if( nId == EE_CHAR_LANGUAGE && meLanguage != eLang )
+ {
+ meLanguage = eLang;
+ bChanged = true;
+ }
+ else if( nId == EE_CHAR_LANGUAGE_CJK && meLanguageCJK != eLang )
+ {
+ meLanguageCJK = eLang;
+ bChanged = true;
+ }
+ else if( nId == EE_CHAR_LANGUAGE_CTL && meLanguageCTL != eLang )
+ {
+ meLanguageCTL = eLang;
+ bChanged = true;
+ }
+
+ if( bChanged )
+ {
+ GetDrawOutliner().SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
+ m_pHitTestOutliner->SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
+ m_pItemPool->SetPoolDefaultItem( SvxLanguageItem( eLang, nId ) );
+ SetChanged( bChanged );
+ }
+}
+
+// Return language
+LanguageType SdDrawDocument::GetLanguage( const sal_uInt16 nId ) const
+{
+ LanguageType eLangType = meLanguage;
+
+ if( nId == EE_CHAR_LANGUAGE_CJK )
+ eLangType = meLanguageCJK;
+ else if( nId == EE_CHAR_LANGUAGE_CTL )
+ eLangType = meLanguageCTL;
+
+ return eLangType;
+}
+
+// Initiate WorkStartup
+IMPL_LINK_NOARG(SdDrawDocument, WorkStartupHdl, Timer *, void)
+{
+ if (IsTransportContainer())
+ return;
+
+ if( mpDocSh )
+ mpDocSh->SetWaitCursor( true );
+
+ bool bChanged = IsChanged(); // remember this
+
+ // Initialize Autolayouts
+ SdPage* pHandoutMPage = GetMasterSdPage(0, PageKind::Handout);
+
+ if (pHandoutMPage->GetAutoLayout() == AUTOLAYOUT_NONE)
+ {
+ // No AutoLayout yet -> initialize
+ pHandoutMPage->SetAutoLayout(AUTOLAYOUT_HANDOUT6, true, true);
+ }
+
+ SdPage* pPage = GetSdPage(0, PageKind::Standard);
+
+ if (pPage->GetAutoLayout() == AUTOLAYOUT_NONE)
+ {
+ // No AutoLayout yet -> initialize
+ pPage->SetAutoLayout(AUTOLAYOUT_NONE, true, true);
+ }
+
+ SdPage* pNotesPage = GetSdPage(0, PageKind::Notes);
+
+ if (pNotesPage->GetAutoLayout() == AUTOLAYOUT_NONE)
+ {
+ // No AutoLayout yet -> initialize
+ pNotesPage->SetAutoLayout(AUTOLAYOUT_NOTES, true, true);
+ }
+
+ SetChanged(bChanged);
+
+ if( mpDocSh )
+ mpDocSh->SetWaitCursor( false );
+}
+
+// When the WorkStartupTimer has been created (this only happens in
+// SdDrawViewShell::Construct() ), the timer may be stopped and the WorkStartup
+// may be initiated.
+void SdDrawDocument::StopWorkStartupDelay()
+{
+ if (mpWorkStartupTimer)
+ {
+ if ( mpWorkStartupTimer->IsActive() )
+ {
+ // Timer not yet expired -> initiate WorkStartup
+ mpWorkStartupTimer->Stop();
+ WorkStartupHdl(nullptr);
+ }
+
+ mpWorkStartupTimer.reset();
+ }
+}
+
+// When the WorkStartupTimer has been created (this only happens in
+// SdDrawViewShell::Construct() ), the timer may be stopped and the WorkStartup
+// may be initiated.
+SdAnimationInfo* SdDrawDocument::GetAnimationInfo(SdrObject* pObject)
+{
+ DBG_ASSERT(pObject, "sd::SdDrawDocument::GetAnimationInfo(), invalid argument!");
+ if( pObject )
+ return GetShapeUserData( *pObject );
+ else
+ return nullptr;
+}
+
+SdAnimationInfo* SdDrawDocument::GetShapeUserData(SdrObject& rObject, bool bCreate /* = false */ )
+{
+ sal_uInt16 nUD = 0;
+ sal_uInt16 nUDCount = rObject.GetUserDataCount();
+ SdAnimationInfo* pRet = nullptr;
+
+ // Can we find animation information within the user data?
+ for (nUD = 0; nUD < nUDCount; nUD++)
+ {
+ SdrObjUserData* pUD = rObject.GetUserData(nUD);
+ if((pUD->GetInventor() == SdrInventor::StarDrawUserData) && (pUD->GetId() == SD_ANIMATIONINFO_ID))
+ {
+ pRet = dynamic_cast<SdAnimationInfo*>(pUD);
+ break;
+ }
+ }
+
+ if( (pRet == nullptr) && bCreate )
+ {
+ pRet = new SdAnimationInfo( rObject );
+ rObject.AppendUserData( std::unique_ptr<SdrObjUserData>(pRet) );
+ }
+
+ return pRet;
+}
+
+/** this method enforces that the masterpages are in the correct order,
+ that is at position 1 is a PageKind::Standard masterpage followed by a
+ PageKind::Notes masterpage and so on. #
+*/
+void SdDrawDocument::CheckMasterPages()
+{
+ sal_uInt16 nMaxPages = GetMasterPageCount();
+
+ // we need at least a handout master and one master page
+ if( nMaxPages < 2 )
+ {
+ return;
+ }
+
+ SdPage* pPage = nullptr;
+
+ sal_uInt16 nPage;
+
+ // first see if the page order is correct
+ for( nPage = 1; nPage < nMaxPages; nPage++ )
+ {
+ pPage = static_cast<SdPage*> (GetMasterPage( nPage ));
+ // if an odd page is not a standard page or an even page is not a notes page
+ if( ((1 == (nPage & 1)) && (pPage->GetPageKind() != PageKind::Standard) ) ||
+ ((0 == (nPage & 1)) && (pPage->GetPageKind() != PageKind::Notes) ) )
+ break; // then we have a fatal error
+ }
+
+ if( nPage >= nMaxPages )
+ return;
+
+ SdPage* pNotesPage = nullptr;
+
+ // there is a fatal error in the master page order,
+ // we need to repair the document
+ bool bChanged = false;
+
+ nPage = 1;
+ while( nPage < nMaxPages )
+ {
+ pPage = static_cast<SdPage*> (GetMasterPage( nPage ));
+ if( pPage->GetPageKind() != PageKind::Standard )
+ {
+ bChanged = true;
+ sal_uInt16 nFound = nPage + 1;
+ while( nFound < nMaxPages )
+ {
+ pPage = static_cast<SdPage*>(GetMasterPage( nFound ));
+ if( PageKind::Standard == pPage->GetPageKind() )
+ {
+ MoveMasterPage( nFound, nPage );
+ pPage->SetInserted();
+ break;
+
+ }
+
+ nFound++;
+ }
+
+ // if we don't have any more standard pages, were done
+ if( nMaxPages == nFound )
+ break;
+ }
+
+ nPage++;
+
+ if( nPage < nMaxPages )
+ pNotesPage = static_cast<SdPage*>(GetMasterPage( nPage ));
+ else
+ pNotesPage = nullptr;
+
+ if( (nullptr == pNotesPage) || (pNotesPage->GetPageKind() != PageKind::Notes) || ( pPage->GetLayoutName() != pNotesPage->GetLayoutName() ) )
+ {
+ bChanged = true;
+
+ sal_uInt16 nFound = nPage + 1;
+ while( nFound < nMaxPages )
+ {
+ pNotesPage = static_cast<SdPage*>(GetMasterPage( nFound ));
+ if( (PageKind::Notes == pNotesPage->GetPageKind()) && ( pPage->GetLayoutName() == pNotesPage->GetLayoutName() ) )
+ {
+ MoveMasterPage( nFound, nPage );
+ pNotesPage->SetInserted();
+ break;
+ }
+
+ nFound++;
+ }
+
+ // looks like we lost a notes page
+ if( nMaxPages == nFound )
+ {
+ // so create one
+
+ // first find a reference notes page for size
+ SdPage* pRefNotesPage = nullptr;
+ nFound = 0;
+ while( nFound < nMaxPages )
+ {
+ pRefNotesPage = static_cast<SdPage*>(GetMasterPage( nFound ));
+ if( PageKind::Notes == pRefNotesPage->GetPageKind() )
+ break;
+ nFound++;
+ }
+ if( nFound == nMaxPages )
+ pRefNotesPage = nullptr;
+
+ rtl::Reference<SdPage> pNewNotesPage = AllocSdPage(true);
+ pNewNotesPage->SetPageKind(PageKind::Notes);
+ if( pRefNotesPage )
+ {
+ pNewNotesPage->SetSize( pRefNotesPage->GetSize() );
+ pNewNotesPage->SetBorder( pRefNotesPage->GetLeftBorder(),
+ pRefNotesPage->GetUpperBorder(),
+ pRefNotesPage->GetRightBorder(),
+ pRefNotesPage->GetLowerBorder() );
+ }
+ InsertMasterPage(pNewNotesPage.get(), nPage );
+ pNewNotesPage->SetLayoutName( pPage->GetLayoutName() );
+ pNewNotesPage->SetAutoLayout(AUTOLAYOUT_NOTES, true, true );
+ nMaxPages++;
+ }
+ }
+
+ nPage++;
+ }
+
+ // now remove all remaining and unused non PageKind::Standard slides
+ while( nPage < nMaxPages )
+ {
+ bChanged = true;
+
+ RemoveMasterPage( nPage );
+ nMaxPages--;
+ }
+
+ if( bChanged )
+ {
+ OSL_FAIL( "master pages where in a wrong order" );
+ RecalcPageNums( true);
+ }
+}
+
+sal_uInt16 SdDrawDocument::CreatePage (
+ SdPage* pActualPage,
+ PageKind ePageKind,
+ const OUString& sStandardPageName,
+ const OUString& sNotesPageName,
+ AutoLayout eStandardLayout,
+ AutoLayout eNotesLayout,
+ bool bIsPageBack,
+ bool bIsPageObj,
+ const sal_Int32 nInsertPosition)
+{
+ SdPage* pPreviousStandardPage;
+ SdPage* pPreviousNotesPage;
+ rtl::Reference<SdPage> pStandardPage;
+ rtl::Reference<SdPage> pNotesPage;
+
+ // From the given page determine the standard page and notes page of which
+ // to take the layout and the position where to insert the new pages.
+ if (ePageKind == PageKind::Notes)
+ {
+ pPreviousNotesPage = pActualPage;
+ sal_uInt16 nNotesPageNum = pPreviousNotesPage->GetPageNum() + 2;
+ pPreviousStandardPage = static_cast<SdPage*>( GetPage(nNotesPageNum - 3) );
+ eStandardLayout = pPreviousStandardPage->GetAutoLayout();
+ }
+ else
+ {
+ pPreviousStandardPage = pActualPage;
+ sal_uInt16 nStandardPageNum = pPreviousStandardPage->GetPageNum() + 2;
+ pPreviousNotesPage = static_cast<SdPage*>( GetPage(nStandardPageNum - 1) );
+ eNotesLayout = pPreviousNotesPage->GetAutoLayout();
+ }
+
+ // Create new standard page and set it up
+ pStandardPage = AllocSdPage(false);
+
+ // Set the size here since else the presobj autolayout
+ // will be wrong.
+ pStandardPage->SetSize( pPreviousStandardPage->GetSize() );
+ pStandardPage->SetBorder( pPreviousStandardPage->GetLeftBorder(),
+ pPreviousStandardPage->GetUpperBorder(),
+ pPreviousStandardPage->GetRightBorder(),
+ pPreviousStandardPage->GetLowerBorder() );
+
+ // Use master page of current page.
+ pStandardPage->TRG_SetMasterPage(pPreviousStandardPage->TRG_GetMasterPage());
+
+ // User layout of current standard page
+ pStandardPage->SetLayoutName( pPreviousStandardPage->GetLayoutName() );
+ pStandardPage->SetAutoLayout(eStandardLayout, true);
+ pStandardPage->setHeaderFooterSettings( pPreviousStandardPage->getHeaderFooterSettings() );
+
+ // transition settings of current page
+ pStandardPage->setTransitionType( pPreviousStandardPage->getTransitionType() );
+ pStandardPage->setTransitionSubtype( pPreviousStandardPage->getTransitionSubtype() );
+ pStandardPage->setTransitionDirection( pPreviousStandardPage->getTransitionDirection() );
+ pStandardPage->setTransitionFadeColor( pPreviousStandardPage->getTransitionFadeColor() );
+ pStandardPage->setTransitionDuration( pPreviousStandardPage->getTransitionDuration() );
+
+ // apply previous animation timing
+ pStandardPage->SetPresChange( pPreviousStandardPage->GetPresChange() );
+ pStandardPage->SetTime( pPreviousStandardPage->GetTime() );
+
+ // Create new notes page and set it up
+ pNotesPage = AllocSdPage(false);
+ pNotesPage->SetPageKind(PageKind::Notes);
+
+ // Use master page of current page
+ pNotesPage->TRG_SetMasterPage(pPreviousNotesPage->TRG_GetMasterPage());
+
+ // Use layout of current notes page
+ pNotesPage->SetLayoutName( pPreviousNotesPage->GetLayoutName() );
+ pNotesPage->SetAutoLayout(eNotesLayout, true);
+ pNotesPage->setHeaderFooterSettings( pPreviousNotesPage->getHeaderFooterSettings() );
+
+ return InsertPageSet (
+ pActualPage,
+ ePageKind,
+ sStandardPageName,
+ sNotesPageName,
+ bIsPageBack,
+ bIsPageObj,
+ pStandardPage.get(),
+ pNotesPage.get(),
+ nInsertPosition);
+}
+
+sal_uInt16 SdDrawDocument::DuplicatePage (sal_uInt16 nPageNum)
+{
+ PageKind ePageKind = PageKind::Standard;
+
+ // Get current page
+ SdPage* pActualPage = GetSdPage(nPageNum, ePageKind);
+
+ // Get background flags
+ SdrLayerAdmin& rLayerAdmin = GetLayerAdmin();
+ SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ SdrLayerIDSet aVisibleLayers = pActualPage->TRG_GetMasterPageVisibleLayers();
+
+ return DuplicatePage (
+ pActualPage, ePageKind,
+ // No names for the new slides
+ OUString(), OUString(),
+ aVisibleLayers.IsSet(aBckgrnd),
+ aVisibleLayers.IsSet(aBckgrndObj), -1);
+}
+
+sal_uInt16 SdDrawDocument::DuplicatePage (
+ SdPage* pActualPage,
+ PageKind ePageKind,
+ const OUString& sStandardPageName,
+ const OUString& sNotesPageName,
+ bool bIsPageBack,
+ bool bIsPageObj,
+ const sal_Int32 nInsertPosition)
+{
+ SdPage* pPreviousStandardPage;
+ SdPage* pPreviousNotesPage;
+ rtl::Reference<SdPage> pStandardPage;
+ rtl::Reference<SdPage> pNotesPage;
+
+ // From the given page determine the standard page and the notes page
+ // of which to make copies.
+ if (ePageKind == PageKind::Notes)
+ {
+ pPreviousNotesPage = pActualPage;
+ sal_uInt16 nNotesPageNum = pPreviousNotesPage->GetPageNum() + 2;
+ pPreviousStandardPage = static_cast<SdPage*>( GetPage(nNotesPageNum - 3) );
+ }
+ else
+ {
+ pPreviousStandardPage = pActualPage;
+ sal_uInt16 nStandardPageNum = pPreviousStandardPage->GetPageNum() + 2;
+ pPreviousNotesPage = static_cast<SdPage*>( GetPage(nStandardPageNum - 1) );
+ }
+
+ // Create duplicates of a standard page and the associated notes page
+ pStandardPage = static_cast<SdPage*>( pPreviousStandardPage->CloneSdrPage(*this).get() );
+ pNotesPage = static_cast<SdPage*>( pPreviousNotesPage->CloneSdrPage(*this).get() );
+
+ return InsertPageSet (
+ pActualPage,
+ ePageKind,
+ sStandardPageName,
+ sNotesPageName,
+ bIsPageBack,
+ bIsPageObj,
+ pStandardPage.get(),
+ pNotesPage.get(),
+ nInsertPosition);
+}
+
+sal_uInt16 SdDrawDocument::InsertPageSet (
+ SdPage* pActualPage,
+ PageKind ePageKind,
+ const OUString& sStandardPageName,
+ const OUString& sNotesPageName,
+ bool bIsPageBack,
+ bool bIsPageObj,
+ SdPage* pStandardPage,
+ SdPage* pNotesPage,
+ sal_Int32 nInsertPosition)
+{
+ SdPage* pPreviousStandardPage;
+ SdPage* pPreviousNotesPage;
+ sal_uInt16 nStandardPageNum;
+ sal_uInt16 nNotesPageNum;
+ OUString aNotesPageName(sNotesPageName);
+
+ // Gather some information about the standard page and the notes page
+ // that are to be inserted. This makes sure that there is always one
+ // standard page followed by one notes page.
+ if (ePageKind == PageKind::Notes)
+ {
+ pPreviousNotesPage = pActualPage;
+ nNotesPageNum = pPreviousNotesPage->GetPageNum() + 2;
+ pPreviousStandardPage = static_cast<SdPage*>( GetPage(nNotesPageNum - 3) );
+ nStandardPageNum = nNotesPageNum - 1;
+ }
+ else
+ {
+ pPreviousStandardPage = pActualPage;
+ nStandardPageNum = pPreviousStandardPage->GetPageNum() + 2;
+ pPreviousNotesPage = static_cast<SdPage*>( GetPage(nStandardPageNum - 1) );
+ nNotesPageNum = nStandardPageNum + 1;
+ aNotesPageName = sStandardPageName;
+ }
+
+ OSL_ASSERT(nNotesPageNum==nStandardPageNum+1);
+ if (nInsertPosition < 0)
+ nInsertPosition = nStandardPageNum;
+
+ // Set up and insert the standard page
+ SetupNewPage (
+ pPreviousStandardPage,
+ pStandardPage,
+ sStandardPageName,
+ nInsertPosition,
+ bIsPageBack,
+ bIsPageObj);
+
+ // Set up and insert the notes page
+ pNotesPage->SetPageKind(PageKind::Notes);
+ SetupNewPage (
+ pPreviousNotesPage,
+ pNotesPage,
+ aNotesPageName,
+ nInsertPosition+1,
+ bIsPageBack,
+ bIsPageObj);
+
+ // Return an index that allows the caller to access the newly inserted
+ // pages by using GetSdPage()
+ return pStandardPage->GetPageNum() / 2;
+}
+
+void SdDrawDocument::SetupNewPage (
+ SdPage const * pPreviousPage,
+ SdPage* pPage,
+ const OUString& sPageName,
+ sal_uInt16 nInsertionPoint,
+ bool bIsPageBack,
+ bool bIsPageObj)
+{
+ if (pPreviousPage != nullptr)
+ {
+ pPage->SetSize( pPreviousPage->GetSize() );
+ pPage->SetBorder( pPreviousPage->GetLeftBorder(),
+ pPreviousPage->GetUpperBorder(),
+ pPreviousPage->GetRightBorder(),
+ pPreviousPage->GetLowerBorder() );
+ }
+ pPage->SetName(sPageName);
+
+ InsertPage(pPage, nInsertionPoint);
+
+ if (pPreviousPage != nullptr)
+ {
+ SdrLayerAdmin& rLayerAdmin = GetLayerAdmin();
+ SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ SdrLayerIDSet aVisibleLayers = pPreviousPage->TRG_GetMasterPageVisibleLayers();
+ aVisibleLayers.Set(aBckgrnd, bIsPageBack);
+ aVisibleLayers.Set(aBckgrndObj, bIsPageObj);
+ pPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+ }
+}
+
+sd::UndoManager* SdDrawDocument::GetUndoManager() const
+{
+ return mpDocSh ? dynamic_cast< sd::UndoManager* >(mpDocSh->GetUndoManager()) : nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/drawdoc3.cxx b/sd/source/core/drawdoc3.cxx
new file mode 100644
index 000000000..e25e8199d
--- /dev/null
+++ b/sd/source/core/drawdoc3.cxx
@@ -0,0 +1,1873 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <memory>
+#include <string_view>
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/app.hxx>
+#include <svl/itemset.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <sfx2/fcontnr.hxx>
+#include <svl/style.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdundo.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <xmloff/autolayout.hxx>
+
+#include <strings.hrc>
+#include <drawdoc.hxx>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+#include <stlpool.hxx>
+#include <sdresid.hxx>
+#include <customshowlist.hxx>
+#include <sdxfer.hxx>
+
+#include <unmovss.hxx>
+#include <unchss.hxx>
+#include <unprlout.hxx>
+#include <DrawDocShell.hxx>
+#include <GraphicDocShell.hxx>
+#include <ViewShell.hxx>
+#include <View.hxx>
+#include <ViewShellBase.hxx>
+#include <strings.hxx>
+
+using namespace ::com::sun::star;
+
+/** Concrete incarnations get called by lcl_IterateBookmarkPages, for
+ every page in the bookmark document/list
+ */
+
+namespace {
+
+class InsertBookmarkAsPage_FindDuplicateLayouts
+{
+public:
+ explicit InsertBookmarkAsPage_FindDuplicateLayouts( std::vector<OUString> &rLayoutsToTransfer )
+ : mrLayoutsToTransfer(rLayoutsToTransfer) {}
+ void operator()( SdDrawDocument&, SdPage const *, bool, SdDrawDocument* );
+private:
+ std::vector<OUString> &mrLayoutsToTransfer;
+};
+
+}
+
+void InsertBookmarkAsPage_FindDuplicateLayouts::operator()( SdDrawDocument& rDoc, SdPage const * pBMMPage, bool bRenameDuplicates, SdDrawDocument* pBookmarkDoc )
+{
+ // now check for duplicate masterpage and layout names
+
+ OUString aLayout( pBMMPage->GetLayoutName() );
+ sal_Int32 nIndex = aLayout.indexOf( SD_LT_SEPARATOR );
+ if( nIndex != -1 )
+ aLayout = aLayout.copy(0, nIndex);
+
+ std::vector<OUString>::const_iterator pIter =
+ find(mrLayoutsToTransfer.begin(),mrLayoutsToTransfer.end(),aLayout);
+
+ bool bFound = pIter != mrLayoutsToTransfer.end();
+
+ const sal_uInt16 nMPageCount = rDoc.GetMasterPageCount();
+ for (sal_uInt16 nMPage = 0; nMPage < nMPageCount && !bFound; nMPage++)
+ {
+ // Do the layouts already exist within the document?
+ SdPage* pTestPage = static_cast<SdPage*>( rDoc.GetMasterPage(nMPage) );
+ OUString aTest(pTestPage->GetLayoutName());
+ sal_Int32 nIndex2 = aTest.indexOf( SD_LT_SEPARATOR );
+ if( nIndex2 != -1 )
+ aTest = aTest.copy(0, nIndex2);
+
+ if (aTest == aLayout && pBMMPage->GetPageKind() == pTestPage->GetPageKind())
+ {
+ // Ignore Layouts with "Default" these seem to be special - in the sense that there are lot of assumption all over Impress
+ // about this
+ if( bRenameDuplicates && aTest != SdResId( STR_LAYOUT_DEFAULT_NAME ) && !(pTestPage->Equals(*pBMMPage)) )
+ {
+ pBookmarkDoc->RenameLayoutTemplate(
+ pBMMPage->GetLayoutName(), pBMMPage->GetName() + "_");
+ aLayout = pBMMPage->GetName();
+
+ break;
+ }
+ else
+ bFound = true;
+ }
+ }
+
+ if (!bFound)
+ mrLayoutsToTransfer.push_back(aLayout);
+}
+
+// Inserts a bookmark as a page
+static void lcl_IterateBookmarkPages( SdDrawDocument &rDoc, SdDrawDocument* pBookmarkDoc,
+ const std::vector<OUString> &rBookmarkList, sal_uInt16 nBMSdPageCount,
+ InsertBookmarkAsPage_FindDuplicateLayouts& rPageIterator, bool bRenameDuplicates )
+{
+
+ // Refactored copy'n'pasted layout name collection from InsertBookmarkAsPage
+
+ int nPos, nEndPos;
+
+ if( rBookmarkList.empty() )
+ {
+ // no list? whole source document
+ nEndPos = nBMSdPageCount;
+ }
+ else
+ {
+ // bookmark list? number of entries
+ nEndPos = rBookmarkList.size();
+ }
+
+ SdPage* pBMPage;
+
+ // iterate over number of pages to insert
+ for (nPos = 0; nPos < nEndPos; ++nPos)
+ {
+ // the master page associated to the nPos'th page to insert
+ SdPage* pBMMPage = nullptr;
+
+ if( rBookmarkList.empty() )
+ {
+ // simply take master page of nPos'th page in source document
+ pBMMPage = static_cast<SdPage*>(&(pBookmarkDoc->GetSdPage(static_cast<sal_uInt16>(nPos), PageKind::Standard)->TRG_GetMasterPage()));
+ }
+ else
+ {
+ // fetch nPos'th entry from bookmark list, and determine master page
+ OUString aBMPgName(rBookmarkList[nPos]);
+ bool bIsMasterPage;
+
+ sal_uInt16 nBMPage = pBookmarkDoc->GetPageByName( aBMPgName, bIsMasterPage );
+
+ if (nBMPage != SDRPAGE_NOTFOUND)
+ {
+ pBMPage = static_cast<SdPage*>( pBookmarkDoc->GetPage(nBMPage) );
+ }
+ else
+ {
+ pBMPage = nullptr;
+ }
+
+ // enforce that bookmarked page is a standard page and not already a master page
+ if (pBMPage && pBMPage->GetPageKind()==PageKind::Standard && !pBMPage->IsMasterPage())
+ {
+ const sal_uInt16 nBMSdPage = (nBMPage - 1) / 2;
+ pBMMPage = static_cast<SdPage*> (&(pBookmarkDoc->GetSdPage(nBMSdPage, PageKind::Standard)->TRG_GetMasterPage()));
+ }
+ }
+
+ // successfully determined valid (bookmarked) page?
+ if( pBMMPage )
+ {
+ // yes, call functor
+ rPageIterator( rDoc, pBMMPage, bRenameDuplicates, pBookmarkDoc );
+ }
+ }
+}
+
+// Opens a bookmark document
+SdDrawDocument* SdDrawDocument::OpenBookmarkDoc(SfxMedium* pMedium)
+{
+ bool bOK = true;
+ SdDrawDocument* pBookmarkDoc = nullptr;
+ OUString aBookmarkName = pMedium->GetName();
+ std::shared_ptr<const SfxFilter> pFilter = pMedium->GetFilter();
+ if ( !pFilter )
+ {
+ pMedium->UseInteractionHandler( true );
+ SfxGetpApp()->GetFilterMatcher().GuessFilter(*pMedium, pFilter);
+ }
+
+ if ( !pFilter )
+ {
+ bOK = false;
+ }
+ else if ( !aBookmarkName.isEmpty() && maBookmarkFile != aBookmarkName )
+ {
+ bool bCreateGraphicShell = pFilter->GetServiceName() == "com.sun.star.drawing.DrawingDocument";
+ bool bCreateImpressShell = pFilter->GetServiceName() == "com.sun.star.presentation.PresentationDocument";
+ if ( bCreateGraphicShell || bCreateImpressShell )
+ {
+ CloseBookmarkDoc();
+
+ // Create a DocShell, as OLE objects might be contained in the
+ // document. (Persist)
+ // If that wasn't the case, we could load the model directly.
+ if ( bCreateGraphicShell )
+ // Draw
+ mxBookmarkDocShRef = new ::sd::GraphicDocShell(SfxObjectCreateMode::STANDARD);
+ else
+ // Impress
+ mxBookmarkDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::STANDARD, true, DocumentType::Impress);
+
+ bOK = mxBookmarkDocShRef->DoLoad(pMedium);
+ if( bOK )
+ {
+ maBookmarkFile = aBookmarkName;
+ pBookmarkDoc = mxBookmarkDocShRef->GetDoc();
+ }
+ }
+ }
+
+ DBG_ASSERT(!aBookmarkName.isEmpty(), "Empty document name!");
+
+ if (!bOK)
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::Ok, SdResId(STR_READ_DATA_ERROR)));
+ xErrorBox->run();
+
+ CloseBookmarkDoc();
+ pBookmarkDoc = nullptr;
+ }
+ else if (mxBookmarkDocShRef.is())
+ {
+ pBookmarkDoc = mxBookmarkDocShRef->GetDoc();
+ }
+
+ return pBookmarkDoc;
+}
+
+// Opens a bookmark document
+SdDrawDocument* SdDrawDocument::OpenBookmarkDoc(const OUString& rBookmarkFile)
+{
+ SdDrawDocument* pBookmarkDoc = nullptr;
+
+ if (!rBookmarkFile.isEmpty() && maBookmarkFile != rBookmarkFile)
+ {
+ std::unique_ptr<SfxMedium> xMedium(new SfxMedium(rBookmarkFile, StreamMode::READ));
+ pBookmarkDoc = OpenBookmarkDoc(xMedium.release());
+ }
+ else if (mxBookmarkDocShRef.is())
+ {
+ pBookmarkDoc = mxBookmarkDocShRef->GetDoc();
+ }
+
+ return pBookmarkDoc;
+}
+
+// Inserts a bookmark (page or object)
+void SdDrawDocument::InsertBookmark(
+ const std::vector<OUString> &rBookmarkList, // List of names of the bookmarks to be inserted
+ std::vector<OUString> &rExchangeList, // List of the names to be used
+ bool bLink, // Insert bookmarks as links?
+ sal_uInt16 nInsertPos, // Insertion position of pages
+ ::sd::DrawDocShell* pBookmarkDocSh, // If set, this is the source document
+ Point const * pObjPos) // Insertion position of objects
+{
+ bool bOK = true;
+ bool bInsertPages = false;
+
+ if (rBookmarkList.empty())
+ {
+ // Insert all pages
+ bInsertPages = true;
+ }
+ else
+ {
+ SdDrawDocument* pBookmarkDoc = nullptr;
+
+ if (pBookmarkDocSh)
+ {
+ pBookmarkDoc = pBookmarkDocSh->GetDoc();
+ }
+ else if ( mxBookmarkDocShRef.is() )
+ {
+ pBookmarkDoc = mxBookmarkDocShRef->GetDoc();
+ }
+ else
+ bOK = false;
+
+ bInsertPages = bOK && std::any_of(rBookmarkList.begin(), rBookmarkList.end(),
+ [&pBookmarkDoc](const OUString& rBookmark) {
+ // Is there a page name in the bookmark list?
+ bool bIsMasterPage;
+ return pBookmarkDoc->GetPageByName(rBookmark, bIsMasterPage) != SDRPAGE_NOTFOUND;
+ });
+ }
+
+ bool bCalcObjCount = !rExchangeList.empty();
+
+ if ( bOK && bInsertPages )
+ {
+ // Insert all page bookmarks
+ bOK = InsertBookmarkAsPage(rBookmarkList, &rExchangeList, bLink, false/*bReplace*/,
+ nInsertPos, false/*bNoDialogs*/, pBookmarkDocSh, true/*bCopy*/, true, false);
+ }
+
+ if ( bOK && !rBookmarkList.empty() )
+ {
+ // Insert all object bookmarks
+ InsertBookmarkAsObject(rBookmarkList, rExchangeList,
+ pBookmarkDocSh, pObjPos, bCalcObjCount);
+ }
+}
+
+namespace
+{
+
+void
+lcl_removeUnusedStyles(SfxStyleSheetBasePool* const pStyleSheetPool, StyleSheetCopyResultVector& rStyles)
+{
+ StyleSheetCopyResultVector aUsedStyles;
+ aUsedStyles.reserve(rStyles.size());
+ for (const auto& a : rStyles)
+ {
+ if (a.m_xStyleSheet->IsUsed())
+ aUsedStyles.push_back(a);
+ else
+ pStyleSheetPool->Remove(a.m_xStyleSheet.get());
+ }
+ rStyles = aUsedStyles;
+}
+
+SfxStyleSheet *lcl_findStyle(StyleSheetCopyResultVector& rStyles, std::u16string_view aStyleName)
+{
+ for (const auto& a : rStyles)
+ {
+ if (a.m_xStyleSheet->GetName().startsWith(aStyleName))
+ return a.m_xStyleSheet.get();
+ }
+ return nullptr;
+}
+
+}
+
+bool SdDrawDocument::InsertBookmarkAsPage(
+ const std::vector<OUString> &rBookmarkList,
+ std::vector<OUString> *pExchangeList, // List of names to be used
+ bool bLink,
+ bool bReplace,
+ sal_uInt16 nInsertPos,
+ bool bNoDialogs,
+ ::sd::DrawDocShell* pBookmarkDocSh,
+ bool bCopy,
+ bool bMergeMasterPages,
+ bool bPreservePageNames)
+{
+ bool bContinue = true;
+ bool bScaleObjects = false;
+ sal_uInt16 nReplacedStandardPages = 0;
+
+ SdDrawDocument* pBookmarkDoc = nullptr;
+ OUString aBookmarkName;
+
+ if (pBookmarkDocSh)
+ {
+ pBookmarkDoc = pBookmarkDocSh->GetDoc();
+
+ if (pBookmarkDocSh->GetMedium())
+ {
+ aBookmarkName = pBookmarkDocSh->GetMedium()->GetName();
+ }
+ }
+ else if ( mxBookmarkDocShRef.is() )
+ {
+ pBookmarkDoc = mxBookmarkDocShRef->GetDoc();
+ aBookmarkName = maBookmarkFile;
+ }
+ else
+ {
+ return false;
+ }
+
+ const sal_uInt16 nSdPageCount = GetSdPageCount(PageKind::Standard);
+ const sal_uInt16 nBMSdPageCount = pBookmarkDoc->GetSdPageCount(PageKind::Standard);
+ const sal_uInt16 nMPageCount = GetMasterPageCount();
+
+ if (nSdPageCount==0 || nBMSdPageCount==0 || nMPageCount==0)
+ {
+ return false;
+ }
+
+ // Store the size and some other properties of the first page and notes
+ // page so that inserted pages can be properly scaled even when inserted
+ // before the first page.
+ // Note that the pointers are used later on as general page pointers.
+ SdPage* pRefPage = GetSdPage(0, PageKind::Standard);
+ Size aSize(pRefPage->GetSize());
+ sal_Int32 nLeft = pRefPage->GetLeftBorder();
+ sal_Int32 nRight = pRefPage->GetRightBorder();
+ sal_Int32 nUpper = pRefPage->GetUpperBorder();
+ sal_Int32 nLower = pRefPage->GetLowerBorder();
+ Orientation eOrient = pRefPage->GetOrientation();
+
+ SdPage* pNPage = GetSdPage(0, PageKind::Notes);
+ Size aNSize(pNPage->GetSize());
+ sal_Int32 nNLeft = pNPage->GetLeftBorder();
+ sal_Int32 nNRight = pNPage->GetRightBorder();
+ sal_Int32 nNUpper = pNPage->GetUpperBorder();
+ sal_Int32 nNLower = pNPage->GetLowerBorder();
+ Orientation eNOrient = pNPage->GetOrientation();
+
+ // Adapt page size and margins to those of the later pages?
+ pRefPage = GetSdPage(nSdPageCount - 1, PageKind::Standard);
+
+ if( bNoDialogs )
+ {
+ // If this is clipboard, then no need to scale objects:
+ // this will make copied masters to differ from the originals,
+ // and thus InsertBookmarkAsPage_FindDuplicateLayouts will
+ // duplicate masters on insert to same document
+ m_bTransportContainer = (SD_MOD()->pTransferClip &&
+ SD_MOD()->pTransferClip->GetWorkDocument() == this);
+ if (!m_bTransportContainer)
+ {
+ if (rBookmarkList.empty())
+ bScaleObjects = pRefPage->IsScaleObjects();
+ else
+ bScaleObjects = true;
+ }
+ }
+ else
+ {
+ SdPage* pBMPage = pBookmarkDoc->GetSdPage(0,PageKind::Standard);
+
+ if (pBMPage->GetSize() != pRefPage->GetSize() ||
+ pBMPage->GetLeftBorder() != pRefPage->GetLeftBorder() ||
+ pBMPage->GetRightBorder() != pRefPage->GetRightBorder() ||
+ pBMPage->GetUpperBorder() != pRefPage->GetUpperBorder() ||
+ pBMPage->GetLowerBorder() != pRefPage->GetLowerBorder())
+ {
+ OUString aStr(SdResId(STR_SCALE_OBJECTS));
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Question, VclButtonsType::YesNo,
+ aStr));
+ xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ sal_uInt16 nBut = xQueryBox->run();
+
+ bScaleObjects = nBut == RET_YES;
+ bContinue = nBut != RET_CANCEL;
+
+ if (!bContinue)
+ {
+ return bContinue;
+ }
+ }
+ }
+
+ // Get the necessary presentation stylesheets and transfer them before
+ // the pages, else, the text objects won't reference their styles anymore.
+ SfxUndoManager* pUndoMgr = nullptr;
+ if( mpDocSh )
+ {
+ pUndoMgr = mpDocSh->GetUndoManager();
+ ViewShellId nViewShellId(-1);
+ if (sd::ViewShell* pViewShell = mpDocSh->GetViewShell())
+ nViewShellId = pViewShell->GetViewShellBase().GetViewShellId();
+ pUndoMgr->EnterListAction(SdResId(STR_UNDO_INSERTPAGES), "", 0, nViewShellId);
+ }
+
+ // Refactored copy'n'pasted layout name collection into IterateBookmarkPages
+
+ std::vector<OUString> aLayoutsToTransfer;
+ InsertBookmarkAsPage_FindDuplicateLayouts aSearchFunctor( aLayoutsToTransfer );
+ lcl_IterateBookmarkPages( *this, pBookmarkDoc, rBookmarkList, nBMSdPageCount, aSearchFunctor, ( rBookmarkList.empty() && pBookmarkDoc != this ) );
+
+ // Copy the style that we actually need.
+ SdStyleSheetPool& rBookmarkStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*pBookmarkDoc->GetStyleSheetPool());
+ SdStyleSheetPool& rStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*GetStyleSheetPool());
+
+ // When copying styles, also copy the master pages!
+ if( !aLayoutsToTransfer.empty() )
+ bMergeMasterPages = true;
+
+ for ( const OUString& layoutName : aLayoutsToTransfer )
+ {
+ StyleSheetCopyResultVector aCreatedStyles;
+
+ rStyleSheetPool.CopyLayoutSheets(layoutName, rBookmarkStyleSheetPool,aCreatedStyles);
+
+ if(!aCreatedStyles.empty())
+ {
+ if( pUndoMgr )
+ {
+ pUndoMgr->AddUndoAction(std::make_unique<SdMoveStyleSheetsUndoAction>(this, aCreatedStyles, true));
+ }
+ }
+ }
+
+ // Copy styles. This unconditionally copies all styles, even those
+ // that are not used in any of the inserted pages. The unused styles
+ // are then removed at the end of the function, where we also create
+ // undo records for the inserted styles.
+ StyleSheetCopyResultVector aNewGraphicStyles;
+ OUString aRenameStr;
+ if(!bReplace && !bNoDialogs)
+ aRenameStr = "_";
+ rStyleSheetPool.RenameAndCopyGraphicSheets(rBookmarkStyleSheetPool, aNewGraphicStyles, aRenameStr);
+ StyleSheetCopyResultVector aNewCellStyles;
+ rStyleSheetPool.CopyCellSheets(rBookmarkStyleSheetPool, aNewCellStyles);
+
+ // TODO handle undo of table styles too
+ rStyleSheetPool.CopyTableStyles(rBookmarkStyleSheetPool);
+
+ // Insert document
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo(SdResId(STR_UNDO_INSERTPAGES));
+
+ if (rBookmarkList.empty())
+ {
+ if (nInsertPos >= GetPageCount())
+ {
+ // Add pages to the end
+ nInsertPos = GetPageCount();
+ }
+
+ sal_uInt16 nActualInsertPos = nInsertPos;
+
+ sal_uInt16 nBMSdPage;
+ std::set<sal_uInt16> aRenameSet;
+ std::map<sal_uInt16,OUString> aNameMap;
+
+ for (nBMSdPage=0; nBMSdPage < nBMSdPageCount; nBMSdPage++)
+ {
+ SdPage* pBMPage = pBookmarkDoc->GetSdPage(nBMSdPage, PageKind::Standard);
+ OUString sName(pBMPage->GetName());
+ bool bIsMasterPage;
+
+ if (bLink)
+ {
+ // Remember the names of all pages
+ aNameMap.insert(std::make_pair(nBMSdPage,sName));
+ }
+
+ // Have to check for duplicate names here, too
+ // don't change name if source and dest model are the same!
+ if( pBookmarkDoc != this &&
+ GetPageByName(sName, bIsMasterPage ) != SDRPAGE_NOTFOUND )
+ {
+ // delay renaming *after* pages are copied (might destroy source otherwise)
+ aRenameSet.insert(nBMSdPage);
+ }
+ }
+
+ Merge(*pBookmarkDoc,
+ 1, // Not the handout page
+ 0xFFFF, // But all others
+ nActualInsertPos, // Insert at position ...
+ bMergeMasterPages, // Move master pages?
+ false, // But only the master pages used
+ true, // Create an undo action
+ bCopy); // Copy (or merge) pages?
+
+ for (nBMSdPage=0; nBMSdPage < nBMSdPageCount; nBMSdPage++)
+ {
+ SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) );
+ SdPage* pNotesPage = static_cast<SdPage*>( GetPage(nActualInsertPos+1) );
+
+ // delay renaming *after* pages are copied (might destroy source otherwise)
+ if( aRenameSet.find(nBMSdPage) != aRenameSet.end() )
+ {
+ // Page name already in use -> Use default name for default and
+ // notes page
+ pPage->SetName(OUString());
+ pNotesPage->SetName(OUString());
+ }
+
+ if (bLink)
+ {
+ OUString aName(aNameMap[nBMSdPage]);
+
+ // Assemble all link names
+ pPage->SetFileName(aBookmarkName);
+ pPage->SetBookmarkName(aName);
+ }
+
+ nActualInsertPos += 2;
+ }
+ }
+ else
+ {
+ // Insert selected pages
+ SdPage* pBMPage;
+
+ if (nInsertPos >= GetPageCount())
+ {
+ // Add pages to the end
+ bReplace = false;
+ nInsertPos = GetPageCount();
+ }
+
+ sal_uInt16 nActualInsertPos = nInsertPos;
+
+ // Collect the bookmarked pages
+ ::std::vector<SdPage*> aBookmarkedPages (rBookmarkList.size(), nullptr);
+ for ( size_t nPos = 0, n = rBookmarkList.size(); nPos < n; ++nPos)
+ {
+ OUString aPgName(rBookmarkList[nPos]);
+ bool bIsMasterPage;
+ sal_uInt16 nBMPage = pBookmarkDoc->GetPageByName( aPgName, bIsMasterPage );
+
+ if (nBMPage != SDRPAGE_NOTFOUND)
+ {
+ aBookmarkedPages[nPos] = dynamic_cast<SdPage*>(pBookmarkDoc->GetPage(nBMPage));
+ }
+ }
+
+ for ( size_t nPos = 0, n = rBookmarkList.size(); nPos < n; ++nPos)
+ {
+ pBMPage = aBookmarkedPages[nPos];
+ sal_uInt16 nBMPage = pBMPage!=nullptr ? pBMPage->GetPageNum() : SDRPAGE_NOTFOUND;
+
+ if (pBMPage && pBMPage->GetPageKind()==PageKind::Standard && !pBMPage->IsMasterPage())
+ {
+ // It has to be a default page
+ bool bMustRename = false;
+
+ // delay renaming *after* pages are copied (might destroy source otherwise)
+ // don't change name if source and dest model are the same!
+ // avoid renaming if replacing the same page
+ OUString aPgName(rBookmarkList[nPos]);
+ bool bIsMasterPage;
+ sal_uInt16 nPageSameName = GetPageByName(aPgName, bIsMasterPage);
+ if( pBookmarkDoc != this &&
+ nPageSameName != SDRPAGE_NOTFOUND &&
+ ( !bReplace ||
+ nPageSameName != nActualInsertPos ) )
+ {
+ bMustRename = true;
+ }
+
+ SdPage* pBookmarkPage = pBMPage;
+ if (bReplace )
+ {
+ ReplacePageInCustomShows( dynamic_cast< SdPage* >( GetPage( nActualInsertPos ) ), pBookmarkPage );
+ }
+
+ Merge(*pBookmarkDoc,
+ nBMPage, // From page (default page)
+ nBMPage+1, // To page (notes page)
+ nActualInsertPos, // Insert at position
+ bMergeMasterPages, // Move master pages?
+ false, // But only the master pages used
+ true, // Create undo action
+ bCopy); // Copy (or merge) pages?
+
+ if( bReplace )
+ {
+ if( GetPage( nActualInsertPos ) != pBookmarkPage )
+ {
+ // bookmark page was not moved but cloned, so update custom shows again
+ ReplacePageInCustomShows( pBookmarkPage, dynamic_cast< SdPage* >( GetPage( nActualInsertPos ) ) );
+ }
+ }
+
+ if( bMustRename )
+ {
+ // Page name already in use -> use default name for default and
+ // notes page
+ SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) );
+ pPage->SetName(OUString());
+ SdPage* pNotesPage = static_cast<SdPage*>( GetPage(nActualInsertPos+1) );
+ pNotesPage->SetName(OUString());
+ }
+
+ if (bLink)
+ {
+ SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) );
+ pPage->SetFileName(aBookmarkName);
+ pPage->SetBookmarkName(aPgName);
+ }
+
+ if (bReplace)
+ {
+ // Remove page and notes page.
+ const sal_uInt16 nDestPageNum(nActualInsertPos + 2);
+ SdPage* pStandardPage = nullptr;
+
+ if(nDestPageNum < GetPageCount())
+ {
+ pStandardPage = static_cast<SdPage*>(GetPage(nDestPageNum));
+ }
+
+ if (pStandardPage)
+ {
+ if( bPreservePageNames )
+ {
+ // Take old slide names for inserted pages
+ SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) );
+ pPage->SetName( pStandardPage->GetRealName() );
+ }
+
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoDeletePage(*pStandardPage));
+
+ RemovePage(nDestPageNum);
+ }
+
+ SdPage* pNotesPage = nullptr;
+
+ if(nDestPageNum < GetPageCount())
+ {
+ pNotesPage = static_cast<SdPage*>(GetPage(nDestPageNum));
+ }
+
+ if (pNotesPage)
+ {
+ if( bPreservePageNames )
+ {
+ // Take old slide names for inserted pages
+ SdPage* pNewNotesPage = static_cast<SdPage*>( GetPage(nActualInsertPos+1));
+ if( pNewNotesPage )
+ pNewNotesPage->SetName( pStandardPage->GetRealName() );
+ }
+
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoDeletePage(*pNotesPage));
+
+ RemovePage(nDestPageNum);
+ }
+
+ nReplacedStandardPages++;
+ }
+
+ nActualInsertPos += 2;
+ }
+ }
+ }
+
+ // We might have duplicate master pages now, as the drawing engine does not
+ // recognize duplicates. Remove these now.
+ sal_uInt16 nNewMPageCount = GetMasterPageCount();
+
+ // Go backwards, so the numbers don't become messed up
+ for (sal_uInt16 nPage = nNewMPageCount - 1; nPage >= nMPageCount; nPage--)
+ {
+ pRefPage = static_cast<SdPage*>( GetMasterPage(nPage) );
+ OUString aMPLayout(pRefPage->GetLayoutName());
+ PageKind eKind = pRefPage->GetPageKind();
+
+ // Does this already exist?
+ for (sal_uInt16 nTest = 0; nTest < nMPageCount; nTest++)
+ {
+ SdPage* pTest = static_cast<SdPage*>( GetMasterPage(nTest) );
+ OUString aTest(pTest->GetLayoutName());
+
+ // nInsertPos > 2 is always true when inserting into non-empty models
+ if ( nInsertPos > 2 &&
+ aTest == aMPLayout &&
+ eKind == pTest->GetPageKind() )
+ {
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoDeletePage(*pRefPage));
+
+ RemoveMasterPage(nPage);
+
+ nNewMPageCount--;
+ break;
+ }
+ }
+ }
+
+ // nInsertPos > 2 is always true when inserting into non-empty models
+ if (nInsertPos > 0)
+ {
+ sal_uInt16 nSdPageStart = (nInsertPos - 1) / 2;
+ sal_uInt16 nSdPageEnd = bReplace
+ ? nSdPageStart + nReplacedStandardPages - 1
+ : GetSdPageCount(PageKind::Standard) - nSdPageCount + nSdPageStart - 1;
+ const bool bRemoveEmptyPresObj =
+ (pBookmarkDoc->GetDocumentType() == DocumentType::Impress) &&
+ (GetDocumentType() == DocumentType::Draw);
+
+ std::vector<OUString>::iterator pExchangeIter;
+
+ if (pExchangeList)
+ pExchangeIter = pExchangeList->begin();
+
+ for (sal_uInt16 nSdPage = nSdPageStart; nSdPage <= nSdPageEnd; nSdPage++)
+ {
+ pRefPage = GetSdPage(nSdPage, PageKind::Standard);
+
+ if (pExchangeList && pExchangeIter != pExchangeList->end())
+ {
+ // Get the name to use from Exchange list
+ OUString aExchangeName(*pExchangeIter);
+ pRefPage->SetName(aExchangeName);
+ Broadcast(SdrHint(SdrHintKind::PageOrderChange, pRefPage));
+
+ SdPage* pNewNotesPage = GetSdPage(nSdPage, PageKind::Notes);
+ pNewNotesPage->SetName(aExchangeName);
+ Broadcast(SdrHint(SdrHintKind::PageOrderChange, pNewNotesPage));
+
+ ++pExchangeIter;
+ }
+
+ OUString aLayout(pRefPage->GetLayoutName());
+ sal_Int32 nIndex = aLayout.indexOf( SD_LT_SEPARATOR );
+ if( nIndex != -1 )
+ aLayout = aLayout.copy(0, nIndex);
+
+ // update layout and referred master page
+ pRefPage->SetPresentationLayout(aLayout);
+ if( bUndo )
+ AddUndo( GetSdrUndoFactory().CreateUndoPageChangeMasterPage( *pRefPage ) );
+
+ if (bScaleObjects)
+ {
+ ::tools::Rectangle aBorderRect(nLeft, nUpper, nRight, nLower);
+ pRefPage->ScaleObjects(aSize, aBorderRect, true);
+ }
+ pRefPage->SetSize(aSize);
+ pRefPage->SetBorder(nLeft, nUpper, nRight, nLower);
+ pRefPage->SetOrientation( eOrient );
+
+ if( bRemoveEmptyPresObj )
+ pRefPage->RemoveEmptyPresentationObjects();
+
+ pRefPage = GetSdPage(nSdPage, PageKind::Notes);
+
+ // update layout and referred master page
+ pRefPage->SetPresentationLayout(aLayout);
+ if( bUndo )
+ AddUndo( GetSdrUndoFactory().CreateUndoPageChangeMasterPage( *pRefPage ) );
+
+ if (bScaleObjects)
+ {
+ ::tools::Rectangle aBorderRect(nNLeft, nNUpper, nNRight, nNLower);
+ pRefPage->ScaleObjects(aNSize, aBorderRect, true);
+ }
+
+ pRefPage->SetSize(aNSize);
+ pRefPage->SetBorder(nNLeft, nNUpper, nNRight, nNLower);
+ pRefPage->SetOrientation( eNOrient );
+
+ if( bRemoveEmptyPresObj )
+ pRefPage->RemoveEmptyPresentationObjects();
+ }
+
+ ///Remove processed elements, to avoid doing hacks in InsertBookmarkAsObject
+ if ( pExchangeList )
+ pExchangeList->erase(pExchangeList->begin(),pExchangeIter);
+
+ for (sal_uInt16 nPage = nMPageCount; nPage < nNewMPageCount; nPage++)
+ {
+ pRefPage = static_cast<SdPage*>( GetMasterPage(nPage) );
+ if (pRefPage->GetPageKind() == PageKind::Standard)
+ {
+ if (bScaleObjects)
+ {
+ ::tools::Rectangle aBorderRect(nLeft, nUpper, nRight, nLower);
+ pRefPage->ScaleObjects(aSize, aBorderRect, true);
+ }
+ pRefPage->SetSize(aSize);
+ pRefPage->SetBorder(nLeft, nUpper, nRight, nLower);
+ pRefPage->SetOrientation( eOrient );
+ }
+ else // Can only be notes
+ {
+ if (bScaleObjects)
+ {
+ ::tools::Rectangle aBorderRect(nNLeft, nNUpper, nNRight, nNLower);
+ pRefPage->ScaleObjects(aNSize, aBorderRect, true);
+ }
+ pRefPage->SetSize(aNSize);
+ pRefPage->SetBorder(nNLeft, nNUpper, nNRight, nNLower);
+ pRefPage->SetOrientation( eNOrient );
+ }
+
+ if( bRemoveEmptyPresObj )
+ pRefPage->RemoveEmptyPresentationObjects();
+ }
+ }
+
+ // Make absolutely sure no double masterpages are there
+ RemoveUnnecessaryMasterPages(nullptr, true);
+
+ // Rename object styles if necessary
+ if(!aRenameStr.isEmpty())
+ {
+ try
+ {
+ for(sal_uInt32 p = nInsertPos; p < sal_uInt32(nInsertPos) + sal_uInt32(nBMSdPageCount); p++)
+ {
+ SdPage *pPg = static_cast<SdPage *>( GetPage(p) );
+ for(size_t i = 0; pPg && (i < pPg->GetObjCount()); ++i)
+ {
+ if(pPg->GetObj(i)->GetStyleSheet())
+ {
+ OUString aStyleName = pPg->GetObj(i)->GetStyleSheet()->GetName();
+ SfxStyleSheet *pSheet = lcl_findStyle(aNewGraphicStyles, OUStringConcatenation(aStyleName + aRenameStr));
+ if(pSheet != nullptr)
+ pPg->GetObj(i)->SetStyleSheet(pSheet, true);
+ }
+ }
+ }
+ }
+ catch(...)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "Exception while renaming styles @ SdDrawDocument::InsertBookmarkAsPage");
+ }
+ }
+ // remove copied styles not used on any inserted page and create
+ // undo records
+ // WARNING: SdMoveStyleSheetsUndoAction clears the passed list of
+ // styles, so it cannot be used after this point
+ lcl_removeUnusedStyles(GetStyleSheetPool(), aNewGraphicStyles);
+ if (!aNewGraphicStyles.empty() && pUndoMgr)
+ pUndoMgr->AddUndoAction(std::make_unique<SdMoveStyleSheetsUndoAction>(this, aNewGraphicStyles, true));
+ lcl_removeUnusedStyles(GetStyleSheetPool(), aNewCellStyles);
+ if (!aNewCellStyles.empty() && pUndoMgr)
+ pUndoMgr->AddUndoAction(std::make_unique<SdMoveStyleSheetsUndoAction>(this, aNewCellStyles, true));
+
+ if( bUndo )
+ EndUndo();
+
+ if (pUndoMgr)
+ pUndoMgr->LeaveListAction();
+
+ return bContinue;
+}
+
+// Inserts a bookmark as an object
+bool SdDrawDocument::InsertBookmarkAsObject(
+ const std::vector<OUString> &rBookmarkList,
+ const std::vector<OUString> &rExchangeList, // List of names to use
+ ::sd::DrawDocShell* pBookmarkDocSh,
+ Point const * pObjPos,
+ bool bCalcObjCount)
+{
+ bool bOK = true;
+ bool bOLEObjFound = false;
+ std::unique_ptr<::sd::View> pBMView;
+
+ SdDrawDocument* pBookmarkDoc = nullptr;
+
+ if (pBookmarkDocSh)
+ {
+ pBookmarkDoc = pBookmarkDocSh->GetDoc();
+ }
+ else if ( mxBookmarkDocShRef.is() )
+ {
+ pBookmarkDoc = mxBookmarkDocShRef->GetDoc();
+ }
+ else
+ {
+ return false;
+ }
+
+ if (rBookmarkList.empty())
+ {
+ pBMView.reset(new ::sd::View(*pBookmarkDoc, nullptr));
+ pBMView->EndListening(*pBookmarkDoc);
+ pBMView->MarkAll();
+ }
+ else
+ {
+ SdrPage* pPage;
+ SdrPageView* pPV;
+
+ for ( const auto& rBookmark : rBookmarkList )
+ {
+ // Get names of bookmarks from the list
+ SdrObject* pObj = pBookmarkDoc->GetObj(rBookmark);
+
+ if (pObj)
+ {
+ // Found an object
+ if (pObj->GetObjInventor() == SdrInventor::Default &&
+ pObj->GetObjIdentifier() == SdrObjKind::OLE2)
+ {
+ bOLEObjFound = true;
+ }
+
+ if (!pBMView)
+ {
+ // Create View for the first time
+ pBMView.reset(new ::sd::View(*pBookmarkDoc, nullptr));
+ pBMView->EndListening(*pBookmarkDoc);
+ }
+
+ pPage = pObj->getSdrPageFromSdrObject();
+
+ if (pPage->IsMasterPage())
+ {
+ pPV = pBMView->ShowSdrPage(pBMView->GetModel()->GetMasterPage(pPage->GetPageNum()));
+ }
+ else
+ {
+ pPV = pBMView->GetSdrPageView();
+ if( !pPV || (pPV->GetPage() != pPage))
+ pPV = pBMView->ShowSdrPage(pPage);
+ }
+
+ pBMView->MarkObj(pObj, pPV);
+ }
+ }
+ }
+
+ if (pBMView)
+ {
+ // Insert selected objects
+ std::optional<::sd::View> pView(std::in_place, *this, nullptr);
+ pView->EndListening(*this);
+
+ // Look for the page into which the objects are supposed to be inserted
+ SdrPage* pPage = GetSdPage(0, PageKind::Standard);
+
+ if (mpDocSh)
+ {
+ ::sd::ViewShell* pViewSh = mpDocSh->GetViewShell();
+
+ if (pViewSh)
+ {
+ // Which page is currently in view?
+ SdrPageView* pPV = pViewSh->GetView()->GetSdrPageView();
+
+ if (pPV)
+ {
+ pPage = pPV->GetPage();
+ }
+ else if (pViewSh->GetActualPage())
+ {
+ pPage = pViewSh->GetActualPage();
+ }
+ }
+ }
+
+ Point aObjPos;
+
+ if (pObjPos)
+ {
+ aObjPos = *pObjPos;
+ }
+ else
+ {
+ aObjPos = ::tools::Rectangle(Point(), pPage->GetSize()).Center();
+ }
+
+ size_t nCountBefore = 0;
+
+ if (!rExchangeList.empty() || bCalcObjCount)
+ {
+ // Sort OrdNums and get the number of objects before inserting
+ pPage->RecalcObjOrdNums();
+ nCountBefore = pPage->GetObjCount();
+ }
+
+ if (bOLEObjFound)
+ pBMView->GetDoc().SetAllocDocSh(true);
+
+ SdDrawDocument* pTmpDoc = static_cast<SdDrawDocument*>( pBMView->CreateMarkedObjModel().release() );
+ bOK = pView->Paste(*pTmpDoc, aObjPos, pPage, SdrInsertFlags::NONE);
+
+ if (bOLEObjFound)
+ pBMView->GetDoc().SetAllocDocSh(false);
+
+ if (!bOLEObjFound)
+ delete pTmpDoc; // Would otherwise be destroyed by DocShell
+
+ pView.reset();
+
+ // Get number of objects after inserting.
+ const size_t nCount = pPage->GetObjCount();
+ if (nCountBefore < nCount)
+ {
+ size_t nObj = nCountBefore;
+ for (const auto& rExchange : rExchangeList)
+ {
+ // Get the name to use from the Exchange list
+ if (pPage->GetObj(nObj))
+ {
+ pPage->GetObj(nObj)->SetName(rExchange);
+ }
+
+ ++nObj;
+ if (nObj >= nCount)
+ break;
+ }
+ }
+ }
+
+ return bOK;
+}
+
+// Stops the bookmark insertion
+void SdDrawDocument::CloseBookmarkDoc()
+{
+ if (mxBookmarkDocShRef.is())
+ {
+ mxBookmarkDocShRef->DoClose();
+ }
+
+ mxBookmarkDocShRef.clear();
+ maBookmarkFile.clear();
+}
+
+// Is this document read-only?
+bool SdDrawDocument::IsReadOnly() const
+{
+ return false;
+}
+
+// In the subsequent AllocModel() a DocShell (xAllocedDocShRef) is created.
+// Any pre-existing DocShell is deleted
+void SdDrawDocument::SetAllocDocSh(bool bAlloc)
+{
+ mbAllocDocSh = bAlloc;
+
+ if(mxAllocedDocShRef.is())
+ {
+ mxAllocedDocShRef->DoClose();
+ }
+
+ mxAllocedDocShRef.clear();
+}
+
+// Return list of CustomShows (create it, too, if necessary)
+SdCustomShowList* SdDrawDocument::GetCustomShowList(bool bCreate)
+{
+ if (!mpCustomShowList && bCreate)
+ {
+ mpCustomShowList.reset(new SdCustomShowList);
+ }
+
+ return mpCustomShowList.get();
+}
+
+// Remove unused master pages and layouts
+void SdDrawDocument::RemoveUnnecessaryMasterPages(SdPage* pMasterPage, bool bOnlyDuplicatePages, bool bUndo)
+{
+ ::sd::View* pView = nullptr;
+ SfxUndoManager* pUndoMgr = nullptr;
+
+ if( bUndo && !IsUndoEnabled() )
+ bUndo = false;
+
+ if (mpDocSh)
+ {
+ pUndoMgr = mpDocSh->GetUndoManager();
+
+ if (mpDocSh->GetViewShell())
+ pView = mpDocSh->GetViewShell()->GetView();
+ }
+
+ // Check all master pages
+ sal_uInt16 nSdMasterPageCount = GetMasterSdPageCount( PageKind::Standard );
+ for (sal_Int32 nMPage = nSdMasterPageCount - 1; nMPage >= 0; nMPage--)
+ {
+ SdPage* pMaster = pMasterPage;
+ SdPage* pNotesMaster = nullptr;
+
+ if (!pMaster)
+ {
+ pMaster = GetMasterSdPage( static_cast<sal_uInt16>(nMPage), PageKind::Standard );
+ pNotesMaster = GetMasterSdPage( static_cast<sal_uInt16>(nMPage), PageKind::Notes );
+ }
+ else
+ {
+ for ( sal_uInt16 nMPg = 0; nMPg < GetMasterPageCount(); nMPg++ )
+ {
+ if ( pMaster == GetMasterPage( nMPg ) )
+ {
+ pNotesMaster = static_cast<SdPage*>( GetMasterPage( ++nMPg ) );
+ break;
+ }
+ }
+ }
+
+ DBG_ASSERT( pMaster->GetPageKind() == PageKind::Standard, "wrong page kind" );
+
+ if ( pMaster->GetPageKind() == PageKind::Standard &&
+ GetMasterPageUserCount( pMaster ) == 0 &&
+ pNotesMaster )
+ {
+ // Do not delete master pages that have their precious flag set
+ bool bDeleteMaster = !pMaster->IsPrecious();
+ OUString aLayoutName = pMaster->GetLayoutName();
+
+ if(bOnlyDuplicatePages )
+ {
+ // remove only duplicate pages
+ bDeleteMaster = false;
+ for (sal_uInt16 i = 0; i < GetMasterSdPageCount( PageKind::Standard ); i++)
+ {
+ SdPage* pMPg = GetMasterSdPage( i, PageKind::Standard );
+ if( pMPg != pMaster &&
+ pMPg->GetLayoutName() == aLayoutName )
+ {
+ // duplicate page found -> remove it
+ bDeleteMaster = true;
+ }
+ }
+ }
+
+ if( bDeleteMaster )
+ {
+ if (pView)
+ {
+ // if MasterPage is visible hide on pageview
+ SdrPageView* pPgView = pView->GetSdrPageView();
+ if (pPgView)
+ {
+ SdrPage* pShownPage = pPgView->GetPage();
+ if( (pShownPage == pMaster) || (pShownPage == pNotesMaster) )
+ {
+ pView->HideSdrPage();
+ pView->ShowSdrPage( GetSdPage( 0, PageKind::Standard ) );
+ }
+ }
+ }
+
+ if( bUndo )
+ {
+ BegUndo();
+ AddUndo( GetSdrUndoFactory().CreateUndoDeletePage( *pNotesMaster ) );
+ }
+
+ RemoveMasterPage( pNotesMaster->GetPageNum() );
+
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoDeletePage(*pMaster));
+
+ RemoveMasterPage( pMaster->GetPageNum() );
+
+ if( bUndo )
+ EndUndo(); // do this here already, so Joe's actions happen _between_ our own
+
+ // Delete old, unused layout stylesheets
+ bool bDeleteOldStyleSheets = true;
+ for ( sal_uInt16 nMPg = 0;
+ nMPg < GetMasterPageCount() && bDeleteOldStyleSheets;
+ nMPg++ )
+ {
+ SdPage* pMPg = static_cast<SdPage*>( GetMasterPage(nMPg) );
+ if (pMPg->GetLayoutName() == aLayoutName)
+ {
+ bDeleteOldStyleSheets = false;
+ }
+ }
+
+ if (bDeleteOldStyleSheets)
+ {
+ SdStyleSheetVector aRemove;
+ static_cast<SdStyleSheetPool*>( mxStyleSheetPool.get())->CreateLayoutSheetList( aLayoutName, aRemove );
+
+ if( bUndo )
+ {
+ StyleSheetCopyResultVector aUndoRemove;
+ aUndoRemove.reserve(aRemove.size());
+ for (const auto& a : aRemove)
+ aUndoRemove.emplace_back(a.get(), true);
+
+ if (pUndoMgr)
+ pUndoMgr->AddUndoAction(std::make_unique<SdMoveStyleSheetsUndoAction>(this, aUndoRemove, false));
+ }
+
+ for( const auto& a : aRemove )
+ static_cast<SdStyleSheetPool*>( mxStyleSheetPool.get())->Remove(a.get());
+ }
+ }
+ }
+
+ if (pMasterPage)
+ break; // Just this one master page!
+ }
+}
+
+/** Exchange master page
+ *
+ * Either the nSdPageNum gets a new, own master page or the master page is
+ * exchanged completely (which then applies to all pages).
+ *
+ * nSdPageNum : page number that the new master page should get.
+ * rLayoutName : LayoutName of the new master page
+ * pSourceDoc : document (template) to get the master page from
+ * bMaster : exchange the master page of nSdPageNum
+ * bCheckMasters: remove unused master pages
+ *
+ * If pSourceDoc == NULL, an empty master page is applied.
+ * If rLayoutName is empty, the first master page is used.
+ */
+// #i121863# factored out functionality
+static bool isMasterPageLayoutNameUnique(const SdDrawDocument& rDoc, std::u16string_view rCandidate)
+{
+ if (rCandidate.empty())
+ {
+ return false;
+ }
+
+ const sal_uInt16 nPageCount(rDoc.GetMasterPageCount());
+
+ for(sal_uInt16 a(0); a < nPageCount; a++)
+ {
+ const SdrPage* pCandidate = rDoc.GetMasterPage(a);
+ OUString aPageLayoutName(pCandidate->GetLayoutName());
+ sal_Int32 nIndex = aPageLayoutName.indexOf(SD_LT_SEPARATOR);
+ if( nIndex != -1 )
+ aPageLayoutName = aPageLayoutName.copy(0, nIndex);
+
+ if(aPageLayoutName == rCandidate)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// #i121863# factored out functionality
+static OUString createNewMasterPageLayoutName(const SdDrawDocument& rDoc)
+{
+ const OUString aBaseName(SdResId(STR_LAYOUT_DEFAULT_NAME));
+ sal_uInt16 nCount(0);
+ for (;;)
+ {
+ OUString aRetval = aBaseName;
+ if(nCount)
+ {
+ aRetval += OUString::number(nCount);
+ }
+ if (isMasterPageLayoutNameUnique(rDoc, aRetval))
+ return aRetval;
+ nCount++;
+ }
+}
+
+void SdDrawDocument::SetMasterPage(sal_uInt16 nSdPageNum,
+ std::u16string_view rLayoutName,
+ SdDrawDocument* pSourceDoc,
+ bool bMaster,
+ bool bCheckMasters)
+{
+ SfxUndoManager* pUndoMgr = nullptr;
+
+ if( mpDocSh )
+ {
+ mpDocSh->SetWaitCursor( true );
+ pUndoMgr = mpDocSh->GetUndoManager();
+ }
+
+ const bool bUndo = pUndoMgr && IsUndoEnabled();
+
+ if (bUndo)
+ {
+ ViewShellId nViewShellId(-1);
+ if (sd::ViewShell* pViewShell = mpDocSh->GetViewShell())
+ nViewShellId = pViewShell->GetViewShellBase().GetViewShellId();
+ pUndoMgr->EnterListAction(SdResId(STR_UNDO_SET_PRESLAYOUT), OUString(), 0, nViewShellId);
+ }
+
+ SdPage* pSelectedPage = GetSdPage(nSdPageNum, PageKind::Standard);
+ SdPage* pNotes = static_cast<SdPage*>( GetPage(pSelectedPage->GetPageNum()+1) );
+ SdPage& rOldMaster = static_cast<SdPage&>(pSelectedPage->TRG_GetMasterPage());
+ SdPage& rOldNotesMaster = static_cast<SdPage&>(pNotes->TRG_GetMasterPage());
+ rtl::Reference<SdPage> pMaster;
+ rtl::Reference<SdPage> pNotesMaster;
+ OUString aOldPageLayoutName(pSelectedPage->GetLayoutName());
+ OUString aOldLayoutName(aOldPageLayoutName);
+ sal_Int32 nIndex = aOldLayoutName.indexOf( SD_LT_SEPARATOR );
+ if( nIndex != -1 )
+ aOldLayoutName = aOldLayoutName.copy(0, nIndex);
+
+ if (pSourceDoc)
+ {
+ std::vector<StyleReplaceData> aReplList; // List of replaced stylesheets
+ bool bLayoutReloaded = false; // Was ex. layout reloaded?
+
+ // LayoutName, Page and Notes page
+ if (rLayoutName.empty())
+ {
+ // No LayoutName: take first MasterPage
+ pMaster = pSourceDoc->GetMasterSdPage(0, PageKind::Standard);
+ pNotesMaster = pSourceDoc->GetMasterSdPage(0, PageKind::Notes);
+ }
+ else
+ {
+ OUString aSearchFor
+ = OUString::Concat(rLayoutName) + SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE;
+
+ for (sal_uInt16 nMP = 0; nMP < pSourceDoc->GetMasterPageCount(); ++nMP)
+ {
+ SdPage* pMP = static_cast<SdPage*>( pSourceDoc->GetMasterPage(nMP) );
+
+ if (pMP->GetLayoutName() == aSearchFor)
+ {
+ if (pMP->GetPageKind() == PageKind::Standard)
+ pMaster = pMP;
+ if (pMP->GetPageKind() == PageKind::Notes)
+ pNotesMaster = pMP;
+ }
+ if (pMaster && pNotesMaster)
+ break;
+ }
+ DBG_ASSERT(pMaster, "MasterPage (Standard page) not found");
+ DBG_ASSERT(pNotesMaster, "MasterPage (Notes page) not found");
+
+ // this should not happen, but looking at crash reports, it does
+ if( (pMaster == nullptr) || (pNotesMaster == nullptr) )
+ {
+ // so take the first MasterPage
+ pMaster = pSourceDoc->GetMasterSdPage(0, PageKind::Standard);
+ pNotesMaster = pSourceDoc->GetMasterSdPage(0, PageKind::Notes);
+ }
+ }
+
+ // we should never reach this, but one never knows...
+ if( (pMaster == nullptr) || (pNotesMaster == nullptr) )
+ {
+ if (bUndo)
+ pUndoMgr->LeaveListAction();
+
+ if( mpDocSh )
+ mpDocSh->SetWaitCursor( false );
+
+ OSL_FAIL( "SdDrawDocument::SetMasterPage() failed!" );
+
+ return;
+ }
+
+ const OUString aOriginalNewLayoutName( pMaster->GetName() );
+ OUString aTargetNewLayoutName(aOriginalNewLayoutName);
+
+ if (pSourceDoc != this)
+ {
+ // #i121863# clone masterpages, they are from another model (!)
+ rtl::Reference<SdPage> pNewNotesMaster(dynamic_cast< SdPage* >(pNotesMaster->CloneSdrPage(*this).get()));
+ rtl::Reference<SdPage> pNewMaster(dynamic_cast< SdPage* >(pMaster->CloneSdrPage(*this).get()));
+
+ if(!pNewNotesMaster || !pNewMaster)
+ {
+ OSL_FAIL("SdDrawDocument::SetMasterPage() cloning of MasterPage/NoteAmsterPage failed!" );
+ return;
+ }
+
+ pNotesMaster = pNewNotesMaster;
+ pMaster = pNewMaster;
+
+ // layout name needs to be unique
+ aTargetNewLayoutName = pMaster->GetLayoutName();
+ sal_Int32 nIndex2 = aTargetNewLayoutName.indexOf(SD_LT_SEPARATOR);
+ if( nIndex2 != -1 )
+ aTargetNewLayoutName = aTargetNewLayoutName.copy(0, nIndex2);
+
+ if(!isMasterPageLayoutNameUnique(*this, aTargetNewLayoutName))
+ {
+ aTargetNewLayoutName = createNewMasterPageLayoutName(*this);
+
+ OUString aTemp = aTargetNewLayoutName + SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE;
+
+ pMaster->SetName(aTargetNewLayoutName);
+ pMaster->SetLayoutName(aTemp);
+
+ pNotesMaster->SetName(aTargetNewLayoutName);
+ pNotesMaster->SetLayoutName(aTemp);
+ }
+ }
+
+ if (pSourceDoc != this)
+ {
+ const sal_uInt16 nMasterPageCount = GetMasterPageCount();
+ for ( sal_uInt16 nMPage = 0; nMPage < nMasterPageCount; nMPage++ )
+ {
+ SdPage* pCheckMaster = static_cast<SdPage*>(GetMasterPage(nMPage));
+ if( pCheckMaster->GetName() == aTargetNewLayoutName )
+ {
+ bLayoutReloaded = true;
+ break;
+ }
+ }
+
+ // Correct or create presentation templates --
+ // only worry about presentation templates
+ OUString aName;
+ SdStyleSheetPool* pSourceStyleSheetPool = static_cast<SdStyleSheetPool*>( pSourceDoc->GetStyleSheetPool() );
+
+ StyleSheetCopyResultVector aCreatedStyles; // List of created stylesheets
+ SfxStyleSheetBase* pHisSheet = pSourceStyleSheetPool->First(SfxStyleFamily::Page);
+
+ while (pHisSheet)
+ {
+ aName = pHisSheet->GetName();
+
+ // #i121863# search in source styles with original style name from source of
+ // evtl. cloned master (not-cloned, renamed for uniqueness)
+ if( aName.startsWith( aOriginalNewLayoutName ) )
+ {
+ // #i121863# build name of evtl. cloned master style to search for
+ if(aOriginalNewLayoutName != aTargetNewLayoutName)
+ {
+ const sal_Int32 nPos(aName.indexOf(SD_LT_SEPARATOR));
+ aName = aTargetNewLayoutName + aName.subView(nPos);
+ }
+
+ SfxStyleSheet* pMySheet = static_cast<SfxStyleSheet*>( mxStyleSheetPool->Find(aName, SfxStyleFamily::Page) );
+
+ if (pMySheet)
+ {
+ // A stylesheet of the same name already exists -> overwrite contents
+ bool bTest = pMySheet->SetName(pHisSheet->GetName());
+ DBG_ASSERT(bTest, "Renaming StyleSheet failed.");
+ pMySheet->GetItemSet().ClearItem(); // Delete all
+
+ if (bUndo)
+ {
+ pUndoMgr->AddUndoAction(std::make_unique<StyleSheetUndoAction>(this,
+ pMySheet, &pHisSheet->GetItemSet()));
+ }
+ pMySheet->GetItemSet().Put(pHisSheet->GetItemSet());
+ pMySheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ }
+ else
+ {
+ // create new style
+ OUString aHelpFile;
+ pMySheet = static_cast<SfxStyleSheet*>( &mxStyleSheetPool->Make(aName, SfxStyleFamily::Page, pHisSheet->GetMask()) );
+ pMySheet->SetHelpId( aHelpFile, pHisSheet->GetHelpId(aHelpFile) );
+ pMySheet->GetItemSet().ClearItem(); // Delete all
+ pMySheet->GetItemSet().Put(pHisSheet->GetItemSet());
+
+ aCreatedStyles.emplace_back(static_cast<SdStyleSheet*>(pMySheet), true);
+ }
+
+ StyleReplaceData aReplData;
+ aReplData.nNewFamily = pMySheet->GetFamily();
+ aReplData.nFamily = pMySheet->GetFamily();
+ aReplData.aNewName = pMySheet->GetName();
+
+ // #i121863# re-create original name of style used at page where to replace with
+ // this new style
+ OUString aTemp(pMySheet->GetName());
+ const sal_Int32 nPos(aTemp.indexOf(SD_LT_SEPARATOR));
+ aTemp = aOldLayoutName + aTemp.subView(nPos);
+ aReplData.aName = aTemp;
+ aReplList.push_back(aReplData);
+ }
+
+ pHisSheet = pSourceStyleSheetPool->Next();
+ }
+
+ // If new styles were created: re-create parent chaining of the item
+ // sets in the styles.
+ if(!aCreatedStyles.empty())
+ {
+ for ( const auto& rRData : aReplList )
+ {
+ SfxStyleSheetBase* pSOld = mxStyleSheetPool->Find(rRData.aName, SfxStyleFamily::Page);
+ SfxStyleSheetBase* pSNew = mxStyleSheetPool->Find(rRData.aNewName, SfxStyleFamily::Page);
+
+ if (pSOld && pSNew)
+ {
+ const OUString& rParentOfOld = pSOld->GetParent();
+ const OUString& rParentOfNew = pSNew->GetParent();
+
+ if (!rParentOfOld.isEmpty() && rParentOfNew.isEmpty())
+ {
+ std::vector<StyleReplaceData>::iterator pRDIter = std::find_if(aReplList.begin(), aReplList.end(),
+ [&rParentOfOld](const StyleReplaceData& rRD) { return (rRD.aName == rParentOfOld) && (rRD.aName != rRD.aNewName); });
+ if (pRDIter != aReplList.end())
+ {
+ OUString aParentOfNew(pRDIter->aNewName);
+ pSNew->SetParent(aParentOfNew);
+ }
+ }
+ }
+ }
+ }
+
+ if (bUndo && !aCreatedStyles.empty())
+ {
+ // Add UndoAction for creating and inserting the stylesheets to
+ // the top of the UndoManager
+ pUndoMgr->AddUndoAction(std::make_unique<SdMoveStyleSheetsUndoAction>( this, aCreatedStyles, true));
+ }
+ }
+
+ // Create layout name based upon the name of the page layout of the
+ // master page
+ OUString aPageLayoutName(pMaster->GetLayoutName());
+ OUString aLayoutName = aPageLayoutName;
+ sal_Int32 nIndex2 = aLayoutName.indexOf( SD_LT_SEPARATOR );
+ if( nIndex2 != -1 )
+ aLayoutName = aLayoutName.copy( 0, nIndex2);
+
+ // #i121863# Do *not* remove from original document any longer, it is potentially used there
+ // and would lead to crashes. Rely on the automatic process of removing unused masterpages
+ // (see RemoveUnnecessaryMasterPages)
+ //if (pSourceDoc != this)
+ //{
+ // // Remove from the source document
+ // pSourceDoc->RemoveMasterPage(pNotesMaster->GetPageNum());
+ // pSourceDoc->RemoveMasterPage(pMaster->GetPageNum());
+ //}
+
+ // Register the new master pages with the document and then use
+ // the new presentation layout for the default and notes pages
+ if (pSourceDoc != this)
+ {
+ // Insert the master pages:
+ // Insert master pages from new layouts at the end.
+ // If a layout is being replaced, however, insert them before the
+ // position of the old master page, so from now on the new master
+ // page will be found when searching (e.g.
+ // SdPage::SetPresentationLayout).
+ sal_uInt16 nInsertPos = rOldMaster.GetPageNum();
+ BegUndo();
+
+ if (!bLayoutReloaded)
+ nInsertPos = 0xFFFF;
+ InsertMasterPage(pMaster.get(), nInsertPos);
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pMaster));
+
+ nInsertPos++;
+ if (!bLayoutReloaded)
+ nInsertPos = 0xFFFF;
+ InsertMasterPage(pNotesMaster.get(), nInsertPos);
+ if( bUndo )
+ {
+ AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pNotesMaster));
+
+ EndUndo(); // do this here already, so Joe's actions happen _between_ our own.
+ }
+ }
+
+ // Fill list with pages
+ std::vector<rtl::Reference<SdPage>> aPageList;
+
+// #98456, this has to be removed according to CL (KA 07/08/2002)
+// #109884# but we need them again to restore the styles of the presentation objects while undo
+ aPageList.push_back(pMaster);
+ aPageList.push_back(pNotesMaster);
+
+ if (bMaster || bLayoutReloaded)
+ {
+ for (sal_uInt16 nPage = 1; nPage < GetPageCount(); nPage++)
+ {
+ SdPage* pPage = static_cast<SdPage*>( GetPage(nPage) );
+ OUString aTest = pPage->GetLayoutName();
+ if (aTest == aOldPageLayoutName)
+ {
+ aPageList.push_back(pPage);
+ }
+ }
+
+ }
+ else
+ {
+ aPageList.push_back(pSelectedPage);
+ aPageList.push_back(pNotes);
+ }
+
+ for (rtl::Reference<SdPage>& pPage : aPageList)
+ {
+ AutoLayout eAutoLayout = pPage->GetAutoLayout();
+
+ if( bUndo )
+ {
+ pUndoMgr->AddUndoAction(std::make_unique<SdPresentationLayoutUndoAction>
+ (this,
+ pPage->IsMasterPage() ? aLayoutName : aOldLayoutName,
+ aLayoutName,
+ eAutoLayout, eAutoLayout, false, pPage.get()));
+ }
+ pPage->SetPresentationLayout(aLayoutName);
+ pPage->SetAutoLayout(eAutoLayout);
+ }
+
+ // Adapt new master pages
+ if (pSourceDoc != this)
+ {
+ Size aSize(rOldMaster.GetSize());
+ ::tools::Rectangle aBorderRect(rOldMaster.GetLeftBorder(),
+ rOldMaster.GetUpperBorder(),
+ rOldMaster.GetRightBorder(),
+ rOldMaster.GetLowerBorder());
+ pMaster->ScaleObjects(aSize, aBorderRect, true);
+ pMaster->SetSize(aSize);
+ pMaster->SetBorder(rOldMaster.GetLeftBorder(),
+ rOldMaster.GetUpperBorder(),
+ rOldMaster.GetRightBorder(),
+ rOldMaster.GetLowerBorder());
+ pMaster->SetOrientation( rOldMaster.GetOrientation() );
+ pMaster->SetAutoLayout(pMaster->GetAutoLayout());
+
+ aSize = rOldNotesMaster.GetSize();
+ ::tools::Rectangle aNotesBorderRect(rOldNotesMaster.GetLeftBorder(),
+ rOldNotesMaster.GetUpperBorder(),
+ rOldNotesMaster.GetRightBorder(),
+ rOldNotesMaster.GetLowerBorder());
+ pNotesMaster->ScaleObjects(aSize, aNotesBorderRect, true);
+ pNotesMaster->SetSize(aSize);
+ pNotesMaster->SetBorder(rOldNotesMaster.GetLeftBorder(),
+ rOldNotesMaster.GetUpperBorder(),
+ rOldNotesMaster.GetRightBorder(),
+ rOldNotesMaster.GetLowerBorder());
+ pNotesMaster->SetOrientation( rOldNotesMaster.GetOrientation() );
+ pNotesMaster->SetAutoLayout(pNotesMaster->GetAutoLayout());
+
+ if( (pSourceDoc->GetDocumentType() == DocumentType::Impress) &&
+ (GetDocumentType() == DocumentType::Draw) )
+ {
+ pMaster->RemoveEmptyPresentationObjects();
+ pNotesMaster->RemoveEmptyPresentationObjects();
+ }
+ }
+ }
+ else
+ {
+ // Find a new name for the layout
+ OUString aName(createNewMasterPageLayoutName(*this));
+ OUString aPageLayoutName(aName + SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE);
+
+ // Generate new stylesheets
+ static_cast<SdStyleSheetPool*>( mxStyleSheetPool.get())->CreateLayoutStyleSheets(aName);
+ SdStyleSheetVector aCreatedStyles;
+ static_cast<SdStyleSheetPool*>( mxStyleSheetPool.get())->CreateLayoutSheetList(aName, aCreatedStyles);
+
+ if( bUndo )
+ {
+ StyleSheetCopyResultVector aUndoInsert;
+ aUndoInsert.reserve(aCreatedStyles.size());
+ for (const auto& a : aCreatedStyles)
+ aUndoInsert.emplace_back(a.get(), true);
+ pUndoMgr->AddUndoAction(std::make_unique<SdMoveStyleSheetsUndoAction>(this, aUndoInsert, true));
+ // Generate new master pages and register them with the document
+ BegUndo();
+ }
+
+ pMaster = AllocSdPage(true);
+ pMaster->SetSize(pSelectedPage->GetSize());
+ pMaster->SetBorder(pSelectedPage->GetLeftBorder(),
+ pSelectedPage->GetUpperBorder(),
+ pSelectedPage->GetRightBorder(),
+ pSelectedPage->GetLowerBorder() );
+ pMaster->SetName(aName);
+ pMaster->SetLayoutName(aPageLayoutName);
+ InsertMasterPage(pMaster.get());
+
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pMaster));
+
+ pMaster->SetAutoLayout(AUTOLAYOUT_NONE, true, true);
+
+ pNotesMaster = AllocSdPage(true);
+ pNotesMaster->SetPageKind(PageKind::Notes);
+ pNotesMaster->SetSize(pNotes->GetSize());
+ pNotesMaster->SetBorder(pNotes->GetLeftBorder(),
+ pNotes->GetUpperBorder(),
+ pNotes->GetRightBorder(),
+ pNotes->GetLowerBorder() );
+ pNotesMaster->SetName(aName);
+ pNotesMaster->SetLayoutName(aPageLayoutName);
+ InsertMasterPage(pNotesMaster.get());
+
+ if( bUndo )
+ AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pNotesMaster));
+
+ pNotesMaster->SetAutoLayout(AUTOLAYOUT_NOTES, true, true);
+
+ if( bUndo )
+ EndUndo();
+
+ // Create a list of affected default and notes pages
+ std::vector<SdPage*> aPageList;
+ if (bMaster)
+ {
+ for (sal_uInt16 nPage = 1; nPage < GetPageCount(); nPage++)
+ {
+ SdPage* pPage = static_cast<SdPage*>( GetPage(nPage) );
+ if (pPage->GetLayoutName() == aOldPageLayoutName)
+ {
+ aPageList.push_back(pPage);
+ }
+ }
+ }
+ else
+ {
+ aPageList.push_back(pSelectedPage);
+ aPageList.push_back(pNotes);
+ }
+
+ // Set presentation layout and AutoLayout for the affected pages
+ for ( auto& rpPage : aPageList )
+ {
+ AutoLayout eOldAutoLayout = rpPage->GetAutoLayout();
+ AutoLayout eNewAutoLayout =
+ rpPage->GetPageKind() == PageKind::Standard ? AUTOLAYOUT_NONE : AUTOLAYOUT_NOTES;
+
+ if( bUndo )
+ {
+ pUndoMgr->AddUndoAction(std::make_unique<SdPresentationLayoutUndoAction>
+ (this, aOldLayoutName, aName,
+ eOldAutoLayout, eNewAutoLayout, true,
+ rpPage));
+ }
+
+ rpPage->SetPresentationLayout(aName);
+ rpPage->SetAutoLayout(eNewAutoLayout);
+ }
+ }
+
+ // If the old master pages aren't used anymore, they and their styles have
+ // to be removed.
+ if (bCheckMasters)
+ {
+ // Check all
+ RemoveUnnecessaryMasterPages();
+ }
+ else
+ {
+ // Check only the master page that was replaced
+ RemoveUnnecessaryMasterPages(&rOldMaster);
+ }
+
+ if( bUndo )
+ pUndoMgr->LeaveListAction();
+
+ if( mpDocSh )
+ mpDocSh->SetWaitCursor( false );
+}
+
+void SdDrawDocument::Merge(SdrModel& rSourceModel,
+ sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum,
+ sal_uInt16 nDestPos,
+ bool bMergeMasterPages, bool bAllMasterPages,
+ bool bUndo, bool bTreadSourceAsConst)
+{
+ sal_uInt16 nMasterPageCount = GetMasterPageCount();
+ SdrModel::Merge( rSourceModel, nFirstPageNum, nLastPageNum, nDestPos, bMergeMasterPages, bAllMasterPages, bUndo, bTreadSourceAsConst );
+
+ // add style family for each new master page
+ for( sal_uInt16 nMaster = nMasterPageCount; nMaster < GetMasterPageCount(); nMaster++ )
+ {
+ SdPage* pPage = static_cast< SdPage* >( GetMasterPage( nMaster ) );
+ if( pPage && pPage->IsMasterPage() && (pPage->GetPageKind() == PageKind::Standard) )
+ {
+ // new master page created, add its style family
+ SdStyleSheetPool* pStylePool = static_cast<SdStyleSheetPool*>( GetStyleSheetPool() );
+ if( pStylePool )
+ pStylePool->AddStyleFamily( pPage );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/drawdoc4.cxx b/sd/source/core/drawdoc4.cxx
new file mode 100644
index 000000000..590450568
--- /dev/null
+++ b/sd/source/core/drawdoc4.cxx
@@ -0,0 +1,1399 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <i18nlangtag/languagetag.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <sfx2/dispatch.hxx>
+#include <Outliner.hxx>
+#include <editeng/outliner.hxx>
+
+#include <DrawDocShell.hxx>
+#include <editeng/eeitem.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/UnitConversion.hxx>
+
+#include <vcl/idle.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+#include <editeng/autokernitem.hxx>
+
+#include <svx/svxids.hrc>
+#include <svl/srchitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/numdef.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <editeng/bulletitem.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/boxitem.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/sdshcitm.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/cmapitem.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlnedcit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedit.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/sdsxyitm.hxx>
+#include <svx/sdtditm.hxx>
+#include <svx/sdtaitm.hxx>
+#include <svx/sdynitm.hxx>
+#include <editeng/numitem.hxx>
+#include <editeng/unolingu.hxx>
+#include <svl/itempool.hxx>
+#include <editeng/outlobj.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <svx/sdasitm.hxx>
+
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <strings.hrc>
+#include <glob.hxx>
+#include <stlpool.hxx>
+#include <shapelist.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <svl/itemset.hxx>
+#include <app.hrc>
+#include <strings.hxx>
+
+namespace com::sun::star::linguistic2 { class XHyphenator; }
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::linguistic2;
+using namespace ::sd;
+
+// CreateLayoutTemplates
+// At the moment (31.03.1995), the StyleSheetPool only saves styleheets that
+// have an ItemSet. To save all stylesheets, we force the creation of an ItemSet
+// with a GetItemSet call.
+// We can remove this behavior once the pool saves styleheets even without an ItemSet
+void SdDrawDocument::CreateLayoutTemplates()
+{
+ SdStyleSheetPool* pSSPool = static_cast<SdStyleSheetPool*>(GetStyleSheetPool());
+ SfxStyleSheetBase* pSheet = nullptr;
+ const OUString aHelpFile;
+ OUString aStdName(SdResId(STR_STANDARD_STYLESHEET_NAME));
+
+ // Default style
+
+ SfxStyleSearchBits nMask = SfxStyleSearchBits::Auto;
+
+ OUString aName(aStdName);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetHelpId( aHelpFile, HID_STANDARD_STYLESHEET_NAME );
+ SfxItemSet& rISet = pSheet->GetItemSet();
+
+ ::basegfx::B2DPolyPolygon aNullPolyPolygon;
+ Color aNullCol(COL_DEFAULT_SHAPE_STROKE);
+
+ XDash aNullDash;
+ XGradient aNullGrad(aNullCol,COL_WHITE);
+ aNullGrad.SetStartIntens( 100 );
+ aNullGrad.SetEndIntens( 100 );
+ XHatch aNullHatch(aNullCol);
+
+ // Line attributes (Extended OutputDevice)
+ rISet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
+ rISet.Put(XLineColorItem(OUString(), COL_DEFAULT_SHAPE_STROKE));
+ rISet.Put(XLineWidthItem(0));
+ rISet.Put(XLineDashItem(aNullDash));
+ rISet.Put(XLineStartItem(aNullPolyPolygon));
+ rISet.Put(XLineEndItem(aNullPolyPolygon));
+ rISet.Put(XLineStartWidthItem(200));
+ rISet.Put(XLineEndWidthItem(200));
+ rISet.Put(XLineStartCenterItem());
+ rISet.Put(XLineEndCenterItem());
+ rISet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK));
+
+ // Fill attributes (Extended OutputDevice)
+ rISet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ rISet.Put(XFillColorItem(OUString(), COL_DEFAULT_SHAPE_FILLING));
+
+ rISet.Put( XFillGradientItem( aNullGrad) );
+ rISet.Put(XFillHatchItem(aNullHatch));
+ Size aNullSize( 32, 32 );
+ Bitmap aNullBmp(aNullSize, vcl::PixelFormat::N8_BPP);
+ aNullBmp.Erase( COL_WHITE );
+ rISet.Put(XFillBitmapItem(Graphic(BitmapEx(aNullBmp))));
+
+ // Shadow attributes (Drawing Engine)
+ rISet.Put(makeSdrShadowItem(false));
+ rISet.Put(makeSdrShadowColorItem(COL_GRAY));
+ rISet.Put(makeSdrShadowXDistItem(200)); // 3 mm Shadow distance
+ rISet.Put(makeSdrShadowYDistItem(200));
+
+ vcl::Font aLatinFont, aCJKFont, aCTLFont;
+
+ getDefaultFonts( aLatinFont, aCJKFont, aCTLFont );
+
+ SvxFontItem aSvxFontItem( aLatinFont.GetFamilyType(), aLatinFont.GetFamilyName(), aLatinFont.GetStyleName(), aLatinFont.GetPitch(),
+ aLatinFont.GetCharSet(), EE_CHAR_FONTINFO );
+
+ SvxFontItem aSvxFontItemCJK( aCJKFont.GetFamilyType(), aCJKFont.GetFamilyName(), aCJKFont.GetStyleName(), aCJKFont.GetPitch(),
+ aCJKFont.GetCharSet(), EE_CHAR_FONTINFO_CJK );
+
+ SvxFontItem aSvxFontItemCTL( aCTLFont.GetFamilyType(), aCTLFont.GetFamilyName(), aCTLFont.GetStyleName(), aCTLFont.GetPitch(),
+ aCTLFont.GetCharSet(), EE_CHAR_FONTINFO_CTL );
+
+ rISet.Put( aSvxFontItem );
+ rISet.Put( aSvxFontItemCJK );
+ rISet.Put( aSvxFontItemCTL );
+
+ rISet.Put( SvxFontHeightItem( 635, 100, EE_CHAR_FONTHEIGHT ) ); // sj: (i33745) changed default from 24 to 18 pt
+ rISet.Put( SvxFontHeightItem( 635, 100, EE_CHAR_FONTHEIGHT_CJK ) ); // 18 pt
+ rISet.Put( SvxFontHeightItem( convertFontHeightToCTL( 635 ), 100, EE_CHAR_FONTHEIGHT_CTL ) ); // 18 pt
+
+ rISet.Put( SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
+ rISet.Put( SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CJK ) );
+ rISet.Put( SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CTL ) );
+
+ rISet.Put( SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC ) );
+ rISet.Put( SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CJK ) );
+ rISet.Put( SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CTL ) );
+
+ rISet.Put(SvxContourItem(false, EE_CHAR_OUTLINE ));
+ rISet.Put(SvxShadowedItem(false, EE_CHAR_SHADOW ));
+ rISet.Put(SvxUnderlineItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE));
+ rISet.Put(SvxOverlineItem(LINESTYLE_NONE, EE_CHAR_OVERLINE));
+ rISet.Put(SvxCrossedOutItem(STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ));
+ rISet.Put(SvxCaseMapItem(SvxCaseMap::NotMapped, EE_CHAR_CASEMAP ));
+ rISet.Put(SvxEmphasisMarkItem(FontEmphasisMark::NONE, EE_CHAR_EMPHASISMARK));
+ rISet.Put(SvxCharReliefItem(FontRelief::NONE, EE_CHAR_RELIEF));
+ rISet.Put(SvxColorItem(COL_AUTO, EE_CHAR_COLOR ));
+
+ // Paragraph attributes (Edit Engine)
+ rISet.Put(SvxLRSpaceItem(EE_PARA_LRSPACE));
+ rISet.Put(SvxULSpaceItem(EE_PARA_ULSPACE));
+
+ rISet.Put( makeSdrTextLeftDistItem( 250 ) ); // sj: (i33745) using text frame distances seems to be a better default
+ rISet.Put( makeSdrTextRightDistItem( 250 ) );
+ rISet.Put( makeSdrTextUpperDistItem( 125 ) );
+ rISet.Put( makeSdrTextLowerDistItem( 125 ) );
+
+ // Set Word-wrap to true by default
+ rISet.Put( makeSdrTextWordWrapItem(true) );
+
+ rISet.Put( SvxLineSpacingItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL ) );
+
+ // #i16874# enable kerning by default but only for new documents
+ rISet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+
+ // Bullet
+ // BulletItem and BulletFont for title and outline
+ SvxBulletItem aBulletItem(EE_PARA_BULLET);
+ // Identical in all layers
+ aBulletItem.SetStyle(SvxBulletStyle::BULLET);
+ aBulletItem.SetStart(1);
+ aBulletItem.SetScale(45); // In percent
+
+ vcl::Font aBulletFont( SdStyleSheetPool::GetBulletFont() );
+
+ aBulletFont.SetFontSize(Size(0,635)); // sj: (i33745) changed default from 24 to 18 pt
+
+ aBulletItem.SetFont(aBulletFont);
+ aBulletItem.SetSymbol( 0x25CF ); // In points
+ rISet.Put(aBulletItem);
+
+ // New BulletItem
+ SdStyleSheetPool::PutNumBulletItem( pSheet, aBulletFont );
+
+ SfxItemSet* pISet = nullptr;
+
+ // Default > Object without filling
+ {
+ aName = SdResId(STR_POOLSHEET_OBJWITHOUTFILL);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aStdName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_OBJWITHOUTFILL );
+ pISet = &pSheet->GetItemSet();
+
+ pISet->Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ // Default > Object no fill no line
+ {
+ aName = SdResId(STR_POOLSHEET_OBJNOLINENOFILL);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aStdName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_OBJNOLINENOFILL );
+ pISet = &pSheet->GetItemSet();
+
+ pISet->Put(XFillStyleItem(drawing::FillStyle_NONE));
+ pISet->Put(XLineStyleItem(drawing::LineStyle_NONE));
+ }
+
+ // tdf#94369
+
+ // Text
+ OUString aTextName;
+ {
+ aTextName = SdResId(STR_POOLSHEET_TEXT);
+ pSheet = &(pSSPool->Make(aTextName, SfxStyleFamily::Para, nMask));
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_TEXT );
+ pISet = &pSheet->GetItemSet();
+ aSvxFontItem.SetFamilyName("Noto Sans");
+ pISet->Put( aSvxFontItem ); // Noto Sans
+ pISet->Put(XFillStyleItem(drawing::FillStyle_SOLID)); // solid fill
+ pISet->Put(XFillColorItem(OUString(), Color(0xeeeeee))); // light gray 5
+ pISet->Put(XLineStyleItem(drawing::LineStyle_SOLID)); // solid fill
+ pISet->Put(XLineColorItem(OUString(), Color(0xcccccc))); // light gray 3
+ }
+ // Text > A4
+ OUString aA4Name;
+ {
+ aA4Name = SdResId(STR_POOLSHEET_A4);
+ pSheet = &(pSSPool->Make(aA4Name, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent( aTextName );
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_A4 );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put(SvxFontHeightItem(635, 100, EE_CHAR_FONTHEIGHT )); // 18 pt
+ pISet->Put(XFillStyleItem(drawing::FillStyle_NONE)); // no filling
+ }
+ // Text > A4 > Title
+ {
+
+ aName = SdResId(STR_POOLSHEET_A4_TITLE);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent( aA4Name );
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_A4_TITLE );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put(SvxFontHeightItem(1551, 100, EE_CHAR_FONTHEIGHT )); // 44 pt
+ pISet->Put(XLineStyleItem(drawing::LineStyle_NONE)); // no border
+ }
+ // Text > A4 > Headline
+ {
+ aName = SdResId(STR_POOLSHEET_A4_HEADLINE);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent( aA4Name );
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_A4_HEADLINE );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put(SvxFontHeightItem(847, 100, EE_CHAR_FONTHEIGHT )); // 24 pt
+ pISet->Put(XLineStyleItem(drawing::LineStyle_NONE)); // no border
+ }
+ // Text > A4 > Text
+ {
+ aName = SdResId(STR_POOLSHEET_A4_TEXT);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aA4Name);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_A4_TEXT );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put(XLineStyleItem(drawing::LineStyle_NONE)); // no border
+ }
+ // Text > A0
+ OUString aA0Name;
+ {
+ aA0Name = SdResId(STR_POOLSHEET_A0);
+ pSheet = &(pSSPool->Make(aA0Name, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aTextName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_A0 );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put(SvxFontHeightItem(1692, 100, EE_CHAR_FONTHEIGHT )); // 48 pt
+ pISet->Put(XFillStyleItem(drawing::FillStyle_NONE)); // no filling
+ }
+ // Text > A0 > Title
+ {
+ aName = SdResId(STR_POOLSHEET_A0_TITLE);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aA0Name);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_A0_TITLE );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put(SvxFontHeightItem(3385, 100, EE_CHAR_FONTHEIGHT )); // 96 pt
+ pISet->Put(XLineStyleItem(drawing::LineStyle_NONE)); // no border
+ }
+ // Text > A0 > Headline
+ {
+ aName = SdResId(STR_POOLSHEET_A0_HEADLINE);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aA0Name);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_A0_HEADLINE );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put(SvxFontHeightItem(2538, 100, EE_CHAR_FONTHEIGHT )); // 72 pt
+ pISet->Put(XLineStyleItem(drawing::LineStyle_NONE)); // no border
+ }
+ // Text > A0 > Text
+ {
+ aName = SdResId(STR_POOLSHEET_A0_TEXT);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aA0Name);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_A0_TEXT );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put(XLineStyleItem(drawing::LineStyle_NONE)); // no border
+ }
+
+ // Graphic
+ OUString aGraphicName;
+ XFillGradientItem aFillGradient;
+ XGradient aGradient;
+
+ {
+ aGraphicName = SdResId(STR_POOLSHEET_GRAPHIC);
+ pSheet = &(pSSPool->Make(aGraphicName, SfxStyleFamily::Para, nMask));
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_GRAPHIC );
+ pISet = &pSheet->GetItemSet();
+ aSvxFontItem.SetFamilyName("Liberation Sans"); // Liberation Sans
+ pISet->Put( aSvxFontItem );
+ pISet->Put( SvxFontHeightItem(635, 100, EE_CHAR_FONTHEIGHT) ); // 18 pt
+ pISet->Put( XFillStyleItem(drawing::FillStyle_SOLID) ); // solid fill
+ pISet->Put( XFillColorItem(OUString(), COL_WHITE) ); // filled white
+
+ }
+ // Graphic > Shapes
+ OUString aShapesName;
+ {
+ aShapesName = SdResId(STR_POOLSHEET_SHAPES);
+ pSheet = &(pSSPool->Make(aShapesName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent( aGraphicName );
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_SHAPES);
+ pISet = &pSheet->GetItemSet();
+ pISet->Put(XFillStyleItem(drawing::FillStyle_GRADIENT)); // fill with gradient
+ aGradient.SetGradientStyle( ::awt::GradientStyle_RECT); // square type
+ aGradient.SetAngle( 0_deg10 ); // 0° angle
+ aGradient.SetStartColor( Color(0xcccccc) ); // white
+ aGradient.SetEndColor( COL_WHITE ); // light gray 3
+ aFillGradient.SetName( aShapesName );
+ aFillGradient.SetGradientValue(aGradient);
+ pISet->Put( aFillGradient );
+ pISet->Put( XLineStyleItem(drawing::LineStyle_NONE) ); // no border
+ pISet->Put( SvxFontHeightItem(494, 100, EE_CHAR_FONTHEIGHT) ); // 14 pt
+ pISet->Put( SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT) ); // bold
+ }
+ // Graphic > Shapes > Filled
+ OUString aFilledName(SdResId(STR_POOLSHEET_FILLED));
+ {
+ aName = aFilledName;
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_FILLED );
+ pSheet->SetParent( aShapesName );
+ pISet = &pSheet->GetItemSet();
+
+ aGradient.SetGradientStyle( ::awt::GradientStyle_LINEAR );
+ aGradient.SetAngle( 300_deg10 );
+ aGradient.SetStartColor( COL_WHITE ); // white
+ aGradient.SetEndColor( Color(0xcccccc) ); // light gray 3
+ aFillGradient.SetName( aName );
+ aFillGradient.SetGradientValue(aGradient);
+ pISet->Put( XFillStyleItem(drawing::FillStyle_GRADIENT) );
+ pISet->Put( aFillGradient );
+ }
+ // Graphic > Shapes > Filled > Blue
+ {
+ aName =SdResId(STR_POOLSHEET_FILLED_BLUE);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aFilledName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_FILLED_BLUE );
+ pISet = &pSheet->GetItemSet();
+
+ aGradient.SetStartColor( Color(0x00729fcf) ); // light blue 2
+ aGradient.SetEndColor( Color(0x00355269) ); // dark blue 2
+ aFillGradient.SetName( aName );
+ aFillGradient.SetGradientValue(aGradient);
+ pISet->Put( aFillGradient );
+ pISet->Put( SvxColorItem(COL_WHITE, EE_CHAR_COLOR )); // font white
+ }
+ // Graphic > Shapes > Filled > Green
+ {
+ aName =SdResId(STR_POOLSHEET_FILLED_GREEN);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aFilledName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_FILLED_GREEN );
+ pISet = &pSheet->GetItemSet();
+
+ aGradient.SetStartColor( Color(0x0077bc65) ); // light green 2
+ aGradient.SetEndColor( Color(0x00127622) ); // dark green 2
+ aFillGradient.SetName( aName );
+ aFillGradient.SetGradientValue(aGradient);
+ pISet->Put( aFillGradient );
+ pISet->Put( aSvxFontItem ); // font name
+ pISet->Put( SvxColorItem(COL_WHITE, EE_CHAR_COLOR )); // font white
+ }
+ // Graphic > Shapes > Filled > Red
+ {
+ aName =SdResId(STR_POOLSHEET_FILLED_RED);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aFilledName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_FILLED_RED );
+ pISet = &pSheet->GetItemSet();
+
+ aGradient.SetStartColor( Color(0x00ff6d6d) ); // light red 2
+ aGradient.SetEndColor( Color(0x00c9211e) ); // dark red 2
+ aFillGradient.SetName( aName );
+ aFillGradient.SetGradientValue(aGradient);
+ pISet->Put( aFillGradient );
+ pISet->Put( SvxColorItem(COL_WHITE, EE_CHAR_COLOR )); // font white
+ }
+ // Graphic > Shapes > Filled > Yellow
+ {
+ aName =SdResId(STR_POOLSHEET_FILLED_YELLOW);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aFilledName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_FILLED_YELLOW );
+ pISet = &pSheet->GetItemSet();
+
+ aGradient.SetStartColor( Color(0x00ffde59) ); // light gold 2
+ aGradient.SetEndColor( Color(0x00b47804) ); // dark gold 2
+ aFillGradient.SetName( aName );
+ aFillGradient.SetGradientValue(aGradient);
+ pISet->Put( aFillGradient );
+ pISet->Put( SvxColorItem(COL_WHITE, EE_CHAR_COLOR )); // font white
+ }
+ // Graphic > Shapes > Outlines
+ OUString aOutlineName(SdResId(STR_POOLSHEET_OUTLINE));
+ {
+ aName = aOutlineName;
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_OUTLINE );
+ pSheet->SetParent( aShapesName );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put( XFillStyleItem(drawing::FillStyle_NONE) ); // clear
+ pISet->Put( XLineStyleItem(drawing::LineStyle_SOLID) ); // solide line
+ pISet->Put( XLineWidthItem(81) ); // 2.3 pt
+ pISet->Put( XLineColorItem(OUString(), COL_BLACK) ); // b/w
+ }
+ // Graphic > Shapes > Outlines > Blue
+ {
+ aName =SdResId(STR_POOLSHEET_OUTLINE_BLUE);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aOutlineName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_OUTLINE_BLUE );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put( XLineColorItem(OUString(), Color(0x00355269)) ); // dark blue 2
+ pISet->Put( SvxColorItem(Color(0x00355269), EE_CHAR_COLOR )); // font color
+ }
+ // Graphic > Shapes > Outlines > Green
+ {
+ aName =SdResId(STR_POOLSHEET_OUTLINE_GREEN);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aOutlineName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_OUTLINE_GREEN );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put( XLineColorItem(OUString(), Color(0x00127622)) ); // dark green 2
+ pISet->Put( SvxColorItem(Color(0x00127622), EE_CHAR_COLOR )); // font color
+ }
+ // Graphic > Shapes > Outlines > Red
+ {
+ aName =SdResId(STR_POOLSHEET_OUTLINE_RED);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aOutlineName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_OUTLINE_RED );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put( XLineColorItem(OUString(), Color(0x00c9211e)) ); // dark red 2
+ pISet->Put( SvxColorItem(Color(0x00c9211e), EE_CHAR_COLOR )); // font color
+ }
+ // Graphic > Shapes > Outlines > Yellow
+ {
+ aName =SdResId(STR_POOLSHEET_OUTLINE_YELLOW);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aOutlineName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_OUTLINE_YELLOW );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put( XLineStyleItem(drawing::LineStyle_SOLID));
+ pISet->Put( XLineColorItem(OUString(), Color(0x00b47804)) ); // dark gold 2
+ pISet->Put( SvxColorItem(Color(0x00b47804), EE_CHAR_COLOR )); // font color
+ }
+ // Graphic > Lines
+ OUString aLinesName;
+ {
+ aLinesName = SdResId(STR_POOLSHEET_LINES);
+ pSheet = &(pSSPool->Make(aLinesName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent( aGraphicName );
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_LINES);
+ pISet = &pSheet->GetItemSet();
+ pISet->Put( XFillStyleItem(drawing::FillStyle_NONE) ); // clear
+ pISet->Put( XLineStyleItem(drawing::LineStyle_SOLID) ); // solide line
+ pISet->Put( XLineColorItem(OUString(), COL_BLACK) ); // b/w
+ }
+ // Graphic > Lines > Measurements
+ {
+ aName = SdResId(STR_POOLSHEET_MEASURE);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aLinesName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_MEASURE );
+ pISet = &pSheet->GetItemSet();
+
+ ::basegfx::B2DPolygon aArrow; // arrows
+ aArrow.append(::basegfx::B2DPoint(10.0, 0.0));
+ aArrow.append(::basegfx::B2DPoint(0.0, 30.0));
+ aArrow.append(::basegfx::B2DPoint(20.0, 30.0));
+ aArrow.setClosed(true);
+
+ pISet->Put(XLineStartItem(SvxResId(RID_SVXSTR_ARROW),::basegfx::B2DPolyPolygon(aArrow)));
+ pISet->Put(XLineStartWidthItem(200));
+ pISet->Put(XLineEndItem(SvxResId(RID_SVXSTR_ARROW),::basegfx::B2DPolyPolygon(aArrow)));
+ pISet->Put(XLineEndWidthItem(200));
+ pISet->Put(SdrYesNoItem(SDRATTR_MEASURESHOWUNIT, true));
+ }
+ // Graphic > Lines > Dashed
+ {
+ aName = SdResId(STR_POOLSHEET_LINES_DASHED);
+ pSheet = &(pSSPool->Make(aName, SfxStyleFamily::Para, nMask));
+ pSheet->SetParent(aLinesName);
+ pSheet->SetHelpId( aHelpFile, HID_POOLSHEET_LINES_DASHED );
+ pISet = &pSheet->GetItemSet();
+ pISet->Put( XLineStyleItem(drawing::LineStyle_DASH) ); // dashed line
+ }
+
+ // Generate presentation templates for default layout.
+ OUString aPrefix = SdResId(STR_LAYOUT_DEFAULT_NAME);
+ pSSPool->CreateLayoutStyleSheets(aPrefix);
+}
+
+static Any implMakeSolidCellStyle( SdStyleSheetPool* pSSPool, const OUString& rName, const OUString& rParent, const Color& rColor )
+{
+ SfxStyleSheetBase* pSheet = &(pSSPool->Make(rName, SfxStyleFamily::Frame, SfxStyleSearchBits::Auto));
+ pSheet->SetParent(rParent);
+ SfxItemSet* pISet = &pSheet->GetItemSet();
+ pISet->Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ pISet->Put(XFillColorItem(OUString(), rColor));
+
+ return Any( Reference< XStyle >( static_cast< XWeak* >( pSheet ), UNO_QUERY ) );
+}
+
+static void implCreateTableTemplate( const Reference< XNameContainer >& xTableFamily, const OUString& rName, const Any& rBody, const Any& rHeading, const Any& rBanding )
+{
+ if( !xTableFamily.is() )
+ return;
+
+ try
+ {
+ if( !xTableFamily->hasByName( rName ) )
+ {
+ Reference< XSingleServiceFactory > xFactory( xTableFamily, UNO_QUERY_THROW );
+ Reference< XNameReplace > xDefaultTableStyle( xFactory->createInstance(), UNO_QUERY_THROW );
+ xTableFamily->insertByName( rName, Any( xDefaultTableStyle ) );
+
+ xDefaultTableStyle->replaceByName( "body", rBody );
+ xDefaultTableStyle->replaceByName( "odd-rows" , rBanding );
+ xDefaultTableStyle->replaceByName( "odd-columns" , rBanding );
+ xDefaultTableStyle->replaceByName( "first-row" , rHeading );
+ xDefaultTableStyle->replaceByName( "first-column" , rHeading );
+ xDefaultTableStyle->replaceByName( "last-row" , rHeading );
+ xDefaultTableStyle->replaceByName( "last-column" , rHeading );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::implCreateTableTemplate()");
+ }
+}
+
+void SdDrawDocument::CreateDefaultCellStyles()
+{
+ SdStyleSheetPool* pSSPool = static_cast< SdStyleSheetPool* >(GetStyleSheetPool());
+ SfxStyleSheetBase* pSheet = nullptr;
+
+ Reference< XNameContainer > xTableFamily( pSSPool->getByName( "table" ), UNO_QUERY );
+
+ // ---- Default -----------------------------------------------
+
+ OUString aDefaultCellStyleName( "default" );
+
+ pSheet = &(pSSPool->Make(aDefaultCellStyleName, SfxStyleFamily::Frame, SfxStyleSearchBits::Auto));
+ pSheet->SetHelpId( OUString(), HID_SD_CELL_STYLE_DEFAULT );
+ SfxItemSet& rISet = pSheet->GetItemSet();
+
+ rISet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ rISet.Put(XFillColorItem(OUString(), Color(0x00ccccff)));
+
+ vcl::Font aLatinFont, aCJKFont, aCTLFont;
+
+ getDefaultFonts( aLatinFont, aCJKFont, aCTLFont );
+
+ SvxFontItem aSvxFontItem( aLatinFont.GetFamilyType(), aLatinFont.GetFamilyName(), aLatinFont.GetStyleName(), aLatinFont.GetPitch(),
+ aLatinFont.GetCharSet(), EE_CHAR_FONTINFO );
+
+ SvxFontItem aSvxFontItemCJK( aCJKFont.GetFamilyType(), aCJKFont.GetFamilyName(), aCJKFont.GetStyleName(), aCJKFont.GetPitch(),
+ aCJKFont.GetCharSet(), EE_CHAR_FONTINFO_CJK );
+
+ SvxFontItem aSvxFontItemCTL( aCTLFont.GetFamilyType(), aCTLFont.GetFamilyName(), aCTLFont.GetStyleName(), aCTLFont.GetPitch(),
+ aCTLFont.GetCharSet(), EE_CHAR_FONTINFO_CTL );
+
+ rISet.Put( aSvxFontItem );
+ rISet.Put( aSvxFontItemCJK );
+ rISet.Put( aSvxFontItemCTL );
+
+ rISet.Put( SvxFontHeightItem( 635, 100, EE_CHAR_FONTHEIGHT ) ); // sj: (i33745) changed default from 24 to 18 pt
+ rISet.Put( SvxFontHeightItem( 635, 100, EE_CHAR_FONTHEIGHT_CJK ) ); // 18 pt
+ rISet.Put( SvxFontHeightItem( convertFontHeightToCTL( 635 ), 100, EE_CHAR_FONTHEIGHT_CTL ) ); // 18 pt
+
+ rISet.Put(SvxColorItem(COL_AUTO, EE_CHAR_COLOR ));
+
+ // Paragraph attributes (Edit Engine)
+ rISet.Put(SvxLRSpaceItem(EE_PARA_LRSPACE));
+ rISet.Put(SvxULSpaceItem(EE_PARA_ULSPACE));
+
+ rISet.Put( makeSdrTextLeftDistItem( 250 ) );
+ rISet.Put( makeSdrTextRightDistItem( 250 ) );
+ rISet.Put( makeSdrTextUpperDistItem( 130 ) );
+ rISet.Put( makeSdrTextLowerDistItem( 130 ) );
+
+ rISet.Put( SvxLineSpacingItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL ) );
+ rISet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+ rISet.Put( SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP) );
+ rISet.Put( SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT) );
+
+ Color aWhite( COL_WHITE );
+ ::editeng::SvxBorderLine aBorderLine(
+ &aWhite, 1, SvxBorderLineStyle::SOLID);
+
+ SvxBoxItem aBoxItem( SDRATTR_TABLE_BORDER );
+ aBoxItem.SetLine( &aBorderLine, SvxBoxItemLine::TOP );
+ aBoxItem.SetLine( &aBorderLine, SvxBoxItemLine::BOTTOM );
+ aBoxItem.SetLine( &aBorderLine, SvxBoxItemLine::LEFT );
+ aBoxItem.SetLine( &aBorderLine, SvxBoxItemLine::RIGHT );
+
+ rISet.Put( aBoxItem );
+
+ // ---- default --------------------------------------------------
+
+ Any aGray1( implMakeSolidCellStyle( pSSPool, "gray1" , aDefaultCellStyleName, Color(230,230,230)));
+ Any aGray2( implMakeSolidCellStyle( pSSPool, "gray2" , aDefaultCellStyleName, Color(204,204,204)));
+ Any aGray3( implMakeSolidCellStyle( pSSPool, "gray3" , aDefaultCellStyleName, Color(179,179,179)));
+
+ implCreateTableTemplate( xTableFamily, "default" , aGray1, aGray3, aGray2 );
+
+ // ---- BW ------------------------------------------------
+
+ Any aBW1( implMakeSolidCellStyle( pSSPool, "bw1" , aDefaultCellStyleName, Color(255,255,255)));
+ Any aBW2( implMakeSolidCellStyle( pSSPool, "bw2" , aDefaultCellStyleName, Color(230,230,230)));
+ Any aBW3( implMakeSolidCellStyle( pSSPool, "bw3" , aDefaultCellStyleName, Color(0,0,0)));
+
+ implCreateTableTemplate( xTableFamily, "bw" , aBW1, aBW3, aBW2 );
+
+ // ---- Orange --------------------------------------------------
+
+ Any aOrange1( implMakeSolidCellStyle( pSSPool, "orange1" , aDefaultCellStyleName, Color(255,204,153)));
+ Any aOrange2( implMakeSolidCellStyle( pSSPool, "orange2" , aDefaultCellStyleName, Color(255,153,102)));
+ Any aOrange3( implMakeSolidCellStyle( pSSPool, "orange3" , aDefaultCellStyleName, Color(255,102,51)));
+
+ implCreateTableTemplate( xTableFamily, "orange" , aOrange1, aOrange3, aOrange2 );
+
+ // ---- Turquoise --------------------------------------------------
+
+ Any aTurquoise1( implMakeSolidCellStyle( pSSPool, "turquoise1" , aDefaultCellStyleName, Color(71,184,184)));
+ Any aTurquoise2( implMakeSolidCellStyle( pSSPool, "turquoise2" , aDefaultCellStyleName, Color(51,163,163)));
+ Any aTurquoise3( implMakeSolidCellStyle( pSSPool, "turquoise3" , aDefaultCellStyleName, Color(25,138,138)));
+
+ implCreateTableTemplate( xTableFamily, "turquoise" , aTurquoise1, aTurquoise3, aTurquoise2 );
+
+ // ---- Gray ------------------------------------------------
+
+ Any aBlue1( implMakeSolidCellStyle( pSSPool, "blue1" , aDefaultCellStyleName, Color(153,204,255)));
+ Any aBlue2( implMakeSolidCellStyle( pSSPool, "blue2" , aDefaultCellStyleName, Color(0,153,255)));
+ Any aBlue3( implMakeSolidCellStyle( pSSPool, "blue3" , aDefaultCellStyleName, Color(0,102,204)));
+
+ implCreateTableTemplate( xTableFamily, "blue" , aBlue1, aBlue3, aBlue2 );
+
+ // ---- Sun ------------------------------------------------
+
+ Any aSun1( implMakeSolidCellStyle( pSSPool, "sun1" , aDefaultCellStyleName, Color(230,230,255)));
+ Any aSun2( implMakeSolidCellStyle( pSSPool, "sun2" , aDefaultCellStyleName, Color(204,204,255)));
+ Any aSun3( implMakeSolidCellStyle( pSSPool, "sun3" , aDefaultCellStyleName, Color(153,153,255)));
+
+ implCreateTableTemplate( xTableFamily, "sun" , aSun1, aSun3, aSun2 );
+
+ // ---- Earth ----------------------------------------------
+
+ Any aEarth1( implMakeSolidCellStyle( pSSPool, "earth1" , aDefaultCellStyleName, Color(255,255,204)));
+ Any aEarth2( implMakeSolidCellStyle( pSSPool, "earth2" , aDefaultCellStyleName, Color(255,204,153)));
+ Any aEarth3( implMakeSolidCellStyle( pSSPool, "earth3" , aDefaultCellStyleName, Color(204,102,51)));
+
+ implCreateTableTemplate( xTableFamily, "earth" , aEarth1, aEarth3, aEarth2 );
+
+ // ---- Green ----------------------------------------------
+
+ Any aGreen1( implMakeSolidCellStyle( pSSPool, "green1" , aDefaultCellStyleName, Color(255,255,204)));
+ Any aGreen2( implMakeSolidCellStyle( pSSPool, "green2" , aDefaultCellStyleName, Color(148,189,94)));
+ Any aGreen3( implMakeSolidCellStyle( pSSPool, "green3" , aDefaultCellStyleName, Color(92,133,38)));
+
+ implCreateTableTemplate( xTableFamily, "green" , aGreen1, aGreen3, aGreen2 );
+
+ // ---- Seaweed ----------------------------------------------
+
+ Any aSeetang1( implMakeSolidCellStyle( pSSPool, "seetang1" , aDefaultCellStyleName, Color(204,255,255)));
+ Any aSeetang2( implMakeSolidCellStyle( pSSPool, "seetang2" , aDefaultCellStyleName, Color(71,184,184)));
+ Any aSeetang3( implMakeSolidCellStyle( pSSPool, "seetang3" , aDefaultCellStyleName, Color(51,163,163)));
+
+ implCreateTableTemplate( xTableFamily, "seetang" , aSeetang1, aSeetang3, aSeetang2 );
+
+ // ---- LightBlue ----------------------------------------------
+
+ Any aLightBlue1( implMakeSolidCellStyle( pSSPool, "lightblue1" , aDefaultCellStyleName, Color(255,255,255)));
+ Any aLightBlue2( implMakeSolidCellStyle( pSSPool, "lightblue2" , aDefaultCellStyleName, Color(230,230,255)));
+ Any aLightBlue3( implMakeSolidCellStyle( pSSPool, "lightblue3" , aDefaultCellStyleName, Color(153,153,204)));
+
+ implCreateTableTemplate( xTableFamily, "lightblue" , aLightBlue1, aLightBlue3, aLightBlue2 );
+
+ // ---- Yellow ----------------------------------------------
+
+ Any aYellow1( implMakeSolidCellStyle( pSSPool, "yellow1" , aDefaultCellStyleName, Color(255,255,204)));
+ Any aYellow2( implMakeSolidCellStyle( pSSPool, "yellow2" , aDefaultCellStyleName, Color(255,255,153)));
+ Any aYellow3( implMakeSolidCellStyle( pSSPool, "yellow3" , aDefaultCellStyleName, Color(255,204,153)));
+
+ implCreateTableTemplate( xTableFamily, "yellow" , aYellow1, aYellow3, aYellow2 );
+}
+
+// Number of pages that reference a master page
+sal_uInt16 SdDrawDocument::GetMasterPageUserCount(SdrPage const * pMaster) const
+{
+ sal_uInt16 nResult = 0;
+ sal_uInt16 nPage;
+ sal_uInt16 nPageCount = GetPageCount();
+
+ for (nPage = 0; nPage < nPageCount; nPage++)
+ {
+ const SdrPage* pPage = GetPage(nPage);
+
+ if(pPage->TRG_HasMasterPage())
+ {
+ if(&(pPage->TRG_GetMasterPage()) == pMaster)
+ {
+ nResult++;
+ }
+ }
+ }
+ return nResult;
+}
+
+// Finish OnlineSpelling in the background
+
+void SdDrawDocument::StopOnlineSpelling()
+{
+ if (mpOnlineSpellingIdle && mpOnlineSpellingIdle->IsActive())
+ {
+ mpOnlineSpellingIdle->Stop();
+ }
+
+ mpOnlineSpellingIdle.reset();
+ mpOnlineSpellingList.reset();
+}
+
+// Start OnlineSpelling in the background
+void SdDrawDocument::StartOnlineSpelling(bool bForceSpelling)
+{
+ if ( !mbOnlineSpell || !(bForceSpelling || mbInitialOnlineSpellingEnabled) ||
+ !mpDocSh || mpDocSh->IsReadOnly() )
+ return;
+
+ StopOnlineSpelling();
+
+ SdOutliner* pOutl = GetInternalOutliner();
+
+ Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() );
+ if ( xSpellChecker.is() )
+ pOutl->SetSpeller( xSpellChecker );
+
+ Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() );
+ if( xHyphenator.is() )
+ pOutl->SetHyphenator( xHyphenator );
+
+ pOutl->SetDefaultLanguage( meLanguage );
+
+ mpOnlineSpellingList.reset(new ShapeList);
+ sal_uInt16 nPage;
+
+ for ( nPage = 0; nPage < GetPageCount(); nPage++ )
+ {
+ // Search in all pages
+ FillOnlineSpellingList(static_cast<SdPage*>(GetPage(nPage)));
+ }
+
+ for (nPage = 0; nPage < GetMasterPageCount(); nPage++)
+ {
+ // Search all master pages
+ FillOnlineSpellingList(static_cast<SdPage*>( GetMasterPage(nPage) ));
+ }
+
+ mpOnlineSpellingList->seekShape(0);
+ mpOnlineSpellingIdle.reset(new Idle("OnlineSpelling"));
+ mpOnlineSpellingIdle->SetInvokeHandler( LINK(this, SdDrawDocument, OnlineSpellingHdl) );
+ mpOnlineSpellingIdle->SetPriority(TaskPriority::LOWEST);
+ mpOnlineSpellingIdle->Start();
+}
+
+// Fill OnlineSpelling list
+void SdDrawDocument::FillOnlineSpellingList(SdPage const * pPage)
+{
+ SdrObjListIter aIter(pPage, SdrIterMode::Flat);
+
+ while (aIter.IsMore())
+ {
+ SdrObject* pObj = aIter.Next();
+
+ if( !pObj )
+ continue;
+
+ if (pObj->GetOutlinerParaObject())
+ {
+ // Found a text object
+ mpOnlineSpellingList->addShape(*pObj);
+ }
+ else if (pObj->GetObjIdentifier() == SdrObjKind::Group)
+ {
+ // Found a group object
+ SdrObjListIter aGroupIter(static_cast< SdrObjGroup* >(pObj)->GetSubList(), SdrIterMode::DeepNoGroups);
+
+ bool bSubTextObjFound = false;
+
+ while (aGroupIter.IsMore() && !bSubTextObjFound)
+ {
+ if (aGroupIter.Next()->GetOutlinerParaObject())
+ {
+ // Found a text object in a group object
+ bSubTextObjFound = true;
+ }
+ }
+
+ if (bSubTextObjFound)
+ {
+ mpOnlineSpellingList->addShape(*pObj);
+ }
+ }
+ }
+}
+
+// OnlineSpelling in the background
+IMPL_LINK_NOARG(SdDrawDocument, OnlineSpellingHdl, Timer *, void)
+{
+ if (mpOnlineSpellingList!=nullptr
+ && ( !mbOnlineSpell || mpOnlineSpellingList->hasMore()))
+ {
+ // Spell next object
+ SdrObject* pObj = mpOnlineSpellingList->getNextShape();
+
+ if (pObj)
+ {
+ if (pObj->GetOutlinerParaObject() && dynamic_cast< const SdrTextObj *>( pObj ) != nullptr)
+ {
+ // Spell text object
+ SpellObject(static_cast<SdrTextObj*>(pObj));
+ }
+ else if (pObj->GetObjIdentifier() == SdrObjKind::Group)
+ {
+ // Found a group object
+ SdrObjListIter aGroupIter(static_cast< SdrObjGroup* >(pObj)->GetSubList(), SdrIterMode::DeepNoGroups);
+
+
+ while (aGroupIter.IsMore())
+ {
+ SdrObject* pSubObj = aGroupIter.Next();
+
+ if (pSubObj->GetOutlinerParaObject())
+ if (auto pTextObj = dynamic_cast< SdrTextObj *>( pSubObj ))
+ // Found a text object in a group object
+ SpellObject(pTextObj);
+ }
+ }
+ }
+
+ // Continue search
+ mpOnlineSpellingIdle->Start();
+ }
+ else
+ {
+ // Initial spelling has finished
+ mbInitialOnlineSpellingEnabled = false;
+
+ // Stop search
+ StopOnlineSpelling();
+
+ mpOnlineSearchItem.reset();
+ }
+}
+
+// Spell object (for OnlineSpelling)
+void SdDrawDocument::SpellObject(SdrTextObj* pObj)
+{
+ if (!(pObj && pObj->GetOutlinerParaObject()) /* && pObj != pView->GetTextEditObject() */)
+ return;
+
+ mbHasOnlineSpellErrors = false;
+ SdOutliner* pOutl = GetInternalOutliner();
+ pOutl->SetUpdateLayout(true);
+ Link<EditStatus&,void> aEvtHdl = pOutl->GetStatusEventHdl();
+ pOutl->SetStatusEventHdl(LINK(this, SdDrawDocument, OnlineSpellEventHdl));
+
+ OutlinerMode nOldOutlMode = pOutl->GetOutlinerMode();
+ OutlinerMode nOutlMode = OutlinerMode::TextObject;
+ if (pObj->GetObjInventor() == SdrInventor::Default &&
+ pObj->GetObjIdentifier() == SdrObjKind::OutlineText)
+ {
+ nOutlMode = OutlinerMode::OutlineObject;
+ }
+ pOutl->Init( nOutlMode );
+
+ // Put text into the outliner
+ pOutl->SetText(*pObj->GetOutlinerParaObject());
+
+ if (!mpOnlineSearchItem || pOutl->HasText(*mpOnlineSearchItem))
+ {
+ // Spelling
+ pOutl->CompleteOnlineSpelling();
+
+ if (mbHasOnlineSpellErrors)
+ {
+ std::optional<OutlinerParaObject> pOPO = pOutl->CreateParaObject();
+ if (pOPO)
+ {
+ if ( *pOPO != *pObj->GetOutlinerParaObject() ||
+ !pObj->GetOutlinerParaObject()->isWrongListEqual( *pOPO ))
+ {
+ sd::ModifyGuard aGuard( this );
+
+ // taking text from the outliner
+ // use non-broadcasting version to avoid O(n^2)
+ pObj->NbcSetOutlinerParaObject( std::move(pOPO) );
+ }
+ }
+ }
+ }
+
+ pOutl->SetStatusEventHdl(aEvtHdl);
+ pOutl->SetUpdateLayout(false);
+ pOutl->Init( nOldOutlMode );
+ mbHasOnlineSpellErrors = false;
+}
+
+// Object was inserted into model
+void SdDrawDocument::InsertObject(SdrObject* pObj)
+{
+ if(mpOnlineSpellingList && pObj)
+ {
+ if (pObj->GetOutlinerParaObject() || (pObj->GetObjIdentifier() == SdrObjKind::Group))
+ {
+ // Add object to OnlineSpelling list
+ mpOnlineSpellingList->addShape(*pObj);
+ }
+ }
+}
+
+// Object removed from model
+void SdDrawDocument::RemoveObject(SdrObject* pObj)
+{
+ if(mpOnlineSpellingList && pObj)
+ {
+ if (pObj->GetOutlinerParaObject() || (pObj->GetObjIdentifier() == SdrObjKind::Group))
+ {
+ // Replace object in OnlineSpelling list by 0 pointer
+ mpOnlineSpellingList->removeShape(*pObj);
+ }
+ }
+}
+
+// Callback for ExecuteSpellPopup()
+IMPL_LINK(SdDrawDocument, OnlineSpellEventHdl, EditStatus&, rEditStat, void)
+{
+ EditStatusFlags nStat = rEditStat.GetStatusWord();
+ mbHasOnlineSpellErrors = bool(nStat & EditStatusFlags::WRONGWORDCHANGED);
+}
+
+// Callback for ExecuteSpellPopup()
+
+// removed link and replaced with Imp method
+void SdDrawDocument::ImpOnlineSpellCallback(SpellCallbackInfo const * pInfo, SdrObject* pObj, SdrOutliner const * pOutl)
+{
+ mpOnlineSearchItem.reset();
+
+ SpellCallbackCommand nCommand = pInfo->nCommand;
+
+ if (nCommand == SpellCallbackCommand::IGNOREWORD
+ // restart when add to dictionary takes place, too.
+ || nCommand == SpellCallbackCommand::ADDTODICTIONARY)
+ {
+ if(pOutl)
+ if (auto pTextObj = dynamic_cast<SdrTextObj *>( pObj ))
+ {
+ bool bModified(IsChanged());
+ pTextObj->SetOutlinerParaObject(pOutl->CreateParaObject());
+ SetChanged(bModified);
+ pObj->BroadcastObjectChange();
+ }
+
+ mpOnlineSearchItem.reset(new SvxSearchItem( SID_SEARCH_ITEM ) );
+ mpOnlineSearchItem->SetSearchString(pInfo->aWord);
+ StartOnlineSpelling();
+ }
+ else if (nCommand == SpellCallbackCommand::STARTSPELLDLG)
+ {
+ if (SfxViewFrame* pViewFrame = SfxViewFrame::Current())
+ pViewFrame->GetDispatcher()->Execute( SID_SPELL_DIALOG, SfxCallMode::ASYNCHRON );
+ }
+ else if (nCommand == SpellCallbackCommand::AUTOCORRECT_OPTIONS)
+ {
+ if (SfxViewFrame* pViewFrame = SfxViewFrame::Current())
+ pViewFrame->GetDispatcher()->Execute( SID_AUTO_CORRECT_DLG, SfxCallMode::ASYNCHRON );
+ }
+}
+
+// Return formatted page number (1, I, i, a, etc.)
+OUString SdDrawDocument::CreatePageNumValue(sal_uInt16 nNum) const
+{
+ OUString aPageNumValue;
+ bool bUpper = false;
+
+ switch (mePageNumType)
+ {
+ case css::style::NumberingType::CHARS_UPPER_LETTER:
+ aPageNumValue += OUStringChar( sal_Unicode((nNum - 1) % 26 + 'A') );
+ break;
+ case css::style::NumberingType::CHARS_LOWER_LETTER:
+ aPageNumValue += OUStringChar( sal_Unicode((nNum - 1) % 26 + 'a') );
+ break;
+ case css::style::NumberingType::ROMAN_UPPER:
+ bUpper = true;
+ [[fallthrough]];
+ case css::style::NumberingType::ROMAN_LOWER:
+ aPageNumValue += SvxNumberFormat::CreateRomanString(nNum, bUpper);
+ break;
+ case css::style::NumberingType::NUMBER_NONE:
+ aPageNumValue = " ";
+ break;
+ default:
+ aPageNumValue += OUString::number(nNum);
+ }
+
+ return aPageNumValue;
+}
+
+// Rename layout template
+// Keep in mind that rOldLayoutName contains the _complete_ name of the layout
+// (including ~LT~). This is unlike rNewName.
+void SdDrawDocument::RenameLayoutTemplate(const OUString& rOldLayoutName, const OUString& rNewName)
+{
+ OUString aSep(SD_LT_SEPARATOR);
+ OUString aOldName(rOldLayoutName);
+ sal_Int32 nPos = aOldName.indexOf( aSep );
+
+ // erase everything after '~LT~'
+ if (nPos != -1)
+ aOldName = aOldName.copy(0, nPos + aSep.getLength());
+
+ std::vector<StyleReplaceData> aReplList;
+ SfxStyleSheetIterator aIter(mxStyleSheetPool.get(), SfxStyleFamily::Page);
+ SfxStyleSheetBase* pSheet = aIter.First();
+
+ while (pSheet)
+ {
+ OUString aSheetName = pSheet->GetName();
+
+ // if the sheetname starts with aOldName + "~LT~"
+ if (aSheetName.startsWith(aOldName))
+ {
+ aSheetName = aSheetName.replaceAt(0, aOldName.getLength() - aSep.getLength(), rNewName);
+
+ StyleReplaceData aReplData;
+ aReplData.nFamily = pSheet->GetFamily();
+ aReplData.nNewFamily = pSheet->GetFamily();
+ aReplData.aName = pSheet->GetName();
+ aReplData.aNewName = aSheetName;
+ aReplList.push_back(aReplData);
+
+ pSheet->SetName(aSheetName);
+ }
+
+ pSheet = aIter.Next();
+ }
+
+ // Now set the layout name of the drawing and the notes page, as well as
+ // their master pages.
+ OUString aPageLayoutName = rNewName + aSep + STR_LAYOUT_OUTLINE;
+
+ // Inform all text objects on pages that use the renamed layout and set the
+ // new name.
+ sal_uInt16 nPage;
+ for (nPage = 0; nPage < GetPageCount(); nPage++)
+ {
+ SdPage* pPage = static_cast<SdPage*>(GetPage(nPage));
+ OUString aTemp(pPage->GetLayoutName());
+
+ if (aTemp == rOldLayoutName)
+ {
+ pPage->SetLayoutName(aPageLayoutName);
+
+ for (size_t nObj = 0; nObj < pPage->GetObjCount(); ++nObj)
+ {
+ SdrObject* pObj = pPage->GetObj(nObj);
+
+ if (pObj->GetObjInventor() == SdrInventor::Default)
+ {
+ switch( pObj->GetObjIdentifier() )
+ {
+ case SdrObjKind::Text:
+ case SdrObjKind::OutlineText:
+ case SdrObjKind::TitleText:
+ {
+ OutlinerParaObject* pOPO = static_cast<SdrTextObj*>(pObj)->GetOutlinerParaObject();
+
+ if (pOPO)
+ {
+ for (const auto& rRepl : aReplList)
+ pOPO->ChangeStyleSheets( rRepl.aName, rRepl.nFamily, rRepl.aNewName, rRepl.nNewFamily );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Now do this again for all master pages.
+ // The affected master pages get the name of the layout as their page name.
+ for (nPage = 0; nPage < GetMasterPageCount(); nPage++)
+ {
+ SdPage* pPage = static_cast<SdPage*>( GetMasterPage(nPage) );
+ OUString aTemp(pPage->GetLayoutName());
+
+ if (aTemp == rOldLayoutName)
+ {
+ pPage->SetLayoutName(aPageLayoutName);
+ pPage->SetName(rNewName);
+
+ for (size_t nObj = 0; nObj < pPage->GetObjCount(); ++nObj)
+ {
+ SdrObject* pObj = pPage->GetObj(nObj);
+
+ if (pObj->GetObjInventor() == SdrInventor::Default)
+ {
+ switch(pObj->GetObjIdentifier())
+ {
+ case SdrObjKind::Text:
+ case SdrObjKind::OutlineText:
+ case SdrObjKind::TitleText:
+ {
+ OutlinerParaObject* pOPO = static_cast<SdrTextObj*>(pObj)->GetOutlinerParaObject();
+
+ if (pOPO)
+ {
+ for (const auto& rRepl : aReplList)
+ pOPO->ChangeStyleSheets( rRepl.aName, rRepl.nFamily, rRepl.aNewName, rRepl.nNewFamily );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+// Set outliner defaults (pool defaults)
+void SdDrawDocument::SetTextDefaults() const
+{
+ // BulletItem and BulletFont for Title and Outline
+ SvxBulletItem aBulletItem(EE_PARA_BULLET);
+ vcl::Font aBulletFont( SdStyleSheetPool::GetBulletFont() );
+ aBulletFont.SetFontSize(Size(0,846)); // 24 pt
+ aBulletItem.SetFont(aBulletFont);
+ aBulletItem.SetStyle(SvxBulletStyle::BULLET);
+ aBulletItem.SetStart(1);
+ aBulletItem.SetScale(45); // In percent
+ aBulletItem.SetSymbol( 0x25CF ); // In points
+ m_pItemPool->SetPoolDefaultItem( aBulletItem );
+
+ // New BulletItem
+ SvxNumberFormat aNumberFormat(SVX_NUM_CHAR_SPECIAL);
+ aNumberFormat.SetBulletFont(&aBulletFont);
+ aNumberFormat.SetBulletChar( 0x25CF ); // StarBats: 0xF000 + 34
+ aNumberFormat.SetBulletRelSize(45);
+ aNumberFormat.SetBulletColor(COL_AUTO);
+ aNumberFormat.SetStart(1);
+ aNumberFormat.SetNumAdjust(SvxAdjust::Left);
+
+ SvxNumRule aNumRule( SvxNumRuleFlags::BULLET_REL_SIZE | SvxNumRuleFlags::BULLET_COLOR, SVX_MAX_NUM, false);
+
+ //aNumberFormat.SetAbsLSpace( 0 );
+ //aNumberFormat.SetFirstLineOffset( 0 );
+ //aNumRule.SetLevel( 0, aNumberFormat );
+
+ for( sal_uInt16 i = 0; i < aNumRule.GetLevelCount(); i++ )
+ {
+ const auto nLSpace = (i + 1) * 600;
+ aNumberFormat.SetAbsLSpace(nLSpace);
+ aNumberFormat.SetFirstLineOffset(-600);
+ aNumRule.SetLevel( i, aNumberFormat );
+ }
+
+ SvxNumBulletItem aNumBulletItem( std::move(aNumRule), EE_PARA_NUMBULLET );
+ m_pItemPool->SetPoolDefaultItem( aNumBulletItem );
+}
+
+css::text::WritingMode SdDrawDocument::GetDefaultWritingMode() const
+{
+ const SfxPoolItem* pItem = ( m_pItemPool ? m_pItemPool->GetPoolDefaultItem( EE_PARA_WRITINGDIR ) : nullptr );
+ css::text::WritingMode eRet = css::text::WritingMode_LR_TB;
+
+ if( pItem )
+ {
+ switch( static_cast<const SvxFrameDirectionItem&>( *pItem ).GetValue() )
+ {
+ case SvxFrameDirection::Horizontal_LR_TB: eRet = css::text::WritingMode_LR_TB; break;
+ case SvxFrameDirection::Horizontal_RL_TB: eRet = css::text::WritingMode_RL_TB; break;
+ case SvxFrameDirection::Vertical_RL_TB: eRet = css::text::WritingMode_TB_RL; break;
+
+ default:
+ OSL_FAIL( "Frame direction not supported yet" );
+ break;
+ }
+ }
+
+ return eRet;
+}
+
+void SdDrawDocument::SetDefaultWritingMode(css::text::WritingMode eMode )
+{
+ if( !m_pItemPool )
+ return;
+
+ SvxFrameDirection nVal;
+ switch( eMode )
+ {
+ case css::text::WritingMode_LR_TB: nVal = SvxFrameDirection::Horizontal_LR_TB; break;
+ case css::text::WritingMode_RL_TB: nVal = SvxFrameDirection::Horizontal_RL_TB; break;
+ case css::text::WritingMode_TB_RL: nVal = SvxFrameDirection::Vertical_RL_TB; break;
+ default:
+ OSL_FAIL( "Frame direction not supported yet" );
+ return;
+ }
+
+ SvxFrameDirectionItem aModeItem( nVal, EE_PARA_WRITINGDIR );
+ m_pItemPool->SetPoolDefaultItem( aModeItem );
+
+ SvxAdjustItem aAdjust( SvxAdjust::Left, EE_PARA_JUST );
+
+ if( eMode == css::text::WritingMode_RL_TB )
+ aAdjust.SetAdjust( SvxAdjust::Right );
+
+ m_pItemPool->SetPoolDefaultItem( aAdjust );
+}
+
+void SdDrawDocument::getDefaultFonts( vcl::Font& rLatinFont, vcl::Font& rCJKFont, vcl::Font& rCTLFont )
+{
+ LanguageType eLatin = GetLanguage( EE_CHAR_LANGUAGE );
+
+ // If the UI language is Korean, the default Latin font has to
+ // be queried for Korean, too (the Latin language from the document can't be Korean).
+ // This is the same logic as in SwDocShell::InitNew.
+ LanguageType eUiLanguage = Application::GetSettings().GetUILanguageTag().getLanguageType();
+ if (MsLangId::isKorean(eUiLanguage))
+ eLatin = eUiLanguage;
+
+ rLatinFont = OutputDevice::GetDefaultFont( DefaultFontType::LATIN_PRESENTATION, eLatin, GetDefaultFontFlags::OnlyOne );
+ rCJKFont = OutputDevice::GetDefaultFont( DefaultFontType::CJK_PRESENTATION, GetLanguage( EE_CHAR_LANGUAGE_CJK ), GetDefaultFontFlags::OnlyOne );
+ rCTLFont = OutputDevice::GetDefaultFont( DefaultFontType::CTL_PRESENTATION, GetLanguage( EE_CHAR_LANGUAGE_CTL ), GetDefaultFontFlags::OnlyOne ) ;
+}
+
+/* converts the given western font height to a corresponding ctl font height, depending on the system language */
+sal_uInt32 SdDrawDocument::convertFontHeightToCTL( sal_uInt32 nWesternFontHeight )
+{
+ LanguageType eRealCTLLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
+ if( LANGUAGE_THAI == eRealCTLLanguage )
+ {
+ // http://specs.openoffice.org/g11n/font_sizes/42775_42725_Individual_configurable_font_size_for_default_fonts.odt
+ double fTemp = double(nWesternFontHeight) * 1.333;
+ nWesternFontHeight = static_cast<sal_uInt32>(fTemp);
+ // make some nice values for UI that displays PT instead of 1/100th mm
+ nWesternFontHeight = convertPointToMm100(convertMm100ToPoint(nWesternFontHeight));
+ }
+ return nWesternFontHeight;
+}
+
+SdStyleSheetPool* SdDrawDocument::GetSdStyleSheetPool() const
+{
+ return dynamic_cast< SdStyleSheetPool* >( GetStyleSheetPool() );
+}
+
+ModifyGuard::ModifyGuard( SdDrawDocument* pDoc )
+: mpDocShell( nullptr ), mpDoc( pDoc )
+{
+ init();
+}
+
+void ModifyGuard::init()
+{
+ if( mpDocShell )
+ {
+ mpDoc = mpDocShell->GetDoc();
+ }
+ else if( mpDoc )
+ {
+ mpDocShell = mpDoc->GetDocSh();
+ }
+
+ mbIsEnableSetModified = mpDocShell && mpDocShell->IsEnableSetModified();
+ mbIsDocumentChanged = mpDoc && mpDoc->IsChanged();
+
+ if( mbIsEnableSetModified )
+ mpDocShell->EnableSetModified( false );
+}
+
+ModifyGuard::~ModifyGuard()
+{
+ if( mbIsEnableSetModified )
+ mpDocShell->EnableSetModified();
+
+ if( mpDoc && (mpDoc->IsChanged() != mbIsDocumentChanged) )
+ mpDoc->SetChanged(mbIsDocumentChanged);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/drawdoc_animations.cxx b/sd/source/core/drawdoc_animations.cxx
new file mode 100644
index 000000000..b7f1bd557
--- /dev/null
+++ b/sd/source/core/drawdoc_animations.cxx
@@ -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 .
+ */
+
+#include <sal/config.h>
+
+#include <createpresentation.hxx>
+#include <drawdoc.hxx>
+#include <cusshow.hxx>
+#include <customshowlist.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::presentation;
+
+/** replaces a slide from all custom shows with a new one or removes a slide from
+ all custom shows if pNewPage is 0.
+*/
+void SdDrawDocument::ReplacePageInCustomShows(const SdPage* pOldPage, const SdPage* pNewPage)
+{
+ if (mpCustomShowList)
+ {
+ for (size_t i = 0; i < mpCustomShowList->size(); i++)
+ {
+ SdCustomShow* pCustomShow = (*mpCustomShowList)[i].get();
+ pCustomShow->ReplacePage(pOldPage, pNewPage);
+ }
+ }
+}
+
+const Reference<XPresentation2>& SdDrawDocument::getPresentation() const
+{
+ if (!mxPresentation.is())
+ {
+ const_cast<SdDrawDocument*>(this)->mxPresentation = CreatePresentation(*this);
+ }
+ return mxPresentation;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/pglink.cxx b/sd/source/core/pglink.cxx
new file mode 100644
index 000000000..358012df9
--- /dev/null
+++ b/sd/source/core/pglink.cxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/linkmgr.hxx>
+
+#include <pglink.hxx>
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+
+/*************************************************************************
+|*
+|* Ctor
+|*
+\************************************************************************/
+
+SdPageLink::SdPageLink(SdPage* pPg, const OUString& rFileName,
+ const OUString& rBookmarkName) :
+ ::sfx2::SvBaseLink( ::SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SIMPLE_FILE),
+ pPage(pPg)
+{
+ pPage->SetFileName(rFileName);
+ pPage->SetBookmarkName(rBookmarkName);
+}
+
+/*************************************************************************
+|*
+|* Dtor
+|*
+\************************************************************************/
+
+SdPageLink::~SdPageLink()
+{
+}
+
+/*************************************************************************
+|*
+|* Date have changed
+|*
+\************************************************************************/
+
+::sfx2::SvBaseLink::UpdateResult SdPageLink::DataChanged(
+ const OUString&, const css::uno::Any& )
+{
+ SdDrawDocument* pDoc = static_cast<SdDrawDocument*>( &pPage->getSdrModelFromSdrPage() );
+ sfx2::LinkManager* pLinkManager = pDoc!=nullptr ? pDoc->GetLinkManager() : nullptr;
+
+ if (pLinkManager)
+ {
+ /**********************************************************************
+ * Only standard pages are allowed to be linked
+ * The corresponding note pages are updated automatically
+ **********************************************************************/
+ OUString aFileName;
+ OUString aBookmarkName;
+ OUString aFilterName;
+ sfx2::LinkManager::GetDisplayNames( this,nullptr, &aFileName, &aBookmarkName,
+ &aFilterName);
+ pPage->SetFileName(aFileName);
+ pPage->SetBookmarkName(aBookmarkName);
+
+ SdDrawDocument* pBookmarkDoc = pDoc->OpenBookmarkDoc(aFileName);
+
+ if (pBookmarkDoc)
+ {
+ /******************************************************************
+ * the linked page is replaced in the model
+ ******************************************************************/
+ if (aBookmarkName.isEmpty())
+ {
+ // no page name specified: we assume it is the first page
+ aBookmarkName = pBookmarkDoc->GetSdPage(0, PageKind::Standard)->GetName();
+ pPage->SetBookmarkName(aBookmarkName);
+ }
+
+ std::vector<OUString> aBookmarkList { aBookmarkName };
+ sal_uInt16 nInsertPos = pPage->GetPageNum();
+ bool bNoDialogs = false;
+ bool bCopy = false;
+
+ if (SdDrawDocument::s_pDocLockedInsertingLinks)
+ {
+ // resolving links while loading pDoc
+ bNoDialogs = true;
+ bCopy = true;
+ }
+
+ pDoc->InsertBookmarkAsPage(aBookmarkList, nullptr, true/*bLink*/, true/*bReplace*/,
+ nInsertPos, bNoDialogs, nullptr, bCopy, true, true);
+
+ if (!SdDrawDocument::s_pDocLockedInsertingLinks)
+ pDoc->CloseBookmarkDoc();
+ }
+ }
+ return SUCCESS;
+}
+
+/*************************************************************************
+|*
+|* Connect or disconnect link
+|*
+\************************************************************************/
+
+void SdPageLink::Closed()
+{
+ // the connection is closed
+ pPage->SetFileName(OUString());
+ pPage->SetBookmarkName(OUString());
+
+ SvBaseLink::Closed();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/sdiocmpt.cxx b/sd/source/core/sdiocmpt.cxx
new file mode 100644
index 000000000..67de6a64d
--- /dev/null
+++ b/sd/source/core/sdiocmpt.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 <tools/debug.hxx>
+
+#include <sdiocmpt.hxx>
+
+old_SdrDownCompat::old_SdrDownCompat(SvStream& rNewStream, StreamMode nNewMode)
+: rStream(rNewStream),
+ nSubRecSiz(0),
+ nSubRecPos(0),
+ nMode(nNewMode),
+ bOpen(false)
+{
+ OpenSubRecord();
+}
+
+old_SdrDownCompat::~old_SdrDownCompat()
+{
+ if(bOpen)
+ CloseSubRecord();
+}
+
+void old_SdrDownCompat::Write()
+{
+ rStream.WriteUInt32( nSubRecSiz );
+}
+
+void old_SdrDownCompat::OpenSubRecord()
+{
+ if(rStream.GetError())
+ return;
+
+ nSubRecPos = rStream.Tell();
+
+ if(nMode == StreamMode::READ)
+ {
+ rStream.ReadUInt32( nSubRecSiz );
+ }
+ else if(nMode == StreamMode::WRITE)
+ {
+ Write();
+ }
+
+ bOpen = true;
+}
+
+void old_SdrDownCompat::CloseSubRecord()
+{
+ if(rStream.GetError())
+ return;
+
+ sal_uInt32 nCurrentPos(rStream.Tell());
+
+ if(nMode == StreamMode::READ)
+ {
+ sal_uInt32 nReadCnt(nCurrentPos - nSubRecPos);
+ if(nReadCnt != nSubRecSiz)
+ {
+ rStream.Seek(nSubRecPos + nSubRecSiz);
+ }
+ }
+ else if(nMode == StreamMode::WRITE)
+ {
+ nSubRecSiz = nCurrentPos - nSubRecPos;
+ rStream.Seek(nSubRecPos);
+ Write();
+ rStream.Seek(nCurrentPos);
+ }
+
+ bOpen = false;
+}
+
+/*************************************************************************
+|*
+|* Constructor, writes and reads version number
+|*
+\************************************************************************/
+
+SdIOCompat::SdIOCompat(SvStream& rNewStream, StreamMode nNewMode, sal_uInt16 nVersion)
+: old_SdrDownCompat(rNewStream, nNewMode)
+{
+ if (nNewMode == StreamMode::WRITE)
+ {
+ DBG_ASSERT(nVersion != SDIOCOMPAT_VERSIONDONTKNOW,
+ "can't write unknown version");
+ rNewStream.WriteUInt16( nVersion );
+ }
+ else if (nNewMode == StreamMode::READ)
+ {
+ DBG_ASSERT(nVersion == SDIOCOMPAT_VERSIONDONTKNOW,
+ "referring to the version while reading is silly!");
+ rNewStream.ReadUInt16( nVersion );
+ }
+}
+
+SdIOCompat::~SdIOCompat()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/sdpage.cxx b/sd/source/core/sdpage.cxx
new file mode 100644
index 000000000..38318f294
--- /dev/null
+++ b/sd/source/core/sdpage.cxx
@@ -0,0 +1,3157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <algorithm>
+#include <array>
+
+#include <comphelper/classids.hxx>
+#include <comphelper/embeddedobjectcontainer.hxx>
+
+#include <sfx2/viewsh.hxx>
+#include <vcl/svapp.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/bulletitem.hxx>
+#include <svx/svdpagv.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdopage.hxx>
+#include <editeng/pbinitem.hxx>
+#include <svx/svdundo.hxx>
+#include <svl/hint.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/editobj.hxx>
+#include <svx/unopage.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdlayer.hxx>
+#include <svx/sdtmfitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/sdtcfitm.hxx>
+#include <svx/xfillit0.hxx>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/animations/XAnimationNode.hpp>
+#include <com/sun/star/animations/XTimeContainer.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XNodeList.hpp>
+#include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <o3tl/enumarray.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/sorted_vector.hxx>
+#include <xmloff/autolayout.hxx>
+
+#include <Outliner.hxx>
+#include <app.hrc>
+#include <createunopageimpl.hxx>
+#include <drawdoc.hxx>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <stlsheet.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <bitmaps.hlst>
+#include <glob.hxx>
+#include <anminfo.hxx>
+#include <undo/undomanager.hxx>
+#include <undo/undoobjects.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/unoapi.hxx>
+#include <unokywds.hxx>
+
+using namespace ::sd;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace com::sun::star::xml::dom;
+using ::com::sun::star::uno::Reference;
+
+
+sal_uInt16 SdPage::mnLastPageId = 1;
+
+/*************************************************************************
+|*
+|* Ctor
+|*
+\************************************************************************/
+
+SdPage::SdPage(SdDrawDocument& rNewDoc, bool bMasterPage)
+: FmFormPage(rNewDoc, bMasterPage)
+, SdrObjUserCall()
+, mePageKind(PageKind::Standard)
+, meAutoLayout(AUTOLAYOUT_NONE)
+, mbSelected(false)
+, mePresChange(PresChange::Manual)
+, mfTime(1.0)
+, mbSoundOn(false)
+, mbExcluded(false)
+, mbLoopSound(false)
+, mbStopSound(false)
+, mbScaleObjects(true)
+, meCharSet(osl_getThreadTextEncoding())
+, mnPaperBin(PAPERBIN_PRINTER_SETTINGS)
+, mpPageLink(nullptr)
+, mnTransitionType(0)
+, mnTransitionSubtype(0)
+, mbTransitionDirection(true)
+, mnTransitionFadeColor(0)
+, mfTransitionDuration(2.0)
+, mbIsPrecious(true)
+, mnPageId(mnLastPageId++)
+{
+ // The name of the layout of the page is used by SVDRAW to determine the
+ // presentation template of the outline objects. Therefore, it already
+ // contains the designator for the outline (STR_LAYOUT_OUTLINE).
+ maLayoutName = SdResId(STR_LAYOUT_DEFAULT_NAME)+ SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE;
+
+ // Stuff that former SetModel did also:
+ ConnectLink();
+}
+
+namespace
+{
+ void clearChildNodes(css::uno::Reference<css::animations::XAnimationNode> const & rAnimationNode)
+ {
+ css::uno::Reference<css::container::XEnumerationAccess > xEnumerationAccess(rAnimationNode, UNO_QUERY);
+ if (!xEnumerationAccess.is())
+ return;
+ css::uno::Reference<css::container::XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
+ if (!xEnumeration.is())
+ return;
+ while (xEnumeration->hasMoreElements())
+ {
+ css::uno::Reference<css::animations::XAnimationNode> xChildNode(xEnumeration->nextElement(), UNO_QUERY);
+ if (!xChildNode.is())
+ continue;
+ clearChildNodes(xChildNode);
+ css::uno::Reference<css::animations::XTimeContainer> xAnimationNode(rAnimationNode, UNO_QUERY);
+ if (!xAnimationNode.is())
+ {
+ SAL_WARN("sd.core", "can't remove node child, possible leak");
+ continue;
+ }
+ xAnimationNode->removeChild(xChildNode);
+ }
+ }
+}
+
+/*************************************************************************
+|*
+|* Dtor
+|*
+\************************************************************************/
+
+SdPage::~SdPage()
+{
+ DisconnectLink();
+
+ EndListenOutlineText();
+
+ clearChildNodes(mxAnimationNode);
+
+ // disconnect the UserCall link
+ SdrObjListIter aIter( this, SdrIterMode::DeepWithGroups );
+ while( aIter.IsMore() )
+ {
+ SdrObject* pChild = aIter.Next();
+ if( pChild->GetUserCall() == this )
+ pChild->SetUserCall(nullptr);
+ }
+
+ // clear SdrObjects with broadcasting
+ ClearSdrObjList();
+}
+
+namespace {
+
+struct OrdNumSorter
+{
+ bool operator()( SdrObject const * p1, SdrObject const * p2 )
+ {
+ return p1->GetOrdNum() < p2->GetOrdNum();
+ }
+};
+
+}
+
+/** returns the nIndex'th object from the given PresObjKind, index starts with 1 */
+SdrObject* SdPage::GetPresObj(PresObjKind eObjKind, int nIndex, bool bFuzzySearch /* = false */ )
+{
+ // first sort all matching shapes with z-order
+ std::vector< SdrObject* > aMatches;
+
+ SdrObject* pObj = nullptr;
+ maPresentationShapeList.seekShape(0);
+
+ while( (pObj = maPresentationShapeList.getNextShape()) )
+ {
+ SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pObj);
+ if( pInfo )
+ {
+ bool bFound = false;
+ if( pInfo->mePresObjKind == eObjKind )
+ {
+ bFound = true;
+ }
+ else if( bFuzzySearch && (eObjKind == PresObjKind::Outline) )
+ {
+ switch( pInfo->mePresObjKind )
+ {
+ case PresObjKind::Graphic:
+ case PresObjKind::Object:
+ case PresObjKind::Chart:
+ case PresObjKind::OrgChart:
+ case PresObjKind::Table:
+ case PresObjKind::Calc:
+ case PresObjKind::Media:
+ bFound = true;
+ break;
+ default:
+ break;
+ }
+ }
+ if( bFound )
+ {
+ aMatches.push_back( pObj );
+ }
+ }
+ }
+
+ if( nIndex > 0 )
+ nIndex--;
+
+ if( (nIndex >= 0) && ( aMatches.size() > o3tl::make_unsigned(nIndex)) )
+ {
+ if( aMatches.size() > 1 )
+ std::nth_element( aMatches.begin(), aMatches.begin() + nIndex, aMatches.end(),
+ OrdNumSorter() );
+ return aMatches[nIndex];
+ }
+
+ return nullptr;
+}
+
+/** create background properties */
+void SdPage::EnsureMasterPageDefaultBackground()
+{
+ if(!mbMaster)
+ return;
+
+ // no hard attributes on MasterPage attributes
+ getSdrPageProperties().ClearItem();
+ SfxStyleSheet* pSheetForPresObj = GetStyleSheetForMasterPageBackground();
+
+ if(pSheetForPresObj)
+ {
+ // set StyleSheet for background fill attributes
+ getSdrPageProperties().SetStyleSheet(pSheetForPresObj);
+ }
+ else
+ {
+ // no style found, assert and set at least drawing::FillStyle_NONE
+ OSL_FAIL("No Style for MasterPageBackground fill found (!)");
+ getSdrPageProperties().PutItem(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+}
+
+/** creates a presentation object with the given PresObjKind on this page. A user call will be set
+*/
+SdrObject* SdPage::CreatePresObj(PresObjKind eObjKind, bool bVertical, const ::tools::Rectangle& rRect )
+{
+ SfxUndoManager* pUndoManager(static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetUndoManager());
+ const bool bUndo = pUndoManager && pUndoManager->IsInListAction() && IsInserted();
+
+ SdrObject* pSdrObj = nullptr;
+
+ bool bForceText = false; // forces the shape text to be set even if it's empty
+ bool bEmptyPresObj = true;
+
+ switch( eObjKind )
+ {
+ case PresObjKind::Title:
+ {
+ pSdrObj = new SdrRectObj(getSdrModelFromSdrPage(), SdrObjKind::TitleText);
+
+ if (mbMaster)
+ {
+ pSdrObj->SetNotVisibleAsMaster(true);
+ }
+ }
+ break;
+
+ case PresObjKind::Outline:
+ {
+ pSdrObj = new SdrRectObj(getSdrModelFromSdrPage(), SdrObjKind::OutlineText);
+
+ if (mbMaster)
+ {
+ pSdrObj->SetNotVisibleAsMaster(true);
+ }
+ }
+ break;
+
+ case PresObjKind::Notes:
+ {
+ pSdrObj = new SdrRectObj(getSdrModelFromSdrPage(), SdrObjKind::Text);
+
+ if (mbMaster)
+ {
+ pSdrObj->SetNotVisibleAsMaster(true);
+ }
+ }
+ break;
+
+ case PresObjKind::Text:
+ {
+ pSdrObj = new SdrRectObj(getSdrModelFromSdrPage(), SdrObjKind::Text);
+ }
+ break;
+
+ case PresObjKind::Graphic:
+ {
+ BitmapEx aBmpEx(BMP_PRESOBJ_GRAPHIC);
+ Graphic aGraphic( aBmpEx );
+ OutputDevice &aOutDev = *Application::GetDefaultDevice();
+ aOutDev.Push();
+
+ aOutDev.SetMapMode( aGraphic.GetPrefMapMode() );
+ Size aSizePix = aOutDev.LogicToPixel( aGraphic.GetPrefSize() );
+ aOutDev.SetMapMode(MapMode(MapUnit::Map100thMM));
+
+ Size aSize = aOutDev.PixelToLogic(aSizePix);
+ Point aPnt (0, 0);
+ ::tools::Rectangle aRect (aPnt, aSize);
+ pSdrObj = new SdrGrafObj(getSdrModelFromSdrPage(), aGraphic, aRect);
+ aOutDev.Pop();
+ }
+ break;
+
+ case PresObjKind::Media:
+ case PresObjKind::Object:
+ {
+ pSdrObj = new SdrOle2Obj(getSdrModelFromSdrPage());
+ BitmapEx aBmpEx(BMP_PRESOBJ_OBJECT);
+ Graphic aGraphic( aBmpEx );
+ static_cast<SdrOle2Obj*>(pSdrObj)->SetGraphic(aGraphic);
+ }
+ break;
+
+ case PresObjKind::Chart:
+ {
+ pSdrObj = new SdrOle2Obj(getSdrModelFromSdrPage());
+ static_cast<SdrOle2Obj*>(pSdrObj)->SetProgName( "StarChart" );
+ BitmapEx aBmpEx(BMP_PRESOBJ_CHART);
+ Graphic aGraphic( aBmpEx );
+ static_cast<SdrOle2Obj*>(pSdrObj)->SetGraphic(aGraphic);
+ }
+ break;
+
+ case PresObjKind::OrgChart:
+ {
+ pSdrObj = new SdrOle2Obj(getSdrModelFromSdrPage());
+ static_cast<SdrOle2Obj*>(pSdrObj)->SetProgName( "StarOrg" );
+ BitmapEx aBmpEx(BMP_PRESOBJ_ORGCHART);
+ Graphic aGraphic( aBmpEx );
+ static_cast<SdrOle2Obj*>(pSdrObj)->SetGraphic(aGraphic);
+ }
+ break;
+
+ case PresObjKind::Table:
+ case PresObjKind::Calc:
+ {
+ pSdrObj = new SdrOle2Obj(getSdrModelFromSdrPage());
+ static_cast<SdrOle2Obj*>(pSdrObj)->SetProgName( "StarCalc" );
+ BitmapEx aBmpEx(BMP_PRESOBJ_TABLE);
+ Graphic aGraphic( aBmpEx );
+ static_cast<SdrOle2Obj*>(pSdrObj)->SetGraphic(aGraphic);
+ }
+ break;
+
+ case PresObjKind::Handout:
+ {
+ // Save the first standard page at SdrPageObj
+ // #i105146# We want no content to be displayed for PageKind::Handout,
+ // so just never set a page as content
+ pSdrObj = new SdrPageObj(getSdrModelFromSdrPage(), nullptr);
+ }
+ break;
+
+ case PresObjKind::Page:
+ {
+ // Save note pages at SdrPageObj
+ sal_uInt16 nDestPageNum(GetPageNum());
+
+ if(nDestPageNum)
+ {
+ // decrement only when != 0, else we get a 0xffff
+ nDestPageNum -= 1;
+ }
+
+ if (nDestPageNum < getSdrModelFromSdrPage().GetPageCount())
+ {
+ pSdrObj = new SdrPageObj(getSdrModelFromSdrPage(), getSdrModelFromSdrPage().GetPage(nDestPageNum));
+ }
+ else
+ {
+ pSdrObj = new SdrPageObj(getSdrModelFromSdrPage());
+ }
+
+ pSdrObj->SetResizeProtect(true);
+ }
+ break;
+
+ case PresObjKind::Header:
+ case PresObjKind::Footer:
+ case PresObjKind::DateTime:
+ case PresObjKind::SlideNumber:
+ {
+ pSdrObj = new SdrRectObj(getSdrModelFromSdrPage(), SdrObjKind::Text);
+ bEmptyPresObj = false;
+ bForceText = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (pSdrObj)
+ {
+ pSdrObj->SetEmptyPresObj(bEmptyPresObj);
+ pSdrObj->SetLogicRect(rRect);
+
+ InsertObject(pSdrObj);
+
+ if ( auto pTextObj = dynamic_cast<SdrTextObj *>( pSdrObj ) )
+ {
+ // Tell the object EARLY that it is vertical to have the
+ // defaults for AutoGrowWidth/Height reversed
+ if(bVertical)
+ pTextObj->SetVerticalWriting(true);
+
+ SfxItemSet aTempAttr(static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetPool());
+ if( bVertical )
+ aTempAttr.Put( makeSdrTextMinFrameWidthItem( rRect.GetSize().Width() ) );
+ else
+ aTempAttr.Put( makeSdrTextMinFrameHeightItem( rRect.GetSize().Height() ) );
+
+ if (mbMaster)
+ {
+ // The size of presentation objects on the master page have to
+ // be freely selectable by the user.
+
+ // potential problem: This action was still NOT
+ // adapted for vertical text. This sure needs to be done.
+ if(bVertical)
+ aTempAttr.Put(makeSdrTextAutoGrowWidthItem(false));
+ else
+ aTempAttr.Put(makeSdrTextAutoGrowHeightItem(false));
+ }
+
+ // check if we need another vertical adjustment than the default
+ SdrTextVertAdjust eV = SDRTEXTVERTADJUST_TOP;
+
+ if( (eObjKind == PresObjKind::Footer) && (mePageKind != PageKind::Standard) )
+ {
+ eV = SDRTEXTVERTADJUST_BOTTOM;
+ }
+ else if( (eObjKind == PresObjKind::SlideNumber) && (mePageKind != PageKind::Standard) )
+ {
+ eV = SDRTEXTVERTADJUST_BOTTOM;
+ }
+
+ if( eV != SDRTEXTVERTADJUST_TOP )
+ aTempAttr.Put(SdrTextVertAdjustItem(eV));
+
+ pSdrObj->SetMergedItemSet(aTempAttr);
+
+ pSdrObj->SetLogicRect(rRect);
+ }
+
+ OUString aString = GetPresObjText(eObjKind);
+ if(!aString.isEmpty() || bForceText)
+ if (auto pTextObj = dynamic_cast<SdrTextObj *>( pSdrObj ) )
+ {
+ SdrOutliner* pOutliner = static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetInternalOutliner();
+
+ OutlinerMode nOutlMode = pOutliner->GetOutlinerMode();
+ pOutliner->Init( OutlinerMode::TextObject );
+ pOutliner->SetStyleSheet( 0, nullptr );
+ pOutliner->SetVertical( bVertical );
+
+ SetObjText( pTextObj, pOutliner, eObjKind, aString );
+
+ pOutliner->Init( nOutlMode );
+ pOutliner->SetStyleSheet( 0, nullptr );
+ }
+
+ if( (eObjKind == PresObjKind::Header) || (eObjKind == PresObjKind::Footer) || (eObjKind == PresObjKind::SlideNumber) || (eObjKind == PresObjKind::DateTime) )
+ {
+ SfxItemSet aTempAttr(static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetPool());
+ aTempAttr.Put( SvxFontHeightItem( 493, 100, EE_CHAR_FONTHEIGHT ) );
+ aTempAttr.Put( SvxFontHeightItem( 493, 100, EE_CHAR_FONTHEIGHT_CTL ) );
+ aTempAttr.Put( SvxFontHeightItem( 493, 100, EE_CHAR_FONTHEIGHT_CJK ) );
+
+ SvxAdjust eH = SvxAdjust::Left;
+
+ if( (eObjKind == PresObjKind::DateTime) && (mePageKind != PageKind::Standard ) )
+ {
+ eH = SvxAdjust::Right;
+ }
+ else if( (eObjKind == PresObjKind::Footer) && (mePageKind == PageKind::Standard ) )
+ {
+ eH = SvxAdjust::Center;
+ }
+ else if( eObjKind == PresObjKind::SlideNumber )
+ {
+ eH = SvxAdjust::Right;
+ }
+
+ if( eH != SvxAdjust::Left )
+ aTempAttr.Put(SvxAdjustItem(eH, EE_PARA_JUST ));
+
+ pSdrObj->SetMergedItemSet(aTempAttr);
+ }
+
+ if (mbMaster)
+ {
+ SdrLayerAdmin& rLayerAdmin(getSdrModelFromSdrPage().GetLayerAdmin());
+
+ // background objects of the master page
+ pSdrObj->SetLayer( rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects) );
+ }
+
+ // Subscribe object at the style sheet
+ // Set style only when one was found (as in 5.2)
+ if( mePageKind != PageKind::Handout )
+ {
+ SfxStyleSheet* pSheetForPresObj = GetStyleSheetForPresObj(eObjKind);
+ if(pSheetForPresObj)
+ pSdrObj->SetStyleSheet(pSheetForPresObj, false);
+ }
+
+ if (eObjKind == PresObjKind::Outline)
+ {
+ for (sal_uInt16 nLevel = 1; nLevel < 10; nLevel++)
+ {
+ OUString aName( maLayoutName + " " + OUString::number( nLevel ) );
+ SfxStyleSheet* pSheet = static_cast<SfxStyleSheet*>(getSdrModelFromSdrPage().GetStyleSheetPool()->Find(aName, SfxStyleFamily::Page));
+ DBG_ASSERT(pSheet, "StyleSheet for outline object not found");
+ if (pSheet)
+ pSdrObj->StartListening(*pSheet, DuplicateHandling::Allow);
+ }
+ }
+
+ if ( eObjKind == PresObjKind::Object ||
+ eObjKind == PresObjKind::Chart ||
+ eObjKind == PresObjKind::OrgChart ||
+ eObjKind == PresObjKind::Calc ||
+ eObjKind == PresObjKind::Graphic )
+ {
+ SfxItemSet aSet( static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetPool() );
+ aSet.Put( makeSdrTextContourFrameItem( true ) );
+ aSet.Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
+
+ pSdrObj->SetMergedItemSet(aSet);
+ }
+
+ if( bUndo )
+ {
+ pUndoManager->AddUndoAction(getSdrModelFromSdrPage().GetSdrUndoFactory().CreateUndoNewObject(*pSdrObj));
+
+ pUndoManager->AddUndoAction( std::make_unique<UndoObjectPresentationKind>( *pSdrObj ) );
+ pUndoManager->AddUndoAction( std::make_unique<UndoObjectUserCall>(*pSdrObj) );
+ }
+
+ InsertPresObj(pSdrObj, eObjKind);
+ pSdrObj->SetUserCall(this);
+
+ pSdrObj->RecalcBoundRect();
+ }
+
+ return pSdrObj;
+}
+
+/*************************************************************************
+|*
+|* Creates presentation objects on the master page.
+|* All presentation objects get a UserCall to the page.
+|*
+\************************************************************************/
+
+SfxStyleSheet* SdPage::GetStyleSheetForMasterPageBackground() const
+{
+ OUString aName(GetLayoutName());
+ OUString aSep( SD_LT_SEPARATOR );
+ sal_Int32 nPos = aName.indexOf(aSep);
+
+ if (nPos != -1)
+ {
+ nPos = nPos + aSep.getLength();
+ aName = aName.copy(0, nPos);
+ }
+
+ aName += STR_LAYOUT_BACKGROUND;
+
+ SfxStyleSheetBasePool* pStShPool = getSdrModelFromSdrPage().GetStyleSheetPool();
+ SfxStyleSheetBase* pResult = pStShPool->Find(aName, SfxStyleFamily::Page);
+ return static_cast<SfxStyleSheet*>(pResult);
+}
+
+SfxStyleSheet* SdPage::GetStyleSheetForPresObj(PresObjKind eObjKind) const
+{
+ OUString aName(GetLayoutName());
+ OUString aSep( SD_LT_SEPARATOR );
+ sal_Int32 nPos = aName.indexOf(aSep);
+ if (nPos != -1)
+ {
+ nPos = nPos + aSep.getLength();
+ aName = aName.copy(0, nPos);
+ }
+
+ switch (eObjKind)
+ {
+ case PresObjKind::Outline:
+ {
+ aName = GetLayoutName() + " " + OUString::number( 1 );
+ }
+ break;
+
+ case PresObjKind::Title:
+ aName += STR_LAYOUT_TITLE;
+ break;
+
+ case PresObjKind::Notes:
+ aName += STR_LAYOUT_NOTES;
+ break;
+
+ case PresObjKind::Text:
+ aName += STR_LAYOUT_SUBTITLE;
+ break;
+
+ case PresObjKind::Header:
+ case PresObjKind::Footer:
+ case PresObjKind::DateTime:
+ case PresObjKind::SlideNumber:
+ aName += STR_LAYOUT_BACKGROUNDOBJECTS;
+ break;
+
+ default:
+ break;
+ }
+
+ SfxStyleSheetBasePool* pStShPool = getSdrModelFromSdrPage().GetStyleSheetPool();
+ SfxStyleSheetBase* pResult = pStShPool->Find(aName, SfxStyleFamily::Page);
+ return static_cast<SfxStyleSheet*>(pResult);
+}
+
+/** returns the presentation style with the given helpid from this masterpage or this
+ slides masterpage */
+SdStyleSheet* SdPage::getPresentationStyle( sal_uInt32 nHelpId ) const
+{
+ OUString aStyleName( GetLayoutName() );
+ const OUString aSep( SD_LT_SEPARATOR );
+ sal_Int32 nIndex = aStyleName.indexOf(aSep);
+ if( nIndex != -1 )
+ aStyleName = aStyleName.copy(0, nIndex + aSep.getLength());
+
+ OUString pNameId;
+ bool bOutline = false;
+ switch( nHelpId )
+ {
+ case HID_PSEUDOSHEET_TITLE: pNameId = STR_LAYOUT_TITLE; break;
+ case HID_PSEUDOSHEET_SUBTITLE: pNameId = STR_LAYOUT_SUBTITLE; break;
+ case HID_PSEUDOSHEET_OUTLINE1:
+ case HID_PSEUDOSHEET_OUTLINE2:
+ case HID_PSEUDOSHEET_OUTLINE3:
+ case HID_PSEUDOSHEET_OUTLINE4:
+ case HID_PSEUDOSHEET_OUTLINE5:
+ case HID_PSEUDOSHEET_OUTLINE6:
+ case HID_PSEUDOSHEET_OUTLINE7:
+ case HID_PSEUDOSHEET_OUTLINE8:
+ case HID_PSEUDOSHEET_OUTLINE9: pNameId = STR_LAYOUT_OUTLINE; bOutline = true; break;
+ case HID_PSEUDOSHEET_BACKGROUNDOBJECTS: pNameId = STR_LAYOUT_BACKGROUNDOBJECTS; break;
+ case HID_PSEUDOSHEET_BACKGROUND: pNameId = STR_LAYOUT_BACKGROUND; break;
+ case HID_PSEUDOSHEET_NOTES: pNameId = STR_LAYOUT_NOTES; break;
+
+ default:
+ OSL_FAIL( "SdPage::getPresentationStyle(), illegal argument!" );
+ return nullptr;
+ }
+ aStyleName += pNameId;
+ if (bOutline)
+ {
+ aStyleName += " " +
+ OUString::number( sal_Int32( nHelpId - HID_PSEUDOSHEET_OUTLINE ));
+ }
+
+ SfxStyleSheetBasePool* pStShPool = getSdrModelFromSdrPage().GetStyleSheetPool();
+ SfxStyleSheetBase* pResult = pStShPool->Find(aStyleName, SfxStyleFamily::Page);
+ return dynamic_cast<SdStyleSheet*>(pResult);
+}
+
+/*************************************************************************
+|*
+|* The presentation object rObj has changed and is no longer referenced by the
+|* presentation object of the master page.
+|* The UserCall is deleted.
+|*
+\************************************************************************/
+
+void SdPage::Changed(const SdrObject& rObj, SdrUserCallType eType, const ::tools::Rectangle& )
+{
+ if (maLockAutoLayoutArrangement.isLocked())
+ return;
+
+ switch (eType)
+ {
+ case SdrUserCallType::MoveOnly:
+ case SdrUserCallType::Resize:
+ {
+ if ( getSdrModelFromSdrPage().isLocked())
+ break;
+
+ if (!mbMaster)
+ {
+ if (rObj.GetUserCall())
+ {
+ SdrObject& _rObj = const_cast<SdrObject&>(rObj);
+ SfxUndoManager* pUndoManager
+ = static_cast<SdDrawDocument&>(getSdrModelFromSdrPage())
+ .GetUndoManager();
+ const bool bUndo
+ = pUndoManager && pUndoManager->IsInListAction() && IsInserted();
+
+ if (bUndo)
+ pUndoManager->AddUndoAction(
+ std::make_unique<UndoObjectUserCall>(_rObj));
+
+ // Object was resized by user and does not listen to its slide anymore
+ _rObj.SetUserCall(nullptr);
+ }
+ }
+ else
+ {
+ // Object of the master page changed, therefore adjust
+ // object on all pages
+ sal_uInt16 nPageCount = static_cast<SdDrawDocument&>(getSdrModelFromSdrPage())
+ .GetSdPageCount(mePageKind);
+
+ for (sal_uInt16 i = 0; i < nPageCount; i++)
+ {
+ SdPage* pLoopPage = static_cast<SdDrawDocument&>(getSdrModelFromSdrPage())
+ .GetSdPage(i, mePageKind);
+
+ if (pLoopPage && this == &(pLoopPage->TRG_GetMasterPage()))
+ {
+ // Page listens to this master page, therefore
+ // adjust AutoLayout
+ pLoopPage->SetAutoLayout(pLoopPage->GetAutoLayout());
+ }
+ }
+ }
+ }
+ break;
+
+ case SdrUserCallType::Delete:
+ case SdrUserCallType::Removed:
+ default:
+ break;
+ }
+}
+
+/*************************************************************************
+|*
+|* Creates on a master page: background, title- and layout area
+|*
+\************************************************************************/
+
+void SdPage::CreateTitleAndLayout(bool bInit, bool bCreate )
+{
+ SfxUndoManager* pUndoManager(static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetUndoManager());
+ const bool bUndo = pUndoManager && pUndoManager->IsInListAction() && IsInserted();
+
+ SdPage* pMasterPage = this;
+
+ if (!mbMaster)
+ {
+ pMasterPage = static_cast<SdPage*>(&(TRG_GetMasterPage()));
+ }
+
+ if (!pMasterPage)
+ {
+ return;
+ }
+
+ /**************************************************************************
+ * create background, title- and layout area
+ **************************************************************************/
+ if( mePageKind == PageKind::Standard )
+ {
+ pMasterPage->EnsureMasterPageDefaultBackground();
+ }
+
+ if (static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetDocumentType() != DocumentType::Impress)
+ return;
+
+ if( mePageKind == PageKind::Handout && bInit )
+ {
+ // handout template
+
+ // delete all available handout presentation objects
+ SdrObject *pObj=nullptr;
+ while( (pObj = pMasterPage->GetPresObj(PresObjKind::Handout)) != nullptr )
+ {
+ pMasterPage->RemoveObject(pObj->GetOrdNum());
+
+ if( bUndo )
+ {
+ pUndoManager->AddUndoAction(getSdrModelFromSdrPage().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
+ }
+ else
+ {
+ SdrObject::Free( pObj );
+ }
+ }
+
+ std::vector< ::tools::Rectangle > aAreas;
+ CalculateHandoutAreas( static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()), pMasterPage->GetAutoLayout(), false, aAreas );
+
+ const bool bSkip = pMasterPage->GetAutoLayout() == AUTOLAYOUT_HANDOUT3;
+ std::vector< ::tools::Rectangle >::iterator iter( aAreas.begin() );
+
+ while( iter != aAreas.end() )
+ {
+ SdrPageObj* pPageObj = static_cast<SdrPageObj*>(pMasterPage->CreatePresObj(PresObjKind::Handout, false, (*iter++)) );
+ // #i105146# We want no content to be displayed for PageKind::Handout,
+ // so just never set a page as content
+ pPageObj->SetReferencedPage(nullptr);
+
+ if( bSkip && iter != aAreas.end() )
+ ++iter;
+ }
+ }
+
+ if( mePageKind != PageKind::Handout )
+ {
+ SdrObject* pMasterTitle = pMasterPage->GetPresObj( PresObjKind::Title );
+ if( pMasterTitle == nullptr )
+ pMasterPage->CreateDefaultPresObj(PresObjKind::Title);
+
+ SdrObject* pMasterOutline = pMasterPage->GetPresObj( mePageKind==PageKind::Notes ? PresObjKind::Notes : PresObjKind::Outline );
+ if( pMasterOutline == nullptr )
+ pMasterPage->CreateDefaultPresObj( mePageKind == PageKind::Standard ? PresObjKind::Outline : PresObjKind::Notes );
+ }
+
+ // create header&footer objects
+
+ if( !bCreate )
+ return;
+
+ if( mePageKind != PageKind::Standard )
+ {
+ SdrObject* pHeader = pMasterPage->GetPresObj( PresObjKind::Header );
+ if( pHeader == nullptr )
+ pMasterPage->CreateDefaultPresObj( PresObjKind::Header );
+ }
+
+ SdrObject* pDate = pMasterPage->GetPresObj( PresObjKind::DateTime );
+ if( pDate == nullptr )
+ pMasterPage->CreateDefaultPresObj( PresObjKind::DateTime );
+
+ SdrObject* pFooter = pMasterPage->GetPresObj( PresObjKind::Footer );
+ if( pFooter == nullptr )
+ pMasterPage->CreateDefaultPresObj( PresObjKind::Footer );
+
+ SdrObject* pNumber = pMasterPage->GetPresObj( PresObjKind::SlideNumber );
+ if( pNumber == nullptr )
+ pMasterPage->CreateDefaultPresObj( PresObjKind::SlideNumber );
+}
+
+namespace {
+
+const o3tl::enumarray<PageKind, char const *> PageKindVector = {
+ "PageKind::Standard", "PageKind::Notes", "PageKind::Handout"
+};
+
+const o3tl::enumarray<PresObjKind, const char*> PresObjKindVector = {
+ "PRESOBJ_NONE", "PRESOBJ_TITLE", "PRESOBJ_OUTLINE",
+ "PRESOBJ_TEXT" ,"PRESOBJ_GRAPHIC" , "PRESOBJ_OBJECT",
+ "PRESOBJ_CHART", "PRESOBJ_ORGCHART", "PRESOBJ_TABLE",
+ "PRESOBJ_PAGE", "PRESOBJ_HANDOUT",
+ "PRESOBJ_NOTES","PRESOBJ_HEADER", "PRESOBJ_FOOTER",
+ "PRESOBJ_DATETIME", "PRESOBJ_SLIDENUMBER", "PRESOBJ_CALC",
+ "PRESOBJ_MEDIA"
+};
+
+void getPresObjProp( const SdPage& rPage, const char* sObjKind, const char* sPageKind, double presObjPropValue[] )
+{
+ bool bNoObjectFound = true; //used to break from outer loop
+
+ const std::vector< Reference<XNode> >& objectInfo = static_cast< const SdDrawDocument& >(rPage.getSdrModelFromSdrPage()).GetObjectVector();
+ for( const Reference<XNode>& objectNode : objectInfo )
+ {
+ if(bNoObjectFound)
+ {
+ Reference<XNamedNodeMap> objectattrlist = objectNode->getAttributes();
+ Reference<XNode> objectattr = objectattrlist->getNamedItem("type");
+ OUString sObjType = objectattr->getNodeValue();
+
+ if (sObjType.equalsAscii(sObjKind))
+ {
+ Reference<XNodeList> objectChildren = objectNode->getChildNodes();
+ const int objSize = objectChildren->getLength();
+
+ for( int j=0; j< objSize; j++)
+ {
+ Reference<XNode> obj = objectChildren->item(j);
+ OUString nodename = obj->getNodeName();
+
+ //check whether child is blank 'text-node' or 'object-prop' node
+ if(nodename == "object-prop")
+ {
+ Reference<XNamedNodeMap> ObjAttributes = obj->getAttributes();
+ Reference<XNode> ObjPageKind = ObjAttributes->getNamedItem("pagekind");
+ OUString sObjPageKind = ObjPageKind->getNodeValue();
+
+ if (sObjPageKind.equalsAscii(sPageKind))
+ {
+ Reference<XNode> ObjSizeHeight = ObjAttributes->getNamedItem("relative-height");
+ OUString sValue = ObjSizeHeight->getNodeValue();
+ presObjPropValue[0] = sValue.toDouble();
+
+ Reference<XNode> ObjSizeWidth = ObjAttributes->getNamedItem("relative-width");
+ sValue = ObjSizeWidth->getNodeValue();
+ presObjPropValue[1] = sValue.toDouble();
+
+ Reference<XNode> ObjPosX = ObjAttributes->getNamedItem("relative-posX");
+ sValue = ObjPosX->getNodeValue();
+ presObjPropValue[2] = sValue.toDouble();
+
+ Reference<XNode> ObjPosY = ObjAttributes->getNamedItem("relative-posY");
+ sValue = ObjPosY->getNodeValue();
+ presObjPropValue[3] = sValue.toDouble();
+
+ bNoObjectFound = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ break;
+ }
+}
+
+}
+
+SdrObject* SdPage::CreateDefaultPresObj(PresObjKind eObjKind)
+{
+ if( eObjKind == PresObjKind::Title )
+ {
+ ::tools::Rectangle aTitleRect( GetTitleRect() );
+ return CreatePresObj(PresObjKind::Title, false, aTitleRect);
+ }
+ else if( eObjKind == PresObjKind::Outline )
+ {
+ ::tools::Rectangle aLayoutRect( GetLayoutRect() );
+ return CreatePresObj( PresObjKind::Outline, false, aLayoutRect);
+ }
+ else if( eObjKind == PresObjKind::Notes )
+ {
+ ::tools::Rectangle aLayoutRect( GetLayoutRect() );
+ return CreatePresObj( PresObjKind::Notes, false, aLayoutRect);
+ }
+ else if( (eObjKind == PresObjKind::Footer) || (eObjKind == PresObjKind::DateTime) || (eObjKind == PresObjKind::SlideNumber) || (eObjKind == PresObjKind::Header ) )
+ {
+ double propvalue[] = {0,0,0,0};
+ const char* sObjKind = PresObjKindVector[eObjKind];
+ const char* sPageKind = PageKindVector[mePageKind];
+ // create footer objects for standard master page
+ if( mePageKind == PageKind::Standard )
+ {
+ const ::tools::Long nLftBorder = GetLeftBorder();
+ const ::tools::Long nUppBorder = GetUpperBorder();
+
+ Point aPos ( nLftBorder, nUppBorder );
+ Size aSize ( GetSize() );
+
+ aSize.AdjustWidth( -(nLftBorder + GetRightBorder()) );
+ aSize.AdjustHeight( -(nUppBorder + GetLowerBorder()) );
+
+ getPresObjProp( *this, sObjKind, sPageKind, propvalue);
+ aPos.AdjustX(::tools::Long( aSize.Width() * propvalue[2] ) );
+ aPos.AdjustY(::tools::Long( aSize.Height() * propvalue[3] ) );
+ aSize.setWidth( ::tools::Long( aSize.Width() * propvalue[1] ) );
+ aSize.setHeight( ::tools::Long( aSize.Height() * propvalue[0] ) );
+
+ if(eObjKind == PresObjKind::Header )
+ {
+ OSL_FAIL( "SdPage::CreateDefaultPresObj() - can't create a header placeholder for a master slide" );
+ return nullptr;
+ }
+ else
+ {
+ ::tools::Rectangle aRect( aPos, aSize );
+ return CreatePresObj( eObjKind, false, aRect );
+ }
+ }
+ else
+ {
+ // create header&footer objects for handout and notes master
+ Size aPageSize ( GetSize() );
+ aPageSize.AdjustWidth( -(GetLeftBorder() + GetRightBorder()) );
+ aPageSize.AdjustHeight( -(GetUpperBorder() + GetLowerBorder()) );
+
+ Point aPosition ( GetLeftBorder(), GetUpperBorder() );
+
+ getPresObjProp( *this, sObjKind, sPageKind, propvalue);
+ int NOTES_HEADER_FOOTER_WIDTH = ::tools::Long(aPageSize.Width() * propvalue[1]);
+ int NOTES_HEADER_FOOTER_HEIGHT = ::tools::Long(aPageSize.Height() * propvalue[0]);
+ Size aSize( NOTES_HEADER_FOOTER_WIDTH, NOTES_HEADER_FOOTER_HEIGHT );
+ Point aPos ( 0 ,0 );
+ if( propvalue[2] == 0 )
+ aPos.setX( aPosition.X() );
+ else
+ aPos.setX( aPosition.X() + ::tools::Long( aPageSize.Width() - NOTES_HEADER_FOOTER_WIDTH ) );
+ if( propvalue[3] == 0 )
+ aPos.setY( aPosition.Y() );
+ else
+ aPos.setY( aPosition.Y() + ::tools::Long( aPageSize.Height() - NOTES_HEADER_FOOTER_HEIGHT ) );
+
+ ::tools::Rectangle aRect( aPos, aSize );
+ return CreatePresObj( eObjKind, false, aRect );
+ }
+ }
+ else
+ {
+ OSL_FAIL("SdPage::CreateDefaultPresObj() - unknown PRESOBJ kind" );
+ return nullptr;
+ }
+}
+
+void SdPage::DestroyDefaultPresObj(PresObjKind eObjKind)
+{
+ SdrObject* pObject = GetPresObj( eObjKind );
+
+ if( pObject )
+ {
+ SdDrawDocument* pDoc(static_cast< SdDrawDocument* >(&getSdrModelFromSdrPage()));
+ const bool bUndo = pDoc->IsUndoEnabled();
+ if( bUndo )
+ pDoc->AddUndo(pDoc->GetSdrUndoFactory().CreateUndoDeleteObject(*pObject));
+ SdrObjList* pOL = pObject->getParentSdrObjListFromSdrObject();
+ pOL->RemoveObject(pObject->GetOrdNumDirect());
+
+ if( !bUndo )
+ SdrObject::Free(pObject);
+ }
+}
+
+/*************************************************************************
+|*
+|* return title area
+|*
+\************************************************************************/
+
+::tools::Rectangle SdPage::GetTitleRect() const
+{
+ ::tools::Rectangle aTitleRect;
+
+ if (mePageKind != PageKind::Handout)
+ {
+ double propvalue[] = {0,0,0,0};
+
+ /******************************************************************
+ * standard- or note page: title area
+ ******************************************************************/
+ Point aTitlePos ( GetLeftBorder(), GetUpperBorder() );
+ Size aTitleSize ( GetSize() );
+ aTitleSize.AdjustWidth( -(GetLeftBorder() + GetRightBorder()) );
+ aTitleSize.AdjustHeight( -(GetUpperBorder() + GetLowerBorder()) );
+ const char* sPageKind = PageKindVector[mePageKind];
+
+ if (mePageKind == PageKind::Standard)
+ {
+ getPresObjProp( *this , "PRESOBJ_TITLE" ,sPageKind, propvalue);
+ aTitlePos.AdjustX(::tools::Long( aTitleSize.Width() * propvalue[2] ) );
+ aTitlePos.AdjustY(::tools::Long( aTitleSize.Height() * propvalue[3] ) );
+ aTitleSize.setWidth( ::tools::Long( aTitleSize.Width() * propvalue[1] ) );
+ aTitleSize.setHeight( ::tools::Long( aTitleSize.Height() * propvalue[0] ) );
+ }
+ else if (mePageKind == PageKind::Notes)
+ {
+ Point aPos = aTitlePos;
+ getPresObjProp( *this, "PRESOBJ_TITLE" ,sPageKind, propvalue);
+ aPos.AdjustX(::tools::Long( aTitleSize.Width() * propvalue[2] ) );
+ aPos.AdjustY(::tools::Long( aTitleSize.Height() * propvalue[3] ) );
+
+ // limit height
+ aTitleSize.setHeight( ::tools::Long( aTitleSize.Height() * propvalue[0] ) );
+ aTitleSize.setWidth( ::tools::Long( aTitleSize.Width() * propvalue[1] ) );
+
+ Size aPartArea = aTitleSize;
+ Size aSize;
+ sal_uInt16 nDestPageNum(GetPageNum());
+ SdrPage* pRefPage = nullptr;
+
+ if(nDestPageNum)
+ {
+ // only decrement if != 0, else we get 0xffff
+ nDestPageNum -= 1;
+ }
+
+ if(nDestPageNum < getSdrModelFromSdrPage().GetPageCount())
+ {
+ pRefPage = getSdrModelFromSdrPage().GetPage(nDestPageNum);
+ }
+
+ if ( pRefPage )
+ {
+ // scale actually page size into handout rectangle
+ double fH = pRefPage->GetWidth() == 0
+ ? 0 : static_cast<double>(aPartArea.Width()) / pRefPage->GetWidth();
+ double fV = pRefPage->GetHeight() == 0
+ ? 0 : static_cast<double>(aPartArea.Height()) / pRefPage->GetHeight();
+
+ if ( fH > fV )
+ fH = fV;
+ aSize.setWidth( static_cast<::tools::Long>(fH * pRefPage->GetWidth()) );
+ aSize.setHeight( static_cast<::tools::Long>(fH * pRefPage->GetHeight()) );
+
+ aPos.AdjustX((aPartArea.Width() - aSize.Width()) / 2 );
+ aPos.AdjustY((aPartArea.Height()- aSize.Height())/ 2 );
+ }
+
+ aTitlePos = aPos;
+ aTitleSize = aSize;
+ }
+
+ aTitleRect.SetPos(aTitlePos);
+ aTitleRect.SetSize(aTitleSize);
+ }
+
+ return aTitleRect;
+}
+
+/*************************************************************************
+|*
+|* return outline area
+|*
+\************************************************************************/
+
+::tools::Rectangle SdPage::GetLayoutRect() const
+{
+ ::tools::Rectangle aLayoutRect;
+
+ if (mePageKind != PageKind::Handout)
+ {
+ double propvalue[] = {0,0,0,0};
+
+ Point aLayoutPos ( GetLeftBorder(), GetUpperBorder() );
+ Size aLayoutSize ( GetSize() );
+ aLayoutSize.AdjustWidth( -(GetLeftBorder() + GetRightBorder()) );
+ aLayoutSize.AdjustHeight( -(GetUpperBorder() + GetLowerBorder()) );
+ const char* sPageKind = PageKindVector[mePageKind];
+
+ if (mePageKind == PageKind::Standard)
+ {
+ getPresObjProp( *this ,"PRESOBJ_OUTLINE", sPageKind, propvalue);
+ aLayoutPos.AdjustX(::tools::Long( aLayoutSize.Width() * propvalue[2] ) );
+ aLayoutPos.AdjustY(::tools::Long( aLayoutSize.Height() * propvalue[3] ) );
+ aLayoutSize.setWidth( ::tools::Long( aLayoutSize.Width() * propvalue[1] ) );
+ aLayoutSize.setHeight( ::tools::Long( aLayoutSize.Height() * propvalue[0] ) );
+ aLayoutRect.SetPos(aLayoutPos);
+ aLayoutRect.SetSize(aLayoutSize);
+ }
+ else if (mePageKind == PageKind::Notes)
+ {
+ getPresObjProp( *this, "PRESOBJ_NOTES", sPageKind, propvalue);
+ aLayoutPos.AdjustX(::tools::Long( aLayoutSize.Width() * propvalue[2] ) );
+ aLayoutPos.AdjustY(::tools::Long( aLayoutSize.Height() * propvalue[3] ) );
+ aLayoutSize.setWidth( ::tools::Long( aLayoutSize.Width() * propvalue[1] ) );
+ aLayoutSize.setHeight( ::tools::Long( aLayoutSize.Height() * propvalue[0] ) );
+ aLayoutRect.SetPos(aLayoutPos);
+ aLayoutRect.SetSize(aLayoutSize);
+ }
+ }
+
+ return aLayoutRect;
+}
+
+/**************************************************************************
+|*
+|* assign an AutoLayout
+|*
+\*************************************************************************/
+
+const int MAX_PRESOBJS = 7; // maximum number of presentation objects per layout
+const int VERTICAL = 0x8000;
+
+static constexpr PresObjKind operator|(PresObjKind e, int x)
+{
+ return static_cast<PresObjKind>(static_cast<int>(e) | x);
+}
+
+namespace {
+
+struct LayoutDescriptor
+{
+ PresObjKind meKind[MAX_PRESOBJS];
+ bool mbVertical[MAX_PRESOBJS];
+
+ LayoutDescriptor( PresObjKind k0 = PresObjKind::NONE, PresObjKind k1 = PresObjKind::NONE, PresObjKind k2 = PresObjKind::NONE, PresObjKind k3 = PresObjKind::NONE, PresObjKind k4 = PresObjKind::NONE, PresObjKind k5 = PresObjKind::NONE, PresObjKind k6 = PresObjKind::NONE );
+};
+
+}
+
+LayoutDescriptor::LayoutDescriptor( PresObjKind k0, PresObjKind k1, PresObjKind k2, PresObjKind k3, PresObjKind k4, PresObjKind k5, PresObjKind k6 )
+{
+ auto removeVertical = [] (PresObjKind k) { return static_cast<PresObjKind>(static_cast<int>(k) & ~VERTICAL); };
+ auto isVertical = [] (PresObjKind k) { return bool(static_cast<int>(k) & VERTICAL); };
+ meKind[0] = removeVertical(k0); mbVertical[0] = isVertical(k0);
+ meKind[1] = removeVertical(k1); mbVertical[1] = isVertical(k1);
+ meKind[2] = removeVertical(k2); mbVertical[2] = isVertical(k2);
+ meKind[3] = removeVertical(k3); mbVertical[3] = isVertical(k3);
+ meKind[4] = removeVertical(k4); mbVertical[4] = isVertical(k4);
+ meKind[5] = removeVertical(k5); mbVertical[5] = isVertical(k5);
+ meKind[6] = removeVertical(k6); mbVertical[6] = isVertical(k6);
+}
+
+static const LayoutDescriptor& GetLayoutDescriptor( AutoLayout eLayout )
+{
+ static const LayoutDescriptor aLayouts[AUTOLAYOUT_END-AUTOLAYOUT_START] =
+ {
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Text ), // AUTOLAYOUT_TITLE
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline ), // AUTOLAYOUT_TITLE_CONTENT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline ), // AUTOLAYOUT_CHART
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_TITLE_2CONTENT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_TEXTCHART
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline ), // AUTOLAYOUT_ORG
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_TEXTCLbIP
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_CHARTTEXT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline ), // AUTOLAYOUT_TAB
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_CLIPTEXT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_TEXTOBJ
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Object ), // AUTOLAYOUT_OBJ
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_TITLE_CONTENT_2CONTENT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_TEXTOBJ
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_TITLE_2CONTENT_CONTENT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline ), // AUTOLAYOUT_TEXTOVEROBJ
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline, // AUTOLAYOUT_TITLE_4CONTENT
+ PresObjKind::Outline, PresObjKind::Outline ),
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::NONE ), // AUTOLAYOUT_TITLE_ONLY
+ LayoutDescriptor( PresObjKind::NONE ), // AUTOLAYOUT_NONE
+ LayoutDescriptor( PresObjKind::Page, PresObjKind::Notes ), // AUTOLAYOUT_NOTES
+ LayoutDescriptor( ), // AUTOLAYOUT_HANDOUT1
+ LayoutDescriptor( ), // AUTOLAYOUT_HANDOUT2
+ LayoutDescriptor( ), // AUTOLAYOUT_HANDOUT3
+ LayoutDescriptor( ), // AUTOLAYOUT_HANDOUT4
+ LayoutDescriptor( ), // AUTOLAYOUT_HANDOUT6
+ LayoutDescriptor( PresObjKind::Title|VERTICAL, PresObjKind::Outline|VERTICAL, PresObjKind::Outline ),// AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT
+ LayoutDescriptor( PresObjKind::Title|VERTICAL, PresObjKind::Outline|VERTICAL ), // AUTOLAYOUT_VTITLE_VCONTENT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline|VERTICAL ), // AUTOLAYOUT_TITLE_VCONTENT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline|VERTICAL, PresObjKind::Outline|VERTICAL ), // AUTOLAYOUT_TITLE_2VTEXT
+ LayoutDescriptor( ), // AUTOLAYOUT_HANDOUT9
+ LayoutDescriptor( PresObjKind::Text, PresObjKind::NONE ), // AUTOLAYOUT_ONLY_TEXT
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline, // AUTOLAYOUT_4CLIPART
+ PresObjKind::Graphic, PresObjKind::Graphic ),
+ LayoutDescriptor( PresObjKind::Title, PresObjKind::Outline, PresObjKind::Outline, // AUTOLAYOUT_TITLE_6CONTENT
+ PresObjKind::Outline, PresObjKind::Outline, PresObjKind::Outline, PresObjKind::Outline )
+ };
+
+ if( (eLayout < AUTOLAYOUT_START) || (eLayout >= AUTOLAYOUT_END) )
+ eLayout = AUTOLAYOUT_NONE;
+
+ return aLayouts[ eLayout - AUTOLAYOUT_START ];
+}
+
+static OUString enumtoString(AutoLayout aut)
+{
+ OUString retstr;
+ switch (aut)
+ {
+ case AUTOLAYOUT_TITLE_CONTENT:
+ retstr="AUTOLAYOUT_TITLE_CONTENT";
+ break;
+ case AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT:
+ retstr="AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT";
+ break;
+ case AUTOLAYOUT_TITLE_CONTENT_2CONTENT:
+ retstr="AUTOLAYOUT_TITLE_CONTENT_2CONTENT";
+ break;
+ case AUTOLAYOUT_TITLE_4CONTENT:
+ retstr="AUTOLAYOUT_TITLE_4CONTENT";
+ break;
+ case AUTOLAYOUT_ONLY_TEXT:
+ retstr="AUTOLAYOUT_ONLY_TEXT";
+ break;
+ case AUTOLAYOUT_TITLE_ONLY:
+ retstr="AUTOLAYOUT_TITLE_ONLY";
+ break;
+ case AUTOLAYOUT_TITLE_6CONTENT:
+ retstr="AUTOLAYOUT_TITLE_6CONTENT";
+ break;
+ case AUTOLAYOUT_START:
+ retstr="AUTOLAYOUT_START";
+ break;
+ case AUTOLAYOUT_TITLE_2CONTENT_CONTENT:
+ retstr="AUTOLAYOUT_TITLE_2CONTENT_CONTENT";
+ break;
+ case AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT:
+ retstr="AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT";
+ break;
+ case AUTOLAYOUT_TITLE_2CONTENT:
+ retstr="AUTOLAYOUT_TITLE_2CONTENT";
+ break;
+ case AUTOLAYOUT_VTITLE_VCONTENT:
+ retstr="AUTOLAYOUT_VTITLE_VCONTENT";
+ break;
+ case AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT:
+ retstr="AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT";
+ break;
+ case AUTOLAYOUT_TITLE_VCONTENT:
+ retstr="AUTOLAYOUT_TITLE_VCONTENT";
+ break;
+ case AUTOLAYOUT_TITLE_2VTEXT:
+ retstr="AUTOLAYOUT_TITLE_2VTEXT";
+ break;
+ default:
+ retstr="unknown";
+ break;
+ // case AUTOLAYOUT_TITLE_4SCONTENT: return "AUTOLAYOUT_TITLE_4SCONTENT";
+ }
+ return retstr;
+}
+
+static void CalcAutoLayoutRectangles( SdPage const & rPage,::tools::Rectangle* rRectangle ,const OUString& sLayoutType )
+{
+ ::tools::Rectangle aTitleRect;
+ ::tools::Rectangle aLayoutRect;
+
+ if( rPage.GetPageKind() != PageKind::Handout )
+ {
+ SdPage& rMasterPage = static_cast<SdPage&>(rPage.TRG_GetMasterPage());
+ SdrObject* pMasterTitle = rMasterPage.GetPresObj( PresObjKind::Title );
+ SdrObject* pMasterSubTitle = rMasterPage.GetPresObj( PresObjKind::Text );
+ SdrObject* pMasterOutline = rMasterPage.GetPresObj( rPage.GetPageKind()==PageKind::Notes ? PresObjKind::Notes : PresObjKind::Outline );
+
+ if( pMasterTitle )
+ aTitleRect = pMasterTitle->GetLogicRect();
+
+ if (aTitleRect.IsEmpty() )
+ aTitleRect = rPage.GetTitleRect();
+ if( pMasterSubTitle )
+ aLayoutRect = pMasterSubTitle->GetLogicRect();
+ else if( pMasterOutline )
+ aLayoutRect = pMasterOutline->GetLogicRect();
+
+ if (aLayoutRect.IsEmpty() )
+ aLayoutRect = rPage.GetLayoutRect();
+ }
+
+ rRectangle[0] = aTitleRect;
+ for( int i = 1; i < MAX_PRESOBJS; i++ )
+ rRectangle[i] = aLayoutRect;
+
+ const Point aTitlePos( aTitleRect.TopLeft() );
+ const Size aLayoutSize( aLayoutRect.GetSize() );
+ const Point aLayoutPos( aLayoutRect.TopLeft() );
+ double propvalue[] = {0,0,0,0};
+
+ const std::vector< Reference<XNode> >& layoutInfo = static_cast< const SdDrawDocument& >(rPage.getSdrModelFromSdrPage()).GetLayoutVector();
+ auto aIter = std::find_if(layoutInfo.begin(), layoutInfo.end(),
+ [&sLayoutType](const Reference<XNode>& layoutNode) {
+ Reference<XNamedNodeMap> layoutAttrList = layoutNode->getAttributes();
+
+ // get the attribute value of layout (i.e it's type)
+ OUString sLayoutAttName = layoutAttrList->getNamedItem("type")->getNodeValue();
+ return sLayoutAttName == sLayoutType;
+ });
+ if (aIter == layoutInfo.end())
+ return;
+
+ int count=0;
+ Reference<XNode> layoutNode = *aIter;
+ Reference<XNodeList> layoutChildren = layoutNode->getChildNodes();
+ const int presobjsize = layoutChildren->getLength();
+ for( int j=0; j< presobjsize ; j++)
+ {
+ OUString nodename;
+ Reference<XNode> presobj = layoutChildren->item(j);
+ nodename=presobj->getNodeName();
+
+ //check whether child is blank 'text-node' or 'presobj' node
+ if(nodename == "presobj")
+ {
+ // TODO: rework sd to permit arbitrary number of presentation objects
+ assert(count < MAX_PRESOBJS);
+
+ Reference<XNamedNodeMap> presObjAttributes = presobj->getAttributes();
+
+ Reference<XNode> presObjSizeHeight = presObjAttributes->getNamedItem("relative-height");
+ OUString sValue = presObjSizeHeight->getNodeValue();
+ propvalue[0] = sValue.toDouble();
+
+ Reference<XNode> presObjSizeWidth = presObjAttributes->getNamedItem("relative-width");
+ sValue = presObjSizeWidth->getNodeValue();
+ propvalue[1] = sValue.toDouble();
+
+ Reference<XNode> presObjPosX = presObjAttributes->getNamedItem("relative-posX");
+ sValue = presObjPosX->getNodeValue();
+ propvalue[2] = sValue.toDouble();
+
+ Reference<XNode> presObjPosY = presObjAttributes->getNamedItem("relative-posY");
+ sValue = presObjPosY->getNodeValue();
+ propvalue[3] = sValue.toDouble();
+
+ if(count == 0)
+ {
+ Size aSize ( aTitleRect.GetSize() );
+ aSize.setHeight( basegfx::fround(aSize.Height() * propvalue[0]) );
+ aSize.setWidth( basegfx::fround(aSize.Width() * propvalue[1]) );
+ Point aPos( basegfx::fround(aTitlePos.X() +(aSize.Width() * propvalue[2])),
+ basegfx::fround(aTitlePos.Y() + (aSize.Height() * propvalue[3])) );
+ rRectangle[count] = ::tools::Rectangle(aPos, aSize);
+ count = count+1;
+ }
+ else
+ {
+ Size aSize( basegfx::fround(aLayoutSize.Width() * propvalue[1]),
+ basegfx::fround(aLayoutSize.Height() * propvalue[0]) );
+ Point aPos( basegfx::fround(aLayoutPos.X() +(aSize.Width() * propvalue[2])),
+ basegfx::fround(aLayoutPos.Y() + (aSize.Height() * propvalue[3])) );
+ rRectangle[count] = ::tools::Rectangle (aPos, aSize);
+ count = count+1;
+ }
+ }
+ }
+}
+
+static void findAutoLayoutShapesImpl( SdPage& rPage, const LayoutDescriptor& rDescriptor, std::array<SdrObject*, MAX_PRESOBJS>& rShapes, bool bInit, bool bSwitchLayout )
+{
+ // init list of indexes for each presentation shape kind
+ // this is used to find subsequent shapes with the same presentation shape kind
+ o3tl::enumarray<PresObjKind,int> PresObjIndex;
+ PresObjIndex.fill(1);
+
+ bool bMissing = false;
+
+ // for each entry in the layoutdescriptor, arrange a presentation shape
+ for (int i = 0; (i < MAX_PRESOBJS) && (rDescriptor.meKind[i] != PresObjKind::NONE); i++)
+ {
+ PresObjKind eKind = rDescriptor.meKind[i];
+ SdrObject* pObj = nullptr;
+ while( (pObj = rPage.GetPresObj( eKind, PresObjIndex[eKind], true )) != nullptr )
+ {
+ PresObjIndex[eKind]++; // on next search for eKind, find next shape with same eKind
+
+ if( !bSwitchLayout || !pObj->IsEmptyPresObj() )
+ {
+ rShapes[i] = pObj;
+ break;
+ }
+ }
+
+ if( !pObj )
+ bMissing = true;
+ }
+
+ if( !(bMissing && bInit) )
+ return;
+
+ // for each entry in the layoutdescriptor, look for an alternative shape
+ for (int i = 0; (i < MAX_PRESOBJS) && (rDescriptor.meKind[i] != PresObjKind::NONE); i++)
+ {
+ if( rShapes[i] )
+ continue;
+
+ PresObjKind eKind = rDescriptor.meKind[i];
+
+ SdrObject* pObj = nullptr;
+ bool bFound = false;
+
+ const size_t nShapeCount = rPage.GetObjCount();
+ for(size_t nShapeIndex = 0; nShapeIndex < nShapeCount && !bFound; ++nShapeIndex )
+ {
+ pObj = rPage.GetObj(nShapeIndex);
+
+ if( pObj->IsEmptyPresObj() )
+ continue;
+
+ if( pObj->GetObjInventor() != SdrInventor::Default )
+ continue;
+
+ // do not reuse shapes that are already part of the layout
+ if( std::find( rShapes.begin(), rShapes.end(), pObj ) != rShapes.end() )
+ continue;
+
+ bool bPresStyle = pObj->GetStyleSheet() && (pObj->GetStyleSheet()->GetFamily() == SfxStyleFamily::Page);
+ SdrObjKind eSdrObjKind = pObj->GetObjIdentifier();
+
+ switch( eKind )
+ {
+ case PresObjKind::Title:
+ bFound = eSdrObjKind == SdrObjKind::TitleText;
+ break;
+ case PresObjKind::Table:
+ bFound = eSdrObjKind == SdrObjKind::Table;
+ break;
+ case PresObjKind::Media:
+ bFound = eSdrObjKind == SdrObjKind::Media;
+ break;
+ case PresObjKind::Outline:
+ bFound = (eSdrObjKind == SdrObjKind::OutlineText) ||
+ ((eSdrObjKind == SdrObjKind::Text) && bPresStyle) ||
+ (eSdrObjKind == SdrObjKind::Table) || (eSdrObjKind == SdrObjKind::Media) || (eSdrObjKind == SdrObjKind::Graphic) || (eSdrObjKind == SdrObjKind::OLE2);
+ break;
+ case PresObjKind::Graphic:
+ bFound = eSdrObjKind == SdrObjKind::Graphic;
+ break;
+ case PresObjKind::Object:
+ if( eSdrObjKind == SdrObjKind::OLE2 )
+ {
+ SdrOle2Obj* pOle2 = dynamic_cast< SdrOle2Obj* >( pObj );
+ if( pOle2 )
+ {
+ if( pOle2->IsEmpty() )
+ bFound = true;
+ else
+ {
+ ::comphelper::IEmbeddedHelper* pPersist(rPage.getSdrModelFromSdrPage().GetPersist());
+
+ if( pPersist )
+ {
+ uno::Reference < embed::XEmbeddedObject > xObject = pPersist->getEmbeddedObjectContainer().
+ GetEmbeddedObject( pOle2->GetPersistName() );
+
+ // TODO CL->KA: Why is this not working anymore?
+ if( xObject.is() )
+ {
+ SvGlobalName aClassId( xObject->getClassID() );
+
+ const SvGlobalName aAppletClassId( SO3_APPLET_CLASSID );
+ const SvGlobalName aPluginClassId( SO3_PLUGIN_CLASSID );
+ const SvGlobalName aIFrameClassId( SO3_IFRAME_CLASSID );
+
+ if( aPluginClassId != aClassId && aAppletClassId != aClassId && aIFrameClassId != aClassId )
+ {
+ bFound = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case PresObjKind::Chart:
+ case PresObjKind::Calc:
+ if( eSdrObjKind == SdrObjKind::OLE2 )
+ {
+ SdrOle2Obj* pOle2 = dynamic_cast< SdrOle2Obj* >( pObj );
+ if( pOle2 )
+ {
+ if(
+ ((eKind == PresObjKind::Chart) &&
+ ( pOle2->GetProgName() == "StarChart" || pOle2->IsChart() ) )
+ ||
+ ((eKind == PresObjKind::Calc) &&
+ ( pOle2->GetProgName() == "StarCalc" || pOle2->IsCalc() ) ) )
+ {
+ bFound = true;
+ }
+ }
+ break;
+ }
+ else if( eSdrObjKind == SdrObjKind::Table )
+ {
+ bFound = true;
+ }
+ break;
+ case PresObjKind::Page:
+ case PresObjKind::Handout:
+ bFound = eSdrObjKind == SdrObjKind::Page;
+ break;
+ case PresObjKind::Notes:
+ case PresObjKind::Text:
+ bFound = (bPresStyle && (eSdrObjKind == SdrObjKind::Text)) || (eSdrObjKind == SdrObjKind::OutlineText);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if( bFound )
+ rShapes[i] = pObj;
+ }
+}
+
+void SdPage::SetAutoLayout(AutoLayout eLayout, bool bInit, bool bCreate )
+{
+ sd::ScopeLockGuard aGuard( maLockAutoLayoutArrangement );
+
+ const bool bSwitchLayout = eLayout != GetAutoLayout();
+
+ SfxUndoManager* pUndoManager(static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetUndoManager());
+ const bool bUndo = pUndoManager && pUndoManager->IsInListAction() && IsInserted();
+
+ meAutoLayout = eLayout;
+
+ // if needed, creates and initialises the presentation shapes on this slides master page
+ CreateTitleAndLayout(bInit, bCreate);
+
+ if((meAutoLayout == AUTOLAYOUT_NONE && maPresentationShapeList.isEmpty()) || mbMaster)
+ {
+ // MasterPage or no layout and no presentation shapes available, nothing to do
+ return;
+ }
+
+ ::tools::Rectangle aRectangle[MAX_PRESOBJS];
+ const LayoutDescriptor& aDescriptor = GetLayoutDescriptor( meAutoLayout );
+ OUString sLayoutName( enumtoString(meAutoLayout) );
+ CalcAutoLayoutRectangles( *this, aRectangle, sLayoutName);
+
+ o3tl::sorted_vector< SdrObject* > aUsedPresentationObjects;
+
+ std::array<SdrObject*, MAX_PRESOBJS > aLayoutShapes;
+ aLayoutShapes.fill(nullptr);
+ findAutoLayoutShapesImpl( *this, aDescriptor, aLayoutShapes, bInit, bSwitchLayout );
+
+ // for each entry in the layoutdescriptor, arrange a presentation shape
+ for (int i = 0; (i < MAX_PRESOBJS) && (aDescriptor.meKind[i] != PresObjKind::NONE); i++)
+ {
+ PresObjKind eKind = aDescriptor.meKind[i];
+ SdrObject* pObj = InsertAutoLayoutShape( aLayoutShapes[i], eKind, aDescriptor.mbVertical[i], aRectangle[i], bInit );
+ if( pObj )
+ aUsedPresentationObjects.insert(pObj); // remember that we used this empty shape
+ }
+
+ // now delete all empty presentation objects that are no longer used by the new layout
+ if( !bInit )
+ return;
+
+ SdrObject* pObj = nullptr;
+ maPresentationShapeList.seekShape(0);
+
+ while( (pObj = maPresentationShapeList.getNextShape()) )
+ {
+ if( aUsedPresentationObjects.count(pObj) == 0 )
+ {
+
+ if( pObj->IsEmptyPresObj() )
+ {
+ if( bUndo )
+ pUndoManager->AddUndoAction(getSdrModelFromSdrPage().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
+
+ RemoveObject( pObj->GetOrdNum() );
+
+ if( !bUndo )
+ SdrObject::Free( pObj );
+ }
+/* #i108541# keep non empty pres obj as pres obj even if they are not part of the current layout */
+ }
+ }
+}
+
+/*************************************************************************
+|*
+|* insert object
+|*
+\************************************************************************/
+
+void SdPage::NbcInsertObject(SdrObject* pObj, size_t nPos)
+{
+ FmFormPage::NbcInsertObject(pObj, nPos);
+
+ static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).InsertObject(pObj);
+
+ SdrLayerID nId = pObj->GetLayer();
+ if( mbMaster )
+ {
+ if( nId == SdrLayerID(0) )
+ pObj->NbcSetLayer( SdrLayerID(2) ); // wrong layer. corrected to BackgroundObj layer
+ }
+ else
+ {
+ if( nId == SdrLayerID(2) )
+ pObj->NbcSetLayer( SdrLayerID(0) ); // wrong layer. corrected to layout layer
+ }
+}
+
+/*************************************************************************
+|*
+|* remove object
+|*
+\************************************************************************/
+
+SdrObject* SdPage::RemoveObject(size_t nObjNum)
+{
+ onRemoveObject(GetObj( nObjNum ));
+ return FmFormPage::RemoveObject(nObjNum);
+}
+
+/*************************************************************************
+|*
+|* remove object without broadcast
+|*
+\************************************************************************/
+
+SdrObject* SdPage::NbcRemoveObject(size_t nObjNum)
+{
+ onRemoveObject(GetObj( nObjNum ));
+ return FmFormPage::NbcRemoveObject(nObjNum);
+}
+
+// Also override ReplaceObject methods to realize when
+// objects are removed with this mechanism instead of RemoveObject
+SdrObject* SdPage::ReplaceObject(SdrObject* pNewObj, size_t nObjNum)
+{
+ onRemoveObject(GetObj( nObjNum ));
+ return FmFormPage::ReplaceObject(pNewObj, nObjNum);
+}
+
+// called after a shape is removed or replaced from this slide
+
+void SdPage::onRemoveObject( SdrObject* pObject )
+{
+ if( pObject )
+ {
+ RemovePresObj(pObject);
+
+ static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).RemoveObject(pObject);
+
+ removeAnimations( pObject );
+ }
+}
+
+void SdPage::SetSize(const Size& aSize)
+{
+ Size aOldSize = GetSize();
+
+ if (aSize != aOldSize)
+ {
+ FmFormPage::SetSize(aSize);
+ }
+}
+
+void SdPage::SetBorder(sal_Int32 nLft, sal_Int32 nUpp, sal_Int32 nRgt, sal_Int32 nLwr)
+{
+ if (nLft != GetLeftBorder() || nUpp != GetUpperBorder() ||
+ nRgt != GetRightBorder() || nLwr != GetLowerBorder() )
+ {
+ FmFormPage::SetBorder(nLft, nUpp, nRgt, nLwr);
+ }
+}
+
+void SdPage::SetLeftBorder(sal_Int32 nBorder)
+{
+ if (nBorder != GetLeftBorder() )
+ {
+ FmFormPage::SetLeftBorder(nBorder);
+ }
+}
+
+void SdPage::SetRightBorder(sal_Int32 nBorder)
+{
+ if (nBorder != GetRightBorder() )
+ {
+ FmFormPage::SetRightBorder(nBorder);
+ }
+}
+
+void SdPage::SetUpperBorder(sal_Int32 nBorder)
+{
+ if (nBorder != GetUpperBorder() )
+ {
+ FmFormPage::SetUpperBorder(nBorder);
+ }
+}
+
+void SdPage::SetLowerBorder(sal_Int32 nBorder)
+{
+ if (nBorder != GetLowerBorder() )
+ {
+ FmFormPage::SetLowerBorder(nBorder);
+ }
+}
+
+/*************************************************************************
+|*
+|* Adjust all objects to new page size.
+|*
+|* bScaleAllObj: all objects are scaled into the new area within the page
+|* margins. We scale the position and size. For presentation objects on the
+|* master page, we also scale the font height of the presentation template.
+|*
+\************************************************************************/
+
+void SdPage::ScaleObjects(const Size& rNewPageSize, const ::tools::Rectangle& rNewBorderRect, bool bScaleAllObj)
+{
+ sd::ScopeLockGuard aGuard( maLockAutoLayoutArrangement );
+
+ mbScaleObjects = bScaleAllObj;
+ SdrObject* pObj = nullptr;
+ Point aRefPnt(0, 0);
+ Size aNewPageSize(rNewPageSize);
+ sal_Int32 nLeft = rNewBorderRect.Left();
+ sal_Int32 nRight = rNewBorderRect.Right();
+ sal_Int32 nUpper = rNewBorderRect.Top();
+ sal_Int32 nLower = rNewBorderRect.Bottom();
+
+ // negative values are fixed values
+ // -> use up to date values
+ if (aNewPageSize.Width() < 0)
+ {
+ aNewPageSize.setWidth( GetWidth() );
+ }
+ if (aNewPageSize.Height() < 0)
+ {
+ aNewPageSize.setHeight( GetHeight() );
+ }
+ if (nLeft < 0)
+ {
+ nLeft = GetLeftBorder();
+ }
+ if (nRight < 0)
+ {
+ nRight = GetRightBorder();
+ }
+ if (nUpper < 0)
+ {
+ nUpper = GetUpperBorder();
+ }
+ if (nLower < 0)
+ {
+ nLower = GetLowerBorder();
+ }
+
+ Size aBackgroundSize(aNewPageSize);
+
+ if (mbScaleObjects)
+ {
+ aBackgroundSize.AdjustWidth( -(nLeft + nRight) );
+ aBackgroundSize.AdjustHeight( -(nUpper + nLower) );
+ aNewPageSize = aBackgroundSize;
+ }
+
+ ::tools::Long nOldWidth = GetWidth() - GetLeftBorder() - GetRightBorder();
+ ::tools::Long nOldHeight = GetHeight() - GetUpperBorder() - GetLowerBorder();
+
+ Fraction aFractX(aNewPageSize.Width(), nOldWidth);
+ Fraction aFractY(aNewPageSize.Height(), nOldHeight);
+
+ const size_t nObjCnt = (mbScaleObjects ? GetObjCount() : 0);
+
+ for (size_t nObj = 0; nObj < nObjCnt; ++nObj)
+ {
+ bool bIsPresObjOnMaster = false;
+
+ // all Objects
+ pObj = GetObj(nObj);
+
+ if (mbMaster && IsPresObj(pObj))
+ {
+ // There is a presentation object on the master page
+ bIsPresObjOnMaster = true;
+ }
+
+ if (pObj)
+ {
+ // remember aTopLeft as original TopLeft
+ Point aTopLeft(pObj->GetCurrentBoundRect().TopLeft());
+
+ if (!pObj->IsEdgeObj())
+ {
+ /**************************************************************
+ * Scale objects
+ **************************************************************/
+ if (mbScaleObjects)
+ {
+ // use aTopLeft as original TopLeft
+ aRefPnt = aTopLeft;
+ }
+
+ pObj->Resize(aRefPnt, aFractX, aFractY);
+
+ if (mbScaleObjects)
+ {
+ SdrObjKind eObjKind = pObj->GetObjIdentifier();
+
+ if (bIsPresObjOnMaster)
+ {
+ /**********************************************************
+ * presentation template: adjust test height
+ **********************************************************/
+
+ if (pObj == GetPresObj(PresObjKind::Title, 0))
+ {
+ SfxStyleSheet* pTitleSheet = GetStyleSheetForPresObj(PresObjKind::Title);
+
+ if (pTitleSheet)
+ {
+ SfxItemSet& rSet = pTitleSheet->GetItemSet();
+
+ const SvxFontHeightItem& rOldHgt = rSet.Get(EE_CHAR_FONTHEIGHT);
+ sal_uLong nFontHeight = rOldHgt.GetHeight();
+ nFontHeight = ::tools::Long(nFontHeight * static_cast<double>(aFractY));
+ rSet.Put(SvxFontHeightItem(nFontHeight, 100, EE_CHAR_FONTHEIGHT));
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( EE_CHAR_FONTHEIGHT_CJK ) )
+ {
+ const SvxFontHeightItem& rOldHgt2 = rSet.Get(EE_CHAR_FONTHEIGHT_CJK);
+ nFontHeight = rOldHgt2.GetHeight();
+ nFontHeight = ::tools::Long(nFontHeight * static_cast<double>(aFractY));
+ rSet.Put(SvxFontHeightItem(nFontHeight, 100, EE_CHAR_FONTHEIGHT_CJK));
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( EE_CHAR_FONTHEIGHT_CTL ) )
+ {
+ const SvxFontHeightItem& rOldHgt2 = rSet.Get(EE_CHAR_FONTHEIGHT_CTL);
+ nFontHeight = rOldHgt2.GetHeight();
+ nFontHeight = ::tools::Long(nFontHeight * static_cast<double>(aFractY));
+ rSet.Put(SvxFontHeightItem(nFontHeight, 100, EE_CHAR_FONTHEIGHT_CTL));
+ }
+
+ pTitleSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ }
+ }
+ else if (pObj == GetPresObj(PresObjKind::Outline, 0))
+ {
+ OUString aName(GetLayoutName() + " ");
+
+ for (sal_Int32 i=1; i<=9; i++)
+ {
+ OUString sLayoutName( aName + OUString::number( i ) );
+ SfxStyleSheet* pOutlineSheet = static_cast<SfxStyleSheet*>(static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetStyleSheetPool()->Find(sLayoutName, SfxStyleFamily::Page));
+
+ if (pOutlineSheet)
+ {
+ // Calculate new font height
+ SfxItemSet aTempSet(pOutlineSheet->GetItemSet());
+
+ const SvxFontHeightItem& rOldHgt = aTempSet.Get(EE_CHAR_FONTHEIGHT);
+ sal_uLong nFontHeight = rOldHgt.GetHeight();
+ nFontHeight = ::tools::Long(nFontHeight * static_cast<double>(aFractY));
+ aTempSet.Put(SvxFontHeightItem(nFontHeight, 100, EE_CHAR_FONTHEIGHT));
+
+ if( SfxItemState::DEFAULT == aTempSet.GetItemState( EE_CHAR_FONTHEIGHT_CJK ) )
+ {
+ const SvxFontHeightItem& rOldHgt2 = aTempSet.Get(EE_CHAR_FONTHEIGHT_CJK);
+ nFontHeight = rOldHgt2.GetHeight();
+ nFontHeight = ::tools::Long(nFontHeight * static_cast<double>(aFractY));
+ aTempSet.Put(SvxFontHeightItem(nFontHeight, 100, EE_CHAR_FONTHEIGHT_CJK));
+ }
+
+ if( SfxItemState::DEFAULT == aTempSet.GetItemState( EE_CHAR_FONTHEIGHT_CTL ) )
+ {
+ const SvxFontHeightItem& rOldHgt2 = aTempSet.Get(EE_CHAR_FONTHEIGHT_CTL);
+ nFontHeight = rOldHgt2.GetHeight();
+ nFontHeight = ::tools::Long(nFontHeight * static_cast<double>(aFractY));
+ aTempSet.Put(SvxFontHeightItem(nFontHeight, 100, EE_CHAR_FONTHEIGHT_CTL));
+ }
+
+ // adjust bullet
+ static_cast<SdStyleSheet*>(pOutlineSheet)->AdjustToFontHeight(aTempSet, false);
+
+ // Special treatment: reset the INVALIDS to
+ // NULL pointer (otherwise we have INVALID's
+ // or pointer to the DefaultItems in the
+ // template; both would suppress the
+ // attribute inheritance)
+ aTempSet.ClearInvalidItems();
+
+ // Special treatment: only the valid parts
+ // of the BulletItems
+ if (aTempSet.GetItemState(EE_PARA_BULLET) == SfxItemState::DEFAULT)
+ {
+ SvxBulletItem aOldBulItem( pOutlineSheet->GetItemSet().Get(EE_PARA_BULLET) );
+ const SvxBulletItem& rNewBulItem = aTempSet.Get(EE_PARA_BULLET);
+ aOldBulItem.CopyValidProperties(rNewBulItem);
+ aTempSet.Put(aOldBulItem);
+ }
+
+ pOutlineSheet->GetItemSet().Put(aTempSet);
+ pOutlineSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ }
+ }
+ }
+ else if (pObj == GetPresObj(PresObjKind::Notes, 0))
+ {
+ SfxStyleSheet* pNotesSheet = GetStyleSheetForPresObj(PresObjKind::Notes);
+
+ if (pNotesSheet)
+ {
+ sal_uLong nHeight = pObj->GetLogicRect().GetSize().Height();
+ sal_uLong nFontHeight = static_cast<sal_uLong>(nHeight * 0.0741);
+ SfxItemSet& rSet = pNotesSheet->GetItemSet();
+ rSet.Put( SvxFontHeightItem(nFontHeight, 100, EE_CHAR_FONTHEIGHT ));
+ rSet.Put( SvxFontHeightItem(nFontHeight, 100, EE_CHAR_FONTHEIGHT_CJK ));
+ rSet.Put( SvxFontHeightItem(nFontHeight, 100, EE_CHAR_FONTHEIGHT_CTL ));
+ pNotesSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ }
+ }
+ }
+ else if ( eObjKind != SdrObjKind::TitleText &&
+ eObjKind != SdrObjKind::OutlineText &&
+ dynamic_cast< const SdrTextObj *>( pObj ) != nullptr &&
+ pObj->GetOutlinerParaObject() )
+ {
+ /******************************************************
+ * normal text object: adjust text height
+ ******************************************************/
+ SvtScriptType nScriptType = pObj->GetOutlinerParaObject()->GetTextObject().GetScriptType();
+ sal_uInt16 nWhich = EE_CHAR_FONTHEIGHT;
+ if ( nScriptType == SvtScriptType::ASIAN )
+ nWhich = EE_CHAR_FONTHEIGHT_CJK;
+ else if ( nScriptType == SvtScriptType::COMPLEX )
+ nWhich = EE_CHAR_FONTHEIGHT_CTL;
+
+ // use more modern method to scale the text height
+ sal_uInt32 nFontHeight = static_cast<const SvxFontHeightItem&>(pObj->GetMergedItem(nWhich)).GetHeight();
+ sal_uInt32 nNewFontHeight = sal_uInt32(static_cast<double>(nFontHeight) * static_cast<double>(aFractY));
+
+ pObj->SetMergedItem(SvxFontHeightItem(nNewFontHeight, 100, nWhich));
+ }
+ }
+ }
+
+ if (mbScaleObjects && !pObj->IsEdgeObj())
+ {
+ /**************************************************************
+ * scale object position
+ **************************************************************/
+ Point aNewPos;
+
+ // corrected scaling; only distances may be scaled
+ // use aTopLeft as original TopLeft
+ aNewPos.setX( ::tools::Long((aTopLeft.X() - GetLeftBorder()) * static_cast<double>(aFractX)) + nLeft );
+ aNewPos.setY( ::tools::Long((aTopLeft.Y() - GetUpperBorder()) * static_cast<double>(aFractY)) + nUpper );
+
+ Size aVec(aNewPos.X() - aTopLeft.X(), aNewPos.Y() - aTopLeft.Y());
+
+ if (aVec.Height() != 0 || aVec.Width() != 0)
+ {
+ pObj->NbcMove(aVec);
+ }
+
+ pObj->SetChanged();
+ pObj->BroadcastObjectChange();
+ }
+ }
+ }
+}
+
+static SdrObject* convertPresentationObjectImpl(SdPage& rPage, SdrObject* pSourceObj, PresObjKind& eObjKind, bool bVertical, const ::tools::Rectangle& rRect)
+{
+ SdDrawDocument& rModel(static_cast< SdDrawDocument& >(rPage.getSdrModelFromSdrPage()));
+ if( !pSourceObj )
+ return pSourceObj;
+
+ SfxUndoManager* pUndoManager = rModel.GetUndoManager();
+ const bool bUndo = pUndoManager && pUndoManager->IsInListAction() && rPage.IsInserted();
+
+ SdrObject* pNewObj = pSourceObj;
+ if((eObjKind == PresObjKind::Outline) && (pSourceObj->GetObjIdentifier() == SdrObjKind::Text) )
+ {
+ pNewObj = rPage.CreatePresObj(PresObjKind::Outline, bVertical, rRect);
+
+ // Set text of the subtitle into PRESOBJ_OUTLINE
+ OutlinerParaObject* pOutlParaObj = pSourceObj->GetOutlinerParaObject();
+
+ if(pOutlParaObj)
+ {
+ // assign text
+ SdOutliner* pOutl = rModel.GetInternalOutliner();
+ pOutl->Clear();
+ pOutl->SetText( *pOutlParaObj );
+ pNewObj->SetOutlinerParaObject( pOutl->CreateParaObject() );
+ pOutlParaObj = pNewObj->GetOutlinerParaObject();
+ pOutl->Clear();
+ pNewObj->SetEmptyPresObj(false);
+
+ for (sal_uInt16 nLevel = 1; nLevel < 10; nLevel++)
+ {
+ // assign new template
+ OUString aName( rPage.GetLayoutName() + " " + OUString::number( nLevel ) );
+ SfxStyleSheet* pSheet = static_cast<SfxStyleSheet*>( rModel.GetStyleSheetPool()->Find(aName, SfxStyleFamily::Page) );
+
+ if (pSheet && nLevel == 1)
+ {
+ SfxStyleSheet* pSubtitleSheet = rPage.GetStyleSheetForPresObj(PresObjKind::Text);
+
+ if (pSubtitleSheet)
+ pOutlParaObj->ChangeStyleSheetName(SfxStyleFamily::Page, pSubtitleSheet->GetName(), pSheet->GetName());
+ }
+ }
+
+ // Remove LRSpace item
+ SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aSet(rModel.GetPool());
+
+ aSet.Put(pNewObj->GetMergedItemSet());
+
+ aSet.ClearItem(EE_PARA_LRSPACE);
+
+ pNewObj->SetMergedItemSet(aSet);
+
+ if( bUndo )
+ pUndoManager->AddUndoAction( rModel.GetSdrUndoFactory().CreateUndoDeleteObject(*pSourceObj) );
+
+ // Remove outline shape from page
+ rPage.RemoveObject( pSourceObj->GetOrdNum() );
+
+ if( !bUndo )
+ SdrObject::Free( pSourceObj );
+ }
+ }
+ else if((eObjKind == PresObjKind::Text) && (pSourceObj->GetObjIdentifier() == SdrObjKind::OutlineText) )
+ {
+ // is there an outline shape we can use to replace empty subtitle shape?
+ pNewObj = rPage.CreatePresObj(PresObjKind::Text, bVertical, rRect);
+
+ // Set text of the outline object into PRESOBJ_TITLE
+ OutlinerParaObject* pOutlParaObj = pSourceObj->GetOutlinerParaObject();
+
+ if(pOutlParaObj)
+ {
+ // assign text
+ SdOutliner* pOutl = rModel.GetInternalOutliner();
+ pOutl->Clear();
+ pOutl->SetText( *pOutlParaObj );
+ pNewObj->SetOutlinerParaObject( pOutl->CreateParaObject() );
+ pOutl->Clear();
+ pNewObj->SetEmptyPresObj(false);
+
+ // reset left indent
+ SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aSet(rModel.GetPool());
+
+ aSet.Put(pNewObj->GetMergedItemSet());
+
+ const SvxLRSpaceItem& rLRItem = aSet.Get(EE_PARA_LRSPACE);
+ SvxLRSpaceItem aNewLRItem(rLRItem);
+ aNewLRItem.SetTextLeft(0);
+ aSet.Put(aNewLRItem);
+
+ pNewObj->SetMergedItemSet(aSet);
+
+ SfxStyleSheet* pSheet = rPage.GetStyleSheetForPresObj(PresObjKind::Text);
+ if (pSheet)
+ pNewObj->SetStyleSheet(pSheet, true);
+
+ // Remove subtitle shape from page
+ if( bUndo )
+ pUndoManager->AddUndoAction(rModel.GetSdrUndoFactory().CreateUndoDeleteObject(*pSourceObj));
+
+ rPage.RemoveObject( pSourceObj->GetOrdNum() );
+
+ if( !bUndo )
+ SdrObject::Free( pSourceObj );
+ }
+ }
+ else if((eObjKind == PresObjKind::Outline) && (pSourceObj->GetObjIdentifier() != SdrObjKind::OutlineText) )
+ {
+ switch( pSourceObj->GetObjIdentifier() )
+ {
+ case SdrObjKind::Table: eObjKind = PresObjKind::Table; break;
+ case SdrObjKind::Media: eObjKind = PresObjKind::Media; break;
+ case SdrObjKind::Graphic: eObjKind = PresObjKind::Graphic; break;
+ case SdrObjKind::OLE2: eObjKind = PresObjKind::Object; break;
+ default: break;
+ }
+ }
+
+ return pNewObj;
+}
+
+/** reuses or creates a presentation shape for an auto layout that fits the given parameter
+
+ @param eObjKind
+ The kind of presentation shape we like to have
+ @param nIndex
+ If > 1 we skip the first nIndex-1 shapes with the presentation shape kind eObjKind while
+ looking for an existing presentation shape
+ @param bVertical
+ If true, the shape is created vertical if bInit is true
+ @param rRect
+ The rectangle that should be used to transform the shape
+ @param bInit
+ If true the shape is created if not found
+ @returns
+ A presentation shape that was either found or created with the given parameters
+*/
+SdrObject* SdPage::InsertAutoLayoutShape(SdrObject* pObj, PresObjKind eObjKind, bool bVertical, const ::tools::Rectangle& rRect, bool bInit)
+{
+ SfxUndoManager* pUndoManager(static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetUndoManager());
+ const bool bUndo = pUndoManager && pUndoManager->IsInListAction() && IsInserted();
+
+ if (!pObj && bInit)
+ {
+ pObj = CreatePresObj(eObjKind, bVertical, rRect);
+ }
+ else if ( pObj && (pObj->GetUserCall() || bInit) )
+ {
+ // convert object if shape type does not match kind (f.e. converting outline text to subtitle text)
+ if( bInit )
+ pObj = convertPresentationObjectImpl(*this, pObj, eObjKind, bVertical, rRect);
+
+ if( bUndo )
+ {
+ pUndoManager->AddUndoAction( getSdrModelFromSdrPage().GetSdrUndoFactory().CreateUndoGeoObject( *pObj ) );
+ pUndoManager->AddUndoAction( getSdrModelFromSdrPage().GetSdrUndoFactory().CreateUndoAttrObject( *pObj, true, true ) );
+ pUndoManager->AddUndoAction( std::make_unique<UndoObjectUserCall>( *pObj ) );
+ }
+
+ pObj->AdjustToMaxRect(rRect);
+
+ pObj->SetUserCall(this);
+
+ SdrTextObj* pTextObject = dynamic_cast< SdrTextObj* >(pObj);
+ if( pTextObject )
+ {
+ if( pTextObject->IsVerticalWriting() != bVertical )
+ {
+ pTextObject->SetVerticalWriting( bVertical );
+
+ // here make sure the correct anchoring is used when the object
+ // is re-used but orientation is changed
+ if(PresObjKind::Outline == eObjKind)
+ pTextObject->SetMergedItem(SdrTextHorzAdjustItem( bVertical ? SDRTEXTHORZADJUST_RIGHT : SDRTEXTHORZADJUST_BLOCK ));
+ }
+
+ if( !mbMaster && (pTextObject->GetObjIdentifier() != SdrObjKind::Table) )
+ {
+ if ( pTextObject->IsAutoGrowHeight() )
+ {
+ // switch off AutoGrowHeight, set new MinHeight
+ SfxItemSet aTempAttr( static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetPool() );
+ SdrMetricItem aMinHeight( makeSdrTextMinFrameHeightItem(rRect.GetSize().Height()) );
+ aTempAttr.Put( aMinHeight );
+ aTempAttr.Put( makeSdrTextAutoGrowHeightItem(false) );
+ pTextObject->SetMergedItemSet(aTempAttr);
+ pTextObject->SetLogicRect(rRect);
+
+ // switch on AutoGrowHeight
+ SfxItemSet aAttr( static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetPool() );
+ aAttr.Put( makeSdrTextAutoGrowHeightItem(true) );
+
+ pTextObject->SetMergedItemSet(aAttr);
+ }
+
+ if ( pTextObject->IsAutoGrowWidth() )
+ {
+ // switch off AutoGrowWidth , set new MinWidth
+ SfxItemSet aTempAttr( static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetPool() );
+ SdrMetricItem aMinWidth( makeSdrTextMinFrameWidthItem(rRect.GetSize().Width()) );
+ aTempAttr.Put( aMinWidth );
+ aTempAttr.Put( makeSdrTextAutoGrowWidthItem(false) );
+ pTextObject->SetMergedItemSet(aTempAttr);
+ pTextObject->SetLogicRect(rRect);
+
+ // switch on AutoGrowWidth
+ SfxItemSet aAttr( static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetPool() );
+ aAttr.Put( makeSdrTextAutoGrowWidthItem(true) );
+ pTextObject->SetMergedItemSet(aAttr);
+ }
+ }
+ }
+ }
+
+ if(pObj && bInit )
+ {
+ if( !IsPresObj( pObj ) )
+ {
+ if( bUndo )
+ pUndoManager->AddUndoAction( std::make_unique<UndoObjectPresentationKind>( *pObj ) );
+
+ InsertPresObj( pObj, eObjKind );
+ }
+
+ // make adjustments for vertical title and outline shapes
+ if( bVertical && (( eObjKind == PresObjKind::Title) || (eObjKind == PresObjKind::Outline)))
+ {
+ SfxItemSet aNewSet(pObj->GetMergedItemSet());
+ aNewSet.Put( makeSdrTextAutoGrowWidthItem(true) );
+ aNewSet.Put( makeSdrTextAutoGrowHeightItem(false) );
+ if( eObjKind == PresObjKind::Outline )
+ {
+ aNewSet.Put( SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP) );
+ aNewSet.Put( SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT) );
+ }
+ pObj->SetMergedItemSet(aNewSet);
+ }
+ }
+
+ if ( pObj && (pObj->GetUserCall() || bInit) && ( pObj->IsEmptyPresObj() || dynamic_cast< const SdrGrafObj *>( pObj ) == nullptr ) )
+ pObj->AdjustToMaxRect(rRect);
+
+ return pObj;
+}
+
+/*************************************************************************
+|*
+|* Returns the PresObjKind of an object
+|*
+\************************************************************************/
+
+PresObjKind SdPage::GetPresObjKind(SdrObject* pObj) const
+{
+ PresObjKind eKind = PresObjKind::NONE;
+ if( (pObj != nullptr) && (maPresentationShapeList.hasShape(*pObj)) )
+ {
+ SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pObj);
+ if( pInfo )
+ eKind = pInfo->mePresObjKind;
+ }
+
+ return eKind;
+}
+
+bool SdPage::IsPresObj(const SdrObject* pObj)
+{
+ return pObj && maPresentationShapeList.hasShape( const_cast<SdrObject&>(*pObj) );
+}
+
+void SdPage::RemovePresObj(const SdrObject* pObj)
+{
+ if( pObj && maPresentationShapeList.hasShape(const_cast<SdrObject&>(*pObj)) )
+ {
+ SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(const_cast<SdrObject&>(*pObj));
+ if( pInfo )
+ pInfo->mePresObjKind = PresObjKind::NONE;
+ maPresentationShapeList.removeShape(const_cast<SdrObject&>(*pObj));
+ }
+}
+
+void SdPage::InsertPresObj(SdrObject* pObj, PresObjKind eKind )
+{
+ DBG_ASSERT( pObj, "sd::SdPage::InsertPresObj(), invalid presentation object inserted!" );
+ DBG_ASSERT( !IsPresObj(pObj), "sd::SdPage::InsertPresObj(), presentation object inserted twice!" );
+ if( pObj )
+ {
+ SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pObj, true);
+ if( pInfo )
+ pInfo->mePresObjKind = eKind;
+ maPresentationShapeList.addShape(*pObj);
+ }
+}
+
+/*************************************************************************
+|*
+|* Set the text of an object
+|*
+\************************************************************************/
+
+void SdPage::SetObjText(SdrTextObj* pObj, SdrOutliner* pOutliner, PresObjKind eObjKind, std::u16string_view rString )
+{
+ if ( !pObj )
+ return;
+
+ ::Outliner* pOutl = pOutliner;
+
+ if (!pOutliner)
+ {
+ SfxItemPool* pPool(static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetDrawOutliner().GetEmptyItemSet().GetPool());
+ pOutl = new ::Outliner( pPool, OutlinerMode::OutlineObject );
+ pOutl->SetRefDevice( SD_MOD()->GetVirtualRefDevice() );
+ pOutl->SetEditTextObjectPool(pPool);
+ pOutl->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(getSdrModelFromSdrPage().GetStyleSheetPool()));
+ pOutl->EnableUndo(false);
+ pOutl->SetUpdateLayout( false );
+ }
+
+ OutlinerMode nOutlMode = pOutl->GetOutlinerMode();
+ Size aPaperSize = pOutl->GetPaperSize();
+ bool bUpdateMode = pOutl->SetUpdateLayout(false);
+ pOutl->SetParaAttribs( 0, pOutl->GetEmptyItemSet() );
+
+ // Always set the object's StyleSheet at the Outliner to
+ // use the current objects StyleSheet. Thus it's the same as in
+ // SetText(...).
+ // Moved this implementation from where SetObjText(...) was called
+ // to inside this method to work even when outliner is fetched here.
+ pOutl->SetStyleSheet(0, pObj->GetStyleSheet());
+
+ OUString aString;
+
+ switch( eObjKind )
+ {
+ case PresObjKind::Outline:
+ {
+ pOutl->Init( OutlinerMode::OutlineObject );
+
+ aString += OUString::Concat("\t") + rString;
+
+ if (mbMaster)
+ {
+ pOutl->SetStyleSheet( 0, GetStyleSheetForPresObj(eObjKind) );
+ aString += "\n\t\t" +
+ SdResId(STR_PRESOBJ_MPOUTLLAYER2) +
+ "\n\t\t\t" +
+ SdResId(STR_PRESOBJ_MPOUTLLAYER3) +
+ "\n\t\t\t\t" +
+ SdResId(STR_PRESOBJ_MPOUTLLAYER4) +
+ "\n\t\t\t\t\t" +
+ SdResId(STR_PRESOBJ_MPOUTLLAYER5) +
+ "\n\t\t\t\t\t\t" +
+ SdResId(STR_PRESOBJ_MPOUTLLAYER6) +
+ "\n\t\t\t\t\t\t\t" +
+ SdResId(STR_PRESOBJ_MPOUTLLAYER7);
+
+ }
+ }
+ break;
+
+ case PresObjKind::Title:
+ {
+ pOutl->Init( OutlinerMode::TitleObject );
+ aString += rString;
+ }
+ break;
+
+ default:
+ {
+ pOutl->Init( OutlinerMode::TextObject );
+ aString += rString;
+
+ // check if we need to add a text field
+ std::unique_ptr<SvxFieldData> pData;
+
+ switch( eObjKind )
+ {
+ case PresObjKind::Header:
+ pData.reset(new SvxHeaderField());
+ break;
+ case PresObjKind::Footer:
+ pData .reset(new SvxFooterField());
+ break;
+ case PresObjKind::SlideNumber:
+ pData.reset(new SvxPageField());
+ break;
+ case PresObjKind::DateTime:
+ pData.reset(new SvxDateTimeField());
+ break;
+ default:
+ break;
+ }
+
+ if( pData )
+ {
+ ESelection e;
+ SvxFieldItem aField( *pData, EE_FEATURE_FIELD );
+ pOutl->QuickInsertField(aField,e);
+ }
+ }
+ break;
+ }
+
+ pOutl->SetPaperSize( pObj->GetLogicRect().GetSize() );
+
+ if( !aString.isEmpty() )
+ pOutl->SetText( aString, pOutl->GetParagraph( 0 ) );
+
+ pObj->SetOutlinerParaObject( pOutl->CreateParaObject() );
+
+ if (!pOutliner)
+ {
+ delete pOutl;
+ pOutl = nullptr;
+ }
+ else
+ {
+ // restore the outliner
+ pOutl->Init( nOutlMode );
+ pOutl->SetParaAttribs( 0, pOutl->GetEmptyItemSet() );
+ pOutl->SetUpdateLayout( bUpdateMode );
+ pOutl->SetPaperSize( aPaperSize );
+ }
+}
+
+/*************************************************************************
+|*
+|* Set the name of the layout
+|*
+\************************************************************************/
+void SdPage::SetLayoutName(const OUString& aName)
+{
+ maLayoutName = aName;
+
+ if( mbMaster )
+ {
+ sal_Int32 nPos = maLayoutName.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ FmFormPage::SetName(maLayoutName.copy(0, nPos));
+ }
+}
+
+/*************************************************************************
+|*
+|* Return the page name and generates it if necessary
+|*
+\************************************************************************/
+
+const OUString& SdPage::GetName() const
+{
+ OUString aCreatedPageName( maCreatedPageName );
+ if (GetRealName().isEmpty())
+ {
+ if ((mePageKind == PageKind::Standard || mePageKind == PageKind::Notes) && !mbMaster)
+ {
+ // default name for handout pages
+ sal_uInt16 nNum = (GetPageNum() + 1) / 2;
+
+ aCreatedPageName = SdResId(STR_PAGE) + " ";
+ if (static_cast<SdDrawDocument&>(getSdrModelFromSdrPage()).GetDocumentType() == DocumentType::Draw )
+ aCreatedPageName = SdResId(STR_PAGE_NAME) + " ";
+
+ if( getSdrModelFromSdrPage().GetPageNumType() == css::style::NumberingType::NUMBER_NONE )
+ {
+ // if the document has number none as a formatting
+ // for page numbers we still default to arabic numbering
+ // to keep the default page names unique
+ aCreatedPageName += OUString::number( static_cast<sal_Int32>(nNum) );
+ }
+ else
+ {
+ aCreatedPageName += static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).CreatePageNumValue(nNum);
+ }
+ }
+ else
+ {
+ /******************************************************************
+ * default name for note pages
+ ******************************************************************/
+ aCreatedPageName = SdResId(STR_LAYOUT_DEFAULT_NAME);
+ }
+ }
+ else
+ {
+ aCreatedPageName = GetRealName();
+ }
+
+ if (mePageKind == PageKind::Notes)
+ {
+ aCreatedPageName += " " + SdResId(STR_NOTES);
+ }
+ else if (mePageKind == PageKind::Handout && mbMaster)
+ {
+ aCreatedPageName += " (" + SdResId(STR_HANDOUT) + ")";
+ }
+
+ const_cast< SdPage* >(this)->maCreatedPageName = aCreatedPageName;
+ return maCreatedPageName;
+}
+
+void SdPage::SetOrientation( Orientation /*eOrient*/)
+{
+ // Do nothing
+}
+
+Orientation SdPage::GetOrientation() const
+{
+ Size aSize = GetSize();
+ if ( aSize.getWidth() > aSize.getHeight() )
+ {
+ return Orientation::Landscape;
+ }
+ else
+ {
+ return Orientation::Portrait;
+ }
+}
+
+/*************************************************************************
+|*
+|* returns the default text of a PresObjektes
+|*
+\************************************************************************/
+
+OUString SdPage::GetPresObjText(PresObjKind eObjKind) const
+{
+ OUString aString;
+
+#if defined(IOS) || defined(ANDROID)
+ bool isMobileDevice = true;
+#else
+ bool isMobileDevice = false;
+ if (const SfxViewShell* pCurrentViewShell = SfxViewShell::Current())
+ isMobileDevice = pCurrentViewShell->isLOKMobilePhone() || pCurrentViewShell->isLOKTablet();
+#endif
+
+ if (eObjKind == PresObjKind::Title)
+ {
+ if (mbMaster)
+ {
+ if (mePageKind != PageKind::Notes)
+ {
+ if (isMobileDevice)
+ aString = SdResId(STR_PRESOBJ_MPTITLE_MOBILE);
+ else
+ aString = SdResId(STR_PRESOBJ_MPTITLE);
+ }
+ else
+ {
+ if (isMobileDevice)
+ aString = SdResId(STR_PRESOBJ_MPNOTESTITLE_MOBILE);
+ else
+ aString = SdResId(STR_PRESOBJ_MPNOTESTITLE);
+ }
+ }
+ else if (isMobileDevice)
+ aString = SdResId(STR_PRESOBJ_TITLE_MOBILE);
+ else
+ aString = SdResId(STR_PRESOBJ_TITLE);
+ }
+ else if (eObjKind == PresObjKind::Outline)
+ {
+ if (mbMaster)
+ {
+ if (isMobileDevice)
+ aString = SdResId(STR_PRESOBJ_MPOUTLINE_MOBILE);
+ else
+ aString = SdResId(STR_PRESOBJ_MPOUTLINE);
+ }
+ else if (isMobileDevice)
+ aString = SdResId(STR_PRESOBJ_OUTLINE_MOBILE);
+ else
+ aString = SdResId(STR_PRESOBJ_OUTLINE);
+ }
+ else if (eObjKind == PresObjKind::Notes)
+ {
+ if (mbMaster)
+ {
+ if (isMobileDevice)
+ aString = SdResId(STR_PRESOBJ_MPNOTESTEXT_MOBILE);
+ else
+ aString = SdResId(STR_PRESOBJ_MPNOTESTEXT);
+ }
+ else if (isMobileDevice)
+ aString = SdResId(STR_PRESOBJ_NOTESTEXT_MOBILE);
+ else
+ aString = SdResId(STR_PRESOBJ_NOTESTEXT);
+ }
+ else if (eObjKind == PresObjKind::Text)
+ {
+ if (isMobileDevice)
+ aString = SdResId(STR_PRESOBJ_TEXT_MOBILE);
+ else
+ aString = SdResId(STR_PRESOBJ_TEXT);
+ }
+ else if (eObjKind == PresObjKind::Graphic)
+ {
+ aString = SdResId( STR_PRESOBJ_GRAPHIC );
+ }
+ else if (eObjKind == PresObjKind::Object)
+ {
+ aString = SdResId( STR_PRESOBJ_OBJECT );
+ }
+ else if (eObjKind == PresObjKind::Chart)
+ {
+ aString = SdResId( STR_PRESOBJ_CHART );
+ }
+ else if (eObjKind == PresObjKind::OrgChart)
+ {
+ aString = SdResId( STR_PRESOBJ_ORGCHART );
+ }
+ else if (eObjKind == PresObjKind::Calc)
+ {
+ aString = SdResId( STR_PRESOBJ_TABLE );
+ }
+
+ return aString;
+}
+
+uno::Reference< uno::XInterface > SdPage::createUnoPage()
+{
+ return createUnoPageImpl( this );
+}
+
+/** returns the SdPage implementation for the given XDrawPage or 0 if not available */
+SdPage* SdPage::getImplementation( const css::uno::Reference< css::drawing::XDrawPage >& xPage )
+{
+ try
+ {
+ auto pUnoPage = comphelper::getFromUnoTunnel<SvxDrawPage>(xPage);
+ if( pUnoPage )
+ return static_cast< SdPage* >( pUnoPage->GetSdrPage() );
+ }
+ catch( css::uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SdPage::getImplementation()" );
+ }
+
+ return nullptr;
+}
+
+sal_Int64 SdPage::GetHashCode() const
+{
+ return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this));
+}
+
+void SdPage::SetName (const OUString& rName)
+{
+ OUString aOldName( GetName() );
+ FmFormPage::SetName (rName);
+ static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).UpdatePageRelativeURLs(aOldName, rName);
+ ActionChanged();
+}
+
+const HeaderFooterSettings& SdPage::getHeaderFooterSettings() const
+{
+ if( mePageKind == PageKind::Handout && !mbMaster )
+ {
+ return static_cast<SdPage&>(TRG_GetMasterPage()).maHeaderFooterSettings;
+ }
+ else
+ {
+ return maHeaderFooterSettings;
+ }
+}
+
+void SdPage::setHeaderFooterSettings( const sd::HeaderFooterSettings& rNewSettings )
+{
+ if( mePageKind == PageKind::Handout && !mbMaster )
+ {
+ static_cast<SdPage&>(TRG_GetMasterPage()).maHeaderFooterSettings = rNewSettings;
+ }
+ else
+ {
+ maHeaderFooterSettings = rNewSettings;
+ }
+
+ SetChanged();
+
+ if(!TRG_HasMasterPage())
+ return;
+
+ TRG_GetMasterPageDescriptorViewContact().ActionChanged();
+
+ // #i119056# For HeaderFooterSettings SdrObjects are used, but the properties
+ // used are not part of their model data, but kept in SD. This data is applied
+ // using a 'backdoor' on primitive creation. Thus, the normal mechanism to detect
+ // object changes does not work here. It is necessary to trigger updates here
+ // directly. BroadcastObjectChange used for PagePreview invalidations,
+ // flushViewObjectContacts used to invalidate and flush all visualizations in
+ // edit views.
+ SdPage* pMasterPage = dynamic_cast< SdPage* >(&TRG_GetMasterPage());
+
+ if(!pMasterPage)
+ return;
+
+ SdrObject* pCandidate = pMasterPage->GetPresObj( PresObjKind::Header );
+
+ if(pCandidate)
+ {
+ pCandidate->BroadcastObjectChange();
+ pCandidate->GetViewContact().flushViewObjectContacts();
+ }
+
+ pCandidate = pMasterPage->GetPresObj( PresObjKind::DateTime );
+
+ if(pCandidate)
+ {
+ pCandidate->BroadcastObjectChange();
+ pCandidate->GetViewContact().flushViewObjectContacts();
+ }
+
+ pCandidate = pMasterPage->GetPresObj( PresObjKind::Footer );
+
+ if(pCandidate)
+ {
+ pCandidate->BroadcastObjectChange();
+ pCandidate->GetViewContact().flushViewObjectContacts();
+ }
+
+ pCandidate = pMasterPage->GetPresObj( PresObjKind::SlideNumber );
+
+ if(pCandidate)
+ {
+ pCandidate->BroadcastObjectChange();
+ pCandidate->GetViewContact().flushViewObjectContacts();
+ }
+}
+
+bool SdPage::checkVisibility(
+ const sdr::contact::ViewObjectContact& rOriginal,
+ const sdr::contact::DisplayInfo& rDisplayInfo,
+ bool bEdit )
+{
+ if( !FmFormPage::checkVisibility( rOriginal, rDisplayInfo, bEdit ) )
+ return false;
+
+ SdrObject* pObj = rOriginal.GetViewContact().TryToGetSdrObject();
+ if( pObj == nullptr )
+ return false;
+
+ const SdrPage* pVisualizedPage = GetSdrPageFromXDrawPage(rOriginal.GetObjectContact().getViewInformation2D().getVisualizedPage());
+ const bool bIsPrinting(rOriginal.GetObjectContact().isOutputToPrinter() || rOriginal.GetObjectContact().isOutputToPDFFile());
+ const SdrPageView* pPageView = rOriginal.GetObjectContact().TryToGetSdrPageView();
+ const bool bIsInsidePageObj(pPageView && pPageView->GetPage() != pVisualizedPage);
+
+ // empty presentation objects only visible during edit mode
+ if( (bIsPrinting || !bEdit || bIsInsidePageObj ) && pObj->IsEmptyPresObj() )
+ {
+ if( (pObj->GetObjInventor() != SdrInventor::Default) || ( (pObj->GetObjIdentifier() != SdrObjKind::Rectangle) && (pObj->GetObjIdentifier() != SdrObjKind::Page) ) )
+ return false;
+ }
+
+ if( ( pObj->GetObjInventor() == SdrInventor::Default ) && ( pObj->GetObjIdentifier() == SdrObjKind::Text ) )
+ {
+ const SdPage* pCheckPage = dynamic_cast< const SdPage* >(pObj->getSdrPageFromSdrObject());
+
+ if( pCheckPage )
+ {
+ PresObjKind eKind = pCheckPage->GetPresObjKind(pObj);
+
+ if((eKind == PresObjKind::Footer) || (eKind == PresObjKind::Header) || (eKind == PresObjKind::DateTime) || (eKind == PresObjKind::SlideNumber) )
+ {
+ const bool bSubContentProcessing(rDisplayInfo.GetSubContentActive());
+
+ if( bSubContentProcessing || ( pCheckPage->GetPageKind() == PageKind::Handout && bIsPrinting ) )
+ {
+ // use the page that is currently processed
+ const SdPage* pVisualizedSdPage = dynamic_cast< const SdPage* >(pVisualizedPage);
+
+ if( pVisualizedSdPage )
+ {
+ // if we are not on a masterpage, see if we have to draw this header&footer object at all
+ const sd::HeaderFooterSettings& rSettings = pVisualizedSdPage->getHeaderFooterSettings();
+
+ switch( eKind )
+ {
+ case PresObjKind::Footer:
+ return rSettings.mbFooterVisible;
+ case PresObjKind::Header:
+ return rSettings.mbHeaderVisible;
+ case PresObjKind::DateTime:
+ return rSettings.mbDateTimeVisible;
+ case PresObjKind::SlideNumber:
+ return rSettings.mbSlideNumberVisible;
+ default:
+ break;
+ }
+ }
+ }
+ } // check for placeholders on master
+ else if( (eKind != PresObjKind::NONE) && pCheckPage->IsMasterPage() && ( pVisualizedPage != pCheckPage ) )
+ {
+ // presentation objects on master slide are always invisible if slide is shown.
+ return false;
+ }
+ }
+ }
+
+ // i63977, do not print SdrpageObjs from master pages
+ if( ( pObj->GetObjInventor() == SdrInventor::Default ) && ( pObj->GetObjIdentifier() == SdrObjKind::Page ) )
+ {
+ if( pObj->getSdrPageFromSdrObject() && pObj->getSdrPageFromSdrObject()->IsMasterPage() )
+ return false;
+ }
+
+ return true;
+}
+
+bool SdPage::RestoreDefaultText( SdrObject* pObj )
+{
+ bool bRet = false;
+
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObj );
+
+ if( pTextObj )
+ {
+ PresObjKind ePresObjKind = GetPresObjKind(pTextObj);
+
+ if (ePresObjKind == PresObjKind::Title ||
+ ePresObjKind == PresObjKind::Outline ||
+ ePresObjKind == PresObjKind::Notes ||
+ ePresObjKind == PresObjKind::Text)
+ {
+ OUString aString( GetPresObjText(ePresObjKind) );
+
+ if (!aString.isEmpty())
+ {
+ bool bVertical = false;
+ OutlinerParaObject* pOldPara = pTextObj->GetOutlinerParaObject();
+ if( pOldPara )
+ bVertical = pOldPara->IsEffectivelyVertical(); // is old para object vertical?
+
+ SetObjText( pTextObj, nullptr, ePresObjKind, aString );
+
+ if( pOldPara )
+ {
+ // Here, only the vertical flag for the
+ // OutlinerParaObjects needs to be changed. The
+ // AutoGrowWidth/Height items still exist in the
+ // not changed object.
+ if(pTextObj->GetOutlinerParaObject()
+ && pTextObj->GetOutlinerParaObject()->IsEffectivelyVertical() != bVertical)
+ {
+ ::tools::Rectangle aObjectRect = pTextObj->GetSnapRect();
+ pTextObj->GetOutlinerParaObject()->SetVertical(bVertical);
+ pTextObj->SetSnapRect(aObjectRect);
+ }
+ }
+
+ pTextObj->SetTextEditOutliner( nullptr ); // to make stylesheet settings work
+ pTextObj->NbcSetStyleSheet( GetStyleSheetForPresObj(ePresObjKind), true );
+ pTextObj->SetEmptyPresObj(true);
+ bRet = true;
+ }
+ }
+ }
+ return bRet;
+}
+
+void SdPage::CalculateHandoutAreas( SdDrawDocument& rModel, AutoLayout eLayout, bool bHorizontal, std::vector< ::tools::Rectangle >& rAreas )
+{
+ SdPage& rHandoutMaster = *rModel.GetMasterSdPage( 0, PageKind::Handout );
+
+ static const sal_uInt16 aOffsets[5][9] =
+ {
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, // AUTOLAYOUT_HANDOUT9, Portrait, Horizontal order
+ { 0, 2, 4, 1, 3, 5, 0, 0, 0 }, // AUTOLAYOUT_HANDOUT3, Landscape, Vertical
+ { 0, 2, 1, 3, 0, 0, 0, 0, 0 }, // AUTOLAYOUT_HANDOUT4, Landscape, Vertical
+ { 0, 3, 1, 4, 2, 5, 0, 0, 0 }, // AUTOLAYOUT_HANDOUT4, Portrait, Vertical
+ { 0, 3, 6, 1, 4, 7, 2, 5, 8 }, // AUTOLAYOUT_HANDOUT9, Landscape, Vertical
+ };
+
+ const sal_uInt16* pOffsets = aOffsets[0];
+
+ Size aArea = rHandoutMaster.GetSize();
+ const bool bLandscape = aArea.Width() > aArea.Height();
+
+ if( eLayout == AUTOLAYOUT_NONE )
+ {
+ // use layout from handout master
+ SdrObjListIter aShapeIter(&rHandoutMaster);
+
+ std::vector< ::tools::Rectangle > vSlidesAreas;
+ while ( aShapeIter.IsMore() )
+ {
+ SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>( aShapeIter.Next() );
+ // get slide rectangles
+ if (pPageObj)
+ vSlidesAreas.push_back( pPageObj->GetCurrentBoundRect() );
+ }
+
+ if ( !bHorizontal || vSlidesAreas.size() < 4 )
+ { // top to bottom, then right
+ rAreas.swap( vSlidesAreas );
+ }
+ else
+ { // left to right, then down
+ switch ( vSlidesAreas.size() )
+ {
+ case 4:
+ pOffsets = aOffsets[2];
+ break;
+
+ default:
+ [[fallthrough]];
+ case 6:
+ pOffsets = aOffsets[ bLandscape ? 3 : 1 ];
+ break;
+
+ case 9:
+ pOffsets = aOffsets[4];
+ break;
+ }
+
+ rAreas.resize( static_cast<size_t>(vSlidesAreas.size()) );
+
+ for( const ::tools::Rectangle& rRect : vSlidesAreas )
+ {
+ rAreas[*pOffsets++] = rRect;
+ }
+ }
+ }
+ else
+ {
+ const ::tools::Long nGapW = 1000; // gap is 1cm
+ const ::tools::Long nGapH = 1000;
+
+ ::tools::Long nLeftBorder = rHandoutMaster.GetLeftBorder();
+ ::tools::Long nRightBorder = rHandoutMaster.GetRightBorder();
+ ::tools::Long nTopBorder = rHandoutMaster.GetUpperBorder();
+ ::tools::Long nBottomBorder = rHandoutMaster.GetLowerBorder();
+
+ const ::tools::Long nHeaderFooterHeight = static_cast< ::tools::Long >( (aArea.Height() - nTopBorder - nLeftBorder) * 0.05 );
+
+ nTopBorder += nHeaderFooterHeight;
+ nBottomBorder += nHeaderFooterHeight;
+
+ ::tools::Long nX = nGapW + nLeftBorder;
+ ::tools::Long nY = nGapH + nTopBorder;
+
+ aArea.AdjustWidth( -(nGapW * 2 + nLeftBorder + nRightBorder) );
+ aArea.AdjustHeight( -(nGapH * 2 + nTopBorder + nBottomBorder) );
+
+ sal_uInt16 nColCnt = 0, nRowCnt = 0;
+ switch ( eLayout )
+ {
+ case AUTOLAYOUT_HANDOUT1:
+ nColCnt = 1; nRowCnt = 1;
+ break;
+
+ case AUTOLAYOUT_HANDOUT2:
+ if( bLandscape )
+ {
+ nColCnt = 2; nRowCnt = 1;
+ }
+ else
+ {
+ nColCnt = 1; nRowCnt = 2;
+ }
+ break;
+
+ case AUTOLAYOUT_HANDOUT3:
+ if( bLandscape )
+ {
+ nColCnt = 3; nRowCnt = 2;
+ }
+ else
+ {
+ nColCnt = 2; nRowCnt = 3;
+ }
+ pOffsets = aOffsets[ bLandscape ? 1 : 0 ];
+ break;
+
+ case AUTOLAYOUT_HANDOUT4:
+ nColCnt = 2; nRowCnt = 2;
+ pOffsets = aOffsets[ bHorizontal ? 0 : 2 ];
+ break;
+
+ case AUTOLAYOUT_HANDOUT6:
+ if( bLandscape )
+ {
+ nColCnt = 3; nRowCnt = 2;
+ }
+ else
+ {
+ nColCnt = 2; nRowCnt = 3;
+ }
+ if( !bHorizontal )
+ pOffsets = aOffsets[ bLandscape ? 1 : 3 ];
+ break;
+
+ default:
+ case AUTOLAYOUT_HANDOUT9:
+ nColCnt = 3; nRowCnt = 3;
+
+ if( !bHorizontal )
+ pOffsets = aOffsets[4];
+ break;
+ }
+
+ rAreas.resize(static_cast<size_t>(nColCnt) * nRowCnt);
+
+ Size aPartArea, aSize;
+ aPartArea.setWidth( (aArea.Width() - ((nColCnt-1) * nGapW) ) / nColCnt );
+ aPartArea.setHeight( (aArea.Height() - ((nRowCnt-1) * nGapH) ) / nRowCnt );
+
+ SdrPage* pFirstPage = rModel.GetMasterSdPage(0, PageKind::Standard);
+ if (pFirstPage && pFirstPage->GetWidth() && pFirstPage->GetHeight())
+ {
+ // scale actual size into handout rect
+ double fScale = static_cast<double>(aPartArea.Width()) / static_cast<double>(pFirstPage->GetWidth());
+
+ aSize.setHeight( static_cast<::tools::Long>(fScale * pFirstPage->GetHeight() ) );
+ if( aSize.Height() > aPartArea.Height() )
+ {
+ fScale = static_cast<double>(aPartArea.Height()) / static_cast<double>(pFirstPage->GetHeight());
+ aSize.setHeight( aPartArea.Height() );
+ aSize.setWidth( static_cast<::tools::Long>(fScale * pFirstPage->GetWidth()) );
+ }
+ else
+ {
+ aSize.setWidth( aPartArea.Width() );
+ }
+
+ nX += (aPartArea.Width() - aSize.Width()) / 2;
+ nY += (aPartArea.Height()- aSize.Height())/ 2;
+ }
+ else
+ {
+ aSize = aPartArea;
+ }
+
+ Point aPos( nX, nY );
+
+ const bool bRTL = rModel.GetDefaultWritingMode() == css::text::WritingMode_RL_TB;
+
+ const ::tools::Long nOffsetX = (aPartArea.Width() + nGapW) * (bRTL ? -1 : 1);
+ const ::tools::Long nOffsetY = aPartArea.Height() + nGapH;
+ const ::tools::Long nStartX = bRTL ? nOffsetX*(1 - nColCnt) + nX : nX;
+
+ for(sal_uInt16 nRow = 0; nRow < nRowCnt; nRow++)
+ {
+ aPos.setX( nStartX );
+ for(sal_uInt16 nCol = 0; nCol < nColCnt; nCol++)
+ {
+ rAreas[*pOffsets++] = ::tools::Rectangle(aPos, aSize);
+ aPos.AdjustX(nOffsetX );
+ }
+
+ aPos.AdjustY(nOffsetY );
+ }
+ }
+}
+
+void SdPage::SetPrecious (const bool bIsPrecious)
+{
+ mbIsPrecious = bIsPrecious;
+}
+
+HeaderFooterSettings::HeaderFooterSettings()
+{
+ mbHeaderVisible = true;
+ mbFooterVisible = true;
+ mbSlideNumberVisible = false;
+ mbDateTimeVisible = true;
+ mbDateTimeIsFixed = true;
+ meDateFormat = SvxDateFormat::A;
+ meTimeFormat = SvxTimeFormat::AppDefault;
+}
+
+bool HeaderFooterSettings::operator==( const HeaderFooterSettings& rSettings ) const
+{
+ return (mbHeaderVisible == rSettings.mbHeaderVisible) &&
+ (maHeaderText == rSettings.maHeaderText) &&
+ (mbFooterVisible == rSettings.mbFooterVisible) &&
+ (maFooterText == rSettings.maFooterText) &&
+ (mbSlideNumberVisible == rSettings.mbSlideNumberVisible) &&
+ (mbDateTimeVisible == rSettings.mbDateTimeVisible) &&
+ (mbDateTimeIsFixed == rSettings.mbDateTimeIsFixed) &&
+ (meDateFormat == rSettings.meDateFormat) &&
+ (meTimeFormat == rSettings.meTimeFormat) &&
+ (maDateTimeText == rSettings.maDateTimeText);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/sdpage2.cxx b/sd/source/core/sdpage2.cxx
new file mode 100644
index 000000000..a5c8d1d5f
--- /dev/null
+++ b/sd/source/core/sdpage2.cxx
@@ -0,0 +1,651 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vector>
+#include <libxml/xmlwriter.h>
+#include <sfx2/docfile.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <svx/svdundo.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/xmlcnitm.hxx>
+#include <svx/svditer.hxx>
+#include <com/sun/star/text/XTextCopy.hpp>
+#include <tools/debug.hxx>
+#include <svx/svddef.hxx>
+#include <rtl/math.hxx>
+#include <svx/svdograf.hxx>
+
+#include <Annotation.hxx>
+#include <notifydocumentevent.hxx>
+#include <sdresid.hxx>
+#include <sdpage.hxx>
+#include <glob.hxx>
+#include <strings.hrc>
+#include <drawdoc.hxx>
+#include <stlpool.hxx>
+#include <pglink.hxx>
+
+#include <strings.hxx>
+#include <DrawDocShell.hxx>
+
+#include <svl/itemset.hxx>
+
+using namespace ::sd;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::office;
+
+/*************************************************************************
+|*
+|* Sets: names of layout, master page links and templates for presentation
+|* objects
+|*
+|* Preconditions: - The page has to know the correct model!
+|* - The corresponding master page has to be in the model.
+|* - The corresponding style sheets have to be in the style sheet
+|* pool.
+|*
+|* bReplaceStyleSheets = sal_True : Named style sheets are replaced
+|* sal_False: All style sheets are reassigned
+|*
+|* bSetMasterPage = sal_True : search and assign master page
+|*
+|* bReverseOrder = sal_False: search master page from head to tail
+|* sal_True : search master page from tail to head
+|* (for undo operations)
+|*
+\************************************************************************/
+
+void SdPage::SetPresentationLayout(std::u16string_view rLayoutName,
+ bool bReplaceStyleSheets,
+ bool bSetMasterPage,
+ bool bReverseOrder)
+{
+ /*********************************************************************
+ |* Name of the layout of the page
+ \********************************************************************/
+ OUString aOldLayoutName(maLayoutName); // memorize
+ maLayoutName = OUString::Concat(rLayoutName) + SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE;
+
+ /*********************************************************************
+ |* search and replace master page if necessary
+ \********************************************************************/
+ if (bSetMasterPage && !IsMasterPage())
+ {
+ SdPage* pMaster;
+ SdPage* pFoundMaster = nullptr;
+ sal_uInt16 nMaster = 0;
+ sal_uInt16 nMasterCount = getSdrModelFromSdrPage().GetMasterPageCount();
+
+ if( !bReverseOrder )
+ {
+ for ( nMaster = 0; nMaster < nMasterCount; nMaster++ )
+ {
+ pMaster = static_cast<SdPage*>(getSdrModelFromSdrPage().GetMasterPage(nMaster));
+ if (pMaster->GetPageKind() == mePageKind && pMaster->GetLayoutName() == maLayoutName)
+ {
+ pFoundMaster = pMaster;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for ( nMaster = nMasterCount; nMaster > 0; nMaster-- )
+ {
+ pMaster = static_cast<SdPage*>(getSdrModelFromSdrPage().GetMasterPage(nMaster - 1));
+ if (pMaster->GetPageKind() == mePageKind && pMaster->GetLayoutName() == maLayoutName)
+ {
+ pFoundMaster = pMaster;
+ break;
+ }
+ }
+ }
+
+ DBG_ASSERT(pFoundMaster, "Masterpage for presentation layout not found!");
+
+ // this should never happen, but we play failsafe here
+ if( pFoundMaster == nullptr )
+ pFoundMaster = static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetSdPage( 0, mePageKind );
+
+ if( pFoundMaster )
+ TRG_SetMasterPage(*pFoundMaster);
+ }
+
+ /*********************************************************************
+ |* templates for presentation objects
+ \********************************************************************/
+ // list with:
+ // - pointer to templates for outline text object (old and new templates)
+ // - replace-data for OutlinerParaObject
+ std::vector<SfxStyleSheetBase*> aOutlineStyles;
+ std::vector<SfxStyleSheetBase*> aOldOutlineStyles;
+ std::vector<StyleReplaceData> aReplList;
+ bool bListsFilled = false;
+
+ const size_t nObjCount = GetObjCount();
+
+ for (size_t nObj = 0; nObj < nObjCount; ++nObj)
+ {
+ auto pObj = GetObj(nObj);
+
+ if (pObj->GetObjInventor() == SdrInventor::Default &&
+ pObj->GetObjIdentifier() == SdrObjKind::OutlineText)
+ {
+ if (!bListsFilled || !bReplaceStyleSheets)
+ {
+ OUString aFullName;
+ OUString aOldFullName;
+ SfxStyleSheetBase* pSheet = nullptr;
+ SfxStyleSheetBasePool* pStShPool = getSdrModelFromSdrPage().GetStyleSheetPool();
+
+ for (sal_Int16 i = -1; i < 9; i++)
+ {
+ aOldFullName = aOldLayoutName + " " +
+ OUString::number( (i <= 0 ) ? 1 : i + 1 );
+ aFullName = maLayoutName + " " +
+ OUString::number( (i <= 0 ) ? 1 : i + 1);
+ pSheet = pStShPool->Find(aOldFullName, SfxStyleFamily::Page);
+ DBG_ASSERT(pSheet, "Old outline style sheet not found");
+ aOldOutlineStyles.push_back(pSheet);
+
+ pSheet = pStShPool->Find(aFullName, SfxStyleFamily::Page);
+ DBG_ASSERT(pSheet, "New outline style sheet not found");
+ aOutlineStyles.push_back(pSheet);
+
+ if (bReplaceStyleSheets && pSheet)
+ {
+ // Replace instead Set
+ StyleReplaceData aReplData;
+ aReplData.nNewFamily = pSheet->GetFamily();
+ aReplData.nFamily = pSheet->GetFamily();
+ aReplData.aNewName = aFullName;
+ aReplData.aName = aOldFullName;
+ aReplList.push_back(aReplData);
+ }
+ else
+ {
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+
+ if( pOPO )
+ pOPO->SetStyleSheets( i, aFullName, SfxStyleFamily::Page );
+ }
+ }
+
+ bListsFilled = true;
+ }
+
+
+ std::vector<SfxStyleSheetBase*>::iterator iterOldOut = aOldOutlineStyles.begin();
+
+ for (const auto& rpOut : aOutlineStyles)
+ {
+ SfxStyleSheet* pSheet = static_cast<SfxStyleSheet*>(rpOut);
+ SfxStyleSheet* pOldSheet = static_cast<SfxStyleSheet*>(*iterOldOut);
+
+ if (pSheet != pOldSheet)
+ {
+ if (pOldSheet)
+ pObj->EndListening(*pOldSheet);
+
+ if (pSheet && !pObj->IsListening(*pSheet))
+ pObj->StartListening(*pSheet);
+ }
+
+ ++iterOldOut;
+ }
+
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+ if ( bReplaceStyleSheets && pOPO )
+ {
+ for (const auto& rRepl : aReplList)
+ {
+ pOPO->ChangeStyleSheets( rRepl.aName, rRepl.nFamily, rRepl.aNewName, rRepl.nNewFamily );
+ }
+ }
+ }
+ else if (pObj->GetObjInventor() == SdrInventor::Default &&
+ pObj->GetObjIdentifier() == SdrObjKind::TitleText)
+ {
+ // We do not get PresObjKind via GetPresObjKind() since there are
+ // only PresObjListe considered. But we want to consider all "Title
+ // objects" here (paste from clipboard etc.)
+ SfxStyleSheet* pSheet = GetStyleSheetForPresObj(PresObjKind::Title);
+
+ if (pSheet)
+ pObj->SetStyleSheet(pSheet, true);
+ }
+ else
+ {
+ SfxStyleSheet* pSheet = GetStyleSheetForPresObj(GetPresObjKind(pObj));
+
+ if (pSheet)
+ pObj->SetStyleSheet(pSheet, true);
+ }
+ }
+}
+
+/*************************************************************************
+|*
+|* disconnect outline text object from templates for outline levels
+|*
+\************************************************************************/
+
+void SdPage::EndListenOutlineText()
+{
+ SdrObject* pOutlineTextObj = GetPresObj(PresObjKind::Outline);
+
+ if (!pOutlineTextObj)
+ return;
+
+ SdStyleSheetPool* pSPool = static_cast<SdStyleSheetPool*>(getSdrModelFromSdrPage().GetStyleSheetPool());
+ DBG_ASSERT(pSPool, "StyleSheetPool missing");
+ OUString aTrueLayoutName(maLayoutName);
+ sal_Int32 nIndex = aTrueLayoutName.indexOf( SD_LT_SEPARATOR );
+ if( nIndex != -1 )
+ aTrueLayoutName = aTrueLayoutName.copy(0, nIndex);
+
+ std::vector<SfxStyleSheetBase*> aOutlineStyles;
+ pSPool->CreateOutlineSheetList(aTrueLayoutName,aOutlineStyles);
+
+ for (const auto& rpStyle : aOutlineStyles)
+ {
+ SfxStyleSheet *pSheet = static_cast<SfxStyleSheet*>(rpStyle);
+ pOutlineTextObj->EndListening(*pSheet);
+ }
+}
+
+/*************************************************************************
+|*
+|* Is this page read-only?
+|*
+\************************************************************************/
+
+bool SdPage::IsReadOnly() const
+{
+ return false;
+}
+
+/*************************************************************************
+|*
+|* Connect to sfx2::LinkManager
+|*
+\************************************************************************/
+
+void SdPage::ConnectLink()
+{
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrPage().GetLinkManager());
+
+ if (!(pLinkManager && !mpPageLink && !maFileName.isEmpty() && !maBookmarkName.isEmpty() &&
+ mePageKind==PageKind::Standard && !IsMasterPage() &&
+ static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).IsNewOrLoadCompleted()))
+ return;
+
+ /**********************************************************************
+ * Connect
+ * Only standard pages are allowed to be linked
+ **********************************************************************/
+ ::sd::DrawDocShell* pDocSh = static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()).GetDocSh();
+
+ if (!pDocSh || pDocSh->GetMedium()->GetOrigURL() != maFileName)
+ {
+ // No links to document owned pages!
+ mpPageLink = new SdPageLink(this, maFileName, maBookmarkName);
+ OUString aFilterName(SdResId(STR_IMPRESS));
+ pLinkManager->InsertFileLink(*mpPageLink, sfx2::SvBaseLinkObjectType::ClientFile,
+ maFileName, &aFilterName, &maBookmarkName);
+ mpPageLink->Connect();
+ }
+}
+
+/*************************************************************************
+|*
+|* Disconnect from sfx2::LinkManager
+|*
+\************************************************************************/
+
+void SdPage::DisconnectLink()
+{
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrPage().GetLinkManager());
+
+ if (pLinkManager && mpPageLink)
+ {
+ /**********************************************************************
+ * Disconnect
+ * (remove deletes *pGraphicLink implicit)
+ **********************************************************************/
+ pLinkManager->Remove(mpPageLink);
+ mpPageLink=nullptr;
+ }
+}
+
+void SdPage::lateInit(const SdPage& rSrcPage)
+{
+ // call parent
+ FmFormPage::lateInit(rSrcPage);
+
+ // copy local variables (former stuff from copy constructor)
+ mePageKind = rSrcPage.mePageKind;
+ meAutoLayout = rSrcPage.meAutoLayout;
+ mbSelected = false;
+ mnTransitionType = rSrcPage.mnTransitionType;
+ mnTransitionSubtype = rSrcPage.mnTransitionSubtype;
+ mbTransitionDirection = rSrcPage.mbTransitionDirection;
+ mnTransitionFadeColor = rSrcPage.mnTransitionFadeColor;
+ mfTransitionDuration = rSrcPage.mfTransitionDuration;
+ mePresChange = rSrcPage.mePresChange;
+ mfTime = rSrcPage.mfTime;
+ mbSoundOn = rSrcPage.mbSoundOn;
+ mbExcluded = rSrcPage.mbExcluded;
+ maLayoutName = rSrcPage.maLayoutName;
+ maSoundFile = rSrcPage.maSoundFile;
+ mbLoopSound = rSrcPage.mbLoopSound;
+ mbStopSound = rSrcPage.mbStopSound;
+ maCreatedPageName.clear();
+ maFileName = rSrcPage.maFileName;
+ maBookmarkName = rSrcPage.maBookmarkName;
+ mbScaleObjects = rSrcPage.mbScaleObjects;
+ meCharSet = rSrcPage.meCharSet;
+ mnPaperBin = rSrcPage.mnPaperBin;
+ mpPageLink = nullptr; // is set when inserting via ConnectLink()
+ mbIsPrecious = false;
+
+ // use shape list directly to preserve constness of rSrcPage
+ const std::list< SdrObject* >& rShapeList = rSrcPage.maPresentationShapeList.getList();
+ const size_t nObjCount = GetObjCount();
+ for( SdrObject* pObj : rShapeList )
+ {
+ size_t nOrdNum = pObj->GetOrdNum();
+ InsertPresObj(nOrdNum < nObjCount ? GetObj(nOrdNum) : nullptr, rSrcPage.GetPresObjKind(pObj));
+ }
+
+ // header footer
+ setHeaderFooterSettings( rSrcPage.getHeaderFooterSettings() );
+
+ // animations
+ rSrcPage.cloneAnimations(*this);
+
+ // annotations
+ for(const Reference< XAnnotation >& srcAnnotation : rSrcPage.maAnnotations)
+ {
+ Reference< XAnnotation > ref;
+ createAnnotation(ref);
+ ref->setPosition(srcAnnotation->getPosition());
+ ref->setSize(srcAnnotation->getSize());
+ ref->setAuthor(srcAnnotation->getAuthor());
+ ref->setInitials(srcAnnotation->getInitials());
+ ref->setDateTime(srcAnnotation->getDateTime());
+ Reference< ::css::text::XTextCopy > srcRange ( srcAnnotation->getTextRange(), uno::UNO_QUERY);
+ Reference< ::css::text::XTextCopy > range ( ref->getTextRange(), uno::UNO_QUERY);
+ if(srcRange.is() && range.is())
+ range->copyText( srcRange );
+ }
+
+ // fix user calls for duplicated slide
+ SdrObjListIter aSourceIter( &rSrcPage, SdrIterMode::DeepWithGroups );
+ SdrObjListIter aTargetIter( this, SdrIterMode::DeepWithGroups );
+
+ while( aSourceIter.IsMore() && aTargetIter.IsMore() )
+ {
+ SdrObject* pSource = aSourceIter.Next();
+ SdrObject* pTarget = aTargetIter.Next();
+
+ if( pSource->GetUserCall() )
+ pTarget->SetUserCall(this);
+ }
+}
+
+/*************************************************************************
+|*
+|* Clone
+|*
+\************************************************************************/
+
+rtl::Reference<SdrPage> SdPage::CloneSdrPage(SdrModel& rTargetModel) const
+{
+ SdDrawDocument& rSdDrawDocument(static_cast< SdDrawDocument& >(rTargetModel));
+ rtl::Reference<SdPage> pClonedSdPage(
+ new SdPage(
+ rSdDrawDocument,
+ IsMasterPage()));
+ pClonedSdPage->lateInit(*this);
+ return pClonedSdPage;
+}
+
+/*************************************************************************
+|*
+|* GetTextStyleSheetForObject
+|*
+\************************************************************************/
+
+SfxStyleSheet* SdPage::GetTextStyleSheetForObject( SdrObject* pObj ) const
+{
+ const PresObjKind eKind = GetPresObjKind(pObj);
+ if( eKind != PresObjKind::NONE )
+ {
+ return GetStyleSheetForPresObj(eKind);
+ }
+
+ return FmFormPage::GetTextStyleSheetForObject( pObj );
+}
+
+SfxItemSet* SdPage::getOrCreateItems()
+{
+ if( mpItems == nullptr )
+ mpItems = std::make_unique<SfxItemSetFixed<SDRATTR_XMLATTRIBUTES, SDRATTR_XMLATTRIBUTES>>( getSdrModelFromSdrPage().GetItemPool());
+
+ return mpItems.get();
+}
+
+bool SdPage::setAlienAttributes( const css::uno::Any& rAttributes )
+{
+ SfxItemSet* pSet = getOrCreateItems();
+
+ SvXMLAttrContainerItem aAlienAttributes( SDRATTR_XMLATTRIBUTES );
+ if( aAlienAttributes.PutValue( rAttributes, 0 ) )
+ {
+ pSet->Put( aAlienAttributes );
+ return true;
+ }
+
+ return false;
+}
+
+void SdPage::getAlienAttributes( css::uno::Any& rAttributes )
+{
+ const SvXMLAttrContainerItem* pItem;
+
+ if( (mpItems == nullptr) || !( pItem = mpItems->GetItemIfSet( SDRATTR_XMLATTRIBUTES, false ) ) )
+ {
+ SvXMLAttrContainerItem aAlienAttributes;
+ aAlienAttributes.QueryValue( rAttributes );
+ }
+ else
+ {
+ pItem->QueryValue( rAttributes );
+ }
+}
+
+void SdPage::RemoveEmptyPresentationObjects()
+{
+ SdrObjListIter aShapeIter( this, SdrIterMode::DeepWithGroups );
+
+ for (SdrObject* pShape = aShapeIter.Next(); pShape; pShape = aShapeIter.Next())
+ {
+ if (pShape->IsEmptyPresObj())
+ {
+ RemoveObject( pShape->GetOrdNum() );
+ SdrObject::Free( pShape );
+ }
+ }
+}
+
+void SdPage::setTransitionType( sal_Int16 nTransitionType )
+{
+ mnTransitionType = nTransitionType;
+ ActionChanged();
+}
+
+void SdPage::setTransitionSubtype ( sal_Int16 nTransitionSubtype )
+{
+ mnTransitionSubtype = nTransitionSubtype;
+ ActionChanged();
+}
+
+void SdPage::setTransitionDirection ( bool bTransitionbDirection )
+{
+ mbTransitionDirection = bTransitionbDirection;
+ ActionChanged();
+}
+
+void SdPage::setTransitionFadeColor ( sal_Int32 nTransitionFadeColor )
+{
+ mnTransitionFadeColor = nTransitionFadeColor;
+ ActionChanged();
+}
+
+void SdPage::setTransitionDuration ( double fTransitionDuration )
+{
+ mfTransitionDuration = fTransitionDuration;
+ ActionChanged();
+}
+
+bool SdPage::Equals(const SdPage& rOtherPage) const
+{
+ if (GetObjCount() != rOtherPage.GetObjCount() ||
+ mePageKind != rOtherPage.mePageKind ||
+ meAutoLayout != rOtherPage.meAutoLayout ||
+ mePresChange != rOtherPage.mePresChange ||
+ !rtl::math::approxEqual(mfTime, rOtherPage.mfTime) ||
+ mbSoundOn != rOtherPage.mbSoundOn ||
+ mbExcluded != rOtherPage.mbExcluded ||
+ maLayoutName != rOtherPage.maLayoutName ||
+ maSoundFile != rOtherPage.maSoundFile ||
+ mbLoopSound != rOtherPage.mbLoopSound ||
+ mbStopSound != rOtherPage.mbStopSound ||
+ maBookmarkName != rOtherPage.maBookmarkName ||
+ mbScaleObjects != rOtherPage.mbScaleObjects ||
+ IsBackgroundFullSize() != rOtherPage.IsBackgroundFullSize() || // ???
+ meCharSet != rOtherPage.meCharSet ||
+ mnPaperBin != rOtherPage.mnPaperBin ||
+ mnTransitionType != rOtherPage.mnTransitionType ||
+ mnTransitionSubtype != rOtherPage.mnTransitionSubtype ||
+ mbTransitionDirection != rOtherPage.mbTransitionDirection ||
+ mnTransitionFadeColor != rOtherPage.mnTransitionFadeColor ||
+ !rtl::math::approxEqual(mfTransitionDuration, rOtherPage.mfTransitionDuration))
+ return false;
+
+ for(size_t i = 0; i < GetObjCount(); ++i)
+ if (!GetObj(i)->Equals(*(rOtherPage.GetObj(i))))
+ return false;
+
+ return true;
+ }
+
+void SdPage::createAnnotation( css::uno::Reference< css::office::XAnnotation >& xAnnotation )
+{
+ sd::createAnnotation( xAnnotation, this );
+}
+
+void SdPage::addAnnotation( const Reference< XAnnotation >& xAnnotation, int nIndex )
+{
+ if( (nIndex == -1) || (nIndex > static_cast<int>(maAnnotations.size())) )
+ {
+ maAnnotations.push_back( xAnnotation );
+ }
+ else
+ {
+ maAnnotations.insert( maAnnotations.begin() + nIndex, xAnnotation );
+ }
+
+ if( getSdrModelFromSdrPage().IsUndoEnabled() )
+ {
+ std::unique_ptr<SdrUndoAction> pAction = CreateUndoInsertOrRemoveAnnotation( xAnnotation, true );
+ if( pAction )
+ getSdrModelFromSdrPage().AddUndo( std::move(pAction) );
+ }
+
+ SetChanged();
+ getSdrModelFromSdrPage().SetChanged();
+ NotifyDocumentEvent(
+ static_cast< SdDrawDocument& >(getSdrModelFromSdrPage()),
+ "OnAnnotationInserted",
+ Reference<XInterface>(xAnnotation, UNO_QUERY));
+}
+
+void SdPage::removeAnnotation( const Reference< XAnnotation >& xAnnotation )
+{
+ if( getSdrModelFromSdrPage().IsUndoEnabled() )
+ {
+ std::unique_ptr<SdrUndoAction> pAction = CreateUndoInsertOrRemoveAnnotation( xAnnotation, false );
+ if( pAction )
+ getSdrModelFromSdrPage().AddUndo( std::move(pAction) );
+ }
+
+ AnnotationVector::iterator iter = std::find( maAnnotations.begin(), maAnnotations.end(), xAnnotation );
+ if( iter != maAnnotations.end() )
+ maAnnotations.erase( iter );
+
+ getSdrModelFromSdrPage().SetChanged();
+ NotifyDocumentEvent(
+ static_cast< SdDrawDocument& >( getSdrModelFromSdrPage() ),
+ "OnAnnotationRemoved",
+ Reference<XInterface>( xAnnotation, UNO_QUERY ) );
+}
+
+void SdPage::getGraphicsForPrefetch(std::vector<Graphic*>& graphics) const
+{
+ for( size_t i = 0; i < GetObjCount(); ++i)
+ {
+ SdrObject* obj = GetObj(i);
+ if( SdrGrafObj* grafObj = dynamic_cast<SdrGrafObj*>(obj))
+ if(!grafObj->GetGraphic().isAvailable())
+ graphics.push_back( const_cast<Graphic*>(&grafObj->GetGraphic()));
+ if( const Graphic* fillGraphic = obj->getFillGraphic())
+ if(!fillGraphic->isAvailable())
+ graphics.push_back( const_cast<Graphic*>(fillGraphic));
+ }
+}
+
+void SdPage::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdPage"));
+
+ const char* pPageKind = nullptr;
+ switch (mePageKind)
+ {
+ case PageKind::Standard:
+ pPageKind = "PageKind::Standard";
+ break;
+ case PageKind::Notes:
+ pPageKind = "PageKind::Notes";
+ break;
+ case PageKind::Handout:
+ pPageKind = "PageKind::Handout";
+ break;
+ }
+ if (pPageKind)
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("mePageKind"), BAD_CAST(pPageKind));
+
+
+ FmFormPage::dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/sdpage_animations.cxx b/sd/source/core/sdpage_animations.cxx
new file mode 100644
index 000000000..c52938fd8
--- /dev/null
+++ b/sd/source/core/sdpage_animations.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/animations/ParallelTimeContainer.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <comphelper/processfactory.hxx>
+#include <editeng/outliner.hxx>
+#include <CustomAnimationCloner.hxx>
+#include <CustomAnimationEffect.hxx>
+#include <sdpage.hxx>
+#include <EffectMigration.hxx>
+
+using namespace ::sd;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::presentation;
+
+using ::com::sun::star::drawing::XShape;
+
+/** returns a helper class to manipulate effects inside the main sequence */
+std::shared_ptr< sd::MainSequence > const & SdPage::getMainSequence()
+{
+ if (nullptr == mpMainSequence)
+ mpMainSequence = std::make_shared<sd::MainSequence>( getAnimationNode() );
+
+ return mpMainSequence;
+}
+
+/** returns the main animation node */
+Reference< XAnimationNode > const & SdPage::getAnimationNode()
+{
+ if( !mxAnimationNode.is() )
+ {
+ mxAnimationNode.set( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW );
+ Sequence< css::beans::NamedValue > aUserData
+ { { "node-type", css::uno::Any(css::presentation::EffectNodeType::TIMING_ROOT) } };
+ mxAnimationNode->setUserData( aUserData );
+ }
+
+ return mxAnimationNode;
+}
+
+void SdPage::setAnimationNode( Reference< XAnimationNode > const & xNode )
+{
+ mxAnimationNode = xNode;
+ if( mpMainSequence )
+ mpMainSequence->reset( xNode );
+}
+
+/** removes all custom animations for the given shape */
+void SdPage::removeAnimations( const SdrObject* pObj )
+{
+ if( mxAnimationNode.is() )
+ {
+ getMainSequence();
+
+ Reference< XShape > xShape( const_cast<SdrObject*>(pObj)->getUnoShape(), UNO_QUERY );
+
+ if( mpMainSequence->hasEffect( xShape ) )
+ mpMainSequence->disposeShape( xShape );
+ }
+}
+
+/** Notify that the object has been renamed and the animation effect has to update. */
+void SdPage::notifyObjectRenamed(const SdrObject* pObj)
+{
+ if (pObj && hasAnimationNode())
+ {
+ Reference<XShape> xShape(const_cast<SdrObject*>(pObj)->getUnoShape(), UNO_QUERY);
+
+ if (xShape.is() && getMainSequence()->hasEffect(xShape))
+ getMainSequence()->notify_change();
+ }
+}
+
+bool SdPage::hasAnimationNode() const
+{
+ return mxAnimationNode.is();
+}
+
+void SdPage::SetFadeEffect(css::presentation::FadeEffect eNewEffect)
+{
+ EffectMigration::SetFadeEffect( this, eNewEffect );
+}
+
+FadeEffect SdPage::GetFadeEffect() const
+{
+ return EffectMigration::GetFadeEffect( this );
+}
+
+/** callback from the sd::View when a new paragraph for one object on this page is created */
+void SdPage::onParagraphInserted( const ::Outliner* pOutliner, Paragraph const * pPara, SdrObject* pObj )
+{
+ if( mxAnimationNode.is() )
+ {
+ ParagraphTarget aTarget;
+ aTarget.Shape.set( pObj->getUnoShape(), UNO_QUERY );
+ /* FIXME: Paragraph should be sal_Int32, though more than 64k
+ * paragraphs at a shape are unlikely... */
+ aTarget.Paragraph = static_cast<sal_Int16>(pOutliner->GetAbsPos( pPara ));
+
+ getMainSequence()->insertTextRange( Any( aTarget ) );
+ }
+}
+
+/** callback from the sd::View when a paragraph from one object on this page is removed */
+void SdPage::onParagraphRemoving( const ::Outliner* pOutliner, Paragraph const * pPara, SdrObject* pObj )
+{
+ if( mxAnimationNode.is() )
+ {
+ ParagraphTarget aTarget;
+ aTarget.Shape.set( pObj->getUnoShape(), UNO_QUERY );
+ /* FIXME: Paragraph should be sal_Int32, though more than 64k
+ * paragraphs at a shape are unlikely... */
+ aTarget.Paragraph = static_cast<sal_Int16>(pOutliner->GetAbsPos( pPara ));
+
+ getMainSequence()->disposeTextRange( Any( aTarget ) );
+ }
+}
+
+/** callback from the sd::View when an object just left text edit mode */
+void SdPage::onEndTextEdit( SdrObject* pObj )
+{
+ if( pObj && mxAnimationNode.is() )
+ {
+ Reference< XShape > xObj( pObj->getUnoShape(), UNO_QUERY );
+ getMainSequence()->onTextChanged( xObj );
+ }
+}
+
+void SdPage::cloneAnimations( SdPage& rTargetPage ) const
+{
+ if( mxAnimationNode.is() )
+ {
+ Reference< XAnimationNode > xClonedNode(
+ ::sd::Clone( mxAnimationNode, this, &rTargetPage ) );
+
+ if( xClonedNode.is() )
+ rTargetPage.setAnimationNode( xClonedNode );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/shapelist.cxx b/sd/source/core/shapelist.cxx
new file mode 100644
index 000000000..613286c9b
--- /dev/null
+++ b/sd/source/core/shapelist.cxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdobj.hxx>
+#include <osl/diagnose.h>
+#include <shapelist.hxx>
+
+#include <algorithm>
+
+using namespace sd;
+
+ShapeList::ShapeList()
+{
+ maIter = maShapeList.end();
+}
+
+ShapeList::~ShapeList()
+{
+ clear();
+}
+
+/** adds the given shape to this list */
+void ShapeList::addShape( SdrObject& rObject )
+{
+ ListImpl::iterator aIter( std::find( maShapeList.begin(), maShapeList.end(), &rObject ) );
+ if( aIter == maShapeList.end() )
+ {
+ maShapeList.push_back(&rObject);
+ rObject.AddObjectUser( *this );
+ }
+ else
+ {
+ OSL_FAIL("sd::ShapeList::addShape(), given shape already part of list!");
+ }
+}
+
+/** removes the given shape from this list */
+void ShapeList::removeShape( SdrObject& rObject )
+{
+ ListImpl::iterator aIter( std::find( maShapeList.begin(), maShapeList.end(), &rObject ) );
+ if( aIter != maShapeList.end() )
+ {
+ bool bIterErased = aIter == maIter;
+
+ (*aIter)->RemoveObjectUser(*this);
+ aIter = maShapeList.erase( aIter );
+
+ if( bIterErased )
+ maIter = aIter;
+ }
+ else
+ {
+ OSL_FAIL("sd::ShapeList::removeShape(), given shape not part of list!");
+ }
+}
+
+/** removes all shapes from this list
+ NOTE: iterators will become invalid */
+void ShapeList::clear()
+{
+ ListImpl aShapeList;
+ aShapeList.swap( maShapeList );
+
+ for( auto& rpShape : aShapeList )
+ rpShape->RemoveObjectUser(*this);
+
+ maIter = maShapeList.end();
+}
+
+/** returns true if this list is empty */
+bool ShapeList::isEmpty() const
+{
+ return maShapeList.empty();
+}
+
+/** returns true if given shape is part of this list */
+bool ShapeList::hasShape( SdrObject& rObject ) const
+{
+ return std::find( maShapeList.begin(), maShapeList.end(), &rObject ) != maShapeList.end();
+}
+
+void ShapeList::ObjectInDestruction(const SdrObject& rObject)
+{
+ ListImpl::iterator aIter( std::find( maShapeList.begin(), maShapeList.end(), &rObject ) );
+ if( aIter != maShapeList.end() )
+ {
+ bool bIterErased = aIter == maIter;
+
+ aIter = maShapeList.erase( aIter );
+
+ if( bIterErased )
+ maIter = aIter;
+ }
+ else
+ {
+ OSL_FAIL("sd::ShapeList::ObjectInDestruction(), got a call from an unknown friend!");
+ }
+}
+
+SdrObject* ShapeList::getNextShape()
+{
+ if( maIter != maShapeList.end() )
+ {
+ return (*maIter++);
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+void ShapeList::seekShape( sal_uInt32 nIndex )
+{
+ maIter = maShapeList.begin();
+ nIndex = std::min(nIndex, static_cast<sal_uInt32>(maShapeList.size()));
+ std::advance(maIter, nIndex);
+}
+
+bool ShapeList::hasMore() const
+{
+ return maIter != maShapeList.end();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/stlfamily.cxx b/sd/source/core/stlfamily.cxx
new file mode 100644
index 000000000..a396bd170
--- /dev/null
+++ b/sd/source/core/stlfamily.cxx
@@ -0,0 +1,513 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IllegalAccessException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include <svl/style.hxx>
+
+#include <tools/debug.hxx>
+#include <unotools/weakref.hxx>
+
+#include <strings.hrc>
+#include <stlfamily.hxx>
+#include <stlsheet.hxx>
+#include <sdresid.hxx>
+#include <sdpage.hxx>
+#include <glob.hxx>
+
+#include <map>
+#include <memory>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::beans;
+
+typedef std::map< OUString, rtl::Reference< SdStyleSheet > > PresStyleMap;
+
+struct SdStyleFamilyImpl
+{
+ unotools::WeakReference<SdPage> mxMasterPage;
+ OUString maLayoutName;
+
+ PresStyleMap& getStyleSheets();
+ rtl::Reference< SfxStyleSheetPool > mxPool;
+
+private:
+ PresStyleMap maStyleSheets;
+};
+
+PresStyleMap& SdStyleFamilyImpl::getStyleSheets()
+{
+ auto pMasterPage = mxMasterPage.get();
+ if (!pMasterPage)
+ return maStyleSheets;
+
+ if (pMasterPage->GetLayoutName() != maLayoutName )
+ {
+ maLayoutName = pMasterPage->GetLayoutName();
+
+ OUString aLayoutName( maLayoutName );
+ const sal_Int32 nLen = aLayoutName.indexOf(SD_LT_SEPARATOR ) + 4;
+ aLayoutName = aLayoutName.copy(0, nLen );
+
+ if( (maStyleSheets.empty()) || !(*maStyleSheets.begin()).second->GetName().startsWith( aLayoutName) )
+ {
+ maStyleSheets.clear();
+
+ // The iterator will return only style sheets of family master page
+ std::shared_ptr<SfxStyleSheetIterator> aSSSIterator = std::make_shared<SfxStyleSheetIterator>(mxPool.get(), SfxStyleFamily::Page);
+ for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
+ pStyle = aSSSIterator->Next() )
+ {
+ // we assume that we have only SdStyleSheets
+ SdStyleSheet* pSdStyle = static_cast< SdStyleSheet* >( pStyle );
+ if (pSdStyle->GetName().startsWith(aLayoutName))
+ {
+ maStyleSheets[ pSdStyle->GetApiName() ].set( pSdStyle );
+ }
+ }
+ }
+ }
+
+ return maStyleSheets;
+}
+
+SdStyleFamily::SdStyleFamily( const rtl::Reference< SfxStyleSheetPool >& xPool, SfxStyleFamily nFamily )
+: mnFamily( nFamily )
+, mxPool( xPool )
+{
+}
+
+SdStyleFamily::SdStyleFamily( const rtl::Reference< SfxStyleSheetPool >& xPool, const SdPage* pMasterPage )
+: mnFamily( SfxStyleFamily::Page )
+, mxPool( xPool )
+, mpImpl( new SdStyleFamilyImpl )
+{
+ mpImpl->mxMasterPage = const_cast< SdPage* >( pMasterPage );
+ mpImpl->mxPool = xPool;
+}
+
+SdStyleFamily::~SdStyleFamily()
+{
+ DBG_ASSERT( !mxPool.is(), "SdStyleFamily::~SdStyleFamily(), dispose me first!" );
+}
+
+void SdStyleFamily::throwIfDisposed() const
+{
+ if( !mxPool.is() )
+ throw DisposedException();
+}
+
+SdStyleSheet* SdStyleFamily::GetValidNewSheet( const Any& rElement )
+{
+ Reference< XStyle > xStyle( rElement, UNO_QUERY );
+ SdStyleSheet* pStyle = static_cast< SdStyleSheet* >( xStyle.get() );
+
+ if( pStyle == nullptr || (pStyle->GetFamily() != mnFamily) || (pStyle->GetPool() != mxPool.get()) || (mxPool->Find( pStyle->GetName(), mnFamily) != nullptr) )
+ throw IllegalArgumentException();
+
+ return pStyle;
+}
+
+SdStyleSheet* SdStyleFamily::GetSheetByName( const OUString& rName )
+{
+ SdStyleSheet* pRet = nullptr;
+ if( !rName.isEmpty() )
+ {
+ if( mnFamily == SfxStyleFamily::Page )
+ {
+ PresStyleMap& rStyleMap = mpImpl->getStyleSheets();
+ PresStyleMap::iterator iter( rStyleMap.find(rName) );
+ if( iter != rStyleMap.end() )
+ pRet = (*iter).second.get();
+ }
+ else
+ {
+ std::shared_ptr<SfxStyleSheetIterator> aSSSIterator = std::make_shared<SfxStyleSheetIterator>(mxPool.get(), mnFamily);
+ for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
+ pStyle = aSSSIterator->Next() )
+ {
+ // we assume that we have only SdStyleSheets
+ SdStyleSheet* pSdStyle = static_cast< SdStyleSheet* >( pStyle );
+ if (pSdStyle->GetApiName() == rName)
+ {
+ pRet = pSdStyle;
+ break;
+ }
+ }
+ }
+ }
+ if( pRet )
+ return pRet;
+
+ throw NoSuchElementException();
+}
+
+// XServiceInfo
+OUString SAL_CALL SdStyleFamily::getImplementationName()
+{
+ return "SdStyleFamily";
+}
+
+sal_Bool SAL_CALL SdStyleFamily::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+Sequence< OUString > SAL_CALL SdStyleFamily::getSupportedServiceNames()
+{
+ return { "com.sun.star.style.StyleFamily" };
+}
+
+// XNamed
+OUString SAL_CALL SdStyleFamily::getName()
+{
+ if( mnFamily == SfxStyleFamily::Page )
+ {
+ rtl::Reference<SdPage> pPage = mpImpl->mxMasterPage.get();
+ if( pPage == nullptr )
+ throw DisposedException();
+
+ OUString aLayoutName( pPage->GetLayoutName() );
+ sal_Int32 nIndex = aLayoutName.indexOf(SD_LT_SEPARATOR);
+ if( nIndex != -1 )
+ aLayoutName = aLayoutName.copy(0, nIndex);
+
+ return aLayoutName;
+ }
+ else
+ {
+ return SdStyleSheet::GetFamilyString( mnFamily );
+ }
+}
+
+void SAL_CALL SdStyleFamily::setName( const OUString& )
+{
+}
+
+// XNameAccess
+
+Any SAL_CALL SdStyleFamily::getByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+ return Any( Reference< XStyle >( static_cast<SfxUnoStyleSheet*>(GetSheetByName( rName )) ) );
+}
+
+Sequence< OUString > SAL_CALL SdStyleFamily::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if( mnFamily == SfxStyleFamily::Page )
+ {
+ PresStyleMap& rStyleMap = mpImpl->getStyleSheets();
+ Sequence< OUString > aNames( rStyleMap.size() );
+
+ OUString* pNames = aNames.getArray();
+ for( const auto& rEntry : rStyleMap )
+ {
+ rtl::Reference< SdStyleSheet > xStyle( rEntry.second );
+ if( xStyle.is() )
+ {
+ *pNames++ = xStyle->GetApiName();
+ }
+ }
+
+ return aNames;
+ }
+ else
+ {
+ std::vector< OUString > aNames;
+ std::shared_ptr<SfxStyleSheetIterator> aSSSIterator = std::make_shared<SfxStyleSheetIterator>(mxPool.get(), mnFamily);
+ for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
+ pStyle = aSSSIterator->Next() )
+ {
+ // we assume that we have only SdStyleSheets
+ SdStyleSheet* pSdStyle = static_cast< SdStyleSheet* >( pStyle );
+ aNames.push_back(pSdStyle->GetApiName());
+ }
+ return Sequence< OUString >( &(*aNames.begin()), aNames.size() );
+ }
+}
+
+sal_Bool SAL_CALL SdStyleFamily::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ if( !aName.isEmpty() )
+ {
+ if( mnFamily == SfxStyleFamily::Page )
+ {
+ PresStyleMap& rStyleSheets = mpImpl->getStyleSheets();
+ PresStyleMap::iterator iter( rStyleSheets.find(aName) );
+ return iter != rStyleSheets.end();
+ }
+ else
+ {
+ std::shared_ptr<SfxStyleSheetIterator> aSSSIterator = std::make_shared<SfxStyleSheetIterator>(mxPool.get(), mnFamily);
+ for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
+ pStyle = aSSSIterator->Next() )
+ {
+ // we assume that we have only SdStyleSheets
+ SdStyleSheet* pSdStyle = static_cast< SdStyleSheet* >( pStyle );
+ if (pSdStyle->GetApiName() == aName)
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+// XElementAccess
+
+Type SAL_CALL SdStyleFamily::getElementType()
+{
+ return cppu::UnoType<XStyle>::get();
+}
+
+sal_Bool SAL_CALL SdStyleFamily::hasElements()
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ if( mnFamily == SfxStyleFamily::Page )
+ {
+ return true;
+ }
+ else
+ {
+ std::shared_ptr<SfxStyleSheetIterator> aSSSIterator = std::make_shared<SfxStyleSheetIterator>(mxPool.get(), mnFamily);
+ if (aSSSIterator->First())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL SdStyleFamily::getCount()
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ sal_Int32 nCount = 0;
+ if( mnFamily == SfxStyleFamily::Page )
+ {
+ return mpImpl->getStyleSheets().size();
+ }
+ else
+ {
+ std::shared_ptr<SfxStyleSheetIterator> aSSSIterator = std::make_shared<SfxStyleSheetIterator>(mxPool.get(), mnFamily);
+ for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
+ pStyle = aSSSIterator->Next() )
+ {
+ nCount++;
+ }
+ }
+
+ return nCount;
+}
+
+Any SAL_CALL SdStyleFamily::getByIndex( sal_Int32 Index )
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ if( Index >= 0 )
+ {
+ if( mnFamily == SfxStyleFamily::Page )
+ {
+ PresStyleMap& rStyleSheets = mpImpl->getStyleSheets();
+ if( Index < static_cast<sal_Int32>(rStyleSheets.size()) )
+ {
+ PresStyleMap::iterator iter( rStyleSheets.begin() );
+ std::advance(iter, Index);
+ return Any( Reference< XStyle >( (*iter).second ) );
+ }
+ }
+ else
+ {
+ std::shared_ptr<SfxStyleSheetIterator> aSSSIterator = std::make_shared<SfxStyleSheetIterator>(mxPool.get(), mnFamily);
+ for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
+ pStyle = aSSSIterator->Next() )
+ {
+ // we assume that we have only SdStyleSheets
+ SdStyleSheet* pSdStyle = static_cast< SdStyleSheet* >( pStyle );
+ if( Index-- == 0 )
+ {
+ return Any( Reference< XStyle >( pSdStyle ) );
+ }
+ }
+ }
+ }
+
+ throw IndexOutOfBoundsException();
+}
+
+// XNameContainer
+
+void SAL_CALL SdStyleFamily::insertByName( const OUString& rName, const Any& rElement )
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ if(rName.isEmpty())
+ throw IllegalArgumentException();
+
+ SdStyleSheet* pStyle = GetValidNewSheet( rElement );
+ if( !pStyle->SetName( rName ) )
+ throw ElementExistException();
+
+ pStyle->SetApiName( rName );
+ mxPool->Insert( pStyle );
+}
+
+void SAL_CALL SdStyleFamily::removeByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ SdStyleSheet* pStyle = GetSheetByName( rName );
+
+ if( !pStyle->IsUserDefined() )
+ throw WrappedTargetException();
+
+ mxPool->Remove( pStyle );
+}
+
+// XNameReplace
+
+void SAL_CALL SdStyleFamily::replaceByName( const OUString& rName, const Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ SdStyleSheet* pOldStyle = GetSheetByName( rName );
+ SdStyleSheet* pNewStyle = GetValidNewSheet( aElement );
+
+ mxPool->Remove( pOldStyle );
+ mxPool->Insert( pNewStyle );
+}
+
+// XSingleServiceFactory
+
+Reference< XInterface > SAL_CALL SdStyleFamily::createInstance()
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ if( mnFamily == SfxStyleFamily::Page )
+ {
+ throw IllegalAccessException();
+ }
+ return Reference<XInterface>(
+ static_cast<XStyle*>(SdStyleSheet::CreateEmptyUserStyle(*mxPool, mnFamily).get()));
+}
+
+Reference< XInterface > SAL_CALL SdStyleFamily::createInstanceWithArguments( const Sequence< Any >& )
+{
+ return createInstance();
+}
+
+// XComponent
+
+void SAL_CALL SdStyleFamily::dispose( )
+{
+ if( mxPool.is() )
+ mxPool.clear();
+
+ mpImpl.reset();
+}
+
+void SAL_CALL SdStyleFamily::addEventListener( const Reference< XEventListener >& )
+{
+}
+
+void SAL_CALL SdStyleFamily::removeEventListener( const Reference< XEventListener >& )
+{
+}
+
+// XPropertySet
+
+Reference<XPropertySetInfo> SdStyleFamily::getPropertySetInfo()
+{
+ OSL_FAIL( "###unexpected!" );
+ return Reference<XPropertySetInfo>();
+}
+
+void SdStyleFamily::setPropertyValue( const OUString& , const Any& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+Any SdStyleFamily::getPropertyValue( const OUString& PropertyName )
+{
+ if ( PropertyName != "DisplayName" )
+ {
+ throw UnknownPropertyException( "unknown property: " + PropertyName, static_cast<OWeakObject *>(this) );
+ }
+
+ SolarMutexGuard aGuard;
+ OUString sDisplayName;
+ switch( mnFamily )
+ {
+ case SfxStyleFamily::Page: sDisplayName = getName(); break;
+ case SfxStyleFamily::Frame: sDisplayName = SdResId(STR_CELL_STYLE_FAMILY); break;
+ default: sDisplayName = SdResId(STR_GRAPHICS_STYLE_FAMILY); break;
+ }
+ return Any( sDisplayName );
+}
+
+void SdStyleFamily::addPropertyChangeListener( const OUString& , const Reference<XPropertyChangeListener>& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+void SdStyleFamily::removePropertyChangeListener( const OUString& , const Reference<XPropertyChangeListener>& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+void SdStyleFamily::addVetoableChangeListener( const OUString& , const Reference<XVetoableChangeListener>& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+void SdStyleFamily::removeVetoableChangeListener( const OUString& , const Reference<XVetoableChangeListener>& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/stlpool.cxx b/sd/source/core/stlpool.cxx
new file mode 100644
index 000000000..12891698a
--- /dev/null
+++ b/sd/source/core/stlpool.cxx
@@ -0,0 +1,1395 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/sdtaitm.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/sdshcitm.hxx>
+#include <svx/sdsxyitm.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/numitem.hxx>
+#include <editeng/cmapitem.hxx>
+#include <svl/hint.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <svx/sdr/table/tabledesign.hxx>
+#include <editeng/autokernitem.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/UnitConversion.hxx>
+
+#include <editeng/lrspitem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/numdef.hxx>
+#include <svl/itempool.hxx>
+#include <svl/IndexedStyleSheets.hxx>
+
+#include <stlpool.hxx>
+#include <sdresid.hxx>
+#include <stlsheet.hxx>
+#include <strings.hrc>
+#include <glob.hxx>
+#include <drawdoc.hxx>
+#include <svl/itemset.hxx>
+#include <app.hrc>
+#include <strings.hxx>
+
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/TextFitToSizeType.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::container;
+
+namespace
+{
+
+OUString lcl_findRenamedStyleName(std::vector< std::pair< OUString, OUString > > &rRenamedList, OUString const & aOriginalName )
+{
+ auto aIter = std::find_if(rRenamedList.begin(), rRenamedList.end(),
+ [&aOriginalName](const std::pair<OUString, OUString>& rItem) { return rItem.first == aOriginalName; });
+ if (aIter != rRenamedList.end())
+ return (*aIter).second;
+ return OUString();
+}
+
+SfxStyleSheet *lcl_findStyle(StyleSheetCopyResultVector& rStyles, std::u16string_view aStyleName)
+{
+ if( aStyleName.empty() )
+ return nullptr;
+ for (const auto& a : rStyles)
+ {
+ if (a.m_xStyleSheet->GetName() == aStyleName)
+ return a.m_xStyleSheet.get();
+ }
+ return nullptr;
+}
+
+}
+
+SdStyleSheetPool::SdStyleSheetPool(SfxItemPool const& _rPool, SdDrawDocument* pDocument)
+: SdStyleSheetPoolBase( _rPool )
+, mpActualStyleSheet(nullptr)
+, mpDoc(pDocument)
+{
+ if( !mpDoc )
+ return;
+
+ rtl::Reference< SfxStyleSheetPool > xPool( this );
+
+ // create graphics family
+ mxGraphicFamily = new SdStyleFamily( xPool, SfxStyleFamily::Para );
+ mxCellFamily = new SdStyleFamily( xPool, SfxStyleFamily::Frame );
+
+ mxTableFamily = sdr::table::CreateTableDesignFamily();
+ Reference< XNamed > xNamed( mxTableFamily, UNO_QUERY );
+ if( xNamed.is() )
+ msTableFamilyName = xNamed->getName();
+
+ // create presentation families, one for each master page
+ const sal_uInt16 nCount = mpDoc->GetMasterSdPageCount(PageKind::Standard);
+ for( sal_uInt16 nPage = 0; nPage < nCount; ++nPage )
+ AddStyleFamily( mpDoc->GetMasterSdPage(nPage,PageKind::Standard) );
+}
+
+SdStyleSheetPool::~SdStyleSheetPool()
+{
+ DBG_ASSERT( mpDoc == nullptr, "sd::SdStyleSheetPool::~SdStyleSheetPool(), dispose me first!" );
+}
+
+rtl::Reference<SfxStyleSheetBase> SdStyleSheetPool::Create(const OUString& rName, SfxStyleFamily eFamily, SfxStyleSearchBits _nMask )
+{
+ return new SdStyleSheet(rName, *this, eFamily, _nMask);
+}
+
+SfxStyleSheetBase* SdStyleSheetPool::GetTitleSheet(std::u16string_view rLayoutName)
+{
+ OUString aName = OUString::Concat(rLayoutName) + SD_LT_SEPARATOR + STR_LAYOUT_TITLE;
+ SfxStyleSheetBase* pResult = Find(aName, SfxStyleFamily::Page);
+ return pResult;
+}
+
+/*************************************************************************
+|*
+|* Create a list of outline text templates for a presentation layout.
+|* The caller has to delete the list.
+|*
+\************************************************************************/
+
+void SdStyleSheetPool::CreateOutlineSheetList (std::u16string_view rLayoutName, std::vector<SfxStyleSheetBase*> &rOutlineStyles)
+{
+ OUString aName = OUString::Concat(rLayoutName) + SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE;
+
+ for (sal_Int32 nSheet = 1; nSheet < 10; nSheet++)
+ {
+ OUString aFullName(aName + " " + OUString::number( nSheet ) );
+ SfxStyleSheetBase* pSheet = Find(aFullName, SfxStyleFamily::Page);
+
+ if (pSheet)
+ rOutlineStyles.push_back(pSheet);
+ }
+}
+
+/*************************************************************************
+|*
+|* Create style sheets with default values for the named presentation layout
+|*
+\************************************************************************/
+
+void SdStyleSheetPool::CreateLayoutStyleSheets(std::u16string_view rLayoutName, bool bCheck /*= sal_False*/ )
+{
+ const SfxStyleSearchBits nUsedMask = SfxStyleSearchBits::All & ~SfxStyleSearchBits::UserDefined;
+
+ bool bCreated = false;
+
+ SfxStyleSheetBase* pSheet = nullptr;
+
+ OUString aPrefix(OUString::Concat(rLayoutName) + SD_LT_SEPARATOR);
+
+ vcl::Font aLatinFont, aCJKFont, aCTLFont;
+
+ mpDoc->getDefaultFonts( aLatinFont, aCJKFont, aCTLFont );
+
+ // Font for title and outline
+ SvxFontItem aSvxFontItem( aLatinFont.GetFamilyType(), aLatinFont.GetFamilyName(), aLatinFont.GetStyleName(), aLatinFont.GetPitch(),
+ aLatinFont.GetCharSet(), EE_CHAR_FONTINFO );
+
+ SvxFontItem aSvxFontItemCJK( aCJKFont.GetFamilyType(), aCJKFont.GetFamilyName(), aCJKFont.GetStyleName(), aCJKFont.GetPitch(),
+ aCJKFont.GetCharSet(), EE_CHAR_FONTINFO_CJK );
+
+ SvxFontItem aSvxFontItemCTL( aCTLFont.GetFamilyType(), aCTLFont.GetFamilyName(), aCTLFont.GetStyleName(), aCTLFont.GetPitch(),
+ aCTLFont.GetCharSet(), EE_CHAR_FONTINFO_CTL );
+
+ vcl::Font aBulletFont( GetBulletFont() );
+
+ /**************************************************************************
+ * outline levels
+ **************************************************************************/
+ OUString aName(STR_LAYOUT_OUTLINE);
+ const OUString aHelpFile;
+
+ SvxLRSpaceItem aSvxLRSpaceItem( EE_PARA_LRSPACE );
+ SvxULSpaceItem aSvxULSpaceItem( EE_PARA_ULSPACE );
+
+ for( sal_Int32 nLevel = 1; nLevel < 10; nLevel++)
+ {
+ OUString aLevelName( aPrefix + aName + " " + OUString::number( nLevel ) ) ;
+
+ if (!Find(aLevelName, SfxStyleFamily::Page))
+ {
+ bCreated = true;
+ pSheet = &Make(aLevelName, SfxStyleFamily::Page,nUsedMask);
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_OUTLINE + nLevel );
+
+ pSheet->SetParent( OUString() );
+
+ // attributing for level 1, the others levels inherit
+ if (nLevel == 1)
+ {
+ SfxItemSet& rSet = pSheet->GetItemSet();
+
+ rSet.Put(aSvxFontItem);
+ rSet.Put(aSvxFontItemCJK);
+ rSet.Put(aSvxFontItemCTL);
+ rSet.Put( SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC ) );
+ rSet.Put( SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CJK ) );
+ rSet.Put( SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CTL ) );
+ rSet.Put( SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
+ rSet.Put( SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CJK ) );
+ rSet.Put( SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CTL ) );
+ rSet.Put( SvxUnderlineItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE ) );
+ rSet.Put( SvxOverlineItem(LINESTYLE_NONE, EE_CHAR_OVERLINE ) );
+ rSet.Put( SvxCrossedOutItem(STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ) );
+ rSet.Put( SvxCaseMapItem(SvxCaseMap::NotMapped, EE_CHAR_CASEMAP ) );
+ rSet.Put( SvxShadowedItem(false, EE_CHAR_SHADOW ) );
+ rSet.Put( SvxContourItem(false, EE_CHAR_OUTLINE ) );
+ rSet.Put( SvxEmphasisMarkItem(FontEmphasisMark::NONE, EE_CHAR_EMPHASISMARK ) );
+ rSet.Put( SvxCharReliefItem(FontRelief::NONE, EE_CHAR_RELIEF) );
+ rSet.Put( SvxColorItem( COL_AUTO, EE_CHAR_COLOR) );
+ rSet.Put( SvxColorItem( COL_AUTO, EE_CHAR_BKGCOLOR ) );
+ rSet.Put( XLineStyleItem(css::drawing::LineStyle_NONE) );
+ rSet.Put( XFillStyleItem(drawing::FillStyle_NONE) );
+ rSet.Put( SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_AUTOFIT) );
+ rSet.Put( makeSdrTextAutoGrowHeightItem(false) );
+ // #i16874# enable kerning by default but only for new documents
+ rSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+
+ vcl::Font f( GetBulletFont() );
+ PutNumBulletItem( pSheet, f );
+ }
+
+ sal_uLong nFontSize = 20;
+ sal_uInt16 nUpper = 100;
+
+ switch (nLevel)
+ {
+ case 1:
+ {
+ nFontSize = 32;
+ nUpper = 500;
+ }
+ break;
+
+ case 2:
+ {
+ nFontSize = 28;
+ nUpper = 400;
+ }
+ break;
+
+ case 3:
+ {
+ nFontSize = 24;
+ nUpper = 300;
+ }
+ break;
+
+ case 4:
+ {
+ nUpper = 200;
+ }
+ break;
+ }
+
+ // FontSize
+ nFontSize = static_cast<sal_uInt16>(convertPointToMm100(nFontSize));
+ SfxItemSet& rOutlineSet = pSheet->GetItemSet();
+ rOutlineSet.Put( SvxFontHeightItem( nFontSize, 100, EE_CHAR_FONTHEIGHT ) );
+ rOutlineSet.Put( SvxFontHeightItem( nFontSize, 100, EE_CHAR_FONTHEIGHT_CJK ) );
+ rOutlineSet.Put( SvxFontHeightItem( SdDrawDocument::convertFontHeightToCTL( nFontSize ), 100, EE_CHAR_FONTHEIGHT_CTL ) );
+
+ // Line distance (upwards). Stuff around here cleaned up in i35937
+ aSvxULSpaceItem.SetUpper(nUpper);
+ pSheet->GetItemSet().Put(aSvxULSpaceItem);
+ }
+ }
+
+ // if we created outline styles, we need to chain them
+ if( bCreated )
+ {
+ SfxStyleSheetBase* pParent = nullptr;
+ for (sal_Int32 nLevel = 1; nLevel < 10; nLevel++)
+ {
+ OUString aLevelName( aPrefix + aName + " " + OUString::number( nLevel ) );
+
+ pSheet = Find(aLevelName, SfxStyleFamily::Page);
+
+ DBG_ASSERT( pSheet, "missing layout style!");
+
+ if( pSheet )
+ {
+ if (pParent)
+ pSheet->SetParent(pParent->GetName());
+ pParent = pSheet;
+ }
+ }
+ }
+
+ /**************************************************************************
+ * Title
+ **************************************************************************/
+ aName = aPrefix + STR_LAYOUT_TITLE;
+
+ if (!Find(aName, SfxStyleFamily::Page))
+ {
+ bCreated = true;
+
+ pSheet = &Make(aName, SfxStyleFamily::Page,nUsedMask);
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_TITLE );
+ pSheet->SetParent( OUString() );
+ SfxItemSet& rTitleSet = pSheet->GetItemSet();
+ rTitleSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ rTitleSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ rTitleSet.Put(aSvxFontItem);
+ rTitleSet.Put(aSvxFontItemCJK);
+ rTitleSet.Put(aSvxFontItemCTL);
+ rTitleSet.Put(SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC ) );
+ rTitleSet.Put(SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CJK ) );
+ rTitleSet.Put(SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CTL ) );
+ rTitleSet.Put(SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
+ rTitleSet.Put(SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CJK ) );
+ rTitleSet.Put(SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CTL ) );
+ rTitleSet.Put(SvxFontHeightItem( 1552, 100, EE_CHAR_FONTHEIGHT ) ); // 44 pt
+ rTitleSet.Put(SvxFontHeightItem( 1552, 100, EE_CHAR_FONTHEIGHT_CJK ) ); // 44 pt
+ rTitleSet.Put(SvxFontHeightItem( SdDrawDocument::convertFontHeightToCTL( 1552 ), 100, EE_CHAR_FONTHEIGHT_CTL ) ); // 44 pt
+ rTitleSet.Put(SvxUnderlineItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE ));
+ rTitleSet.Put(SvxOverlineItem(LINESTYLE_NONE, EE_CHAR_OVERLINE ));
+ rTitleSet.Put(SvxCrossedOutItem(STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ));
+ rTitleSet.Put(SvxCaseMapItem(SvxCaseMap::NotMapped, EE_CHAR_CASEMAP ));
+ rTitleSet.Put(SvxShadowedItem(false, EE_CHAR_SHADOW ));
+ rTitleSet.Put(SvxContourItem(false, EE_CHAR_OUTLINE ));
+ rTitleSet.Put( SvxEmphasisMarkItem(FontEmphasisMark::NONE, EE_CHAR_EMPHASISMARK ) );
+ rTitleSet.Put( SvxCharReliefItem(FontRelief::NONE, EE_CHAR_RELIEF ) );
+ rTitleSet.Put(SvxColorItem( COL_AUTO, EE_CHAR_COLOR ));
+ rTitleSet.Put(SvxColorItem( COL_AUTO, EE_CHAR_BKGCOLOR ));
+ rTitleSet.Put(SvxAdjustItem(SvxAdjust::Center, EE_PARA_JUST ));
+ rTitleSet.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) );
+ // #i16874# enable kerning by default but only for new documents
+ rTitleSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+
+ aBulletFont.SetFontSize(Size(0,1552)); // 44 pt
+ PutNumBulletItem( pSheet, aBulletFont );
+ }
+
+ /**************************************************************************
+ * Subtitle
+ **************************************************************************/
+ aName = aPrefix + STR_LAYOUT_SUBTITLE;
+
+ if (!Find(aName, SfxStyleFamily::Page))
+ {
+ bCreated = true;
+
+ pSheet = &Make(aName, SfxStyleFamily::Page,nUsedMask);
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_SUBTITLE );
+ pSheet->SetParent( OUString() );
+ SfxItemSet& rSubtitleSet = pSheet->GetItemSet();
+ rSubtitleSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ rSubtitleSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ rSubtitleSet.Put(aSvxFontItem);
+ rSubtitleSet.Put(aSvxFontItemCJK);
+ rSubtitleSet.Put(aSvxFontItemCTL);
+ rSubtitleSet.Put(SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC ) );
+ rSubtitleSet.Put(SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CJK ) );
+ rSubtitleSet.Put(SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CTL ) );
+ rSubtitleSet.Put(SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
+ rSubtitleSet.Put(SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CJK ) );
+ rSubtitleSet.Put(SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CTL ) );
+ rSubtitleSet.Put( SvxFontHeightItem( 1129, 100, EE_CHAR_FONTHEIGHT ) ); // 32 pt
+ rSubtitleSet.Put( SvxFontHeightItem( 1129, 100, EE_CHAR_FONTHEIGHT_CJK ) ); // 32 pt
+ rSubtitleSet.Put( SvxFontHeightItem( SdDrawDocument::convertFontHeightToCTL( 1129 ), 100, EE_CHAR_FONTHEIGHT_CTL ) ); // 32 pt
+ rSubtitleSet.Put(SvxUnderlineItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE ));
+ rSubtitleSet.Put(SvxOverlineItem(LINESTYLE_NONE, EE_CHAR_OVERLINE ));
+ rSubtitleSet.Put(SvxCrossedOutItem(STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ));
+ rSubtitleSet.Put(SvxCaseMapItem(SvxCaseMap::NotMapped, EE_CHAR_CASEMAP ));
+ rSubtitleSet.Put(SvxShadowedItem(false, EE_CHAR_SHADOW ));
+ rSubtitleSet.Put(SvxContourItem(false, EE_CHAR_OUTLINE ));
+ rSubtitleSet.Put( SvxEmphasisMarkItem(FontEmphasisMark::NONE, EE_CHAR_EMPHASISMARK ) );
+ rSubtitleSet.Put( SvxCharReliefItem(FontRelief::NONE, EE_CHAR_RELIEF ) );
+ rSubtitleSet.Put(SvxColorItem( COL_AUTO, EE_CHAR_COLOR ));
+ rSubtitleSet.Put(SvxColorItem( COL_AUTO, EE_CHAR_BKGCOLOR ));
+ rSubtitleSet.Put(SvxAdjustItem(SvxAdjust::Center, EE_PARA_JUST ));
+ rSubtitleSet.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) );
+ // #i16874# enable kerning by default but only for new documents
+ rSubtitleSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+ aSvxLRSpaceItem.SetTextLeft(0);
+ rSubtitleSet.Put(aSvxLRSpaceItem);
+
+ vcl::Font aTmpFont( GetBulletFont() );
+ aTmpFont.SetFontSize(Size(0, 1129)); // 32 pt
+ PutNumBulletItem( pSheet, aTmpFont );
+ }
+
+ /**************************************************************************
+ * Notes
+ **************************************************************************/
+ aName = aPrefix + STR_LAYOUT_NOTES;
+
+ if (!Find(aName, SfxStyleFamily::Page))
+ {
+ bCreated = true;
+
+ pSheet = &Make(aName, SfxStyleFamily::Page,nUsedMask);
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_NOTES );
+ pSheet->SetParent( OUString() );
+ SfxItemSet& rNotesSet = pSheet->GetItemSet();
+ rNotesSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ rNotesSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ rNotesSet.Put(aSvxFontItem);
+ rNotesSet.Put(aSvxFontItemCJK);
+ rNotesSet.Put(aSvxFontItemCTL);
+ rNotesSet.Put( SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC ) );
+ rNotesSet.Put( SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CJK ) );
+ rNotesSet.Put( SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CTL ) );
+ rNotesSet.Put( SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
+ rNotesSet.Put( SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CJK ) );
+ rNotesSet.Put( SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CTL ) );
+ rNotesSet.Put( SvxFontHeightItem( 705, 100, EE_CHAR_FONTHEIGHT ) ); // 20 pt
+ rNotesSet.Put( SvxFontHeightItem( 705, 100, EE_CHAR_FONTHEIGHT_CJK ) ); // 20 pt
+ rNotesSet.Put( SvxFontHeightItem( SdDrawDocument::convertFontHeightToCTL( 705 ), 100, EE_CHAR_FONTHEIGHT_CTL ) ); // 20 pt
+ rNotesSet.Put( SvxUnderlineItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE ) );
+ rNotesSet.Put( SvxOverlineItem(LINESTYLE_NONE, EE_CHAR_OVERLINE ) );
+ rNotesSet.Put( SvxCrossedOutItem(STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ) );
+ rNotesSet.Put( SvxCaseMapItem(SvxCaseMap::NotMapped, EE_CHAR_CASEMAP ) );
+ rNotesSet.Put( SvxShadowedItem(false, EE_CHAR_SHADOW ) );
+ rNotesSet.Put( SvxContourItem(false, EE_CHAR_OUTLINE ) );
+ rNotesSet.Put( SvxEmphasisMarkItem(FontEmphasisMark::NONE, EE_CHAR_EMPHASISMARK ) );
+ rNotesSet.Put( SvxCharReliefItem(FontRelief::NONE, EE_CHAR_RELIEF) );
+ rNotesSet.Put( SvxColorItem( COL_AUTO, EE_CHAR_COLOR ) );
+ rNotesSet.Put( SvxColorItem( COL_AUTO, EE_CHAR_BKGCOLOR ) );
+ rNotesSet.Put( SvxLRSpaceItem( 0, 0, 600, -600, EE_PARA_LRSPACE ) );
+ // #i16874# enable kerning by default but only for new documents
+ rNotesSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+
+/* #i35937# */
+
+ }
+
+ /**************************************************************************
+ * Background objects
+ **************************************************************************/
+ aName = aPrefix + STR_LAYOUT_BACKGROUNDOBJECTS;
+
+ if (!Find(aName, SfxStyleFamily::Page))
+ {
+ bCreated = true;
+
+ pSheet = &Make(aName, SfxStyleFamily::Page,nUsedMask);
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_BACKGROUNDOBJECTS );
+ pSheet->SetParent( OUString() );
+ SfxItemSet& rBackgroundObjectsSet = pSheet->GetItemSet();
+ rBackgroundObjectsSet.Put(makeSdrShadowItem(false));
+ rBackgroundObjectsSet.Put(makeSdrShadowColorItem(COL_GRAY));
+ rBackgroundObjectsSet.Put(makeSdrShadowXDistItem(200)); // 3 mm shadow distance
+ rBackgroundObjectsSet.Put(makeSdrShadowYDistItem(200));
+ // #i16874# enable kerning by default but only for new documents
+ rBackgroundObjectsSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+ rBackgroundObjectsSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK));
+ }
+
+ /**************************************************************************
+ * Background
+ **************************************************************************/
+ aName = aPrefix + STR_LAYOUT_BACKGROUND;
+
+ if (!Find(aName, SfxStyleFamily::Page))
+ {
+ bCreated = true;
+
+ pSheet = &Make(aName, SfxStyleFamily::Page,nUsedMask);
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_BACKGROUND );
+ pSheet->SetParent( OUString() );
+ SfxItemSet& rBackgroundSet = pSheet->GetItemSet();
+ rBackgroundSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ rBackgroundSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ // #i16874# enable kerning by default but only for new documents
+ rBackgroundSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+ }
+
+ DBG_ASSERT( !bCheck || !bCreated, "missing layout style sheets detected!" );
+}
+
+/*************************************************************************
+|*
+|* Copy graphic style sheets from source pool into this pool
+|*
+|* (rSourcePool can not be const since SfxStyleSheetPoolBase::Find isn't const)
+|*
+\************************************************************************/
+
+void SdStyleSheetPool::CopyGraphicSheets(SdStyleSheetPool& rSourcePool)
+{
+ CopySheets( rSourcePool, SfxStyleFamily::Para );
+}
+
+void SdStyleSheetPool::CopyCellSheets(SdStyleSheetPool& rSourcePool)
+{
+ CopySheets( rSourcePool, SfxStyleFamily::Frame );
+}
+
+void SdStyleSheetPool::CopyTableStyles(SdStyleSheetPool const & rSourcePool)
+{
+ Reference< XIndexAccess > xSource( rSourcePool.mxTableFamily, UNO_QUERY );
+ Reference< XNameContainer > xTarget( mxTableFamily, UNO_QUERY );
+ Reference< XSingleServiceFactory > xFactory( mxTableFamily, UNO_QUERY );
+
+ if( !(xSource.is() && xFactory.is() && mxTableFamily.is()) )
+ return;
+
+ for( sal_Int32 nIndex = 0; nIndex < xSource->getCount(); nIndex++ ) try
+ {
+ Reference< XStyle > xSourceTableStyle( xSource->getByIndex( nIndex ), UNO_QUERY );
+ if( xSourceTableStyle.is() )
+ {
+ Reference< XStyle > xNewTableStyle( xFactory->createInstance(), UNO_QUERY );
+ if( xNewTableStyle.is() )
+ {
+ Reference< XNameAccess> xSourceNames( xSourceTableStyle, UNO_QUERY_THROW );
+
+ const Sequence< OUString > aStyleNames( xSourceNames->getElementNames() );
+
+ Reference< XNameReplace > xTargetNames( xNewTableStyle, UNO_QUERY );
+
+ for( const OUString& aName : aStyleNames )
+ {
+ Reference< XStyle > xSourceStyle( xSourceNames->getByName( aName ), UNO_QUERY );
+ Reference< XStyle > xTargetStyle;
+ if( xSourceStyle.is() ) try
+ {
+ mxCellFamily->getByName( xSourceStyle->getName() ) >>= xTargetStyle;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SdStyleSheetPool::CopyTableStyles()" );
+ }
+
+ if( xTargetStyle.is() )
+ xTargetNames->replaceByName( aName, Any( xTargetStyle ) );
+ }
+ }
+
+ OUString sName( xSourceTableStyle->getName() );
+ if( xTarget->hasByName( sName ) )
+ xTarget->replaceByName( sName, Any( xNewTableStyle ) );
+ else
+ xTarget->insertByName( sName, Any( xNewTableStyle ) );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SdStyleSheetPool::CopyTableStyles()");
+ }
+}
+
+void SdStyleSheetPool::CopyCellSheets(SdStyleSheetPool& rSourcePool, StyleSheetCopyResultVector& rCreatedSheets)
+{
+ CopySheets( rSourcePool, SfxStyleFamily::Frame, rCreatedSheets );
+}
+
+void SdStyleSheetPool::RenameAndCopyGraphicSheets(SdStyleSheetPool& rSourcePool, StyleSheetCopyResultVector& rCreatedSheets, std::u16string_view rRenameSuffix)
+{
+ CopySheets( rSourcePool, SfxStyleFamily::Para, rCreatedSheets, rRenameSuffix );
+}
+
+void SdStyleSheetPool::CopySheets(SdStyleSheetPool& rSourcePool, SfxStyleFamily eFamily )
+{
+ StyleSheetCopyResultVector aTmpSheets;
+ CopySheets(rSourcePool, eFamily, aTmpSheets);
+}
+
+void SdStyleSheetPool::CopySheets(SdStyleSheetPool& rSourcePool, SfxStyleFamily eFamily, StyleSheetCopyResultVector& rCreatedSheets)
+{
+ CopySheets(rSourcePool, eFamily, rCreatedSheets, u"");
+}
+
+namespace
+{
+
+struct HasFamilyPredicate : svl::StyleSheetPredicate
+{
+ explicit HasFamilyPredicate(SfxStyleFamily eFamily)
+ : meFamily(eFamily) {}
+
+ bool Check(const SfxStyleSheetBase& sheet) override
+ {
+ return sheet.GetFamily() == meFamily;
+ }
+ SfxStyleFamily meFamily;
+};
+
+}
+
+void SdStyleSheetPool::CopySheets(SdStyleSheetPool& rSourcePool, SfxStyleFamily eFamily, StyleSheetCopyResultVector& rCreatedSheets, std::u16string_view rRenameSuffix)
+{
+ std::vector< std::pair< rtl::Reference< SfxStyleSheetBase >, OUString > > aNewStyles;
+ std::vector< std::pair< OUString, OUString > > aRenamedList;
+
+ // find all style sheets of the source pool which have the same family
+ HasFamilyPredicate aHasFamilyPredicate(eFamily);
+ std::vector<sal_Int32> aSheetsWithFamily = rSourcePool.GetIndexedStyleSheets().FindPositionsByPredicate(aHasFamilyPredicate);
+
+ for (const auto& rPos : aSheetsWithFamily)
+ {
+ SfxStyleSheetBase* pSheet = rSourcePool.GetStyleSheetByPositionInIndex( rPos );
+ if( !pSheet )
+ continue;
+ OUString aName( pSheet->GetName() );
+
+ // now check whether we already have a sheet with the same name
+ std::vector<sal_Int32> aSheetsWithName = GetIndexedStyleSheets().FindPositionsByName(aName);
+ bool bAddToList = false;
+ SfxStyleSheetBase * pExistingSheet = nullptr;
+ if (!aSheetsWithName.empty())
+ {
+ // if we have a rename suffix, try to find a new name
+ pExistingSheet =
+ GetStyleSheetByPositionInIndex(aSheetsWithName.front());
+ if (!rRenameSuffix.empty() &&
+ !pExistingSheet->GetItemSet().Equals(pSheet->GetItemSet(), false))
+ {
+ // we have found a sheet with the same name, but different contents. Try to find a new name.
+ // If we already have a sheet with the new name, and it is equal to the one in the source pool,
+ // do nothing.
+ OUString aTmpName = aName + rRenameSuffix;
+ sal_Int32 nSuffix = 1;
+ do
+ {
+ aTmpName = aName + rRenameSuffix + OUString::number(nSuffix);
+ pExistingSheet = Find(aTmpName, eFamily);
+ nSuffix++;
+ } while (pExistingSheet &&
+ !pExistingSheet->GetItemSet().Equals(pSheet->GetItemSet(), false));
+ aName = aTmpName;
+ bAddToList = true;
+ }
+ }
+ // we do not already have a sheet with the same name and contents. Create a new one.
+ if (!pExistingSheet)
+ {
+ assert(!Find(aName, eFamily));
+ rtl::Reference< SfxStyleSheetBase > xNewSheet( &Make( aName, eFamily ) );
+
+ xNewSheet->SetMask( pSheet->GetMask() );
+
+ // Also set parent relation for copied style sheets
+ OUString aParent( pSheet->GetParent() );
+ if( !aParent.isEmpty() )
+ aNewStyles.emplace_back( xNewSheet, aParent );
+
+ if( !bAddToList )
+ {
+ OUString aHelpFile;
+ xNewSheet->SetHelpId( aHelpFile, pSheet->GetHelpId( aHelpFile ) );
+ }
+ xNewSheet->GetItemSet().Put( pSheet->GetItemSet() );
+
+ rCreatedSheets.emplace_back(static_cast<SdStyleSheet*>(xNewSheet.get()), true);
+ aRenamedList.emplace_back( pSheet->GetName(), aName );
+ }
+ else if (bAddToList)
+ {
+ // Add to list - used for renaming
+ rCreatedSheets.emplace_back(static_cast<SdStyleSheet*>(pExistingSheet), false);
+ aRenamedList.emplace_back( pSheet->GetName(), aName );
+ }
+ }
+
+ // set parents on newly added stylesheets
+ for( auto& rStyle : aNewStyles )
+ {
+ if( !rRenameSuffix.empty() )
+ {
+ SfxStyleSheet *pParent = lcl_findStyle(rCreatedSheets, lcl_findRenamedStyleName(aRenamedList, rStyle.second));
+ if( pParent )
+ {
+ rStyle.first->SetParent( pParent->GetName() );
+ continue;
+ }
+ }
+ DBG_ASSERT( rSourcePool.Find( rStyle.second, eFamily ), "StyleSheet has invalid parent: Family mismatch" );
+ rStyle.first->SetParent( rStyle.second );
+ }
+ // we have changed names of style sheets. Trigger reindexing.
+ Reindex();
+}
+
+/*************************************************************************
+|*
+|* Copy style sheets of the named presentation layout from the source pool into
+|* this pool. Copies only the style sheets which aren't yet in this pool.
+|* If not NULL, pCreatedSheets is filled with pointers to the created style
+|* sheets.
+|*
+|* (rSourcePool can not be const since SfxStyleSheetPoolBase::Find isn't const)
+|*
+\************************************************************************/
+
+void SdStyleSheetPool::CopyLayoutSheets(std::u16string_view rLayoutName, SdStyleSheetPool& rSourcePool, StyleSheetCopyResultVector& rCreatedSheets)
+{
+ SfxStyleSheetBase* pSheet = nullptr;
+
+ std::vector<OUString> aNameList;
+ CreateLayoutSheetNames(rLayoutName,aNameList);
+
+ for (const auto& rName : aNameList)
+ {
+ pSheet = Find(rName, SfxStyleFamily::Page);
+ if (!pSheet)
+ {
+ SfxStyleSheetBase* pSourceSheet = rSourcePool.Find(rName, SfxStyleFamily::Page);
+ DBG_ASSERT(pSourceSheet, "CopyLayoutSheets: Style sheet missing");
+ if (pSourceSheet)
+ {
+ // In the case one comes with Methusalem-Docs.
+ SfxStyleSheetBase& rNewSheet = Make(rName, SfxStyleFamily::Page);
+ OUString file;
+ rNewSheet.SetHelpId( file, pSourceSheet->GetHelpId( file ) );
+ rNewSheet.GetItemSet().Put(pSourceSheet->GetItemSet());
+ rCreatedSheets.emplace_back(static_cast<SdStyleSheet*>(&rNewSheet), true);
+ }
+ }
+ }
+
+ // Special treatment for outline templates: create parent relation
+ std::vector<SfxStyleSheetBase*> aOutlineSheets;
+ CreateOutlineSheetList(rLayoutName,aOutlineSheets);
+
+ if( aOutlineSheets.empty() )
+ return;
+
+ std::vector<SfxStyleSheetBase*>::iterator it = aOutlineSheets.begin();
+ SfxStyleSheetBase* pParent = *it;
+ ++it;
+
+ while (it != aOutlineSheets.end())
+ {
+ pSheet = *it;
+
+ if (!pSheet)
+ break;
+
+ if (pSheet->GetParent().isEmpty())
+ pSheet->SetParent(pParent->GetName());
+
+ pParent = pSheet;
+
+ ++it;
+ }
+}
+
+/*************************************************************************
+|*
+|* Create list with names of the presentation templates of a layout.
+|* The list and the containing strings are owned by the caller!
+|*
+\************************************************************************/
+
+void SdStyleSheetPool::CreateLayoutSheetNames(std::u16string_view rLayoutName, std::vector<OUString> &aNameList)
+{
+ OUString aPrefix(OUString::Concat(rLayoutName) + SD_LT_SEPARATOR);
+
+ for (sal_Int32 nLevel = 1; nLevel < 10; nLevel++)
+ aNameList.emplace_back(aPrefix + STR_LAYOUT_OUTLINE + " " + OUString::number( nLevel ) );
+
+ aNameList.emplace_back(aPrefix + STR_LAYOUT_TITLE);
+ aNameList.emplace_back(aPrefix + STR_LAYOUT_SUBTITLE);
+ aNameList.emplace_back(aPrefix + STR_LAYOUT_NOTES);
+ aNameList.emplace_back(aPrefix + STR_LAYOUT_BACKGROUNDOBJECTS);
+ aNameList.emplace_back(aPrefix + STR_LAYOUT_BACKGROUND);
+}
+
+/*************************************************************************
+|*
+|* Create a list with pointer to presentation templates of a layout.
+|* The list is owned by the caller!
+|*
+\************************************************************************/
+
+void SdStyleSheetPool::CreateLayoutSheetList(std::u16string_view rLayoutName, SdStyleSheetVector& rLayoutSheets )
+{
+ OUString aLayoutNameWithSep(OUString::Concat(rLayoutName) + SD_LT_SEPARATOR);
+
+ SfxStyleSheetIterator aIter(this, SfxStyleFamily::Page);
+ SfxStyleSheetBase* pSheet = aIter.First();
+
+ while (pSheet)
+ {
+ if (pSheet->GetName().startsWith(aLayoutNameWithSep))
+ rLayoutSheets.emplace_back( static_cast< SdStyleSheet* >( pSheet ) );
+ pSheet = aIter.Next();
+ }
+}
+
+/*************************************************************************
+|*
+|* Create pseudo style sheets if necessary
+|*
+\************************************************************************/
+
+void SdStyleSheetPool::CreatePseudosIfNecessary()
+{
+ OUString aName;
+ const OUString aHelpFile;
+ SfxStyleSheetBase* pSheet = nullptr;
+ SfxStyleSheetBase* pParent = nullptr;
+
+ SfxStyleSearchBits nUsedMask = SfxStyleSearchBits::Used;
+
+ aName = SdResId(STR_PSEUDOSHEET_TITLE);
+ if( (pSheet = Find(aName, SfxStyleFamily::Pseudo)) == nullptr )
+ {
+ pSheet = &Make(aName, SfxStyleFamily::Pseudo, nUsedMask);
+ pSheet->SetParent( OUString() );
+ static_cast<SfxStyleSheet*>(pSheet)->StartListening(*this);
+ }
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_TITLE );
+
+ aName = SdResId(STR_PSEUDOSHEET_SUBTITLE);
+ if( (pSheet = Find(aName, SfxStyleFamily::Pseudo)) == nullptr )
+ {
+ pSheet = &Make(aName, SfxStyleFamily::Pseudo, nUsedMask);
+ pSheet->SetParent( OUString() );
+ static_cast<SfxStyleSheet*>(pSheet)->StartListening(*this);
+ }
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_SUBTITLE );
+
+ aName = SdResId(STR_PSEUDOSHEET_BACKGROUNDOBJECTS);
+ if( (pSheet = Find(aName, SfxStyleFamily::Pseudo)) == nullptr )
+ {
+ pSheet = &Make(aName, SfxStyleFamily::Pseudo, nUsedMask);
+ pSheet->SetParent( OUString() );
+ static_cast<SfxStyleSheet*>(pSheet)->StartListening(*this);
+ }
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_BACKGROUNDOBJECTS );
+
+ aName = SdResId(STR_PSEUDOSHEET_BACKGROUND);
+ if( (pSheet = Find(aName, SfxStyleFamily::Pseudo)) == nullptr )
+ {
+ pSheet = &Make(aName, SfxStyleFamily::Pseudo, nUsedMask);
+ pSheet->SetParent( OUString() );
+ static_cast<SfxStyleSheet*>(pSheet)->StartListening(*this);
+ }
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_BACKGROUND );
+
+ aName = SdResId(STR_PSEUDOSHEET_NOTES);
+ if( (pSheet = Find(aName, SfxStyleFamily::Pseudo)) == nullptr )
+ {
+ pSheet = &Make(aName, SfxStyleFamily::Pseudo, nUsedMask);
+ pSheet->SetParent( OUString() );
+ static_cast<SfxStyleSheet*>(pSheet)->StartListening(*this);
+ }
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_NOTES );
+
+ pParent = nullptr;
+ aName = SdResId(STR_PSEUDOSHEET_OUTLINE);
+ for (sal_Int32 nLevel = 1; nLevel < 10; nLevel++)
+ {
+ OUString aLevelName( aName + " " + OUString::number( nLevel ) );
+
+ if( (pSheet = Find(aLevelName, SfxStyleFamily::Pseudo)) == nullptr )
+ {
+ pSheet = &Make(aLevelName, SfxStyleFamily::Pseudo, nUsedMask);
+
+ if (pParent)
+ pSheet->SetParent(pParent->GetName());
+ pParent = pSheet;
+ static_cast<SfxStyleSheet*>(pSheet)->StartListening(*this);
+ }
+ pSheet->SetHelpId( aHelpFile, HID_PSEUDOSHEET_OUTLINE + nLevel );
+ }
+}
+
+/*************************************************************************
+|*
+|* Set the correct name in the program language to the standard styles
+|*
+\************************************************************************/
+
+namespace
+{
+struct StyleSheetIsUserDefinedPredicate : svl::StyleSheetPredicate
+{
+ StyleSheetIsUserDefinedPredicate()
+ {}
+
+ bool Check(const SfxStyleSheetBase& sheet) override
+ {
+ return sheet.IsUserDefined();
+ }
+};
+}
+
+void SdStyleSheetPool::UpdateStdNames()
+{
+ OUString aHelpFile;
+ StyleSheetIsUserDefinedPredicate aPredicate;
+ std::vector<SfxStyleSheetBase*> aEraseList;
+ std::vector<sal_Int32> aUserDefinedStyles = GetIndexedStyleSheets().FindPositionsByPredicate(aPredicate);
+ for (const auto& rStyle : aUserDefinedStyles)
+ {
+ SfxStyleSheetBase* pStyle = GetStyleSheetByPositionInIndex(rStyle);
+
+ if( !pStyle->IsUserDefined() )
+ {
+ OUString aOldName = pStyle->GetName();
+ sal_uLong nHelpId = pStyle->GetHelpId( aHelpFile );
+ SfxStyleFamily eFam = pStyle->GetFamily();
+
+ bool bHelpKnown = true;
+ TranslateId pNameId;
+ switch( nHelpId )
+ {
+ case HID_STANDARD_STYLESHEET_NAME: pNameId = STR_STANDARD_STYLESHEET_NAME; break;
+ case HID_POOLSHEET_OBJWITHOUTFILL: pNameId = STR_POOLSHEET_OBJWITHOUTFILL; break;
+ case HID_POOLSHEET_OBJNOLINENOFILL: pNameId = STR_POOLSHEET_OBJNOLINENOFILL;break;
+ case HID_POOLSHEET_TEXT: pNameId = STR_POOLSHEET_TEXT; break;
+ case HID_POOLSHEET_A4: pNameId = STR_POOLSHEET_A4; break;
+ case HID_POOLSHEET_A4_TITLE: pNameId = STR_POOLSHEET_A4_TITLE; break;
+ case HID_POOLSHEET_A4_HEADLINE: pNameId = STR_POOLSHEET_A4_HEADLINE; break;
+ case HID_POOLSHEET_A4_TEXT: pNameId = STR_POOLSHEET_A4_TEXT; break;
+ case HID_POOLSHEET_A0: pNameId = STR_POOLSHEET_A0; break;
+ case HID_POOLSHEET_A0_TITLE: pNameId = STR_POOLSHEET_A0_TITLE; break;
+ case HID_POOLSHEET_A0_HEADLINE: pNameId = STR_POOLSHEET_A0_HEADLINE; break;
+ case HID_POOLSHEET_A0_TEXT: pNameId = STR_POOLSHEET_A0_TEXT; break;
+ case HID_POOLSHEET_GRAPHIC: pNameId = STR_POOLSHEET_GRAPHIC; break;
+ case HID_POOLSHEET_SHAPES: pNameId = STR_POOLSHEET_SHAPES; break;
+ case HID_POOLSHEET_FILLED: pNameId = STR_POOLSHEET_FILLED; break;
+ case HID_POOLSHEET_FILLED_BLUE: pNameId = STR_POOLSHEET_FILLED_BLUE; break;
+ case HID_POOLSHEET_FILLED_GREEN: pNameId = STR_POOLSHEET_FILLED_GREEN; break;
+ case HID_POOLSHEET_FILLED_RED: pNameId = STR_POOLSHEET_FILLED_RED; break;
+ case HID_POOLSHEET_FILLED_YELLOW: pNameId = STR_POOLSHEET_FILLED_YELLOW; break;
+ case HID_POOLSHEET_OUTLINE: pNameId = STR_POOLSHEET_OUTLINE; break;
+ case HID_POOLSHEET_OUTLINE_BLUE: pNameId = STR_POOLSHEET_OUTLINE_BLUE; break;
+ case HID_POOLSHEET_OUTLINE_GREEN: pNameId = STR_POOLSHEET_OUTLINE_GREEN; break;
+ case HID_POOLSHEET_OUTLINE_RED: pNameId = STR_POOLSHEET_OUTLINE_RED; break;
+ case HID_POOLSHEET_OUTLINE_YELLOW: pNameId = STR_POOLSHEET_OUTLINE_YELLOW; break;
+ case HID_POOLSHEET_LINES: pNameId = STR_POOLSHEET_LINES; break;
+ case HID_POOLSHEET_MEASURE: pNameId = STR_POOLSHEET_MEASURE; break;
+ case HID_POOLSHEET_LINES_DASHED: pNameId = STR_POOLSHEET_LINES_DASHED; break;
+
+ case HID_PSEUDOSHEET_OUTLINE1:
+ case HID_PSEUDOSHEET_OUTLINE2:
+ case HID_PSEUDOSHEET_OUTLINE3:
+ case HID_PSEUDOSHEET_OUTLINE4:
+ case HID_PSEUDOSHEET_OUTLINE5:
+ case HID_PSEUDOSHEET_OUTLINE6:
+ case HID_PSEUDOSHEET_OUTLINE7:
+ case HID_PSEUDOSHEET_OUTLINE8:
+ case HID_PSEUDOSHEET_OUTLINE9: pNameId = STR_PSEUDOSHEET_OUTLINE; break;
+ case HID_PSEUDOSHEET_BACKGROUNDOBJECTS: pNameId = STR_PSEUDOSHEET_BACKGROUNDOBJECTS; break;
+ case HID_PSEUDOSHEET_BACKGROUND: pNameId = STR_PSEUDOSHEET_BACKGROUND; break;
+ case HID_PSEUDOSHEET_NOTES: pNameId = STR_PSEUDOSHEET_NOTES; break;
+
+ case HID_SD_CELL_STYLE_DEFAULT: pNameId = STR_STANDARD_STYLESHEET_NAME; break;
+ case HID_SD_CELL_STYLE_BANDED: pNameId = STR_POOLSHEET_BANDED_CELL; break;
+ case HID_SD_CELL_STYLE_HEADER: pNameId = STR_POOLSHEET_HEADER; break;
+ case HID_SD_CELL_STYLE_TOTAL: pNameId = STR_POOLSHEET_TOTAL; break;
+ case HID_SD_CELL_STYLE_FIRST_COLUMN: pNameId = STR_POOLSHEET_FIRST_COLUMN; break;
+ case HID_SD_CELL_STYLE_LAST_COLUMN: pNameId = STR_POOLSHEET_LAST_COLUMN; break;
+
+ default:
+ // 0 or wrong (old) HelpId
+ bHelpKnown = false;
+ }
+ if( bHelpKnown )
+ {
+ OUString aNewName;
+ if (pNameId)
+ {
+ if (pNameId == STR_PSEUDOSHEET_OUTLINE)
+ {
+ aNewName += " " + OUString::number( sal_Int32( nHelpId - HID_PSEUDOSHEET_OUTLINE ) );
+ }
+ }
+
+ if( !aNewName.isEmpty() && aNewName != aOldName )
+ {
+ SfxStyleSheetBase* pSheetFound = Find( aNewName, eFam );
+
+ if ( !pSheetFound )
+ {
+ // Sheet does not yet exist: rename old sheet
+ pStyle->SetName( aNewName ); // transform also parents
+ }
+ else
+ {
+ // Sheet does exist: old sheet has to be removed
+ aEraseList.push_back( pStyle );
+ }
+ }
+ }
+ }
+ }
+
+ if (!aEraseList.empty())
+ {
+ // styles that could not be renamed, must be removed
+ for (SfxStyleSheetBase* p : aEraseList)
+ Remove( p );
+ Reindex();
+ }
+}
+
+void SdStyleSheetPool::setDefaultOutlineNumberFormatBulletAndIndent(sal_uInt16 i, SvxNumberFormat &rNumberFormat)
+{
+ rNumberFormat.SetBulletChar( 0x25CF ); // StarBats: 0xF000 + 34
+ rNumberFormat.SetBulletRelSize(45);
+ const auto nLSpace = (i + 1) * 1200;
+ rNumberFormat.SetAbsLSpace(nLSpace);
+ sal_Int32 nFirstLineOffset = -600;
+
+ switch(i)
+ {
+ case 0:
+ {
+ nFirstLineOffset = -900;
+ }
+ break;
+
+ case 1:
+ {
+ rNumberFormat.SetBulletChar( 0x2013 ); // StarBats: 0xF000 + 150
+ rNumberFormat.SetBulletRelSize(75);
+ nFirstLineOffset = -900;
+ }
+ break;
+
+ case 2:
+ {
+ nFirstLineOffset = -800;
+ }
+ break;
+
+ case 3:
+ {
+ rNumberFormat.SetBulletChar( 0x2013 ); // StarBats: 0xF000 + 150
+ rNumberFormat.SetBulletRelSize(75);
+ }
+ break;
+ }
+
+ rNumberFormat.SetFirstLineOffset(nFirstLineOffset);
+}
+
+// Set new SvxNumBulletItem for the respective style sheet
+void SdStyleSheetPool::PutNumBulletItem( SfxStyleSheetBase* pSheet,
+ vcl::Font& rBulletFont )
+{
+ OUString aHelpFile;
+ sal_uLong nHelpId = pSheet->GetHelpId( aHelpFile );
+ SfxItemSet& rSet = pSheet->GetItemSet();
+
+ switch ( nHelpId )
+ {
+ case HID_STANDARD_STYLESHEET_NAME :
+ {
+ // Standard template
+ SvxNumberFormat aNumberFormat(SVX_NUM_CHAR_SPECIAL);
+ aNumberFormat.SetBulletFont(&rBulletFont);
+ aNumberFormat.SetBulletChar( 0x25CF ); // StarBats: 0xF000 + 34
+ aNumberFormat.SetBulletRelSize(45);
+ aNumberFormat.SetBulletColor(COL_AUTO);
+ aNumberFormat.SetStart(1);
+ aNumberFormat.SetNumAdjust(SvxAdjust::Left);
+
+ SvxNumRule aNumRule( SvxNumRuleFlags::BULLET_REL_SIZE | SvxNumRuleFlags::BULLET_COLOR, SVX_MAX_NUM, false);
+
+ for( sal_uInt16 i = 0; i < aNumRule.GetLevelCount(); i++ )
+ {
+ const auto nLSpace = (i + 1) * 600;
+ aNumberFormat.SetAbsLSpace(nLSpace);
+ aNumberFormat.SetFirstLineOffset(-600);
+ aNumRule.SetLevel( i, aNumberFormat );
+ }
+
+ rSet.Put( SvxNumBulletItem( std::move(aNumRule), EE_PARA_NUMBULLET ) );
+ static_cast<SfxStyleSheet*>(pSheet)->Broadcast(SfxHint( SfxHintId::DataChanged ) );
+ }
+ break;
+
+ case HID_PSEUDOSHEET_TITLE:
+ /* title gets same bullet as subtitle and not that page symbol anymore */
+ case HID_PSEUDOSHEET_SUBTITLE :
+ {
+ // Subtitle template
+ SvxNumBulletItem const*const pItem(
+ rSet.GetPool()->GetSecondaryPool()->GetPoolDefaultItem(EE_PARA_NUMBULLET));
+ const SvxNumRule *const pDefaultRule = pItem ? &pItem->GetNumRule() : nullptr;
+ DBG_ASSERT( pDefaultRule, "Where is my default template? [CL]" );
+
+ if(pDefaultRule)
+ {
+ SvxNumRule aNumRule(pDefaultRule->GetFeatureFlags(), 10, false);
+ for(sal_uInt16 i=0; i < aNumRule.GetLevelCount(); i++)
+ {
+ SvxNumberFormat aFrmt( pDefaultRule->GetLevel(i) );
+ aFrmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
+ // #i93908# clear suffix for bullet lists
+ aFrmt.SetPrefix(OUString());
+ aFrmt.SetSuffix(OUString());
+ aFrmt.SetStart(1);
+ aFrmt.SetBulletRelSize(45);
+ aFrmt.SetBulletChar( 0x25CF ); // StarBats: 0xF000 + 34
+ aFrmt.SetBulletFont(&rBulletFont);
+ aNumRule.SetLevel(i, aFrmt);
+ }
+
+ rSet.Put( SvxNumBulletItem( std::move(aNumRule), EE_PARA_NUMBULLET ) );
+ static_cast<SfxStyleSheet*>(pSheet)->Broadcast(SfxHint( SfxHintId::DataChanged ) );
+ }
+ }
+ break;
+
+ case HID_PSEUDOSHEET_OUTLINE + 1 :
+ {
+ // Outline template
+ SvxNumberFormat aNumberFormat(SVX_NUM_CHAR_SPECIAL);
+ aNumberFormat.SetBulletColor(COL_AUTO);
+ aNumberFormat.SetStart(1);
+ aNumberFormat.SetNumAdjust(SvxAdjust::Left);
+
+ SvxNumRule aNumRule( SvxNumRuleFlags::BULLET_REL_SIZE | SvxNumRuleFlags::BULLET_COLOR,
+ SVX_MAX_NUM, false );
+ for( sal_uInt16 i = 0; i < aNumRule.GetLevelCount(); i++ )
+ {
+ setDefaultOutlineNumberFormatBulletAndIndent(i, aNumberFormat);
+ rBulletFont.SetFontSize(Size(0,846)); // 24 pt
+ aNumberFormat.SetBulletFont(&rBulletFont);
+ aNumRule.SetLevel( i, aNumberFormat );
+ }
+
+ rSet.Put( SvxNumBulletItem( std::move(aNumRule), EE_PARA_NUMBULLET ) );
+ static_cast<SfxStyleSheet*>(pSheet)->Broadcast(SfxHint( SfxHintId::DataChanged ) );
+ }
+ break;
+ }
+}
+
+/*************************************************************************
+|*
+|* Create standard bullet font (without size)
+|*
+\************************************************************************/
+
+vcl::Font SdStyleSheetPool::GetBulletFont()
+{
+ vcl::Font aBulletFont( "StarSymbol", Size(0, 1000) );
+ aBulletFont.SetCharSet(RTL_TEXTENCODING_UNICODE);
+ aBulletFont.SetWeight(WEIGHT_NORMAL);
+ aBulletFont.SetUnderline(LINESTYLE_NONE);
+ aBulletFont.SetOverline(LINESTYLE_NONE);
+ aBulletFont.SetStrikeout(STRIKEOUT_NONE);
+ aBulletFont.SetItalic(ITALIC_NONE);
+ aBulletFont.SetOutline(false);
+ aBulletFont.SetShadow(false);
+ aBulletFont.SetColor(COL_AUTO);
+ aBulletFont.SetTransparent(true);
+
+ return aBulletFont;
+}
+
+void SdStyleSheetPool::AddStyleFamily( const SdPage* pPage )
+{
+ rtl::Reference< SfxStyleSheetPool > xPool( this );
+ maStyleFamilyMap[pPage] = new SdStyleFamily( xPool, pPage );
+}
+
+void SdStyleSheetPool::RemoveStyleFamily( const SdPage* pPage )
+{
+ SdStyleFamilyMap::iterator iter( maStyleFamilyMap.find( pPage ) );
+ if( iter == maStyleFamilyMap.end() )
+ return;
+
+ SdStyleFamilyRef xStyle( (*iter).second );
+ maStyleFamilyMap.erase( iter );
+
+ if( xStyle.is() ) try
+ {
+ xStyle->dispose();
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void SdStyleSheetPool::throwIfDisposed()
+{
+ if( mpDoc == nullptr )
+ throw DisposedException();
+}
+
+// XServiceInfo
+OUString SAL_CALL SdStyleSheetPool::getImplementationName()
+{
+ return "SdStyleSheetPool";
+}
+
+sal_Bool SAL_CALL SdStyleSheetPool::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL SdStyleSheetPool::getSupportedServiceNames()
+{
+ return { "com.sun.star.style.StyleFamilies" };
+}
+
+// XNameAccess
+Any SAL_CALL SdStyleSheetPool::getByName( const OUString& aName )
+{
+ throwIfDisposed();
+
+ if( mxGraphicFamily->getName() == aName )
+ return Any( Reference< XNameAccess >( static_cast< XNameAccess* >( mxGraphicFamily.get() ) ) );
+
+ if( mxCellFamily->getName() == aName )
+ return Any( Reference< XNameAccess >( static_cast< XNameAccess* >( mxCellFamily.get() ) ) );
+
+ if( msTableFamilyName == aName )
+ return Any( mxTableFamily );
+
+ auto iter = std::find_if(maStyleFamilyMap.begin(), maStyleFamilyMap.end(),
+ [&aName](const SdStyleFamilyMap::value_type& rEntry) { return rEntry.second->getName() == aName; });
+ if (iter != maStyleFamilyMap.end())
+ return Any( Reference< XNameAccess >( static_cast< XNameAccess* >( (*iter).second.get() ) ) );
+
+ throw NoSuchElementException();
+}
+
+Sequence< OUString > SAL_CALL SdStyleSheetPool::getElementNames()
+{
+ throwIfDisposed();
+
+ Sequence< OUString > aNames( maStyleFamilyMap.size() + 3 );
+ OUString* pNames = aNames.getArray();
+
+ *pNames++ = mxGraphicFamily->getName();
+ *pNames++ = mxCellFamily->getName();
+ *pNames++ = msTableFamilyName;
+
+ for( const auto& rEntry : maStyleFamilyMap )
+ {
+ *pNames++ = rEntry.second->getName();
+ }
+
+ return aNames;
+}
+
+sal_Bool SAL_CALL SdStyleSheetPool::hasByName( const OUString& aName )
+{
+ throwIfDisposed();
+
+ if( mxGraphicFamily->getName() == aName )
+ return true;
+
+ if( mxCellFamily->getName() == aName )
+ return true;
+
+ if( msTableFamilyName == aName )
+ return true;
+
+ return std::any_of(maStyleFamilyMap.begin(), maStyleFamilyMap.end(),
+ [&aName](const SdStyleFamilyMap::value_type& rEntry) { return rEntry.second->getName() == aName; });
+}
+
+// XElementAccess
+
+Type SAL_CALL SdStyleSheetPool::getElementType()
+{
+ throwIfDisposed();
+
+ return cppu::UnoType<XNameAccess>::get();
+}
+
+sal_Bool SAL_CALL SdStyleSheetPool::hasElements()
+{
+ return true;
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL SdStyleSheetPool::getCount()
+{
+ throwIfDisposed();
+
+ return maStyleFamilyMap.size() + 3;
+}
+
+Any SAL_CALL SdStyleSheetPool::getByIndex( sal_Int32 Index )
+{
+ switch( Index )
+ {
+ case 0:
+ return Any( Reference< XNameAccess >( static_cast< XNameAccess* >( mxGraphicFamily.get() ) ) );
+
+ case 1:
+ return Any( Reference< XNameAccess >( static_cast< XNameAccess* >( mxCellFamily.get() ) ) );
+
+ case 2:
+ return Any( mxTableFamily );
+
+ default:
+ {
+ Index -= 3;
+ if( (Index < 0) || (Index >= sal::static_int_cast<sal_Int32>(maStyleFamilyMap.size())) )
+ throw IndexOutOfBoundsException();
+ SdStyleFamilyMap::iterator iter( maStyleFamilyMap.begin() );
+ std::advance(iter, Index);
+
+ return Any( Reference< XNameAccess >( static_cast< XNameAccess* >( (*iter).second.get() ) ) );
+ }
+ }
+}
+
+// XComponent
+
+void SAL_CALL SdStyleSheetPool::dispose()
+{
+ if( !mpDoc )
+ return;
+
+ mxGraphicFamily->dispose();
+ mxGraphicFamily.clear();
+ mxCellFamily->dispose();
+ mxCellFamily.clear();
+
+ Reference< XComponent > xComp( mxTableFamily, UNO_QUERY );
+ if( xComp.is() )
+ xComp->dispose();
+ mxTableFamily = nullptr;
+
+ SdStyleFamilyMap aTempMap;
+ aTempMap.swap( maStyleFamilyMap );
+
+ for( auto& rEntry : aTempMap ) try
+ {
+ rEntry.second->dispose();
+ }
+ catch( Exception& )
+ {
+ }
+
+ mpDoc = nullptr;
+
+ Clear();
+}
+
+void SAL_CALL SdStyleSheetPool::addEventListener( const Reference< XEventListener >& /*xListener*/ )
+{
+}
+
+void SAL_CALL SdStyleSheetPool::removeEventListener( const Reference< XEventListener >& /*aListener*/ )
+{
+}
+
+SdStyleSheetVector SdStyleSheetPool::CreateChildList( SdStyleSheet const * pSheet )
+{
+ SdStyleSheetVector aResult;
+
+ const size_t nListenerCount = pSheet->GetSizeOfVector();
+ for (size_t n = 0; n < nListenerCount; ++n)
+ {
+ SdStyleSheet* pChild = dynamic_cast< SdStyleSheet* >( pSheet->GetListener(n) );
+ if(pChild && pChild->GetParent() == pSheet->GetName())
+ {
+ aResult.emplace_back( pChild );
+ }
+ }
+
+ return aResult;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/stlsheet.cxx b/sd/source/core/stlsheet.cxx
new file mode 100644
index 000000000..db061922b
--- /dev/null
+++ b/sd/source/core/stlsheet.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 <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/table/BorderLine.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
+
+#include <o3tl/string_view.hxx>
+#include <osl/mutex.hxx>
+#include <vcl/svapp.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <svl/hint.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itemset.hxx>
+
+#include <svx/xflbmtit.hxx>
+#include <svx/xflbstit.hxx>
+#include <editeng/bulletitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <svx/unoshprp.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdtaaitm.hxx>
+#include <svx/sdtacitm.hxx>
+#include <svx/sdtayitm.hxx>
+#include <svx/sdtaiitm.hxx>
+#include <svx/xit.hxx>
+#include <svx/xflclit.hxx>
+#include <tools/diagnose_ex.h>
+#include <stlsheet.hxx>
+#include <sdresid.hxx>
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <stlpool.hxx>
+#include <strings.hrc>
+#include <app.hrc>
+#include <strings.hxx>
+#include <glob.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShellBase.hxx>
+
+#include <cstddef>
+#include <memory>
+#include <string_view>
+
+using ::osl::MutexGuard;
+using ::osl::ClearableMutexGuard;
+using ::com::sun::star::table::BorderLine;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::drawing;
+
+#define WID_STYLE_HIDDEN 7997
+#define WID_STYLE_DISPNAME 7998
+#define WID_STYLE_FAMILY 7999
+
+static SvxItemPropertySet& GetStylePropertySet()
+{
+ static const SfxItemPropertyMapEntry aFullPropertyMap_Impl[] =
+ {
+ { u"Family", WID_STYLE_FAMILY, ::cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0},
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<XNameContainer>::get(), 0, 0},
+ { u"DisplayName", WID_STYLE_DISPNAME, ::cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0},
+ { u"Hidden", WID_STYLE_HIDDEN, cppu::UnoType<bool>::get(), 0, 0},
+
+ SVX_UNOEDIT_NUMBERING_PROPERTY,
+ SHADOW_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ FILL_PROPERTIES
+ EDGERADIUS_PROPERTIES
+ TEXT_PROPERTIES_DEFAULTS
+ CONNECTOR_PROPERTIES
+ SPECIAL_DIMENSIONING_PROPERTIES_DEFAULTS
+ { u"TopBorder", SDRATTR_TABLE_BORDER, ::cppu::UnoType<BorderLine>::get(), 0, TOP_BORDER },
+ { u"BottomBorder", SDRATTR_TABLE_BORDER, ::cppu::UnoType<BorderLine>::get(), 0, BOTTOM_BORDER },
+ { u"LeftBorder", SDRATTR_TABLE_BORDER, ::cppu::UnoType<BorderLine>::get(), 0, LEFT_BORDER },
+ { u"RightBorder", SDRATTR_TABLE_BORDER, ::cppu::UnoType<BorderLine>::get(), 0, RIGHT_BORDER },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ static SvxItemPropertySet aPropSet( aFullPropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ return aPropSet;
+}
+
+class ModifyListenerForwarder : public SfxListener
+{
+public:
+ explicit ModifyListenerForwarder( SdStyleSheet* pStyleSheet );
+
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+private:
+ SdStyleSheet* mpStyleSheet;
+};
+
+ModifyListenerForwarder::ModifyListenerForwarder( SdStyleSheet* pStyleSheet )
+: mpStyleSheet( pStyleSheet )
+{
+ if( pStyleSheet )
+ {
+ SfxBroadcaster& rBC = static_cast< SfxBroadcaster& >( *pStyleSheet );
+ StartListening( rBC );
+ }
+}
+
+void ModifyListenerForwarder::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& /*rHint*/)
+{
+ if( mpStyleSheet )
+ mpStyleSheet->notifyModifyListener();
+}
+
+SdStyleSheet::SdStyleSheet(const OUString& rDisplayName, SfxStyleSheetBasePool& _rPool, SfxStyleFamily eFamily, SfxStyleSearchBits _nMask)
+: SdStyleSheetBase( rDisplayName, _rPool, eFamily, _nMask)
+, ::cppu::BaseMutex()
+, msApiName( rDisplayName )
+, mxPool( &_rPool )
+, mrBHelper( m_aMutex )
+{
+}
+
+SdStyleSheet::~SdStyleSheet()
+{
+ delete pSet;
+ pSet = nullptr; // that following destructors also get a change
+}
+
+void SdStyleSheet::SetApiName( const OUString& rApiName )
+{
+ msApiName = rApiName;
+}
+
+OUString const & SdStyleSheet::GetApiName() const
+{
+ if( !msApiName.isEmpty() )
+ return msApiName;
+ else
+ return GetName();
+}
+
+bool SdStyleSheet::SetParent(const OUString& rParentName)
+{
+ bool bResult = false;
+
+ if (SfxStyleSheet::SetParent(rParentName))
+ {
+ // PseudoStyleSheets do not have their own ItemSets
+ if (nFamily != SfxStyleFamily::Pseudo)
+ {
+ if( !rParentName.isEmpty() )
+ {
+ SfxStyleSheetBase* pStyle = m_pPool->Find(rParentName, nFamily);
+ if (pStyle)
+ {
+ bResult = true;
+ SfxItemSet& rParentSet = pStyle->GetItemSet();
+ GetItemSet().SetParent(&rParentSet);
+ Broadcast( SfxHint( SfxHintId::DataChanged ) );
+ }
+ }
+ else
+ {
+ bResult = true;
+ GetItemSet().SetParent(nullptr);
+ Broadcast( SfxHint( SfxHintId::DataChanged ) );
+ }
+ }
+ else
+ {
+ bResult = true;
+ }
+ }
+ return bResult;
+}
+
+/**
+ * create if necessary and return ItemSets
+ */
+SfxItemSet& SdStyleSheet::GetItemSet()
+{
+ if (nFamily == SfxStyleFamily::Para || nFamily == SfxStyleFamily::Page)
+ {
+ // we create the ItemSet 'on demand' if necessary
+ if (!pSet)
+ {
+ pSet = new SfxItemSetFixed<
+ XATTR_LINE_FIRST, XATTR_LINE_LAST,
+ XATTR_FILL_FIRST, XATTR_FILL_LAST,
+ SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST,
+ SDRATTR_TEXT_MINFRAMEHEIGHT, SDRATTR_TEXT_WORDWRAP,
+ SDRATTR_EDGE_FIRST, SDRATTR_MEASURE_LAST,
+ SDRATTR_3D_FIRST, SDRATTR_3D_LAST,
+ EE_PARA_START, EE_CHAR_END>(GetPool()->GetPool());
+ bMySet = true;
+ }
+
+ return *pSet;
+ }
+
+ else if( nFamily == SfxStyleFamily::Frame )
+ {
+ if (!pSet)
+ {
+ pSet = new SfxItemSetFixed<
+ XATTR_LINE_FIRST, XATTR_LINE_LAST,
+ XATTR_FILL_FIRST, XATTR_FILL_LAST,
+ SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST,
+ SDRATTR_TEXT_MINFRAMEHEIGHT, SDRATTR_XMLATTRIBUTES,
+ SDRATTR_TEXT_WORDWRAP, SDRATTR_TEXT_WORDWRAP,
+ SDRATTR_TABLE_FIRST, SDRATTR_TABLE_LAST,
+ EE_PARA_START, EE_CHAR_END>(GetPool()->GetPool());
+
+ bMySet = true;
+ }
+
+ return *pSet;
+ }
+
+ // this is a dummy template for the internal template of the
+ // current presentation layout; return the ItemSet of that template
+ else
+ {
+
+ SdStyleSheet* pSdSheet = GetRealStyleSheet();
+
+ if (pSdSheet)
+ {
+ return pSdSheet->GetItemSet();
+ }
+ else
+ {
+ if (!pSet)
+ {
+ pSet = new SfxItemSetFixed<
+ XATTR_LINE_FIRST, XATTR_LINE_LAST,
+ XATTR_FILL_FIRST, XATTR_FILL_LAST,
+ SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST,
+ SDRATTR_TEXT_MINFRAMEHEIGHT, SDRATTR_TEXT_WORDWRAP,
+ SDRATTR_EDGE_FIRST, SDRATTR_MEASURE_LAST,
+ SDRATTR_3D_FIRST, SDRATTR_3D_LAST,
+ EE_PARA_START, EE_CHAR_END>(GetPool()->GetPool());
+ bMySet = true;
+ }
+
+ return(*pSet);
+ }
+ }
+}
+
+/**
+ * A template is used when it is referenced by inserted object or by a used
+ * template.
+ */
+bool SdStyleSheet::IsUsed() const
+{
+ bool bResult = false;
+
+ const size_t nListenerCount = GetSizeOfVector();
+ for (size_t n = 0; n < nListenerCount; ++n)
+ {
+ SfxListener* pListener = GetListener(n);
+ if( pListener == this )
+ continue;
+
+ const svl::StyleSheetUser* const pUser(dynamic_cast<svl::StyleSheetUser*>(pListener));
+ if (pUser)
+ bResult = pUser->isUsedByModel();
+ if (bResult)
+ break;
+ }
+
+ if( !bResult )
+ {
+ MutexGuard aGuard( mrBHelper.rMutex );
+
+ cppu::OInterfaceContainerHelper * pContainer = mrBHelper.getContainer( cppu::UnoType<XModifyListener>::get() );
+ if( pContainer )
+ {
+ const Sequence< Reference< XInterface > > aModifyListeners( pContainer->getElements() );
+ bResult = std::any_of(aModifyListeners.begin(), aModifyListeners.end(),
+ [](const Reference<XInterface>& rListener) {
+ Reference< XStyle > xStyle( rListener, UNO_QUERY );
+ return xStyle.is() && xStyle->isInUse();
+ });
+ }
+ }
+ return bResult;
+}
+
+/**
+ * Determine the style sheet for which this dummy is for.
+ */
+SdStyleSheet* SdStyleSheet::GetRealStyleSheet() const
+{
+ OUString aRealStyle;
+ OUString aSep( SD_LT_SEPARATOR );
+ SdStyleSheet* pRealStyle = nullptr;
+ SdDrawDocument* pDoc = static_cast<SdStyleSheetPool*>(m_pPool)->GetDoc();
+
+ ::sd::DrawViewShell* pDrawViewShell = nullptr;
+
+ ::sd::ViewShellBase* pBase = dynamic_cast< ::sd::ViewShellBase* >( SfxViewShell::Current() );
+ if( pBase )
+ pDrawViewShell = dynamic_cast< ::sd::DrawViewShell* >( pBase->GetMainViewShell().get() );
+
+ if (pDrawViewShell && pDrawViewShell->GetDoc() == pDoc)
+ {
+ SdPage* pPage = pDrawViewShell->getCurrentPage();
+ if( pPage )
+ {
+ aRealStyle = pPage->GetLayoutName();
+ // cut after separator string
+
+ if( aRealStyle.indexOf(aSep) >= 0)
+ {
+ aRealStyle = aRealStyle.copy(0,(aRealStyle.indexOf(aSep) + aSep.getLength()));
+ }
+ }
+ }
+ if (aRealStyle.isEmpty())
+ {
+ SdPage* pPage = pDoc->GetSdPage(0, PageKind::Standard);
+
+ if (pPage)
+ {
+ aRealStyle = pDoc->GetSdPage(0, PageKind::Standard)->GetLayoutName();
+ }
+ else
+ {
+ /* no page available yet. This can happen when actualizing the
+ document templates. */
+ SfxStyleSheetIterator aIter(m_pPool, SfxStyleFamily::Page);
+ SfxStyleSheetBase* pSheet = aIter.First();
+ if( pSheet )
+ aRealStyle = pSheet->GetName();
+ }
+
+ if( aRealStyle.indexOf(aSep) >= 0)
+ {
+ aRealStyle = aRealStyle.copy(0,(aRealStyle.indexOf(aSep) + aSep.getLength()));
+ }
+ }
+
+ /* now map from the name (specified for country language) to the internal
+ name (independent of the country language) */
+ OUString aInternalName;
+ OUString aStyleName(aName);
+
+ if (aStyleName == SdResId(STR_PSEUDOSHEET_TITLE))
+ {
+ aInternalName = STR_LAYOUT_TITLE;
+ }
+ else if (aStyleName == SdResId(STR_PSEUDOSHEET_SUBTITLE))
+ {
+ aInternalName = STR_LAYOUT_SUBTITLE;
+ }
+ else if (aStyleName == SdResId(STR_PSEUDOSHEET_BACKGROUND))
+ {
+ aInternalName = STR_LAYOUT_BACKGROUND;
+ }
+ else if (aStyleName == SdResId(STR_PSEUDOSHEET_BACKGROUNDOBJECTS))
+ {
+ aInternalName = STR_LAYOUT_BACKGROUNDOBJECTS;
+ }
+ else if (aStyleName == SdResId(STR_PSEUDOSHEET_NOTES))
+ {
+ aInternalName = STR_LAYOUT_NOTES;
+ }
+ else
+ {
+ OUString aOutlineStr(SdResId(STR_PSEUDOSHEET_OUTLINE));
+ sal_Int32 nPos = aStyleName.indexOf(aOutlineStr);
+ if (nPos >= 0)
+ {
+ std::u16string_view aNumStr(aStyleName.subView(aOutlineStr.getLength()));
+ aInternalName = STR_LAYOUT_OUTLINE + aNumStr;
+ }
+ }
+
+ aRealStyle += aInternalName;
+ pRealStyle = static_cast< SdStyleSheet* >( m_pPool->Find(aRealStyle, SfxStyleFamily::Page) );
+
+#ifdef DBG_UTIL
+ if( !pRealStyle )
+ {
+ SfxStyleSheetIterator aIter(m_pPool, SfxStyleFamily::Page);
+ if( aIter.Count() > 0 )
+ // StyleSheet not found, but pool already loaded
+ DBG_ASSERT(pRealStyle, "Internal StyleSheet not found");
+ }
+#endif
+
+ return pRealStyle;
+}
+
+/**
+ * Determine pseudo style sheet which stands for this style sheet.
+ */
+SdStyleSheet* SdStyleSheet::GetPseudoStyleSheet() const
+{
+ SdStyleSheet* pPseudoStyle = nullptr;
+ OUString aSep( SD_LT_SEPARATOR );
+ OUString aStyleName(aName);
+ // without layout name and separator
+
+ if( aStyleName.indexOf(aSep) >=0 )
+ {
+ aStyleName = aStyleName.copy (aStyleName.indexOf(aSep) + aSep.getLength());
+ }
+
+ if (aStyleName == STR_LAYOUT_TITLE)
+ {
+ aStyleName = SdResId(STR_PSEUDOSHEET_TITLE);
+ }
+ else if (aStyleName == STR_LAYOUT_SUBTITLE)
+ {
+ aStyleName = SdResId(STR_PSEUDOSHEET_SUBTITLE);
+ }
+ else if (aStyleName == STR_LAYOUT_BACKGROUND)
+ {
+ aStyleName = SdResId(STR_PSEUDOSHEET_BACKGROUND);
+ }
+ else if (aStyleName == STR_LAYOUT_BACKGROUNDOBJECTS)
+ {
+ aStyleName = SdResId(STR_PSEUDOSHEET_BACKGROUNDOBJECTS);
+ }
+ else if (aStyleName == STR_LAYOUT_NOTES)
+ {
+ aStyleName = SdResId(STR_PSEUDOSHEET_NOTES);
+ }
+ else
+ {
+ OUString aOutlineStr(STR_LAYOUT_OUTLINE);
+ sal_Int32 nPos = aStyleName.indexOf(aOutlineStr);
+ if (nPos != -1)
+ {
+ std::u16string_view aNumStr(aStyleName.subView(aOutlineStr.getLength()));
+ aStyleName = SdResId(STR_PSEUDOSHEET_OUTLINE) + aNumStr;
+ }
+ }
+
+ pPseudoStyle = static_cast<SdStyleSheet*>(m_pPool->Find(aStyleName, SfxStyleFamily::Pseudo));
+ DBG_ASSERT(pPseudoStyle, "PseudoStyleSheet missing");
+
+ return pPseudoStyle;
+}
+
+void SdStyleSheet::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ // first, base class functionality
+ SfxStyleSheet::Notify(rBC, rHint);
+
+ if (nFamily != SfxStyleFamily::Pseudo)
+ return;
+
+ /* if the dummy gets a notify about a changed attribute, he takes care that
+ the actual meant style sheet sends broadcasts. */
+ if (rHint.GetId() == SfxHintId::DataChanged)
+ {
+ SdStyleSheet* pRealStyle = GetRealStyleSheet();
+ if (pRealStyle)
+ pRealStyle->Broadcast(rHint);
+ }
+}
+
+/**
+ * Adjust the bullet width and the left text indent of the provided ItemSets to
+ * their font height. The new values are calculated that the ratio to the font
+ * height is as in the style sheet.
+ *
+ * @param bOnlyMissingItems If sal_True, only not set items are completed. With
+ * sal_False, are items are overwritten.
+ */
+void SdStyleSheet::AdjustToFontHeight(SfxItemSet& rSet, bool bOnlyMissingItems)
+{
+ /* If not explicit set, adjust bullet width and text indent to new font
+ height. */
+ SfxStyleFamily eFamily = nFamily;
+ OUString aStyleName(aName);
+ if (eFamily == SfxStyleFamily::Pseudo)
+ {
+ SfxStyleSheet* pRealStyle = GetRealStyleSheet();
+ eFamily = pRealStyle->GetFamily();
+ aStyleName = pRealStyle->GetName();
+ }
+
+ if (!(eFamily == SfxStyleFamily::Page &&
+ aStyleName.indexOf(STR_LAYOUT_OUTLINE) != -1 &&
+ rSet.GetItemState(EE_CHAR_FONTHEIGHT) == SfxItemState::SET))
+ return;
+
+ const SfxItemSet* pCurSet = &GetItemSet();
+ sal_uInt32 nNewHeight = rSet.Get(EE_CHAR_FONTHEIGHT).GetHeight();
+ sal_uInt32 nOldHeight = pCurSet->Get(EE_CHAR_FONTHEIGHT).GetHeight();
+
+ if (rSet.GetItemState(EE_PARA_BULLET) != SfxItemState::SET || !bOnlyMissingItems)
+ {
+ const SvxBulletItem& rBItem = pCurSet->Get(EE_PARA_BULLET);
+ double fBulletFraction = double(rBItem.GetWidth()) / nOldHeight;
+ SvxBulletItem aNewBItem(rBItem);
+ aNewBItem.SetWidth(static_cast<sal_uInt32>(fBulletFraction * nNewHeight));
+ rSet.Put(aNewBItem);
+ }
+
+ if (rSet.GetItemState(EE_PARA_LRSPACE) != SfxItemState::SET || !bOnlyMissingItems)
+ {
+ const SvxLRSpaceItem& rLRItem = pCurSet->Get(EE_PARA_LRSPACE);
+ double fIndentFraction = double(rLRItem.GetTextLeft()) / nOldHeight;
+ SvxLRSpaceItem aNewLRItem(rLRItem);
+ aNewLRItem.SetTextLeft(fIndentFraction * nNewHeight);
+ double fFirstIndentFraction = double(rLRItem.GetTextFirstLineOffset()) / nOldHeight;
+ aNewLRItem.SetTextFirstLineOffset(static_cast<short>(fFirstIndentFraction * nNewHeight));
+ rSet.Put(aNewLRItem);
+ }
+
+ if (rSet.GetItemState(EE_PARA_ULSPACE) != SfxItemState::SET || !bOnlyMissingItems)
+ {
+ const SvxULSpaceItem& rULItem = pCurSet->Get(EE_PARA_ULSPACE);
+ SvxULSpaceItem aNewULItem(rULItem);
+ double fLowerFraction = double(rULItem.GetLower()) / nOldHeight;
+ aNewULItem.SetLower(static_cast<sal_uInt16>(fLowerFraction * nNewHeight));
+ double fUpperFraction = double(rULItem.GetUpper()) / nOldHeight;
+ aNewULItem.SetUpper(static_cast<sal_uInt16>(fUpperFraction * nNewHeight));
+ rSet.Put(aNewULItem);
+ }
+}
+
+bool SdStyleSheet::HasFollowSupport() const
+{
+ return false;
+}
+
+bool SdStyleSheet::HasParentSupport() const
+{
+ return true;
+}
+
+bool SdStyleSheet::HasClearParentSupport() const
+{
+ return true;
+}
+
+namespace
+{
+struct ApiNameMap
+{
+ std::u16string_view mpApiName;
+ sal_uInt32 mnHelpId;
+} const pApiNameMap[]
+ = { { std::u16string_view(u"title"), HID_PSEUDOSHEET_TITLE },
+ { std::u16string_view(u"subtitle"), HID_PSEUDOSHEET_SUBTITLE },
+ { std::u16string_view(u"background"), HID_PSEUDOSHEET_BACKGROUND },
+ { std::u16string_view(u"backgroundobjects"), HID_PSEUDOSHEET_BACKGROUNDOBJECTS },
+ { std::u16string_view(u"notes"), HID_PSEUDOSHEET_NOTES },
+ { std::u16string_view(u"standard"), HID_STANDARD_STYLESHEET_NAME },
+ { std::u16string_view(u"objectwithoutfill"), HID_POOLSHEET_OBJWITHOUTFILL },
+
+ { std::u16string_view(u"Text"), HID_POOLSHEET_TEXT },
+ { std::u16string_view(u"A4"), HID_POOLSHEET_A4 },
+ { std::u16string_view(u"Title A4"), HID_POOLSHEET_A4_TITLE },
+ { std::u16string_view(u"Heading A4"), HID_POOLSHEET_A4_HEADLINE },
+ { std::u16string_view(u"Text A4"), HID_POOLSHEET_A4_TEXT },
+ { std::u16string_view(u"A0"), HID_POOLSHEET_A0 },
+ { std::u16string_view(u"Title A0"), HID_POOLSHEET_A0_TITLE },
+ { std::u16string_view(u"Heading A0"), HID_POOLSHEET_A0_HEADLINE },
+ { std::u16string_view(u"Text A0"), HID_POOLSHEET_A0_TEXT },
+
+ { std::u16string_view(u"Graphic"), HID_POOLSHEET_GRAPHIC },
+ { std::u16string_view(u"Shapes"), HID_POOLSHEET_SHAPES },
+ { std::u16string_view(u"Filled"), HID_POOLSHEET_FILLED },
+ { std::u16string_view(u"Filled Blue"), HID_POOLSHEET_FILLED_BLUE },
+ { std::u16string_view(u"Filled Green"), HID_POOLSHEET_FILLED_GREEN },
+ { std::u16string_view(u"Filled Red"), HID_POOLSHEET_FILLED_RED },
+ { std::u16string_view(u"Filled Yellow"), HID_POOLSHEET_FILLED_YELLOW },
+ { std::u16string_view(u"Outlined"), HID_POOLSHEET_OUTLINE },
+ { std::u16string_view(u"Outlined Blue"), HID_POOLSHEET_OUTLINE_BLUE },
+ { std::u16string_view(u"Outlined Green"), HID_POOLSHEET_OUTLINE_GREEN },
+ { std::u16string_view(u"Outlined Red"), HID_POOLSHEET_OUTLINE_RED },
+ { std::u16string_view(u"Outlined Yellow"), HID_POOLSHEET_OUTLINE_YELLOW },
+ { std::u16string_view(u"Lines"), HID_POOLSHEET_LINES },
+ { std::u16string_view(u"Arrow Line"), HID_POOLSHEET_MEASURE },
+ { std::u16string_view(u"Arrow Dashed"), HID_POOLSHEET_LINES_DASHED }
+ };
+
+OUString GetApiNameForHelpId(sal_uLong nId)
+{
+ if ((nId >= HID_PSEUDOSHEET_OUTLINE1) && (nId <= HID_PSEUDOSHEET_OUTLINE9))
+ return "outline" + OUStringChar(sal_Unicode('1' + (nId - HID_PSEUDOSHEET_OUTLINE1)));
+
+ for (const auto& i : pApiNameMap)
+ if (nId == i.mnHelpId)
+ return OUString(i.mpApiName);
+
+ return OUString();
+}
+
+sal_uInt32 GetHelpIdForApiName(std::u16string_view sName)
+{
+ std::u16string_view sRest;
+ if (o3tl::starts_with(sName, u"outline", &sRest))
+ {
+ if (sRest.length() == 1)
+ {
+ sal_Unicode ch = sRest.front();
+ if ('1' <= ch && ch <= '9')
+ return HID_PSEUDOSHEET_OUTLINE1 + ch - '1';
+ }
+ // No other pre-defined names start with "outline"
+ return 0;
+ }
+
+ for (const auto& i : pApiNameMap)
+ if (sName == i.mpApiName)
+ return i.mnHelpId;
+
+ return 0;
+}
+}
+
+void SdStyleSheet::SetHelpId( const OUString& r, sal_uLong nId )
+{
+ SfxStyleSheet::SetHelpId( r, nId );
+
+ const OUString sNewApiName = GetApiNameForHelpId(nId);
+ if (!sNewApiName.isEmpty())
+ msApiName = sNewApiName;
+}
+
+OUString SdStyleSheet::GetFamilyString( SfxStyleFamily eFamily )
+{
+ switch( eFamily )
+ {
+ case SfxStyleFamily::Frame:
+ return "cell";
+ default:
+ OSL_FAIL( "SdStyleSheet::GetFamilyString(), illegal family!" );
+ [[fallthrough]];
+ case SfxStyleFamily::Para:
+ return "graphics";
+ }
+}
+
+void SdStyleSheet::throwIfDisposed()
+{
+ if( !mxPool.is() )
+ throw DisposedException();
+}
+
+rtl::Reference<SdStyleSheet> SdStyleSheet::CreateEmptyUserStyle( SfxStyleSheetBasePool& rPool, SfxStyleFamily eFamily )
+{
+ OUString aName;
+ sal_Int32 nIndex = 1;
+ do
+ {
+ aName = "user" + OUString::number( nIndex++ );
+ }
+ while( rPool.Find( aName, eFamily ) != nullptr );
+
+ return new SdStyleSheet(aName, rPool, eFamily, SfxStyleSearchBits::UserDefined);
+}
+
+// XInterface
+
+void SAL_CALL SdStyleSheet::release( ) noexcept
+{
+ if (osl_atomic_decrement( &m_refCount ) != 0)
+ return;
+
+ // restore reference count:
+ osl_atomic_increment( &m_refCount );
+ if (! mrBHelper.bDisposed) try
+ {
+ dispose();
+ }
+ catch (RuntimeException const&)
+ {
+ // don't break throw ()
+ TOOLS_WARN_EXCEPTION( "sd", "" );
+ }
+ OSL_ASSERT( mrBHelper.bDisposed );
+ SdStyleSheetBase::release();
+}
+
+// XComponent
+
+void SAL_CALL SdStyleSheet::dispose( )
+{
+ {
+ MutexGuard aGuard(mrBHelper.rMutex);
+ if (mrBHelper.bDisposed || mrBHelper.bInDispose)
+ return;
+
+ mrBHelper.bInDispose = true;
+ }
+ try
+ {
+ // side effect: keeping a reference to this
+ EventObject aEvt( static_cast< OWeakObject * >( this ) );
+ try
+ {
+ mrBHelper.aLC.disposeAndClear( aEvt );
+ disposing();
+ }
+ catch (...)
+ {
+ MutexGuard aGuard2( mrBHelper.rMutex );
+ // bDisposed and bInDispose must be set in this order:
+ mrBHelper.bDisposed = true;
+ mrBHelper.bInDispose = false;
+ throw;
+ }
+ MutexGuard aGuard2( mrBHelper.rMutex );
+ // bDisposed and bInDispose must be set in this order:
+ mrBHelper.bDisposed = true;
+ mrBHelper.bInDispose = false;
+ }
+ catch (RuntimeException &)
+ {
+ throw;
+ }
+ catch (const Exception & exc)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "unexpected UNO exception caught: " + exc.Message ,
+ nullptr, anyEx );
+ }
+}
+
+void SdStyleSheet::disposing()
+{
+ SolarMutexGuard aGuard;
+ if (bMySet)
+ {
+ delete pSet;
+ }
+ pSet = nullptr;
+ m_pPool = nullptr;
+ mxPool.clear();
+}
+
+void SAL_CALL SdStyleSheet::addEventListener( const Reference< XEventListener >& xListener )
+{
+ ClearableMutexGuard aGuard( mrBHelper.rMutex );
+ if (mrBHelper.bDisposed || mrBHelper.bInDispose)
+ {
+ aGuard.clear();
+ EventObject aEvt( static_cast< OWeakObject * >( this ) );
+ xListener->disposing( aEvt );
+ }
+ else
+ {
+ mrBHelper.addListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
+ }
+}
+
+void SAL_CALL SdStyleSheet::removeEventListener( const Reference< XEventListener >& xListener )
+{
+ mrBHelper.removeListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
+}
+
+// XModifyBroadcaster
+
+void SAL_CALL SdStyleSheet::addModifyListener( const Reference< XModifyListener >& xListener )
+{
+ ClearableMutexGuard aGuard( mrBHelper.rMutex );
+ if (mrBHelper.bDisposed || mrBHelper.bInDispose)
+ {
+ aGuard.clear();
+ EventObject aEvt( static_cast< OWeakObject * >( this ) );
+ xListener->disposing( aEvt );
+ }
+ else
+ {
+ if (!mpModifyListenerForwarder)
+ mpModifyListenerForwarder.reset( new ModifyListenerForwarder( this ) );
+ mrBHelper.addListener( cppu::UnoType<XModifyListener>::get(), xListener );
+ }
+}
+
+void SAL_CALL SdStyleSheet::removeModifyListener( const Reference< XModifyListener >& xListener )
+{
+ mrBHelper.removeListener( cppu::UnoType<XModifyListener>::get(), xListener );
+}
+
+void SdStyleSheet::notifyModifyListener()
+{
+ MutexGuard aGuard( mrBHelper.rMutex );
+
+ cppu::OInterfaceContainerHelper * pContainer = mrBHelper.getContainer( cppu::UnoType<XModifyListener>::get() );
+ if( pContainer )
+ {
+ EventObject aEvt( static_cast< OWeakObject * >( this ) );
+ pContainer->forEach<XModifyListener>(
+ [&] (Reference<XModifyListener> const& xListener) {
+ return xListener->modified(aEvt);
+ } );
+ }
+}
+
+// XServiceInfo
+OUString SAL_CALL SdStyleSheet::getImplementationName()
+{
+ return "SdStyleSheet";
+}
+
+sal_Bool SAL_CALL SdStyleSheet::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+Sequence< OUString > SAL_CALL SdStyleSheet::getSupportedServiceNames()
+{
+ return { "com.sun.star.style.Style",
+ "com.sun.star.drawing.FillProperties",
+ "com.sun.star.drawing.LineProperties",
+ "com.sun.star.drawing.ShadowProperties",
+ "com.sun.star.drawing.ConnectorProperties",
+ "com.sun.star.drawing.MeasureProperties",
+ "com.sun.star.style.ParagraphProperties",
+ "com.sun.star.style.CharacterProperties",
+ "com.sun.star.drawing.TextProperties",
+ "com.sun.star.drawing.Text" };
+}
+
+bool SdStyleSheet::SetName(const OUString& rNewName, bool bReindexNow)
+{
+ const bool bResult = SfxUnoStyleSheet::SetName(rNewName, bReindexNow);
+ // Don't overwrite predefined API names
+ if (bResult && GetHelpIdForApiName(msApiName) == 0)
+ {
+ msApiName = rNewName;
+ Broadcast(SfxHint(SfxHintId::DataChanged));
+ }
+ return bResult;
+}
+
+// XNamed
+OUString SAL_CALL SdStyleSheet::getName()
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+ return GetApiName();
+}
+
+void SAL_CALL SdStyleSheet::setName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+ SetName(rName);
+}
+
+// XStyle
+
+sal_Bool SAL_CALL SdStyleSheet::isUserDefined()
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+ return IsUserDefined();
+}
+
+sal_Bool SAL_CALL SdStyleSheet::isInUse()
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+ return IsUsed();
+}
+
+OUString SAL_CALL SdStyleSheet::getParentStyle()
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ if( !GetParent().isEmpty() )
+ {
+ SdStyleSheet* pParentStyle = static_cast< SdStyleSheet* >( mxPool->Find( GetParent(), nFamily ) );
+ if( pParentStyle )
+ return pParentStyle->GetApiName();
+ }
+ return OUString();
+}
+
+void SAL_CALL SdStyleSheet::setParentStyle( const OUString& rParentName )
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ if( !rParentName.isEmpty() )
+ {
+ OUString const name(GetName());
+ sal_Int32 const sep(name.indexOf(SD_LT_SEPARATOR));
+ OUString const master((sep == -1) ? OUString() : name.copy(0, sep));
+ std::shared_ptr<SfxStyleSheetIterator> aSSSI = std::make_shared<SfxStyleSheetIterator>(mxPool.get(), nFamily);
+ for (SfxStyleSheetBase *pStyle = aSSSI->First(); pStyle; pStyle = aSSSI->Next())
+ {
+ // we hope that we have only sd style sheets
+ SdStyleSheet* pSdStyleSheet = static_cast<SdStyleSheet*>(pStyle);
+ OUString const curName(pStyle->GetName());
+ sal_Int32 const curSep(curName.indexOf(SD_LT_SEPARATOR));
+ OUString const curMaster((curSep == -1)
+ ? OUString() : curName.copy(0, curSep));
+ // check that the master matches, as msApiName exists once per
+ // master page
+ if (pSdStyleSheet->msApiName == rParentName && master == curMaster)
+ {
+ if( pStyle != this )
+ {
+ SetParent(curName);
+ }
+ return;
+ }
+ }
+ throw NoSuchElementException();
+ }
+ else
+ {
+ SetParent( rParentName );
+ }
+}
+
+// XPropertySet/XMultiPropertySet utility functions
+
+// Does not broadcast
+// Must be guarded by solar mutex; must not be disposed
+void SdStyleSheet::setPropertyValue_Impl(const OUString& aPropertyName, const css::uno::Any& aValue)
+{
+ const SfxItemPropertyMapEntry* pEntry = getPropertyMapEntry( aPropertyName );
+ if( pEntry == nullptr )
+ {
+ throw UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ if( pEntry->nWID == WID_STYLE_HIDDEN )
+ {
+ bool bValue = false;
+ if ( aValue >>= bValue )
+ SetHidden( bValue );
+ return;
+ }
+ if( pEntry->nWID == SDRATTR_TEXTDIRECTION )
+ return; // not yet implemented for styles
+
+ if( pEntry->nWID == WID_STYLE_FAMILY )
+ throw PropertyVetoException();
+
+ if( (pEntry->nWID == EE_PARA_NUMBULLET) && (GetFamily() == SfxStyleFamily::Page) )
+ {
+ OUString aStr;
+ const sal_uInt32 nTempHelpId = GetHelpId( aStr );
+
+ if( (nTempHelpId >= HID_PSEUDOSHEET_OUTLINE2) && (nTempHelpId <= HID_PSEUDOSHEET_OUTLINE9) )
+ return;
+ }
+
+ SfxItemSet &rStyleSet = GetItemSet();
+
+ if( pEntry->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ BitmapMode eMode;
+ if( aValue >>= eMode )
+ {
+ rStyleSet.Put( XFillBmpStretchItem( eMode == BitmapMode_STRETCH ) );
+ rStyleSet.Put( XFillBmpTileItem( eMode == BitmapMode_REPEAT ) );
+ return;
+ }
+ throw IllegalArgumentException();
+ }
+
+ if (pEntry->nWID == OWN_ATTR_TEXTCOLUMNS)
+ {
+ if (css::uno::Reference<css::text::XTextColumns> xColumns; aValue >>= xColumns)
+ {
+ rStyleSet.Put(SfxInt16Item(SDRATTR_TEXTCOLUMNS_NUMBER, xColumns->getColumnCount()));
+ if (css::uno::Reference<css::beans::XPropertySet> xPropSet{ xColumns,
+ css::uno::UNO_QUERY })
+ {
+ auto aVal = xPropSet->getPropertyValue("AutomaticDistance");
+ if (sal_Int32 nSpacing; aVal >>= nSpacing)
+ rStyleSet.Put(SdrMetricItem(SDRATTR_TEXTCOLUMNS_SPACING, nSpacing));
+ }
+ return;
+ }
+ throw IllegalArgumentException();
+ }
+
+ SfxItemSet aSet( GetPool()->GetPool(), pEntry->nWID, pEntry->nWID);
+ aSet.Put( rStyleSet );
+
+ if( !aSet.Count() )
+ {
+ if( EE_PARA_NUMBULLET == pEntry->nWID )
+ {
+ vcl::Font aBulletFont;
+ SdStyleSheetPool::PutNumBulletItem( this, aBulletFont );
+ aSet.Put( rStyleSet );
+ }
+ else
+ {
+ aSet.Put( GetPool()->GetPool().GetDefaultItem( pEntry->nWID ) );
+ }
+ }
+
+ if( pEntry->nMemberId == MID_NAME &&
+ ( pEntry->nWID == XATTR_FILLBITMAP || pEntry->nWID == XATTR_FILLGRADIENT ||
+ pEntry->nWID == XATTR_FILLHATCH || pEntry->nWID == XATTR_FILLFLOATTRANSPARENCE ||
+ pEntry->nWID == XATTR_LINESTART || pEntry->nWID == XATTR_LINEEND || pEntry->nWID == XATTR_LINEDASH) )
+ {
+ OUString aTempName;
+ if(!(aValue >>= aTempName ))
+ throw IllegalArgumentException();
+
+ SvxShape::SetFillAttribute( pEntry->nWID, aTempName, aSet );
+ }
+ else if(!SvxUnoTextRangeBase::SetPropertyValueHelper( pEntry, aValue, aSet ))
+ {
+ SvxItemPropertySet_setPropertyValue( pEntry, aValue, aSet );
+ }
+
+ rStyleSet.Put( aSet );
+}
+
+// Must be guarded by solar mutex; must not be disposed
+css::uno::Any SdStyleSheet::getPropertyValue_Impl(const OUString& PropertyName)
+{
+ const SfxItemPropertyMapEntry* pEntry = getPropertyMapEntry( PropertyName );
+ if( pEntry == nullptr )
+ {
+ throw UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ Any aAny;
+
+ if( pEntry->nWID == WID_STYLE_FAMILY )
+ {
+ if( nFamily == SfxStyleFamily::Page )
+ {
+ const OUString aLayoutName( GetName() );
+ aAny <<= aLayoutName.copy( 0, aLayoutName.indexOf( SD_LT_SEPARATOR) );
+ }
+ else
+ {
+ aAny <<= GetFamilyString(nFamily);
+ }
+ }
+ else if( pEntry->nWID == WID_STYLE_DISPNAME )
+ {
+ OUString aDisplayName;
+ if ( nFamily == SfxStyleFamily::Page )
+ {
+ const SdStyleSheet* pStyleSheet = GetPseudoStyleSheet();
+ if (pStyleSheet != nullptr)
+ aDisplayName = pStyleSheet->GetName();
+ }
+
+ if (aDisplayName.isEmpty())
+ aDisplayName = GetName();
+
+ aAny <<= aDisplayName;
+ }
+ else if( pEntry->nWID == SDRATTR_TEXTDIRECTION )
+ {
+ aAny <<= false;
+ }
+ else if( pEntry->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ SfxItemSet &rStyleSet = GetItemSet();
+
+ const XFillBmpStretchItem* pStretchItem = rStyleSet.GetItem<XFillBmpStretchItem>(XATTR_FILLBMP_STRETCH);
+ const XFillBmpTileItem* pTileItem = rStyleSet.GetItem<XFillBmpTileItem>(XATTR_FILLBMP_TILE);
+
+ if( pStretchItem && pTileItem )
+ {
+ if( pTileItem->GetValue() )
+ aAny <<= BitmapMode_REPEAT;
+ else if( pStretchItem->GetValue() )
+ aAny <<= BitmapMode_STRETCH;
+ else
+ aAny <<= BitmapMode_NO_REPEAT;
+ }
+ }
+ else if( pEntry->nWID == WID_STYLE_HIDDEN )
+ {
+ aAny <<= IsHidden( );
+ }
+ else
+ {
+ SfxItemSet aSet( GetPool()->GetPool(), pEntry->nWID, pEntry->nWID);
+
+ const SfxPoolItem* pItem;
+ SfxItemSet& rStyleSet = GetItemSet();
+
+ if( rStyleSet.GetItemState( pEntry->nWID, true, &pItem ) == SfxItemState::SET )
+ aSet.Put( *pItem );
+
+ if( !aSet.Count() )
+ aSet.Put( GetPool()->GetPool().GetDefaultItem( pEntry->nWID ) );
+
+ if(SvxUnoTextRangeBase::GetPropertyValueHelper( aSet, pEntry, aAny ))
+ return aAny;
+
+ // Get value of ItemSet
+ aAny = SvxItemPropertySet_getPropertyValue( pEntry, aSet );
+ }
+
+ if( pEntry->aType != aAny.getValueType() )
+ {
+ // since the sfx uint16 item now exports a sal_Int32, we may have to fix this here
+ if( ( pEntry->aType == ::cppu::UnoType<sal_Int16>::get()) && aAny.getValueType() == ::cppu::UnoType<sal_Int32>::get() )
+ {
+ sal_Int32 nValue = 0;
+ aAny >>= nValue;
+ aAny <<= static_cast<sal_Int16>(nValue);
+ }
+ else
+ {
+ OSL_FAIL("SvxShape::GetAnyForItem() Returnvalue has wrong Type!" );
+ }
+ }
+
+ return aAny;
+}
+
+// XPropertySet
+
+Reference< XPropertySetInfo > SdStyleSheet::getPropertySetInfo()
+{
+ throwIfDisposed();
+ static Reference< XPropertySetInfo > xInfo = GetStylePropertySet().getPropertySetInfo();
+ return xInfo;
+}
+
+void SAL_CALL SdStyleSheet::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ setPropertyValue_Impl(aPropertyName, aValue);
+ Broadcast(SfxHint(SfxHintId::DataChanged));
+}
+
+Any SAL_CALL SdStyleSheet::getPropertyValue( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ return getPropertyValue_Impl(PropertyName);
+}
+
+void SAL_CALL SdStyleSheet::addPropertyChangeListener( const OUString& , const Reference< XPropertyChangeListener >& ) {}
+void SAL_CALL SdStyleSheet::removePropertyChangeListener( const OUString& , const Reference< XPropertyChangeListener >& ) {}
+void SAL_CALL SdStyleSheet::addVetoableChangeListener( const OUString& , const Reference< XVetoableChangeListener >& ) {}
+void SAL_CALL SdStyleSheet::removeVetoableChangeListener( const OUString& , const Reference< XVetoableChangeListener >& ) {}
+
+// XMultiPropertySet
+
+void SAL_CALL SdStyleSheet::setPropertyValues(const css::uno::Sequence<OUString>& aPropertyNames,
+ const css::uno::Sequence<css::uno::Any>& aValues)
+{
+ const sal_Int32 nCount = aPropertyNames.getLength();
+
+ if (nCount != aValues.getLength())
+ throw css::lang::IllegalArgumentException();
+
+ if (!nCount)
+ return;
+
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ try
+ {
+ setPropertyValue_Impl(aPropertyNames[i], aValues[i]);
+ }
+ catch (const css::beans::UnknownPropertyException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ }
+
+ Broadcast(SfxHint(SfxHintId::DataChanged));
+}
+
+css::uno::Sequence<css::uno::Any>
+SAL_CALL SdStyleSheet::getPropertyValues(const css::uno::Sequence<OUString>& aPropertyNames)
+{
+ SolarMutexGuard aGuard;
+ throwIfDisposed();
+
+ const sal_Int32 nCount = aPropertyNames.getLength();
+ css::uno::Sequence<css::uno::Any> aValues(nCount);
+ Any* pAny = aValues.getArray();
+
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ pAny[i] = getPropertyValue_Impl(aPropertyNames[i]);
+
+ return aValues;
+}
+
+void SAL_CALL SdStyleSheet::addPropertiesChangeListener(const css::uno::Sequence<OUString>&, const css::uno::Reference<css::beans::XPropertiesChangeListener>&) {}
+void SAL_CALL SdStyleSheet::removePropertiesChangeListener(const css::uno::Reference<css::beans::XPropertiesChangeListener>&) {}
+void SAL_CALL SdStyleSheet::firePropertiesChangeEvent(const css::uno::Sequence<OUString>&, const css::uno::Reference<css::beans::XPropertiesChangeListener>&) {}
+
+// XPropertyState
+
+PropertyState SAL_CALL SdStyleSheet::getPropertyState( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ const SfxItemPropertyMapEntry* pEntry = getPropertyMapEntry( PropertyName );
+
+ if( pEntry == nullptr )
+ throw UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+
+ if( pEntry->nWID == WID_STYLE_FAMILY )
+ {
+ return PropertyState_DIRECT_VALUE;
+ }
+ else if( pEntry->nWID == SDRATTR_TEXTDIRECTION )
+ {
+ return PropertyState_DEFAULT_VALUE;
+ }
+ else if( pEntry->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ const SfxItemSet& rSet = GetItemSet();
+
+ if( rSet.GetItemState( XATTR_FILLBMP_STRETCH, false ) == SfxItemState::SET ||
+ rSet.GetItemState( XATTR_FILLBMP_TILE, false ) == SfxItemState::SET )
+ {
+ return PropertyState_DIRECT_VALUE;
+ }
+ else
+ {
+ return PropertyState_AMBIGUOUS_VALUE;
+ }
+ }
+ else if (pEntry->nWID == OWN_ATTR_TEXTCOLUMNS)
+ {
+ const SfxItemSet& rSet = GetItemSet();
+
+ const auto eState1 = rSet.GetItemState(SDRATTR_TEXTCOLUMNS_NUMBER, false);
+ const auto eState2 = rSet.GetItemState(SDRATTR_TEXTCOLUMNS_SPACING, false);
+ if (eState1 == SfxItemState::SET || eState2 == SfxItemState::SET)
+ return PropertyState_DIRECT_VALUE;
+ else if (eState1 == SfxItemState::DEFAULT && eState2 == SfxItemState::DEFAULT)
+ return PropertyState_DEFAULT_VALUE;
+ else
+ return PropertyState_AMBIGUOUS_VALUE;
+ }
+ else
+ {
+ SfxItemSet &rStyleSet = GetItemSet();
+
+ PropertyState eState;
+
+ switch( rStyleSet.GetItemState( pEntry->nWID, false ) )
+ {
+ case SfxItemState::SET:
+ eState = PropertyState_DIRECT_VALUE;
+ break;
+ case SfxItemState::DEFAULT:
+ eState = PropertyState_DEFAULT_VALUE;
+ break;
+ default:
+ eState = PropertyState_AMBIGUOUS_VALUE;
+ break;
+ }
+
+ // if an item is set, this doesn't mean we want it :)
+ if( PropertyState_DIRECT_VALUE == eState )
+ {
+ switch( pEntry->nWID )
+ {
+ case XATTR_FILLBITMAP:
+ case XATTR_FILLGRADIENT:
+ case XATTR_FILLHATCH:
+ case XATTR_FILLFLOATTRANSPARENCE:
+ case XATTR_LINEEND:
+ case XATTR_LINESTART:
+ case XATTR_LINEDASH:
+ {
+ const NameOrIndex* pItem = rStyleSet.GetItem<NameOrIndex>(pEntry->nWID);
+ if( ( pItem == nullptr ) || pItem->GetName().isEmpty() )
+ eState = PropertyState_DEFAULT_VALUE;
+ }
+ break;
+ case XATTR_FILLCOLOR:
+ if (pEntry->nMemberId == MID_COLOR_THEME_INDEX)
+ {
+ const XFillColorItem* pColor = rStyleSet.GetItem<XFillColorItem>(pEntry->nWID);
+ if (pColor->GetThemeColor().GetThemeIndex() == -1)
+ {
+ eState = PropertyState_DEFAULT_VALUE;
+ }
+ }
+ else if (pEntry->nMemberId == MID_COLOR_LUM_MOD)
+ {
+ const XFillColorItem* pColor = rStyleSet.GetItem<XFillColorItem>(pEntry->nWID);
+ if (pColor->GetThemeColor().GetLumMod() == 10000)
+ {
+ eState = PropertyState_DEFAULT_VALUE;
+ }
+ }
+ else if (pEntry->nMemberId == MID_COLOR_LUM_OFF)
+ {
+ const XFillColorItem* pColor = rStyleSet.GetItem<XFillColorItem>(pEntry->nWID);
+ if (pColor->GetThemeColor().GetLumOff() == 0)
+ {
+ eState = PropertyState_DEFAULT_VALUE;
+ }
+ }
+ break;
+ }
+ }
+
+ return eState;
+ }
+}
+
+Sequence< PropertyState > SAL_CALL SdStyleSheet::getPropertyStates( const Sequence< OUString >& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ sal_Int32 nCount = aPropertyName.getLength();
+
+ Sequence< PropertyState > aPropertyStateSequence( nCount );
+
+ std::transform(aPropertyName.begin(), aPropertyName.end(), aPropertyStateSequence.getArray(),
+ [this](const OUString& rName) -> PropertyState { return getPropertyState(rName); });
+
+ return aPropertyStateSequence;
+}
+
+void SAL_CALL SdStyleSheet::setPropertyToDefault( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ const SfxItemPropertyMapEntry* pEntry = getPropertyMapEntry( PropertyName );
+ if( pEntry == nullptr )
+ throw UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+
+ SfxItemSet &rStyleSet = GetItemSet();
+
+ if( pEntry->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ rStyleSet.ClearItem( XATTR_FILLBMP_STRETCH );
+ rStyleSet.ClearItem( XATTR_FILLBMP_TILE );
+ }
+ else
+ {
+ rStyleSet.ClearItem( pEntry->nWID );
+ }
+ Broadcast(SfxHint(SfxHintId::DataChanged));
+}
+
+Any SAL_CALL SdStyleSheet::getPropertyDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ const SfxItemPropertyMapEntry* pEntry = getPropertyMapEntry( aPropertyName );
+ if( pEntry == nullptr )
+ throw UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+ Any aRet;
+ if( pEntry->nWID == WID_STYLE_FAMILY )
+ {
+ aRet <<= GetFamilyString(nFamily);
+ }
+ else if( pEntry->nWID == SDRATTR_TEXTDIRECTION )
+ {
+ aRet <<= false;
+ }
+ else if( pEntry->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ aRet <<= BitmapMode_REPEAT;
+ }
+ else
+ {
+ SfxItemPool& rMyPool = GetPool()->GetPool();
+ SfxItemSet aSet( rMyPool, pEntry->nWID, pEntry->nWID);
+ aSet.Put( rMyPool.GetDefaultItem( pEntry->nWID ) );
+ aRet = SvxItemPropertySet_getPropertyValue( pEntry, aSet );
+ }
+ return aRet;
+}
+
+/** this is used because our property map is not sorted yet */
+const SfxItemPropertyMapEntry* SdStyleSheet::getPropertyMapEntry( std::u16string_view rPropertyName )
+{
+ return GetStylePropertySet().getPropertyMapEntry(rPropertyName);
+}
+
+//Broadcast that a SdStyleSheet has changed, taking into account outline sublevels
+//which need to be explicitly broadcast as changing if their parent style was
+//the one that changed
+void SdStyleSheet::BroadcastSdStyleSheetChange(SfxStyleSheetBase const * pStyleSheet,
+ PresentationObjects ePO, SfxStyleSheetBasePool* pSSPool)
+{
+ SdStyleSheet* pRealSheet = static_cast<SdStyleSheet const *>(pStyleSheet)->GetRealStyleSheet();
+ pRealSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+
+ if( (ePO < PresentationObjects::Outline_1) || (ePO > PresentationObjects::Outline_8) )
+ return;
+
+ OUString sStyleName(SdResId(STR_PSEUDOSHEET_OUTLINE) + " ");
+
+ for( sal_uInt16 n = static_cast<sal_uInt16>(ePO) - static_cast<sal_uInt16>(PresentationObjects::Outline_1) + 2; n < 10; n++ )
+ {
+ OUString aName( sStyleName + OUString::number(n) );
+
+ SfxStyleSheetBase* pSheet = pSSPool->Find( aName, SfxStyleFamily::Pseudo);
+
+ if(pSheet)
+ {
+ SdStyleSheet* pRealStyleSheet = static_cast<SdStyleSheet*>(pSheet)->GetRealStyleSheet();
+ pRealStyleSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/text/textapi.cxx b/sd/source/core/text/textapi.cxx
new file mode 100644
index 000000000..2499588f8
--- /dev/null
+++ b/sd/source/core/text/textapi.cxx
@@ -0,0 +1,278 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/text/XTextField.hpp>
+
+#include <textapi.hxx>
+#include <drawdoc.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/unoforou.hxx>
+#include <editeng/unoprnms.hxx>
+#include <editeng/unoipset.hxx>
+#include <Outliner.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdundo.hxx>
+
+namespace com::sun::star::container { class XNameContainer; }
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+namespace sd {
+
+namespace {
+
+class UndoTextAPIChanged : public SdrUndoAction
+{
+public:
+ UndoTextAPIChanged( SdrModel& rModel, TextApiObject* pTextObj );
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+protected:
+ std::optional<OutlinerParaObject> mpOldText;
+ std::optional<OutlinerParaObject> mpNewText;
+ rtl::Reference< TextApiObject > mxTextObj;
+};
+
+}
+
+UndoTextAPIChanged::UndoTextAPIChanged(SdrModel& rModel, TextApiObject* pTextObj )
+: SdrUndoAction( rModel )
+, mpOldText( pTextObj->CreateText() )
+, mxTextObj( pTextObj )
+{
+}
+
+void UndoTextAPIChanged::Undo()
+{
+ if( !mpNewText )
+ mpNewText = mxTextObj->CreateText();
+
+ mxTextObj->SetText( *mpOldText );
+}
+
+void UndoTextAPIChanged::Redo()
+{
+ if( mpNewText )
+ {
+ mxTextObj->SetText( *mpNewText );
+ }
+}
+
+namespace {
+
+struct TextAPIEditSource_Impl
+{
+ SdDrawDocument* mpDoc;
+ Outliner* mpOutliner;
+ SvxOutlinerForwarder* mpTextForwarder;
+};
+
+}
+
+class TextAPIEditSource : public SvxEditSource
+{
+ // refcounted
+ std::shared_ptr<TextAPIEditSource_Impl> m_xImpl;
+
+ virtual std::unique_ptr<SvxEditSource> Clone() const override;
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual void UpdateData() override;
+ explicit TextAPIEditSource( const TextAPIEditSource& rSource );
+
+public:
+ explicit TextAPIEditSource(SdDrawDocument* pDoc);
+
+ void Dispose();
+ void SetText( OutlinerParaObject const & rText );
+ std::optional<OutlinerParaObject> CreateText();
+ OUString GetText() const;
+ SdDrawDocument* GetDoc() { return m_xImpl->mpDoc; }
+};
+
+static const SvxItemPropertySet* ImplGetSdTextPortionPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aSdTextPortionPropertyEntries[] =
+ {
+ SVX_UNOEDIT_CHAR_PROPERTIES,
+ SVX_UNOEDIT_FONT_PROPERTIES,
+ SVX_UNOEDIT_OUTLINER_PROPERTIES,
+ SVX_UNOEDIT_PARA_PROPERTIES,
+ {u"TextField", EE_FEATURE_FIELD, cppu::UnoType<XTextField>::get(), PropertyAttribute::READONLY, 0 },
+ {u"TextPortionType", WID_PORTIONTYPE, ::cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0 },
+ {u"TextUserDefinedAttributes", EE_CHAR_XMLATTRIBS, cppu::UnoType<XNameContainer>::get(), 0, 0},
+ {u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SvxItemPropertySet aSdTextPortionPropertyMap( aSdTextPortionPropertyEntries, SdrObject::GetGlobalDrawObjectItemPool() );
+
+ return &aSdTextPortionPropertyMap;
+}
+
+TextApiObject::TextApiObject( std::unique_ptr<TextAPIEditSource> pEditSource )
+: SvxUnoText( pEditSource.get(), ImplGetSdTextPortionPropertyMap(), Reference < XText >() )
+, mpSource(std::move(pEditSource))
+{
+}
+
+TextApiObject::~TextApiObject() noexcept
+{
+ dispose();
+}
+
+rtl::Reference< TextApiObject > TextApiObject::create( SdDrawDocument* pDoc )
+{
+ rtl::Reference< TextApiObject > xRet( new TextApiObject( std::make_unique<TextAPIEditSource>( pDoc ) ) );
+ return xRet;
+}
+
+void TextApiObject::dispose()
+{
+ if( mpSource )
+ {
+ mpSource->Dispose();
+ mpSource.reset();
+ }
+
+}
+
+std::optional<OutlinerParaObject> TextApiObject::CreateText()
+{
+ return mpSource->CreateText();
+}
+
+void TextApiObject::SetText( OutlinerParaObject const & rText )
+{
+ SdrModel* pModel = mpSource->GetDoc();
+ if( pModel && pModel->IsUndoEnabled() )
+ pModel->AddUndo( std::make_unique<UndoTextAPIChanged>( *pModel, this ) );
+
+ mpSource->SetText( rText );
+ maSelection.nStartPara = EE_PARA_MAX_COUNT;
+}
+
+OUString TextApiObject::GetText() const
+{
+ return mpSource->GetText();
+}
+
+TextApiObject* TextApiObject::getImplementation( const css::uno::Reference< css::text::XText >& xText )
+{
+ TextApiObject* pImpl = dynamic_cast< TextApiObject* >( xText.get() );
+
+ if( !pImpl )
+ pImpl = dynamic_cast< TextApiObject* >( comphelper::getFromUnoTunnel<SvxUnoTextBase>( xText ) );
+
+ return pImpl;
+}
+
+TextAPIEditSource::TextAPIEditSource(const TextAPIEditSource& rSource)
+ : SvxEditSource(*this)
+ , m_xImpl(rSource.m_xImpl) // shallow copy; uses internal refcounting
+{
+}
+
+std::unique_ptr<SvxEditSource> TextAPIEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new TextAPIEditSource( *this ));
+}
+
+void TextAPIEditSource::UpdateData()
+{
+ // data is kept in outliner all the time
+}
+
+TextAPIEditSource::TextAPIEditSource(SdDrawDocument* pDoc)
+: m_xImpl(std::make_shared<TextAPIEditSource_Impl>())
+{
+ m_xImpl->mpDoc = pDoc;
+ m_xImpl->mpOutliner = nullptr;
+ m_xImpl->mpTextForwarder = nullptr;
+}
+
+void TextAPIEditSource::Dispose()
+{
+ m_xImpl->mpDoc=nullptr;
+ delete m_xImpl->mpTextForwarder;
+ m_xImpl->mpTextForwarder = nullptr;
+
+ delete m_xImpl->mpOutliner;
+ m_xImpl->mpOutliner = nullptr;
+}
+
+SvxTextForwarder* TextAPIEditSource::GetTextForwarder()
+{
+ if(!m_xImpl->mpDoc)
+ return nullptr; // mpDoc == 0 can be used to flag this as disposed
+
+ if (!m_xImpl->mpOutliner)
+ {
+ //init draw model first
+ m_xImpl->mpOutliner = new SdOutliner(m_xImpl->mpDoc, OutlinerMode::TextObject);
+ SdDrawDocument::SetCalcFieldValueHdl(m_xImpl->mpOutliner);
+ }
+
+ if (!m_xImpl->mpTextForwarder)
+ m_xImpl->mpTextForwarder = new SvxOutlinerForwarder(*m_xImpl->mpOutliner, false);
+
+ return m_xImpl->mpTextForwarder;
+}
+
+void TextAPIEditSource::SetText( OutlinerParaObject const & rText )
+{
+ if (m_xImpl->mpDoc)
+ {
+ if (!m_xImpl->mpOutliner)
+ {
+ //init draw model first
+ m_xImpl->mpOutliner = new SdOutliner(m_xImpl->mpDoc, OutlinerMode::TextObject);
+ SdDrawDocument::SetCalcFieldValueHdl(m_xImpl->mpOutliner);
+ }
+
+ m_xImpl->mpOutliner->SetText( rText );
+ }
+}
+
+std::optional<OutlinerParaObject> TextAPIEditSource::CreateText()
+{
+ if (m_xImpl->mpDoc && m_xImpl->mpOutliner)
+ return m_xImpl->mpOutliner->CreateParaObject();
+ else
+ return std::nullopt;
+}
+
+OUString TextAPIEditSource::GetText() const
+{
+ if (m_xImpl->mpDoc && m_xImpl->mpOutliner)
+ return m_xImpl->mpOutliner->GetEditEngine().GetText();
+ else
+ return OUString();
+}
+
+} // namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/typemap.cxx b/sd/source/core/typemap.cxx
new file mode 100644
index 000000000..4378ad2d2
--- /dev/null
+++ b/sd/source/core/typemap.cxx
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_options.h>
+
+#include <editeng/cmapitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/tstpitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/protitem.hxx>
+#include <svx/chrtitem.hxx>
+#include <sfx2/msg.hxx>
+#include <svl/globalnameitem.hxx>
+#include <svx/hlnkitem.hxx>
+#include <svx/postattr.hxx>
+#include <svx/rulritem.hxx>
+#include <svx/clipfmtitem.hxx>
+#include <svl/srchitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/sdmetitm.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <editeng/memberids.h>
+#include <svx/unomid.hxx>
+#include <svx/xftstit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xtextit0.hxx>
+#include <svx/xftadit.hxx>
+#include <svx/xftdiit.hxx>
+#include <svx/xftmrit.hxx>
+#include <svx/xftouit.hxx>
+#include <svx/xftshit.hxx>
+#include <svx/xftshcit.hxx>
+#include <svx/xftshxy.hxx>
+#include <avmedia/mediaitem.hxx>
+#include <svx/drawitem.hxx>
+
+// #UndoRedo#
+#include <svl/slstitm.hxx>
+
+#include <svl/lckbitem.hxx>
+
+#define avmedia_MediaItem ::avmedia::MediaItem
+#include <sfx2/tplpitem.hxx>
+#include <svl/ptitem.hxx>
+#include <svl/rectitem.hxx>
+
+#include <sfx2/frame.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/galleryitem.hxx>
+#include <svx/sdangitm.hxx>
+
+#ifdef DISABLE_DYNLOADING
+/* Avoid clash with the ones from svx/source/form/typemap.cxx */
+#define aSfxBoolItem_Impl sd_source_core_typemap_aSfxBoolItem_Impl
+#define aSfxInt32Item_Impl sd_source_core_typemap_aSfxInt32Item_Impl
+#define aSfxStringItem_Impl sd_source_core_typemap_aSfxStringItem_Impl
+#define aSfxUInt16Item_Impl sd_source_core_typemap_aSfxUInt16Item_Impl
+#define aSfxUInt32Item_Impl sd_source_core_typemap_aSfxUInt32Item_Impl
+#define aSfxVoidItem_Impl sd_source_core_typemap_aSfxVoidItem_Impl
+#define aSvxClipboardFormatItem_Impl sd_source_core_typemap_aSvxClipboardFormatItem_Impl
+#define aSvxColorItem_Impl sd_source_core_typemap_aSvxColorItem_Impl
+#define aSvxContourItem_Impl sd_source_core_typemap_aSvxContourItem_Impl
+#define aSvxCrossedOutItem_Impl sd_source_core_typemap_aSvxCrossedOutItem_Impl
+#define aSvxFontHeightItem_Impl sd_source_core_typemap_aSvxFontHeightItem_Impl
+#define aSvxFontItem_Impl sd_source_core_typemap_aSvxFontItem_Impl
+#define aSvxLanguageItem_Impl sd_source_core_typemap_aSvxLanguageItem_Impl
+#define aSvxPostureItem_Impl sd_source_core_typemap_aSvxPostureItem_Impl
+#define aSvxShadowedItem_Impl sd_source_core_typemap_aSvxShadowedItem_Impl
+#define aSvxUnderlineItem_Impl sd_source_core_typemap_aSvxUnderlineItem_Impl
+#define aSvxOverlineItem_Impl sd_source_core_typemap_aSvxOverlineItem_Impl
+#define aSvxWeightItem_Impl sd_source_core_typemap_aSvxWeightItem_Impl
+#endif
+
+#define SFX_TYPEMAP
+#include <sdslots.hxx>
+
+#ifdef DISABLE_DYNLOADING
+#undef aSfxBoolItem_Impl
+#undef aSfxInt32Item_Impl
+#undef aSfxStringItem_Impl
+#undef aSfxUInt16Item_Impl
+#undef aSfxUInt32Item_Impl
+#undef aSfxVoidItem_Impl
+#undef aSvxClipboardFormatItem_Impl
+#undef aSvxColorItem_Impl
+#undef aSvxContourItem_Impl
+#undef aSvxCrossedOutItem_Impl
+#undef aSvxFontHeightItem_Impl
+#undef aSvxFontItem_Impl
+#undef aSvxLanguageItem_Impl
+#undef aSvxPostureItem_Impl
+#undef aSvxShadowedItem_Impl
+#undef aSvxTextLineItem_Impl
+#undef aSvxWeightItem_Impl
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/undo/undofactory.cxx b/sd/source/core/undo/undofactory.cxx
new file mode 100644
index 000000000..c87433b81
--- /dev/null
+++ b/sd/source/core/undo/undofactory.cxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <undo/undofactory.hxx>
+#include <undo/undoobjects.hxx>
+
+using namespace sd;
+
+std::unique_ptr<SdrUndoAction> UndoFactory::CreateUndoRemoveObject(SdrObject& rObject)
+{
+ return std::make_unique<UndoRemoveObject>(rObject);
+}
+
+std::unique_ptr<SdrUndoAction> UndoFactory::CreateUndoDeleteObject( SdrObject& rObject, bool bOrdNumDirect )
+{
+ return std::make_unique<UndoDeleteObject>( rObject, bOrdNumDirect );
+}
+
+std::unique_ptr<SdrUndoAction> UndoFactory::CreateUndoObjectSetText( SdrObject& rNewObj, sal_Int32 nText )
+{
+ return std::make_unique<UndoObjectSetText>( rNewObj, nText );
+}
+
+std::unique_ptr<SdrUndoAction> UndoFactory::CreateUndoReplaceObject( SdrObject& rOldObject, SdrObject& rNewObject )
+{
+ return std::make_unique<UndoReplaceObject>( rOldObject, rNewObject );
+}
+
+std::unique_ptr<SdrUndoAction> UndoFactory::CreateUndoGeoObject( SdrObject& rObject )
+{
+ return std::make_unique<UndoGeoObject>( rObject );
+}
+
+std::unique_ptr<SdrUndoAction> UndoFactory::CreateUndoAttrObject( SdrObject& rObject, bool bStyleSheet1, bool bSaveText )
+{
+ return std::make_unique<UndoAttrObject>( rObject, bStyleSheet1, bSaveText );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/undo/undomanager.cxx b/sd/source/core/undo/undomanager.cxx
new file mode 100644
index 000000000..672fe00e1
--- /dev/null
+++ b/sd/source/core/undo/undomanager.cxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <undo/undomanager.hxx>
+
+using namespace sd;
+
+UndoManager::UndoManager()
+ : mpLinkedUndoManager(nullptr)
+{
+}
+
+void UndoManager::EnterListAction(const OUString &rComment, const OUString& rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId)
+{
+ if( !IsDoing() )
+ {
+ ClearLinkedRedoActions();
+ SdrUndoManager::EnterListAction( rComment, rRepeatComment, nId, nViewShellId );
+ }
+}
+
+void UndoManager::AddUndoAction( std::unique_ptr<SfxUndoAction> pAction, bool bTryMerg /* = sal_False */ )
+{
+ if( !IsDoing() )
+ {
+ ClearLinkedRedoActions();
+ SdrUndoManager::AddUndoAction( std::move(pAction), bTryMerg );
+ }
+}
+
+void UndoManager::SetLinkedUndoManager (SfxUndoManager* pLinkedUndoManager)
+{
+ mpLinkedUndoManager = pLinkedUndoManager;
+}
+
+void UndoManager::ClearLinkedRedoActions()
+{
+ if (mpLinkedUndoManager != nullptr)
+ mpLinkedUndoManager->ClearRedo();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/undo/undoobjects.cxx b/sd/source/core/undo/undoobjects.cxx
new file mode 100644
index 000000000..f586dac21
--- /dev/null
+++ b/sd/source/core/undo/undoobjects.cxx
@@ -0,0 +1,392 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/debug.hxx>
+#include <undo/undoobjects.hxx>
+#include <sdpage.hxx>
+#include <CustomAnimationEffect.hxx>
+#include <drawdoc.hxx>
+#include <undoanim.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <DrawDocShell.hxx>
+
+using namespace sd;
+
+SdUndoAction::SdUndoAction(SdDrawDocument* pSdDrawDocument)
+ : mpDoc(pSdDrawDocument),
+ mnViewShellId(-1)
+{
+ sd::DrawDocShell* pDocShell = pSdDrawDocument ? pSdDrawDocument->GetDocSh() : nullptr;
+ sd::ViewShell* pViewShell = pDocShell ? pDocShell->GetViewShell() : nullptr;
+ if (pViewShell)
+ mnViewShellId = pViewShell->GetViewShellBase().GetViewShellId();
+}
+
+ViewShellId SdUndoAction::GetViewShellId() const
+{
+ return mnViewShellId;
+}
+
+UndoRemovePresObjectImpl::UndoRemovePresObjectImpl( SdrObject& rObject )
+{
+ SdPage* pPage = dynamic_cast< SdPage* >( rObject.getSdrPageFromSdrObject() );
+ if( !pPage )
+ return;
+
+ if( pPage->IsPresObj(&rObject) )
+ mpUndoPresObj.reset( new UndoObjectPresentationKind( rObject ) );
+ if( rObject.GetUserCall() )
+ mpUndoUsercall.reset( new UndoObjectUserCall(rObject) );
+
+ if( pPage->hasAnimationNode() )
+ {
+ css::uno::Reference< css::drawing::XShape > xShape( rObject.getUnoShape(), css::uno::UNO_QUERY );
+ if( pPage->getMainSequence()->hasEffect( xShape ) )
+ {
+ mpUndoAnimation.reset(
+ new UndoAnimation( // TTTT may use ref? Or just *SdrPage?
+ static_cast< SdDrawDocument* >(&pPage->getSdrModelFromSdrPage()),
+ pPage));
+ }
+ }
+}
+
+UndoRemovePresObjectImpl::~UndoRemovePresObjectImpl()
+{
+}
+
+void UndoRemovePresObjectImpl::Undo()
+{
+ if( mpUndoUsercall )
+ mpUndoUsercall->Undo();
+ if( mpUndoPresObj )
+ mpUndoPresObj->Undo();
+ if( mpUndoAnimation )
+ mpUndoAnimation->Undo();
+}
+
+void UndoRemovePresObjectImpl::Redo()
+{
+ if( mpUndoAnimation )
+ mpUndoAnimation->Redo();
+ if( mpUndoPresObj )
+ mpUndoPresObj->Redo();
+ if( mpUndoUsercall )
+ mpUndoUsercall->Redo();
+}
+
+UndoRemoveObject::UndoRemoveObject( SdrObject& rObject )
+: SdrUndoRemoveObj( rObject ), UndoRemovePresObjectImpl( rObject )
+, mxSdrObject(&rObject)
+{
+}
+
+void UndoRemoveObject::Undo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoRemoveObject::Undo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ SdrUndoRemoveObj::Undo();
+ UndoRemovePresObjectImpl::Undo();
+ }
+}
+
+void UndoRemoveObject::Redo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoRemoveObject::Redo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ UndoRemovePresObjectImpl::Redo();
+ SdrUndoRemoveObj::Redo();
+ }
+}
+
+UndoDeleteObject::UndoDeleteObject( SdrObject& rObject, bool bOrdNumDirect )
+: SdrUndoDelObj( rObject, bOrdNumDirect )
+, UndoRemovePresObjectImpl( rObject )
+, mxSdrObject(&rObject)
+{
+}
+
+void UndoDeleteObject::Undo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoDeleteObject::Undo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ SdrUndoDelObj::Undo();
+ UndoRemovePresObjectImpl::Undo();
+ }
+}
+
+void UndoDeleteObject::Redo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoDeleteObject::Redo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ UndoRemovePresObjectImpl::Redo();
+ SdrUndoDelObj::Redo();
+ }
+}
+
+UndoReplaceObject::UndoReplaceObject( SdrObject& rOldObject, SdrObject& rNewObject )
+: SdrUndoReplaceObj( rOldObject, rNewObject )
+, UndoRemovePresObjectImpl( rOldObject )
+, mxSdrObject( &rOldObject )
+{
+}
+
+void UndoReplaceObject::Undo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoReplaceObject::Undo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ SdrUndoReplaceObj::Undo();
+ UndoRemovePresObjectImpl::Undo();
+ }
+}
+
+void UndoReplaceObject::Redo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoReplaceObject::Redo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ UndoRemovePresObjectImpl::Redo();
+ SdrUndoReplaceObj::Redo();
+ }
+}
+
+UndoObjectSetText::UndoObjectSetText( SdrObject& rObject, sal_Int32 nText )
+: SdrUndoObjSetText( rObject, nText )
+, mbNewEmptyPresObj(false)
+, mxSdrObject( &rObject )
+{
+ SdPage* pPage = dynamic_cast< SdPage* >( rObject.getSdrPageFromSdrObject() );
+ if( pPage && pPage->hasAnimationNode() )
+ {
+ css::uno::Reference< css::drawing::XShape > xShape( rObject.getUnoShape(), css::uno::UNO_QUERY );
+ if( pPage->getMainSequence()->hasEffect( xShape ) )
+ {
+ mpUndoAnimation.reset(
+ new UndoAnimation(
+ static_cast< SdDrawDocument* >(&pPage->getSdrModelFromSdrPage()),
+ pPage));
+ }
+ }
+}
+
+UndoObjectSetText::~UndoObjectSetText()
+{
+}
+
+void UndoObjectSetText::Undo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoObjectSetText::Undo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ mbNewEmptyPresObj = mxSdrObject->IsEmptyPresObj();
+ SdrUndoObjSetText::Undo();
+ if( mpUndoAnimation )
+ mpUndoAnimation->Undo();
+ }
+}
+
+void UndoObjectSetText::Redo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoObjectSetText::Redo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ if( mpUndoAnimation )
+ mpUndoAnimation->Redo();
+ SdrUndoObjSetText::Redo();
+ mxSdrObject->SetEmptyPresObj(mbNewEmptyPresObj);
+ }
+}
+
+// Undo for SdrObject::SetUserCall()
+
+UndoObjectUserCall::UndoObjectUserCall(SdrObject& rObject)
+: SdrUndoObj(rObject)
+, mpOldUserCall(static_cast<SdPage*>(rObject.GetUserCall()))
+, mpNewUserCall(nullptr)
+, mxSdrObject( &rObject )
+{
+}
+
+void UndoObjectUserCall::Undo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoObjectUserCall::Undo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ mpNewUserCall = mxSdrObject->GetUserCall();
+ mxSdrObject->SetUserCall(mpOldUserCall);
+ }
+}
+
+void UndoObjectUserCall::Redo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoObjectUserCall::Redo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ mxSdrObject->SetUserCall(mpNewUserCall);
+ }
+}
+
+// Undo for SdPage::InsertPresObj() and SdPage::RemovePresObj()
+
+UndoObjectPresentationKind::UndoObjectPresentationKind(SdrObject& rObject)
+: SdrUndoObj(rObject)
+, meOldKind(PresObjKind::NONE)
+, meNewKind(PresObjKind::NONE)
+, mxPage( static_cast<SdPage*>(rObject.getSdrPageFromSdrObject()) )
+, mxSdrObject( &rObject )
+{
+ DBG_ASSERT( mxPage.get(), "sd::UndoObjectPresentationKind::UndoObjectPresentationKind(), does not work for shapes without a slide!" );
+
+ if( auto pPage = mxPage.get() )
+ meOldKind = pPage->GetPresObjKind( &rObject );
+}
+
+void UndoObjectPresentationKind::Undo()
+{
+ if( !mxSdrObject.is() )
+ return;
+ if( rtl::Reference<SdPage> pPage = mxPage.get() )
+ {
+ meNewKind = pPage->GetPresObjKind( mxSdrObject.get() );
+ if( meNewKind != PresObjKind::NONE )
+ pPage->RemovePresObj( mxSdrObject.get() );
+ if( meOldKind != PresObjKind::NONE )
+ pPage->InsertPresObj( mxSdrObject.get(), meOldKind );
+ }
+}
+
+void UndoObjectPresentationKind::Redo()
+{
+ if( !mxSdrObject.is() )
+ return;
+ if( rtl::Reference<SdPage> pPage = mxPage.get() )
+ {
+ if( meOldKind != PresObjKind::NONE )
+ pPage->RemovePresObj( mxSdrObject.get() );
+ if( meNewKind != PresObjKind::NONE )
+ pPage->InsertPresObj( mxSdrObject.get(), meNewKind );
+ }
+}
+
+UndoAutoLayoutPosAndSize::UndoAutoLayoutPosAndSize( SdPage& rPage )
+: mxPage( &rPage )
+{
+}
+
+void UndoAutoLayoutPosAndSize::Undo()
+{
+ // do nothing
+}
+
+void UndoAutoLayoutPosAndSize::Redo()
+{
+ rtl::Reference<SdPage> pPage = mxPage.get();
+ if( pPage )
+ pPage->SetAutoLayout( pPage->GetAutoLayout() );
+}
+
+UndoGeoObject::UndoGeoObject( SdrObject& rNewObj )
+: SdrUndoGeoObj( rNewObj )
+, mxPage( static_cast<SdPage*>(rNewObj.getSdrPageFromSdrObject()) )
+, mxSdrObject( &rNewObj )
+{
+}
+
+void UndoGeoObject::Undo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoGeoObject::Undo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ if( auto pPage = mxPage.get() )
+ {
+ ScopeLockGuard aGuard( pPage->maLockAutoLayoutArrangement );
+ SdrUndoGeoObj::Undo();
+ }
+ else
+ {
+ SdrUndoGeoObj::Undo();
+ }
+ }
+}
+
+void UndoGeoObject::Redo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoGeoObject::Redo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ if( auto pPage = mxPage.get() )
+ {
+ ScopeLockGuard aGuard( pPage->maLockAutoLayoutArrangement );
+ SdrUndoGeoObj::Redo();
+ }
+ else
+ {
+ SdrUndoGeoObj::Redo();
+ }
+ }
+}
+
+UndoAttrObject::UndoAttrObject( SdrObject& rObject, bool bStyleSheet1, bool bSaveText )
+: SdrUndoAttrObj( rObject, bStyleSheet1, bSaveText )
+, mxPage( static_cast<SdPage*>(rObject.getSdrPageFromSdrObject()) )
+, mxSdrObject( &rObject )
+{
+}
+
+void UndoAttrObject::Undo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoAttrObject::Undo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ if( auto pPage = mxPage.get() )
+ {
+ ScopeLockGuard aGuard( pPage->maLockAutoLayoutArrangement );
+ SdrUndoAttrObj::Undo();
+ }
+ else
+ {
+ SdrUndoAttrObj::Undo();
+ }
+ }
+}
+
+void UndoAttrObject::Redo()
+{
+ DBG_ASSERT( mxSdrObject.is(), "sd::UndoAttrObject::Redo(), object already dead!" );
+ if( mxSdrObject.is() )
+ {
+ if( auto pPage = mxPage.get() )
+ {
+ ScopeLockGuard aGuard( pPage->maLockAutoLayoutArrangement );
+ SdrUndoAttrObj::Redo();
+ }
+ else
+ {
+ SdrUndoAttrObj::Redo();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/undoanim.cxx b/sd/source/core/undoanim.cxx
new file mode 100644
index 000000000..64b233322
--- /dev/null
+++ b/sd/source/core/undoanim.cxx
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <CustomAnimationCloner.hxx>
+
+#include <undoanim.hxx>
+#include <strings.hrc>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <CustomAnimationEffect.hxx>
+#include <drawdoc.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace com::sun::star::animations { class XAnimationNode; }
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using namespace ::com::sun::star::animations;
+
+namespace sd
+{
+
+struct UndoAnimationImpl
+{
+ SdPage* mpPage;
+ Reference< XAnimationNode > mxOldNode;
+ Reference< XAnimationNode > mxNewNode;
+ bool mbNewNodeSet;
+};
+
+UndoAnimation::UndoAnimation( SdDrawDocument* pDoc, SdPage* pThePage )
+: SdrUndoAction( *pDoc ), mpImpl( new UndoAnimationImpl )
+{
+ mpImpl->mpPage = pThePage;
+ mpImpl->mbNewNodeSet = false;
+
+ try
+ {
+ if( pThePage->mxAnimationNode.is() )
+ mpImpl->mxOldNode = ::sd::Clone( pThePage->getAnimationNode() );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::UndoAnimation::UndoAnimation()");
+ }
+}
+
+UndoAnimation::~UndoAnimation()
+{
+}
+
+void UndoAnimation::Undo()
+{
+ try
+ {
+ if( !mpImpl->mbNewNodeSet )
+ {
+ if( mpImpl->mpPage->mxAnimationNode.is() )
+ mpImpl->mxNewNode.set( ::sd::Clone( mpImpl->mpPage->mxAnimationNode ) );
+ mpImpl->mbNewNodeSet = true;
+ }
+
+ Reference< XAnimationNode > xOldNode;
+ if( mpImpl->mxOldNode.is() )
+ xOldNode = ::sd::Clone( mpImpl->mxOldNode );
+
+ mpImpl->mpPage->setAnimationNode( xOldNode );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::UndoAnimation::Undo()");
+ }
+}
+
+void UndoAnimation::Redo()
+{
+ try
+ {
+ Reference< XAnimationNode > xNewNode;
+ if( mpImpl->mxNewNode.is() )
+ xNewNode = ::sd::Clone( mpImpl->mxNewNode );
+ mpImpl->mpPage->setAnimationNode( xNewNode );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::UndoAnimation::Redo()");
+ }
+}
+
+OUString UndoAnimation::GetComment() const
+{
+ return SdResId(STR_UNDO_ANIMATION);
+}
+
+struct UndoAnimationPathImpl
+{
+ SdPage* mpPage;
+ sal_Int32 mnEffectOffset;
+ OUString msUndoPath;
+ OUString msRedoPath;
+
+ UndoAnimationPathImpl( SdPage* pThePage, const css::uno::Reference< css::animations::XAnimationNode >& xNode )
+ : mpPage( pThePage )
+ , mnEffectOffset( -1 )
+ {
+ if( !(mpPage && xNode.is()) )
+ return;
+
+ std::shared_ptr< sd::MainSequence > pMainSequence( mpPage->getMainSequence() );
+ if( pMainSequence )
+ {
+ CustomAnimationEffectPtr pEffect( pMainSequence->findEffect( xNode ) );
+ if( pEffect )
+ {
+ mnEffectOffset = pMainSequence->getOffsetFromEffect( pEffect );
+ msUndoPath = pEffect->getPath();
+ }
+ }
+ }
+ UndoAnimationPathImpl(const UndoAnimationPathImpl&) = delete;
+ UndoAnimationPathImpl& operator=(const UndoAnimationPathImpl&) = delete;
+
+ CustomAnimationEffectPtr getEffect() const
+ {
+ CustomAnimationEffectPtr pEffect;
+ if( mpPage && (mnEffectOffset >= 0) )
+ {
+ std::shared_ptr< sd::MainSequence > pMainSequence( mpPage->getMainSequence() );
+ if( pMainSequence )
+ pEffect = pMainSequence->getEffectFromOffset( mnEffectOffset );
+ }
+ return pEffect;
+ }
+};
+
+UndoAnimationPath::UndoAnimationPath( SdDrawDocument* pDoc, SdPage* pThePage, const css::uno::Reference< css::animations::XAnimationNode >& xNode )
+: SdrUndoAction( *pDoc )
+, mpImpl( new UndoAnimationPathImpl( pThePage, xNode ) )
+{
+}
+
+UndoAnimationPath::~UndoAnimationPath()
+{
+}
+
+void UndoAnimationPath::Undo()
+{
+ CustomAnimationEffectPtr pEffect = mpImpl->getEffect();
+ if( pEffect )
+ {
+ mpImpl->msRedoPath = pEffect->getPath();
+ pEffect->setPath( mpImpl->msUndoPath );
+ }
+}
+
+void UndoAnimationPath::Redo()
+{
+ CustomAnimationEffectPtr pEffect = mpImpl->getEffect();
+ if( pEffect )
+ {
+ pEffect->setPath( mpImpl->msRedoPath );
+ }
+}
+
+OUString UndoAnimationPath::GetComment() const
+{
+ return SdResId(STR_UNDO_ANIMATION);
+}
+
+struct UndoTransitionImpl
+{
+ SdPage* mpPage;
+
+ sal_Int16 mnNewTransitionType;
+ sal_Int16 mnNewTransitionSubtype;
+ bool mbNewTransitionDirection;
+ sal_Int32 mnNewTransitionFadeColor;
+ double mfNewTransitionDuration;
+ OUString maNewSoundFile;
+ bool mbNewSoundOn;
+ bool mbNewLoopSound;
+ bool mbNewStopSound;
+
+ sal_Int16 mnOldTransitionType;
+ sal_Int16 mnOldTransitionSubtype;
+ bool mbOldTransitionDirection;
+ sal_Int32 mnOldTransitionFadeColor;
+ double mfOldTransitionDuration;
+ OUString maOldSoundFile;
+ bool mbOldSoundOn;
+ bool mbOldLoopSound;
+ bool mbOldStopSound;
+};
+
+UndoTransition::UndoTransition( SdDrawDocument* _pDoc, SdPage* pThePage )
+: SdUndoAction( _pDoc ), mpImpl( new UndoTransitionImpl )
+{
+ mpImpl->mpPage = pThePage;
+
+ mpImpl->mnNewTransitionType = -1;
+ mpImpl->mnOldTransitionType = pThePage->mnTransitionType;
+ mpImpl->mnOldTransitionSubtype = pThePage->mnTransitionSubtype;
+ mpImpl->mbOldTransitionDirection = pThePage->mbTransitionDirection;
+ mpImpl->mnOldTransitionFadeColor = pThePage->mnTransitionFadeColor;
+ mpImpl->mfOldTransitionDuration = pThePage->mfTransitionDuration;
+ mpImpl->maOldSoundFile = pThePage->maSoundFile;
+ mpImpl->mbOldSoundOn = pThePage->mbSoundOn;
+ mpImpl->mbOldLoopSound = pThePage->mbLoopSound;
+ mpImpl->mbOldStopSound = pThePage->mbStopSound;
+}
+
+UndoTransition::~UndoTransition()
+{
+}
+
+void UndoTransition::Undo()
+{
+ if( mpImpl->mnNewTransitionType == -1 )
+ {
+ mpImpl->mnNewTransitionType = mpImpl->mpPage->mnTransitionType;
+ mpImpl->mnNewTransitionSubtype = mpImpl->mpPage->mnTransitionSubtype;
+ mpImpl->mbNewTransitionDirection = mpImpl->mpPage->mbTransitionDirection;
+ mpImpl->mnNewTransitionFadeColor = mpImpl->mpPage->mnTransitionFadeColor;
+ mpImpl->mfNewTransitionDuration = mpImpl->mpPage->mfTransitionDuration;
+ mpImpl->maNewSoundFile = mpImpl->mpPage->maSoundFile;
+ mpImpl->mbNewSoundOn = mpImpl->mpPage->mbSoundOn;
+ mpImpl->mbNewLoopSound = mpImpl->mpPage->mbLoopSound;
+ mpImpl->mbNewStopSound = mpImpl->mpPage->mbStopSound;
+ }
+
+ mpImpl->mpPage->mnTransitionType = mpImpl->mnOldTransitionType;
+ mpImpl->mpPage->mnTransitionSubtype = mpImpl->mnOldTransitionSubtype;
+ mpImpl->mpPage->mbTransitionDirection = mpImpl->mbOldTransitionDirection;
+ mpImpl->mpPage->mnTransitionFadeColor = mpImpl->mnOldTransitionFadeColor;
+ mpImpl->mpPage->mfTransitionDuration = mpImpl->mfOldTransitionDuration;
+ mpImpl->mpPage->maSoundFile = mpImpl->maOldSoundFile;
+ mpImpl->mpPage->mbSoundOn = mpImpl->mbOldSoundOn;
+ mpImpl->mpPage->mbLoopSound = mpImpl->mbOldLoopSound;
+ mpImpl->mpPage->mbStopSound = mpImpl->mbOldStopSound;
+}
+
+void UndoTransition::Redo()
+{
+ mpImpl->mpPage->mnTransitionType = mpImpl->mnNewTransitionType;
+ mpImpl->mpPage->mnTransitionSubtype = mpImpl->mnNewTransitionSubtype;
+ mpImpl->mpPage->mbTransitionDirection = mpImpl->mbNewTransitionDirection;
+ mpImpl->mpPage->mnTransitionFadeColor = mpImpl->mnNewTransitionFadeColor;
+ mpImpl->mpPage->mfTransitionDuration = mpImpl->mfNewTransitionDuration;
+ mpImpl->mpPage->maSoundFile = mpImpl->maNewSoundFile;
+ mpImpl->mpPage->mbSoundOn = mpImpl->mbNewSoundOn;
+ mpImpl->mpPage->mbLoopSound = mpImpl->mbNewLoopSound;
+ mpImpl->mpPage->mbStopSound = mpImpl->mbNewStopSound;
+}
+
+OUString UndoTransition::GetComment() const
+{
+ return SdResId(STR_UNDO_SLIDE_PARAMS);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/cgm/sdcgmfilter.cxx b/sd/source/filter/cgm/sdcgmfilter.cxx
new file mode 100644
index 000000000..80b11519d
--- /dev/null
+++ b/sd/source/filter/cgm/sdcgmfilter.cxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <tools/urlobj.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <sfx2/docfile.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfillit0.hxx>
+
+#include <sddll.hxx>
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <sdcgmfilter.hxx>
+
+#include <DrawDocShell.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::frame;
+
+typedef sal_uInt32 ( *ImportCGMPointer )(SvStream&, Reference< XModel > const &, Reference< XStatusIndicator > const &);
+
+#ifdef DISABLE_DYNLOADING
+
+extern "C" sal_uInt32 ImportCGM(SvStream&, Reference< XModel > const &, Reference< XStatusIndicator > const &);
+
+#endif
+
+SdCGMFilter::SdCGMFilter( SfxMedium& rMedium, ::sd::DrawDocShell& rDocShell ) :
+ SdFilter( rMedium, rDocShell )
+{
+}
+
+SdCGMFilter::~SdCGMFilter()
+{
+}
+
+namespace
+{
+ class CGMPointer
+ {
+ ImportCGMPointer m_pPointer;
+ public:
+ CGMPointer()
+ {
+#ifdef DISABLE_DYNLOADING
+ m_pPointer = ImportCGM;
+#else
+ m_pPointer = reinterpret_cast<ImportCGMPointer>(
+ SdFilter::GetLibrarySymbol("icg", "ImportCGM"));
+#endif
+ }
+ ImportCGMPointer get() { return m_pPointer; }
+ };
+}
+
+bool SdCGMFilter::Import()
+{
+ bool bRet = false;
+
+ CGMPointer aPointer;
+ ImportCGMPointer FncImportCGM = aPointer.get();
+ if (FncImportCGM && mxModel.is())
+ {
+ OUString aFileURL( mrMedium.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ sal_uInt32 nRetValue;
+
+ if( mrDocument.GetPageCount() == 0 )
+ mrDocument.CreateFirstPages();
+
+ CreateStatusIndicator();
+ std::unique_ptr<SvStream> xIn(::utl::UcbStreamHelper::CreateStream(aFileURL, StreamMode::READ));
+ nRetValue = xIn ? FncImportCGM(*xIn, mxModel, mxStatusIndicator) : 0;
+
+ if( nRetValue )
+ {
+ bRet = true;
+
+ if( ( nRetValue &~0xff000000 ) != 0xffffff ) // maybe the backgroundcolor is already white
+ { // so we must not set a master page
+ mrDocument.StopWorkStartupDelay();
+ SdPage* pSdPage = mrDocument.GetMasterSdPage(0, PageKind::Standard);
+
+ if(pSdPage)
+ {
+ // set PageFill to given color
+ const Color aColor(static_cast<sal_uInt8>(nRetValue >> 16), static_cast<sal_uInt8>(nRetValue >> 8), static_cast<sal_uInt8>(nRetValue >> 16));
+ pSdPage->getSdrPageProperties().PutItem(XFillColorItem(OUString(), aColor));
+ pSdPage->getSdrPageProperties().PutItem(XFillStyleItem(drawing::FillStyle_SOLID));
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+bool SdCGMFilter::Export()
+{
+ // No ExportCGM function exists(!)
+ return false;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportCGM(SvStream &rStream)
+{
+ SdDLL::Init();
+
+ ::sd::DrawDocShellRef xDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress);
+
+ CGMPointer aPointer;
+
+ xDocShRef->GetDoc()->EnableUndo(false);
+ bool bRet = aPointer.get()(rStream, xDocShRef->GetModel(), css::uno::Reference<css::task::XStatusIndicator>()) == 0;
+
+ xDocShRef->DoClose();
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/eppt.cxx b/sd/source/filter/eppt/eppt.cxx
new file mode 100644
index 000000000..6f58d919e
--- /dev/null
+++ b/sd/source/filter/eppt/eppt.cxx
@@ -0,0 +1,1464 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "eppt.hxx"
+#include "epptdef.hxx"
+#include "pptexanimations.hxx"
+#include <o3tl/any.hxx>
+#include <tools/globname.hxx>
+#include <rtl/ustring.hxx>
+#include <tools/stream.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/office/XAnnotation.hpp>
+#include <com/sun/star/office/XAnnotationAccess.hpp>
+#include <com/sun/star/office/XAnnotationEnumeration.hpp>
+#include <com/sun/star/presentation/AnimationSpeed.hpp>
+#include <com/sun/star/presentation/XPresentationSupplier.hpp>
+#include <com/sun/star/presentation/XCustomPresentationSupplier.hpp>
+#include <com/sun/star/geometry/RealPoint2D.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <comphelper/sequence.hxx>
+#include <tools/zcodec.hxx>
+#include <filter/msfilter/classids.hxx>
+#include <filter/msfilter/msoleexp.hxx>
+#include <filter/msfilter/msdffimp.hxx>
+#include <filter/msfilter/svxmsbas.hxx>
+#include <editeng/flditem.hxx>
+#include <sfx2/docinf.hxx>
+#include <oox/export/utils.hxx>
+#include <oox/ole/olehelper.hxx>
+#include <memory>
+
+class SfxObjectShell;
+ // complete SfxObjectShell for SaveVBA under -fsanitize=function
+
+using namespace com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::presentation;
+
+using ::com::sun::star::beans::XPropertySet;
+
+//============================ PPTWriter ==================================
+
+PPTWriter::PPTWriter( tools::SvRef<SotStorage> const & rSvStorage,
+ css::uno::Reference< css::frame::XModel > const & rXModel,
+ css::uno::Reference< css::task::XStatusIndicator > const & rXStatInd,
+ SvMemoryStream* pVBA, sal_uInt32 nCnvrtFlags ) :
+ PPTWriterBase ( rXModel, rXStatInd ),
+ mnCnvrtFlags ( nCnvrtFlags ),
+ mbStatus ( false ),
+ mnStatMaxValue ( 0 ),
+ mnLatestStatValue ( 0 ),
+ mnTextStyle( 0 ),
+ mbFontIndependentLineSpacing( false ),
+ mnTextSize( 0 ),
+ mrStg ( rSvStorage ),
+ mnVBAOleOfs ( 0 ),
+ mpVBA ( pVBA ),
+ mnExEmbed ( 0 ),
+ mpExEmbed ( new SvMemoryStream ),
+ mnPagesWritten ( 0 ),
+ mnTxId ( 0x7a2f64 ),
+ mnDiaMode ( 0 ),
+ mnShapeMasterTitle ( 0 ),
+ mnShapeMasterBody ( 0 )
+{
+}
+
+void PPTWriter::exportPPTPre( const std::vector< css::beans::PropertyValue >& rMediaData )
+{
+ if ( !mrStg.is() )
+ return;
+
+ if ( mXStatusIndicator.is() )
+ {
+ mbStatusIndicator = true;
+ mnStatMaxValue = ( mnPages + mnMasterPages ) * 5;
+ mXStatusIndicator->start( "PowerPoint Export", mnStatMaxValue + ( mnStatMaxValue >> 3 ) );
+ }
+
+ SvGlobalName aGName(MSO_PPT8_CLASSID);
+ mrStg->SetClass( aGName, SotClipboardFormatId::NONE, "MS PowerPoint 97" );
+
+ if ( !ImplCreateCurrentUserStream() )
+ return;
+
+ mpStrm = mrStg->OpenSotStream( "PowerPoint Document" );
+ if ( !mpStrm )
+ return;
+
+ if ( !mpPicStrm )
+ mpPicStrm = mrStg->OpenSotStream( "Pictures" );
+
+ auto aIter = std::find_if(rMediaData.begin(), rMediaData.end(),
+ [](const css::beans::PropertyValue& rProp) { return rProp.Name == "BaseURI"; });
+ if (aIter != rMediaData.end())
+ (*aIter).Value >>= maBaseURI;
+ mpPptEscherEx.reset( new PptEscherEx( *mpStrm, maBaseURI ) );
+}
+
+void PPTWriter::exportPPTPost( )
+{
+ if ( !ImplCloseDocument() )
+ return;
+
+ if ( mbStatusIndicator )
+ {
+ mXStatusIndicator->setText( "PowerPoint Export" );
+ sal_uInt32 nValue = mnStatMaxValue + ( mnStatMaxValue >> 3 );
+ if ( nValue > mnLatestStatValue )
+ {
+ mXStatusIndicator->setValue( nValue );
+ mnLatestStatValue = nValue;
+ }
+ }
+
+ ImplWriteOLE();
+
+ ImplWriteVBA();
+
+ ImplWriteAtomEnding();
+
+ ImplCreateDocumentSummaryInformation();
+
+ mbStatus = true;
+};
+
+static void ImplExportComments( const uno::Reference< drawing::XDrawPage >& xPage, SvMemoryStream& rBinaryTagData10Atom );
+
+void PPTWriter::ImplWriteSlide( sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 nMode,
+ bool bHasBackground, Reference< XPropertySet > const & aXBackgroundPropSet )
+{
+ Any aAny;
+
+ const PHLayout& rLayout = GetLayout( mXPagePropSet );
+ mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_Slide | nPageNum, mpStrm->Tell() );
+ mpPptEscherEx->OpenContainer( EPP_Slide );
+ mpPptEscherEx->AddAtom( 24, EPP_SlideAtom, 2 );
+ mpStrm->WriteInt32( static_cast<sal_Int32>(rLayout.nLayout) );
+ mpStrm->WriteBytes(rLayout.nPlaceHolder, 8); // placeholderIDs (8 parts)
+ mpStrm->WriteUInt32( nMasterNum | 0x80000000 ) // master ID (equals 0x80000000 on a master page)
+ .WriteUInt32( nPageNum + 0x100 ) // notes ID (equals null if no notes are present)
+ .WriteUInt16( nMode )
+ .WriteUInt16( 0 ); // padword
+
+ mnDiaMode = 0;
+ bool bVisible = true;
+ css::presentation::FadeEffect eFe = css::presentation::FadeEffect_NONE;
+
+ if ( GetPropertyValue( aAny, mXPagePropSet, "Visible" ) )
+ aAny >>= bVisible;
+ if ( GetPropertyValue( aAny, mXPagePropSet, "Change" ) )
+ {
+ switch ( *o3tl::doAccess<sal_Int32>(aAny) )
+ {
+ case 1 : // automatic
+ mnDiaMode++;
+ [[fallthrough]];
+ case 2 : // semi-automatic
+ mnDiaMode++;
+ break;
+ default :
+ case 0 : // manual
+ break;
+ }
+ }
+ if ( GetPropertyValue( aAny, mXPagePropSet, "Effect" ) )
+ aAny >>= eFe;
+
+ sal_uInt32 nSoundRef = 0;
+ bool bIsSound = false;
+ bool bStopSound = false;
+ bool bLoopSound = false;
+
+ if ( GetPropertyValue( aAny, mXPagePropSet, "Sound" ) )
+ {
+ OUString aSoundURL;
+ if ( aAny >>= aSoundURL )
+ {
+ nSoundRef = maSoundCollection.GetId( aSoundURL );
+ bIsSound = true;
+ }
+ else
+ aAny >>= bStopSound;
+ }
+ if ( GetPropertyValue( aAny, mXPagePropSet, "LoopSound" ) )
+ aAny >>= bLoopSound;
+
+ bool bNeedsSSSlideInfoAtom = !bVisible
+ || ( mnDiaMode == 2 )
+ || bIsSound
+ || bStopSound
+ || ( eFe != css::presentation::FadeEffect_NONE );
+ if ( bNeedsSSSlideInfoAtom )
+ {
+ sal_uInt8 nDirection = 0;
+ sal_uInt8 nTransitionType = 0;
+ sal_uInt16 nBuildFlags = 1; // advance by mouseclick
+ sal_Int32 nSlideTime = 0; // still has to !!!
+ sal_uInt8 nSpeed = 1;
+
+ if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionDuration" ) )
+ {
+ css::presentation::AnimationSpeed aAs;
+ double fTransitionDuration = -1.0;
+ aAny >>= fTransitionDuration;
+
+ if (fTransitionDuration >= 0)
+ {
+ if (fTransitionDuration <= 0.5)
+ {
+ aAs = css::presentation::AnimationSpeed::AnimationSpeed_FAST;
+ }
+ else if (fTransitionDuration >= 1.0)
+ {
+ aAs = css::presentation::AnimationSpeed::AnimationSpeed_SLOW;
+ }
+ else
+ {
+ aAs = css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM;
+ }
+ }
+ else
+ aAs = css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM;
+
+ nSpeed = static_cast<sal_uInt8>(aAs);
+ }
+ sal_Int16 nTT = 0;
+ if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionType" )
+ && ( aAny >>= nTT ) )
+ {
+ sal_Int16 nTST = 0;
+ if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionSubtype" )
+ && ( aAny >>= nTST ) )
+ nTransitionType = GetTransition( nTT, nTST, eFe, 0, nDirection );
+
+ }
+ if ( !nTransitionType )
+ nTransitionType = GetTransition( eFe, nDirection );
+ if ( mnDiaMode == 2 ) // automatic ?
+ nBuildFlags |= 0x400;
+ if ( !bVisible )
+ nBuildFlags |= 4;
+ if ( bIsSound )
+ nBuildFlags |= 16;
+ if ( bLoopSound )
+ nBuildFlags |= 64;
+ if ( bStopSound )
+ nBuildFlags |= 256;
+
+ if ( GetPropertyValue( aAny, mXPagePropSet, "Duration" ) )// duration of this slide
+ nSlideTime = *o3tl::doAccess<sal_Int32>(aAny) << 10; // in ticks
+
+ mpPptEscherEx->AddAtom( 16, EPP_SSSlideInfoAtom );
+ mpStrm->WriteInt32( nSlideTime ) // standtime in ticks
+ .WriteUInt32( nSoundRef )
+ .WriteUChar( nDirection )
+ .WriteUChar( nTransitionType )
+ .WriteUInt16( nBuildFlags )
+ .WriteUChar( nSpeed )
+ .WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
+ }
+
+ ImplCreateHeaderFooters( mXPagePropSet );
+
+ EscherSolverContainer aSolverContainer;
+ mpPptEscherEx->OpenContainer( EPP_PPDrawing );
+ mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
+ mpPptEscherEx->EnterGroup(nullptr,nullptr);
+ ImplWritePage( rLayout, aSolverContainer, NORMAL, false, nPageNum ); // the shapes of the pages are created in the PPT document
+ mpPptEscherEx->LeaveGroup();
+
+ if ( bHasBackground )
+ ImplWriteBackground( aXBackgroundPropSet );
+ else
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
+ EscherPropertyContainer aPropOpt;
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, PPTtoEMU( maDestPageSize.Width ) );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, PPTtoEMU( maDestPageSize.Width ) );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
+ aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
+ aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 ); // if true, this is the background shape
+ aPropOpt.Commit( *mpStrm );
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+ }
+
+ aSolverContainer.WriteSolver( *mpStrm );
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer
+ mpPptEscherEx->CloseContainer(); // EPP_Drawing
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
+
+ SvMemoryStream aBinaryTagData10Atom;
+ ImplExportComments( mXDrawPage, aBinaryTagData10Atom );
+ SvMemoryStream amsofbtAnimGroup;
+ ppt::AnimationExporter aExporter( aSolverContainer, maSoundCollection );
+ aExporter.doexport( mXDrawPage, amsofbtAnimGroup );
+ sal_uInt32 nmsofbtAnimGroupSize = amsofbtAnimGroup.Tell();
+ if ( nmsofbtAnimGroupSize )
+ {
+ {
+ EscherExAtom aMagic2( aBinaryTagData10Atom, 0x2eeb );
+ aBinaryTagData10Atom.WriteUInt32( 0x01c45df9 )
+ .WriteUInt32( 0xe1471b30 );
+ }
+ {
+ EscherExAtom aMagic( aBinaryTagData10Atom, 0x2b00 );
+ aBinaryTagData10Atom.WriteUInt32( 0 );
+ }
+ aBinaryTagData10Atom.WriteBytes(amsofbtAnimGroup.GetData(), amsofbtAnimGroup.Tell());
+ {
+ EscherExContainer aMagic2( aBinaryTagData10Atom, 0x2b02 );
+ }
+ }
+ if ( aBinaryTagData10Atom.Tell() )
+ {
+ EscherExContainer aProgTags ( *mpStrm, EPP_ProgTags );
+ EscherExContainer aProgBinaryTag( *mpStrm, EPP_ProgBinaryTag );
+ {
+ EscherExAtom aCString( *mpStrm, EPP_CString );
+ mpStrm->WriteUInt32( 0x5f005f )
+ .WriteUInt32( 0x50005f )
+ .WriteUInt32( 0x540050 )
+ .WriteUInt16( 0x31 )
+ .WriteUInt16( 0x30 );
+ }
+ {
+ EscherExAtom aBinaryTagData( *mpStrm, EPP_BinaryTagData );
+ mpStrm->WriteBytes(aBinaryTagData10Atom.GetData(), aBinaryTagData10Atom.Tell());
+ }
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_Slide
+}
+
+void PPTWriter::ImplWriteSlideMaster( sal_uInt32 nPageNum, Reference< XPropertySet > const & aXBackgroundPropSet )
+{
+ if (!aXBackgroundPropSet)
+ return;
+ mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_MainMaster | nPageNum, mpStrm->Tell() );
+ mpPptEscherEx->OpenContainer( EPP_MainMaster );
+ mpPptEscherEx->AddAtom( 24, EPP_SlideAtom, 2 );
+ mpStrm->WriteInt32( static_cast<sal_Int32>(EppLayout::TITLEANDBODYSLIDE) ) // slide layout -> title and body slide
+ .WriteUChar( 1 ).WriteUChar( 2 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ) // placeholderID
+ .WriteUInt32( 0 ) // master ID (equals null at a master page)
+ .WriteUInt32( 0 ) // notes ID (equals null if no notes are present)
+ .WriteUInt16( 0 ) // Bit 1: Follow master objects, Bit 2: Follow master scheme, Bit 3: Follow master background
+ .WriteUInt16( 0 ); // padword
+
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xff0000 ).WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x00ffff ).WriteUInt32( 0x0099ff ).WriteUInt32( 0xffff00 ).WriteUInt32( 0x0000ff ).WriteUInt32( 0x969696 );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xccffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x336666 ).WriteUInt32( 0x008080 ).WriteUInt32( 0x339933 ).WriteUInt32( 0x000080 ).WriteUInt32( 0xcc3300 ).WriteUInt32( 0x66ccff );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x333333 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xdddddd ).WriteUInt32( 0x808080 ).WriteUInt32( 0x4d4d4d ).WriteUInt32( 0xeaeaea );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x66ccff ).WriteUInt32( 0xff0000 ).WriteUInt32( 0xcc00cc ).WriteUInt32( 0xc0c0c0 );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xc0c0c0 ).WriteUInt32( 0xff6600 ).WriteUInt32( 0x0000ff ).WriteUInt32( 0x009900 );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xff9933 ).WriteUInt32( 0xccff99 ).WriteUInt32( 0xcc00cc ).WriteUInt32( 0xb2b2b2 );
+
+ for ( int nInstance = EPP_TEXTTYPE_Title; nInstance <= EPP_TEXTTYPE_QuarterBody; nInstance++ )
+ {
+ if ( nInstance == EPP_TEXTTYPE_notUsed )
+ continue;
+
+ // the auto color is dependent to the page background,so we have to set a page that is in the right context
+ if ( nInstance == EPP_TEXTTYPE_Notes )
+ (void)GetPageByIndex(0, NOTICE);
+ else
+ (void)GetPageByIndex(0, MASTER);
+
+ mpPptEscherEx->BeginAtom();
+
+ bool bSimpleText = false;
+
+ mpStrm->WriteUInt16( 5 ); // paragraph count
+
+ for ( sal_uInt16 nLev = 0; nLev < 5; nLev++ )
+ {
+ if ( nInstance >= EPP_TEXTTYPE_CenterBody )
+ {
+ bSimpleText = true;
+ mpStrm->WriteUInt16( nLev );
+ }
+ mpStyleSheet->mpParaSheet[ nInstance ]->Write( *mpStrm, nLev, bSimpleText, mXPagePropSet );
+ mpStyleSheet->mpCharSheet[ nInstance ]->Write( *mpStrm, nLev, bSimpleText, mXPagePropSet );
+ }
+ mpPptEscherEx->EndAtom( EPP_TxMasterStyleAtom, 0, nInstance );
+ }
+ GetPageByIndex( nPageNum, MASTER );
+
+ EscherSolverContainer aSolverContainer;
+
+ mpPptEscherEx->OpenContainer( EPP_PPDrawing );
+ mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
+
+ mpPptEscherEx->EnterGroup(nullptr,nullptr);
+ ImplWritePage( GetLayout( 0 ), aSolverContainer, MASTER, true ); // the shapes of the pages are created in the PPT document
+ mpPptEscherEx->LeaveGroup();
+
+ ImplWriteBackground( aXBackgroundPropSet );
+
+ aSolverContainer.WriteSolver( *mpStrm );
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer
+ mpPptEscherEx->CloseContainer(); // EPP_Drawing
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
+
+ if ( aBuExMasterStream.Tell() )
+ {
+ ImplProgTagContainer( mpStrm.get(), &aBuExMasterStream );
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_MainMaster
+};
+
+PPTWriter::~PPTWriter()
+{
+ mpExEmbed.reset();
+ mpPptEscherEx.reset();
+ mpCurUserStrm.clear();
+ mpPicStrm.clear();
+ mpStrm.clear();
+ maStyleSheetList.clear();
+ maExOleObj.clear();
+ if ( mbStatusIndicator )
+ mXStatusIndicator->end();
+}
+
+bool PPTWriter::ImplCreateCurrentUserStream()
+{
+ mpCurUserStrm = mrStg->OpenSotStream( "Current User" );
+ if ( !mpCurUserStrm )
+ return false;
+ char pUserName[] = "Current User";
+ sal_uInt32 nLenOfUserName = strlen( pUserName );
+ sal_uInt32 nSizeOfRecord = 0x14 + ( ( nLenOfUserName + 4 ) & ~ 3 );
+
+ mpCurUserStrm->WriteUInt16( 0 ).WriteUInt16( EPP_CurrentUserAtom ).WriteUInt32( nSizeOfRecord );
+ mpCurUserStrm->WriteUInt32( 0x14 ) // Len
+ .WriteUInt32( 0xe391c05f ); // Magic
+
+ sal_uInt32 nEditPos = mpCurUserStrm->Tell();
+ mpCurUserStrm->WriteUInt32( 0x0 ) // OffsetToCurrentEdit;
+ .WriteUInt16( nLenOfUserName )
+ .WriteUInt16( 0x3f4 ) // DocFileVersion
+ .WriteUChar( 3 ) // MajorVersion
+ .WriteUChar( 0 ) // MinorVersion
+ .WriteUInt16( 0 ); // Pad Word
+ pUserName[ nLenOfUserName ] = 8;
+ mpCurUserStrm->WriteBytes(pUserName, nLenOfUserName + 1);
+ for ( sal_uInt32 i = 0x15 + nLenOfUserName; i < nSizeOfRecord; i++ )
+ {
+ mpCurUserStrm->WriteUChar( 0 ); // pad bytes
+ }
+ mpCurUserStrm->Seek( nEditPos );
+ return true;
+};
+
+void PPTWriter::ImplCreateDocumentSummaryInformation()
+{
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ mXModel, uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps(
+ xDPS->getDocumentProperties());
+
+ if (!xDocProps.is())
+ return;
+
+ // no idea what this is...
+ static const sal_Int8 aGuid[ 0x52 ] =
+ {
+ 0x4e, 0x00, 0x00, 0x00,
+ '{',0,'D',0,'B',0,'1',0,'A',0,'C',0,'9',0,'6',0,'4',0,'-',0,
+ 'E',0,'3',0,'9',0,'C',0,'-',0,'1',0,'1',0,'D',0,'2',0,'-',0,
+ 'A',0,'1',0,'E',0,'F',0,'-',0,'0',0,'0',0,'6',0,'0',0,'9',0,
+ '7',0,'D',0,'A',0,'5',0,'6',0,'8',0,'9',0,'}',0
+ };
+ // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence
+ uno::Sequence<sal_Int8> aGuidSeq(aGuid, 0x52);
+
+ SvMemoryStream aHyperBlob;
+ ImplCreateHyperBlob( aHyperBlob );
+
+ auto nHyperLength = static_cast<sal_Int32>(aHyperBlob.Tell());
+ const sal_Int8* pBlob(
+ static_cast<const sal_Int8*>(aHyperBlob.GetData()));
+ auto aHyperSeq = comphelper::arrayToSequence<sal_Int8>(pBlob, nHyperLength);
+
+ if ( mnCnvrtFlags & 0x8000 )
+ {
+ uno::Sequence<sal_Int8> aThumbSeq;
+ if ( GetPageByIndex( 0, NORMAL ) && ImplGetPropertyValue( mXPagePropSet, "PreviewBitmap" ) )
+ {
+ aThumbSeq = *o3tl::doAccess<uno::Sequence<sal_Int8>>(mAny);
+ }
+ sfx2::SaveOlePropertySet( xDocProps, mrStg.get(),
+ &aThumbSeq, &aGuidSeq, &aHyperSeq);
+ }
+ else
+ {
+ sfx2::SaveOlePropertySet( xDocProps, mrStg.get(),
+ nullptr, &aGuidSeq, &aHyperSeq );
+ }
+}
+
+void PPTWriter::ImplWriteExtParaHeader( SvMemoryStream& rSt, sal_uInt32 nRef, sal_uInt32 nInstance, sal_uInt32 nSlideId )
+{
+ if ( rSt.Tell() )
+ {
+ aBuExOutlineStream.WriteUInt32( ( EPP_PST_ExtendedParagraphHeaderAtom << 16 )
+ | ( nRef << 4 ) )
+ .WriteUInt32( 8 )
+ .WriteUInt32( nSlideId )
+ .WriteUInt32( nInstance );
+ aBuExOutlineStream.WriteBytes(rSt.GetData(), rSt.Tell());
+ }
+}
+
+void PPTWriter::ImplCreateHeaderFooterStrings( SvStream& rStrm, css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet )
+{
+ if ( !rXPagePropSet.is() )
+ return;
+
+ OUString aString;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "HeaderText", true ) )
+ {
+ if ( aAny >>= aString )
+ PPTWriter::WriteCString( rStrm, aString, 1 );
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "FooterText", true ) )
+ {
+ if ( aAny >>= aString )
+ PPTWriter::WriteCString( rStrm, aString, 2 );
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "DateTimeText", true ) )
+ {
+ if ( aAny >>= aString )
+ PPTWriter::WriteCString( rStrm, aString );
+ }
+}
+
+void PPTWriter::ImplCreateHeaderFooters( css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet )
+{
+ if ( !rXPagePropSet.is() )
+ return;
+
+ bool bVal = false;
+ sal_uInt32 nVal = 0;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsHeaderVisible", true ) )
+ {
+ if ( ( aAny >>= bVal ) && bVal )
+ nVal |= 0x100000;
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsFooterVisible", true ) )
+ {
+ if ( ( aAny >>= bVal ) && bVal )
+ nVal |= 0x200000;
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsDateTimeVisible", true ) )
+ {
+ if ( ( aAny >>= bVal ) && bVal )
+ nVal |= 0x010000;
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsPageNumberVisible", true ) )
+ {
+ if ( ( aAny >>= bVal ) && bVal )
+ nVal |= 0x080000;
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsDateTimeFixed", true ) )
+ {
+ if ( ( aAny >>= bVal ) && !bVal )
+ nVal |= 0x20000;
+ else
+ nVal |= 0x40000;
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "DateTimeFormat", true ) )
+ {
+ sal_Int32 nFormat = *o3tl::doAccess<sal_Int32>(aAny);
+ SvxDateFormat eDateFormat = static_cast<SvxDateFormat>( nFormat & 0xf );
+ SvxTimeFormat eTimeFormat = static_cast<SvxTimeFormat>( ( nFormat >> 4 ) & 0xf );
+ switch( eDateFormat )
+ {
+ case SvxDateFormat::F :
+ nFormat = 1;
+ break;
+ case SvxDateFormat::D :
+ nFormat = 2;
+ break;
+ case SvxDateFormat::C :
+ nFormat = 4;
+ break;
+ default:
+ case SvxDateFormat::A :
+ nFormat = 0;
+ }
+ switch( eTimeFormat )
+ {
+ case SvxTimeFormat::HH24_MM :
+ nFormat = 9;
+ break;
+ case SvxTimeFormat::HH12_MM :
+ nFormat = 11;
+ break;
+ case SvxTimeFormat::HH24_MM_SS :
+ nFormat = 10;
+ break;
+ case SvxTimeFormat::HH12_MM_SS :
+ nFormat = 12;
+ break;
+ default:
+ break;
+ }
+ nVal |= nFormat;
+ }
+
+ mpPptEscherEx->OpenContainer( EPP_HeadersFooters );
+ mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
+ mpStrm->WriteUInt32( nVal );
+ ImplCreateHeaderFooterStrings( *mpStrm, rXPagePropSet );
+ mpPptEscherEx->CloseContainer();
+}
+
+bool PPTWriter::ImplCreateDocument()
+{
+ sal_uInt32 i;
+ sal_uInt16 nSlideType = EPP_SLIDESIZE_TYPECUSTOM;
+
+ sal_uInt32 nWidth = maDestPageSize.Width;
+ sal_uInt32 nHeight = maDestPageSize.Height;
+
+ if ( ( nWidth == 0x1680 ) && ( nHeight == 0x10e0 ) )
+ nSlideType = EPP_SLIDESIZE_TYPEONSCREEN;
+ else if ( ( nWidth == 0x1200 ) && ( nHeight == 0x240 ) )
+ nSlideType = EPP_SLIDESIZE_TYPEBANNER;
+ else if ( ( nWidth == 0x1950 ) && ( nHeight == 0x10e0 ) )
+ nSlideType = EPP_SLIDESIZE_TYPE35MM;
+ else if ( ( nWidth == 0x1860 ) && ( nHeight == 0x10e0 ) )
+ nSlideType = EPP_SLIDESIZE_TYPEA4PAPER;
+
+ mpPptEscherEx->OpenContainer( EPP_Document );
+ // CREATE DOCUMENT ATOM
+ mpPptEscherEx->AddAtom( 40, EPP_DocumentAtom, 1 );
+ mpStrm->WriteUInt32( nWidth ) // Slide Size in Master coordinates X
+ .WriteUInt32( nHeight ) // " " " " " Y
+ .WriteInt32( maNotesPageSize.Width ) // Notes Page Size X
+ .WriteInt32( maNotesPageSize.Height ) // " " " Y
+ .WriteInt32( 1 ).WriteInt32( 2 ); // the scale used when the Powerpoint document is embedded. the default is 1:2
+ mpPptEscherEx->InsertPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY, mpStrm->Tell() );
+ mpStrm->WriteUInt32( 0 ) // Reference to NotesMaster ( 0 if none );
+ .WriteUInt32( 0 ) // Reference to HandoutMaster ( 0 if none );
+ .WriteInt16( 1 ) // Number of the first slide;
+ .WriteUInt16( nSlideType ) // Size of the document slides ( default: EPP_SLIDESIZETYPEONSCREEN )
+ .WriteUChar( 0 ) // bool1 indicates if document was saved with embedded true type fonts
+ .WriteUChar( 0 ) // bool1 indicates if the placeholders on the title slide are omitted
+ .WriteUChar( 0 ) // bool1 right to left ( flag for Bidi version )
+ .WriteUChar( 1 ); // bool1 visibility of comments shapes
+
+ mpPptEscherEx->PtInsert( EPP_Persist_Document, mpStrm->Tell() );
+
+ mpPptEscherEx->OpenContainer( EPP_HeadersFooters, 3 ); //Master footer (default)
+ mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
+ mpStrm->WriteUInt32( 0x25000d );
+ if ( GetPageByIndex( 0, MASTER ) )
+ ImplCreateHeaderFooterStrings( *mpStrm, mXPagePropSet );
+ mpPptEscherEx->CloseContainer();
+ mpPptEscherEx->OpenContainer( EPP_HeadersFooters, 4 ); //NotesMaster footer (default)
+ mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
+ mpStrm->WriteUInt32( 0x3d000d );
+ if ( GetPageByIndex( 0, NOTICE ) )
+ ImplCreateHeaderFooterStrings( *mpStrm, mXPagePropSet );
+ mpPptEscherEx->CloseContainer();
+
+ mpPptEscherEx->OpenContainer( EPP_SlideListWithText ); // animation information for the slides
+
+ for ( i = 0; i < mnPages; i++ )
+ {
+ mpPptEscherEx->AddAtom( 20, EPP_SlidePersistAtom );
+ mpPptEscherEx->InsertPersistOffset( EPP_MAINSLIDE_PERSIST_KEY | i, mpStrm->Tell() );
+ mpStrm->WriteUInt32( 0 ) // psrReference - logical reference to the slide persist object ( EPP_MAINSLIDE_PERSIST_KEY )
+ .WriteUInt32( 4 ) // flags - only bit 3 used, if set then slide contains shapes other than placeholders
+ .WriteInt32( 0 ) // numberTexts - number of placeholder texts stored with the persist object. Allows to display outline view without loading the slide persist objects
+ .WriteInt32( i + 0x100 ) // slideId - Unique slide identifier, used for OLE link monikers for example
+ .WriteUInt32( 0 ); // reserved, usually 0
+
+ if ( !GetPageByIndex( i, NORMAL ) ) // very exciting: once again through all pages
+ return false;
+ SetCurrentStyleSheet( GetMasterIndex( NORMAL ) );
+
+ css::uno::Reference< css::container::XNamed >
+ aXName( mXDrawPage, css::uno::UNO_QUERY );
+
+ if ( aXName.is() )
+ maSlideNameList.push_back( aXName->getName() );
+ else
+ maSlideNameList.emplace_back( );
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_SlideListWithText
+
+ mpPptEscherEx->OpenContainer( EPP_SlideListWithText, 2 ); // animation information for the notes
+ for( i = 0; i < mnPages; i++ )
+ {
+ mpPptEscherEx->AddAtom( 20, EPP_SlidePersistAtom );
+ mpPptEscherEx->InsertPersistOffset( EPP_MAINNOTES_PERSIST_KEY | i, mpStrm->Tell() );
+ mpStrm->WriteUInt32( 0 )
+ .WriteUInt32( 4 )
+ .WriteInt32( 0 )
+ .WriteInt32( i + 0x100 )
+ .WriteUInt32( 0 );
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_SlideListWithText
+
+ css::uno::Reference< css::presentation::XPresentationSupplier >
+ aXPresSupplier( mXModel, css::uno::UNO_QUERY );
+ if ( aXPresSupplier.is() )
+ {
+ css::uno::Reference< css::presentation::XPresentation > aXPresentation( aXPresSupplier->getPresentation() );
+ if ( aXPresentation.is() )
+ {
+ mXPropSet.set( aXPresentation, css::uno::UNO_QUERY );
+ if ( mXPropSet.is() )
+ {
+ OUString aCustomShow;
+ sal_uInt32 const nPenColor = 0x1000000;
+ sal_Int32 const nRestartTime = 0x7fffffff;
+ sal_Int16 nStartSlide = 0;
+ sal_Int16 nEndSlide = 0;
+ sal_uInt32 nFlags = 0; // Bit 0: Auto advance
+ // Bit 1 Skip builds ( do not allow slide effects )
+ // Bit 2 Use slide range
+ // Bit 3 Use named show
+ // Bit 4 Browse mode on
+ // Bit 5 Kiosk mode on
+ // Bit 6 Skip narration
+ // Bit 7 loop continuously
+ // Bit 8 show scrollbar
+
+ if ( ImplGetPropertyValue( "CustomShow" ) )
+ {
+ aCustomShow = *o3tl::doAccess<OUString>(mAny);
+ if ( !aCustomShow.isEmpty() )
+ {
+ nFlags |= 8;
+ }
+ }
+ if ( ( nFlags & 8 ) == 0 )
+ {
+ if ( ImplGetPropertyValue( "FirstPage" ) )
+ {
+ auto aSlideName = o3tl::doAccess<OUString>(mAny);
+
+ std::vector<OUString>::const_iterator pIter = std::find(
+ maSlideNameList.begin(),maSlideNameList.end(), *aSlideName);
+
+ if (pIter != maSlideNameList.end())
+ {
+ nStartSlide = pIter - maSlideNameList.begin() + 1;
+ nFlags |= 4;
+ nEndSlide = static_cast<sal_uInt16>(mnPages);
+ }
+ }
+ }
+
+ if ( ImplGetPropertyValue( "IsAutomatic" ) )
+ {
+ bool bBool = false;
+ mAny >>= bBool;
+ if ( !bBool )
+ nFlags |= 1;
+ }
+
+ if ( ImplGetPropertyValue( "IsEndless" ) )
+ {
+ bool bBool = false;
+ mAny >>= bBool;
+ if ( bBool )
+ nFlags |= 0x80;
+ }
+ if ( ImplGetPropertyValue( "IsFullScreen" ) )
+ {
+ bool bBool = false;
+ mAny >>= bBool;
+ if ( !bBool )
+ nFlags |= 0x11;
+ }
+
+ mpPptEscherEx->AddAtom( 80, EPP_SSDocInfoAtom, 1 );
+ mpStrm->WriteUInt32( nPenColor ).WriteInt32( nRestartTime ).WriteInt16( nStartSlide ).WriteInt16( nEndSlide );
+
+ sal_uInt32 nCustomShowNameLen = aCustomShow.getLength();
+ if ( nCustomShowNameLen > 31 )
+ nCustomShowNameLen = 31;
+ if ( nCustomShowNameLen ) // named show identifier
+ {
+ const sal_Unicode* pCustomShow = aCustomShow.getStr();
+ for ( i = 0; i < nCustomShowNameLen; i++ )
+ {
+ mpStrm->WriteUInt16( pCustomShow[ i ] );
+ }
+ }
+ for ( i = nCustomShowNameLen; i < 32; i++, mpStrm->WriteUInt16( 0 ) ) ;
+
+ mpStrm->WriteUInt32( nFlags );
+ css::uno::Reference< css::presentation::XCustomPresentationSupplier > aXCPSup( mXModel, css::uno::UNO_QUERY );
+ if ( aXCPSup.is() )
+ {
+ css::uno::Reference< css::container::XNameContainer > aXCont( aXCPSup->getCustomPresentations() );
+ if ( aXCont.is() )
+ {
+ const css::uno::Sequence< OUString> aNameSeq( aXCont->getElementNames() );
+ if ( aNameSeq.hasElements() )
+ {
+ mpPptEscherEx->OpenContainer( EPP_NamedShows );
+ sal_uInt32 nCustomShowIndex = 0;
+ for( OUString const & customShowName : aNameSeq )
+ {
+ if ( !customShowName.isEmpty() )
+ {
+ mpPptEscherEx->OpenContainer( EPP_NamedShow, nCustomShowIndex++ );
+
+ sal_uInt32 nNamedShowLen = customShowName.getLength();
+ if ( nNamedShowLen > 31 )
+ nNamedShowLen = 31;
+ mpPptEscherEx->AddAtom( nNamedShowLen << 1, EPP_CString );
+ const sal_Unicode* pCustomShowName = customShowName.getStr();
+ for ( sal_uInt32 k = 0; k < nNamedShowLen; ++k )
+ mpStrm->WriteUInt16( pCustomShowName[ k ] );
+ mAny = aXCont->getByName( customShowName );
+ css::uno::Reference< css::container::XIndexContainer > aXIC;
+ if ( mAny >>= aXIC )
+ {
+ mpPptEscherEx->BeginAtom();
+
+ sal_Int32 nSlideCount = aXIC->getCount();
+ for ( sal_Int32 j = 0; j < nSlideCount; j++ ) // number of slides
+ {
+ mAny = aXIC->getByIndex( j );
+ css::uno::Reference< css::drawing::XDrawPage > aXDrawPage;
+ if ( mAny >>= aXDrawPage )
+ {
+ css::uno::Reference< css::container::XNamed > aXName( aXDrawPage, css::uno::UNO_QUERY );
+ if ( aXName.is() )
+ {
+ OUString aSlideName( aXName->getName() );
+ std::vector<OUString>::const_iterator pIter = std::find(
+ maSlideNameList.begin(),maSlideNameList.end(),aSlideName);
+
+ if (pIter != maSlideNameList.end())
+ {
+ sal_uInt32 nPageNumber = pIter - maSlideNameList.begin();
+ mpStrm->WriteUInt32( nPageNumber + 0x100 ); // unique slide id
+ }
+ }
+ }
+ }
+ mpPptEscherEx->EndAtom( EPP_NamedShowSlides );
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_NamedShow
+ }
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_NamedShows
+ }
+ }
+ }
+ }
+ }
+ }
+ mpPptEscherEx->AddAtom( 0, EPP_EndDocument );
+ mpPptEscherEx->CloseContainer(); // EPP_Document
+ return true;
+};
+
+void PPTWriter::ImplCreateHyperBlob( SvMemoryStream& rStrm )
+{
+ sal_uInt32 nCurrentOfs, nParaOfs, nParaCount = 0;
+
+ nParaOfs = rStrm.Tell();
+ rStrm.WriteUInt32( 0 ); // property size
+ rStrm.WriteUInt32( 0 ); // property count
+
+ for ( const auto& rHyperlink : maHyperlink )
+ {
+ nParaCount += 6;
+ rStrm .WriteUInt32( 3 ) // Type VT_I4
+ .WriteUInt32( 7 ) // (VTI4 - Private1)
+ .WriteUInt32( 3 ) // Type VT_I4
+ .WriteUInt32( 6 ) // (VTI4 - Private2)
+ .WriteUInt32( 3 ) // Type VT_I4
+ .WriteUInt32( 0 ); // (VTI4 - Private3)
+
+ // INFO
+ // HIWORD: = 0 : do not change anything
+ // = 1 : replace the hyperlink with the target and subaddress in the following two VTLPWSTR
+ // = 2 : delete the hyperlink
+ // LOWORD: = 0 : graphic shown as background (link)
+ // = 1 : graphic shown as shape (link)
+ // = 2 : graphic is used to fill a shape
+ // = 3 : graphic used to fill a shape outline (future use)
+ // = 4 : hyperlink attached to a shape
+ // = 5 : " " " " (Word) field
+ // = 6 : " " " " (Excel) range
+ // = 7 : " " " " (PPT) text range
+ // = 8 : " " " " (Project) task
+
+ sal_Int32 nUrlLen = rHyperlink.aURL.getLength();
+ const OUString& rUrl = rHyperlink.aURL;
+
+ sal_uInt32 const nInfo = 7;
+
+ rStrm .WriteUInt32( 3 ) // Type VT_I4
+ .WriteUInt32( nInfo ); // Info
+
+ switch( rHyperlink.nType & 0xff )
+ {
+ case 1 : // click action to slidenumber
+ {
+ rStrm.WriteUInt32( 0x1f ).WriteUInt32( 1 ).WriteUInt32( 0 ); // path
+ rStrm.WriteUInt32( 0x1f ).WriteUInt32( nUrlLen + 1 );
+ for ( sal_Int32 i = 0; i < nUrlLen; i++ )
+ {
+ rStrm.WriteUInt16( rUrl[ i ] );
+ }
+ rStrm.WriteUInt16( 0 );
+ }
+ break;
+ case 2 :
+ {
+ sal_Int32 i;
+
+ rStrm .WriteUInt32( 0x1f )
+ .WriteUInt32( nUrlLen + 1 );
+ for ( i = 0; i < nUrlLen; i++ )
+ {
+ rStrm.WriteUInt16( rUrl[ i ] );
+ }
+ if ( ! ( i & 1 ) )
+ rStrm.WriteUInt16( 0 );
+ rStrm .WriteUInt16( 0 )
+ .WriteUInt32( 0x1f )
+ .WriteUInt32( 1 )
+ .WriteUInt32( 0 );
+ }
+ break;
+ }
+ }
+ nCurrentOfs = rStrm.Tell();
+ rStrm.Seek( nParaOfs );
+ rStrm.WriteUInt32( nCurrentOfs - ( nParaOfs + 4 ) );
+ rStrm.WriteUInt32( nParaCount );
+ rStrm.Seek( nCurrentOfs );
+}
+
+bool PPTWriter::ImplCreateMainNotes()
+{
+ EscherSolverContainer aSolverContainer;
+
+ mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_MainNotes, mpStrm->Tell() );
+ mpPptEscherEx->OpenContainer( EPP_Notes );
+ mpPptEscherEx->AddAtom( 8, EPP_NotesAtom, 1 );
+ mpStrm->WriteUInt32( 0x80000001 ) // Number that identifies this slide
+ .WriteUInt32( 0 ); // follow nothing
+ mpPptEscherEx->OpenContainer( EPP_PPDrawing );
+ mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
+ mpPptEscherEx->EnterGroup(nullptr,nullptr);
+
+ ImplWritePage( GetLayout( 20 ), aSolverContainer, NOTICE, true );
+
+ mpPptEscherEx->LeaveGroup();
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
+ EscherPropertyContainer aPropOpt;
+ aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0xffffff ); // stock valued fill color
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, 0x68bdde );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, 0x8b9f8e );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0 );
+ aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
+ aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 ); // if true, this is the background shape
+ aPropOpt.Commit( *mpStrm );
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+
+ aSolverContainer.WriteSolver( *mpStrm );
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer
+ mpPptEscherEx->CloseContainer(); // EPP_Drawing
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
+ mpPptEscherEx->CloseContainer(); // EPP_Notes
+ return true;
+}
+
+static OUString getInitials( const OUString& rName )
+{
+ OUStringBuffer sInitials;
+
+ const sal_Unicode * pStr = rName.getStr();
+ sal_Int32 nLength = rName.getLength();
+
+ while( nLength )
+ {
+ // skip whitespace
+ while( nLength && (*pStr <= ' ') )
+ {
+ nLength--; pStr++;
+ }
+
+ // take letter
+ if( nLength )
+ {
+ sInitials.append( *pStr );
+ nLength--; pStr++;
+ }
+
+ // skip letters until whitespace
+ while( nLength && (*pStr > ' ') )
+ {
+ nLength--; pStr++;
+ }
+ }
+
+ return sInitials.makeStringAndClear();
+}
+
+void ImplExportComments( const uno::Reference< drawing::XDrawPage >& xPage, SvMemoryStream& rBinaryTagData10Atom )
+{
+ try
+ {
+ uno::Reference< office::XAnnotationAccess > xAnnotationAccess( xPage, uno::UNO_QUERY_THROW );
+ uno::Reference< office::XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() );
+
+ sal_Int32 nIndex = 1;
+
+ while( xAnnotationEnumeration->hasMoreElements() )
+ {
+ EscherExContainer aComment10( rBinaryTagData10Atom, EPP_Comment10 );
+ {
+ uno::Reference< office::XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement() );
+
+ geometry::RealPoint2D aRealPoint2D( xAnnotation->getPosition() );
+ Point aPoint(o3tl::convert(aRealPoint2D.X, o3tl::Length::mm, o3tl::Length::master),
+ o3tl::convert(aRealPoint2D.Y, o3tl::Length::mm, o3tl::Length::master));
+
+ OUString sAuthor( xAnnotation->getAuthor() );
+ uno::Reference< text::XText > xText( xAnnotation->getTextRange() );
+ OUString sText( xText->getString() );
+ OUString sInitials( getInitials( sAuthor ) );
+ util::DateTime aDateTime( xAnnotation->getDateTime() );
+ if ( !sAuthor.isEmpty() )
+ PPTWriter::WriteCString( rBinaryTagData10Atom, sAuthor );
+ if ( !sText.isEmpty() )
+ PPTWriter::WriteCString( rBinaryTagData10Atom, sText, 1 );
+ if ( !sInitials.isEmpty() )
+ PPTWriter::WriteCString( rBinaryTagData10Atom, sInitials, 2 );
+
+ sal_Int16 nMilliSeconds = static_cast<sal_Int16>(::rtl::math::round(static_cast<double>(aDateTime.NanoSeconds) / 1000000000.0));
+ EscherExAtom aCommentAtom10( rBinaryTagData10Atom, EPP_CommentAtom10 );
+ rBinaryTagData10Atom.WriteInt32( nIndex++ )
+ .WriteInt16( aDateTime.Year )
+ .WriteUInt16( aDateTime.Month )
+ .WriteUInt16( aDateTime.Day ) // todo: day of week
+ .WriteUInt16( aDateTime.Day )
+ .WriteUInt16( aDateTime.Hours )
+ .WriteUInt16( aDateTime.Minutes )
+ .WriteUInt16( aDateTime.Seconds )
+ .WriteInt16( nMilliSeconds )
+ .WriteInt32( aPoint.X() )
+ .WriteInt32( aPoint.Y() );
+ }
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+}
+
+void PPTWriter::ImplWriteNotes( sal_uInt32 nPageNum )
+{
+ mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_Notes | nPageNum, mpStrm->Tell() );
+ mpPptEscherEx->OpenContainer( EPP_Notes );
+ mpPptEscherEx->AddAtom( 8, EPP_NotesAtom, 1 );
+ mpStrm->WriteUInt32( nPageNum + 0x100 )
+ .WriteUInt16( 3 ) // follow master...
+ .WriteUInt16( 0 );
+
+ ImplCreateHeaderFooters( mXPagePropSet );
+
+ EscherSolverContainer aSolverContainer;
+
+ mpPptEscherEx->OpenContainer( EPP_PPDrawing );
+ mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
+ mpPptEscherEx->EnterGroup(nullptr,nullptr);
+
+ ImplWritePage( GetLayout( 20 ), aSolverContainer, NOTICE, false ); // the shapes of the pages are created in the PPT document
+
+ mpPptEscherEx->LeaveGroup();
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
+ EscherPropertyContainer aPropOpt;
+ aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0xffffff ); // stock valued fill color
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, 0x8b9f8e );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, 0x68bdde );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
+ aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
+ aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 );
+ aPropOpt.Commit( *mpStrm );
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+
+ aSolverContainer.WriteSolver( *mpStrm );
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer
+ mpPptEscherEx->CloseContainer(); // EPP_Drawing
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
+ mpPptEscherEx->CloseContainer(); // EPP_Notes
+};
+
+void PPTWriter::ImplWriteBackground( css::uno::Reference< css::beans::XPropertySet > const & rXPropSet )
+{
+ //************************ ******
+ //** DEFAULT BACKGROUND SHAPE **
+
+ sal_uInt32 nFillColor = 0xffffff;
+ sal_uInt32 nFillBackColor = 0;
+
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
+
+ // #i121183# Use real PageSize in 100th mm
+ ::tools::Rectangle aRect(Point(0, 0), Size(maPageSize.Width, maPageSize.Height));
+
+ EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
+ aPropOpt.AddOpt( ESCHER_Prop_fillType, ESCHER_FillSolid );
+ css::drawing::FillStyle aFS( css::drawing::FillStyle_NONE );
+ if ( ImplGetPropertyValue( rXPropSet, "FillStyle" ) )
+ mAny >>= aFS;
+
+ switch( aFS )
+ {
+ case css::drawing::FillStyle_GRADIENT :
+ {
+ aPropOpt.CreateGradientProperties( rXPropSet );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x1f001e );
+ aPropOpt.GetOpt( ESCHER_Prop_fillColor, nFillColor );
+ aPropOpt.GetOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
+ }
+ break;
+
+ case css::drawing::FillStyle_BITMAP :
+ aPropOpt.CreateGraphicProperties( rXPropSet, "FillBitmap", true );
+ break;
+
+ case css::drawing::FillStyle_HATCH :
+ aPropOpt.CreateGraphicProperties( rXPropSet, "FillHatch", true );
+ break;
+
+ case css::drawing::FillStyle_SOLID :
+ {
+ if ( ImplGetPropertyValue( rXPropSet, "FillColor" ) )
+ {
+ nFillColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(mAny) );
+ nFillBackColor = nFillColor ^ 0xffffff;
+ }
+ [[fallthrough]];
+ }
+ case css::drawing::FillStyle_NONE :
+ default:
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
+ break;
+ }
+ aPropOpt.AddOpt( ESCHER_Prop_fillColor, nFillColor );
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, PPTtoEMU( maDestPageSize.Width ) );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, PPTtoEMU( maDestPageSize.Height ) );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
+ aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_bwWhite );
+ aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 );
+ aPropOpt.Commit( *mpStrm );
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+}
+
+void PPTWriter::ImplWriteVBA()
+{
+ if ( mpVBA )
+ {
+ sal_uInt32 nLen = mpVBA->TellEnd();
+ if ( nLen > 8 )
+ {
+ nLen -= 8;
+ mnVBAOleOfs = mpStrm->Tell();
+ mpPptEscherEx->BeginAtom();
+ mpStrm->WriteBytes(static_cast<sal_Int8 const *>(mpVBA->GetData()) + 8, nLen);
+ mpPptEscherEx->EndAtom( EPP_ExOleObjStg, 0, 1 );
+ }
+ }
+}
+
+void PPTWriter::ImplWriteOLE( )
+{
+
+ SvxMSExportOLEObjects aOleExport( mnCnvrtFlags );
+
+ for ( const auto& rxExOleObjEntry : maExOleObj )
+ {
+ PPTExOleObjEntry* pPtr = rxExOleObjEntry.get();
+ std::unique_ptr<SvMemoryStream> pStrm;
+ pPtr->nOfsB = mpStrm->Tell();
+ switch ( pPtr->eType )
+ {
+ case NORMAL_OLE_OBJECT :
+ {
+ SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(pPtr->xShape);
+ if ( auto pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >(pSdrObj) )
+ {
+ const ::uno::Reference < embed::XEmbeddedObject >& xObj( pSdrOle2Obj->GetObjRef() );
+ if( xObj.is() )
+ {
+ tools::SvRef<SotStorage> xTempStorage( new SotStorage( new SvMemoryStream(), true ) );
+ aOleExport.ExportOLEObject( xObj, *xTempStorage );
+
+ //TODO/MBA: testing
+ SvMemoryStream aStream;
+ tools::SvRef<SotStorage> xCleanStorage( new SotStorage( false, aStream ) );
+ xTempStorage->CopyTo( xCleanStorage.get() );
+ // create a dummy content stream, the dummy content is necessary for ppt, but not for
+ // doc files, so we can't share code.
+ tools::SvRef<SotStorageStream> xStm = xCleanStorage->OpenSotStream( SVEXT_PERSIST_STREAM );
+ xStm->WriteUInt32( 0 ) // no ClipboardId
+ .WriteUInt32( 4 ) // no target device
+ .WriteUInt32( 1 ) // aspect ratio
+ .WriteInt32( -1 ) // L-Index
+ .WriteUInt32( 0 ) // Advanced Flags
+ .WriteUInt32( 0 ) // compression
+ .WriteUInt32( 0 ) // Size
+ .WriteUInt32( 0 ) // "
+ .WriteUInt32( 0 );
+ pStrm = xCleanStorage->CreateMemoryStream();
+ }
+ }
+ }
+ break;
+
+ case OCX_CONTROL :
+ {
+ if ( pPtr->xControlModel.is() )
+ {
+ OUString aName;
+ //Initialize the graphic size which will be used on export
+ css::awt::Size aSize( pPtr->xShape->getSize() );
+ tools::SvRef<SotStorage> xDest( new SotStorage( new SvMemoryStream(), true ) );
+ bool bOk = oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel, xDest, pPtr->xControlModel, aSize, aName );
+ if ( bOk )
+ pStrm = xDest->CreateMemoryStream();
+ }
+ }
+ }
+ if ( pStrm )
+ {
+ mpPptEscherEx->BeginAtom();
+ pStrm->Seek( STREAM_SEEK_TO_END );
+ sal_uInt32 npStrmSize = pStrm->Tell();
+ mpStrm->WriteUInt32( npStrmSize ); // uncompressed size
+
+ pStrm->Seek( 0 );
+ ZCodec aZCodec( 0x8000, 0x8000 );
+ aZCodec.BeginCompression();
+ aZCodec.Compress( *pStrm, *mpStrm );
+ aZCodec.EndCompression();
+ pStrm.reset();
+ mpPptEscherEx->EndAtom( EPP_ExOleObjStg, 0, 1 );
+ }
+ }
+}
+
+// write PersistantTable and UserEditAtom
+
+void PPTWriter::ImplWriteAtomEnding()
+{
+
+#define EPP_LastViewTypeSlideView 1
+
+ sal_uInt32 i, nPos, nOfs, nPersistOfs = mpStrm->Tell();
+ sal_uInt32 nPersistEntrys = 0;
+ mpStrm->WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ); // skip record header and first entry
+
+ // write document persist
+ nPersistEntrys++;
+ mpStrm->WriteUInt32( 0 );
+ // write MasterPages persists
+ for ( i = 0; i < mnMasterPages; i++ )
+ {
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainMaster | i );
+ if ( nOfs )
+ {
+ mpStrm->WriteUInt32( nOfs );
+ mpPptEscherEx->InsertAtPersistOffset( EPP_MAINMASTER_PERSIST_KEY | i, ++nPersistEntrys );
+ }
+ }
+ // write MainNotesMaster persist
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainNotes );
+ if ( nOfs )
+ {
+ mpStrm->WriteUInt32( nOfs );
+ mpPptEscherEx->InsertAtPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY, ++nPersistEntrys );
+ }
+ // write slide persists -> we have to write a valid value into EPP_SlidePersistAtome too
+ for ( i = 0; i < mnPages; i++ )
+ {
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Slide | i );
+ if ( nOfs )
+ {
+ mpStrm->WriteUInt32( nOfs );
+ mpPptEscherEx->InsertAtPersistOffset( EPP_MAINSLIDE_PERSIST_KEY | i, ++nPersistEntrys );
+ }
+ }
+ // write Notes persists
+ for ( i = 0; i < mnPages; i++ )
+ {
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Notes | i );
+ if ( nOfs )
+ {
+ mpStrm->WriteUInt32( nOfs );
+ mpPptEscherEx->InsertAtPersistOffset( EPP_MAINNOTES_PERSIST_KEY | i, ++nPersistEntrys );
+ }
+ }
+ // Ole persists
+ for ( const auto& rxExOleObjEntry : maExOleObj )
+ {
+ PPTExOleObjEntry* pPtr = rxExOleObjEntry.get();
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_ExObj );
+ if ( nOfs )
+ {
+ nPersistEntrys++;
+ mpStrm->WriteUInt32( pPtr->nOfsB );
+ sal_uInt32 nOldPos, nPersOfs = nOfs + pPtr->nOfsA + 16 + 8; // 8 bytes atom header, +16 to the persist entry
+ nOldPos = mpStrm->Tell();
+ mpStrm->Seek( nPersOfs );
+ mpStrm->WriteUInt32( nPersistEntrys );
+ mpStrm->Seek( nOldPos );
+ }
+ }
+ // VB persist
+ if ( mnVBAOleOfs && mpVBA )
+ {
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_VBAInfoAtom );
+ if ( nOfs )
+ {
+ nPersistEntrys++;
+ sal_uInt32 n1, n2;
+
+ mpVBA->Seek( 0 );
+ mpVBA->ReadUInt32( n1 )
+ .ReadUInt32( n2 );
+
+ mpStrm->WriteUInt32( mnVBAOleOfs );
+ sal_uInt32 nOldPos = mpStrm->Tell();
+ mpStrm->Seek( nOfs ); // Fill the VBAInfoAtom with the correct index to the persisttable
+ mpStrm->WriteUInt32( nPersistEntrys )
+ .WriteUInt32( n1 )
+ .WriteInt32( 2 );
+ mpStrm->Seek( nOldPos );
+
+ }
+ }
+ nPos = mpStrm->Tell();
+ mpStrm->Seek( nPersistOfs );
+ mpPptEscherEx->AddAtom( ( nPersistEntrys + 1 ) << 2, EPP_PersistPtrIncrementalBlock ); // insert Record Header
+ mpStrm->WriteUInt32( ( nPersistEntrys << 20 ) | 1 );
+ mpStrm->Seek( nPos );
+
+ mpCurUserStrm->WriteUInt32( nPos ); // set offset to current edit
+ mpPptEscherEx->AddAtom( 28, EPP_UserEditAtom );
+ mpStrm->WriteInt32( 0x100 ) // last slide ID
+ .WriteUInt32( 0x03000dbc ) // minor and major app version that did the save
+ .WriteUInt32( 0 ) // offset last save, 0 after a full save
+ .WriteUInt32( nPersistOfs ) // File offset to persist pointers for this save operation
+ .WriteUInt32( 1 ) // Persist reference to the document persist object
+ .WriteUInt32( nPersistEntrys ) // max persists written, Seed value for persist object id management
+ .WriteInt16( EPP_LastViewTypeSlideView ) // last view type
+ .WriteInt16( 0x12 ); // padword
+}
+
+// - exported function -
+
+extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool ExportPPT( const std::vector< css::beans::PropertyValue >& rMediaData,
+ tools::SvRef<SotStorage> const & rSvStorage,
+ css::uno::Reference< css::frame::XModel > const & rXModel,
+ css::uno::Reference< css::task::XStatusIndicator > const & rXStatInd,
+ SvMemoryStream* pVBA,
+ sal_uInt32 nCnvrtFlags )
+{
+ PPTWriter aPPTWriter( rSvStorage, rXModel, rXStatInd, pVBA, nCnvrtFlags );
+ aPPTWriter.exportPPT(rMediaData);
+ bool bStatus = aPPTWriter.IsValid();
+ return bStatus;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool SaveVBA( SfxObjectShell& rDocShell, SvMemoryStream*& pBas )
+{
+ tools::SvRef<SotStorage> xDest( new SotStorage( new SvMemoryStream(), true ) );
+ SvxImportMSVBasic aMSVBas( rDocShell, *xDest );
+ aMSVBas.SaveOrDelMSVBAStorage( true, "_MS_VBA_Overhead" );
+
+ tools::SvRef<SotStorage> xOverhead = xDest->OpenSotStorage( "_MS_VBA_Overhead" );
+ if ( xOverhead.is() && ( xOverhead->GetError() == ERRCODE_NONE ) )
+ {
+ tools::SvRef<SotStorage> xOverhead2 = xOverhead->OpenSotStorage( "_MS_VBA_Overhead" );
+ if ( xOverhead2.is() && ( xOverhead2->GetError() == ERRCODE_NONE ) )
+ {
+ tools::SvRef<SotStorageStream> xTemp = xOverhead2->OpenSotStream( "_MS_VBA_Overhead2" );
+ if ( xTemp.is() && ( xTemp->GetError() == ERRCODE_NONE ) )
+ {
+ sal_uInt32 nLen = xTemp->GetSize();
+ if ( nLen )
+ {
+ char* pTemp = new char[ nLen ];
+ xTemp->Seek( STREAM_SEEK_TO_BEGIN );
+ xTemp->ReadBytes(pTemp, nLen);
+ pBas = new SvMemoryStream( pTemp, nLen, StreamMode::READ );
+ pBas->ObjectOwnsMemory( true );
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/eppt.hxx b/sd/source/filter/eppt/eppt.hxx
new file mode 100644
index 000000000..eec839290
--- /dev/null
+++ b/sd/source/filter/eppt/eppt.hxx
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+#include <memory>
+#include <vector>
+#include "escherex.hxx"
+#include <sal/types.h>
+#include <sot/storage.hxx>
+#include "pptexsoundcollection.hxx"
+
+#include "text.hxx"
+
+#include <com/sun/star/presentation/AnimationEffect.hpp>
+#include <com/sun/star/presentation/ClickAction.hpp>
+
+#include "epptbase.hxx"
+
+namespace com::sun::star::awt { class XControlModel; }
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::beans { struct PropertyValue; }
+namespace com::sun::star::drawing { class XShape; }
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::task { class XStatusIndicator; }
+namespace com::sun::star::text { class XSimpleText; }
+
+class SotStorage;
+
+#define EPP_MAINMASTER_PERSIST_KEY 0x80010000
+#define EPP_MAINNOTESMASTER_PERSIST_KEY 0x80020000
+#define EPP_MAINSLIDE_PERSIST_KEY 0x80030000
+#define EPP_MAINNOTES_PERSIST_KEY 0x80040000
+
+#define EPP_Persist_Document 0x80080000
+#define EPP_Persist_MainMaster 0x80100000
+#define EPP_Persist_MainNotes 0x80200000
+#define EPP_Persist_Slide 0x80400000
+#define EPP_Persist_Notes 0x80800000
+#define EPP_Persist_CurrentPos 0x81000000
+#define EPP_Persist_VBAInfoAtom 0x84000000
+#define EPP_Persist_ExObj 0x88000000
+
+#define EPP_TEXTSTYLE_NORMAL 0x00000001
+#define EPP_TEXTSTYLE_TITLE 0x00000010
+#define EPP_TEXTSTYLE_BODY 0x00000100
+#define EPP_TEXTSTYLE_TEXT 0x00001000
+
+struct EPPTHyperlink
+{
+ OUString aURL;
+ sal_uInt32 nType; // bit 0-7 : type ( 1: click action to a slide )
+ // ( 2: hyperlink url )
+ // bit 8-23: index
+ // bit 31 : hyperlink is attached to a shape
+
+ EPPTHyperlink( const OUString& rURL, sal_uInt32 nT ) :
+ aURL ( rURL ),
+ nType ( nT ){};
+};
+
+enum PPTExOleObjEntryType
+{
+ NORMAL_OLE_OBJECT, OCX_CONTROL
+};
+
+struct PPTExOleObjEntry
+{
+ PPTExOleObjEntryType eType;
+ sal_uInt32 nOfsA; ///< offset to the EPP_ExOleObjAtom in mpExEmbed (set at creation)
+ sal_uInt32 nOfsB; ///< offset to the EPP_ExOleObjStg
+
+ css::uno::Reference< css::awt::XControlModel > xControlModel;
+ css::uno::Reference< css::drawing::XShape > xShape;
+
+ PPTExOleObjEntry(PPTExOleObjEntryType eT, sal_uInt32 nOfs)
+ : eType(eT)
+ , nOfsA(nOfs)
+ , nOfsB(0)
+ {}
+};
+
+struct TextRuleEntry
+{
+ std::unique_ptr<SvMemoryStream> pOut;
+};
+
+class TextObjBinary : public TextObj
+{
+public:
+ TextObjBinary( css::uno::Reference< css::text::XSimpleText > const & rXText,
+ int nInstance, FontCollection& rFontCollection, PPTExBulletProvider& rBuProv ) : TextObj( rXText, nInstance, rFontCollection, rBuProv ) {}
+ void Write( SvStream* pStrm );
+ void WriteTextSpecInfo( SvStream* pStrm );
+};
+
+struct CellBorder;
+class PPTWriter final : public PPTWriterBase, public PPTExBulletProvider
+{
+ sal_uInt32 mnCnvrtFlags;
+ bool mbStatus;
+ sal_uInt32 mnStatMaxValue;
+ sal_uInt32 mnLatestStatValue;
+
+ std::vector<OUString> maSlideNameList;
+ OUString maBaseURI;
+
+ css::uno::Reference< css::text::XSimpleText > mXText; // TextRef of the global text
+ sal_uInt32 mnTextStyle;
+
+ bool mbFontIndependentLineSpacing;
+ sal_uInt32 mnTextSize;
+
+ tools::SvRef<SotStorage> mrStg;
+ tools::SvRef<SotStorageStream> mpCurUserStrm;
+ tools::SvRef<SotStorageStream> mpStrm;
+ tools::SvRef<SotStorageStream> mpPicStrm;
+ std::unique_ptr<PptEscherEx> mpPptEscherEx;
+
+ std::vector<std::unique_ptr<PPTExOleObjEntry>> maExOleObj;
+ sal_uInt32 mnVBAOleOfs;
+ SvMemoryStream* mpVBA;
+ sal_uInt32 mnExEmbed;
+ std::unique_ptr<SvMemoryStream> mpExEmbed;
+
+ sal_uInt32 mnPagesWritten;
+ sal_uInt32 mnTxId; // Identifier determined by the HOST (PP) ????
+ sal_uInt32 mnDiaMode; // 0 -> manual
+ // 1 -> semi-automatic
+ // 2 -> automatic
+
+ sal_uInt32 mnShapeMasterTitle;
+ sal_uInt32 mnShapeMasterBody;
+
+ std::vector<EPPTHyperlink> maHyperlink;
+
+ ppt::ExSoundCollection maSoundCollection;
+
+ void ImplWriteExtParaHeader( SvMemoryStream& rSt, sal_uInt32 nRef, sal_uInt32 nInstance, sal_uInt32 nSlideId );
+
+ sal_uInt32 ImplProgBinaryTag( SvStream* pOutStrm );
+ sal_uInt32 ImplProgBinaryTagContainer( SvStream* pOutStrm, SvMemoryStream* pBinTag );
+ sal_uInt32 ImplProgTagContainer( SvStream* pOutStrm, SvMemoryStream* pBinTag = nullptr );
+ static sal_uInt32 ImplOutlineViewInfoContainer( SvStream* pOutStrm );
+ static sal_uInt32 ImplSlideViewInfoContainer( sal_uInt32 nInstance, SvStream* pOutStrm );
+ sal_uInt32 ImplVBAInfoContainer( SvStream* pOutStrm );
+ sal_uInt32 ImplDocumentListContainer( SvStream* pOutStrm );
+ sal_uInt32 ImplMasterSlideListContainer( SvStream* pOutStrm );
+
+ public:
+ static void WriteCString( SvStream&, const OUString&, sal_uInt32 nInstance = 0 );
+
+ private:
+
+ void ImplCreateDocumentSummaryInformation();
+ bool ImplCreateCurrentUserStream();
+ static void ImplCreateHeaderFooterStrings( SvStream& rOut,
+ css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet );
+ void ImplCreateHeaderFooters( css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet );
+ virtual bool ImplCreateDocument() override;
+ void ImplCreateHyperBlob( SvMemoryStream& rStream );
+ sal_uInt32 ImplInsertBookmarkURL( const OUString& rBookmark, const sal_uInt32 nType,
+ const OUString& rStringVer0, const OUString& rStringVer1, const OUString& rStringVer2, const OUString& rStringVer3 );
+ virtual bool ImplCreateMainNotes() override;
+ void ImplWriteBackground( css::uno::Reference< css::beans::XPropertySet > const & rXBackgroundPropSet );
+ void ImplWriteVBA();
+ void ImplWriteOLE();
+ void ImplWriteAtomEnding();
+
+ void ImplFlipBoundingBox( EscherPropertyContainer& rPropOpt );
+ bool ImplGetText();
+ bool ImplCreatePresentationPlaceholder( const bool bMaster,
+ const sal_uInt32 StyleInstance, const sal_uInt8 PlaceHolderId );
+ static bool ImplGetEffect( const css::uno::Reference< css::beans::XPropertySet > &,
+ css::presentation::AnimationEffect& eEffect,
+ css::presentation::AnimationEffect& eTextEffect,
+ bool& bHasSound );
+ void ImplWriteClickAction( SvStream& rSt, css::presentation::ClickAction eAction, bool bMediaClickAction );
+ void ImplWriteParagraphs( SvStream& rOutStrm, TextObj& rTextObj );
+ void ImplWritePortions( SvStream& rOutStrm, TextObj& rTextObj );
+ void ImplWriteTextStyleAtom( SvStream& rOut, int nTextInstance, sal_uInt32 nAtomInstance,
+ TextRuleEntry* pTextRule, SvStream& rExtBu, EscherPropertyContainer* );
+ void ImplAdjustFirstLineLineSpacing( TextObj& rTextObj, EscherPropertyContainer& rPropOpt );
+ void ImplCreateShape( sal_uInt32 nType, ShapeFlag nFlags, EscherSolverContainer& );
+ void ImplCreateTextShape( EscherPropertyContainer&, EscherSolverContainer&, bool bFill );
+
+ void ImplWritePage( const PHLayout& rLayout,
+ EscherSolverContainer& rSolver,
+ PageType ePageType,
+ bool bMaster,
+ int nPageNumber = 0 );
+ bool ImplCreateCellBorder( const CellBorder* pCellBorder, sal_Int32 nX1, sal_Int32 nY1, sal_Int32 nX2, sal_Int32 nY2 );
+ void ImplCreateTable( css::uno::Reference< css::drawing::XShape > const & rXShape, EscherSolverContainer& aSolverContainer,
+ EscherPropertyContainer& aPropOpt );
+
+ bool ImplCloseDocument(); // we write the font, hyper and sound list
+
+ virtual void ImplWriteSlide( sal_uInt32 nPageNum, sal_uInt32 nMasterID, sal_uInt16 nMode,
+ bool bHasBackground, css::uno::Reference< css::beans::XPropertySet > const & aXBackgroundPropSet ) override;
+ virtual void ImplWriteNotes( sal_uInt32 nPageNum ) override;
+ virtual void ImplWriteSlideMaster( sal_uInt32 nPageNum, css::uno::Reference< css::beans::XPropertySet > const & aXBackgroundPropSet ) override;
+
+ public:
+ PPTWriter( tools::SvRef<SotStorage> const & rSvStorage,
+ css::uno::Reference< css::frame::XModel > const & rModel,
+ css::uno::Reference< css::task::XStatusIndicator > const & rStatInd,
+ SvMemoryStream* pVBA, sal_uInt32 nCnvrtFlags );
+
+ virtual ~PPTWriter() override;
+
+ bool IsValid() const { return mbStatus; };
+
+ virtual void exportPPTPre( const std::vector< css::beans::PropertyValue >& ) override;
+ virtual void exportPPTPost( ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/epptbase.hxx b/sd/source/filter/eppt/epptbase.hxx
new file mode 100644
index 000000000..e8ac992e3
--- /dev/null
+++ b/sd/source/filter/eppt/epptbase.hxx
@@ -0,0 +1,412 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <vcl/mapmod.hxx>
+#include <tools/stream.hxx>
+#include <tools/fract.hxx>
+#include <tools/gen.hxx>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/presentation/FadeEffect.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <vcl/vclptr.hxx>
+#include <vcl/graph.hxx>
+
+#include "grouptable.hxx"
+
+namespace com::sun::star::task { class XStatusIndicator; }
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::awt { struct Rectangle; }
+namespace com::sun::star::drawing { class XMasterPagesSupplier; }
+namespace com::sun::star::drawing { class XDrawPage; }
+namespace com::sun::star::drawing { class XDrawPages; }
+namespace com::sun::star::drawing { class XDrawPagesSupplier; }
+namespace com::sun::star::beans { struct PropertyValue; }
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::drawing { class XShape; }
+namespace com::sun::star::drawing { class XShapes; }
+
+class VirtualDevice;
+
+// PLACEMENT_ID
+enum class EppLayout
+{
+ TITLESLIDE = 0, /* The slide is a title slide */
+ TITLEANDBODYSLIDE = 1, /* Title and body slide */
+ TITLEMASTERSLIDE = 2, /* Title master slide */
+ MASTERSLIDE = 3, /* Master slide layout */
+ MASTERNOTES = 4, /* Master notes layout */
+ NOTESTITLEBODY = 5, /* Notes title/body layout */
+ HANDOUTLAYOUT = 6, /* Handout layout, therefore it doesn't have placeholders except header, footer, and date */
+ ONLYTITLE = 7, /* Only title placeholder */
+ TWOCOLUMNSANDTITLE = 8, /* Body of the slide has 2 columns and a title */
+ TWOROWSANDTITLE = 9, /* Slide's body has 2 rows and a title */
+ RIGHTCOLUMN2ROWS = 10, /* Body contains 2 columns, right column has 2 rows */
+ LEFTCOLUMN2ROWS = 11, /* Body contains 2 columns, left column has 2 rows */
+ BOTTOMROW2COLUMNS = 12, /* Body contains 2 rows, bottom row has 2 columns */
+ TOPROW2COLUMN = 13, /* Body contains 2 rows, top row has 2 columns */
+ FOUROBJECTS = 14, /* 4 objects */
+ BIGOBJECT = 15, /* Big object */
+ BLANKSLIDE = 16, /* Blank slide */
+ TITLERIGHTBODYLEFT = 17, /* Vertical title on the right, body on the left */
+ TITLERIGHT2BODIESLEFT = 18 /* Vertical title on the right, body on the left split into 2 rows */
+};
+
+#define EPP_LAYOUT_SIZE 25
+
+struct PHLayout
+{
+ EppLayout nLayout;
+ sal_uInt8 nPlaceHolder[ 8 ];
+
+ sal_uInt8 nUsedObjectPlaceHolder;
+ sal_uInt8 nTypeOfTitle;
+ sal_uInt8 nTypeOfOutliner;
+
+ bool bTitlePossible;
+ bool bOutlinerPossible;
+ bool bSecOutlinerPossible;
+};
+
+enum PageType { NORMAL = 0, MASTER = 1, NOTICE = 2, UNDEFINED = 3, LAYOUT = 4 };
+
+class PropValue
+{
+ protected:
+
+ css::uno::Any mAny;
+ css::uno::Reference< css::beans::XPropertySet > mXPropSet;
+
+ bool ImplGetPropertyValue( const OUString& rString );
+ bool ImplGetPropertyValue( const css::uno::Reference
+ < css::beans::XPropertySet > &, const OUString& );
+
+ public:
+
+ PropValue() {}
+
+ static bool GetPropertyValue(
+ css::uno::Any& rAny,
+ const css::uno::Reference< css::beans::XPropertySet > &,
+ const OUString& rPropertyName,
+ bool bTestPropertyAvailability = false );
+
+ static css::beans::PropertyState GetPropertyState(
+ const css::uno::Reference < css::beans::XPropertySet > &,
+ const OUString& rPropertyName );
+};
+
+class EscherGraphicProvider;
+class PPTExBulletProvider
+{
+ friend struct PPTExParaSheet;
+
+ protected:
+
+ SvMemoryStream aBuExPictureStream;
+ SvMemoryStream aBuExOutlineStream;
+ SvMemoryStream aBuExMasterStream;
+
+ std::unique_ptr<EscherGraphicProvider>
+ pGraphicProv;
+
+ public:
+
+ sal_uInt16 GetId(Graphic const & rGraphic, Size& rGraphicSize);
+
+ PPTExBulletProvider();
+ ~PPTExBulletProvider();
+};
+
+struct FontCollectionEntry
+{
+ OUString Name;
+ double Scaling;
+ sal_Int16 Family;
+ sal_Int16 Pitch;
+ sal_Int16 CharSet;
+
+ OUString Original;
+
+ FontCollectionEntry( const OUString& rName, sal_Int16 nFamily, sal_Int16 nPitch, sal_Int16 nCharSet ) :
+ Scaling ( 1.0 ),
+ Family ( nFamily ),
+ Pitch ( nPitch ),
+ CharSet ( nCharSet ),
+ Original( rName )
+ {
+ ImplInit( rName );
+ };
+
+ explicit FontCollectionEntry( const OUString& rName ) :
+ Scaling ( 1.0 ),
+ Family ( 0 ),
+ Pitch ( 0 ),
+ CharSet ( 0 ),
+ Original( rName )
+ {
+ ImplInit( rName );
+ };
+
+ private:
+
+ void ImplInit( const OUString& rName );
+};
+
+class FontCollection
+{
+public:
+
+ FontCollection();
+
+ ~FontCollection();
+
+ static short GetScriptDirection( std::u16string_view rText );
+
+ sal_uInt32 GetId( FontCollectionEntry& rFontDescriptor );
+
+ sal_uInt32 GetCount() const { return maFonts.size(); };
+
+ const FontCollectionEntry* GetById( sal_uInt32 nId );
+
+ FontCollectionEntry& GetLast() { return *(maFonts.rbegin()); };
+
+private:
+
+ VclPtr<VirtualDevice> pVDev;
+ std::vector<FontCollectionEntry> maFonts;
+};
+
+#define PPTEX_STYLESHEETENTRIES 9
+
+enum PPTExTextAttr
+{
+ ParaAttr_BulletOn,
+ ParaAttr_BuHardFont,
+ ParaAttr_BuHardColor,
+ ParaAttr_BuHardHeight,
+ ParaAttr_BulletChar,
+ ParaAttr_BulletFont,
+ ParaAttr_BulletHeight,
+ ParaAttr_BulletColor,
+ ParaAttr_Adjust,
+ ParaAttr_LineFeed,
+ ParaAttr_UpperDist,
+ ParaAttr_LowerDist,
+ ParaAttr_TextOfs,
+ ParaAttr_BulletOfs,
+ ParaAttr_DefaultTab,
+ ParaAttr_BiDi,
+ CharAttr_Bold,
+ CharAttr_Italic,
+ CharAttr_Underline,
+ CharAttr_Shadow,
+ CharAttr_Strikeout,
+ CharAttr_Embossed,
+ CharAttr_Font,
+ CharAttr_AsianOrComplexFont,
+ CharAttr_Symbol,
+ CharAttr_FontHeight,
+ CharAttr_FontColor,
+ CharAttr_Escapement
+};
+
+struct PPTExCharLevel
+{
+ sal_uInt16 mnFlags;
+ sal_uInt16 mnFont;
+ sal_uInt16 mnAsianOrComplexFont;
+ sal_uInt16 mnFontHeight;
+ sal_uInt16 mnEscapement;
+ Color mnFontColor;
+};
+
+struct PPTExCharSheet
+{
+ PPTExCharLevel maCharLevel[ 5 ];
+
+ explicit PPTExCharSheet( int nInstance );
+
+ void SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > &,
+ FontCollection& rFontCollection, int nLevel );
+ void Write( SvStream& rSt, sal_uInt16 nLev, bool bSimpleText,
+ const css::uno::Reference< css::beans::XPropertySet > & rPagePropSet );
+
+};
+
+struct PPTExParaLevel
+{
+ bool mbIsBullet;
+ sal_uInt16 mnBulletChar;
+ sal_uInt16 mnBulletFont;
+ sal_uInt16 mnBulletHeight;
+ sal_uInt32 mnBulletColor;
+
+ sal_uInt16 mnAdjust;
+ sal_uInt16 mnLineFeed;
+ sal_uInt16 mnUpperDist;
+ sal_uInt16 mnLowerDist;
+ sal_uInt16 mnTextOfs;
+ sal_uInt16 mnBulletOfs;
+ sal_uInt16 mnDefaultTab;
+
+ bool mbExtendedBulletsUsed;
+ sal_uInt16 mnBulletId;
+ sal_uInt16 mnBulletStart;
+ sal_uInt32 mnMappedNumType;
+ sal_uInt32 mnNumberingType;
+ sal_uInt16 mnAsianSettings;
+ sal_uInt16 mnBiDi;
+};
+
+struct PPTExParaSheet
+{
+ PPTExBulletProvider* pBuProv;
+
+ sal_uInt32 mnInstance;
+
+ PPTExParaLevel maParaLevel[ 5 ];
+ PPTExParaSheet( int nInstance, sal_uInt16 nDefaultTab, PPTExBulletProvider* pProv );
+
+ void SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > &,
+ FontCollection& rFontCollection, int nLevel, const PPTExCharLevel& rCharLevel );
+ void Write( SvStream& rSt, sal_uInt16 nLev, bool bSimpleText,
+ const css::uno::Reference< css::beans::XPropertySet > & rPagePropSet );
+};
+
+class PPTExStyleSheet
+{
+
+ public:
+
+ std::unique_ptr<PPTExCharSheet> mpCharSheet[ PPTEX_STYLESHEETENTRIES ];
+ std::unique_ptr<PPTExParaSheet> mpParaSheet[ PPTEX_STYLESHEETENTRIES ];
+
+ PPTExStyleSheet( sal_uInt16 nDefaultTab, PPTExBulletProvider* pBuProv );
+ ~PPTExStyleSheet();
+
+ PPTExParaSheet& GetParaSheet( int nInstance ) { return *mpParaSheet[ nInstance ]; };
+
+ void SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > &,
+ FontCollection& rFontCollection, int nInstance, int nLevel );
+ bool IsHardAttribute( sal_uInt32 nInstance, sal_uInt32 nLevel, PPTExTextAttr eAttr, sal_uInt32 nValue );
+
+ static sal_uInt32 SizeOfTxCFStyleAtom() { return 24; }
+ void WriteTxCFStyleAtom( SvStream& rSt );
+};
+
+class PPTWriterBase : public PropValue, public GroupTable
+{
+protected:
+ css::uno::Reference< css::frame::XModel > mXModel;
+ css::uno::Reference< css::task::XStatusIndicator > mXStatusIndicator;
+
+ bool mbStatusIndicator;
+
+ css::uno::Reference< css::drawing::XDrawPagesSupplier > mXDrawPagesSupplier;
+ css::uno::Reference< css::drawing::XMasterPagesSupplier > mXMasterPagesSupplier;
+ css::uno::Reference< css::drawing::XDrawPages > mXDrawPages;
+ css::uno::Reference< css::drawing::XDrawPage > mXDrawPage;
+ css::uno::Reference< css::beans::XPropertySet > mXPagePropSet;
+ css::uno::Reference< css::beans::XPropertySet > mXBackgroundPropSet;
+ css::uno::Reference< css::drawing::XShapes > mXShapes;
+ css::uno::Reference< css::drawing::XShape > mXShape;
+ css::awt::Size maSize;
+ css::awt::Point maPosition;
+ ::tools::Rectangle maRect;
+ OString mType;
+ bool mbPresObj;
+ bool mbEmptyPresObj;
+ bool mbIsBackgroundDark;
+ sal_Int32 mnAngle;
+
+ sal_uInt32 mnPages; ///< number of Slides ( w/o master pages & notes & handout )
+ sal_uInt32 mnMasterPages;
+
+ Fraction maFraction;
+ MapMode maMapModeSrc;
+ MapMode maMapModeDest;
+ css::awt::Size maDestPageSize;
+ css::awt::Size maPageSize; // #i121183# Keep size in logic coordinates (100th mm)
+ css::awt::Size maNotesPageSize;
+
+ PageType meLatestPageType;
+ std::vector< std::unique_ptr<PPTExStyleSheet> > maStyleSheetList;
+ PPTExStyleSheet* mpStyleSheet;
+
+ FontCollection maFontCollection;
+
+ virtual void ImplWriteSlide( sal_uInt32 /* nPageNum */, sal_uInt32 /* nMasterNum */, sal_uInt16 /* nMode */,
+ bool /* bHasBackground */, css::uno::Reference< css::beans::XPropertySet > const & /* aXBackgroundPropSet */ ) {}
+ virtual void ImplWriteNotes( sal_uInt32 nPageNum ) = 0;
+ virtual void ImplWriteSlideMaster( sal_uInt32 /* nPageNum */, css::uno::Reference< css::beans::XPropertySet > const & /* aXBackgroundPropSet */ ) {}
+
+ virtual void exportPPTPre( const std::vector< css::beans::PropertyValue >& ) {}
+ virtual void exportPPTPost() {}
+
+ virtual bool ImplCreateDocument()=0;
+ virtual bool ImplCreateMainNotes()=0;
+
+ bool GetStyleSheets();
+ bool GetShapeByIndex( sal_uInt32 nIndex, bool bGroup );
+
+ bool CreateMainNotes();
+
+ css::awt::Size MapSize( const css::awt::Size& );
+ css::awt::Point MapPoint( const css::awt::Point& );
+ ::tools::Rectangle MapRectangle( const css::awt::Rectangle& );
+
+ bool ContainsOtherShapeThanPlaceholders();
+
+public:
+ PPTWriterBase();
+ PPTWriterBase( const css::uno::Reference< css::frame::XModel > & rModel,
+ const css::uno::Reference< css::task::XStatusIndicator > & rStatInd );
+
+ virtual ~PPTWriterBase();
+
+ void exportPPT(const std::vector< css::beans::PropertyValue >&);
+
+ bool InitSOIface();
+ bool GetPageByIndex( sal_uInt32 nIndex, PageType );
+ sal_uInt32 GetMasterIndex( PageType ePageType );
+ void SetCurrentStyleSheet( sal_uInt32 nPageNum );
+
+ bool GetPresObj() const { return mbPresObj; }
+
+ static PHLayout const & GetLayout( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet );
+ static PHLayout const & GetLayout( sal_Int32 nOffset );
+ static sal_Int32 GetLayoutOffset( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet );
+ static sal_Int32 GetLayoutOffsetFixed( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet );
+
+ bool CreateSlide( sal_uInt32 nPageNum );
+ bool CreateSlideMaster( sal_uInt32 nPageNum );
+ bool CreateNotes( sal_uInt32 nPageNum );
+
+ static sal_Int8 GetTransition( sal_Int16 nTransitionType, sal_Int16 nTransitionSubtype, css::presentation::FadeEffect eEffect,
+ sal_Int32 nTransitionFadeColor, sal_uInt8& nDirection );
+ static sal_Int8 GetTransition( css::presentation::FadeEffect eEffect, sal_uInt8& nDirection );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/epptdef.hxx b/sd/source/filter/eppt/epptdef.hxx
new file mode 100644
index 000000000..f5059681c
--- /dev/null
+++ b/sd/source/filter/eppt/epptdef.hxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#define EPP_Document 1000
+#define EPP_DocumentAtom 1001
+#define EPP_EndDocument 1002
+#define EPP_Slide 1006
+#define EPP_SlideAtom 1007
+#define EPP_Notes 1008
+#define EPP_NotesAtom 1009
+#define EPP_Environment 1010
+#define EPP_SlidePersistAtom 1011 //0x03F3
+#define EPP_MainMaster 1016
+#define EPP_SSSlideInfoAtom 1017
+#define EPP_SlideViewInfo 1018
+#define EPP_GuideAtom 1019
+#define EPP_ViewInfoAtom 1021
+#define EPP_SlideViewInfoAtom 1022
+#define EPP_VBAInfo 1023
+#define EPP_VBAInfoAtom 1024
+#define EPP_SSDocInfoAtom 1025
+#define EPP_OutlineViewInfo 1031
+#define EPP_ExObjList 1033
+#define EPP_ExObjListAtom 1034
+#define EPP_PPDrawingGroup 1035
+#define EPP_PPDrawing 1036
+#define EPP_NamedShows 1040
+#define EPP_NamedShow 1041
+#define EPP_NamedShowSlides 1042
+#define EPP_List 2000
+#define EPP_FontCollection 2005
+#define EPP_SoundCollection 2020
+#define EPP_SoundCollAtom 2021
+#define EPP_Sound 2022
+#define EPP_SoundData 2023
+#define EPP_ColorSchemeAtom 2032
+
+// these atoms first was seen in ppt2000 in a private Tag atom
+#define EPP_PST_ExtendedBuGraContainer 2040 // consist of 4041
+
+#define EPP_ExObjRefAtom 3009
+#define EPP_OEPlaceholderAtom 3011
+#define EPP_TextHeaderAtom 3999
+#define EPP_TextCharsAtom 4000
+#define EPP_StyleTextPropAtom 4001
+#define EPP_BaseTextPropAtom 4002
+#define EPP_TxMasterStyleAtom 4003
+#define EPP_TxCFStyleAtom 4004
+#define EPP_TextRulerAtom 4006
+#define EPP_TxSIStyleAtom 4009
+#define EPP_TextSpecInfoAtom 4010
+
+// these atoms first was seen in ppt2000 in a private Tag atom
+#define EPP_PST_ExtendedParagraphAtom 4012
+#define EPP_PST_ExtendedParagraphMasterAtom 4013
+#define EPP_PST_ExtendedPresRuleContainer 4014 // consist of 4012, 4015,
+#define EPP_PST_ExtendedParagraphHeaderAtom 4015 // the instance of this atom indices the current presobj
+ // the first sal_uInt32 in this atom indices the current slideId
+
+#define EPP_FontEnityAtom 4023
+#define EPP_CString 4026
+#define EPP_ExOleObjAtom 4035
+#define EPP_SrKinsoku 4040
+#define EPP_ExEmbed 4044
+#define EPP_ExEmbedAtom 4045
+#define EPP_SrKinsokuAtom 4050
+#define EPP_ExHyperlinkAtom 4051
+#define EPP_ExHyperlink 4055
+#define EPP_SlideNumberMCAtom 4056
+#define EPP_HeadersFooters 4057
+#define EPP_HeadersFootersAtom 4058
+#define EPP_TxInteractiveInfoAtom 4063
+#define EPP_ExControl 4078
+#define EPP_ExControlAtom 4091
+#define EPP_SlideListWithText 4080 // 0x0FF0
+#define EPP_AnimationInfoAtom 4081
+#define EPP_InteractiveInfo 4082
+#define EPP_InteractiveInfoAtom 4083
+#define EPP_UserEditAtom 4085
+#define EPP_CurrentUserAtom 4086
+#define EPP_DateTimeMCAtom 4087
+#define EPP_GenericDateMCAtom 4088
+#define EPP_HeaderMCAtom 4089
+#define EPP_FooterMCAtom 4090
+#define EPP_ExMediaAtom 4100
+#define EPP_ExVideo 4101
+#define EPP_ExMCIMovie 4103
+#define EPP_ExOleObjStg 4113
+#define EPP_AnimationInfo 4116
+#define EPP_ProgTags 5000
+#define EPP_ProgBinaryTag 5002
+#define EPP_BinaryTagData 5003
+#define EPP_PersistPtrIncrementalBlock 6002
+#define EPP_Comment10 12000
+#define EPP_CommentAtom10 12001
+
+#define EPP_PLACEHOLDER_NONE 0 // 0 None
+#define EPP_PLACEHOLDER_MASTERTITLE 1 // 1 Master title
+#define EPP_PLACEHOLDER_MASTERBODY 2 // 2 Master body
+#define EPP_PLACEHOLDER_MASTERSUBTITLE 4 // 10 Master subtitle
+#define EPP_PLACEHOLDER_MASTERNOTESSLIDEIMAGE 5 // 4 Master notes slide image
+#define EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE 6 // 5 Master notes body image
+#define EPP_PLACEHOLDER_MASTERDATE 7 // 6 Master date
+#define EPP_PLACEHOLDER_MASTERSLIDENUMBER 8 // 7 Master slide number
+#define EPP_PLACEHOLDER_MASTERFOOTER 9 // 8 Master footer
+#define EPP_PLACEHOLDER_MASTERHEADER 10 // 9 Master header
+#define EPP_PLACEHOLDER_GENERICTEXTOBJECT // 11 Generic text object
+#define EPP_PLACEHOLDER_NOTESBODY 12 // 14 Notes body
+#define EPP_PLACEHOLDER_NOTESSLIDEIMAGE 11 // 19 Notes slide image
+
+#define EPP_TEXTTYPE_Title 0
+#define EPP_TEXTTYPE_Body 1
+#define EPP_TEXTTYPE_Notes 2
+#define EPP_TEXTTYPE_notUsed 3
+#define EPP_TEXTTYPE_Other 4 // ( Text in a shape )
+#define EPP_TEXTTYPE_CenterBody 5 // ( subtitle in title slide )
+#define EPP_TEXTTYPE_CenterTitle 6 // ( title in title slide )
+#define EPP_TEXTTYPE_HalfBody 7 // ( body in two-column slide )
+#define EPP_TEXTTYPE_QuarterBody 8 // ( body in four-body slide )
+
+#define EPP_SLIDESIZE_TYPEONSCREEN 0
+#define EPP_SLIDESIZE_TYPEA4PAPER 2
+#define EPP_SLIDESIZE_TYPE35MM 3
+#define EPP_SLIDESIZE_TYPEBANNER 5
+#define EPP_SLIDESIZE_TYPECUSTOM 6
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/epptooxml.hxx b/sd/source/filter/eppt/epptooxml.hxx
new file mode 100644
index 000000000..5ee3248ec
--- /dev/null
+++ b/sd/source/filter/eppt/epptooxml.hxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <oox/core/xmlfilterbase.hxx>
+#include <oox/vml/vmldrawing.hxx>
+#include <oox/export/shapes.hxx>
+#include "epptbase.hxx"
+
+using ::sax_fastparser::FSHelperPtr;
+
+namespace svx
+{
+class Theme;
+}
+
+namespace oox::core {
+
+struct LayoutInfo
+{
+ std::vector< sal_Int32 > mnFileIdArray;
+};
+
+enum PlaceholderType
+{
+ None,
+ SlideImage,
+ Notes,
+ Header,
+ Footer,
+ SlideNumber,
+ DateAndTime,
+ Outliner,
+ Title,
+ Subtitle
+};
+
+class PowerPointShapeExport;
+
+class PowerPointExport final : public XmlFilterBase, public PPTWriterBase
+{
+ friend class PowerPointShapeExport;
+public:
+
+ PowerPointExport(const css::uno::Reference<css::uno::XComponentContext> & rContext, const css::uno::Sequence<css::uno::Any>& rArguments);
+
+ virtual ~PowerPointExport() override;
+
+ // from FilterBase
+ virtual bool importDocument() noexcept override;
+ virtual bool exportDocument() override;
+
+ // only needed for import, leave them empty, refactor later XmlFilterBase to export and import base?
+ virtual oox::vml::Drawing* getVmlDrawing() override { return nullptr; }
+ virtual const oox::drawingml::Theme* getCurrentTheme() const override { return nullptr; }
+ virtual oox::drawingml::table::TableStyleListPtr getTableStyles() override { return oox::drawingml::table::TableStyleListPtr(); }
+ virtual oox::drawingml::chart::ChartConverter* getChartConverter() override { return nullptr; }
+
+ static const char* GetSideDirection( sal_uInt8 nDirection );
+ static const char* GetCornerDirection( sal_uInt8 nDirection );
+ static const char* Get8Direction( sal_uInt8 nDirection );
+ static int GetPPTXLayoutId( int nOffset );
+
+ sal_Int32 GetShapeID(const css::uno::Reference<css::drawing::XShape>& rXShape);
+ sal_Int32 GetNextAnimationNodeID();
+
+ void embedEffectAudio(const FSHelperPtr& pFS, const OUString& sUrl, OUString& sRelId, OUString& sName);
+
+private:
+
+ virtual void ImplWriteSlide( sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 nMode,
+ bool bHasBackground, css::uno::Reference< css::beans::XPropertySet > const & aXBackgroundPropSet ) override;
+ virtual void ImplWriteNotes( sal_uInt32 nPageNum ) override;
+ virtual void ImplWriteSlideMaster( sal_uInt32 nPageNum, css::uno::Reference< css::beans::XPropertySet > const & aXBackgroundPropSet ) override;
+ void ImplWritePPTXLayout( sal_Int32 nOffset, sal_uInt32 nMasterNum );
+
+ /// Export the color set part of a theme.
+ static bool WriteColorSets(const FSHelperPtr& pFS, svx::Theme* pTheme);
+
+ /// Same as WriteColorSets(), but works from a grab-bag.
+ bool WriteColorSchemes(const FSHelperPtr& pFS, const OUString& rThemePath);
+
+ static void WriteDefaultColorSchemes(const FSHelperPtr& pFS);
+ void WriteTheme( sal_Int32 nThemeNum, svx::Theme* pTheme );
+
+ virtual bool ImplCreateDocument() override;
+ virtual bool ImplCreateMainNotes() override;
+ virtual ::oox::ole::VbaProject* implCreateVbaProject() const override;
+ void WriteNotesMaster();
+
+ bool WriteComments( sal_uInt32 nPageNum );
+ void ImplWriteBackground( const ::sax_fastparser::FSHelperPtr& pFS, const css::uno::Reference< css::beans::XPropertySet >& aXBackgroundPropSet );
+ void WriteTransition( const ::sax_fastparser::FSHelperPtr& pFS );
+
+ sal_Int32 GetLayoutFileId( sal_Int32 nOffset, sal_uInt32 nMasterNum );
+
+ // shapes
+ void WriteShapeTree( const ::sax_fastparser::FSHelperPtr& pFS, PageType ePageType, bool bMaster );
+
+ sal_uInt32 GetNewSlideId() { return mnSlideIdMax ++; }
+ sal_uInt32 GetNewSlideMasterId() { return mnSlideMasterIdMax ++; }
+ sal_Int32 GetAuthorIdAndLastIndex( const OUString& sAuthor, sal_Int32& nLastIndex );
+
+ // Write docProps/core.xml and docprops/custom.xml and docprops/app.xml
+ void writeDocumentProperties();
+
+ void WriteCustomSlideShow();
+
+ void AddLayoutIdAndRelation( const ::sax_fastparser::FSHelperPtr& pFS, sal_Int32 nLayoutFileId );
+
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ static void WriteDiagram(const FSHelperPtr& pFS, PowerPointShapeExport& rDML, const css::uno::Reference<css::drawing::XShape>& rXShape, int nDiagramId);
+
+ /** Create a new placeholder index for a master placeholder shape
+
+ @param rXShape Master placeholder shape
+ @returns Placeholder index
+ */
+ sal_Int32 CreateNewPlaceholderIndex(const css::uno::Reference<css::drawing::XShape>& rXShape);
+ css::uno::Reference<css::drawing::XShape> GetReferencedPlaceholderXShape(const PlaceholderType eType, PageType ePageType) const;
+ void WritePlaceholderReferenceShapes(PowerPointShapeExport& rDML, PageType ePageType);
+
+ /// Should we export as .pptm, ie. do we contain macros?
+ bool mbPptm;
+
+ // Export as a template
+ bool mbExportTemplate;
+
+ ::sax_fastparser::FSHelperPtr mPresentationFS;
+
+ LayoutInfo mLayoutInfo[EPP_LAYOUT_SIZE];
+ std::vector< ::sax_fastparser::FSHelperPtr > mpSlidesFSArray;
+ sal_Int32 mnLayoutFileIdMax;
+
+ sal_uInt32 mnSlideIdMax;
+ sal_uInt32 mnSlideMasterIdMax;
+ sal_uInt32 mnAnimationNodeIdMax;
+
+ sal_uInt32 mnDiagramId;
+
+ std::vector<OUString> maRelId;
+
+ bool mbCreateNotes;
+
+ ::oox::drawingml::ShapeExport::ShapeHashMap maShapeMap;
+
+ sal_Int32 mnPlaceholderIndexMax; ///< Last used placeholder index
+ /// Map of placeholder indexes for Master placeholders
+ std::unordered_map< css::uno::Reference<css::drawing::XShape>, sal_Int32 > maPlaceholderShapeToIndexMap;
+
+ struct AuthorComments {
+ sal_Int32 nId;
+ sal_Int32 nLastIndex;
+ };
+ typedef std::unordered_map< OUString, struct AuthorComments > AuthorsMap;
+ AuthorsMap maAuthors;
+
+ void WriteAuthors();
+
+ void WritePresentationProps();
+
+ /// If this is PPTM, output the VBA stream.
+ void WriteVBA();
+
+ void WriteModifyVerifier();
+};
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/epptso.cxx b/sd/source/filter/eppt/epptso.cxx
new file mode 100644
index 000000000..41126aedf
--- /dev/null
+++ b/sd/source/filter/eppt/epptso.cxx
@@ -0,0 +1,3361 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+
+#include <basegfx/numeric/ftools.hxx>
+#include <o3tl/any.hxx>
+#include "eppt.hxx"
+#include "text.hxx"
+#include "epptdef.hxx"
+#include "escherex.hxx"
+#include <tools/poly.hxx>
+#include <tools/stream.hxx>
+#include <tools/fontenum.hxx>
+#include <tools/UnitConversion.hxx>
+#include <sot/storage.hxx>
+#include <vcl/graph.hxx>
+#include <editeng/svxenum.hxx>
+#include <svx/svdobj.hxx>
+#include <com/sun/star/awt/FontFamily.hpp>
+#include <com/sun/star/awt/FontPitch.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/style/TabStop.hpp>
+#include <com/sun/star/drawing/CircleKind.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <tools/urlobj.hxx>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/table/XTable.hpp>
+#include <com/sun/star/table/XMergeableCell.hpp>
+#include <com/sun/star/table/BorderLine.hpp>
+#include <com/sun/star/table/XColumnRowRange.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <oox/ole/olehelper.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+using namespace ::com::sun::star;
+
+#define ANSI_CHARSET 0
+#define SYMBOL_CHARSET 2
+
+/* Font Families */
+#define FF_ROMAN 0x10
+#define FF_SWISS 0x20
+#define FF_MODERN 0x30
+#define FF_SCRIPT 0x40
+#define FF_DECORATIVE 0x50
+
+#define DEFAULT_PITCH 0x00
+#define FIXED_PITCH 0x01
+
+PPTExBulletProvider::PPTExBulletProvider()
+ : pGraphicProv( new EscherGraphicProvider( EscherGraphicProviderFlags::UseInstances ) )
+{
+}
+
+PPTExBulletProvider::~PPTExBulletProvider()
+{
+}
+
+sal_uInt16 PPTExBulletProvider::GetId(Graphic const & rGraphic, Size& rGraphicSize )
+{
+ sal_uInt16 nRetValue = 0xffff;
+
+ if (!rGraphic.IsNone())
+ {
+ Graphic aMappedGraphic, aGraphic(rGraphic);
+ GraphicObject aGraphicObject(aGraphic);
+ Size aPrefSize( aGraphic.GetPrefSize() );
+ BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
+
+ if ( rGraphicSize.Width() && rGraphicSize.Height() )
+ {
+ if (aPrefSize.IsEmpty())
+ {
+ aBmpEx.Scale(aPrefSize);
+ }
+ else
+ {
+ double fQ1 = static_cast<double>(aPrefSize.Width()) / static_cast<double>(aPrefSize.Height());
+ double fQ2 = static_cast<double>(rGraphicSize.Width()) / static_cast<double>(rGraphicSize.Height());
+ double fXScale = 1;
+ double fYScale = 1;
+
+ if ( fQ1 > fQ2 )
+ fYScale = fQ1 / fQ2;
+ else if ( fQ1 < fQ2 )
+ fXScale = fQ2 / fQ1;
+
+ if ( ( fXScale != 1.0 ) || ( fYScale != 1.0 ) )
+ {
+ aBmpEx.Scale( fXScale, fYScale );
+ rGraphicSize = Size( static_cast<sal_Int32>(static_cast<double>(rGraphicSize.Width()) / fXScale + 0.5 ),
+ static_cast<sal_Int32>(static_cast<double>(rGraphicSize.Height()) / fYScale + 0.5 ) );
+
+ aMappedGraphic = Graphic( aBmpEx );
+ aGraphicObject.SetGraphic(aMappedGraphic);
+ }
+ }
+ }
+ sal_uInt32 nId = pGraphicProv->GetBlibID(aBuExPictureStream, aGraphicObject);
+
+ if ( nId && ( nId < 0x10000 ) )
+ nRetValue = static_cast<sal_uInt16>(nId) - 1;
+ }
+ return nRetValue;
+}
+
+sal_uInt32 PPTWriter::ImplVBAInfoContainer( SvStream* pStrm )
+{
+ sal_uInt32 nSize = 28;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( 0x1f | ( EPP_VBAInfo << 16 ) )
+ .WriteUInt32( nSize - 8 )
+ .WriteUInt32( 2 | ( EPP_VBAInfoAtom << 16 ) )
+ .WriteUInt32( 12 );
+ mpPptEscherEx->InsertPersistOffset( EPP_Persist_VBAInfoAtom, pStrm->Tell() );
+ pStrm->WriteUInt32( 0 )
+ .WriteUInt32( 0 )
+ .WriteUInt32( 1 );
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplSlideViewInfoContainer( sal_uInt32 nInstance, SvStream* pStrm )
+{
+ sal_uInt32 nSize = 111;
+ if ( pStrm )
+ {
+ sal_uInt8 bShowGuides = 0;
+ sal_uInt8 const bSnapToGrid = 1;
+ sal_uInt8 const bSnapToShape = 0;
+
+ sal_Int32 nScaling = 85;
+ sal_Int32 nMasterCoordinate = 0xdda;
+ sal_Int32 nXOrigin = -780;
+ sal_Int32 nYOrigin = -84;
+
+ sal_Int32 nPosition1 = 0x870;
+ sal_Int32 nPosition2 = 0xb40;
+
+ if ( nInstance )
+ {
+ bShowGuides = 1;
+ nScaling = 0x3b;
+ nMasterCoordinate = 0xf0c;
+ nXOrigin = -1752;
+ nYOrigin = -72;
+ nPosition1 = 0xb40;
+ nPosition2 = 0x870;
+ }
+ pStrm->WriteUInt32( 0xf | ( EPP_SlideViewInfo << 16 ) | ( nInstance << 4 ) )
+ .WriteUInt32( nSize - 8 )
+ .WriteUInt32( EPP_SlideViewInfoAtom << 16 ).WriteUInt32( 3 )
+ .WriteUChar( bShowGuides ).WriteUChar( bSnapToGrid ).WriteUChar( bSnapToShape )
+ .WriteUInt32( EPP_ViewInfoAtom << 16 ).WriteUInt32( 52 )
+ .WriteInt32( nScaling ).WriteInt32( 100 ).WriteInt32( nScaling ).WriteInt32( 100 ) // scaling atom - Keeps the current scale
+ .WriteInt32( nScaling ).WriteInt32( 100 ).WriteInt32( nScaling ).WriteInt32( 100 ) // scaling atom - Keeps the previous scale
+ .WriteInt32( 0x17ac ).WriteInt32( nMasterCoordinate )// Origin - Keeps the origin in master coordinates
+ .WriteInt32( nXOrigin ).WriteInt32( nYOrigin ) // Origin
+ .WriteUChar( 1 ) // Bool1 varScale - Set if zoom to fit is set
+ .WriteUChar( 0 ) // bool1 draftMode - Not used
+ .WriteUInt16( 0 ) // padword
+ .WriteUInt32( ( 7 << 4 ) | ( EPP_GuideAtom << 16 ) ).WriteUInt32( 8 )
+ .WriteUInt32( 0 ) // Type of the guide. If the guide is horizontal this value is zero. If it's vertical, it's one.
+ .WriteInt32( nPosition1 ) // Position of the guide in master coordinates. X coordinate if it's vertical, and Y coordinate if it's horizontal.
+ .WriteUInt32( ( 7 << 4 ) | ( EPP_GuideAtom << 16 ) ).WriteUInt32( 8 )
+ .WriteInt32( 1 ) // Type of the guide. If the guide is horizontal this value is zero. If it's vertical, it's one.
+ .WriteInt32( nPosition2 ); // Position of the guide in master coordinates. X coordinate if it's vertical, and Y coordinate if it's horizontal.
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplOutlineViewInfoContainer( SvStream* pStrm )
+{
+ sal_uInt32 nSize = 68;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( 0xf | ( EPP_OutlineViewInfo << 16 ) ).WriteUInt32( nSize - 8 )
+ .WriteUInt32( EPP_ViewInfoAtom << 16 ).WriteUInt32( 52 )
+ .WriteInt32( 170 ).WriteInt32( 200 ).WriteInt32( 170 ).WriteInt32( 200 ) // scaling atom - Keeps the current scale
+ .WriteInt32( 170 ).WriteInt32( 200 ).WriteInt32( 170 ).WriteInt32( 200 ) // scaling atom - Keeps the previous scale
+ .WriteInt32( 0x17ac ).WriteInt32( 0xdda ) // Origin - Keeps the origin in master coordinates
+ .WriteInt32( -780 ).WriteInt32( -84 ) // Origin
+ .WriteUChar( 1 ) // bool1 varScale - Set if zoom to fit is set
+ .WriteUChar( 0 ) // bool1 draftMode - Not used
+ .WriteUInt16( 0 ); // padword
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplProgBinaryTag( SvStream* pStrm )
+{
+ sal_uInt32 nPictureStreamSize, nOutlineStreamSize, nSize = 8;
+
+ nPictureStreamSize = aBuExPictureStream.Tell();
+ if ( nPictureStreamSize )
+ nSize += nPictureStreamSize + 8;
+
+ nOutlineStreamSize = aBuExOutlineStream.Tell();
+ if ( nOutlineStreamSize )
+ nSize += nOutlineStreamSize + 8;
+
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( EPP_BinaryTagData << 16 ).WriteUInt32( nSize - 8 );
+ if ( nPictureStreamSize )
+ {
+ pStrm->WriteUInt32( 0xf | ( EPP_PST_ExtendedBuGraContainer << 16 ) ).WriteUInt32( nPictureStreamSize );
+ pStrm->WriteBytes(aBuExPictureStream.GetData(), nPictureStreamSize);
+ }
+ if ( nOutlineStreamSize )
+ {
+ pStrm->WriteUInt32( 0xf | ( EPP_PST_ExtendedPresRuleContainer << 16 ) ).WriteUInt32( nOutlineStreamSize );
+ pStrm->WriteBytes(aBuExOutlineStream.GetData(), nOutlineStreamSize);
+ }
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplProgBinaryTagContainer( SvStream* pStrm, SvMemoryStream* pBinTagStrm )
+{
+ sal_uInt32 nSize = 8 + 8 + 14;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( 0xf | ( EPP_ProgBinaryTag << 16 ) ).WriteUInt32( 0 )
+ .WriteUInt32( EPP_CString << 16 ).WriteUInt32( 14 )
+ .WriteUInt32( 0x5f005f ).WriteUInt32( 0x50005f )
+ .WriteUInt32( 0x540050 ).WriteUInt16( 0x39 );
+ }
+ if ( pStrm && pBinTagStrm )
+ {
+ sal_uInt32 nLen = pBinTagStrm->Tell();
+ nSize += nLen + 8;
+ pStrm->WriteUInt32( EPP_BinaryTagData << 16 ).WriteUInt32( nLen );
+ pStrm->WriteBytes(pBinTagStrm->GetData(), nLen);
+ }
+ else
+ nSize += ImplProgBinaryTag( pStrm );
+
+ if ( pStrm )
+ {
+ pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
+ pStrm->WriteUInt32( nSize - 8 );
+ pStrm->SeekRel( nSize - 8 );
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplProgTagContainer( SvStream* pStrm, SvMemoryStream* pBinTagStrm )
+{
+ sal_uInt32 nSize = 0;
+ if ( aBuExPictureStream.Tell() || aBuExOutlineStream.Tell() || pBinTagStrm )
+ {
+ nSize = 8;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( 0xf | ( EPP_ProgTags << 16 ) ).WriteUInt32( 0 );
+ }
+ nSize += ImplProgBinaryTagContainer( pStrm, pBinTagStrm );
+ if ( pStrm )
+ {
+ pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
+ pStrm->WriteUInt32( nSize - 8 );
+ pStrm->SeekRel( nSize - 8 );
+ }
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplDocumentListContainer( SvStream* pStrm )
+{
+ sal_uInt32 nSize = 8;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( ( EPP_List << 16 ) | 0xf ).WriteUInt32( 0 );
+ }
+
+ nSize += ImplVBAInfoContainer( pStrm );
+ nSize += ImplSlideViewInfoContainer( 0, pStrm );
+ nSize += ImplOutlineViewInfoContainer( pStrm );
+ nSize += ImplSlideViewInfoContainer( 1, pStrm );
+ nSize += ImplProgTagContainer( pStrm );
+
+ if ( pStrm )
+ {
+ pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
+ pStrm->WriteUInt32( nSize - 8 );
+ pStrm->SeekRel( nSize - 8 );
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplMasterSlideListContainer( SvStream* pStrm )
+{
+ sal_uInt32 i, nSize = 28 * mnMasterPages + 8;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( 0x1f | ( EPP_SlideListWithText << 16 ) ).WriteUInt32( nSize - 8 );
+
+ for ( i = 0; i < mnMasterPages; i++ )
+ {
+ pStrm->WriteUInt32( EPP_SlidePersistAtom << 16 ).WriteUInt32( 20 );
+ mpPptEscherEx->InsertPersistOffset( EPP_MAINMASTER_PERSIST_KEY | i, pStrm->Tell() );
+ pStrm->WriteUInt32( 0 ) // psrReference - logical reference to the slide persist object ( EPP_MAINMASTER_PERSIST_KEY )
+ .WriteUInt32( 0 ) // flags - only bit 3 used, if set then slide contains shapes other than placeholders
+ .WriteInt32( 0 ) // numberTexts - number of placeholder texts stored with the persist object. Allows to display outline view without loading the slide persist objects
+ .WriteInt32( 0x80000000 | i ) // slideId - Unique slide identifier, used for OLE link monikers for example
+ .WriteUInt32( 0 ); // reserved, usually 0
+ }
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplInsertBookmarkURL( const OUString& rBookmarkURL, const sal_uInt32 nType,
+ const OUString& rStringVer0, const OUString& rStringVer1, const OUString& rStringVer2, const OUString& rStringVer3 )
+{
+ sal_uInt32 nHyperId = ++mnExEmbed;
+
+ OUString sBookmarkURL( rBookmarkURL );
+ INetURLObject aBaseURI( maBaseURI );
+ INetURLObject aBookmarkURI( rBookmarkURL );
+ if( aBaseURI.GetProtocol() == aBookmarkURI.GetProtocol() )
+ {
+ OUString aRelUrl( INetURLObject::GetRelURL( maBaseURI, rBookmarkURL ) );
+ if ( !aRelUrl.isEmpty() )
+ sBookmarkURL = aRelUrl;
+ }
+ maHyperlink.emplace_back( sBookmarkURL, nType );
+
+ mpExEmbed->WriteUInt16( 0xf )
+ .WriteUInt16( EPP_ExHyperlink )
+ .WriteUInt32( 0 );
+ sal_uInt32 nHyperSize, nHyperStart = mpExEmbed->Tell();
+ mpExEmbed->WriteUInt16( 0 )
+ .WriteUInt16( EPP_ExHyperlinkAtom )
+ .WriteUInt32( 4 )
+ .WriteUInt32( nHyperId );
+
+ PPTWriter::WriteCString( *mpExEmbed, rStringVer0 );
+ PPTWriter::WriteCString( *mpExEmbed, rStringVer1, 1 );
+ PPTWriter::WriteCString( *mpExEmbed, rStringVer2, 2 );
+ PPTWriter::WriteCString( *mpExEmbed, rStringVer3, 3 );
+
+ nHyperSize = mpExEmbed->Tell() - nHyperStart;
+ mpExEmbed->SeekRel( - ( static_cast<sal_Int32>(nHyperSize) + 4 ) );
+ mpExEmbed->WriteUInt32( nHyperSize );
+ mpExEmbed->SeekRel( nHyperSize );
+ return nHyperId;
+}
+
+bool PPTWriter::ImplCloseDocument()
+{
+ sal_uInt32 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Document );
+ if ( nOfs )
+ {
+ mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_CurrentPos, mpStrm->Tell() );
+ mpStrm->Seek( nOfs );
+
+ // creating the TxMasterStyleAtom
+ SvMemoryStream aTxMasterStyleAtomStrm( 0x200, 0x200 );
+ {
+ EscherExAtom aTxMasterStyleAtom( aTxMasterStyleAtomStrm, EPP_TxMasterStyleAtom, EPP_TEXTTYPE_Other );
+ aTxMasterStyleAtomStrm.WriteUInt16( 5 ); // paragraph count
+ sal_uInt16 nLev;
+ for ( nLev = 0; nLev < 5; nLev++ )
+ {
+ mpStyleSheet->mpParaSheet[ EPP_TEXTTYPE_Other ]->Write( aTxMasterStyleAtomStrm, nLev, false, mXPagePropSet );
+ mpStyleSheet->mpCharSheet[ EPP_TEXTTYPE_Other ]->Write( aTxMasterStyleAtomStrm, nLev, false, mXPagePropSet );
+ }
+ }
+
+ sal_uInt32 nExEmbedSize = mpExEmbed->TellEnd();
+
+ // nEnvironment : whole size of the environment container
+ sal_uInt32 nEnvironment = maFontCollection.GetCount() * 76 // 68 bytes per Fontenityatom and 8 Bytes per header
+ + 8 // 1 FontCollection container
+ + 20 // SrKinsoku container
+ + 18 // 1 TxSiStyleAtom
+ + aTxMasterStyleAtomStrm.Tell() // 1 TxMasterStyleAtom;
+ + PPTExStyleSheet::SizeOfTxCFStyleAtom();
+
+ sal_uInt32 nBytesToInsert = nEnvironment + 8;
+
+ if ( nExEmbedSize )
+ nBytesToInsert += nExEmbedSize + 8 + 12;
+
+ nBytesToInsert += maSoundCollection.GetSize();
+ nBytesToInsert += mpPptEscherEx->DrawingGroupContainerSize();
+ nBytesToInsert += ImplMasterSlideListContainer(nullptr);
+ nBytesToInsert += ImplDocumentListContainer(nullptr);
+
+ // insert nBytes into stream and adjust depending container
+ mpPptEscherEx->InsertAtCurrentPos( nBytesToInsert );
+
+ // CREATE HYPERLINK CONTAINER
+ if ( nExEmbedSize )
+ {
+ mpStrm->WriteUInt16( 0xf )
+ .WriteUInt16( EPP_ExObjList )
+ .WriteUInt32( nExEmbedSize + 12 )
+ .WriteUInt16( 0 )
+ .WriteUInt16( EPP_ExObjListAtom )
+ .WriteUInt32( 4 )
+ .WriteUInt32( mnExEmbed );
+ mpPptEscherEx->InsertPersistOffset( EPP_Persist_ExObj, mpStrm->Tell() );
+ mpStrm->WriteBytes(mpExEmbed->GetData(), nExEmbedSize);
+ }
+
+ // CREATE ENVIRONMENT
+ mpStrm->WriteUInt16( 0xf ).WriteUInt16( EPP_Environment ).WriteUInt32( nEnvironment );
+
+ // Open Container ( EPP_SrKinsoku )
+ mpStrm->WriteUInt16( 0x2f ).WriteUInt16( EPP_SrKinsoku ).WriteUInt32( 12 );
+ mpPptEscherEx->AddAtom( 4, EPP_SrKinsokuAtom, 0, 3 );
+ mpStrm->WriteInt32( 0 ); // SrKinsoku Level 0
+
+ // Open Container ( EPP_FontCollection )
+ mpStrm->WriteUInt16( 0xf ).WriteUInt16( EPP_FontCollection ).WriteUInt32( maFontCollection.GetCount() * 76 );
+
+ for ( sal_uInt32 i = 0; i < maFontCollection.GetCount(); i++ )
+ {
+ mpPptEscherEx->AddAtom( 68, EPP_FontEnityAtom, 0, i );
+ const FontCollectionEntry* pDesc = maFontCollection.GetById( i );
+ sal_Int32 nFontLen = pDesc->Name.getLength();
+ if ( nFontLen > 31 )
+ nFontLen = 31;
+ for ( sal_Int32 n = 0; n < 32; n++ )
+ {
+ sal_Unicode nUniCode = 0;
+ if ( n < nFontLen )
+ nUniCode = pDesc->Name[n];
+ mpStrm->WriteUInt16( nUniCode );
+ }
+ sal_uInt8 lfCharSet = ANSI_CHARSET;
+ sal_uInt8 const lfClipPrecision = 0;
+ sal_uInt8 const lfQuality = 6;
+ sal_uInt8 lfPitchAndFamily = 0;
+
+ if ( pDesc->CharSet == RTL_TEXTENCODING_SYMBOL )
+ lfCharSet = SYMBOL_CHARSET;
+
+ switch( pDesc->Family )
+ {
+ case css::awt::FontFamily::ROMAN :
+ lfPitchAndFamily |= FF_ROMAN;
+ break;
+
+ case css::awt::FontFamily::SWISS :
+ lfPitchAndFamily |= FF_SWISS;
+ break;
+
+ case css::awt::FontFamily::MODERN :
+ lfPitchAndFamily |= FF_MODERN;
+ break;
+
+ case css::awt::FontFamily::SCRIPT:
+ lfPitchAndFamily |= FF_SCRIPT;
+ break;
+
+ case css::awt::FontFamily::DECORATIVE:
+ lfPitchAndFamily |= FF_DECORATIVE;
+ break;
+
+ default:
+ lfPitchAndFamily |= FAMILY_DONTKNOW;
+ break;
+ }
+ switch( pDesc->Pitch )
+ {
+ case css::awt::FontPitch::FIXED:
+ lfPitchAndFamily |= FIXED_PITCH;
+ break;
+
+ default:
+ lfPitchAndFamily |= DEFAULT_PITCH;
+ break;
+ }
+ mpStrm->WriteUChar( lfCharSet )
+ .WriteUChar( lfClipPrecision )
+ .WriteUChar( lfQuality )
+ .WriteUChar( lfPitchAndFamily );
+ }
+ mpStyleSheet->WriteTxCFStyleAtom( *mpStrm ); // create style that is used for new standard objects
+ mpPptEscherEx->AddAtom( 10, EPP_TxSIStyleAtom );
+ mpStrm->WriteUInt32( 7 ) // ?
+ .WriteInt16( 2 ) // ?
+ .WriteUChar( 9 ) // ?
+ .WriteUChar( 8 ) // ?
+ .WriteInt16( 0 ); // ?
+
+ mpStrm->WriteBytes(aTxMasterStyleAtomStrm.GetData(), aTxMasterStyleAtomStrm.Tell());
+ maSoundCollection.Write( *mpStrm );
+ mpPptEscherEx->WriteDrawingGroupContainer( *mpStrm );
+ ImplMasterSlideListContainer( mpStrm.get() );
+ ImplDocumentListContainer( mpStrm.get() );
+
+ sal_uInt32 nOldPos = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_CurrentPos );
+ if ( nOldPos )
+ {
+ mpStrm->Seek( nOldPos );
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PropValue::GetPropertyValue(
+ css::uno::Any& rAny,
+ const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ const OUString& rString,
+ bool bTestPropertyAvailability )
+{
+ bool bRetValue = true;
+ if ( bTestPropertyAvailability )
+ {
+ bRetValue = false;
+ try
+ {
+ css::uno::Reference< css::beans::XPropertySetInfo > aXPropSetInfo( rXPropSet->getPropertySetInfo() );
+ if ( aXPropSetInfo.is() )
+ bRetValue = aXPropSetInfo->hasPropertyByName( rString );
+ }
+ catch( css::uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ }
+ if ( bRetValue )
+ {
+ try
+ {
+ rAny = rXPropSet->getPropertyValue( rString );
+ if ( !rAny.hasValue() )
+ bRetValue = false;
+ }
+ catch( css::uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ }
+ return bRetValue;
+}
+
+css::beans::PropertyState PropValue::GetPropertyState(
+ const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ const OUString& rPropertyName )
+{
+ css::beans::PropertyState eRetValue = css::beans::PropertyState_AMBIGUOUS_VALUE;
+ try
+ {
+ css::uno::Reference< css::beans::XPropertyState > aXPropState( rXPropSet, css::uno::UNO_QUERY );
+ if ( aXPropState.is() )
+ eRetValue = aXPropState->getPropertyState( rPropertyName );
+ }
+ catch( css::uno::Exception& )
+ {
+
+ }
+ return eRetValue;
+}
+
+bool PropValue::ImplGetPropertyValue( const OUString& rString )
+{
+ return GetPropertyValue( mAny, mXPropSet, rString );
+}
+
+bool PropValue::ImplGetPropertyValue( const css::uno::Reference< css::beans::XPropertySet > & aXPropSet, const OUString& rString )
+{
+ return GetPropertyValue( mAny, aXPropSet, rString );
+}
+
+bool PropStateValue::ImplGetPropertyValue( const OUString& rString, bool bGetPropertyState )
+{
+ ePropState = css::beans::PropertyState_AMBIGUOUS_VALUE;
+ bool bRetValue = true;
+#ifdef UNX
+ css::uno::Reference< css::beans::XPropertySetInfo >
+ aXPropSetInfo( mXPropSet->getPropertySetInfo() );
+ if ( !aXPropSetInfo.is() )
+ return false;
+#endif
+ try
+ {
+ mAny = mXPropSet->getPropertyValue( rString );
+ if ( !mAny.hasValue() )
+ bRetValue = false;
+ else if ( bGetPropertyState )
+ ePropState = mXPropState->getPropertyState( rString );
+ else
+ ePropState = css::beans::PropertyState_DIRECT_VALUE;
+ }
+ catch( css::uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ return bRetValue;
+}
+
+void PPTWriter::ImplWriteParagraphs( SvStream& rOut, TextObj& rTextObj )
+{
+ bool bFirstParagraph = true;
+ sal_uInt32 nCharCount;
+ sal_uInt32 nPropertyFlags = 0;
+ sal_Int16 nLineSpacing;
+ int nInstance = rTextObj.GetInstance();
+
+ for ( sal_uInt32 i = 0; i < rTextObj.ParagraphCount(); ++i, bFirstParagraph = false )
+ {
+ ParagraphObj* pPara = rTextObj.GetParagraph(i);
+ const PortionObj& rPortion = pPara->front();
+ nCharCount = pPara->CharacterCount();
+
+ if ( ( pPara->meTextAdjust == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_Adjust, pPara->mnTextAdjust ) ) )
+ nPropertyFlags |= 0x00000800;
+ nLineSpacing = pPara->mnLineSpacing;
+
+ const FontCollectionEntry* pDesc = maFontCollection.GetById( rPortion.mnFont );
+ sal_Int16 nNormalSpacing = 100;
+ if ( !mbFontIndependentLineSpacing && pDesc )
+ {
+ double fN = 100.0;
+ fN *= pDesc->Scaling;
+ nNormalSpacing = static_cast<sal_Int16>( fN + 0.5 );
+ }
+ if ( !mbFontIndependentLineSpacing && bFirstParagraph && ( nLineSpacing > nNormalSpacing ) ) // sj: i28747, no replacement for fixed linespacing
+ {
+ nLineSpacing = nNormalSpacing;
+ nPropertyFlags |= 0x00001000;
+ }
+ else
+ {
+ if ( nLineSpacing > 0 )
+ {
+ if ( !mbFontIndependentLineSpacing && pDesc )
+ nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
+ }
+ else
+ {
+ if ( !pPara->mbFixedLineSpacing && rPortion.mnCharHeight > static_cast<sal_uInt16>( static_cast<double>(-nLineSpacing) * 0.001 * 72.0 / 2.54 ) ) // 1/100mm to point
+ nLineSpacing = nNormalSpacing;
+ else
+ nLineSpacing = static_cast<sal_Int16>( convertMm100ToMasterUnit(nLineSpacing) );
+ }
+ if ( ( pPara->meLineSpacing == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_LineFeed, nLineSpacing ) ) )
+ nPropertyFlags |= 0x00001000;
+ }
+ if ( ( pPara->meLineSpacingTop == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mnLineSpacingTop ) ) )
+ nPropertyFlags |= 0x00002000;
+ if ( ( pPara->meLineSpacingBottom == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_LowerDist, pPara->mnLineSpacingBottom ) ) )
+ nPropertyFlags |= 0x00004000;
+ if ( ( pPara->meForbiddenRules == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mbForbiddenRules ? 1 : 0 ) ) )
+ nPropertyFlags |= 0x00020000;
+ if ( ( pPara->meParagraphPunctation == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mbParagraphPunctation ? 1 : 0 ) ) )
+ nPropertyFlags |= 0x00080000;
+ if ( ( pPara->meBiDi == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_BiDi, pPara->mnBiDi ) ) )
+ nPropertyFlags |= 0x00200000;
+
+ sal_Int32 nBuRealSize = pPara->nBulletRealSize;
+ sal_Int16 nBulletFlags = pPara->nBulletFlags;
+
+ if ( pPara->bExtendedParameters )
+ nPropertyFlags |= pPara->nParaFlags;
+ else
+ {
+ nPropertyFlags |= 1; // turn off bullet explicit
+ nBulletFlags = 0;
+ }
+
+ // Write nTextOfs and nBullets
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_TextOfs, pPara->nTextOfs ) )
+ nPropertyFlags |= 0x100;
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_BulletOfs, pPara->nBulletOfs ))
+ nPropertyFlags |= 0x400;
+
+ FontCollectionEntry aFontDescEntry( pPara->aFontDesc.Name, pPara->aFontDesc.Family, pPara->aFontDesc.Pitch, pPara->aFontDesc.CharSet );
+ sal_uInt16 nFontId = static_cast<sal_uInt16>(maFontCollection.GetId( aFontDescEntry ));
+
+ rOut.WriteUInt32( nCharCount )
+ .WriteUInt16( pPara->nDepth ) // Level
+ .WriteUInt32( nPropertyFlags ); // Paragraph Attribute Set
+
+ if ( nPropertyFlags & 0xf )
+ rOut.WriteInt16( nBulletFlags );
+ if ( nPropertyFlags & 0x80 )
+ rOut.WriteUInt16( pPara->cBulletId );
+ if ( nPropertyFlags & 0x10 )
+ rOut.WriteUInt16( nFontId );
+ if ( nPropertyFlags & 0x40 )
+ rOut.WriteInt16( nBuRealSize );
+ if ( nPropertyFlags & 0x20 )
+ {
+ sal_uInt32 nBulletColor = pPara->nBulletColor;
+ if ( nBulletColor == sal_uInt32(COL_AUTO) )
+ {
+ bool bIsDark = false;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark", true ) )
+ aAny >>= bIsDark;
+ nBulletColor = bIsDark ? 0xffffff : 0x000000;
+ }
+ nBulletColor &= 0xffffff;
+ nBulletColor |= 0xfe000000;
+ rOut.WriteUInt32( nBulletColor );
+ }
+ if ( nPropertyFlags & 0x00000800 )
+ rOut.WriteUInt16( pPara->mnTextAdjust );
+ if ( nPropertyFlags & 0x00001000 )
+ rOut.WriteUInt16( nLineSpacing );
+ if ( nPropertyFlags & 0x00002000 )
+ rOut.WriteUInt16( pPara->mnLineSpacingTop );
+ if ( nPropertyFlags & 0x00004000 )
+ rOut.WriteUInt16( pPara->mnLineSpacingBottom );
+ if ( nPropertyFlags & 0x100 )
+ rOut.WriteUInt16( pPara->nTextOfs );
+ if ( nPropertyFlags & 0x400 )
+ rOut.WriteUInt16( pPara->nBulletOfs );
+ if ( nPropertyFlags & 0x000e0000 )
+ {
+ sal_uInt16 nAsianSettings = 0;
+ if ( pPara->mbForbiddenRules )
+ nAsianSettings |= 1;
+ if ( pPara->mbParagraphPunctation )
+ nAsianSettings |= 4;
+ rOut.WriteUInt16( nAsianSettings );
+ }
+ if ( nPropertyFlags & 0x200000 )
+ rOut.WriteUInt16( pPara->mnBiDi );
+ }
+}
+
+void PPTWriter::ImplWritePortions( SvStream& rOut, TextObj& rTextObj )
+{
+ sal_uInt32 nPropertyFlags;
+ int nInstance = rTextObj.GetInstance();
+
+ for ( sal_uInt32 i = 0; i < rTextObj.ParagraphCount(); ++i )
+ {
+ ParagraphObj* pPara = rTextObj.GetParagraph(i);
+ for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPara->begin(); it != pPara->end(); ++it )
+ {
+ const PortionObj& rPortion = **it;
+ nPropertyFlags = 0;
+ sal_uInt32 nCharAttr = rPortion.mnCharAttr;
+ sal_uInt32 nCharColor = rPortion.mnCharColor;
+
+ if ( nCharColor == sal_uInt32(COL_AUTO) ) // nCharColor depends to the background color
+ {
+ bool bIsDark = false;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark", true ) )
+ aAny >>= bIsDark;
+ nCharColor = bIsDark ? 0xffffff : 0x000000;
+ }
+
+ nCharColor &= 0xffffff;
+
+ /* the portion is using the embossed or engraved attribute, which we want to map to the relief feature of PPT.
+ Because the relief feature of PPT is dependent to the background color, such a mapping can not always be used. */
+ if ( nCharAttr & 0x200 )
+ {
+ sal_uInt32 nBackgroundColor = 0xffffff;
+
+ if ( !nCharColor ) // special treatment for
+ nCharColor = 0xffffff; // black fontcolor
+
+ css::uno::Any aAny;
+ css::drawing::FillStyle aFS( css::drawing::FillStyle_NONE );
+ if ( PropValue::GetPropertyValue( aAny, mXPropSet, "FillStyle" ) )
+ aAny >>= aFS;
+ switch( aFS )
+ {
+ case css::drawing::FillStyle_GRADIENT :
+ {
+ ::tools::Rectangle aRect( Point(), Size( 28000, 21000 ) );
+ EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
+ aPropOpt.CreateGradientProperties( mXPropSet );
+ aPropOpt.GetOpt( ESCHER_Prop_fillColor, nBackgroundColor );
+ }
+ break;
+ case css::drawing::FillStyle_SOLID :
+ {
+ if ( PropValue::GetPropertyValue( aAny, mXPropSet, "FillColor" ) )
+ nBackgroundColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
+ }
+ break;
+ case css::drawing::FillStyle_NONE :
+ {
+ css::uno::Any aBackAny;
+ css::drawing::FillStyle aBackFS( css::drawing::FillStyle_NONE );
+ if ( PropValue::GetPropertyValue( aBackAny, mXBackgroundPropSet, "FillStyle" ) )
+ aBackAny >>= aBackFS;
+ switch( aBackFS )
+ {
+ case css::drawing::FillStyle_GRADIENT :
+ {
+ ::tools::Rectangle aRect( Point(), Size( 28000, 21000 ) );
+ EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
+ aPropOpt.CreateGradientProperties( mXBackgroundPropSet );
+ aPropOpt.GetOpt( ESCHER_Prop_fillColor, nBackgroundColor );
+ }
+ break;
+ case css::drawing::FillStyle_SOLID :
+ {
+ if ( PropValue::GetPropertyValue( aAny, mXBackgroundPropSet, "FillColor" ) )
+ nBackgroundColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ sal_Int32 nB = nBackgroundColor & 0xff;
+ nB += static_cast<sal_uInt8>( nBackgroundColor >> 8 );
+ nB += static_cast<sal_uInt8>( nBackgroundColor >> 16 );
+ // if the background color is nearly black, relief can't been used, because the text would not be visible
+ if ( nB < 0x60 || ( nBackgroundColor != nCharColor ) )
+ {
+ nCharAttr &=~ 0x200;
+
+ // now check if the text is part of a group, and if the previous object has the same color than the fontcolor
+ // ( and if fillcolor is not available the background color ), it is sometimes
+ // not possible to export the 'embossed' flag
+ if ( ( GetCurrentGroupLevel() > 0 ) && ( GetCurrentGroupIndex() >= 1 ) )
+ {
+ css::uno::Reference< css::drawing::XShape > aGroupedShape( GetCurrentGroupAccess()->getByIndex( GetCurrentGroupIndex() - 1 ), uno::UNO_QUERY );
+ if( aGroupedShape.is() )
+ {
+ css::uno::Reference< css::beans::XPropertySet > aPropSetOfNextShape
+ ( aGroupedShape, css::uno::UNO_QUERY );
+ if ( aPropSetOfNextShape.is() )
+ {
+ if ( PropValue::GetPropertyValue( aAny, aPropSetOfNextShape,
+ "FillColor", true ) )
+ {
+ if ( nCharColor == EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) ) )
+ {
+ nCharAttr |= 0x200;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ nCharColor |= 0xfe000000;
+ if ( nInstance == 4 ) // special handling for normal textobjects:
+ nPropertyFlags |= nCharAttr & 0x217; // not all attributes are inherited
+ else
+ {
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Bold, nCharAttr ) )
+ nPropertyFlags |= 1;
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Italic, nCharAttr ) )
+ nPropertyFlags |= 2;
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Underline, nCharAttr ) )
+ nPropertyFlags |= 4;
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Shadow, nCharAttr ) )
+ nPropertyFlags |= 0x10;
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Embossed, nCharAttr ) )
+ nPropertyFlags |= 512;
+ }
+ if ( rTextObj.HasExtendedBullets() )
+ {
+ nPropertyFlags |= ( i & 0x3f ) << 10 ;
+ nCharAttr |= ( i & 0x3f ) << 10;
+ }
+ if ( ( rPortion.meFontName == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Font, rPortion.mnFont ) ) )
+ nPropertyFlags |= 0x00010000;
+ if ( ( rPortion.meAsianOrComplexFont == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_AsianOrComplexFont, rPortion.mnAsianOrComplexFont ) ) )
+ nPropertyFlags |= 0x00200000;
+ if ( ( rPortion.meCharHeight == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_FontHeight, rPortion.mnCharHeight ) ) )
+ nPropertyFlags |= 0x00020000;
+ if ( ( rPortion.meCharColor == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_FontColor, nCharColor & 0xffffff ) ) )
+ nPropertyFlags |= 0x00040000;
+ if ( ( rPortion.meCharEscapement == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Escapement, rPortion.mnCharEscapement ) ) )
+ nPropertyFlags |= 0x00080000;
+
+ sal_uInt32 nCharCount = rPortion.Count();
+
+ rOut.WriteUInt32( nCharCount )
+ .WriteUInt32( nPropertyFlags ); //PropertyFlags
+
+ if ( nPropertyFlags & 0xffff )
+ rOut.WriteUInt16( nCharAttr );
+ if ( nPropertyFlags & 0x00010000 )
+ rOut.WriteUInt16( rPortion.mnFont );
+ if ( nPropertyFlags & 0x00200000 )
+ rOut.WriteUInt16( rPortion.mnAsianOrComplexFont );
+ if ( nPropertyFlags & 0x00020000 )
+ rOut.WriteUInt16( rPortion.mnCharHeight );
+ if ( nPropertyFlags & 0x00040000 )
+ rOut.WriteUInt32( nCharColor );
+ if ( nPropertyFlags & 0x00080000 )
+ rOut.WriteInt16( rPortion.mnCharEscapement );
+ }
+ }
+}
+
+/**
+ * Loads and converts text from shape, value is stored in mnTextSize.
+ */
+bool PPTWriter::ImplGetText()
+{
+ mnTextSize = 0;
+ mbFontIndependentLineSpacing = false;
+ mXText.set( mXShape, css::uno::UNO_QUERY );
+
+ if ( mXText.is() )
+ {
+ mnTextSize = mXText->getString().getLength();
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, mXPropSet, "FontIndependentLineSpacing", true ) )
+ aAny >>= mbFontIndependentLineSpacing;
+ }
+ return ( mnTextSize != 0 );
+}
+
+void PPTWriter::ImplFlipBoundingBox( EscherPropertyContainer& rPropOpt )
+{
+ if ( mnAngle < 0 )
+ mnAngle = ( 36000 + mnAngle ) % 36000;
+ else
+ mnAngle = ( 36000 - ( mnAngle % 36000 ) );
+
+ double fCos = cos( basegfx::deg2rad<100>(mnAngle) );
+ double fSin = sin( basegfx::deg2rad<100>(mnAngle) );
+
+ double fWidthHalf = maRect.GetWidth() / 2.0;
+ double fHeightHalf = maRect.GetHeight() / 2.0;
+
+ double fXDiff = fCos * fWidthHalf + fSin * (-fHeightHalf);
+ double fYDiff = - ( fSin * fWidthHalf - fCos * ( -fHeightHalf ) );
+
+ maRect.Move( static_cast<sal_Int32>( -( fWidthHalf - fXDiff ) ), static_cast<sal_Int32>( - ( fHeightHalf + fYDiff ) ) );
+ mnAngle *= 655;
+ mnAngle += 0x8000;
+ mnAngle &=~0xffff; // round nAngle to full grads
+ rPropOpt.AddOpt( ESCHER_Prop_Rotation, mnAngle );
+
+ if ( ( mnAngle >= ( 45 << 16 ) && mnAngle < ( 135 << 16 ) ) ||
+ ( mnAngle >= ( 225 << 16 ) && mnAngle < ( 315 << 16 ) ) )
+ {
+ // Maddeningly, in those two areas of PPT is the BoundingBox already
+ // vertical. Therefore, we need to put down it BEFORE THE ROTATION.
+ css::awt::Point aTopLeft( static_cast<sal_Int32>( maRect.Left() + fWidthHalf - fHeightHalf ), static_cast<sal_Int32>( maRect.Top() + fHeightHalf - fWidthHalf ) );
+ const tools::Long nRotatedWidth(maRect.GetHeight());
+ const tools::Long nRotatedHeight(maRect.GetWidth());
+ const Size aNewSize(nRotatedWidth, nRotatedHeight);
+ maRect = ::tools::Rectangle( Point( aTopLeft.X, aTopLeft.Y ), aNewSize );
+ }
+}
+
+void PPTWriter::ImplAdjustFirstLineLineSpacing( TextObj& rTextObj, EscherPropertyContainer& rPropOpt )
+{
+ if ( mbFontIndependentLineSpacing )
+ return;
+
+ if ( !rTextObj.ParagraphCount() )
+ return;
+
+ ParagraphObj* pPara = rTextObj.GetParagraph(0);
+ if ( pPara->empty() )
+ return;
+
+ const PortionObj& rPortion = pPara->front();
+ sal_Int16 nLineSpacing = pPara->mnLineSpacing;
+ const FontCollectionEntry* pDesc = maFontCollection.GetById( rPortion.mnFont );
+ if ( pDesc )
+ nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
+
+ if ( ( nLineSpacing > 0 ) && ( nLineSpacing < 100 ) )
+ {
+ double fCharHeight = convertPointToMm100<double>(rPortion.mnCharHeight);
+ fCharHeight *= 100 - nLineSpacing;
+ fCharHeight /= 100;
+
+ sal_uInt32 nUpperDistance = 0;
+ rPropOpt.GetOpt( ESCHER_Prop_dyTextTop, nUpperDistance );
+ nUpperDistance += static_cast< sal_uInt32 >( fCharHeight * 360.0 );
+ rPropOpt.AddOpt( ESCHER_Prop_dyTextTop, nUpperDistance );
+ }
+}
+
+void PPTWriter::ImplWriteTextStyleAtom( SvStream& rOut, int nTextInstance, sal_uInt32 nAtomInstance,
+ TextRuleEntry* pTextRule, SvStream& rExtBuStr, EscherPropertyContainer* pPropOpt )
+{
+ PPTExParaSheet& rParaSheet = mpStyleSheet->GetParaSheet( nTextInstance );
+
+ rOut.WriteUInt32( ( EPP_TextHeaderAtom << 16 ) | ( nAtomInstance << 4 ) ).WriteUInt32( 4 )
+ .WriteInt32( nTextInstance );
+
+ if ( mbEmptyPresObj )
+ mnTextSize = 0;
+ if ( mbEmptyPresObj )
+ return;
+
+ ParagraphObj* pPara;
+ TextObjBinary aTextObj( mXText, nTextInstance, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
+
+ // leaving out EPP_TextCharsAtom w/o text - still write out
+ // attribute info though
+ if ( mnTextSize )
+ aTextObj.Write( &rOut );
+
+ if ( pPropOpt && mType != "drawing.Table" )
+ ImplAdjustFirstLineLineSpacing( aTextObj, *pPropOpt );
+
+ sal_uInt32 nSize, nPos = rOut.Tell();
+
+ rOut.WriteUInt32( EPP_StyleTextPropAtom << 16 ).WriteUInt32( 0 );
+ ImplWriteParagraphs( rOut, aTextObj );
+ ImplWritePortions( rOut, aTextObj );
+ nSize = rOut.Tell() - nPos;
+ rOut.SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
+ rOut.WriteUInt32( nSize - 8 );
+ rOut.SeekRel( nSize - 8 );
+
+ for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
+ {
+ pPara = aTextObj.GetParagraph(i);
+ for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPara->begin(); it != pPara->end(); ++it )
+ {
+ const PortionObj& rPortion = **it;
+ if ( rPortion.mpFieldEntry )
+ {
+ const FieldEntry* pFieldEntry = rPortion.mpFieldEntry.get();
+
+ switch ( pFieldEntry->nFieldType >> 28 )
+ {
+ case 1 :
+ case 2 :
+ {
+ rOut.WriteUInt32( EPP_DateTimeMCAtom << 16 ).WriteUInt32( 8 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos ) // TxtOffset to TxtField;
+ .WriteUChar( pFieldEntry->nFieldType & 0xff ) // Type
+ .WriteUChar( 0 ).WriteUInt16( 0 ); // PadBytes
+ }
+ break;
+ case 3 :
+ {
+ rOut.WriteUInt32( EPP_SlideNumberMCAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos );
+ }
+ break;
+ case 4 :
+ {
+ sal_uInt32 nPageIndex = 0;
+ OUString aPageUrl;
+ OUString aFile( pFieldEntry->aFieldUrl );
+ OUString aTarget( pFieldEntry->aFieldUrl );
+ INetURLObject aUrl( pFieldEntry->aFieldUrl );
+ if ( INetProtocol::File == aUrl.GetProtocol() )
+ aFile = aUrl.PathToFileName();
+ else if ( INetProtocol::Smb == aUrl.GetProtocol() )
+ {
+ // Convert smb notation to '\\' and skip the 'smb:' part
+ aFile = aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE).copy(4);
+ aFile = aFile.replaceAll( "/", "\\" );
+ aTarget = aFile;
+ }
+ else if ( pFieldEntry->aFieldUrl.startsWith("#") )
+ {
+ OUString aPage( INetURLObject::decode( pFieldEntry->aFieldUrl, INetURLObject::DecodeMechanism::WithCharset ) );
+ aPage = aPage.copy( 1 );
+
+ std::vector<OUString>::const_iterator pIter = std::find(
+ maSlideNameList.begin(),maSlideNameList.end(),aPage);
+
+ if ( pIter != maSlideNameList.end() )
+ {
+ nPageIndex = pIter - maSlideNameList.begin();
+ aPageUrl = OUString::number(256 + nPageIndex) +
+ "," +
+ OUString::number(nPageIndex + 1) +
+ ",Slide " +
+ OUString::number(nPageIndex + 1);
+ }
+ }
+ sal_uInt32 nHyperId(0);
+ if ( !aPageUrl.isEmpty() )
+ nHyperId = ImplInsertBookmarkURL( aPageUrl, 1 | ( nPageIndex << 8 ) | ( 1U << 31 ), pFieldEntry->aRepresentation, "", "", aPageUrl );
+ else
+ nHyperId = ImplInsertBookmarkURL( pFieldEntry->aFieldUrl, 2 | ( nHyperId << 8 ), aFile, aTarget, "", "" );
+
+ rOut.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( 24 )
+ .WriteUInt32( EPP_InteractiveInfoAtom << 16 ).WriteUInt32( 16 )
+ .WriteUInt32( 0 ) // soundref
+ .WriteUInt32( nHyperId ) // hyperlink id
+ .WriteUChar( 4 ) // hyperlink action
+ .WriteUChar( 0 ) // ole verb
+ .WriteUChar( 0 ) // jump
+ .WriteUChar( 0 ) // flags
+ .WriteUChar( 8 ) // hyperlink type ?
+ .WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 )
+ .WriteUInt32( EPP_TxInteractiveInfoAtom << 16 ).WriteUInt32( 8 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos )
+ .WriteUInt32( pFieldEntry->nFieldEndPos );
+ }
+ break;
+ case 5 :
+ {
+ rOut.WriteUInt32( EPP_GenericDateMCAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos );
+ }
+ break;
+ case 6 :
+ {
+ rOut.WriteUInt32( EPP_HeaderMCAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos );
+ }
+ break;
+ case 7 :
+ {
+ rOut.WriteUInt32( EPP_FooterMCAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ aTextObj.WriteTextSpecInfo( &rOut );
+
+ // write Star Office Default TabSizes (if necessary)
+ if ( aTextObj.ParagraphCount() )
+ {
+ pPara = aTextObj.GetParagraph(0);
+ sal_uInt32 nParaFlags = 0x1f;
+ sal_Int16 nMask, nNumberingRule[ 10 ];
+ const sal_uInt32 nTabs = pPara->maTabStop.getLength();
+ const auto& rTabStops = pPara->maTabStop;
+
+ for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
+ {
+ pPara = aTextObj.GetParagraph(i);
+ if ( pPara->bExtendedParameters )
+ {
+ nMask = 1 << pPara->nDepth;
+ if ( nParaFlags & nMask )
+ {
+ nParaFlags &=~ nMask;
+ if ( ( rParaSheet.maParaLevel[ pPara->nDepth ].mnTextOfs != pPara->nTextOfs ) ||
+ ( rParaSheet.maParaLevel[ pPara->nDepth ].mnBulletOfs != pPara->nBulletOfs ) )
+ {
+ nParaFlags |= nMask << 16;
+ nNumberingRule[ pPara->nDepth << 1 ] = pPara->nTextOfs;
+ nNumberingRule[ ( pPara->nDepth << 1 ) + 1 ] = static_cast<sal_Int16>(pPara->nBulletOfs);
+ }
+ }
+ }
+ }
+ nParaFlags >>= 16;
+
+ sal_Int32 nDefaultTabSizeSrc = 2011; // I've no idea where this number came from, honestly
+ const uno::Reference< beans::XPropertySet > xPropSet( mXModel, uno::UNO_QUERY );
+ if ( xPropSet.is() )
+ {
+ if(ImplGetPropertyValue( xPropSet, "TabStop" ))
+ {
+ sal_Int32 nTabStop( 0 );
+ if ( mAny >>= nTabStop )
+ nDefaultTabSizeSrc = nTabStop;
+ }
+ }
+ const sal_uInt32 nDefaultTabSize = MapSize( awt::Size( nDefaultTabSizeSrc, 1 ) ).Width;
+ sal_uInt32 nDefaultTabs = std::abs( maRect.GetWidth() ) / nDefaultTabSize;
+ if ( nTabs )
+ nDefaultTabs -= static_cast<sal_Int32>( convertMm100ToMasterUnit(rTabStops[ nTabs - 1 ].Position) / nDefaultTabSize );
+ if ( static_cast<sal_Int32>(nDefaultTabs) < 0 )
+ nDefaultTabs = 0;
+
+ sal_uInt32 nTabCount = nTabs + nDefaultTabs;
+ sal_uInt32 i, nTextRulerAtomFlags = 0;
+
+ if ( nTabCount )
+ nTextRulerAtomFlags |= 4;
+ if ( nParaFlags )
+ nTextRulerAtomFlags |= ( ( nParaFlags << 3 ) | ( nParaFlags << 8 ) );
+
+ if ( nTextRulerAtomFlags )
+ {
+ SvStream* pRuleOut = &rOut;
+ if ( pTextRule )
+ {
+ pTextRule->pOut.reset( new SvMemoryStream( 0x100, 0x100 ) );
+ pRuleOut = pTextRule->pOut.get();
+ }
+
+ sal_uInt32 nRulePos = pRuleOut->Tell();
+ pRuleOut->WriteUInt32( EPP_TextRulerAtom << 16 ).WriteUInt32( 0 );
+ pRuleOut->WriteUInt32( nTextRulerAtomFlags );
+ if ( nTextRulerAtomFlags & 4 )
+ {
+ pRuleOut->WriteUInt16( nTabCount );
+ for ( const css::style::TabStop& rTabStop : rTabStops )
+ {
+ sal_uInt16 nPosition = static_cast<sal_uInt16>( convertMm100ToMasterUnit(rTabStop.Position) );
+ sal_uInt16 nType;
+ switch ( rTabStop.Alignment )
+ {
+ case css::style::TabAlign_DECIMAL : nType = 3; break;
+ case css::style::TabAlign_RIGHT : nType = 2; break;
+ case css::style::TabAlign_CENTER : nType = 1; break;
+
+ case css::style::TabAlign_LEFT :
+ default: nType = 0;
+ }
+ pRuleOut->WriteUInt16( nPosition )
+ .WriteUInt16( nType );
+ }
+
+ sal_uInt32 nWidth = 1;
+ if ( nTabs )
+ nWidth += static_cast<sal_Int32>( convertMm100ToMasterUnit(rTabStops[ nTabs - 1 ].Position) / nDefaultTabSize );
+ nWidth *= nDefaultTabSize;
+ for ( i = 0; i < nDefaultTabs; i++, nWidth += nDefaultTabSize )
+ pRuleOut->WriteUInt32( nWidth );
+ }
+ for ( i = 0; i < 5; i++ )
+ {
+ if ( nTextRulerAtomFlags & ( 8 << i ) )
+ pRuleOut->WriteInt16( nNumberingRule[ i << 1 ] );
+ if ( nTextRulerAtomFlags & ( 256 << i ) )
+ pRuleOut->WriteInt16( nNumberingRule[ ( i << 1 ) + 1 ] );
+ }
+ sal_uInt32 nBufSize = pRuleOut->Tell() - nRulePos;
+ pRuleOut->SeekRel( - ( static_cast<sal_Int32>(nBufSize) - 4 ) );
+ pRuleOut->WriteUInt32( nBufSize - 8 );
+ pRuleOut->SeekRel( nBufSize - 8 );
+ }
+ }
+ if ( !aTextObj.HasExtendedBullets() )
+ return;
+
+ if ( !aTextObj.ParagraphCount() )
+ return;
+
+ sal_uInt32 nNumberingType = 0, nPos2 = rExtBuStr.Tell();
+
+ rExtBuStr.WriteUInt32( EPP_PST_ExtendedParagraphAtom << 16 ).WriteUInt32( 0 );
+
+ for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
+ {
+ ParagraphObj* pBulletPara = aTextObj.GetParagraph(i);
+ sal_uInt32 nBulletFlags = 0;
+ sal_uInt16 nBulletId = pBulletPara->nBulletId;
+
+ if ( pBulletPara->bExtendedBulletsUsed )
+ {
+ nBulletFlags = 0x800000;
+ if ( pBulletPara->nNumberingType != SVX_NUM_BITMAP )
+ nBulletFlags = 0x3000000;
+ }
+ rExtBuStr.WriteUInt32( nBulletFlags );
+
+ if ( nBulletFlags & 0x800000 )
+ rExtBuStr.WriteUInt16( nBulletId );
+ if ( nBulletFlags & 0x1000000 )
+ {
+ switch( pBulletPara->nNumberingType )
+ {
+ case SVX_NUM_NUMBER_NONE :
+ case SVX_NUM_CHAR_SPECIAL :
+ nNumberingType = 0;
+ break;
+ case SVX_NUM_CHARS_UPPER_LETTER :
+ case SVX_NUM_CHARS_UPPER_LETTER_N :
+ case SVX_NUM_CHARS_LOWER_LETTER :
+ case SVX_NUM_CHARS_LOWER_LETTER_N :
+ case SVX_NUM_ROMAN_UPPER :
+ case SVX_NUM_ROMAN_LOWER :
+ case SVX_NUM_ARABIC :
+ case SVX_NUM_NUMBER_UPPER_ZH:
+ case SVX_NUM_CIRCLE_NUMBER:
+ case SVX_NUM_NUMBER_UPPER_ZH_TW:
+ case SVX_NUM_NUMBER_LOWER_ZH:
+ case SVX_NUM_FULL_WIDTH_ARABIC:
+ nNumberingType = pBulletPara->nMappedNumType;
+ break;
+
+ case SVX_NUM_BITMAP :
+ nNumberingType = 0;
+ break;
+ default: break;
+ }
+ rExtBuStr.WriteUInt32( nNumberingType );
+ }
+ if ( nBulletFlags & 0x2000000 )
+ rExtBuStr.WriteUInt16( pBulletPara->nStartWith );
+ rExtBuStr.WriteUInt32( 0 ).WriteUInt32( 0 );
+ }
+ sal_uInt32 nBulletSize = ( rExtBuStr.Tell() - nPos2 ) - 8;
+ rExtBuStr.SeekRel( - ( static_cast<sal_Int32>(nBulletSize) + 4 ) );
+ rExtBuStr.WriteUInt32( nBulletSize );
+ rExtBuStr.SeekRel( nBulletSize );
+}
+
+void PPTWriter::ImplWriteClickAction( SvStream& rSt, css::presentation::ClickAction eCa, bool bMediaClickAction )
+{
+ sal_uInt32 nSoundRef = 0; // a reference to a sound in the sound collection, or NULL.
+ sal_uInt32 nHyperLinkID = 0;// a persistent unique identifier to an external hyperlink object (only valid when action == HyperlinkAction).
+ sal_uInt8 nAction = 0; // Action See Action Table
+ sal_uInt8 const nOleVerb = 0; // OleVerb Only valid when action == OLEAction. OLE verb to use, 0 = first verb, 1 = second verb, etc.
+ sal_uInt8 nJump = 0; // Jump See Jump Table
+ sal_uInt8 const nFlags = 0; // Bit 1: Animated. If 1, then button is animated
+ // Bit 2: Stop sound. If 1, then stop current sound when button is pressed.
+ // Bit 3: CustomShowReturn. If 1, and this is a jump to custom show, then return to this slide after custom show.
+ sal_uInt8 nHyperLinkType = 0;// HyperlinkType a value from the LinkTo enum, such as LT_URL (only valid when action == HyperlinkAction).
+
+ OUString aFile;
+
+ /*
+ Action Table: Action Value
+ NoAction 0
+ MacroAction 1
+ RunProgramAction 2
+ JumpAction 3
+ HyperlinkAction 4
+ OLEAction 5
+ MediaAction 6
+ CustomShowAction 7
+
+ Jump Table: Jump Value
+ NoJump 0
+ NextSlide, 1
+ PreviousSlide, 2
+ FirstSlide, 3
+ LastSlide, 4
+ LastSlideViewed 5
+ EndShow 6
+ */
+
+ if ( bMediaClickAction )
+ nAction = 6;
+ else switch( eCa )
+ {
+ case css::presentation::ClickAction_STOPPRESENTATION :
+ nJump += 2;
+ [[fallthrough]];
+ case css::presentation::ClickAction_LASTPAGE :
+ nJump++;
+ [[fallthrough]];
+ case css::presentation::ClickAction_FIRSTPAGE :
+ nJump++;
+ [[fallthrough]];
+ case css::presentation::ClickAction_PREVPAGE :
+ nJump++;
+ [[fallthrough]];
+ case css::presentation::ClickAction_NEXTPAGE :
+ {
+ nJump++;
+ nAction = 3;
+ }
+ break;
+ case css::presentation::ClickAction_SOUND :
+ {
+ if ( ImplGetPropertyValue( "Bookmark" ) )
+ nSoundRef = maSoundCollection.GetId( *o3tl::doAccess<OUString>(mAny) );
+ }
+ break;
+ case css::presentation::ClickAction_PROGRAM :
+ {
+ if ( ImplGetPropertyValue( "Bookmark" ) )
+ {
+ INetURLObject aUrl( *o3tl::doAccess<OUString>(mAny) );
+ if ( INetProtocol::File == aUrl.GetProtocol() )
+ {
+ aFile = aUrl.PathToFileName();
+ nAction = 2;
+ }
+ }
+ }
+ break;
+
+ case css::presentation::ClickAction_BOOKMARK :
+ {
+ if ( ImplGetPropertyValue( "Bookmark" ) )
+ {
+ OUString aBookmark( *o3tl::doAccess<OUString>(mAny) );
+ sal_uInt32 nIndex = 0;
+ for ( const auto& rSlideName : maSlideNameList )
+ {
+ if ( rSlideName == aBookmark )
+ {
+ // Bookmark is a link to a document page
+ nAction = 4;
+ nHyperLinkType = 7;
+
+ OUString aHyperString = OUString::number(256 + nIndex) +
+ "," +
+ OUString::number(nIndex + 1) +
+ ",Slide " +
+ OUString::number(nIndex + 1);
+ nHyperLinkID = ImplInsertBookmarkURL( aHyperString, 1 | ( nIndex << 8 ) | ( 1U << 31 ), aBookmark, "", "", aHyperString );
+ }
+ nIndex++;
+ }
+ }
+ }
+ break;
+
+ case css::presentation::ClickAction_DOCUMENT :
+ {
+ if ( ImplGetPropertyValue( "Bookmark" ) )
+ {
+ OUString aBookmark( *o3tl::doAccess<OUString>(mAny) );
+ if ( !aBookmark.isEmpty() )
+ {
+ nAction = 4;
+ nHyperLinkType = 8;
+
+ OUString aBookmarkFile( aBookmark );
+ INetURLObject aUrl( aBookmark );
+ if ( INetProtocol::File == aUrl.GetProtocol() )
+ aBookmarkFile = aUrl.PathToFileName();
+ nHyperLinkID = ImplInsertBookmarkURL( aBookmark, sal_uInt32(2 | ( 1U << 31 )), aBookmarkFile, aBookmark, "", "" );
+ }
+ }
+ }
+ break;
+
+ case css::presentation::ClickAction_INVISIBLE :
+ case css::presentation::ClickAction_VERB :
+ case css::presentation::ClickAction_VANISH :
+ case css::presentation::ClickAction_MACRO :
+ default :
+ break;
+ }
+
+ sal_uInt32 nContainerSize = 24;
+ if ( nAction == 2 )
+ nContainerSize += ( aFile.getLength() * 2 ) + 8;
+ rSt.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( nContainerSize )
+ .WriteUInt32( EPP_InteractiveInfoAtom << 16 ).WriteUInt32( 16 )
+ .WriteUInt32( nSoundRef )
+ .WriteUInt32( nHyperLinkID )
+ .WriteUChar( nAction )
+ .WriteUChar( nOleVerb )
+ .WriteUChar( nJump )
+ .WriteUChar( nFlags )
+ .WriteUInt32( nHyperLinkType );
+
+ if ( nAction == 2 ) // run program Action
+ {
+ sal_Int32 nLen = aFile.getLength();
+ rSt.WriteUInt32( ( EPP_CString << 16 ) | 0x20 ).WriteUInt32( nLen * 2 );
+ for ( sal_Int32 i = 0; i < nLen; i++ )
+ rSt.WriteUInt16( aFile[i] );
+ }
+
+ rSt.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0x1f ).WriteUInt32( 24 ) // Mouse Over Action
+ .WriteUInt32( EPP_InteractiveInfo << 16 ).WriteUInt32( 16 );
+ for ( int i = 0; i < 4; i++, rSt.WriteUInt32( 0 ) ) ;
+}
+
+bool PPTWriter::ImplGetEffect( const css::uno::Reference< css::beans::XPropertySet > & rPropSet,
+ css::presentation::AnimationEffect& eEffect,
+ css::presentation::AnimationEffect& eTextEffect,
+ bool& bIsSound )
+{
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, rPropSet, "Effect" ) )
+ aAny >>= eEffect;
+ else
+ eEffect = css::presentation::AnimationEffect_NONE;
+
+ if ( GetPropertyValue( aAny, rPropSet, "TextEffect" ) )
+ aAny >>= eTextEffect;
+ else
+ eTextEffect = css::presentation::AnimationEffect_NONE;
+ if ( GetPropertyValue( aAny, rPropSet, "SoundOn" ) )
+ aAny >>= bIsSound;
+ else
+ bIsSound = false;
+
+ bool bHasEffect = ( ( eEffect != css::presentation::AnimationEffect_NONE )
+ || ( eTextEffect != css::presentation::AnimationEffect_NONE )
+ || bIsSound );
+ return bHasEffect;
+};
+
+bool PPTWriter::ImplCreatePresentationPlaceholder( const bool bMasterPage,
+ const sal_uInt32 nStyleInstance, const sal_uInt8 nPlaceHolderId )
+{
+ bool bRet = ImplGetText();
+ if ( bRet && bMasterPage )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ sal_uInt32 nPresShapeID = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty, nPresShapeID );
+ EscherPropertyContainer aPropOpt;
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
+ mnTxId += 0x60;
+ aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
+ aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
+ aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
+ aPropOpt.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ sal_uInt32 nLineFlags = 0x90001;
+ if ( aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
+ nLineFlags |= 0x10001; // draw dashed line if no line
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
+
+ SvMemoryStream aExtBu( 0x200, 0x200 );
+ SvMemoryStream aClientTextBox( 0x200, 0x200 );
+ ImplWriteTextStyleAtom( aClientTextBox, nStyleInstance, 0, nullptr, aExtBu, &aPropOpt );
+
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
+ aPropOpt.CreateShapeProperties( mXShape );
+ aPropOpt.Commit( *mpStrm );
+ mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
+ mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
+ mpPptEscherEx->OpenContainer( ESCHER_ClientData );
+ mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
+ mpStrm->WriteUInt32( 0 ) // PlacementID
+ .WriteUChar( nPlaceHolderId ) // PlaceHolderID
+ .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
+ .WriteUInt16( 0 ); // padword
+ mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
+
+ if ( aClientTextBox.Tell() )
+ {
+ mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
+ .WriteUInt32( aClientTextBox.Tell() );
+
+ mpStrm->WriteBytes(aClientTextBox.GetData(), aClientTextBox.Tell());
+ }
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+ }
+ else
+ bRet = false;
+ return bRet;
+}
+
+void PPTWriter::ImplCreateShape( sal_uInt32 nType, ShapeFlag nFlags, EscherSolverContainer& rSolver )
+{
+ sal_uInt32 nId = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( nType, nFlags, nId );
+ rSolver.AddShape( mXShape, nId );
+}
+
+void PPTWriter::ImplCreateTextShape( EscherPropertyContainer& rPropOpt, EscherSolverContainer& rSolver, bool bFill )
+{
+ mnTextStyle = EPP_TEXTSTYLE_TEXT;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty, rSolver );
+ if ( bFill )
+ rPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ if ( ImplGetText() )
+ {
+ mnTxId += 0x60;
+ rPropOpt.CreateTextProperties( mXPropSet, mnTxId );
+ }
+}
+
+void PPTWriter::ImplWritePage( const PHLayout& rLayout, EscherSolverContainer& aSolverContainer, PageType ePageType, bool bMasterPage, int nPageNumber )
+{
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // sal_uInt32 nGroupLevel = 0;
+
+ sal_uInt32 nGroups, nShapes, nShapeCount, nPer, nLastPer, nIndices, nOlePictureId;
+ css::awt::Point aTextRefPoint;
+
+ nShapes = mXShapes->getCount();
+ ResetGroupTable( nShapes );
+
+ nIndices = nLastPer = nShapeCount = 0;
+
+ bool bIsTitlePossible = true; // powerpoint is not able to handle more than one title
+
+ sal_uInt32 nOutlinerCount = 0; // the outline objects have to conform to the layout,
+ sal_uInt32 nPrevTextStyle = 0; // there are no more than two allowed
+
+ nOlePictureId = 0;
+
+ bool bAdditionalText = false;
+
+ bool bSecOutl = false;
+ sal_uInt32 nPObjects = 0;
+
+ std::unique_ptr<SvMemoryStream> pClientTextBox;
+ std::unique_ptr<SvMemoryStream> pClientData;
+
+ while( GetNextGroupEntry() )
+ {
+ nShapeCount++;
+
+ nPer = ( 5 * nShapeCount ) / nShapes;
+ if ( nPer != nLastPer )
+ {
+ nLastPer = nPer;
+ sal_uInt32 nValue = mnPagesWritten * 5 + nPer;
+ if ( nValue > mnStatMaxValue )
+ nValue = mnStatMaxValue;
+ if ( mbStatusIndicator && ( nValue > mnLatestStatValue ) )
+ {
+ mXStatusIndicator->setValue( nValue );
+ mnLatestStatValue = nValue;
+ }
+ }
+ nGroups = GetGroupsClosed();
+ for ( sal_uInt32 i = 0; i < nGroups; i++, mpPptEscherEx->LeaveGroup() ) ;
+
+ if ( GetShapeByIndex( GetCurrentGroupIndex(), true ) )
+ {
+ bool bIsSound;
+ bool bMediaClickAction = false;
+ css::presentation::AnimationEffect eAe;
+ css::presentation::AnimationEffect eTe;
+
+ bool bEffect = ImplGetEffect( mXPropSet, eAe, eTe, bIsSound );
+ css::presentation::ClickAction eCa = css::presentation::ClickAction_NONE;
+ if ( ImplGetPropertyValue( "OnClick" ) )
+ mAny >>= eCa;
+
+ bool bGroup = mType == "drawing.Group";
+ bool bOpenBezier = mType == "drawing.OpenBezier";
+ bool bClosedBezier = mType == "drawing.ClosedBezier";
+ bool bPolyPolygon = mType == "drawing.PolyPolygon";
+ bool bPolyLine = mType == "drawing.PolyLine";
+ OUString aGraphicPropertyName("Graphic");
+
+ const css::awt::Size aSize100thmm( mXShape->getSize() );
+ const css::awt::Point aPoint100thmm( mXShape->getPosition() );
+ ::tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) );
+ EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect100thmm );
+
+ if ( bGroup )
+ {
+ css::uno::Reference< css::container::XIndexAccess >
+ aXIndexAccess( mXShape, css::uno::UNO_QUERY );
+ if ( EnterGroup( aXIndexAccess ) )
+ {
+ std::unique_ptr<SvMemoryStream> pTmp;
+ if ( eCa != css::presentation::ClickAction_NONE )
+ {
+ pTmp.reset(new SvMemoryStream(0x200, 0x200));
+ ImplWriteClickAction( *pTmp, eCa, bMediaClickAction );
+ }
+ sal_uInt32 nShapeId = mpPptEscherEx->EnterGroup(&maRect, pTmp.get());
+ aSolverContainer.AddShape( mXShape, nShapeId );
+ }
+ }
+ else
+ {
+ bool bIsFontwork = false;
+ bool bIsHatching = false;
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, mXPropSet, "IsFontwork", true ) )
+ aAny >>= bIsFontwork;
+ if ( GetPropertyValue( aAny, mXPropSet, "FillStyle", true ) )
+ {
+ css::drawing::FillStyle eFS;
+ aAny >>= eFS;
+ bIsHatching = eFS == css::drawing::FillStyle_HATCH;
+ if (mType == "drawing.Custom" && eFS == drawing::FillStyle_BITMAP)
+ {
+ ShapeFlag nMirrorFlags;
+ OUString sCustomShapeType;
+ MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType(
+ mXShape, nMirrorFlags, sCustomShapeType);
+ if (eShapeType == mso_sptMax)
+ {
+ // We can't map this custom shape to a PPT preset and it has a bitmap
+ // fill. Make sure that at least the bitmap fill is not lost.
+ mType = "drawing.GraphicObject";
+ aGraphicPropertyName = "Bitmap";
+ }
+ }
+ }
+ if ( bIsHatching || bIsFontwork || ( mType == "drawing.Measure" ) || ( mType == "drawing.Caption" ) )
+ {
+ if ( ImplGetPropertyValue( "BoundRect" ) )
+ {
+ auto aRect = o3tl::doAccess<css::awt::Rectangle>(mAny);
+ maPosition = MapPoint( css::awt::Point( aRect->X, aRect->Y ) );
+ maSize = MapSize( css::awt::Size( aRect->Width, aRect->Height ) );
+ maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
+ }
+ mType = "drawing.dontknow";
+ }
+ }
+ sal_uInt8 nPlaceHolderAtom = EPP_PLACEHOLDER_NONE;
+
+ mnTextSize = 0;
+ mnTextStyle = EPP_TEXTSTYLE_NORMAL;
+
+ if ( mType == "drawing.Custom" )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ShapeFlag nMirrorFlags;
+ OUString sCustomShapeType;
+ MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( mXShape, nMirrorFlags, sCustomShapeType );
+ if ( sCustomShapeType == "col-502ad400" || sCustomShapeType == "col-60da8460" )
+ { // sj: creating metafile for customshapes that can't be saved to ms format properly
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
+ {
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mXShape);
+ if ( pObj )
+ {
+ ::tools::Rectangle aBound = pObj->GetCurrentBoundRect();
+ maPosition = MapPoint( css::awt::Point( aBound.Left(), aBound.Top() ) );
+ maSize = MapSize( css::awt::Size ( aBound.GetWidth(), aBound.GetHeight() ) );
+ maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
+ mnAngle = 0;
+ }
+ }
+ }
+ else
+ {
+ ImplCreateShape( eShapeType,
+ nMirrorFlags | ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ aPropOpt.CreateCustomShapeProperties( eShapeType, mXShape );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape);
+ if ( ImplGetText() )
+ {
+ if ( !aPropOpt.IsFontWork() )
+ {
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId, true );
+ }
+ }
+ }
+ }
+ else if ( mType == "drawing.Rectangle" )
+ {
+ sal_Int32 nRadius = 0;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ if ( ImplGetPropertyValue( "CornerRadius" ) )
+ {
+ mAny >>= nRadius;
+ nRadius = MapSize( css::awt::Size( nRadius, 0 ) ).Width;
+ }
+ if ( nRadius )
+ {
+ ImplCreateShape( ESCHER_ShpInst_RoundRectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ sal_Int32 nLength = maRect.GetWidth();
+ if ( nLength > maRect.GetHeight() )
+ nLength = maRect.GetHeight();
+ nLength >>= 1;
+ if ( nRadius >= nLength )
+ nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
+ else
+ {
+ if (nLength != 0)
+ nRadius = ( 0x2a30 * nRadius ) / nLength;
+ else
+ nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
+ }
+ aPropOpt.AddOpt( ESCHER_Prop_adjustValue, nRadius );
+ }
+ else
+ {
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ }
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ if ( ImplGetText() )
+ {
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
+ }
+ }
+ else if ( mType == "drawing.Ellipse" )
+ {
+ css::drawing::CircleKind eCircleKind( css::drawing::CircleKind_FULL );
+ PolyStyle ePolyKind = PolyStyle::Chord;
+ if ( ImplGetPropertyValue( "CircleKind" ) )
+ {
+ mAny >>= eCircleKind;
+ switch ( eCircleKind )
+ {
+ case css::drawing::CircleKind_SECTION :
+ {
+ ePolyKind = PolyStyle::Pie;
+ }
+ break;
+ case css::drawing::CircleKind_ARC :
+ {
+ ePolyKind = PolyStyle::Arc;
+ }
+ break;
+
+ case css::drawing::CircleKind_CUT :
+ {
+ ePolyKind = PolyStyle::Chord;
+ }
+ break;
+
+ default:
+ eCircleKind = css::drawing::CircleKind_FULL;
+ }
+ }
+ if ( eCircleKind == css::drawing::CircleKind_FULL )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_Ellipse,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ if ( ImplGetText() )
+ {
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
+ }
+ }
+ else
+ {
+ sal_Int32 nStartAngle, nEndAngle;
+ if ( !ImplGetPropertyValue( "CircleStartAngle" ) )
+ continue;
+ nStartAngle = *o3tl::doAccess<sal_Int32>(mAny);
+ if( !ImplGetPropertyValue( "CircleEndAngle" ) )
+ continue;
+ nEndAngle = *o3tl::doAccess<sal_Int32>(mAny);
+ css::awt::Point aPoint( mXShape->getPosition() );
+ css::awt::Size aSize( mXShape->getSize() );
+ css::awt::Point aStart, aEnd, aCenter;
+ ::tools::Rectangle aRect( Point( aPoint.X, aPoint.Y ), Size( aSize.Width, aSize.Height ) );
+ aStart.X = static_cast<sal_Int32>( cos( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 );
+ aStart.Y = - static_cast<sal_Int32>( sin( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 );
+ aEnd.X = static_cast<sal_Int32>( cos( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 );
+ aEnd.Y = - static_cast<sal_Int32>( sin( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 );
+ aCenter.X = aPoint.X + ( aSize.Width / 2 );
+ aCenter.Y = aPoint.Y + ( aSize.Height / 2 );
+ aStart.X += aCenter.X;
+ aStart.Y += aCenter.Y;
+ aEnd.X += aCenter.X;
+ aEnd.Y += aCenter.Y;
+ tools::Polygon aPolygon( aRect, Point( aStart.X, aStart.Y ), Point( aEnd.X, aEnd.Y ), ePolyKind );
+ bool bNeedText = true;
+ if ( mnAngle )
+ {
+ aPolygon.Rotate( aRect.TopLeft(), Degree10(static_cast<sal_Int16>( mnAngle / 10 )) );
+ if ( ImplGetText() )
+ {
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( 0,0 );
+ // nGroupLevel = mpPptEscherEx->GetGroupLevel();
+ bNeedText = false;
+ bAdditionalText = true;
+ mnTextSize = 0;
+ }
+ mnAngle = 0;
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ css::awt::Rectangle aNewRect;
+ switch ( ePolyKind )
+ {
+ case PolyStyle::Pie :
+ case PolyStyle::Chord :
+ {
+ if ( aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect, &aPolygon ) )
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ }
+ break;
+
+ case PolyStyle::Arc :
+ {
+ if ( aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect, &aPolygon ) )
+ aPropOpt.CreateLineProperties( mXPropSet, false );
+ }
+ break;
+ }
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ if ( bNeedText && ImplGetText() )
+ {
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
+ }
+ }
+ }
+ else if ( mType == "drawing.Control" )
+ {
+ css::uno::Reference< css::drawing::XControlShape > aXControlShape( mXShape, css::uno::UNO_QUERY );
+ if ( !aXControlShape.is() )
+ continue;
+ css::uno::Reference< css::awt::XControlModel > aXControlModel( aXControlShape->getControl() );
+ if ( !aXControlModel.is() )
+ continue;
+
+ sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
+ try
+ {
+ // try to get the aspect when available
+ css::uno::Reference< css::beans::XPropertySet > xShapeProps( mXShape, css::uno::UNO_QUERY_THROW );
+ xShapeProps->getPropertyValue("Aspect") >>= nAspect;
+ }
+ catch( css::uno::Exception& )
+ {}
+
+ mpExEmbed->WriteUInt32( 0xf | ( EPP_ExControl << 16 ) )
+ .WriteUInt32( 0 ); // Size of this container
+
+ sal_uInt32 nSize, nOldPos = mpExEmbed->Tell();
+
+ sal_uInt32 nPageId = nPageNumber;
+ if ( ePageType == MASTER )
+ nPageId |= 0x80000000;
+ else
+ nPageId += 0x100;
+ mpExEmbed->WriteUInt32( EPP_ExControlAtom << 16 )
+ .WriteUInt32( 4 )
+ .WriteUInt32( nPageId );
+ std::unique_ptr<PPTExOleObjEntry> pEntry( new PPTExOleObjEntry( OCX_CONTROL, mpExEmbed->Tell() ) );
+ pEntry->xControlModel = aXControlModel;
+ pEntry->xShape = mXShape;
+ maExOleObj.push_back( std::move(pEntry) );
+
+ mnExEmbed++;
+
+ mpExEmbed->WriteUInt32( 1 | ( EPP_ExOleObjAtom << 16 ) )
+ .WriteUInt32( 24 )
+ .WriteUInt32( nAspect )
+ .WriteUInt32( 2 )
+ .WriteUInt32( mnExEmbed )
+ .WriteUInt32( 0 )
+ .WriteUInt32( 4 ) // index to the persist table
+ .WriteUInt32( 0x0012de00 );
+
+ css::awt::Size aSize;
+ OUString aControlName;
+ tools::SvRef<SotStorage> xTemp( new SotStorage( new SvMemoryStream(), true ) );
+ if ( oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel, xTemp, aXControlModel, aSize, aControlName ) )
+ {
+ OUString aUserName( xTemp->GetUserName() );
+ OUString aOleIdentifier;
+ if ( !aUserName.isEmpty() )
+ {
+ tools::SvRef<SotStorageStream> xCompObj = xTemp->OpenSotStream(
+ "\1CompObj",
+ StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL );
+ sal_uInt32 const nStreamLen = xCompObj->remainingSize();
+ sal_Int16 nVersion, nByteOrder;
+ sal_Int32 nWinVersion, nVal, nStringLen;
+ xCompObj->ReadInt16( nVersion )
+ .ReadInt16( nByteOrder )
+ .ReadInt32( nWinVersion )
+ .ReadInt32( nVal );
+ xCompObj->SeekRel( 16 ); // skipping clsid
+ xCompObj->ReadInt32( nStringLen );
+ if ( ( xCompObj->Tell() + nStringLen ) < nStreamLen )
+ {
+ xCompObj->SeekRel( nStringLen ); // now skipping the UserName;
+ xCompObj->ReadInt32( nStringLen );
+ if ( ( xCompObj->Tell() + nStringLen ) < nStreamLen )
+ {
+ xCompObj->SeekRel( nStringLen ); // now skipping the clipboard formatname
+ xCompObj->ReadInt32( nStringLen );
+ if ( ( nStringLen > 1 ) && ( ( xCompObj->Tell() + nStringLen ) < nStreamLen ) )
+ { // i think that the OleIdentifier will follow
+ OString aTemp = read_uInt8s_ToOString(*xCompObj, nStringLen - 1);
+ aOleIdentifier = OStringToOUString(aTemp, RTL_TEXTENCODING_MS_1252);
+ }
+ }
+ }
+ }
+
+ PPTWriter::WriteCString( *mpExEmbed, aControlName, 1 );
+ PPTWriter::WriteCString( *mpExEmbed, aOleIdentifier, 2 );
+ PPTWriter::WriteCString( *mpExEmbed, aUserName, 3 );
+ }
+ nSize = mpExEmbed->Tell() - nOldPos;
+ mpExEmbed->Seek( nOldPos - 4 );
+ mpExEmbed->WriteUInt32( nSize );
+ mpExEmbed->Seek( STREAM_SEEK_TO_END );
+ nOlePictureId = mnExEmbed;
+
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ShapeFlag const nSpFlags = ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | ShapeFlag::OLEShape;
+ ImplCreateShape( ESCHER_ShpInst_HostControl, nSpFlags, aSolverContainer );
+ if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ //export form control graphic
+ else if ( aPropOpt.CreateBlipPropertiesforOLEControl(mXPropSet,mXShape))
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ aPropOpt.AddOpt( ESCHER_Prop_pictureId, mnExEmbed );
+ aPropOpt.AddOpt( ESCHER_Prop_pictureActive, 0x10000 );
+
+ if ( !aControlName.isEmpty() )
+ {
+ aPropOpt.AddOpt(ESCHER_Prop_wzName, aControlName);
+ }
+ }
+ else if ( mType == "drawing.Connector" )
+ {
+ sal_uInt16 nSpType;
+ ShapeFlag nSpFlags;
+ css::awt::Rectangle aNewRect;
+ if ( !aPropOpt.CreateConnectorProperties( mXShape, aSolverContainer, aNewRect, nSpType, nSpFlags ) )
+ continue;
+
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( nSpType, nSpFlags, aSolverContainer );
+
+ // #119459# for connector shape, the start point and end point is fixed, and should not be rotated.
+ mnAngle = 0;
+ }
+ else if ( mType == "drawing.Measure" )
+ {
+ continue;
+ }
+ else if ( mType == "drawing.Line" )
+ {
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_LINE, false, aNewRect );
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ if ( ImplGetText() )
+ {
+ aTextRefPoint = css::awt::Point( maRect.Left(), maRect.Top() );
+ mnTextSize = 0;
+ bAdditionalText = true;
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( &maRect,0 );
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ShapeFlag nFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty;
+
+ if ( maRect.Top() > maRect.Bottom() )
+ nFlags |= ShapeFlag::FlipV;
+ if ( maRect.Left() > maRect.Right() )
+ nFlags |= ShapeFlag::FlipH;
+
+ ImplCreateShape( ESCHER_ShpInst_Line, nFlags, aSolverContainer );
+ aPropOpt.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
+ aPropOpt.CreateLineProperties( mXPropSet, false );
+ mnAngle = 0;
+ }
+ else if ( bPolyPolygon )
+ {
+ if ( ImplGetText() )
+ {
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( 0,0 );
+ // nGroupLevel = mpPptEscherEx->GetGroupLevel();
+ bAdditionalText = true;
+ mnTextSize = 0;
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect );
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ mnAngle = 0;
+ }
+ else if ( bPolyLine )
+ {
+ if ( ImplGetText() )
+ {
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( 0,0 );
+ // nGroupLevel = mpPptEscherEx->GetGroupLevel();
+ bAdditionalText = true;
+ mnTextSize = 0;
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect );
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ aPropOpt.CreateLineProperties( mXPropSet, false );
+ mnAngle = 0;
+ }
+ else if ( bOpenBezier )
+ {
+ if ( ImplGetText() )
+ {
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( 0,0 );
+ // nGroupLevel = mpPptEscherEx->GetGroupLevel();
+ bAdditionalText = true;
+ mnTextSize = 0;
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, true, aNewRect );
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ aPropOpt.CreateLineProperties( mXPropSet, false );
+ mnAngle = 0;
+ }
+ else if ( bClosedBezier )
+ {
+ if ( ImplGetText() )
+ {
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( 0,0 );
+ // nGroupLevel = mpPptEscherEx->GetGroupLevel();
+ bAdditionalText = true;
+ mnTextSize = 0;
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, true, aNewRect );
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ mnAngle = 0;
+ }
+ else if ( ( mType == "drawing.GraphicObject" ) || ( mType == "presentation.GraphicObject" ) )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+
+ // a GraphicObject can also be a ClickMe element
+ if ( mbEmptyPresObj && ( ePageType == NORMAL ) )
+ {
+ nPlaceHolderAtom = rLayout.nUsedObjectPlaceHolder;
+ ImplCreateShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster, aSolverContainer );
+ mnTxId += 0x60;
+ aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
+ }
+ else
+ {
+ mXText.set( mXShape, css::uno::UNO_QUERY );
+
+ if ( mXText.is() )
+ mnTextSize = mXText->getString().getLength();
+
+ if ( mnTextSize ) // graphic object or area fill
+ {
+ /* SJ #i34951#: because M. documents are not allowing GraphicObjects containing text, we
+ have to create a simple Rectangle with fill bitmap instead (while not allowing BitmapMode_Repeat).
+ */
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Graphic", true, true, false ) )
+ {
+ aPropOpt.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone );
+ aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 );
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x8000000 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
+ if ( ImplGetText() )
+ {
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
+ }
+ }
+ }
+ else
+ {
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+
+ if (aPropOpt.CreateGraphicProperties(mXPropSet, aGraphicPropertyName, false,
+ true))
+ {
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ }
+ }
+ }
+ else if ( ( mType == "drawing.Text" ) || ( mType == "presentation.Notes" ) )
+ {
+ if ( ( ePageType == NOTICE ) && mbPresObj )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Notes, EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE ) )
+ continue;
+ else
+ nPlaceHolderAtom = EPP_PLACEHOLDER_NOTESBODY;
+ }
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ else if ( mType == "presentation.TitleText" )
+ {
+ if ( mbPresObj )
+ {
+ if ( ( ePageType == NOTICE ) && mbEmptyPresObj )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ nPlaceHolderAtom = EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE;
+ ImplCreateShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveAnchor, aSolverContainer );
+ aPropOpt.CreateLineProperties( mXPropSet, false );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
+ }
+ else if ( rLayout.bTitlePossible && bIsTitlePossible )
+ {
+ bIsTitlePossible = false;
+
+ ImplGetText();
+ TextObjBinary aTextObj( mXText, EPP_TEXTTYPE_Title, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
+ if ( ePageType == MASTER )
+ {
+ if ( mnTextSize )
+ {
+ OUString aUString( mXText->getString() );
+ sal_uInt16 nChar;
+
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mnShapeMasterTitle = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ mnShapeMasterTitle );
+ EscherPropertyContainer aPropertyOptions;
+ aPropertyOptions.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
+ mnTxId += 0x60;
+ aPropertyOptions.AddOpt( ESCHER_Prop_lTxid, mnTxId );
+ aPropertyOptions.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
+ aPropertyOptions.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
+ aPropertyOptions.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
+ aPropertyOptions.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
+ aPropertyOptions.CreateFillProperties( mXPropSet, true, mXShape );
+ sal_uInt32 nLineFlags = 0x90001;
+ if ( aPropertyOptions.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
+ nLineFlags |= 0x10001; // draw dashed line if no line
+ aPropertyOptions.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
+ mnTxId += 0x60;
+ aPropertyOptions.CreateTextProperties( mXPropSet, mnTxId );
+ ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
+ aPropertyOptions.Commit( *mpStrm );
+ mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
+ mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
+ mpPptEscherEx->OpenContainer( ESCHER_ClientData );
+ mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
+ mpStrm->WriteUInt32( 0 ) // PlacementID
+ .WriteUChar( EPP_PLACEHOLDER_MASTERTITLE ) // PlaceHolderID
+ .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
+ .WriteUInt16( 0 ); // padword
+ mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
+ mpPptEscherEx->OpenContainer( ESCHER_ClientTextbox );
+ mpPptEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
+ mpStrm->WriteUInt32( EPP_TEXTTYPE_Title );
+ mpPptEscherEx->AddAtom( mnTextSize << 1, EPP_TextCharsAtom );
+ const sal_Unicode* pString = aUString.getStr();
+ for ( sal_uInt32 i = 0; i < mnTextSize; i++ )
+ {
+ nChar = pString[ i ]; // 0xa -> 0xb soft newline
+ if ( nChar == 0xa )
+ nChar++; // 0xd -> 0xd hard newline
+ mpStrm->WriteUInt16( nChar );
+ }
+ mpPptEscherEx->AddAtom( 6, EPP_BaseTextPropAtom );
+ mpStrm->WriteUInt32( mnTextSize + 1 ).WriteUInt16( 0 );
+ mpPptEscherEx->AddAtom( 10, EPP_TextSpecInfoAtom );
+ mpStrm->WriteUInt32( mnTextSize + 1 ).WriteUInt32( 1 ).WriteUInt16( 0 );
+ mpPptEscherEx->CloseContainer(); // ESCHER_ClientTextBox
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+ }
+ continue;
+ }
+ else
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mnTextStyle = EPP_TEXTSTYLE_TITLE;
+ nPlaceHolderAtom = rLayout.nTypeOfTitle;
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
+ aSolverContainer );
+ aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterTitle );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
+ ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
+ if ( mbEmptyPresObj )
+ {
+ sal_uInt32 nNoLineDrawDash = 0;
+ aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
+ nNoLineDrawDash |= 0x10001;
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
+ }
+ }
+ }
+ else
+ mbPresObj = false;
+ }
+ if ( !mbPresObj )
+ {
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( ( mType == "presentation.Outliner" ) || ( mType == "presentation.Subtitle" ) )
+ {
+ if ( mbPresObj )
+ {
+ nOutlinerCount++;
+ if ( (rLayout.bOutlinerPossible && ( nOutlinerCount == 1 )) ||
+ (( rLayout.bSecOutlinerPossible && ( nOutlinerCount == 2 ) ) && ( nPrevTextStyle == EPP_TEXTSTYLE_BODY ))
+ )
+ {
+ ImplGetText();
+ TextObjBinary aTextObj( mXText, EPP_TEXTTYPE_Body, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
+ if ( ePageType == MASTER )
+ {
+ nPrevTextStyle = EPP_TEXTSTYLE_TITLE;
+ if ( mnTextSize )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mnShapeMasterBody = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ mnShapeMasterBody );
+ EscherPropertyContainer aPropOpt2;
+ aPropOpt2.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
+ mnTxId += 0x60;
+ aPropOpt2.AddOpt( ESCHER_Prop_lTxid, mnTxId );
+ aPropOpt2.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
+ aPropOpt2.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
+ aPropOpt2.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90001 );
+ aPropOpt2.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
+ aPropOpt2.CreateFillProperties( mXPropSet, true, mXShape );
+ sal_uInt32 nLineFlags = 0x90001;
+ if ( aPropOpt2.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
+ nLineFlags |= 0x10001; // draw dashed line if no line
+ aPropOpt2.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
+ mnTxId += 0x60;
+ aPropOpt2.CreateTextProperties( mXPropSet, mnTxId );
+ ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt2 );
+ aPropOpt2.Commit( *mpStrm );
+ mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
+ mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
+ mpPptEscherEx->OpenContainer( ESCHER_ClientData );
+ mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
+ sal_uInt8 PlaceHolderID = ( mType == "presentation.Subtitle") ? EPP_PLACEHOLDER_MASTERSUBTITLE:EPP_PLACEHOLDER_MASTERBODY;
+ mpStrm->WriteUInt32( 1 ) // PlacementID
+ .WriteUChar( PlaceHolderID )/*(sal_uInt8)EPP_PLACEHOLDER_MASTERBODY */ // PlaceHolderID
+ .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
+ .WriteUInt16( 0 ); // padword
+ mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
+ mpPptEscherEx->OpenContainer( ESCHER_ClientTextbox ); // printf
+ mpPptEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
+ if ( mType == "presentation.Subtitle")
+ mpStrm->WriteUInt32( EPP_TEXTTYPE_CenterBody );
+ else
+ mpStrm->WriteUInt32( EPP_TEXTTYPE_Body );
+ mnTextSize = aTextObj.Count();
+ aTextObj.Write( mpStrm.get() );
+ mpPptEscherEx->BeginAtom();
+ for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount() ; ++i )
+ {
+ ParagraphObj* pPara = aTextObj.GetParagraph(i);
+ mpStrm->WriteUInt32( pPara->CharacterCount() )
+ .WriteUInt16( pPara->nDepth );
+ }
+ mpPptEscherEx->EndAtom( EPP_BaseTextPropAtom );
+ mpPptEscherEx->AddAtom( 10, EPP_TextSpecInfoAtom );
+ mpStrm->WriteUInt32( mnTextSize ).WriteUInt32( 1 ).WriteUInt16( 0 );
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_ClientTextBox
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+ }
+ continue;
+ }
+ else
+ {
+ mnTextStyle = EPP_TEXTSTYLE_BODY;
+ nPlaceHolderAtom = rLayout.nTypeOfOutliner;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
+ aSolverContainer );
+ aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
+ ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
+ if ( mbEmptyPresObj )
+ {
+ sal_uInt32 nNoLineDrawDash = 0;
+ aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
+ nNoLineDrawDash |= 0x10001;
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
+ }
+ }
+ }
+ else
+ mbPresObj = false;
+ }
+ if ( !mbPresObj )
+ {
+ if (ePageType == MASTER )
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mXShape);
+ if (pObj && pObj->IsNotVisibleAsMaster())
+ continue;
+ }
+
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( ( mType == "drawing.Page" ) || ( mType == "presentation.Page" ) )
+ {
+ if ( ( ePageType == NOTICE ) && mbPresObj )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Notes, EPP_PLACEHOLDER_MASTERNOTESSLIDEIMAGE ) )
+ continue;
+ else
+ nPlaceHolderAtom = EPP_PLACEHOLDER_NOTESSLIDEIMAGE;
+ }
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ else if ( mType == "drawing.Frame" )
+ {
+ continue;
+ }
+ else if ( ( mType == "drawing.OLE2" ) || ( mType == "presentation.OLE2" )
+ || ( mType == "presentation.Chart" ) || ( mType == "presentation.Calc" )
+ || ( mType == "presentation.OrgChart" ) )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ if ( mbEmptyPresObj && ( ePageType == NORMAL ) )
+ {
+ nPlaceHolderAtom = rLayout.nUsedObjectPlaceHolder;
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
+ aSolverContainer );
+ mnTxId += 0x60;
+ aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
+ }
+ else
+ {
+ mpExEmbed->WriteUInt32( 0xf | ( EPP_ExEmbed << 16 ) )
+ .WriteUInt32( 0 ); // Size of this container
+
+ sal_uInt32 nSize, nOldPos = mpExEmbed->Tell();
+
+ mpExEmbed->WriteUInt32( EPP_ExEmbedAtom << 16 )
+ .WriteUInt32( 8 )
+ .WriteUInt32( 0 ) // follow colorscheme : 0->do not follow
+ // 1->follow colorscheme
+ // 2->follow text and background scheme
+ .WriteUChar( 1 ) // (bool)set if embedded server can not be locked
+ .WriteUChar( 0 ) // (bool)do not need to send dimension
+ .WriteUChar( 0 ) // (bool)is object a world table
+ .WriteUChar( 0 ); // pad byte
+
+ std::unique_ptr<PPTExOleObjEntry> pE( new PPTExOleObjEntry( NORMAL_OLE_OBJECT, mpExEmbed->Tell() ) );
+ pE->xShape = mXShape;
+ maExOleObj.push_back( std::move(pE) );
+
+ mnExEmbed++;
+
+ sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
+ try
+ {
+ // try to get the aspect when available
+ css::uno::Reference< css::beans::XPropertySet > xShapeProps( mXShape, css::uno::UNO_QUERY_THROW );
+ xShapeProps->getPropertyValue("Aspect") >>= nAspect;
+ }
+ catch( css::uno::Exception& )
+ {}
+
+ mpExEmbed->WriteUInt32( 1 | ( EPP_ExOleObjAtom << 16 ) )
+ .WriteUInt32( 24 )
+ .WriteUInt32( nAspect ) // Aspect
+ .WriteUInt32( 0 )
+ .WriteUInt32( mnExEmbed ) // index to the persist table
+ .WriteUInt32( 0 ) // subtype
+ .WriteUInt32( 0 )
+ .WriteUInt32( 0x0012b600 );
+
+ nSize = mpExEmbed->Tell() - nOldPos;
+ mpExEmbed->Seek( nOldPos - 4 );
+ mpExEmbed->WriteUInt32( nSize );
+ mpExEmbed->Seek( STREAM_SEEK_TO_END );
+ nOlePictureId = mnExEmbed;
+
+ ShapeFlag nSpFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty;
+ if ( nOlePictureId )
+ nSpFlags |= ShapeFlag::OLEShape;
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame, nSpFlags, aSolverContainer );
+ if ( aPropOpt.CreateOLEGraphicProperties( mXShape ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ if ( nOlePictureId )
+ aPropOpt.AddOpt( ESCHER_Prop_pictureId, nOlePictureId );
+ }
+ }
+ else if ( mType == "presentation.Header" )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERHEADER ) )
+ continue;
+ else
+ {
+ mbPresObj = false;
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( mType == "presentation.Footer" )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERFOOTER ) )
+ continue;
+ else
+ {
+ mbPresObj = false;
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( mType == "presentation.DateTime" )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERDATE ) )
+ continue;
+ else
+ {
+ mbPresObj = false;
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( mType == "presentation.SlideNumber" )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERSLIDENUMBER ) )
+ continue;
+ else
+ {
+ mbPresObj = false;
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( (mType.getLength() > 9) && (mType[8] == '3') && (mType[9] == 'D') ) // drawing.3D
+ {
+ // SceneObject, CubeObject, SphereObject, LatheObject, ExtrudeObject, PolygonObject
+ if ( !ImplGetPropertyValue( "Bitmap" ) )
+ continue;
+
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+
+ if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Bitmap", false ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ else if ( mType == "drawing.Media" )
+ {
+ mnAngle = 0;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ if ( aPropOpt.CreateMediaGraphicProperties( mXShape ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, mXPropSet, "MediaURL", true ) )
+ {
+ OUString aMediaURL;
+ if ( (aAny >>= aMediaURL ) && !aMediaURL.isEmpty() )
+ {
+ // SJ: creating the Media RefObj
+ sal_uInt32 nRefId = ++mnExEmbed;
+
+ mpExEmbed->WriteUInt16( 0xf )
+ .WriteUInt16( EPP_ExMCIMovie ) // PPT_PST_ExAviMovie
+ .WriteUInt32( 0 );
+ sal_uInt32 nSize, nStart = mpExEmbed->Tell();
+ mpExEmbed->WriteUInt16( 0 )
+ .WriteUInt16( EPP_ExObjRefAtom )
+ .WriteUInt32( 4 )
+ .WriteUInt32( nRefId );
+ mpExEmbed->WriteUInt16( 0xf )
+ .WriteUInt16( EPP_ExVideo )
+ .WriteUInt32( 0 );
+
+ mpExEmbed->WriteUInt16( 0 )
+ .WriteUInt16( EPP_ExMediaAtom )
+ .WriteUInt32( 8 )
+ .WriteUInt32( nRefId )
+ .WriteUInt16( 0 )
+ .WriteUInt16( 0x435 );
+
+ sal_uInt16 i, nStringLen = static_cast<sal_uInt16>(aMediaURL.getLength());
+ mpExEmbed->WriteUInt32( EPP_CString << 16 ).WriteUInt32( nStringLen * 2 );
+ for ( i = 0; i < nStringLen; i++ )
+ {
+ sal_Unicode nChar = aMediaURL[ i ];
+ mpExEmbed->WriteUInt16( nChar );
+ }
+ nSize = mpExEmbed->Tell() - nStart;
+ mpExEmbed->SeekRel( - ( static_cast<sal_Int32>(nSize) + 4 ) );
+ mpExEmbed->WriteUInt32( nSize ); // size of PPT_PST_ExMCIMovie
+ mpExEmbed->SeekRel( 0x10 );
+ nSize -= 20;
+ mpExEmbed->WriteUInt32( nSize ); // PPT_PST_ExMediaAtom
+ mpExEmbed->SeekRel( nSize );
+
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+ pClientData->WriteUInt16( 0 )
+ .WriteUInt16( EPP_ExObjRefAtom )
+ .WriteUInt32( 4 )
+ .WriteUInt32( nRefId );
+ // write EPP_InteractiveInfo container for no_action
+ pClientData->WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( 24 );
+ pClientData->WriteUInt16( 0 )
+ .WriteUInt16( EPP_InteractiveInfoAtom )
+ .WriteUInt32( 16 )
+ .WriteUInt32( 0 )
+ .WriteUInt32( 0 )
+ .WriteUChar( 6 )
+ .WriteUChar( 0 )
+ .WriteUChar( 0 )
+ .WriteUChar( 0 )
+ .WriteUInt32( 0 );
+ }
+ }
+ }
+ else if ( (mType == "drawing.Table") || (mType == "presentation.Table") )
+ {
+ if ( eCa != css::presentation::ClickAction_NONE )
+ {
+ SvMemoryStream aTmp(0x200, 0x200);
+ ImplWriteClickAction( aTmp, eCa, bMediaClickAction );
+ }
+ ImplCreateTable( mXShape, aSolverContainer, aPropOpt );
+ continue;
+ }
+ else if ( mType == "drawing.dontknow" )
+ {
+ mnAngle = 0;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ else
+ {
+ continue;
+ }
+
+ bool bClientData = ( bEffect || ( eCa != css::presentation::ClickAction_NONE ) ||
+ nPlaceHolderAtom || nOlePictureId );
+ if ( bClientData )
+ {
+ if ( nPlaceHolderAtom )
+ {
+ sal_Int32 nPlacementID = -1;
+ if ( ( mnTextStyle == EPP_TEXTSTYLE_TITLE ) || ( mnTextStyle == EPP_TEXTSTYLE_BODY ) )
+ nPlacementID = nIndices++;
+ else
+ {
+ switch ( nPlaceHolderAtom )
+ {
+ default :
+ {
+ if ( nPlaceHolderAtom < 19 )
+ break;
+ [[fallthrough]];
+ }
+ case EPP_PLACEHOLDER_NOTESBODY :
+ case EPP_PLACEHOLDER_MASTERDATE :
+ case EPP_PLACEHOLDER_NOTESSLIDEIMAGE :
+ case EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE :
+ nPlacementID = nIndices++;
+ }
+ }
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+
+ pClientData->WriteUInt32( EPP_OEPlaceholderAtom << 16 ).WriteUInt32( 8 )
+ .WriteInt32( nPlacementID ) // PlacementID
+ .WriteUChar( nPlaceHolderAtom ) // PlaceHolderID
+ .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
+ .WriteUInt16( 0 ); // padword
+ }
+ if ( nOlePictureId )
+ {
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+
+ pClientData->WriteUInt32( EPP_ExObjRefAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( nOlePictureId );
+ nOlePictureId = 0;
+ }
+ if ( bEffect && !pClientData )
+ {
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+ }
+
+ if ( eCa != css::presentation::ClickAction_NONE )
+ {
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+ ImplWriteClickAction( *pClientData, eCa, bMediaClickAction );
+ }
+ }
+ if ( ( mnTextStyle == EPP_TEXTSTYLE_TITLE ) || ( mnTextStyle == EPP_TEXTSTYLE_BODY ) )
+ {
+ if ( !pClientTextBox )
+ pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
+
+ if ( !mbEmptyPresObj )
+ {
+ if ( ( ePageType == NORMAL ) && !bMasterPage )
+ {
+ sal_uInt32 nTextType = EPP_TEXTTYPE_Body;
+ if ( mnTextStyle == EPP_TEXTSTYLE_BODY )
+ {
+ if ( bSecOutl )
+ nTextType = EPP_TEXTTYPE_HalfBody;
+ else if ( mType == "presentation.Subtitle" )
+ nTextType = EPP_TEXTTYPE_CenterBody;
+ bSecOutl = true;
+ }
+ else
+ nTextType = EPP_TEXTTYPE_Title;
+
+ TextRuleEntry aTextRule;
+ SvMemoryStream aExtBu( 0x200, 0x200 );
+ ImplGetText();
+ ImplWriteTextStyleAtom( *pClientTextBox, nTextType, nPObjects, &aTextRule, aExtBu, nullptr );
+ ImplWriteExtParaHeader( aExtBu, nPObjects++, nTextType, nPageNumber + 0x100 );
+ SvMemoryStream* pOut = aTextRule.pOut.get();
+ if ( pOut )
+ {
+ pClientTextBox->WriteBytes(pOut->GetData(), pOut->Tell());
+ aTextRule.pOut.reset();
+ }
+ if ( aExtBu.Tell() )
+ {
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+ ImplProgTagContainer( pClientData.get(), &aExtBu );
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( !aPropOpt.IsFontWork() )
+ {
+ if ( mnTextSize || ( nPlaceHolderAtom == EPP_PLACEHOLDER_MASTERDATE ) || ( nPlaceHolderAtom == EPP_PLACEHOLDER_NOTESBODY ) )
+ {
+ int nInstance2;
+ if ( ( nPlaceHolderAtom == EPP_PLACEHOLDER_MASTERDATE ) || ( nPlaceHolderAtom == EPP_PLACEHOLDER_NOTESBODY ) )
+ nInstance2 = 2;
+ else
+ nInstance2 = EPP_TEXTTYPE_Other; // Text in a Shape
+
+ if ( !pClientTextBox )
+ pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
+
+ SvMemoryStream aExtBu( 0x200, 0x200 );
+ ImplWriteTextStyleAtom( *pClientTextBox, nInstance2, 0, nullptr, aExtBu, &aPropOpt );
+ if ( aExtBu.Tell() )
+ {
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+ ImplProgTagContainer( pClientData.get(), &aExtBu );
+ }
+ }
+ else if ( nPlaceHolderAtom >= 19 )
+ {
+ if ( !pClientTextBox )
+ pClientTextBox.reset(new SvMemoryStream( 12 ));
+
+ pClientTextBox->WriteUInt32( EPP_TextHeaderAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( 7 );
+ }
+ }
+ }
+
+ aPropOpt.CreateShadowProperties( mXPropSet );
+ maRect.Justify();
+ if ( mnAngle )
+ ImplFlipBoundingBox( aPropOpt );
+ aPropOpt.CreateShapeProperties( mXShape );
+ aPropOpt.Commit( *mpStrm );
+ if ( GetCurrentGroupLevel() > 0 )
+ mpPptEscherEx->AddChildAnchor( maRect );
+ else
+ mpPptEscherEx->AddClientAnchor( maRect );
+
+ if ( pClientData )
+ {
+ mpStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
+ .WriteUInt32( pClientData->Tell() );
+
+ mpStrm->WriteBytes(pClientData->GetData(), pClientData->Tell());
+ pClientData.reset();
+ }
+ if ( pClientTextBox )
+ {
+ mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
+ .WriteUInt32( pClientTextBox->Tell() );
+
+ mpStrm->WriteBytes(pClientTextBox->GetData(), pClientTextBox->Tell());
+ pClientTextBox.reset();
+ }
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+ }
+ nPrevTextStyle = mnTextStyle;
+
+ if ( bAdditionalText )
+ {
+ bAdditionalText = false;
+
+ css::uno::Any aAny;
+ EscherPropertyContainer aPropOpt;
+ mnAngle = ( PropValue::GetPropertyValue( aAny,
+ mXPropSet, "RotateAngle", true ) )
+ ? *o3tl::doAccess<sal_Int32>(aAny)
+ : 0;
+
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
+ if ( mType == "drawing.Line" )
+ {
+ double fDist = hypot( maRect.GetWidth(), maRect.GetHeight() );
+ maRect = ::tools::Rectangle( Point( aTextRefPoint.X, aTextRefPoint.Y ),
+ Point( static_cast<sal_Int32>( aTextRefPoint.X + fDist ), aTextRefPoint.Y - 1 ) );
+ ImplCreateTextShape( aPropOpt, aSolverContainer, false );
+ aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x60006 ); // Size Shape To Fit Text
+ if ( mnAngle < 0 )
+ mnAngle = ( 36000 + mnAngle ) % 36000;
+ if ( mnAngle )
+ ImplFlipBoundingBox( aPropOpt );
+ }
+ else
+ {
+ ImplCreateTextShape( aPropOpt, aSolverContainer, false );
+ if ( mnAngle < 0 )
+ mnAngle = ( 36000 + mnAngle ) % 36000;
+ else
+ mnAngle = ( 36000 - ( mnAngle % 36000 ) );
+
+ mnAngle *= 655;
+ mnAngle += 0x8000;
+ mnAngle &=~0xffff; // round nAngle to full grad
+ aPropOpt.AddOpt( ESCHER_Prop_Rotation, mnAngle );
+
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->SetGroupSnapRect( nGroupLevel, maRect );
+ // mpPptEscherEx->SetGroupLogicRect( nGroupLevel, maRect );
+ }
+ if ( !pClientTextBox )
+ pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
+
+ SvMemoryStream aExtBu( 0x200, 0x200 );
+ ImplWriteTextStyleAtom( *pClientTextBox, EPP_TEXTTYPE_Other, 0, nullptr, aExtBu, &aPropOpt );
+
+ aPropOpt.CreateShapeProperties( mXShape );
+ aPropOpt.Commit( *mpStrm );
+ if ( GetCurrentGroupLevel() > 0 )
+ mpPptEscherEx->AddChildAnchor( maRect );
+ else
+ mpPptEscherEx->AddClientAnchor( maRect );
+
+ mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
+ .WriteUInt32( pClientTextBox->Tell() );
+
+ mpStrm->WriteBytes(pClientTextBox->GetData(), pClientTextBox->Tell());
+ pClientTextBox.reset();
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->LeaveGroup();
+ }
+ }
+ ClearGroupTable(); // storing groups if any are still open, which should not be the case
+ nGroups = GetGroupsClosed();
+ for ( sal_uInt32 i = 0; i < nGroups; i++, mpPptEscherEx->LeaveGroup() ) ;
+ mnPagesWritten++;
+}
+
+struct CellBorder
+{
+ sal_Int32 mnPos; // specifies the distance to the top/left position of the table
+ table::BorderLine maCellBorder;
+
+ CellBorder() : mnPos ( 0 ) {};
+};
+
+bool PPTWriter::ImplCreateCellBorder( const CellBorder* pCellBorder, sal_Int32 nX1, sal_Int32 nY1, sal_Int32 nX2, sal_Int32 nY2)
+{
+ sal_Int32 nLineWidth = pCellBorder->maCellBorder.OuterLineWidth + pCellBorder->maCellBorder.InnerLineWidth;
+ if ( nLineWidth )
+ {
+ nLineWidth *= 2;
+ mnAngle = 0;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ EscherPropertyContainer aPropOptSp;
+
+ sal_uInt32 nId = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Line,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Child,
+ nId );
+ aPropOptSp.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
+ aPropOptSp.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0xa0008 );
+ aPropOptSp.AddOpt( ESCHER_Prop_fshadowObscured, 0x20000 );
+
+ sal_uInt32 nBorderColor = pCellBorder->maCellBorder.Color & 0xff00; // green
+ nBorderColor |= static_cast< sal_uInt8 >( pCellBorder->maCellBorder.Color ) << 16; // red
+ nBorderColor |= static_cast< sal_uInt8 >( pCellBorder->maCellBorder.Color >> 16 ); // blue
+ aPropOptSp.AddOpt( ESCHER_Prop_lineColor, nBorderColor );
+
+ aPropOptSp.AddOpt( ESCHER_Prop_lineWidth, nLineWidth * 360 );
+ aPropOptSp.AddOpt( ESCHER_Prop_fc3DLightFace, 0x80000 );
+ aPropOptSp.Commit( *mpStrm );
+ mpPptEscherEx->AddAtom( 16, ESCHER_ChildAnchor );
+ mpStrm ->WriteInt32( nX1 )
+ .WriteInt32( nY1 )
+ .WriteInt32( nX2 )
+ .WriteInt32( nY2 );
+ mpPptEscherEx->CloseContainer();
+ return true;
+ }
+ return false;
+}
+
+//get merged cell's width
+static sal_Int32 GetCellRight( sal_Int32 nColumn,
+ ::tools::Rectangle const & rect,
+ std::vector< std::pair< sal_Int32, sal_Int32 > >& aColumns,
+ uno::Reference< table::XMergeableCell > const & xCell )
+{
+ sal_Int32 nRight = aColumns[ nColumn ].first + aColumns[ nColumn ].second;
+ for ( sal_Int32 nColumnSpan = 1; nColumnSpan < xCell->getColumnSpan(); nColumnSpan++ )
+ {
+ sal_uInt32 nC = nColumnSpan + nColumn;
+ if ( nC < aColumns.size() )
+ nRight += aColumns[ nC ].second;
+ else
+ nRight = rect.Right();
+ }
+ return nRight;
+}
+//get merged cell's height
+static sal_Int32 GetCellBottom( sal_Int32 nRow,
+ ::tools::Rectangle const & rect,
+ std::vector< std::pair< sal_Int32, sal_Int32 > >& aRows,
+ uno::Reference< table::XMergeableCell > const & xCell )
+{
+ sal_Int32 nBottom = aRows[nRow].first + aRows[nRow].second;
+ for ( sal_Int32 nRowSpan = 1; nRowSpan < xCell->getRowSpan(); nRowSpan++ )
+ {
+ sal_uInt32 nR = nRowSpan + nRow;
+ if ( nR < aRows.size() )
+ nBottom += aRows[ nR ].second;
+ else
+ nBottom = rect.Bottom();
+ }
+ return nBottom;
+}
+
+void PPTWriter::WriteCString( SvStream& rSt, const OUString& rString, sal_uInt32 nInstance )
+{
+ sal_Int32 nLen = rString.getLength();
+ if ( nLen )
+ {
+ rSt.WriteUInt32( ( nInstance << 4 ) | ( EPP_CString << 16 ) )
+ .WriteUInt32( nLen << 1 );
+ for ( sal_Int32 i = 0; i < nLen; i++ )
+ rSt.WriteUInt16( rString[i] );
+ }
+}
+
+namespace {
+
+class ContainerGuard
+{
+private:
+ PptEscherEx* m_pPptEscherEx;
+public:
+ ContainerGuard(PptEscherEx* pPptEscherEx, sal_uInt16 nRecord)
+ : m_pPptEscherEx(pPptEscherEx)
+ {
+ m_pPptEscherEx->OpenContainer(nRecord);
+ }
+ ~ContainerGuard()
+ {
+ m_pPptEscherEx->CloseContainer();
+ }
+};
+
+}
+
+void PPTWriter::ImplCreateTable( uno::Reference< drawing::XShape > const & rXShape, EscherSolverContainer& aSolverContainer,
+ EscherPropertyContainer& aPropOpt )
+{
+ try
+ {
+ uno::Reference< table::XTable > xTable;
+ if ( mXPropSet->getPropertyValue( "Model" ) >>= xTable )
+ {
+ uno::Reference< table::XColumnRowRange > xColumnRowRange( xTable, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xColumns( xColumnRowRange->getColumns(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xRows( xColumnRowRange->getRows(), uno::UNO_QUERY_THROW );
+ sal_uInt16 nRowCount = static_cast< sal_uInt16 >( xRows->getCount() );
+ sal_uInt16 nColumnCount = static_cast< sal_uInt16 >( xColumns->getCount() );
+
+ std::vector< std::pair< sal_Int32, sal_Int32 > > aColumns;
+ std::vector< std::pair< sal_Int32, sal_Int32 > > aRows;
+
+ awt::Point aPosition( MapPoint( rXShape->getPosition() ) );
+ sal_Int32 nPosition = aPosition.X;
+ for ( sal_Int32 x = 0; x < nColumnCount; x++ )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xColumns->getByIndex( x ), uno::UNO_QUERY_THROW );
+ awt::Size aS( 0, 0 );
+ xPropSet->getPropertyValue( "Width" ) >>= aS.Width;
+ awt::Size aM( MapSize( aS ) );
+ aColumns.emplace_back( nPosition, aM.Width );
+ nPosition += aM.Width;
+ if ( x == nColumnCount - 1 && nPosition != maRect.Right() )
+ maRect.SetRight( nPosition );
+ }
+
+ nPosition = aPosition.Y;
+ for ( sal_Int32 y = 0; y < nRowCount; y++ )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xRows->getByIndex( y ), uno::UNO_QUERY_THROW );
+ awt::Size aS( 0, 0 );
+ xPropSet->getPropertyValue( "Height" ) >>= aS.Height;
+ awt::Size aM( MapSize( aS ) );
+ aRows.emplace_back( nPosition, aM.Height );
+ nPosition += aM.Height;
+ if ( y == nRowCount - 1 && nPosition != maRect.Bottom())
+ maRect.SetBottom( nPosition );
+ }
+ std::optional<ContainerGuard> xSpgrContainer(std::in_place, mpPptEscherEx.get(), ESCHER_SpgrContainer);
+ std::optional<ContainerGuard> xSpContainer(std::in_place, mpPptEscherEx.get(), ESCHER_SpContainer);
+ mpPptEscherEx->AddAtom( 16, ESCHER_Spgr, 1 );
+ mpStrm ->WriteInt32( maRect.Left() ) // Bounding box for the grouped shapes to which they are attached
+ .WriteInt32( maRect.Top() )
+ .WriteInt32( maRect.Right() )
+ .WriteInt32( maRect.Bottom() );
+
+ sal_uInt32 nShapeId = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Min, ShapeFlag::HaveAnchor | ShapeFlag::Group, nShapeId );
+ // TODO: check flags, comment does not match code // Flags: Group | Patriarch
+ aSolverContainer.AddShape( rXShape, nShapeId );
+ EscherPropertyContainer aPropOpt2;
+
+ SvMemoryStream aMemStrm;
+ aMemStrm.WriteUInt16( nRowCount )
+ .WriteUInt16( nRowCount )
+ .WriteUInt16( 4 );
+
+ for( const auto& rRow : aRows )
+ aMemStrm.WriteInt32( rRow.second );
+
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x1000100 );
+ aPropOpt2.AddOpt( ESCHER_Prop_tableProperties, 1 );
+ aPropOpt2.AddOpt(ESCHER_Prop_tableRowProperties, true, 0, aMemStrm);
+ aPropOpt.CreateShapeProperties( rXShape );
+ aPropOpt.Commit( *mpStrm );
+ aPropOpt2.Commit( *mpStrm, 3, ESCHER_UDefProp );
+ if ( GetCurrentGroupLevel() > 0 )
+ mpPptEscherEx->AddChildAnchor( maRect );
+ else
+ mpPptEscherEx->AddClientAnchor( maRect );
+ xSpContainer.reset(); //ESCHER_SpContainer
+
+ uno::Reference< table::XCellRange > xCellRange( xTable, uno::UNO_QUERY_THROW );
+ for( sal_Int32 nRow = 0; nRow < xRows->getCount(); nRow++ )
+ {
+ for( sal_Int32 nColumn = 0; nColumn < xColumns->getCount(); nColumn++ )
+ {
+ uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nRow ), uno::UNO_QUERY_THROW );
+ if ( !xCell->isMerged() )
+ {
+ sal_Int32 nLeft = aColumns[ nColumn ].first;
+ sal_Int32 nTop = aRows[ nRow ].first;
+ sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
+ sal_Int32 nBottom = GetCellBottom( nRow, maRect,aRows,xCell );
+
+ mbFontIndependentLineSpacing = false;
+ mXPropSet.set( xCell, uno::UNO_QUERY_THROW );
+ mXText.set( xCell, uno::UNO_QUERY_THROW );
+ mnTextSize = mXText->getString().getLength();
+
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, mXPropSet, "FontIndependentLineSpacing", true ) )
+ aAny >>= mbFontIndependentLineSpacing;
+
+ EscherPropertyContainer aPropOptSp;
+ std::optional<ContainerGuard> xCellContainer(std::in_place, mpPptEscherEx.get(), ESCHER_SpContainer);
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Child,
+ aSolverContainer );
+ aPropOptSp.CreateFillProperties( mXPropSet, true );
+ aPropOptSp.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
+ mnTxId += 0x60;
+ aPropOptSp.CreateTextProperties( mXPropSet, mnTxId );
+ aPropOptSp.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapSquare );
+
+ SvMemoryStream aClientTextBox( 0x200, 0x200 );
+ SvMemoryStream aExtBu( 0x200, 0x200 );
+
+ ImplWriteTextStyleAtom( aClientTextBox, EPP_TEXTTYPE_Other, 0, nullptr, aExtBu, &aPropOptSp );
+
+ // need write client data for extend bullet
+ if ( aExtBu.Tell() )
+ {
+ SvMemoryStream aClientData( 0x200, 0x200 );
+ ImplProgTagContainer( &aClientData, &aExtBu );
+ mpStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
+ .WriteUInt32( aClientData.Tell() );
+
+ mpStrm->WriteBytes(aClientData.GetData(), aClientData.Tell());
+ }
+
+ aPropOptSp.Commit( *mpStrm );
+ mpPptEscherEx->AddAtom( 16, ESCHER_ChildAnchor );
+ mpStrm ->WriteInt32( nLeft )
+ .WriteInt32( nTop )
+ .WriteInt32( nRight )
+ .WriteInt32( nBottom );
+
+ mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
+ .WriteUInt32( aClientTextBox.Tell() );
+
+ mpStrm->WriteBytes(aClientTextBox.GetData(), aClientTextBox.Tell());
+ xCellContainer.reset();
+ }
+ }
+ }
+
+ // creating horz lines
+ for( sal_Int32 nLine = 0; nLine < ( xRows->getCount() + 1 ); nLine++ )
+ {
+ for( sal_Int32 nColumn = 0; nColumn < xColumns->getCount(); nColumn++ )
+ {
+ CellBorder aCellBorder;
+ aCellBorder.mnPos = aColumns[ nColumn ].first;
+ bool bTop = false;
+ //write nLine*nColumn cell's top border
+ if ( nLine < xRows->getCount() )
+ { // top border
+ uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nLine ), uno::UNO_QUERY_THROW );
+ if ( !xCell->isMerged() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet2( xCell, uno::UNO_QUERY_THROW );
+ table::BorderLine aBorderLine;
+ if ( xPropSet2->getPropertyValue( "TopBorder" ) >>= aBorderLine )
+ aCellBorder.maCellBorder = aBorderLine;
+ sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
+ bTop = ImplCreateCellBorder( &aCellBorder, aCellBorder.mnPos,
+ aRows[ nLine ].first, nRight, aRows[ nLine ].first );
+ }
+ }
+
+ //if nLine*nColumn cell's top border is empty, check (nLine-1)*nColumn cell's bottom border
+ //and write the last row's bottom border
+ if (( nLine && !bTop ) || (nLine == xRows->getCount()))
+ { // bottom border
+ sal_Int32 nRow = nLine;
+
+ while( nRow )
+ { //find last no merged cell
+ uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nRow - 1 ), uno::UNO_QUERY_THROW );
+ if ( !xCell->isMerged() )
+ {
+ sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
+ sal_Int32 nBottom = GetCellBottom( nRow - 1, maRect,aRows,xCell );
+ if ( nBottom == ( aRows[ nLine-1 ].first + aRows[ nLine-1 ].second ) )
+ {
+ uno::Reference< table::XMergeableCell > xCellOwn( xCellRange->getCellByPosition( nColumn, nRow - 1 ), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xPropSet2( xCellOwn, uno::UNO_QUERY_THROW );
+ table::BorderLine aBorderLine;
+ if ( xPropSet2->getPropertyValue( "BottomBorder" ) >>= aBorderLine )
+ aCellBorder.maCellBorder = aBorderLine;
+ ImplCreateCellBorder( &aCellBorder, aCellBorder.mnPos,
+ nBottom, nRight, nBottom);
+ }
+ nRow=0;
+ }
+ else
+ nRow--;
+ }
+ }
+ }
+ }
+
+ // creating vertical lines
+ for( sal_Int32 nLine = 0; nLine < ( xColumns->getCount() + 1 ); nLine++ )
+ {
+ for( sal_Int32 nRow = 0; nRow < xRows->getCount(); nRow++ )
+ {
+
+ CellBorder aCellBorder;
+ aCellBorder.mnPos = aRows[ nRow].first;
+ bool bLeft = false;
+ if ( nLine < xColumns->getCount() )
+ { // left border
+ uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nLine, nRow ), uno::UNO_QUERY_THROW );
+ if (!xCell->isMerged() )
+ {
+ uno::Reference< beans::XPropertySet > xCellSet( xCell, uno::UNO_QUERY_THROW );
+ table::BorderLine aBorderLine;
+ if ( xCellSet->getPropertyValue( "LeftBorder" ) >>= aBorderLine )
+ aCellBorder.maCellBorder = aBorderLine;
+ sal_Int32 nBottom = GetCellBottom( nRow, maRect, aRows,xCell );
+ bLeft = ImplCreateCellBorder( &aCellBorder, aColumns[nLine].first, aCellBorder.mnPos,
+ aColumns[nLine].first, nBottom );
+ }
+ }
+ if ( ( nLine && !bLeft )||(nLine == xColumns->getCount()))
+ { // right border
+ sal_Int32 nColumn = nLine;
+ while ( nColumn )
+ {
+ uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn - 1, nRow ), uno::UNO_QUERY_THROW );
+ if (!xCell->isMerged() )
+ {
+ sal_Int32 nRight = GetCellRight( nColumn-1, maRect, aColumns,xCell );
+ sal_Int32 nBottom = GetCellBottom( nRow, maRect, aRows, xCell );
+ if ( nRight == (aColumns[nLine-1].first + aColumns[nLine-1].second) )
+ {
+ uno::Reference< table::XMergeableCell > xCellOwn( xCellRange->getCellByPosition( nColumn - 1, nRow ), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xCellSet( xCellOwn, uno::UNO_QUERY_THROW );
+ table::BorderLine aBorderLine;
+ if ( xCellSet->getPropertyValue( "RightBorder" ) >>= aBorderLine )
+ aCellBorder.maCellBorder = aBorderLine;
+ ImplCreateCellBorder( &aCellBorder, nRight, aCellBorder.mnPos,
+ nRight, nBottom );
+ }
+ nColumn = 0;
+ }
+ else
+ nColumn --;
+ }
+ }
+ }
+ }
+
+ xSpgrContainer.reset(); //ESCHER_SpgrContainer
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+void TextObjBinary::Write( SvStream* pStrm )
+{
+ sal_uInt32 nSize, nPos = pStrm->Tell();
+ pStrm->WriteUInt32( EPP_TextCharsAtom << 16 ).WriteUInt32( 0 );
+ for ( sal_uInt32 i = 0; i < ParagraphCount(); ++i )
+ GetParagraph(i)->Write( pStrm );
+ nSize = pStrm->Tell() - nPos;
+ pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
+ pStrm->WriteUInt32( nSize - 8 );
+ pStrm->SeekRel( nSize - 8 );
+}
+
+void TextObjBinary::WriteTextSpecInfo( SvStream* pStrm )
+{
+ sal_uInt32 nCharactersLeft( Count() );
+ if ( nCharactersLeft < 1 )
+ return;
+
+ EscherExAtom aAnimationInfoAtom( *pStrm, EPP_TextSpecInfoAtom, 0, 0 );
+ for ( sal_uInt32 i = 0; nCharactersLeft && i < ParagraphCount(); ++i )
+ {
+ ParagraphObj* pPtr = GetParagraph(i);
+ for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPtr->begin(); nCharactersLeft && it != pPtr->end(); ++it )
+ {
+ const PortionObj& rPortion = **it;
+ sal_Int32 nPortionSize = rPortion.mnTextSize >= nCharactersLeft ? nCharactersLeft : rPortion.mnTextSize;
+ sal_Int32 const nFlags = 7;
+ nCharactersLeft -= nPortionSize;
+ pStrm ->WriteUInt32( nPortionSize )
+ .WriteInt32( nFlags )
+ .WriteInt16( 1 ) // spellinfo -> needs rechecking
+ .WriteInt16( static_cast<sal_uInt16>(LanguageTag( rPortion.meCharLocale ).makeFallback().getLanguageType()) )
+ .WriteInt16( 0 ); // alt language
+ }
+ }
+ if ( nCharactersLeft )
+ pStrm->WriteUInt32( nCharactersLeft ).WriteInt32( 1 ).WriteInt16( 1 );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/escherex.cxx b/sd/source/filter/eppt/escherex.cxx
new file mode 100644
index 000000000..5032c2721
--- /dev/null
+++ b/sd/source/filter/eppt/escherex.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 "escherex.hxx"
+
+PptEscherEx::PptEscherEx( SvStream& rOutStrm, const OUString& rBaseURI ) :
+ EscherEx( std::make_shared<EscherExGlobal>( ), &rOutStrm )
+{
+ mxGlobal->SetBaseURI( rBaseURI );
+ mnCurrentDg = 0;
+}
+
+sal_uInt32 PptEscherEx::DrawingGroupContainerSize()
+{
+ return ImplDggContainerSize() + 8;
+}
+
+void PptEscherEx::WriteDrawingGroupContainer( SvStream& rSt )
+{
+ sal_uInt32 nSize = DrawingGroupContainerSize();
+ rSt.WriteUInt32( 0xf | ( 1035 << 16 ) ) // EPP_PPDrawingGroup
+ .WriteUInt32( nSize - 8 );
+
+ ImplWriteDggContainer( rSt );
+}
+
+sal_uInt32 PptEscherEx::ImplDggContainerSize()
+{
+ sal_uInt32 nSize;
+
+ nSize = mxGlobal->GetDggAtomSize();
+ nSize += mxGlobal->GetBlibStoreContainerSize();
+ nSize += ImplOptAtomSize();
+ nSize += ImplSplitMenuColorsAtomSize();
+
+ return nSize + 8;
+}
+
+void PptEscherEx::ImplWriteDggContainer( SvStream& rSt )
+{
+ sal_uInt32 nSize = ImplDggContainerSize();
+ if ( nSize )
+ {
+ rSt.WriteUInt32( 0xf | ( ESCHER_DggContainer << 16 ) )
+ .WriteUInt32( nSize - 8 );
+
+ mxGlobal->SetDggContainer();
+ mxGlobal->WriteDggAtom( rSt );
+ mxGlobal->WriteBlibStoreContainer( rSt );
+ ImplWriteOptAtom( rSt );
+ ImplWriteSplitMenuColorsAtom( rSt );
+ }
+}
+
+#define ESCHER_OPT_COUNT 6
+
+sal_uInt32 PptEscherEx::ImplOptAtomSize()
+{
+ sal_uInt32 nSize = 0;
+ if ( ESCHER_OPT_COUNT != 0 )
+ nSize = ( ESCHER_OPT_COUNT * 6 ) + 8;
+ return nSize;
+}
+
+void PptEscherEx::ImplWriteOptAtom( SvStream& rSt )
+{
+ sal_uInt32 nSize = ImplOptAtomSize();
+ if ( nSize )
+ {
+ rSt.WriteUInt32( ( ESCHER_OPT << 16 ) | ( ESCHER_OPT_COUNT << 4 ) | 0x3 )
+ .WriteUInt32( nSize - 8 )
+ .WriteUInt16( ESCHER_Prop_fillColor ) .WriteUInt32( 0xffb800 )
+ .WriteUInt16( ESCHER_Prop_fillBackColor ) .WriteUInt32( 0 )
+ .WriteUInt16( ESCHER_Prop_fNoFillHitTest ) .WriteUInt32( 0x00100010 )
+ .WriteUInt16( ESCHER_Prop_lineColor ) .WriteUInt32( 0x8000001 )
+ .WriteUInt16( ESCHER_Prop_fNoLineDrawDash ) .WriteUInt32( 0x00080008 )
+ .WriteUInt16( ESCHER_Prop_shadowColor ) .WriteUInt32( 0x8000002 );
+ }
+}
+
+#define ESCHER_SPLIT_MENU_COLORS_COUNT 4
+
+sal_uInt32 PptEscherEx::ImplSplitMenuColorsAtomSize()
+{
+ sal_uInt32 nSize = 0;
+ if ( ESCHER_SPLIT_MENU_COLORS_COUNT != 0 )
+ nSize = ( ESCHER_SPLIT_MENU_COLORS_COUNT << 2 ) + 8;
+ return nSize;
+}
+
+void PptEscherEx::ImplWriteSplitMenuColorsAtom( SvStream& rSt )
+{
+ sal_uInt32 nSize = ImplSplitMenuColorsAtomSize();
+ if ( nSize )
+ {
+ rSt.WriteUInt32( ( ESCHER_SplitMenuColors << 16 ) | ( ESCHER_SPLIT_MENU_COLORS_COUNT << 4 ) )
+ .WriteUInt32( nSize - 8 )
+ .WriteUInt32( 0x08000004 )
+ .WriteUInt32( 0x08000001 )
+ .WriteUInt32( 0x08000002 )
+ .WriteUInt32( 0x100000f7 );
+ }
+
+}
+
+PptEscherEx::~PptEscherEx()
+{
+}
+
+void PptEscherEx::OpenContainer( sal_uInt16 n_EscherContainer, int nRecInstance )
+{
+ mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | 0xf ).WriteUInt16( n_EscherContainer ).WriteUInt32( 0 );
+ mOffsets.push_back( mpOutStrm->Tell() - 4 );
+ mRecTypes.push_back( n_EscherContainer );
+
+ switch( n_EscherContainer )
+ {
+ case ESCHER_DgContainer :
+ {
+ if ( !mbEscherDg )
+ {
+ mbEscherDg = true;
+ mnCurrentDg = mxGlobal->GenerateDrawingId();
+ AddAtom( 8, ESCHER_Dg, 0, mnCurrentDg );
+ PtReplaceOrInsert( ESCHER_Persist_Dg | mnCurrentDg, mpOutStrm->Tell() );
+ mpOutStrm->WriteUInt32( 0 ) // The number of shapes in this drawing
+ .WriteUInt32( 0 ); // The last MSOSPID given to an SP in this DG
+ }
+ }
+ break;
+
+ case ESCHER_SpgrContainer :
+ {
+ if ( mbEscherDg )
+ {
+ mbEscherSpgr = true;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void PptEscherEx::CloseContainer()
+{
+ /* SJ: #Issue 26747#
+ not creating group objects with a depth higher than 16, because then
+ PPT is having a big performance problem when starting a slide show
+ */
+ if ( ( mRecTypes.back() == ESCHER_SpgrContainer ) && ( mnGroupLevel >= 12 ) )
+ return;
+
+ sal_uInt32 nSize, nPos = mpOutStrm->Tell();
+ nSize = ( nPos - mOffsets.back() ) - 4;
+ mpOutStrm->Seek( mOffsets.back() );
+ mpOutStrm->WriteUInt32( nSize );
+
+ switch( mRecTypes.back() )
+ {
+ case ESCHER_DgContainer :
+ {
+ if ( mbEscherDg )
+ {
+ mbEscherDg = false;
+ if ( DoSeek( ESCHER_Persist_Dg | mnCurrentDg ) )
+ mpOutStrm->WriteUInt32( mxGlobal->GetDrawingShapeCount( mnCurrentDg ) ).WriteUInt32( mxGlobal->GetLastShapeId( mnCurrentDg ) );
+ }
+ }
+ break;
+
+ case ESCHER_SpgrContainer :
+ {
+ if ( mbEscherSpgr )
+ {
+ mbEscherSpgr = false;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ mOffsets.pop_back();
+ mRecTypes.pop_back();
+ mpOutStrm->Seek( nPos );
+}
+
+sal_uInt32 PptEscherEx::EnterGroup( ::tools::Rectangle const * pBoundRect, SvMemoryStream* pClientData )
+{
+ sal_uInt32 nShapeId = 0;
+ /* SJ: #Issue 26747#
+ not creating group objects with a depth higher than 16, because then
+ PPT is having a big performance problem when starting a slide show
+ */
+ if ( mnGroupLevel < 12 )
+ {
+ ::tools::Rectangle aRect;
+ if ( pBoundRect )
+ aRect = *pBoundRect;
+
+ OpenContainer( ESCHER_SpgrContainer );
+ OpenContainer( ESCHER_SpContainer );
+ AddAtom( 16, ESCHER_Spgr, 1 );
+ PtReplaceOrInsert( ESCHER_Persist_Grouping_Snap | mnGroupLevel, mpOutStrm->Tell() );
+ mpOutStrm ->WriteInt32( aRect.Left() ) // bounding box for the grouped shapes to which they are attached
+ .WriteInt32( aRect.Top() )
+ .WriteInt32( aRect.Right() )
+ .WriteInt32( aRect.Bottom() );
+
+ nShapeId = GenerateShapeId();
+ if ( !mnGroupLevel )
+ AddShape( ESCHER_ShpInst_Min, ShapeFlag::Group | ShapeFlag::Patriarch, nShapeId );
+ else
+ {
+ AddShape( ESCHER_ShpInst_Min, ShapeFlag::HaveAnchor | ShapeFlag::Group, nShapeId );
+ if ( mnGroupLevel == 1 )
+ {
+ AddAtom( 8, ESCHER_ClientAnchor );
+ PtReplaceOrInsert( ESCHER_Persist_Grouping_Logic | mnGroupLevel, mpOutStrm->Tell() );
+ mpOutStrm->WriteInt16( aRect.Top() ).WriteInt16( aRect.Left() ).WriteInt16( aRect.Right() ).WriteInt16( aRect.Bottom() );
+ }
+ else
+ {
+ AddAtom( 16, ESCHER_ChildAnchor );
+ PtReplaceOrInsert( ESCHER_Persist_Grouping_Snap | mnGroupLevel, mpOutStrm->Tell() );
+ mpOutStrm ->WriteInt32( aRect.Left() )
+ .WriteInt32( aRect.Top() )
+ .WriteInt32( aRect.Right() )
+ .WriteInt32( aRect.Bottom() );
+ }
+ }
+ if ( pClientData )
+ {
+ sal_uInt32 nSize = pClientData->TellEnd();
+ if ( nSize )
+ {
+ mpOutStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
+ .WriteUInt32( nSize );
+ mpOutStrm->WriteBytes(pClientData->GetData(), nSize);
+ }
+ }
+ CloseContainer(); // ESCHER_SpContainer
+ }
+ mnGroupLevel++;
+ return nShapeId;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/escherex.hxx b/sd/source/filter/eppt/escherex.hxx
new file mode 100644
index 000000000..8f64419f4
--- /dev/null
+++ b/sd/source/filter/eppt/escherex.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+#include <filter/msfilter/escherex.hxx>
+
+/// Values for the sal_uLong in PPT_PST_TextHeaderAtom.
+enum PPT_TextHeader
+{
+ PPTTH_TITLE,
+ PPTTH_BODY,
+ PPTTH_NOTES,
+ PPTTH_NOTUSED,
+ PPTTH_OTHER, ///< Text in a Shape
+ PPTTH_CENTERBODY, ///< Subtitle in Title-Slide
+ PPTTH_CENTERTITLE, ///< Title in Title-Slide
+ PPTTH_HALFBODY, ///< Body in two-column slide
+ PPTTH_QUARTERBODY ///< Body in four-body slide
+};
+
+class PptEscherEx : public EscherEx
+{
+ sal_uInt32 ImplDggContainerSize();
+ void ImplWriteDggContainer( SvStream& rSt );
+
+ static sal_uInt32 ImplOptAtomSize();
+ static void ImplWriteOptAtom( SvStream& rSt );
+
+ static sal_uInt32 ImplSplitMenuColorsAtomSize();
+ static void ImplWriteSplitMenuColorsAtom( SvStream& rSt );
+
+ public:
+
+ PptEscherEx( SvStream& rOut, const OUString& );
+ virtual ~PptEscherEx() override;
+
+ void OpenContainer( sal_uInt16 n_EscherContainer, int nRecInstance = 0 ) override;
+ void CloseContainer() override;
+
+ sal_uInt32 EnterGroup( ::tools::Rectangle const * pBoundRect, SvMemoryStream* pClientData );
+
+ sal_uInt32 DrawingGroupContainerSize();
+ void WriteDrawingGroupContainer( SvStream& rSt );
+
+ using EscherEx::EnterGroup;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/grouptable.hxx b/sd/source/filter/eppt/grouptable.hxx
new file mode 100644
index 000000000..885f95741
--- /dev/null
+++ b/sd/source/filter/eppt/grouptable.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <memory>
+#include <vector>
+
+struct GroupEntry
+{
+ sal_uInt32 mnCurrentPos;
+ sal_uInt32 mnCount;
+ css::uno::Reference< css::container::XIndexAccess > mXIndexAccess;
+
+ explicit GroupEntry( css::uno::Reference< css::container::XIndexAccess > const & rIndex )
+ : mnCurrentPos(0),
+ mnCount(rIndex->getCount()),
+ mXIndexAccess(rIndex)
+ {
+ };
+
+ explicit GroupEntry( sal_uInt32 nCount )
+ : mnCurrentPos(0),
+ mnCount(nCount)
+ {
+ };
+};
+
+class GroupTable
+{
+ protected:
+
+ sal_uInt32 mnIndex;
+ sal_uInt32 mnGroupsClosed;
+ std::vector<GroupEntry> mvGroupEntry;
+
+ public:
+
+ sal_uInt32 GetCurrentGroupIndex() const { return mnIndex; };
+ sal_Int32 GetCurrentGroupLevel() const { return mvGroupEntry.size() - 1; };
+ const css::uno::Reference< css::container::XIndexAccess > &
+ GetCurrentGroupAccess() const { return mvGroupEntry.back().mXIndexAccess; };
+ sal_uInt32 GetGroupsClosed();
+ void ResetGroupTable( sal_uInt32 nCount );
+ void ClearGroupTable();
+ bool EnterGroup( css::uno::Reference< css::container::XIndexAccess > const & rIndex );
+ bool GetNextGroupEntry();
+ GroupTable();
+ ~GroupTable();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptexanimations.cxx b/sd/source/filter/eppt/pptexanimations.cxx
new file mode 100644
index 000000000..99fe0b443
--- /dev/null
+++ b/sd/source/filter/eppt/pptexanimations.cxx
@@ -0,0 +1,2150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/animations/AnimationRestart.hpp>
+#include <com/sun/star/animations/Timing.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/AnimationEndSync.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/EffectPresetClass.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+#include <com/sun/star/animations/AnimationCalcMode.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
+#include <com/sun/star/animations/XAnimateSet.hpp>
+#include <com/sun/star/animations/XAudio.hpp>
+#include <com/sun/star/animations/XTransitionFilter.hpp>
+#include <com/sun/star/animations/XAnimateColor.hpp>
+#include <com/sun/star/animations/XAnimateMotion.hpp>
+#include <com/sun/star/animations/XAnimateTransform.hpp>
+#include <com/sun/star/animations/ValuePair.hpp>
+#include <com/sun/star/animations/AnimationColorSpace.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/animations/XIterateContainer.hpp>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+
+#include <oox/ppt/pptfilterhelpers.hxx>
+#include "pptexanimations.hxx"
+#include "pptexsoundcollection.hxx"
+#include "../ppt/pptanimations.hxx"
+#include <filter/msfilter/escherex.hxx>
+#include <osl/diagnose.h>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/string_view.hxx>
+
+#include <algorithm>
+
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::util::XCloneable;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::beans::NamedValue;
+using ::com::sun::star::container::XEnumerationAccess;
+using ::com::sun::star::container::XEnumeration;
+
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::presentation;
+
+namespace ppt
+{
+
+static void ImplTranslateAttribute( OUString& rString, const TranslateMode eTranslateMode )
+{
+ if ( eTranslateMode == TRANSLATE_NONE )
+ return;
+
+ if ( ( eTranslateMode & TRANSLATE_VALUE ) || ( eTranslateMode & TRANSLATE_ATTRIBUTE ) )
+ {
+ const oox::ppt::ImplAttributeNameConversion* p = oox::ppt::getAttributeConversionList();
+ while( p->mpAPIName )
+ {
+ if( rString.equalsAscii( p->mpAPIName ) )
+ break;
+ p++;
+ }
+ if( p->mpMSName )
+ {
+ if ( eTranslateMode & TRANSLATE_VALUE )
+ {
+ rString = "#";
+ rString += OUString::createFromAscii( p->mpMSName );
+ }
+ else
+ rString = OUString::createFromAscii( p->mpMSName );
+ }
+ }
+ else if ( eTranslateMode & TRANSLATE_MEASURE )
+ {
+ const char* pDest[] = { "#ppt_x", "#ppt_y", "#ppt_w", "#ppt_h", nullptr };
+ const char* pSource[] = { "x", "y", "width", "height", nullptr };
+ sal_Int32 nIndex = 0;
+
+ const char** ps = pSource;
+ const char** pd = pDest;
+
+ while( *ps )
+ {
+ const OUString aSearch( OUString::createFromAscii( *ps ) );
+ while( (nIndex = rString.indexOf( aSearch, nIndex )) != -1 )
+ {
+ sal_Int32 nLength = aSearch.getLength();
+ if( nIndex && ( rString[nIndex-1] == '#' ) )
+ {
+ nIndex--;
+ nLength++;
+ }
+
+ const OUString aNew( OUString::createFromAscii( *pd ) );
+ rString = rString.replaceAt( nIndex, nLength, aNew );
+ nIndex += aNew.getLength();
+ }
+ ps++;
+ pd++;
+ }
+ }
+}
+
+sal_uInt32 AnimationExporter::TranslatePresetSubType( const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, std::u16string_view rPresetSubType )
+{
+ sal_uInt32 nPresetSubType = 0;
+ bool bTranslated = false;
+
+ if ( ( nPresetClass == sal_uInt32(EffectPresetClass::ENTRANCE) ) || ( nPresetClass == sal_uInt32(EffectPresetClass::EXIT) ) )
+ {
+ if ( nPresetId != 21 )
+ {
+ switch( nPresetId )
+ {
+ case 5 :
+ {
+ if ( rPresetSubType == u"downward" )
+ {
+ nPresetSubType = 5;
+ bTranslated = true;
+ }
+ else if ( rPresetSubType == u"across" )
+ {
+ nPresetSubType = 10;
+ bTranslated = true;
+ }
+ }
+ break;
+ case 17 :
+ {
+ if ( rPresetSubType == u"across" )
+ {
+ nPresetSubType = 10;
+ bTranslated = true;
+ }
+ }
+ break;
+ case 18 :
+ {
+ if ( rPresetSubType == u"right-to-top" )
+ {
+ nPresetSubType = 3;
+ bTranslated = true;
+ }
+ else if ( rPresetSubType == u"right-to-bottom" )
+ {
+ nPresetSubType = 6;
+ bTranslated = true;
+ }
+ else if ( rPresetSubType == u"left-to-top" )
+ {
+ nPresetSubType = 9;
+ bTranslated = true;
+ }
+ else if ( rPresetSubType == u"left-to-bottom" )
+ {
+ nPresetSubType = 12;
+ bTranslated = true;
+ }
+ }
+ break;
+ }
+ }
+ if ( !bTranslated )
+ {
+ const oox::ppt::convert_subtype* p = oox::ppt::convert_subtype::getList();
+ while( p->mpStrSubType )
+ {
+ if ( o3tl::equalsAscii( rPresetSubType, p->mpStrSubType ) )
+ {
+ nPresetSubType = p->mnID;
+ bTranslated = true;
+ break;
+ }
+ p++;
+ }
+ }
+ }
+ if ( !bTranslated )
+ nPresetSubType = o3tl::toUInt32(rPresetSubType);
+ return nPresetSubType;
+}
+
+const char* AnimationExporter::FindTransitionName( const sal_Int16 nType, const sal_Int16 nSubType, const bool bDirection )
+{
+ const char* pRet = nullptr;
+ int nFit = 0;
+
+ const oox::ppt::transition* p = oox::ppt::transition::getList();
+ while( p->mpName )
+ {
+ int nF = 0;
+ if ( nType == p->mnType )
+ nF += 4;
+ if ( nSubType == p->mnSubType )
+ nF += 2;
+ if ( bDirection == p->mbDirection )
+ nF += 1;
+ if ( nF > nFit )
+ {
+ pRet = p->mpName;
+ nFit = nF;
+ }
+ if ( nFit == 7 ) // maximum
+ break;
+ p++;
+ }
+ return pRet;
+}
+
+SvStream& WriteAnimationNode(SvStream& rOut, AnimationNode const & rNode )
+{
+ rOut.WriteInt32( rNode.mnU1 );
+ rOut.WriteInt32( rNode.mnRestart );
+ rOut.WriteInt32( rNode.mnGroupType );
+ rOut.WriteInt32( rNode.mnFill );
+ rOut.WriteInt32( rNode.mnU3 );
+ rOut.WriteInt32( rNode.mnU4 );
+ rOut.WriteInt32( rNode.mnDuration );
+ rOut.WriteInt32( rNode.mnNodeType );
+
+ return rOut;
+}
+
+AnimationExporter::AnimationExporter( const EscherSolverContainer& rSolverContainer, ppt::ExSoundCollection& rExSoundCollection ) :
+ mrSolverContainer ( rSolverContainer ),
+ mrExSoundCollection ( rExSoundCollection ),
+ mnCurrentGroup(0)
+{
+}
+
+sal_Int16 AnimationExporter::GetFillMode( const Reference< XAnimationNode >& xNode, const sal_Int16 nFillDefault )
+{
+ sal_Int16 nFill = xNode->getFill();
+ //#i119699 <Animation> The animation effect "Emphasis->FlashBulb" play incorrectly in Aoo saves a .ppt to another .ppt and plays the saved one.
+ //#i119740 <Animation> The animation effect "Entrance->Flash Once" fails to play in Aoo while Aoo saves a .ppt to another .ppt and plays the saved one.
+ if ((xNode->getType() == AnimationNodeType::ANIMATE)
+ ||(xNode->getType() == AnimationNodeType::SET)
+ ||(xNode->getType() == AnimationNodeType::TRANSITIONFILTER))
+ {
+ if ( nFill == AnimationFill::DEFAULT )
+ return nFill;
+ }
+
+ if ( nFill == AnimationFill::DEFAULT )
+ {
+ nFill = nFillDefault;
+ }
+ if( nFill == AnimationFill::AUTO )
+ {
+ nFill = AnimationFill::REMOVE;
+ bool bIsIndefiniteTiming = true;
+ Any aAny = xNode->getDuration();
+ if( aAny.hasValue() )
+ {
+ Timing eTiming;
+ if( aAny >>= eTiming )
+ bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
+ }
+ if ( bIsIndefiniteTiming )
+ {
+ aAny = xNode->getEnd();
+ if( aAny.hasValue() )
+ {
+ Timing eTiming;
+ if( aAny >>= eTiming )
+ bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
+ }
+ if ( bIsIndefiniteTiming )
+ {
+ if ( !xNode->getRepeatCount().hasValue() )
+ {
+ aAny = xNode->getRepeatDuration();
+ if( aAny.hasValue() )
+ {
+ Timing eTiming;
+ if( aAny >>= eTiming )
+ bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
+ }
+ if ( bIsIndefiniteTiming )
+ nFill = AnimationFill::FREEZE;
+ }
+ }
+ }
+ }
+ return nFill;
+}
+
+void AnimationExporter::doexport( const Reference< XDrawPage >& xPage, SvStream& rStrm )
+{
+ Reference< XAnimationNodeSupplier > xNodeSupplier( xPage, UNO_QUERY );
+ if( xNodeSupplier.is() )
+ {
+ const Reference< XAnimationNode > xRootNode( xNodeSupplier->getAnimationNode() );
+ if( xRootNode.is() )
+ {
+ processAfterEffectNodes( xRootNode );
+ exportNode( rStrm, xRootNode, DFF_msofbtAnimGroup, 1, 0, false, AnimationFill::AUTO );
+ }
+ }
+}
+
+void AnimationExporter::processAfterEffectNodes( const Reference< XAnimationNode >& xRootNode )
+{
+ try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+
+ Reference< XEnumerationAccess > xEnumerationAccess2( xNode, UNO_QUERY );
+ if ( xEnumerationAccess2.is() )
+ {
+ Reference< XEnumeration > xEnumeration2( xEnumerationAccess2->createEnumeration(), css::uno::UNO_SET_THROW );
+ while( xEnumeration2->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration2->nextElement(), UNO_QUERY_THROW );
+
+ Reference< XEnumerationAccess > xEnumerationAccess3( xChildNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration3( xEnumerationAccess3->createEnumeration(), css::uno::UNO_SET_THROW );
+ while( xEnumeration3->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode2( xEnumeration3->nextElement(), UNO_QUERY_THROW );
+
+ Reference< XEnumerationAccess > xEnumerationAccess4( xChildNode2, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration4( xEnumerationAccess4->createEnumeration(), css::uno::UNO_SET_THROW );
+ while( xEnumeration4->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode3( xEnumeration4->nextElement(), UNO_QUERY_THROW );
+
+ switch( xChildNode3->getType() )
+ {
+ // found an after effect
+ case AnimationNodeType::SET:
+ case AnimationNodeType::ANIMATECOLOR:
+ {
+ Reference< XAnimationNode > xMaster;
+
+ const Sequence< NamedValue > aUserData( xChildNode3->getUserData() );
+ const NamedValue* p = std::find_if(aUserData.begin(), aUserData.end(),
+ [](const NamedValue& rProp) { return rProp.Name == "master-element"; });
+
+ if (p != aUserData.end())
+ p->Value >>= xMaster;
+
+ AfterEffectNodePtr pAfterEffectNode = std::make_shared<AfterEffectNode>( xChildNode3, xMaster );
+ maAfterEffectNodes.push_back( pAfterEffectNode );
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "(@CL)AnimationExporter::processAfterEffectNodes()" );
+ }
+}
+
+bool AnimationExporter::isAfterEffectNode( const Reference< XAnimationNode >& xNode ) const
+{
+ return std::any_of(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
+ [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxNode == xNode; });
+}
+
+bool AnimationExporter::hasAfterEffectNode( const Reference< XAnimationNode >& xNode, Reference< XAnimationNode >& xAfterEffectNode ) const
+{
+ auto aIter = std::find_if(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
+ [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxMaster == xNode; });
+ if (aIter != maAfterEffectNodes.end())
+ {
+ xAfterEffectNode = (*aIter)->mxNode;
+ return true;
+ }
+
+ return false;
+}
+
+// check if this group only contain empty groups. this may happen when
+// after effect nodes are not exported at their original position
+bool AnimationExporter::isEmptyNode( const Reference< XAnimationNode >& xNode ) const
+{
+ if( xNode.is() ) switch( xNode->getType() )
+ {
+ case AnimationNodeType::PAR :
+ case AnimationNodeType::SEQ :
+ case AnimationNodeType::ITERATE :
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( xChildNode.is() && !isEmptyNode( xChildNode ) )
+ return false;
+ }
+ }
+ }
+ }
+ break;
+
+ case AnimationNodeType::SET :
+ case AnimationNodeType::ANIMATECOLOR :
+ return isAfterEffectNode( xNode );
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+void AnimationExporter::exportNode( SvStream& rStrm, Reference< XAnimationNode > const & xNode_in, const sal_uInt16 nContainerRecType,
+ const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const bool bTakeBackInteractiveSequenceTiming, const sal_Int16 nFDef )
+{
+ auto xNode = xNode_in;
+
+ if( (nGroupLevel == 4) && isEmptyNode( xNode ) )
+ return;
+
+ if ( ( nContainerRecType == DFF_msofbtAnimGroup ) && ( nGroupLevel == 2 ) && isEmptyNode( xNode ) )
+ return;
+
+ if( nContainerRecType == DFF_msofbtAnimGroup )
+ mnCurrentGroup++;
+
+ bool bTakeBackInteractiveSequenceTimingForChild = false;
+ sal_Int16 nFillDefault = GetFillMode( xNode, nFDef );
+
+ Reference< XAnimationNode > xAudioNode;
+ static sal_uInt32 nAudioGroup;
+
+ {
+ bool bSkipChildren = false;
+ EscherExContainer aContainer( rStrm, nContainerRecType, nInstance );
+ switch( xNode->getType() )
+ {
+ case AnimationNodeType::CUSTOM :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+
+ case AnimationNodeType::PAR :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ sal_Int32 nFlags = nGroupLevel == 2 ? 0x10 : 0;
+ if ( bTakeBackInteractiveSequenceTiming )
+ nFlags |= 0x40;
+ exportAnimEvent( rStrm, xNode, nFlags );
+ exportAnimValue( rStrm, xNode, nGroupLevel == 4 );
+ }
+ break;
+
+ case AnimationNodeType::SEQ :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ sal_Int16 nNodeType = exportAnimPropertySet( rStrm, xNode );
+ sal_Int32 nFlags = 12;
+ if ( ( nGroupLevel == 1 ) && ( nNodeType == css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ) )
+ {
+ nFlags |= 0x20;
+ bTakeBackInteractiveSequenceTimingForChild = true;
+ }
+ exportAnimAction( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode, nFlags );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+
+ case AnimationNodeType::ITERATE :
+ {
+ {
+ EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
+ AnimationNode aAnim;
+ aAnim.mnGroupType = mso_Anim_GroupType_PAR;
+ aAnim.mnNodeType = 1;
+ // attribute Restart
+ switch( xNode->getRestart() )
+ {
+ default:
+ case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
+ case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
+ case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
+ case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
+ }
+ // attribute Fill
+ switch( xNode->getFill() )
+ {
+ default:
+ case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
+ case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
+ case AnimationFill::FREEZE : aAnim.mnFill = 2; break;
+ case AnimationFill::HOLD : aAnim.mnFill = 3; break;
+ case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
+ }
+ WriteAnimationNode( rStrm, aAnim );
+ }
+ exportIterate( rStrm, xNode );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+
+ case AnimationNodeType::ANIMATE :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ exportAnimate( rStrm, xNode );
+ }
+ break;
+
+ case AnimationNodeType::SET :
+ {
+ bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
+ if( (nGroupLevel != 4) || !bIsAfterEffectNode )
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimateSet( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_SET : AFTEREFFECT_NONE );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ else
+ {
+ bSkipChildren = true;
+ }
+ }
+ break;
+
+ case AnimationNodeType::ANIMATEMOTION :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimateMotion( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+
+ case AnimationNodeType::ANIMATECOLOR :
+ {
+ bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
+ if( (nGroupLevel != 4) || !bIsAfterEffectNode )
+ {
+ if( bIsAfterEffectNode )
+ xNode = createAfterEffectNodeClone( xNode );
+
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimateColor( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_COLOR : AFTEREFFECT_NONE );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ else
+ {
+ bSkipChildren = true;
+ }
+ }
+ break;
+
+ case AnimationNodeType::ANIMATETRANSFORM :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimateTransform( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+
+ case AnimationNodeType::TRANSITIONFILTER :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ exportTransitionFilter( rStrm, xNode );
+ }
+ break;
+
+ case AnimationNodeType::AUDIO : // #i58428#
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+
+ Reference< XAudio > xAudio( xNode, UNO_QUERY );
+ if( xAudio.is() )
+ {
+ Any aAny( xAudio->getSource() );
+ OUString aURL;
+
+ if ( ( aAny >>= aURL) && !aURL.isEmpty() )
+ {
+ sal_Int32 nU1 = 2;
+ sal_Int32 nTrigger = 3;
+ sal_Int32 nU3 = nAudioGroup;
+ sal_Int32 nBegin = 0;
+ {
+ EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 1 );
+ {
+ EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
+ rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
+ }
+ }
+ nU1 = 1;
+ nTrigger = 0xb;
+ nU3 = 0;
+ {
+ EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 2 );
+ {
+ EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
+ rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
+ }
+ }
+ EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
+ {
+ sal_uInt32 const nRefMode = 3;
+ sal_uInt32 const nRefType = 2;
+ sal_uInt32 nRefId = mrExSoundCollection.GetId( aURL );
+ sal_Int32 const begin = -1;
+ sal_Int32 const end = -1;
+
+ EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
+ rStrm.WriteUInt32( nRefMode ).WriteUInt32( nRefType ).WriteUInt32( nRefId ).WriteInt32( begin ).WriteInt32( end );
+ }
+ }
+ }
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+ }
+ if( !bSkipChildren )
+ {
+ // export after effect node if one exists for this node
+ Reference< XAnimationNode > xAfterEffectNode;
+ if( hasAfterEffectNode( xNode, xAfterEffectNode ) )
+ {
+ exportNode( rStrm, xAfterEffectNode, DFF_msofbtAnimSubGoup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
+ }
+
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( xChildNode.is() )
+ {
+ if ( xChildNode->getType() == AnimationNodeType::AUDIO )
+ {
+ xAudioNode = xChildNode;
+ nAudioGroup = mnCurrentGroup;
+ }
+ else
+ exportNode( rStrm, xChildNode, DFF_msofbtAnimGroup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
+ }
+ }
+ }
+ }
+ }
+ }
+ if ( xAudioNode.is() )
+ exportNode( rStrm, xAudioNode, DFF_msofbtAnimGroup, 1, nGroupLevel, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
+
+ if( xNode->getType() == AnimationNodeType::ITERATE )
+ aTarget = Any();
+}
+
+Reference< XAnimationNode > AnimationExporter::createAfterEffectNodeClone( const Reference< XAnimationNode >& xNode )
+{
+ try
+ {
+ Reference< css::util::XCloneable > xClonable( xNode, UNO_QUERY_THROW );
+ Reference< XAnimationNode > xCloneNode( xClonable->createClone(), UNO_QUERY_THROW );
+
+ Any aEmpty;
+ xCloneNode->setBegin( aEmpty );
+
+ return xCloneNode;
+ }
+ catch( Exception& )
+ {
+ OSL_FAIL("(@CL)sd::ppt::AnimationExporter::createAfterEffectNodeClone(), could not create clone!" );
+ }
+ return xNode;
+}
+
+bool AnimationExporter::GetNodeType( const Reference< XAnimationNode >& xNode, sal_Int16& nType )
+{
+ // trying to get the nodetype
+ const Sequence< NamedValue > aUserData = xNode->getUserData();
+ for( const NamedValue& rProp : aUserData )
+ {
+ if ( rProp.Name == "node-type" )
+ {
+ if ( rProp.Value >>= nType )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void AnimationExporter::exportAnimNode( SvStream& rStrm, const Reference< XAnimationNode >& xNode,
+ const sal_Int16 nFillDefault )
+{
+ EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
+ AnimationNode aAnim;
+
+ // attribute Restart
+ switch( xNode->getRestart() )
+ {
+ default:
+ case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
+ case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
+ case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
+ case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
+ }
+
+ switch( nFillDefault )
+ {
+ default:
+ case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
+ case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
+ case AnimationFill::FREEZE :
+ case AnimationFill::HOLD : aAnim.mnFill = 3; break;
+ case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
+ }
+ // attribute Duration
+ double fDuration = 0.0;
+ css::animations::Timing eTiming;
+ if ( xNode->getDuration() >>= eTiming )
+ {
+ if ( eTiming == Timing_INDEFINITE )
+ aAnim.mnDuration = -1;
+ }
+ else if ( xNode->getDuration() >>= fDuration )
+ {
+ aAnim.mnDuration = static_cast<sal_Int32>( fDuration * 1000.0 );
+ }
+ else
+ aAnim.mnDuration = -1;
+
+ // NodeType, NodeGroup
+ aAnim.mnNodeType = 1;
+ aAnim.mnGroupType = mso_Anim_GroupType_SEQ;
+ switch( xNode->getType() )
+ {
+ case AnimationNodeType::PAR :
+ aAnim.mnGroupType = mso_Anim_GroupType_PAR;
+ [[fallthrough]];
+ case AnimationNodeType::SEQ :
+ {
+ sal_Int16 nType = 0;
+ if( GetNodeType( xNode, nType ) )
+ switch( nType )
+ {
+ case css::presentation::EffectNodeType::TIMING_ROOT : aAnim.mnNodeType = 0x12; break;
+ case css::presentation::EffectNodeType::MAIN_SEQUENCE : aAnim.mnNodeType = 0x18; break;
+ }
+ }
+ break;
+
+ case AnimationNodeType::ANIMATE :
+ case AnimationNodeType::SET :
+
+ case AnimationNodeType::CUSTOM :
+ case AnimationNodeType::ITERATE :
+ case AnimationNodeType::ANIMATEMOTION :
+ case AnimationNodeType::ANIMATECOLOR :
+ case AnimationNodeType::ANIMATETRANSFORM :
+ {
+ aAnim.mnGroupType = mso_Anim_GroupType_NODE;
+ aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION;
+ }
+ break;
+
+ case AnimationNodeType::AUDIO :
+ {
+ aAnim.mnGroupType = mso_Anim_GroupType_MEDIA;
+ aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION;
+ }
+ break;
+
+ case AnimationNodeType::TRANSITIONFILTER :
+ {
+ aAnim.mnGroupType = mso_Anim_GroupType_NODE;
+ aAnim.mnNodeType = mso_Anim_Behaviour_FILTER;
+ }
+ break;
+ }
+
+ WriteAnimationNode( rStrm, aAnim );
+}
+
+void AnimationExporter::GetUserData( const Sequence< NamedValue >& rUserData, const Any ** pAny, std::size_t nLen )
+{
+ // storing user data into pAny, to allow direct access later
+ memset( pAny, 0, nLen );
+ if ( !rUserData.hasElements() )
+ return;
+
+ for( const NamedValue& rProp : rUserData )
+ {
+ if ( rProp.Name == "node-type" )
+ {
+ pAny[ DFF_ANIM_NODE_TYPE ] = &(rProp.Value);
+ }
+ else if ( rProp.Name == "preset-class" )
+ {
+ pAny[ DFF_ANIM_PRESET_CLASS ] = &(rProp.Value);
+ }
+ else if ( rProp.Name == "preset-id" )
+ {
+ pAny[ DFF_ANIM_PRESET_ID ] = &(rProp.Value);
+ }
+ else if ( rProp.Name == "preset-sub-type" )
+ {
+ pAny[ DFF_ANIM_PRESET_SUB_TYPE ] = &(rProp.Value);
+ }
+ else if ( rProp.Name == "master-element" )
+ {
+ pAny[ DFF_ANIM_AFTEREFFECT ] = &(rProp.Value);
+ }
+ }
+}
+
+sal_uInt32 AnimationExporter::GetPresetID( const OUString& rPreset, sal_uInt32 nAPIPresetClass, bool& bPresetId )
+{
+ sal_uInt32 nPresetId = 0;
+ bPresetId = false;
+
+ if ( rPreset.match("ppt_", 0) )
+ {
+ sal_Int32 nLast = rPreset.lastIndexOf( '_' );
+ if ( ( nLast != -1 ) && ( ( nLast + 1 ) < rPreset.getLength() ) )
+ {
+ std::u16string_view aNumber( rPreset.subView( nLast + 1 ) );
+ nPresetId = o3tl::toUInt32(aNumber);
+ bPresetId = true;
+ }
+ }
+ else
+ {
+ const oox::ppt::preset_mapping* p = oox::ppt::preset_mapping::getList();
+ while( p->mpStrPresetId && ((p->mnPresetClass != static_cast<sal_Int32>(nAPIPresetClass)) || !rPreset.equalsAscii( p->mpStrPresetId )) )
+ p++;
+
+ if( p->mpStrPresetId )
+ {
+ nPresetId = p->mnPresetId;
+ bPresetId = true;
+ }
+ }
+
+ return nPresetId;
+}
+
+sal_Int16 AnimationExporter::exportAnimPropertySet( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ sal_Int16 nNodeType = css::presentation::EffectNodeType::DEFAULT;
+
+ EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
+
+ Reference< XAnimationNode > xMaster;
+
+ Any aMasterRel, aOverride, aRunTimeContext;
+
+ // storing user data into pAny, to allow direct access later
+ const Sequence< NamedValue > aUserData = xNode->getUserData();
+ const css::uno::Any* pAny[ DFF_ANIM_PROPERTY_ID_COUNT ];
+ GetUserData( aUserData, pAny, sizeof( pAny ) );
+
+ if( pAny[ DFF_ANIM_AFTEREFFECT ] )
+ ( *pAny[ DFF_ANIM_AFTEREFFECT ] ) >>= xMaster;
+
+ // calculate master-rel
+ if( xMaster.is() )
+ {
+ sal_Int32 nMasterRel = 2;
+ if( xNode.is() && xMaster.is() && (xNode->getParent() == xMaster->getParent() ) )
+ nMasterRel = 0;
+
+ aMasterRel <<= nMasterRel;
+
+ pAny[ DFF_ANIM_MASTERREL ] = &aMasterRel;
+
+ aOverride <<= sal_Int32(1);
+ pAny[ DFF_ANIM_OVERRIDE ] = &aOverride;
+
+ aRunTimeContext <<= sal_Int32(1);
+ pAny[ DFF_ANIM_RUNTIMECONTEXT ] = &aRunTimeContext;
+ }
+
+ // the order is important
+ if ( pAny[ DFF_ANIM_NODE_TYPE ] )
+ {
+ if ( *pAny[ DFF_ANIM_NODE_TYPE ] >>= nNodeType )
+ {
+ sal_uInt32 nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK;
+ switch( nNodeType )
+ {
+ case css::presentation::EffectNodeType::ON_CLICK : nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK; break;
+ case css::presentation::EffectNodeType::WITH_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_WITH_PREVIOUS; break;
+ case css::presentation::EffectNodeType::AFTER_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS; break;
+ case css::presentation::EffectNodeType::MAIN_SEQUENCE : nPPTNodeType = DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE; break;
+ case css::presentation::EffectNodeType::TIMING_ROOT : nPPTNodeType = DFF_ANIM_NODE_TYPE_TIMING_ROOT; break;
+ case css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE: nPPTNodeType = DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ; break;
+ }
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_NODE_TYPE, nPPTNodeType );
+ }
+ }
+ sal_uInt32 nPresetId = 0;
+ sal_uInt32 nPresetSubType = 0;
+ sal_uInt32 nAPIPresetClass = EffectPresetClass::CUSTOM;
+ sal_uInt32 nPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
+ bool bPresetClass, bPresetId, bPresetSubType;
+ bPresetId = bPresetClass = bPresetSubType = false;
+
+ if ( pAny[ DFF_ANIM_PRESET_CLASS ] )
+ {
+ if ( *pAny[ DFF_ANIM_PRESET_CLASS ] >>= nAPIPresetClass )
+ {
+ sal_uInt8 nPPTPresetClass;
+ switch( nAPIPresetClass )
+ {
+ case EffectPresetClass::ENTRANCE : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_ENTRANCE; break;
+ case EffectPresetClass::EXIT : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EXIT; break;
+ case EffectPresetClass::EMPHASIS : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EMPHASIS; break;
+ case EffectPresetClass::MOTIONPATH : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MOTIONPATH; break;
+ case EffectPresetClass::OLEACTION : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_OLE_ACTION; break;
+ case EffectPresetClass::MEDIACALL : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MEDIACALL; break;
+ default :
+ nPPTPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
+ }
+ nPresetClass = nPPTPresetClass;
+ bPresetClass = true;
+ }
+ }
+ if ( pAny[ DFF_ANIM_PRESET_ID ] )
+ {
+ OUString sPreset;
+ if ( *pAny[ DFF_ANIM_PRESET_ID ] >>= sPreset )
+ nPresetId = GetPresetID( sPreset, nAPIPresetClass, bPresetId );
+ }
+
+ if ( pAny[ DFF_ANIM_PRESET_SUB_TYPE ] )
+ {
+ OUString sPresetSubType;
+ if ( *pAny[ DFF_ANIM_PRESET_SUB_TYPE ] >>= sPresetSubType )
+ {
+ nPresetSubType = TranslatePresetSubType( nPresetClass, nPresetId, sPresetSubType );
+ bPresetSubType = true;
+ }
+ }
+ if ( bPresetId )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_ID, nPresetId );
+ if ( bPresetSubType )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_SUB_TYPE, nPresetSubType );
+ if ( bPresetClass )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_CLASS, nPresetClass );
+
+ if ( pAny[ DFF_ANIM_ID ] )
+ {
+ // TODO DFF_ANIM_ID
+ }
+
+ if ( pAny[ DFF_ANIM_AFTEREFFECT ] )
+ {
+ bool bAfterEffect = false;
+ if ( *pAny[ DFF_ANIM_AFTEREFFECT ] >>= bAfterEffect )
+ exportAnimPropertyByte( rStrm, DFF_ANIM_AFTEREFFECT, int(bAfterEffect) );
+ }
+
+ if ( pAny[ DFF_ANIM_RUNTIMECONTEXT ] )
+ {
+ sal_Int32 nRunTimeContext = 0;
+ if ( *pAny[ DFF_ANIM_RUNTIMECONTEXT ] >>= nRunTimeContext )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_RUNTIMECONTEXT, nRunTimeContext );
+ }
+ if ( pAny[ DFF_ANIM_PATH_EDIT_MODE ] )
+ {
+ // TODO DFF_ANIM_ID
+ }
+
+ if( !xMaster.is() )
+ {
+ Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
+ if( xColor.is() )
+ {
+
+ bool bDirection = !xColor->getDirection();
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_DIRECTION, bDirection ? 1 : 0 );
+ }
+ }
+
+ if ( pAny[ DFF_ANIM_OVERRIDE ] )
+ {
+ sal_Int32 nOverride = 0;
+ if ( *pAny[ DFF_ANIM_OVERRIDE ] >>= nOverride )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_OVERRIDE, nOverride );
+ }
+
+ if ( pAny[ DFF_ANIM_MASTERREL ] )
+ {
+ sal_Int32 nMasterRel = 0;
+ if ( *pAny[ DFF_ANIM_MASTERREL ] >>= nMasterRel )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_MASTERREL, nMasterRel );
+ }
+
+/* todo
+ Reference< XAudio > xAudio( xNode, UNO_QUERY );
+ if( xAudio.is() )
+ {
+ sal_Int16 nEndAfterSlide = 0;
+ nEndAfterSlide = xAudio->getEndAfterSlide();
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_ENDAFTERSLIDE, nEndAfterSlide, TRANSLATE_NONE );
+ }
+*/
+ Reference< XAnimate > xAnim( xNode, UNO_QUERY );
+ if( xAnim.is() )
+ {
+ // TODO: DFF_ANIM_TIMEFILTER
+ }
+ if ( pAny[ DFF_ANIM_EVENT_FILTER ] )
+ {
+ // TODO DFF_ANIM_EVENT_FILTER
+ }
+ if ( pAny[ DFF_ANIM_VOLUME ] )
+ {
+ // TODO DFF_ANIM_VOLUME
+ }
+ return nNodeType;
+}
+
+bool AnimationExporter::exportAnimProperty( SvStream& rStrm, const sal_uInt16 nPropertyId, const css::uno::Any& rAny, const TranslateMode eTranslateMode )
+{
+ bool bRet = false;
+ if ( rAny.hasValue() )
+ {
+ switch( rAny.getValueType().getTypeClass() )
+ {
+ case css::uno::TypeClass_UNSIGNED_SHORT :
+ case css::uno::TypeClass_SHORT :
+ case css::uno::TypeClass_UNSIGNED_LONG :
+ case css::uno::TypeClass_LONG :
+ {
+ sal_Int32 nVal = 0;
+ if ( rAny >>= nVal )
+ {
+ exportAnimPropertyuInt32( rStrm, nPropertyId, nVal );
+ bRet = true;
+ }
+ }
+ break;
+
+ case css::uno::TypeClass_DOUBLE :
+ {
+ double fVal = 0.0;
+ if ( rAny >>= fVal )
+ {
+ exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
+ bRet = true;
+ }
+ }
+ break;
+ case css::uno::TypeClass_FLOAT :
+ {
+ float fVal = 0.0;
+ if ( rAny >>= fVal )
+ {
+ if ( eTranslateMode & TRANSLATE_NUMBER_TO_STRING )
+ {
+ OUString aNumber( OUString::number( fVal ) );
+ exportAnimPropertyString( rStrm, nPropertyId, aNumber, eTranslateMode );
+ }
+ else
+ {
+ exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
+ bRet = true;
+ }
+ }
+ }
+ break;
+ case css::uno::TypeClass_STRING :
+ {
+ OUString aStr;
+ if ( rAny >>= aStr )
+ {
+ exportAnimPropertyString( rStrm, nPropertyId, aStr, eTranslateMode );
+ bRet = true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return bRet;
+}
+void AnimationExporter::exportAnimPropertyString( SvStream& rStrm, const sal_uInt16 nPropertyId, const OUString& rVal, const TranslateMode eTranslateMode )
+{
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
+ rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_UNISTRING );
+ OUString aStr( rVal );
+ if ( eTranslateMode != TRANSLATE_NONE )
+ ImplTranslateAttribute( aStr, eTranslateMode );
+ writeZString( rStrm, aStr );
+}
+
+void AnimationExporter::exportAnimPropertyFloat( SvStream& rStrm, const sal_uInt16 nPropertyId, const double& rVal )
+{
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
+ float fFloat = static_cast<float>(rVal);
+ rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_FLOAT )
+ .WriteFloat( fFloat );
+}
+
+void AnimationExporter::exportAnimPropertyuInt32( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal )
+{
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
+ rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_INT32 )
+ .WriteUInt32( nVal );
+}
+
+void AnimationExporter::exportAnimPropertyByte( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal )
+{
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
+ rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_BYTE )
+ .WriteUChar( nVal );
+}
+
+void AnimationExporter::writeZString( SvStream& rStrm, const OUString& rVal )
+{
+ sal_Int32 i;
+ for ( i = 0; i < rVal.getLength(); i++ )
+ rStrm.WriteUInt16( rVal[ i ] );
+ rStrm.WriteUInt16( 0 );
+}
+
+void AnimationExporter::exportAnimAction( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAction );
+
+ sal_Int32 const nConcurrent = 1;
+ sal_Int32 const nNextAction = 1;
+ sal_Int32 nEndSync = 0;
+ sal_Int32 const nU4 = 0;
+ sal_Int32 const nU5 = 3;
+
+ sal_Int16 nAnimationEndSync = 0;
+ if ( xNode->getEndSync() >>= nAnimationEndSync )
+ {
+ if ( nAnimationEndSync == AnimationEndSync::ALL )
+ nEndSync = 1;
+ }
+ rStrm.WriteInt32( nConcurrent )
+ .WriteInt32( nNextAction )
+ .WriteInt32( nEndSync )
+ .WriteInt32( nU4 )
+ .WriteInt32( nU5 );
+
+}
+
+// nFlags Bit 6 = fixInteractiveSequenceTiming (for child)
+// nFlags Bit 5 = fixInteractiveSequenceTiming (for root)
+// nFlags Bit 4 = first node of main sequence -> begin event next has to be replaced to indefinite
+void AnimationExporter::exportAnimEvent( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_Int32 nFlags )
+{
+ sal_uInt16 i;
+ for ( i = 0; i < 4; i++ )
+ {
+ sal_Int32 nU1 = 0;
+ sal_Int32 nTrigger = 0;
+ sal_Int32 nU3 = 0;
+ sal_Int32 nBegin = 0;
+
+ bool bCreateEvent = false;
+ Any aSource;
+
+ switch( i )
+ {
+ case 0 :
+ case 1 :
+ {
+ Any aAny;
+ Event aEvent;
+ css::animations::Timing eTiming;
+ if ( i == 0 )
+ {
+ if ( nFlags & 0x20 )
+ {
+ // taking the first child
+ Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xE( xEA->createEnumeration(), css::uno::UNO_SET_THROW );
+ if ( xE->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY );
+ aAny = xClickNode->getBegin();
+ }
+ }
+ else if ( nFlags & 0x40 )
+ {
+ // begin has to be replaced with void, so don't do anything
+ }
+ else
+ {
+ aAny = xNode->getBegin();
+ if ( nFlags & 0x10 ) // replace ON_NEXT with INDEFINITE
+ {
+ if ( ( aAny >>= aEvent ) && ( aEvent.Trigger == EventTrigger::ON_NEXT ) )
+ {
+ eTiming = Timing_INDEFINITE;
+ aAny <<= eTiming;
+ }
+ }
+ }
+ }
+ else
+ aAny = xNode->getEnd();
+
+ double fTiming = 0.0;
+ if ( aAny >>= aEvent )
+ {
+ bCreateEvent = true;
+ switch( aEvent.Trigger )
+ {
+ case EventTrigger::NONE : nTrigger = 0; break;
+ case EventTrigger::ON_BEGIN : nTrigger = 1; break;
+ case EventTrigger::ON_END : nTrigger = 2; break;
+ case EventTrigger::BEGIN_EVENT : nTrigger = 3; break;
+ case EventTrigger::END_EVENT : nTrigger = 4; nU1 = 2; nU3 = mnCurrentGroup; break;
+ case EventTrigger::ON_CLICK : nTrigger = 5; break;
+ case EventTrigger::ON_DBL_CLICK : nTrigger = 6; break;
+ case EventTrigger::ON_MOUSE_ENTER : nTrigger = 7; break;
+ case EventTrigger::ON_MOUSE_LEAVE : nTrigger = 8; break;
+ case EventTrigger::ON_NEXT : nTrigger = 9; break;
+ case EventTrigger::ON_PREV : nTrigger = 10; break;
+ case EventTrigger::ON_STOP_AUDIO : nTrigger = 11; break;
+ }
+ if ( aEvent.Offset.hasValue() )
+ {
+ if ( aEvent.Offset >>= eTiming )
+ {
+ if ( eTiming == Timing_INDEFINITE )
+ nBegin = -1;
+ }
+ else if ( aEvent.Offset >>= fTiming )
+ nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
+ }
+ aSource = aEvent.Source;
+ }
+ else if ( aAny >>= eTiming )
+ {
+ bCreateEvent = true;
+ if ( eTiming == Timing_INDEFINITE )
+ nBegin = -1;
+ }
+ else if ( aAny >>= fTiming )
+ {
+ bCreateEvent = true;
+ nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
+ }
+ }
+ break;
+
+ case 2 :
+ {
+ if ( nFlags & ( 1 << i ) )
+ {
+ bCreateEvent = true;
+ nU1 = 1;
+ nTrigger = 9;
+ }
+ }
+ break;
+ case 3 :
+ {
+ if ( nFlags & ( 1 << i ) )
+ {
+ bCreateEvent = true;
+ nU1 = 1;
+ nTrigger = 10;
+ }
+ }
+ break;
+ }
+ if ( bCreateEvent )
+ {
+ EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, i + 1 );
+ {
+ EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
+ rStrm.WriteInt32( nU1 )
+ .WriteInt32( nTrigger )
+ .WriteInt32( nU3 )
+ .WriteInt32( nBegin );
+ }
+ exportAnimateTargetElement( rStrm, aSource, ( nFlags & ( 1 << i ) ) != 0 );
+ }
+ }
+}
+
+Any AnimationExporter::convertAnimateValue( const Any& rSourceValue, std::u16string_view rAttributeName )
+{
+ OUString aDest;
+ if ( rAttributeName == u"X"
+ || rAttributeName == u"Y"
+ || rAttributeName == u"Width"
+ || rAttributeName == u"Height"
+ )
+ {
+ OUString aStr;
+ if ( rSourceValue >>= aStr )
+ {
+ ImplTranslateAttribute( aStr, TRANSLATE_MEASURE );
+ aDest += aStr;
+ }
+ }
+ else if ( rAttributeName == u"Rotate" // "r" or "style.rotation" ?
+ || rAttributeName == u"Opacity"
+ || rAttributeName == u"CharHeight"
+ || rAttributeName == u"SkewX"
+ )
+ {
+ double fNumber = 0.0;
+ if ( rSourceValue >>= fNumber )
+ aDest += OUString::number( fNumber );
+ }
+ else if ( rAttributeName == u"Color"
+ || rAttributeName == u"FillColor" // "Fillcolor" or "FillColor" ?
+ || rAttributeName == u"LineColor"
+ || rAttributeName == u"CharColor"
+ )
+ {
+ sal_Int32 nColor = 0;
+ Sequence< double > aHSL( 3 );
+ OUString aP( "," );
+ if ( rSourceValue >>= aHSL )
+ {
+ aDest += "hsl("
+ + OUString::number( static_cast<sal_Int32>( aHSL[ 0 ] / ( 360.0 / 255 ) ) )
+ + aP
+ + OUString::number( static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 ) )
+ + aP
+ + OUString::number( static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 ) )
+ + ")";
+ }
+ else if ( rSourceValue >>= nColor )
+ {
+ aDest += "rgb("
+ + OUString::number( static_cast<sal_Int8>(nColor) )
+ + aP
+ + OUString::number( static_cast<sal_Int8>( nColor >> 8 ) )
+ + aP
+ + OUString::number( static_cast<sal_Int8>( nColor >> 16 ) )
+ + ")";
+ }
+ }
+ else if ( rAttributeName == u"FillStyle" )
+ {
+ css::drawing::FillStyle eFillStyle;
+ if ( rSourceValue >>= eFillStyle )
+ {
+ if ( eFillStyle == css::drawing::FillStyle_NONE )
+ aDest += "none"; // ?
+ else
+ aDest += "solid";
+ }
+ }
+ else if (rAttributeName == u"FillOn")
+ {
+ bool bFillOn;
+ if ( rSourceValue >>= bFillOn )
+ {
+ if ( bFillOn )
+ aDest += "true";
+ else
+ aDest += "false";
+ }
+ }
+ else if ( rAttributeName == u"LineStyle" )
+ {
+ css::drawing::LineStyle eLineStyle;
+ if ( rSourceValue >>= eLineStyle )
+ {
+ if ( eLineStyle == css::drawing::LineStyle_NONE )
+ aDest += "false";
+ else
+ aDest += "true";
+ }
+ }
+ else if ( rAttributeName == u"CharWeight" )
+ {
+ float fFontWeight = 0.0;
+ if ( rSourceValue >>= fFontWeight )
+ {
+ if ( fFontWeight == css::awt::FontWeight::BOLD )
+ aDest += "bold";
+ else
+ aDest += "normal";
+ }
+ }
+ else if ( rAttributeName == u"CharUnderline" )
+ {
+ sal_Int16 nFontUnderline = 0;
+ if ( rSourceValue >>= nFontUnderline )
+ {
+ if ( nFontUnderline == css::awt::FontUnderline::NONE )
+ aDest += "false";
+ else
+ aDest += "true";
+ }
+ }
+ else if ( rAttributeName == u"CharPosture" )
+ {
+ css::awt::FontSlant eFontSlant;
+ if ( rSourceValue >>= eFontSlant )
+ {
+ if ( eFontSlant == css::awt::FontSlant_ITALIC )
+ aDest += "italic";
+ else
+ aDest += "normal"; // ?
+ }
+ }
+ else if ( rAttributeName == u"Visibility" )
+ {
+ bool bVisible = true;
+ if ( rSourceValue >>= bVisible )
+ {
+ if ( bVisible )
+ aDest += "visible";
+ else
+ aDest += "hidden";
+ }
+ }
+ Any aRet;
+ if ( !aDest.isEmpty() )
+ aRet <<= aDest;
+ else
+ aRet = rSourceValue;
+ return aRet;
+}
+
+void AnimationExporter::exportAnimateSet( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
+{
+ Reference< XAnimateSet > xSet( xNode, UNO_QUERY );
+ if( !xSet.is() )
+ return;
+
+ EscherExContainer aAnimateSet( rStrm, DFF_msofbtAnimateSet, 0 );
+ {
+ EscherExAtom aAnimateSetData( rStrm, DFF_msofbtAnimateSetData );
+ sal_uInt32 const nId1 = 1; // ??
+ sal_uInt32 const nId2 = 1; // ??
+ rStrm.WriteUInt32( nId1 ).WriteUInt32( nId2 );
+ }
+ Any aConvertedValue( convertAnimateValue( xSet->getTo(), xSet->getAttributeName() ) );
+ if ( aConvertedValue.hasValue() )
+ exportAnimProperty( rStrm, 1, aConvertedValue, TRANSLATE_NONE );
+ exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
+}
+
+sal_uInt32 AnimationExporter::GetValueTypeForAttributeName( const OUString& rAttributeName )
+{
+ sal_uInt32 nValueType = 0;
+
+ struct Entry
+ {
+ const char* pName;
+ sal_uInt8 nType;
+ };
+ static const Entry lcl_attributeMap[] =
+ {
+ { "charcolor", 2 },
+ { "charfontname", 0 },
+ { "charheight", 1 },
+ { "charposture", 0 },
+ // TODO(Q1): This should prolly be changed in PPT import
+ // { "charrotation", ATTRIBUTE_CHAR_ROTATION },
+ { "charrotation", 1 },
+ { "charunderline", 0 },
+ { "charweight", 0 },
+ { "color", 2 },
+ { "dimcolor", 2 },
+ { "fillcolor", 2 },
+ { "fillstyle", 0 },
+ { "height", 1 },
+ { "linecolor", 2 },
+ { "linestyle", 0 },
+ { "opacity", 0 },
+ { "rotate", 1 },
+ { "skewx", 1 },
+ { "skewy", 1 },
+ { "visibility", 1 },
+ { "width", 1 },
+ { "x", 1 },
+ { "y", 1 },
+ { nullptr, 0 }
+ };
+ const Entry* pPtr = &lcl_attributeMap[ 0 ];
+ while( pPtr->pName )
+ {
+ if ( rAttributeName.equalsIgnoreAsciiCaseAscii( pPtr->pName ) )
+ {
+ nValueType = pPtr->nType;
+ break;
+ }
+ pPtr++;
+ }
+ DBG_ASSERT( pPtr->pName, "GetValueTypeForAttributeName, unknown property value!" );
+ return nValueType;
+}
+
+void AnimationExporter::exportAnimate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
+ if ( !xAnimate.is() )
+ return;
+
+ Any aBy ( xAnimate->getBy() );
+ Any aFrom( xAnimate->getFrom() );
+ Any aTo ( xAnimate->getTo() );
+
+ EscherExContainer aContainer( rStrm, DFF_msofbtAnimate, 0 );
+ {
+ EscherExAtom aAnimateData( rStrm, DFF_msofbtAnimateData );
+ sal_uInt32 nBits = 0x38;
+ sal_Int16 nTmp = xAnimate->getCalcMode();
+ sal_uInt32 nCalcMode = /* (nTmp == AnimationCalcMode::FORMULA) ? 2 : */ (nTmp == AnimationCalcMode::LINEAR) ? 1 : 0;
+ sal_uInt32 nValueType = GetValueTypeForAttributeName( xAnimate->getAttributeName() );
+
+ if ( aBy.hasValue() )
+ nBits |= 1;
+ if ( aFrom.hasValue() )
+ nBits |= 2;
+ if ( aTo.hasValue() )
+ nBits |= 4;
+
+ rStrm.WriteUInt32( nCalcMode )
+ .WriteUInt32( nBits )
+ .WriteUInt32( nValueType );
+ }
+ if ( aBy.hasValue() )
+ exportAnimProperty( rStrm, 1, aBy, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
+ if ( aFrom.hasValue() )
+ exportAnimProperty( rStrm, 2, aFrom, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
+ if ( aTo.hasValue() )
+ exportAnimProperty( rStrm, 3, aTo, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
+
+ exportAnimateKeyPoints( rStrm, xAnimate );
+ exportAnimateTarget( rStrm, xNode );
+}
+
+void AnimationExporter::exportAnimateTarget( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_uInt32 nForceAttributeNames, int nAfterEffectType )
+{
+ EscherExContainer aAnimateTarget( rStrm, DFF_msofbtAnimateTarget, 0 );
+ Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
+ if ( !xAnimate.is() )
+ return;
+
+ {
+ EscherExAtom aAnimateTargetSettings( rStrm, DFF_msofbtAnimateTargetSettings, 0 );
+ // nBits %0001: additive, %0010: accumulate, %0100: attributeName, %1000: transformtype
+ // nAdditive 0 = base, 1 = sum, 2 = replace, 3 = multiply, 4 = none
+ // nAccumulate 0 = none, 1 = always
+ // nTransformType 0: "property" else "image"
+ sal_uInt32 nBits = 0;
+ sal_uInt32 nAdditive = 0;
+ sal_uInt32 nAccumulate = 0;
+ sal_uInt32 const nTransformType = 0;
+ if ( xAnimate.is() )
+ {
+ if ( !xAnimate->getAttributeName().isEmpty() )
+ nBits |= 4; // what is attributeName ?, maybe this is set if a DFF_msofbtAnimateAttributeNames is written
+ sal_Int16 nAdditiveMode = xAnimate->getAdditive();
+ if ( nAdditiveMode != AnimationAdditiveMode::BASE )
+ {
+ nBits |= 1;
+ switch( nAdditiveMode )
+ {
+ case AnimationAdditiveMode::SUM : nAdditive = 1; break;
+ case AnimationAdditiveMode::REPLACE : nAdditive = 2; break;
+ case AnimationAdditiveMode::MULTIPLY : nAdditive = 3; break;
+ case AnimationAdditiveMode::NONE : nAdditive = 4; break;
+ }
+ }
+ if ( xAnimate->getAccumulate() )
+ {
+ nBits |= 2;
+ nAccumulate = 1;
+ }
+ }
+ rStrm.WriteUInt32( nBits )
+ .WriteUInt32( nAdditive )
+ .WriteUInt32( nAccumulate )
+ .WriteUInt32( nTransformType );
+ }
+ if ( !xAnimate->getAttributeName().isEmpty() || nForceAttributeNames )
+ {
+ EscherExContainer aAnimateAttributeNames( rStrm, DFF_msofbtAnimateAttributeNames, 1 );
+ OUString aAttributeName( xAnimate->getAttributeName() );
+ if ( nForceAttributeNames )
+ {
+ if( nForceAttributeNames == 1 )
+ {
+ aAttributeName = "r";
+ }
+ }
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OUString aToken( aAttributeName.getToken( 0, ';', nIndex ) );
+ exportAnimPropertyString( rStrm, 0, aToken, TRANSLATE_ATTRIBUTE );
+ }
+ while ( nIndex >= 0 );
+ }
+
+ if( nAfterEffectType != AFTEREFFECT_NONE )
+ {
+ EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
+ exportAnimPropertyuInt32( rStrm, 6, 1 );
+ if( nAfterEffectType == AFTEREFFECT_COLOR )
+ {
+ exportAnimPropertyuInt32( rStrm, 4, 0 );
+ exportAnimPropertyuInt32( rStrm, 5, 0 );
+ }
+ }
+ exportAnimateTargetElement( rStrm, aTarget.hasValue() ? aTarget : xAnimate->getTarget(), false );
+}
+
+Reference< XShape > AnimationExporter::getTargetElementShape( const Any& rAny, sal_Int32& rBegin, sal_Int32& rEnd, bool& rParagraphTarget )
+{
+ Reference< XShape > xShape;
+ rAny >>= xShape;
+
+ rParagraphTarget = false;
+
+ if( xShape.is() )
+ return xShape;
+
+ ParagraphTarget aParaTarget;
+ if( rAny >>= aParaTarget )
+ xShape = aParaTarget.Shape;
+ if ( !xShape.is() )
+ return xShape;
+
+ // now calculating the character range for the paragraph
+ sal_Int16 nParagraph = aParaTarget.Paragraph;
+ Reference< XSimpleText > xText( xShape, UNO_QUERY );
+ if ( !xText.is() )
+ return xShape;
+
+ rParagraphTarget = true;
+ Reference< XEnumerationAccess > xTextParagraphEnumerationAccess( xText, UNO_QUERY );
+ if ( !xTextParagraphEnumerationAccess.is() )
+ return xShape;
+
+ Reference< XEnumeration > xTextParagraphEnumeration( xTextParagraphEnumerationAccess->createEnumeration() );
+ if ( !xTextParagraphEnumeration.is() )
+ return xShape;
+
+ sal_Int16 nCurrentParagraph;
+ rBegin = rEnd = nCurrentParagraph = 0;
+ while ( xTextParagraphEnumeration->hasMoreElements() )
+ {
+ Reference< XTextRange > xTextRange( xTextParagraphEnumeration->nextElement(), UNO_QUERY );
+ if ( xTextRange.is() )
+ {
+ OUString aParaText( xTextRange->getString() );
+ sal_Int32 nLength = aParaText.getLength() + 1;
+ rEnd += nLength;
+ if ( nCurrentParagraph == nParagraph )
+ break;
+ nCurrentParagraph++;
+ rBegin += nLength;
+ }
+ }
+
+ return xShape;
+}
+
+void AnimationExporter::exportAnimateTargetElement( SvStream& rStrm, const Any& rAny, const bool bCreate2b01Atom )
+{
+ sal_uInt32 nRefMode = 0; // nRefMode == 2 -> Paragraph
+ sal_Int32 begin = -1;
+ sal_Int32 end = -1;
+ bool bParagraphTarget;
+
+ Reference< XShape > xShape = getTargetElementShape(rAny, begin, end, bParagraphTarget);
+
+ if( bParagraphTarget )
+ nRefMode = 2;
+
+ if ( !(xShape.is() || bCreate2b01Atom) )
+ return;
+
+ EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
+ if ( xShape.is() )
+ {
+ EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
+
+ sal_uInt32 const nRefType = 1; // TODO: nRefType == 2 -> Sound;
+ sal_uInt32 nRefId = mrSolverContainer.GetShapeId( xShape );
+
+ rStrm.WriteUInt32( nRefMode )
+ .WriteUInt32( nRefType )
+ .WriteUInt32( nRefId )
+ .WriteInt32( begin )
+ .WriteInt32( end );
+ }
+ if ( bCreate2b01Atom )
+ {
+ EscherExAtom a2b01Atom( rStrm, 0x2b01 );
+ rStrm.WriteUInt32( 1 ); // ?
+ }
+}
+
+void AnimationExporter::exportAnimateKeyPoints( SvStream& rStrm, const Reference< XAnimate >& xAnimate )
+{
+ Sequence< double > aKeyTimes( xAnimate->getKeyTimes() );
+ Sequence< Any > aValues( xAnimate->getValues() );
+ OUString aFormula( xAnimate->getFormula() );
+ if ( !aKeyTimes.hasElements() )
+ return;
+
+ EscherExContainer aAnimKeyPoints( rStrm, DFF_msofbtAnimKeyPoints );
+ sal_Int32 i;
+ for ( i = 0; i < aKeyTimes.getLength(); i++ )
+ {
+ {
+ EscherExAtom aAnimKeyTime( rStrm, DFF_msofbtAnimKeyTime );
+ sal_Int32 nKeyTime = static_cast<sal_Int32>( aKeyTimes[ i ] * 1000.0 );
+ rStrm.WriteInt32( nKeyTime );
+ }
+ Any aAny[ 2 ];
+ if ( aValues[ i ].hasValue() )
+ {
+ ValuePair aPair;
+ if ( aValues[ i ] >>= aPair )
+ {
+ aAny[ 0 ] = convertAnimateValue( aPair.First, xAnimate->getAttributeName() );
+ aAny[ 1 ] = convertAnimateValue( aPair.Second, xAnimate->getAttributeName() );
+ }
+ else
+ {
+ aAny[ 0 ] = convertAnimateValue( aValues[ i ], xAnimate->getAttributeName() );
+ }
+ if ( !i && !aFormula.isEmpty() )
+ {
+ ImplTranslateAttribute( aFormula, TRANSLATE_MEASURE );
+ aAny[ 1 ] <<= aFormula;
+ }
+ exportAnimProperty( rStrm, 0, aAny[ 0 ], TRANSLATE_NONE );
+ exportAnimProperty( rStrm, 1, aAny[ 1 ], TRANSLATE_NONE );
+ }
+ }
+}
+
+void AnimationExporter::exportAnimValue( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const bool bExportAlways )
+{
+ Any aAny;
+ // repeat count (0)
+ double fRepeat = 0.0;
+ float fRepeatCount = 0.0;
+ css::animations::Timing eTiming;
+ aAny = xNode->getRepeatCount();
+ if ( aAny >>= eTiming )
+ {
+ if ( eTiming == Timing_INDEFINITE )
+ fRepeatCount = (float(3.40282346638528860e+38));
+ }
+ else if ( aAny >>= fRepeat )
+ fRepeatCount = static_cast<float>(fRepeat);
+ if ( fRepeatCount != 0.0 )
+ {
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
+ sal_uInt32 const nType = 0;
+ rStrm.WriteUInt32( nType )
+ .WriteFloat( fRepeatCount );
+ }
+ // accelerate (3)
+ float fAccelerate = static_cast<float>(xNode->getAcceleration());
+ if ( bExportAlways || ( fAccelerate != 0.0 ) )
+ {
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
+ sal_uInt32 const nType = 3;
+ rStrm.WriteUInt32( nType )
+ .WriteFloat( fAccelerate );
+ }
+
+ // decelerate (4)
+ float fDecelerate = static_cast<float>(xNode->getDecelerate());
+ if ( bExportAlways || ( fDecelerate != 0.0 ) )
+ {
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
+ sal_uInt32 const nType = 4;
+ rStrm.WriteUInt32( nType )
+ .WriteFloat( fDecelerate );
+ }
+
+ // autoreverse (5)
+ bool bAutoReverse = xNode->getAutoReverse();
+ if ( bExportAlways || bAutoReverse )
+ {
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
+ sal_uInt32 const nType = 5;
+ sal_uInt32 nVal = bAutoReverse ? 1 : 0;
+ rStrm.WriteUInt32( nType )
+ .WriteUInt32( nVal );
+ }
+}
+
+void AnimationExporter::exportTransitionFilter( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY );
+ if ( !xFilter.is() )
+ return;
+
+ EscherExContainer aAnimateFilter( rStrm, DFF_msofbtAnimateFilter );
+ {
+ EscherExAtom aAnimateFilterData( rStrm, DFF_msofbtAnimateFilterData );
+ sal_uInt32 const nBits = 3; // bit 0 -> use AnimAttributeValue
+ // bit 1 -> use nTransition
+
+ sal_uInt32 nTransition = xFilter->getMode() ? 0 : 1;
+ rStrm.WriteUInt32( nBits )
+ .WriteUInt32( nTransition );
+ }
+ const char* pFilter = FindTransitionName( xFilter->getTransition(), xFilter->getSubtype(), xFilter->getDirection() );
+ if ( pFilter )
+ {
+ const OUString aStr( OUString::createFromAscii( pFilter ) );
+ exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE );
+ }
+ exportAnimateTarget( rStrm, xNode );
+}
+
+void AnimationExporter::exportAnimateMotion( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateMotion > xMotion( xNode, UNO_QUERY );
+ if ( !xMotion.is() )
+ return;
+
+ EscherExContainer aAnimateMotion( rStrm, DFF_msofbtAnimateMotion );
+ {
+ { //SJ: Ignored from import filter
+ EscherExAtom aAnimateMotionData( rStrm, DFF_msofbtAnimateMotionData );
+ sal_uInt32 const nBits = 0x98;
+ sal_uInt32 const nOrigin = 0x2;
+ float const fByX = 100.0; // nBits&1
+ float const fByY = 100.0; // nBits&1
+ float const fFromX = 0.0; // nBits&2
+ float const fFromY = 0.0; // nBits&2
+ float const fToX = 100.0; // nBits&4
+ float const fToY = 100.0; // nBits&4
+ rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nOrigin );
+ }
+
+ OUString aStr;
+ if ( xMotion->getPath() >>= aStr )
+ {
+ if ( !aStr.isEmpty() )
+ exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE );
+ }
+ exportAnimateTarget( rStrm, xNode );
+ }
+}
+
+void AnimationExporter::exportAnimateTransform( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY );
+ if ( !xTransform.is() )
+ return;
+
+ if ( xTransform->getTransformType() == AnimationTransformType::SCALE )
+ {
+ EscherExContainer aAnimateScale( rStrm, DFF_msofbtAnimateScale );
+ {
+ EscherExAtom aAnimateScaleData( rStrm, DFF_msofbtAnimateScaleData );
+ sal_uInt32 nBits = 0;
+ sal_uInt32 const nZoomContents = 1;
+ float fByX = 100.0;
+ float fByY = 100.0;
+ float fFromX = 0.0;
+ float fFromY = 0.0;
+ float fToX = 100.0;
+ float fToY = 100.0;
+
+ double fX = 0.0, fY = 0.0;
+ ValuePair aPair;
+ if ( xTransform->getBy() >>= aPair )
+ {
+ if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
+ {
+ nBits |= 1;
+ fByX = static_cast<float>( fX * 100 );
+ fByY = static_cast<float>( fY * 100 );
+ }
+ }
+ if ( xTransform->getFrom() >>= aPair )
+ {
+ if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
+ {
+ nBits |= 2;
+ fFromX = static_cast<float>( fX * 100 );
+ fFromY = static_cast<float>( fY * 100 );
+ }
+ }
+ if( xTransform->getTo() >>= aPair )
+ {
+ if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
+ {
+ nBits |= 4;
+ fToX = static_cast<float>( fX * 100 );
+ fToY = static_cast<float>( fY * 100 );
+ }
+ }
+
+ // TODO: ZoomContents:
+ //if( nBits & 8 )
+ //( fprintf( mpFile, " zoomContents=\"%s\"", nZoomContents ? "true" : "false" );
+
+ rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nZoomContents );
+ }
+ exportAnimateTarget( rStrm, xNode );
+ }
+ else if ( xTransform->getTransformType() == AnimationTransformType::ROTATE )
+ {
+ EscherExContainer aAnimateRotation( rStrm, DFF_msofbtAnimateRotation );
+ {
+ EscherExAtom aAnimateRotationData( rStrm, DFF_msofbtAnimateRotationData );
+ sal_uInt32 nBits = 0;
+ sal_uInt32 const nU1 = 0;
+ float fBy = 360.0;
+ float fFrom = 0.0;
+ float fTo = 360.0;
+
+ double fVal = 0.0;
+ if ( xTransform->getBy() >>= fVal )
+ {
+ nBits |= 1;
+ fBy = static_cast<float>(fVal);
+ }
+ if ( xTransform->getFrom() >>= fVal )
+ {
+ nBits |= 2;
+ fFrom = static_cast<float>(fVal);
+ }
+ if ( xTransform->getTo() >>= fVal )
+ {
+ nBits |= 4;
+ fTo = static_cast<float>(fVal);
+ }
+ rStrm.WriteUInt32( nBits ).WriteFloat( fBy ).WriteFloat( fFrom ).WriteFloat( fTo ).WriteUInt32( nU1 );
+ }
+ exportAnimateTarget( rStrm, xNode, 1 );
+ }
+}
+
+bool AnimationExporter::getColorAny( const Any& rAny, const sal_Int16 nColorSpace, sal_Int32& rMode, sal_Int32& rA, sal_Int32& rB, sal_Int32& rC )
+{
+ bool bIsColor = true;
+
+ rMode = 0;
+ if ( nColorSpace == AnimationColorSpace::HSL )
+ rMode = 1;
+
+ sal_Int32 nColor = 0;
+ Sequence< double > aHSL( 3 );
+ if ( rAny >>= nColor ) // RGB color
+ {
+ rA = static_cast<sal_uInt8>( nColor >> 16 );
+ rB = static_cast<sal_uInt8>( nColor >> 8 );
+ rC = static_cast<sal_uInt8>(nColor);
+ }
+ else if ( rAny >>= aHSL ) // HSL
+ {
+ rA = static_cast<sal_Int32>( aHSL[ 0 ] * 255.0 / 360.0 );
+ rB = static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 );
+ rC = static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 );
+ }
+ else
+ bIsColor = false;
+ return bIsColor;
+}
+
+void AnimationExporter::exportAnimateColor( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
+{
+ Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
+ if ( !xColor.is() )
+ return;
+
+ EscherExContainer aAnimateColor( rStrm, DFF_msofbtAnimateColor );
+ {
+ EscherExAtom aAnimateColorData( rStrm, DFF_msofbtAnimateColorData );
+ sal_uInt32 nBits = 8;
+
+ sal_Int32 nByMode, nByA, nByB, nByC;
+ nByMode = nByA = nByB = nByC = 0;
+
+ sal_Int32 nFromMode, nFromA, nFromB, nFromC;
+ nFromMode = nFromA = nFromB = nFromC = 0;
+
+ sal_Int32 nToMode, nToA, nToB, nToC;
+ nToMode = nToA = nToB = nToC = 0;
+
+ sal_Int16 nColorSpace = xColor->getColorInterpolation();
+
+ Any aAny( xColor->getBy() );
+ if ( aAny.hasValue() )
+ {
+ if ( getColorAny( aAny, nColorSpace, nByMode, nByA, nByB, nByC ) )
+ nBits |= 0x11;
+ }
+ aAny = xColor->getFrom();
+ if ( aAny.hasValue() )
+ {
+ if ( getColorAny( aAny, nColorSpace, nFromMode, nFromA, nFromB, nFromC ) )
+ nBits |= 0x12;
+ }
+ aAny = xColor->getTo();
+ if ( aAny.hasValue() )
+ {
+ if ( getColorAny( aAny, nColorSpace, nToMode, nToA, nToB, nToC ) )
+ nBits |= 0x14;
+ }
+ rStrm .WriteUInt32( nBits )
+ .WriteInt32( nByMode ).WriteInt32( nByA ).WriteInt32( nByB ).WriteInt32( nByC )
+ .WriteInt32( nFromMode ).WriteInt32( nFromA ).WriteInt32( nFromB ).WriteInt32( nFromC )
+ .WriteInt32( nToMode ).WriteInt32( nToA ).WriteInt32( nToB ).WriteInt32( nToC );
+ }
+ exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
+}
+
+void AnimationExporter::exportIterate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XIterateContainer > xIterate( xNode, UNO_QUERY );
+ if ( !xIterate.is() )
+ return;
+
+ EscherExAtom aAnimIteration( rStrm, DFF_msofbtAnimIteration );
+
+ float fInterval = 10.0;
+ sal_Int32 nTextUnitEffect = 0;
+ sal_Int32 const nU1 = 1;
+ sal_Int32 const nU2 = 1;
+ sal_Int32 const nU3 = 0xe;
+
+ sal_Int16 nIterateType = xIterate->getIterateType();
+ switch( nIterateType )
+ {
+ case TextAnimationType::BY_WORD : nTextUnitEffect = 1; break;
+ case TextAnimationType::BY_LETTER : nTextUnitEffect = 2; break;
+ }
+
+ fInterval = static_cast<float>(xIterate->getIterateInterval());
+
+ // convert interval from absolute to percentage
+ double fDuration = 0.0;
+
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimate > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( xChildNode.is() )
+ {
+ double fChildBegin = 0.0;
+ double fChildDuration = 0.0;
+ xChildNode->getBegin() >>= fChildBegin;
+ xChildNode->getDuration() >>= fChildDuration;
+
+ fChildDuration += fChildBegin;
+ if( fChildDuration > fDuration )
+ fDuration = fChildDuration;
+ }
+ }
+ }
+ }
+
+ if( fDuration )
+ fInterval = static_cast<float>(100.0 * fInterval / fDuration);
+
+ rStrm.WriteFloat( fInterval ).WriteInt32( nTextUnitEffect ).WriteInt32( nU1 ).WriteInt32( nU2 ).WriteInt32( nU3 );
+ aTarget = xIterate->getTarget();
+}
+
+} // namespace ppt;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptexanimations.hxx b/sd/source/filter/eppt/pptexanimations.hxx
new file mode 100644
index 000000000..daa54d85b
--- /dev/null
+++ b/sd/source/filter/eppt/pptexanimations.hxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#ifdef DBG_ANIM_LOG
+#include <stdio.h>
+#endif
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::animations { class XAnimate; }
+namespace com::sun::star::animations { class XAnimationNode; }
+namespace com::sun::star::beans { struct NamedValue; }
+namespace com::sun::star::drawing { class XDrawPage; }
+namespace com::sun::star::drawing { class XShape; }
+namespace ppt { class ExSoundCollection; }
+
+class SvStream;
+class EscherSolverContainer;
+
+namespace ppt
+{
+
+ struct AfterEffectNode
+ {
+ css::uno::Reference< css::animations::XAnimationNode > mxNode;
+ css::uno::Reference< css::animations::XAnimationNode > mxMaster;
+
+ AfterEffectNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode,
+ const css::uno::Reference< css::animations::XAnimationNode >& xMaster )
+ : mxNode( xNode ), mxMaster( xMaster ) {}
+ };
+
+ typedef std::shared_ptr< AfterEffectNode > AfterEffectNodePtr;
+
+typedef sal_uInt32 TranslateMode;
+#define TRANSLATE_NONE 0
+#define TRANSLATE_VALUE 1
+#define TRANSLATE_ATTRIBUTE 2
+#define TRANSLATE_MEASURE 4
+#define TRANSLATE_NUMBER_TO_STRING 8
+
+const int AFTEREFFECT_NONE = 0;
+const int AFTEREFFECT_COLOR = 1;
+const int AFTEREFFECT_SET = 2;
+
+class AnimationExporter
+{
+ css::uno::Any aTarget;
+ const EscherSolverContainer& mrSolverContainer;
+ ppt::ExSoundCollection& mrExSoundCollection;
+ std::vector< AfterEffectNodePtr > maAfterEffectNodes;
+ sal_Int32 mnCurrentGroup;
+
+ static void writeZString( SvStream& rStrm, const OUString& rVal );
+ static bool getColorAny( const css::uno::Any& rAny, const sal_Int16 nColorSpace, sal_Int32& rMode, sal_Int32& rA, sal_Int32& rB, sal_Int32& rC );
+ static bool exportAnimProperty( SvStream& rStrm, const sal_uInt16 nPropertyId, const css::uno::Any& rAny, const TranslateMode eTranslateMode );
+ static void exportAnimPropertyString( SvStream& rStrm, const sal_uInt16 nPropertyId, const OUString& rVal, const TranslateMode eTranslateMode );
+ static void exportAnimPropertyFloat( SvStream& rStrm, const sal_uInt16 nPropertyId, const double& rVal );
+ static void exportAnimPropertyuInt32( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal );
+ static void exportAnimPropertyByte( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal );
+
+ /** if available exportAnimPropertySet
+ @return the css::presentation::EffectNodeType*/
+ static sal_Int16 exportAnimPropertySet( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ static void exportAnimNode( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode,
+ const sal_Int16 nFillDefault );
+ void exportAnimate( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void exportAnimateTarget( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode, const sal_uInt32 nForceAttributeName = 0, int nAfterEffectType = AFTEREFFECT_NONE );
+ void exportAnimateSet( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode, int nAfterEffectType );
+ static void exportAnimAction( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void exportAnimEvent( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode, const sal_Int32 nFlags = 0 );
+ void exportNode( SvStream& rStrm, css::uno::Reference< css::animations::XAnimationNode > const & xNode,
+ const sal_uInt16 nContainerRecType, const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const bool bTakeBackInteractiveSequenceTiming,
+ const sal_Int16 nFillDefault );
+ void exportAnimateTargetElement( SvStream& rStrm, const css::uno::Any& rAny, const bool bCreate2b01Atom );
+ static void exportAnimateKeyPoints( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimate >& xAnimate );
+ static void exportAnimValue( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode, const bool bExportAlways );
+ void exportTransitionFilter( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void exportAnimateMotion( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void exportAnimateTransform( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void exportAnimateColor( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode, int nAfterEffectType );
+ void exportIterate( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+
+ void processAfterEffectNodes( const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+
+ bool isAfterEffectNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode ) const;
+ bool hasAfterEffectNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode, css::uno::Reference< css::animations::XAnimationNode >& xAfterEffectNode ) const;
+ bool isEmptyNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode ) const;
+
+ static css::uno::Reference< css::animations::XAnimationNode > createAfterEffectNodeClone( const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+
+public:
+ AnimationExporter( const EscherSolverContainer& rSolverContainer, ppt::ExSoundCollection& rExSoundCollection );
+
+ void doexport( const css::uno::Reference< css::drawing::XDrawPage >& xPage, SvStream& rStrm );
+
+ // helper methods also used in ooxml export
+ static css::uno::Any convertAnimateValue( const css::uno::Any& rSource, std::u16string_view rAttributeName );
+ static bool GetNodeType( const css::uno::Reference< css::animations::XAnimationNode >& xNode, sal_Int16& nType );
+ static sal_Int16 GetFillMode( const css::uno::Reference< css::animations::XAnimationNode >& xNode, const sal_Int16 nFillDefault );
+ static void GetUserData( const css::uno::Sequence< css::beans::NamedValue >& rUserData, const css::uno::Any ** pAny, std::size_t nLen );
+ static sal_uInt32 TranslatePresetSubType( const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, std::u16string_view rPresetSubType );
+ static sal_uInt32 GetPresetID( const OUString& rPreset, sal_uInt32 nAPIPresetClass, bool& bPresetId );
+ static sal_uInt32 GetValueTypeForAttributeName( const OUString& rAttributeName );
+
+ static const char* FindTransitionName( const sal_Int16 nType, const sal_Int16 nSubType, const bool bDirection );
+ static css::uno::Reference< css::drawing::XShape > getTargetElementShape( const css::uno::Any& rAny, sal_Int32& rBegin, sal_Int32& rEnd, bool& rParagraphTarget );
+};
+} // namespace ppt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptexsoundcollection.cxx b/sd/source/filter/eppt/pptexsoundcollection.cxx
new file mode 100644
index 000000000..c4770e644
--- /dev/null
+++ b/sd/source/filter/eppt/pptexsoundcollection.cxx
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "pptexsoundcollection.hxx"
+#include "epptdef.hxx"
+#include <tools/stream.hxx>
+#include <tools/urlobj.hxx>
+#include <ucbhelper/content.hxx>
+#include <comphelper/processfactory.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+
+namespace ppt
+{
+
+ExSoundEntry::ExSoundEntry(const OUString& rString)
+ : nFileSize(0)
+ , aSoundURL(rString)
+{
+ try
+ {
+ ::ucbhelper::Content aCnt( aSoundURL,
+ css::uno::Reference< css::ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+ sal_Int64 nVal = 0;
+ aCnt.getPropertyValue("Size") >>= nVal;
+ nFileSize = static_cast<sal_uInt32>(nVal);
+ }
+ catch( css::uno::Exception& )
+ {
+
+ }
+};
+
+OUString ExSoundEntry::ImplGetName() const
+{
+ INetURLObject aTmp( aSoundURL );
+ return aTmp.GetLastName();
+}
+
+OUString ExSoundEntry::ImplGetExtension() const
+{
+ INetURLObject aTmp( aSoundURL );
+ OUString aExtension(aTmp.GetFileExtension());
+ if ( !aExtension.isEmpty() )
+ {
+ aExtension = "." + aExtension;
+ }
+ return aExtension;
+}
+
+bool ExSoundEntry::IsSameURL(std::u16string_view rURL) const
+{
+ return ( rURL == aSoundURL );
+}
+
+sal_uInt32 ExSoundEntry::GetSize( sal_uInt32 nId ) const
+{
+ OUString aName( ImplGetName() );
+ OUString aExtension( ImplGetExtension() );
+
+ sal_uInt32 nSize = 8; // SoundContainer Header
+ if ( !aName.isEmpty() ) // String Atom ( instance 0 - name of sound )
+ nSize += aName.getLength() * 2 + 8;
+ if ( !aExtension.isEmpty() ) // String Atom ( instance 1 - extension of sound )
+ nSize += aExtension.getLength() * 2 + 8;
+
+ OUString aId( OUString::number(nId) ); // String Atom ( instance 2 - reference id )
+ nSize += 2 * aId.getLength() + 8;
+
+ nSize += nFileSize + 8; // SoundData Atom
+
+ return nSize;
+}
+
+void ExSoundEntry::Write( SvStream& rSt, sal_uInt32 nId ) const
+{
+ try
+ {
+ ::ucbhelper::Content aLoadContentIfExists( aSoundURL,
+ css::uno::Reference< css::ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+
+ // create SoundContainer
+ rSt.WriteUInt32( ( EPP_Sound << 16 ) | 0xf ).WriteUInt32( GetSize( nId ) - 8 );
+
+ OUString aSoundName( ImplGetName() );
+ sal_Int32 i, nSoundNameLen = aSoundName.getLength();
+ if ( nSoundNameLen )
+ {
+ // name of sound ( instance 0 )
+ rSt.WriteUInt32( EPP_CString << 16 ).WriteUInt32( nSoundNameLen * 2 );
+ for ( i = 0; i < nSoundNameLen; ++i )
+ rSt.WriteUInt16( aSoundName[i] );
+ }
+ OUString aExtension( ImplGetExtension() );
+ sal_Int32 nExtensionLen = aExtension.getLength();
+ if ( nExtensionLen )
+ {
+ // extension of sound ( instance 1 )
+ rSt.WriteUInt32( ( EPP_CString << 16 ) | 16 ).WriteUInt32( nExtensionLen * 2 );
+ for ( i = 0; i < nExtensionLen; ++i )
+ rSt.WriteUInt16( aExtension[i] );
+ }
+ // id of sound ( instance 2 )
+ OUString aId( OUString::number(nId ) );
+ sal_Int32 nIdLen = aId.getLength();
+ rSt.WriteUInt32( ( EPP_CString << 16 ) | 32 ).WriteUInt32( nIdLen * 2 );
+ for ( i = 0; i < nIdLen; ++i )
+ rSt.WriteUInt16( aId[i] );
+
+ rSt.WriteUInt32( EPP_SoundData << 16 ).WriteUInt32( nFileSize );
+ sal_uInt32 nBytesLeft = nFileSize;
+ std::unique_ptr<SvStream> pSourceFile = ::utl::UcbStreamHelper::CreateStream( aSoundURL, StreamMode::READ );
+ if ( pSourceFile )
+ {
+ std::unique_ptr<sal_uInt8[]> pBuf( new sal_uInt8[ 0x10000 ] ); // 64 kB Buffer
+ while ( nBytesLeft )
+ {
+ sal_uInt32 nToDo = std::min<sal_uInt32>( nBytesLeft, 0x10000 );
+ pSourceFile->ReadBytes(pBuf.get(), nToDo);
+ rSt.WriteBytes(pBuf.get(), nToDo);
+ nBytesLeft -= nToDo;
+ }
+ }
+ }
+ catch( css::uno::Exception& )
+ {
+
+ }
+}
+
+sal_uInt32 ExSoundCollection::GetId(const OUString& rString)
+{
+ sal_uInt32 nSoundId = 0;
+ if (!rString.isEmpty())
+ {
+ const sal_uInt32 nSoundCount = maEntries.size();
+
+ auto iter = std::find_if(maEntries.begin(), maEntries.end(),
+ [&rString](const ExSoundEntry& rEntry) { return rEntry.IsSameURL(rString); });
+ nSoundId = static_cast<sal_uInt32>(std::distance(maEntries.begin(), iter));
+
+ if ( nSoundId++ == nSoundCount )
+ {
+ ExSoundEntry aEntry( rString );
+ if ( aEntry.GetFileSize() )
+ maEntries.push_back(aEntry);
+ else
+ {
+ nSoundId = 0; // only insert sounds that are accessible
+ }
+ }
+ }
+ return nSoundId;
+}
+
+sal_uInt32 ExSoundCollection::GetSize() const
+{
+ sal_uInt32 nSize = 0;
+ if (!maEntries.empty())
+ {
+ nSize += 8 + 12; // size of SoundCollectionContainerHeader + SoundCollAtom
+ sal_uInt32 i = 1;
+ for ( const auto& rEntry : maEntries )
+ {
+ nSize += rEntry.GetSize(i);
+ ++i;
+ }
+ }
+ return nSize;
+}
+
+void ExSoundCollection::Write( SvStream& rSt ) const
+{
+ if (maEntries.empty())
+ return;
+
+ sal_uInt32 i = 1;
+ sal_uInt32 nSoundCount = maEntries.size();
+
+ // create SoundCollection Container
+ rSt.WriteUInt16( 0xf ).WriteUInt16( EPP_SoundCollection ).WriteUInt32( GetSize() - 8 );
+
+ // create SoundCollAtom ( reference to the next free SoundId );
+ rSt.WriteUInt32( EPP_SoundCollAtom << 16 ).WriteUInt32( 4 ).WriteUInt32( nSoundCount );
+
+ for ( const auto& rEntry : maEntries )
+ {
+ rEntry.Write(rSt,i);
+ ++i;
+ }
+}
+
+} // namespace ppt;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptexsoundcollection.hxx b/sd/source/filter/eppt/pptexsoundcollection.hxx
new file mode 100644
index 000000000..d81bb8118
--- /dev/null
+++ b/sd/source/filter/eppt/pptexsoundcollection.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vector>
+
+#ifdef DBG_ANIM_LOG
+#include <stdio.h>
+#endif
+#include <rtl/ustring.hxx>
+
+class SvStream;
+
+namespace ppt
+{
+
+class ExSoundEntry
+{
+ sal_uInt32 nFileSize;
+ OUString aSoundURL;
+
+ OUString ImplGetName() const;
+ OUString ImplGetExtension() const;
+
+ public:
+
+ bool IsSameURL(std::u16string_view rURL) const;
+ sal_uInt32 GetFileSize( ) const { return nFileSize; };
+
+ ExSoundEntry(const OUString& rSoundURL);
+
+ /// @return size of a complete SoundContainer.
+ sal_uInt32 GetSize( sal_uInt32 nId ) const;
+ void Write( SvStream& rSt, sal_uInt32 nId ) const;
+};
+
+class ExSoundCollection
+{
+ public:
+
+ sal_uInt32 GetId(const OUString&);
+
+ /// @return size of a complete SoundCollectionContainer.
+ sal_uInt32 GetSize() const;
+ void Write( SvStream& rSt ) const;
+
+private:
+
+ std::vector<ExSoundEntry> maEntries;
+};
+
+} // namespace ppt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-animations.cxx b/sd/source/filter/eppt/pptx-animations.cxx
new file mode 100644
index 000000000..1c901573c
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-animations.cxx
@@ -0,0 +1,1539 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <o3tl/any.hxx>
+#include <oox/token/tokens.hxx>
+#include "epptooxml.hxx"
+#include <sax/fshelper.hxx>
+#include <sal/log.hxx>
+#include <rtl/math.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+
+#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
+#include <com/sun/star/animations/AnimationCalcMode.hpp>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/AnimationRestart.hpp>
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+#include <com/sun/star/animations/AnimationValueType.hpp>
+#include <com/sun/star/animations/AnimationColorSpace.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/animations/Timing.hpp>
+#include <com/sun/star/animations/ValuePair.hpp>
+#include <com/sun/star/animations/XAnimateMotion.hpp>
+#include <com/sun/star/animations/XAnimateTransform.hpp>
+#include <com/sun/star/animations/XAnimationNode.hpp>
+#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
+#include <com/sun/star/animations/XAnimateColor.hpp>
+#include <com/sun/star/animations/XCommand.hpp>
+#include <com/sun/star/animations/XAudio.hpp>
+#include <com/sun/star/animations/XTransitionFilter.hpp>
+#include <com/sun/star/animations/XIterateContainer.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/presentation/EffectCommands.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/EffectPresetClass.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <oox/export/utils.hxx>
+#include <oox/ppt/pptfilterhelpers.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+#include "pptexanimations.hxx"
+#include "pptx-animations.hxx"
+#include "../ppt/pptanimations.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::uno;
+using namespace ::ppt;
+using namespace oox::drawingml;
+using namespace oox::core;
+using namespace oox;
+
+using ::com::sun::star::beans::NamedValue;
+using ::com::sun::star::drawing::XDrawPage;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::text::XSimpleText;
+using ::sax_fastparser::FSHelperPtr;
+
+namespace
+{
+void WriteAnimationProperty(const FSHelperPtr& pFS, const Any& rAny, sal_Int32 nToken = 0)
+{
+ if (!rAny.hasValue())
+ return;
+
+ ValuePair aPair;
+
+ if (rAny >>= aPair)
+ {
+ double x, y;
+ if ((aPair.First >>= x) && (aPair.Second >>= y))
+ {
+ if (nToken == XML_by)
+ {
+ // MS needs ending values but we have offset values.
+ x += 1.0;
+ y += 1.0;
+ }
+ pFS->singleElementNS(XML_p, nToken, XML_x, OString::number(x * 100000), XML_y,
+ OString::number(y * 100000));
+ }
+ return;
+ }
+
+ sal_Int32 nRgb = {}; // spurious -Werror=maybe-uninitialized
+ double fDouble = {}; // spurious -Werror=maybe-uninitialized
+
+ TypeClass aClass = rAny.getValueType().getTypeClass();
+ bool bWriteToken
+ = nToken
+ && (aClass == TypeClass_LONG || aClass == TypeClass_DOUBLE || aClass == TypeClass_STRING);
+
+ if (bWriteToken)
+ pFS->startElementNS(XML_p, nToken);
+
+ switch (rAny.getValueType().getTypeClass())
+ {
+ case TypeClass_LONG:
+ if (!(rAny >>= nRgb))
+ {
+ assert(false);
+ }
+ pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nRgb));
+ break;
+ case TypeClass_DOUBLE:
+ if (!(rAny >>= fDouble))
+ {
+ assert(false);
+ }
+ pFS->singleElementNS(XML_p, XML_fltVal, XML_val, OString::number(fDouble));
+ break;
+ case TypeClass_STRING:
+ pFS->singleElementNS(XML_p, XML_strVal, XML_val, *o3tl::doAccess<OUString>(rAny));
+ break;
+ default:
+ break;
+ }
+
+ if (bWriteToken)
+ pFS->endElementNS(XML_p, nToken);
+}
+
+void WriteAnimateColorColor(const FSHelperPtr& pFS, const Any& rAny, sal_Int32 nToken)
+{
+ if (!rAny.hasValue())
+ return;
+
+ sal_Int32 nColor = 0;
+ if (rAny >>= nColor)
+ {
+ pFS->startElementNS(XML_p, nToken);
+
+ if (nToken == XML_by)
+ {
+ // CT_TLByRgbColorTransform
+ SAL_WARN("sd.eppt", "Export p:rgb in p:by of animClr isn't implemented yet.");
+ }
+ else
+ {
+ // CT_Color
+ pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nColor));
+ }
+
+ pFS->endElementNS(XML_p, nToken);
+ }
+
+ Sequence<double> aHSL(3);
+ if (!(rAny >>= aHSL))
+ return;
+
+ pFS->startElementNS(XML_p, nToken);
+
+ if (nToken == XML_by)
+ {
+ // CT_TLByHslColorTransform
+ pFS->singleElementNS(XML_p, XML_hsl, XML_h, OString::number(aHSL[0] * 60000), // ST_Angel
+ XML_s, OString::number(aHSL[1] * 100000), XML_l,
+ OString::number(aHSL[2] * 100000));
+ }
+ else
+ {
+ // CT_Color
+ SAL_WARN("sd.eppt", "Export p:hsl in p:from or p:to of animClr isn't implemented yet.");
+ }
+
+ pFS->endElementNS(XML_p, nToken);
+}
+
+void WriteAnimateTo(const FSHelperPtr& pFS, const Any& rValue, const OUString& rAttributeName)
+{
+ if (!rValue.hasValue())
+ return;
+
+ SAL_INFO("sd.eppt", "to attribute name: " << rAttributeName.toUtf8());
+
+ WriteAnimationProperty(pFS, AnimationExporter::convertAnimateValue(rValue, rAttributeName),
+ XML_to);
+}
+
+void WriteAnimateValues(const FSHelperPtr& pFS, const Reference<XAnimate>& rXAnimate)
+{
+ const Sequence<double> aKeyTimes = rXAnimate->getKeyTimes();
+ if (!aKeyTimes.hasElements())
+ return;
+ const Sequence<Any> aValues = rXAnimate->getValues();
+ const OUString& sFormula = rXAnimate->getFormula();
+ const OUString& rAttributeName = rXAnimate->getAttributeName();
+
+ SAL_INFO("sd.eppt", "animate values, formula: " << sFormula.toUtf8());
+
+ assert(aValues.getLength() == aKeyTimes.getLength());
+
+ pFS->startElementNS(XML_p, XML_tavLst);
+
+ for (int i = 0; i < aKeyTimes.getLength(); i++)
+ {
+ SAL_INFO("sd.eppt", "animate value " << i << ": " << aKeyTimes[i]);
+ if (aValues[i].hasValue())
+ {
+ pFS->startElementNS(XML_p, XML_tav, XML_fmla,
+ sax_fastparser::UseIf(sFormula, !sFormula.isEmpty()), XML_tm,
+ OString::number(static_cast<sal_Int32>(aKeyTimes[i] * 100000.0)));
+ pFS->startElementNS(XML_p, XML_val);
+ ValuePair aPair;
+ if (aValues[i] >>= aPair)
+ {
+ WriteAnimationProperty(
+ pFS, AnimationExporter::convertAnimateValue(aPair.First, rAttributeName));
+ WriteAnimationProperty(
+ pFS, AnimationExporter::convertAnimateValue(aPair.Second, rAttributeName));
+ }
+ else
+ WriteAnimationProperty(
+ pFS, AnimationExporter::convertAnimateValue(aValues[i], rAttributeName));
+
+ pFS->endElementNS(XML_p, XML_val);
+ pFS->endElementNS(XML_p, XML_tav);
+ }
+ }
+
+ pFS->endElementNS(XML_p, XML_tavLst);
+}
+
+// Write condition list ( either prevCondlst or nextCondlst ) of Seq.
+void WriteAnimationCondListForSeq(const FSHelperPtr& pFS, sal_Int32 nToken)
+{
+ const char* pEvent = (nToken == XML_prevCondLst) ? "onPrev" : "onNext";
+
+ pFS->startElementNS(XML_p, nToken);
+ pFS->startElementNS(XML_p, XML_cond, XML_evt, pEvent);
+ pFS->startElementNS(XML_p, XML_tgtEl);
+ pFS->singleElementNS(XML_p, XML_sldTgt);
+ pFS->endElementNS(XML_p, XML_tgtEl);
+ pFS->endElementNS(XML_p, XML_cond);
+ pFS->endElementNS(XML_p, nToken);
+}
+
+const char* convertEventTrigger(sal_Int16 nTrigger)
+{
+ const char* pEvent = nullptr;
+ switch (nTrigger)
+ {
+ case EventTrigger::ON_NEXT:
+ pEvent = "onNext";
+ break;
+ case EventTrigger::ON_PREV:
+ pEvent = "onPrev";
+ break;
+ case EventTrigger::BEGIN_EVENT:
+ pEvent = "begin";
+ break;
+ case EventTrigger::END_EVENT:
+ pEvent = "end";
+ break;
+ case EventTrigger::ON_BEGIN:
+ pEvent = "onBegin";
+ break;
+ case EventTrigger::ON_END:
+ pEvent = "onEnd";
+ break;
+ case EventTrigger::ON_CLICK:
+ pEvent = "onClick";
+ break;
+ case EventTrigger::ON_DBL_CLICK:
+ pEvent = "onDblClick";
+ break;
+ case EventTrigger::ON_STOP_AUDIO:
+ pEvent = "onStopAudio";
+ break;
+ case EventTrigger::ON_MOUSE_ENTER:
+ pEvent = "onMouseOver"; // not exact?
+ break;
+ case EventTrigger::ON_MOUSE_LEAVE:
+ pEvent = "onMouseOut";
+ break;
+ }
+ return pEvent;
+}
+
+void WriteAnimationAttributeName(const FSHelperPtr& pFS, const OUString& rAttributeName)
+{
+ if (rAttributeName.isEmpty())
+ return;
+
+ pFS->startElementNS(XML_p, XML_attrNameLst);
+
+ SAL_INFO("sd.eppt", "write attribute name: " << rAttributeName.toUtf8());
+
+ if (rAttributeName == "X;Y")
+ {
+ pFS->startElementNS(XML_p, XML_attrName);
+ pFS->writeEscaped("ppt_x");
+ pFS->endElementNS(XML_p, XML_attrName);
+
+ pFS->startElementNS(XML_p, XML_attrName);
+ pFS->writeEscaped("ppt_y");
+ pFS->endElementNS(XML_p, XML_attrName);
+ }
+ else
+ {
+ const oox::ppt::ImplAttributeNameConversion* attrConv
+ = oox::ppt::getAttributeConversionList();
+ const char* pAttribute = nullptr;
+
+ while (attrConv->mpAPIName != nullptr)
+ {
+ if (rAttributeName.equalsAscii(attrConv->mpAPIName))
+ {
+ pAttribute = attrConv->mpMSName;
+ break;
+ }
+ attrConv++;
+ }
+
+ if (pAttribute)
+ {
+ pFS->startElementNS(XML_p, XML_attrName);
+ pFS->writeEscaped(pAttribute);
+ pFS->endElementNS(XML_p, XML_attrName);
+ }
+ else
+ {
+ SAL_WARN("sd.eppt", "unhandled animation attribute name: " << rAttributeName);
+ }
+ }
+
+ pFS->endElementNS(XML_p, XML_attrNameLst);
+}
+
+bool isValidTarget(const Any& rTarget)
+{
+ Reference<XShape> xShape;
+
+ if ((rTarget >>= xShape) && xShape.is())
+ return true;
+
+ ParagraphTarget aParagraphTarget;
+
+ return (rTarget >>= aParagraphTarget) && aParagraphTarget.Shape.is();
+}
+
+/// extract ooxml node type from a XAnimationNode.
+sal_Int32 extractNodeType(const Reference<XAnimationNode>& rXNode)
+{
+ sal_Int16 nType = rXNode->getType();
+ sal_Int32 xmlNodeType = -1;
+ switch (nType)
+ {
+ case AnimationNodeType::ITERATE:
+ case AnimationNodeType::PAR:
+ xmlNodeType = XML_par;
+ break;
+ case AnimationNodeType::SEQ:
+ xmlNodeType = XML_seq;
+ break;
+ case AnimationNodeType::ANIMATE:
+ xmlNodeType = XML_anim;
+ break;
+ case AnimationNodeType::ANIMATEMOTION:
+ xmlNodeType = XML_animMotion;
+ break;
+ case AnimationNodeType::ANIMATETRANSFORM:
+ {
+ Reference<XAnimateTransform> xTransform(rXNode, UNO_QUERY);
+ if (xTransform.is())
+ {
+ if (xTransform->getTransformType() == AnimationTransformType::SCALE)
+ xmlNodeType = XML_animScale;
+ else if (xTransform->getTransformType() == AnimationTransformType::ROTATE)
+ xmlNodeType = XML_animRot;
+ }
+ break;
+ }
+ case AnimationNodeType::ANIMATECOLOR:
+ xmlNodeType = XML_animClr;
+ break;
+ case AnimationNodeType::SET:
+ xmlNodeType = XML_set;
+ break;
+ case AnimationNodeType::TRANSITIONFILTER:
+ xmlNodeType = XML_animEffect;
+ break;
+ case AnimationNodeType::COMMAND:
+ xmlNodeType = XML_cmd;
+ break;
+ case AnimationNodeType::AUDIO:
+ xmlNodeType = XML_audio;
+ break;
+ default:
+ SAL_WARN("sd.eppt", "unhandled animation node: " << nType);
+ break;
+ }
+ return xmlNodeType;
+}
+
+/// Convert AnimationRestart to ST_TLTimeNodeRestartType value.
+const char* convertAnimationRestart(sal_Int16 nRestart)
+{
+ const char* pRestart = nullptr;
+ switch (nRestart)
+ {
+ case AnimationRestart::ALWAYS:
+ pRestart = "always";
+ break;
+ case AnimationRestart::WHEN_NOT_ACTIVE:
+ pRestart = "whenNotActive";
+ break;
+ case AnimationRestart::NEVER:
+ pRestart = "never";
+ break;
+ }
+ return pRestart;
+}
+
+/// Convert EffectNodeType to ST_TLTimeNodeType
+const char* convertEffectNodeType(sal_Int16 nType)
+{
+ const char* pNodeType = nullptr;
+ switch (nType)
+ {
+ case EffectNodeType::TIMING_ROOT:
+ pNodeType = "tmRoot";
+ break;
+ case EffectNodeType::MAIN_SEQUENCE:
+ pNodeType = "mainSeq";
+ break;
+ case EffectNodeType::ON_CLICK:
+ pNodeType = "clickEffect";
+ break;
+ case EffectNodeType::AFTER_PREVIOUS:
+ pNodeType = "afterEffect";
+ break;
+ case EffectNodeType::WITH_PREVIOUS:
+ pNodeType = "withEffect";
+ break;
+ case EffectNodeType::INTERACTIVE_SEQUENCE:
+ pNodeType = "interactiveSeq";
+ break;
+ }
+ return pNodeType;
+}
+
+/// Convert EffectPresetClass to ST_TLTimeNodePresetClassType
+const char* convertEffectPresetClass(sal_Int16 nPresetClass)
+{
+ const char* pPresetClass = nullptr;
+ switch (nPresetClass)
+ {
+ case EffectPresetClass::ENTRANCE:
+ pPresetClass = "entr";
+ break;
+ case EffectPresetClass::EXIT:
+ pPresetClass = "exit";
+ break;
+ case EffectPresetClass::EMPHASIS:
+ pPresetClass = "emph";
+ break;
+ case EffectPresetClass::MOTIONPATH:
+ pPresetClass = "path";
+ break;
+ case EffectPresetClass::OLEACTION:
+ pPresetClass = "verb"; // ?
+ break;
+ case EffectPresetClass::MEDIACALL:
+ pPresetClass = "mediacall";
+ break;
+ }
+ return pPresetClass;
+}
+
+/// convert AnimationFill to ST_TLTimeNodeFillType.
+const char* convertAnimationFill(sal_Int16 nFill)
+{
+ const char* pFill = nullptr;
+ switch (nFill)
+ {
+ case AnimationFill::FREEZE:
+ pFill = "hold";
+ break;
+ case AnimationFill::HOLD:
+ pFill = "hold";
+ break;
+ case AnimationFill::REMOVE:
+ pFill = "remove";
+ break;
+ case AnimationFill::TRANSITION:
+ pFill = "transition";
+ break;
+ }
+ return pFill;
+}
+
+/// Convert TextAnimationType to ST_IterateType.
+const char* convertTextAnimationType(sal_Int16 nType)
+{
+ const char* sType = nullptr;
+ switch (nType)
+ {
+ case TextAnimationType::BY_PARAGRAPH:
+ sType = "el";
+ break;
+ case TextAnimationType::BY_LETTER:
+ sType = "lt";
+ break;
+ case TextAnimationType::BY_WORD:
+ default:
+ sType = "wd";
+ break;
+ }
+ return sType;
+}
+
+class NodeContext;
+
+typedef std::unique_ptr<NodeContext> NodeContextPtr;
+
+class NodeContext
+{
+ const Reference<XAnimationNode> mxNode;
+ const bool mbMainSeqChild;
+
+ std::vector<NodeContextPtr> maChildNodes;
+ // if the node has valid target or contains at least one valid target.
+ bool mbValid;
+
+ // Attributes initialized from mxNode->getUserData().
+ sal_Int16 mnEffectNodeType;
+ sal_Int16 mnEffectPresetClass;
+ OUString msEffectPresetId;
+ OUString msEffectPresetSubType;
+
+ /// constructor helper for initializing user data.
+ void initUserData();
+
+ /// constructor helper to initialize maChildNodes.
+ /// return true if at least one childnode is valid.
+ bool initChildNodes();
+
+ /// constructor helper to initialize mbValid
+ void initValid(bool bHasValidChild, bool bIsIterateChild);
+
+public:
+ NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild, bool bIsIterateChild);
+ const Reference<XAnimationNode>& getNode() const { return mxNode; }
+ bool isMainSeqChild() const { return mbMainSeqChild; }
+ sal_Int16 getEffectNodeType() const { return mnEffectNodeType; }
+ sal_Int16 getEffectPresetClass() const { return mnEffectPresetClass; }
+ const OUString& getEffectPresetId() const { return msEffectPresetId; }
+ const OUString& getEffectPresetSubType() const { return msEffectPresetSubType; }
+ bool isValid() const { return mbValid; }
+ const std::vector<NodeContextPtr>& getChildNodes() const { return maChildNodes; };
+ Any getCondition(bool bBegin) const;
+};
+
+struct Cond
+{
+ OString msDelay;
+ const char* mpEvent;
+ Reference<XShape> mxShape;
+ Reference<XAnimationNode> mxNode;
+
+ Cond(const Any& rAny, bool bIsMainSeqChild);
+
+ bool isValid() const { return msDelay.getLength() || mpEvent; }
+ const char* getDelay() const { return msDelay.getLength() ? msDelay.getStr() : nullptr; }
+};
+
+Cond::Cond(const Any& rAny, bool bIsMainSeqChild)
+ : mpEvent(nullptr)
+{
+ bool bHasFDelay = false;
+ double fDelay = 0;
+ Timing eTiming;
+ Event aEvent;
+
+ if (rAny >>= eTiming)
+ {
+ if (eTiming == Timing_INDEFINITE)
+ msDelay = "indefinite";
+ }
+ else if (rAny >>= aEvent)
+ {
+ if (aEvent.Trigger == EventTrigger::ON_NEXT && bIsMainSeqChild)
+ msDelay = "indefinite";
+ else
+ {
+ mpEvent = convertEventTrigger(aEvent.Trigger);
+ if (!(aEvent.Source >>= mxShape))
+ aEvent.Source >>= mxNode;
+
+ if (aEvent.Offset >>= fDelay)
+ bHasFDelay = true;
+ }
+ }
+ else if (rAny >>= fDelay)
+ bHasFDelay = true;
+
+ if (bHasFDelay)
+ {
+ sal_Int32 nDelay = static_cast<sal_uInt32>(fDelay * 1000.0);
+ msDelay = OString::number(nDelay);
+ }
+}
+
+class PPTXAnimationExport
+{
+ void WriteAnimationNode(const NodeContextPtr& pContext);
+ void WriteAnimationNodeAnimate(sal_Int32 nXmlNodeType);
+ void WriteAnimationNodeAnimateInside(bool bSimple, bool bWriteTo = true);
+ void WriteAnimationNodeSeq();
+ void WriteAnimationNodeEffect();
+ void WriteAnimationNodeCommand();
+ void WriteAnimationNodeAudio();
+ void WriteAnimationNodeCommonPropsStart();
+ void WriteAnimationTarget(const Any& rTarget);
+ void WriteAnimationCondList(const Any& rAny, sal_Int32 nToken);
+ void WriteAnimationCond(const Cond& rCond);
+ bool isMainSeqChild() const;
+ const Reference<XAnimationNode>& getCurrentNode() const;
+
+ PowerPointExport& mrPowerPointExport;
+ const FSHelperPtr& mpFS;
+ const NodeContext* mpContext;
+
+ std::map<Reference<XAnimationNode>, sal_Int32> maAnimationNodeIdMap;
+ sal_Int32 GetNextAnimationNodeId(const Reference<XAnimationNode>& rNode);
+ sal_Int32 GetAnimationNodeId(const Reference<XAnimationNode>& rNode);
+
+public:
+ PPTXAnimationExport(PowerPointExport& rExport, const FSHelperPtr& pFS);
+ void WriteAnimations(const Reference<XDrawPage>& rXDrawPage);
+};
+
+/// Returns if rURL has an extension which is an audio format.
+bool IsAudioURL(const OUString& rURL)
+{
+ return rURL.endsWithIgnoreAsciiCase(".wav") || rURL.endsWithIgnoreAsciiCase(".m4a");
+}
+
+/// Returns if rURL has an extension which is a video format.
+bool IsVideoURL(const OUString& rURL) { return rURL.endsWithIgnoreAsciiCase(".mp4"); }
+}
+
+namespace oox::core
+{
+void WriteAnimations(const FSHelperPtr& pFS, const Reference<XDrawPage>& rXDrawPage,
+ PowerPointExport& rExport)
+{
+ PPTXAnimationExport aAnimationExport(rExport, pFS);
+ aAnimationExport.WriteAnimations(rXDrawPage);
+}
+}
+
+PPTXAnimationExport::PPTXAnimationExport(PowerPointExport& rExport, const FSHelperPtr& pFS)
+ : mrPowerPointExport(rExport)
+ , mpFS(pFS)
+ , mpContext(nullptr)
+{
+}
+
+bool PPTXAnimationExport::isMainSeqChild() const
+{
+ assert(mpContext);
+ return mpContext->isMainSeqChild();
+}
+
+const Reference<XAnimationNode>& PPTXAnimationExport::getCurrentNode() const
+{
+ assert(mpContext);
+ return mpContext->getNode();
+}
+
+void PPTXAnimationExport::WriteAnimationTarget(const Any& rTarget)
+{
+ sal_Int32 nParagraph = -1;
+ bool bParagraphTarget = false;
+
+ Reference<XShape> rXShape;
+ rTarget >>= rXShape;
+
+ if (!rXShape.is())
+ {
+ ParagraphTarget aParagraphTarget;
+ if (rTarget >>= aParagraphTarget)
+ rXShape = aParagraphTarget.Shape;
+ if (rXShape.is())
+ {
+ nParagraph = static_cast<sal_Int32>(aParagraphTarget.Paragraph);
+ Reference<XSimpleText> xText(rXShape, UNO_QUERY);
+ if (xText.is())
+ {
+ bParagraphTarget = true;
+ }
+ }
+ }
+
+ if (!rXShape.is())
+ return;
+
+ sal_Int32 nShapeID = mrPowerPointExport.GetShapeID(rXShape);
+
+ mpFS->startElementNS(XML_p, XML_tgtEl);
+ mpFS->startElementNS(XML_p, XML_spTgt, XML_spid, OString::number(nShapeID));
+ if (bParagraphTarget)
+ {
+ mpFS->startElementNS(XML_p, XML_txEl);
+ mpFS->singleElementNS(XML_p, XML_pRg, XML_st, OString::number(nParagraph), XML_end,
+ OString::number(nParagraph));
+ mpFS->endElementNS(XML_p, XML_txEl);
+ }
+ mpFS->endElementNS(XML_p, XML_spTgt);
+ mpFS->endElementNS(XML_p, XML_tgtEl);
+}
+
+void PPTXAnimationExport::WriteAnimationCondList(const Any& rAny, sal_Int32 nToken)
+{
+ if (!rAny.hasValue())
+ return;
+
+ std::vector<Cond> aList;
+
+ bool bIsMainSeqChild = isMainSeqChild();
+
+ Sequence<Any> aCondSeq;
+ if (rAny >>= aCondSeq)
+ {
+ for (const auto& rCond : std::as_const(aCondSeq))
+ {
+ Cond aCond(rCond, bIsMainSeqChild);
+ if (aCond.isValid())
+ aList.push_back(aCond);
+ }
+ }
+ else
+ {
+ Cond aCond(rAny, bIsMainSeqChild);
+ if (aCond.isValid())
+ aList.push_back(aCond);
+ }
+
+ if (aList.size() > 0)
+ {
+ mpFS->startElementNS(XML_p, nToken);
+
+ for (const Cond& rCond : aList)
+ WriteAnimationCond(rCond);
+
+ mpFS->endElementNS(XML_p, nToken);
+ }
+}
+
+void PPTXAnimationExport::WriteAnimationCond(const Cond& rCond)
+{
+ if (rCond.mpEvent)
+ {
+ sal_Int32 nId = -1;
+ if (rCond.mxShape.is())
+ {
+ mpFS->startElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay(), XML_evt,
+ rCond.mpEvent);
+ WriteAnimationTarget(Any(rCond.mxShape));
+ mpFS->endElementNS(XML_p, XML_cond);
+ }
+ else if (rCond.mxNode.is() && (nId = GetAnimationNodeId(rCond.mxNode)) != -1)
+ {
+ mpFS->startElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay(), XML_evt,
+ rCond.mpEvent);
+ mpFS->singleElementNS(XML_p, XML_tn, XML_val, OString::number(nId));
+ mpFS->endElementNS(XML_p, XML_cond);
+ }
+ else
+ {
+ mpFS->singleElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay(), XML_evt,
+ rCond.mpEvent);
+ }
+ }
+ else
+ mpFS->singleElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay());
+}
+
+void PPTXAnimationExport::WriteAnimationNodeAnimate(sal_Int32 nXmlNodeType)
+{
+ const Reference<XAnimationNode>& rXNode = getCurrentNode();
+ Reference<XAnimate> rXAnimate(rXNode, UNO_QUERY);
+ if (!rXAnimate.is())
+ return;
+
+ const char* pCalcMode = nullptr;
+ const char* pValueType = nullptr;
+ bool bSimple = (nXmlNodeType != XML_anim);
+ bool bTo = true;
+
+ if (!bSimple)
+ {
+ switch (rXAnimate->getCalcMode())
+ {
+ case AnimationCalcMode::DISCRETE:
+ pCalcMode = "discrete";
+ break;
+ case AnimationCalcMode::LINEAR:
+ pCalcMode = "lin";
+ break;
+ }
+
+ switch (AnimationExporter::GetValueTypeForAttributeName(rXAnimate->getAttributeName()))
+ {
+ case AnimationValueType::STRING:
+ pValueType = "str";
+ break;
+ case AnimationValueType::NUMBER:
+ pValueType = "num";
+ break;
+ case AnimationValueType::COLOR:
+ pValueType = "clr";
+ break;
+ }
+ }
+
+ if (nXmlNodeType == XML_animMotion)
+ {
+ OUString aPath;
+ Reference<XAnimateMotion> xMotion(rXNode, UNO_QUERY);
+ if (xMotion.is())
+ {
+ xMotion->getPath() >>= aPath;
+ ::basegfx::B2DPolyPolygon aPolyPoly;
+ if (::basegfx::utils::importFromSvgD(aPolyPoly, aPath, true, nullptr))
+ aPath = ::basegfx::utils::exportToSvgD(aPolyPoly, false, false, true, true);
+ }
+
+ mpFS->startElementNS(XML_p, nXmlNodeType, XML_origin, "layout", XML_path, aPath);
+ }
+ else if (nXmlNodeType == XML_animRot)
+ {
+ // when const char* is nullptr, the attribute is completely omitted in the output
+ const char* pBy = nullptr;
+ const char* pFrom = nullptr;
+ const char* pTo = nullptr;
+ OString aBy, aFrom, aTo;
+
+ Reference<XAnimateTransform> xTransform(rXNode, UNO_QUERY);
+ if (xTransform.is())
+ {
+ double value;
+ if (xTransform->getBy() >>= value)
+ {
+ aBy = OString::number(static_cast<int>(value * PER_DEGREE));
+ pBy = aBy.getStr();
+ }
+
+ if (xTransform->getFrom() >>= value)
+ {
+ aFrom = OString::number(static_cast<int>(value * PER_DEGREE));
+ pFrom = aFrom.getStr();
+ }
+
+ if (xTransform->getTo() >>= value)
+ {
+ aTo = OString::number(static_cast<int>(value * PER_DEGREE));
+ pTo = aTo.getStr();
+ }
+ }
+
+ mpFS->startElementNS(XML_p, nXmlNodeType, XML_by, pBy, XML_from, pFrom, XML_to, pTo);
+ }
+ else if (nXmlNodeType == XML_animClr)
+ {
+ Reference<XAnimateColor> xColor(rXNode, UNO_QUERY);
+ const char* pColorSpace = "rgb";
+ const char* pDirection = nullptr;
+ if (xColor.is() && xColor->getColorInterpolation() == AnimationColorSpace::HSL)
+ {
+ // Note: from, to, by can still be specified in any supported format.
+ pColorSpace = "hsl";
+ pDirection = xColor->getDirection() ? "cw" : "ccw";
+ }
+ mpFS->startElementNS(XML_p, nXmlNodeType, XML_clrSpc, pColorSpace, XML_dir, pDirection,
+ XML_calcmode, pCalcMode, XML_valueType, pValueType);
+ }
+ else
+ {
+ OUString sFrom, sTo, sBy;
+ if (rXAnimate.is() && nXmlNodeType == XML_anim)
+ {
+ OUString sAttributeName = rXAnimate->getAttributeName();
+ Any aFrom
+ = AnimationExporter::convertAnimateValue(rXAnimate->getFrom(), sAttributeName);
+ aFrom >>= sFrom;
+ Any aTo = AnimationExporter::convertAnimateValue(rXAnimate->getTo(), sAttributeName);
+ aTo >>= sTo;
+ Any aBy = AnimationExporter::convertAnimateValue(rXAnimate->getBy(), sAttributeName);
+ aBy >>= sBy;
+ }
+
+ mpFS->startElementNS(XML_p, nXmlNodeType, XML_calcmode, pCalcMode, XML_valueType,
+ pValueType, XML_from, sax_fastparser::UseIf(sFrom, !sFrom.isEmpty()),
+ XML_to, sax_fastparser::UseIf(sTo, !sTo.isEmpty()), XML_by,
+ sax_fastparser::UseIf(sBy, !sBy.isEmpty()));
+ bTo = sTo.isEmpty() && sFrom.isEmpty() && sBy.isEmpty();
+ }
+
+ WriteAnimationNodeAnimateInside(bSimple, bTo);
+ mpFS->endElementNS(XML_p, nXmlNodeType);
+}
+
+void PPTXAnimationExport::WriteAnimationNodeAnimateInside(bool bSimple, bool bWriteTo)
+{
+ const Reference<XAnimationNode>& rXNode = getCurrentNode();
+ Reference<XAnimate> rXAnimate(rXNode, UNO_QUERY);
+ if (!rXAnimate.is())
+ return;
+
+ const char* pAdditive = nullptr;
+
+ if (!bSimple)
+ {
+ switch (rXAnimate->getAdditive())
+ {
+ case AnimationAdditiveMode::BASE:
+ pAdditive = "base";
+ break;
+ case AnimationAdditiveMode::SUM:
+ pAdditive = "sum";
+ break;
+ case AnimationAdditiveMode::REPLACE:
+ pAdditive = "repl";
+ break;
+ case AnimationAdditiveMode::MULTIPLY:
+ pAdditive = "mult";
+ break;
+ case AnimationAdditiveMode::NONE:
+ pAdditive = "none";
+ break;
+ }
+ }
+
+ mpFS->startElementNS(XML_p, XML_cBhvr, XML_additive, pAdditive);
+ WriteAnimationNodeCommonPropsStart();
+
+ Reference<XIterateContainer> xIterate(rXNode->getParent(), UNO_QUERY);
+ WriteAnimationTarget(xIterate.is() ? xIterate->getTarget() : rXAnimate->getTarget());
+
+ Reference<XAnimateTransform> xTransform(rXNode, UNO_QUERY);
+
+ // The attribute name of AnimateTransform is "Transform", we have to fix it.
+ OUString sNewAttr;
+ if (xTransform.is() && xTransform->getTransformType() == AnimationTransformType::ROTATE)
+ sNewAttr = "Rotate";
+
+ WriteAnimationAttributeName(mpFS, xTransform.is() ? sNewAttr : rXAnimate->getAttributeName());
+
+ mpFS->endElementNS(XML_p, XML_cBhvr);
+ WriteAnimateValues(mpFS, rXAnimate);
+
+ Reference<XAnimateColor> xColor(rXNode, UNO_QUERY);
+
+ if (xColor.is())
+ {
+ WriteAnimateColorColor(mpFS, xColor->getBy(), XML_by);
+ WriteAnimateColorColor(mpFS, xColor->getFrom(), XML_from);
+ WriteAnimateColorColor(mpFS, xColor->getTo(), XML_to);
+ }
+ else if (xTransform.is() && xTransform->getTransformType() == AnimationTransformType::SCALE)
+ {
+ WriteAnimationProperty(mpFS, rXAnimate->getBy(), XML_by);
+ WriteAnimationProperty(mpFS, rXAnimate->getFrom(), XML_from);
+ WriteAnimationProperty(mpFS, rXAnimate->getTo(), XML_to);
+ }
+ else if (bWriteTo)
+ WriteAnimateTo(mpFS, rXAnimate->getTo(), rXAnimate->getAttributeName());
+}
+
+void PPTXAnimationExport::WriteAnimationNodeCommonPropsStart()
+{
+ const Reference<XAnimationNode>& rXNode = getCurrentNode();
+ std::optional<OString> sDuration;
+ std::optional<OString> sRepeatCount;
+ const char* pRestart = nullptr;
+ const char* pNodeType = nullptr;
+ const char* pPresetClass = nullptr;
+ const char* pFill = nullptr;
+ double fDuration = 0;
+ double fRepeatCount = 0;
+ Any aAny;
+ assert(mpContext);
+
+ aAny = rXNode->getDuration();
+ if (aAny.hasValue())
+ {
+ Timing eTiming;
+
+ if (aAny >>= eTiming)
+ {
+ if (eTiming == Timing_INDEFINITE)
+ sDuration = "indefinite";
+ }
+ else
+ aAny >>= fDuration;
+ }
+
+ pRestart = convertAnimationRestart(rXNode->getRestart());
+
+ sal_Int16 nType = mpContext->getEffectNodeType();
+ if (nType != -1)
+ {
+ pNodeType = convertEffectNodeType(nType);
+ if (nType == EffectNodeType::TIMING_ROOT)
+ {
+ if (!sDuration)
+ sDuration = "indefinite";
+ if (!pRestart)
+ pRestart = "never";
+ }
+ else if (nType == EffectNodeType::MAIN_SEQUENCE)
+ {
+ sDuration = "indefinite";
+ }
+ }
+
+ if (fDuration != 0)
+ sDuration = OString::number(static_cast<sal_Int32>(fDuration * 1000.0));
+
+ sal_uInt32 nPresetClass = mpContext->getEffectPresetClass();
+ if (nPresetClass != DFF_ANIM_PRESS_CLASS_USER_DEFINED)
+ pPresetClass = convertEffectPresetClass(nPresetClass);
+
+ sal_uInt32 nPresetId = 0;
+ bool bPresetId = false;
+ const OUString& rPresetId = mpContext->getEffectPresetId();
+ if (rPresetId.getLength() > 0)
+ {
+ nPresetId = AnimationExporter::GetPresetID(rPresetId, nPresetClass, bPresetId);
+ bPresetId = true;
+ }
+
+ sal_uInt32 nPresetSubType = 0;
+ bool bPresetSubType = false;
+ const OUString& sPresetSubType = mpContext->getEffectPresetSubType();
+ if (sPresetSubType.getLength() > 0)
+ {
+ nPresetSubType
+ = AnimationExporter::TranslatePresetSubType(nPresetClass, nPresetId, sPresetSubType);
+ bPresetSubType = true;
+ }
+
+ if (nType != EffectNodeType::TIMING_ROOT && nType != EffectNodeType::MAIN_SEQUENCE)
+ {
+ // it doesn't seem to work right on root and mainseq nodes
+ sal_Int16 nFill = AnimationExporter::GetFillMode(rXNode, AnimationFill::AUTO);
+ pFill = convertAnimationFill(nFill);
+ }
+
+ bool bAutoReverse = rXNode->getAutoReverse();
+
+ aAny = rXNode->getRepeatCount();
+ if (aAny.hasValue())
+ {
+ Timing eTiming;
+
+ if (aAny >>= eTiming)
+ {
+ if (eTiming == Timing_INDEFINITE)
+ sRepeatCount = "indefinite";
+ }
+ else
+ aAny >>= fRepeatCount;
+ }
+
+ if (fRepeatCount != 0)
+ sRepeatCount = OString::number(static_cast<sal_Int32>(fRepeatCount * 1000.0));
+
+ mpFS->startElementNS(
+ XML_p, XML_cTn, XML_id, OString::number(GetNextAnimationNodeId(rXNode)), XML_dur, sDuration,
+ XML_autoRev, sax_fastparser::UseIf("1", bAutoReverse), XML_restart, pRestart, XML_nodeType,
+ pNodeType, XML_fill, pFill, XML_presetClass, pPresetClass, XML_presetID,
+ sax_fastparser::UseIf(OString::number(nPresetId), bPresetId), XML_presetSubtype,
+ sax_fastparser::UseIf(OString::number(nPresetSubType), bPresetSubType), XML_repeatCount,
+ sRepeatCount);
+
+ WriteAnimationCondList(mpContext->getCondition(true), XML_stCondLst);
+ WriteAnimationCondList(mpContext->getCondition(false), XML_endCondLst);
+
+ if (rXNode->getType() == AnimationNodeType::ITERATE)
+ {
+ Reference<XIterateContainer> xIterate(rXNode, UNO_QUERY);
+ if (xIterate.is())
+ {
+ const char* sType = convertTextAnimationType(xIterate->getIterateType());
+
+ mpFS->startElementNS(XML_p, XML_iterate, XML_type, sType);
+ mpFS->singleElementNS(XML_p, XML_tmAbs, XML_val,
+ OString::number(xIterate->getIterateInterval() * 1000));
+ mpFS->endElementNS(XML_p, XML_iterate);
+ }
+ }
+
+ const std::vector<NodeContextPtr>& aChildNodes = mpContext->getChildNodes();
+ if (!aChildNodes.empty())
+ {
+ mpFS->startElementNS(XML_p, XML_childTnLst);
+ for (const NodeContextPtr& pChildContext : aChildNodes)
+ {
+ if (pChildContext->isValid())
+ WriteAnimationNode(pChildContext);
+ }
+ mpFS->endElementNS(XML_p, XML_childTnLst);
+ }
+ mpFS->endElementNS(XML_p, XML_cTn);
+}
+
+void PPTXAnimationExport::WriteAnimationNodeSeq()
+{
+ SAL_INFO("sd.eppt", "write animation node SEQ");
+
+ mpFS->startElementNS(XML_p, XML_seq);
+
+ WriteAnimationNodeCommonPropsStart();
+
+ WriteAnimationCondListForSeq(mpFS, XML_prevCondLst);
+ WriteAnimationCondListForSeq(mpFS, XML_nextCondLst);
+
+ mpFS->endElementNS(XML_p, XML_seq);
+}
+
+void PPTXAnimationExport::WriteAnimationNodeEffect()
+{
+ SAL_INFO("sd.eppt", "write animation node FILTER");
+ Reference<XTransitionFilter> xFilter(getCurrentNode(), UNO_QUERY);
+ if (xFilter.is())
+ {
+ const char* pFilter = ::ppt::AnimationExporter::FindTransitionName(
+ xFilter->getTransition(), xFilter->getSubtype(), xFilter->getDirection());
+ const char* pMode = xFilter->getMode() ? "in" : "out";
+ mpFS->startElementNS(XML_p, XML_animEffect, XML_filter, pFilter, XML_transition, pMode);
+
+ WriteAnimationNodeAnimateInside(false);
+
+ mpFS->endElementNS(XML_p, XML_animEffect);
+ }
+}
+
+void PPTXAnimationExport::WriteAnimationNodeCommand()
+{
+ SAL_INFO("sd.eppt", "write animation node COMMAND");
+ Reference<XCommand> xCommand(getCurrentNode(), UNO_QUERY);
+ if (!xCommand.is())
+ return;
+
+ const char* pType = "call";
+ OString aCommand;
+ switch (xCommand->getCommand())
+ {
+ case EffectCommands::VERB:
+ pType = "verb";
+ aCommand = "1"; /* FIXME hardcoded viewing */
+ break;
+ case EffectCommands::PLAY:
+ {
+ aCommand = "play";
+ uno::Sequence<beans::NamedValue> aParamSeq;
+ xCommand->getParameter() >>= aParamSeq;
+ comphelper::SequenceAsHashMap aMap(aParamSeq);
+ auto it = aMap.find("MediaTime");
+ if (it != aMap.end())
+ {
+ double fMediaTime = 0;
+ it->second >>= fMediaTime;
+ // PowerPoint represents 0 as 0.0, so just use a single decimal.
+ OString aMediaTime
+ = rtl::math::doubleToString(fMediaTime, rtl_math_StringFormat_F, 1, '.');
+ aCommand += "From(" + aMediaTime + ")";
+ }
+ break;
+ }
+ case EffectCommands::TOGGLEPAUSE:
+ aCommand = "togglePause";
+ break;
+ case EffectCommands::STOP:
+ aCommand = "stop";
+ break;
+ default:
+ SAL_WARN("sd.eppt", "unknown command: " << xCommand->getCommand());
+ break;
+ }
+
+ mpFS->startElementNS(XML_p, XML_cmd, XML_type, pType, XML_cmd, aCommand.getStr());
+
+ WriteAnimationNodeAnimateInside(false);
+ mpFS->startElementNS(XML_p, XML_cBhvr);
+ WriteAnimationNodeCommonPropsStart();
+ WriteAnimationTarget(xCommand->getTarget());
+ mpFS->endElementNS(XML_p, XML_cBhvr);
+
+ mpFS->endElementNS(XML_p, XML_cmd);
+}
+
+void PPTXAnimationExport::WriteAnimationNodeAudio()
+{
+ SAL_INFO("sd.eppt", "write animation node audio");
+ Reference<XAudio> xAudio(getCurrentNode(), UNO_QUERY);
+
+ OUString sUrl;
+ uno::Reference<drawing::XShape> xShape;
+ OUString sRelId;
+ OUString sName;
+
+ if (!xAudio.is())
+ {
+ return;
+ }
+
+ bool bValid = false;
+ if ((xAudio->getSource() >>= sUrl) && !sUrl.isEmpty() && IsAudioURL(sUrl))
+ {
+ bValid = true;
+ }
+
+ bool bVideo = false;
+ if (!bValid)
+ {
+ if (xAudio->getSource() >>= xShape)
+ {
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ bool bHasMediaURL = xShapeProps->getPropertySetInfo()->hasPropertyByName("MediaURL");
+ if (bHasMediaURL && (xShapeProps->getPropertyValue("MediaURL") >>= sUrl))
+ {
+ bVideo = IsVideoURL(sUrl);
+ bValid = IsAudioURL(sUrl) || bVideo;
+ }
+ }
+ }
+
+ if (!bValid)
+ return;
+
+ if (!xShape.is())
+ {
+ mrPowerPointExport.embedEffectAudio(mpFS, sUrl, sRelId, sName);
+ }
+
+ if (bVideo)
+ {
+ mpFS->startElementNS(XML_p, XML_video);
+ mpFS->startElementNS(XML_p, XML_cMediaNode);
+ }
+ else
+ {
+ bool bNarration = xAudio->getNarration();
+ mpFS->startElementNS(XML_p, XML_audio, XML_isNarration, bNarration ? "1" : "0");
+ bool bHideDuringShow = xAudio->getHideDuringShow();
+ mpFS->startElementNS(XML_p, XML_cMediaNode, XML_showWhenStopped,
+ bHideDuringShow ? "0" : "1");
+ }
+
+ animations::Timing eTiming{};
+ bool bLooping
+ = (xAudio->getRepeatCount() >>= eTiming) && eTiming == animations::Timing_INDEFINITE;
+ if (bVideo && bLooping)
+ {
+ mpFS->startElementNS(XML_p, XML_cTn, XML_repeatCount, "indefinite");
+ }
+ else
+ {
+ mpFS->startElementNS(XML_p, XML_cTn);
+ }
+ WriteAnimationCondList(mpContext->getCondition(true), XML_stCondLst);
+ WriteAnimationCondList(mpContext->getCondition(false), XML_endCondLst);
+ mpFS->endElementNS(XML_p, XML_cTn);
+
+ mpFS->startElementNS(XML_p, XML_tgtEl);
+ if (xShape.is())
+ {
+ sal_Int32 nShapeID = mrPowerPointExport.GetShapeID(xShape);
+ mpFS->singleElementNS(XML_p, XML_spTgt, XML_spid, OString::number(nShapeID));
+ }
+ else
+ {
+ mpFS->singleElementNS(XML_p, XML_sndTgt, FSNS(XML_r, XML_embed),
+ sax_fastparser::UseIf(sRelId, !sRelId.isEmpty()), XML_name,
+ sax_fastparser::UseIf(sName, !sUrl.isEmpty()));
+ }
+ mpFS->endElementNS(XML_p, XML_tgtEl);
+
+ mpFS->endElementNS(XML_p, XML_cMediaNode);
+ if (bVideo)
+ {
+ mpFS->endElementNS(XML_p, XML_video);
+ }
+ else
+ {
+ mpFS->endElementNS(XML_p, XML_audio);
+ }
+}
+
+void PPTXAnimationExport::WriteAnimationNode(const NodeContextPtr& pContext)
+{
+ const NodeContext* pSavedContext = mpContext;
+ mpContext = pContext.get();
+
+ const Reference<XAnimationNode>& rXNode = getCurrentNode();
+
+ SAL_INFO("sd.eppt", "export node type: " << rXNode->getType());
+ sal_Int32 xmlNodeType = extractNodeType(rXNode);
+
+ switch (xmlNodeType)
+ {
+ case XML_par:
+ mpFS->startElementNS(XML_p, xmlNodeType);
+ WriteAnimationNodeCommonPropsStart();
+ mpFS->endElementNS(XML_p, xmlNodeType);
+ break;
+ case XML_seq:
+ WriteAnimationNodeSeq();
+ break;
+ case XML_animScale:
+ case XML_animRot:
+ case XML_anim:
+ case XML_animMotion:
+ case XML_animClr:
+ case XML_set:
+ WriteAnimationNodeAnimate(xmlNodeType);
+ break;
+ case XML_animEffect:
+ WriteAnimationNodeEffect();
+ break;
+ case XML_cmd:
+ WriteAnimationNodeCommand();
+ break;
+ case XML_audio:
+ WriteAnimationNodeAudio();
+ break;
+ default:
+ SAL_WARN("sd.eppt", "export ooxml node type: " << xmlNodeType);
+ break;
+ }
+
+ mpContext = pSavedContext;
+}
+
+void PPTXAnimationExport::WriteAnimations(const Reference<XDrawPage>& rXDrawPage)
+{
+ Reference<XAnimationNodeSupplier> xNodeSupplier(rXDrawPage, UNO_QUERY);
+ if (!xNodeSupplier.is())
+ return;
+
+ const Reference<XAnimationNode> xNode(xNodeSupplier->getAnimationNode());
+ if (!xNode.is())
+ return;
+
+ Reference<XEnumerationAccess> xEnumerationAccess(xNode, UNO_QUERY);
+ if (!xEnumerationAccess.is())
+ return;
+
+ Reference<XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
+ if (!(xEnumeration.is() && xEnumeration->hasMoreElements()))
+ return;
+
+ auto pNodeContext = std::make_unique<NodeContext>(xNode, false, false);
+ if (pNodeContext->isValid())
+ {
+ mpFS->startElementNS(XML_p, XML_timing);
+ mpFS->startElementNS(XML_p, XML_tnLst);
+
+ WriteAnimationNode(pNodeContext);
+
+ mpFS->endElementNS(XML_p, XML_tnLst);
+ mpFS->endElementNS(XML_p, XML_timing);
+ }
+}
+
+sal_Int32 PPTXAnimationExport::GetNextAnimationNodeId(const Reference<XAnimationNode>& xNode)
+{
+ sal_Int32 nId = mrPowerPointExport.GetNextAnimationNodeID();
+ maAnimationNodeIdMap[xNode] = nId;
+ return nId;
+}
+
+sal_Int32 PPTXAnimationExport::GetAnimationNodeId(const Reference<XAnimationNode>& xNode)
+{
+ sal_Int32 nId = -1;
+ const auto& aIter = maAnimationNodeIdMap.find(xNode);
+ if (aIter != maAnimationNodeIdMap.end())
+ {
+ nId = aIter->second;
+ }
+ return nId;
+}
+
+NodeContext::NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild,
+ bool bIsIterateChild)
+ : mxNode(xNode)
+ , mbMainSeqChild(bMainSeqChild)
+ , mbValid(true)
+ , mnEffectNodeType(-1)
+ , mnEffectPresetClass(DFF_ANIM_PRESS_CLASS_USER_DEFINED)
+{
+ assert(xNode.is());
+
+ initUserData();
+
+ initValid(initChildNodes(), bIsIterateChild);
+}
+
+void NodeContext::initUserData()
+{
+ assert(mxNode.is());
+
+ Sequence<NamedValue> aUserData = mxNode->getUserData();
+ const Any* aIndexedData[DFF_ANIM_PROPERTY_ID_COUNT];
+ AnimationExporter::GetUserData(aUserData, aIndexedData, sizeof(aIndexedData));
+
+ const Any* pAny = aIndexedData[DFF_ANIM_NODE_TYPE];
+ if (pAny)
+ *pAny >>= mnEffectNodeType;
+
+ pAny = aIndexedData[DFF_ANIM_PRESET_CLASS];
+ if (pAny)
+ *pAny >>= mnEffectPresetClass;
+
+ pAny = aIndexedData[DFF_ANIM_PRESET_ID];
+ if (pAny)
+ *pAny >>= msEffectPresetId;
+
+ pAny = aIndexedData[DFF_ANIM_PRESET_SUB_TYPE];
+ if (pAny)
+ *pAny >>= msEffectPresetSubType;
+}
+
+void NodeContext::initValid(bool bHasValidChild, bool bIsIterateChild)
+{
+ sal_Int16 nType = mxNode->getType();
+
+ if (nType == AnimationNodeType::ITERATE)
+ {
+ Reference<XIterateContainer> xIterate(mxNode, UNO_QUERY);
+ mbValid = xIterate.is() && (bIsIterateChild || isValidTarget(xIterate->getTarget()))
+ && !maChildNodes.empty();
+ }
+ else if (nType == AnimationNodeType::COMMAND)
+ {
+ Reference<XCommand> xCommand(mxNode, UNO_QUERY);
+ mbValid = xCommand.is() && (bIsIterateChild || isValidTarget(xCommand->getTarget()));
+ }
+ else if (nType == AnimationNodeType::PAR || nType == AnimationNodeType::SEQ)
+ {
+ mbValid = bHasValidChild;
+ }
+ else if (nType == AnimationNodeType::AUDIO)
+ {
+ Reference<XAudio> xAudio(mxNode, UNO_QUERY);
+ OUString sURL;
+ uno::Reference<drawing::XShape> xShape;
+ mbValid = false;
+ if (xAudio.is())
+ {
+ if (xAudio->getSource() >>= sURL)
+ {
+ mbValid = IsAudioURL(sURL);
+ }
+ else if (xAudio->getSource() >>= xShape)
+ {
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ bool bHasMediaURL
+ = xShapeProps->getPropertySetInfo()->hasPropertyByName("MediaURL");
+ if (bHasMediaURL && (xShapeProps->getPropertyValue("MediaURL") >>= sURL))
+ {
+ mbValid = IsAudioURL(sURL) || IsVideoURL(sURL);
+ }
+ }
+ }
+ }
+ else
+ {
+ Reference<XAnimate> xAnimate(mxNode, UNO_QUERY);
+ mbValid = xAnimate.is() && (bIsIterateChild || isValidTarget(xAnimate->getTarget()));
+ }
+}
+
+bool NodeContext::initChildNodes()
+{
+ bool bValid = false;
+ Reference<XEnumerationAccess> xEnumerationAccess(mxNode, UNO_QUERY);
+ if (xEnumerationAccess.is())
+ {
+ Reference<XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
+ bool bIsMainSeq = mnEffectNodeType == EffectNodeType::MAIN_SEQUENCE;
+ bool bIsIterateChild = mxNode->getType() == AnimationNodeType::ITERATE;
+ if (xEnumeration.is())
+ {
+ while (xEnumeration->hasMoreElements())
+ {
+ Reference<XAnimationNode> xChildNode(xEnumeration->nextElement(), UNO_QUERY);
+ if (xChildNode.is())
+ {
+ auto pChildContext
+ = std::make_unique<NodeContext>(xChildNode, bIsMainSeq, bIsIterateChild);
+ if (pChildContext->isValid())
+ bValid = true;
+ maChildNodes.push_back(std::move(pChildContext));
+ }
+ }
+ }
+ }
+ return bValid;
+}
+
+Any NodeContext::getCondition(bool bBegin) const
+{
+ const bool bParent
+ = (mnEffectNodeType != EffectNodeType::INTERACTIVE_SEQUENCE || maChildNodes.empty());
+ const Reference<XAnimationNode>& rNode = bParent ? mxNode : maChildNodes[0]->getNode();
+
+ return bBegin ? rNode->getBegin() : rNode->getEnd();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-animations.hxx b/sd/source/filter/eppt/pptx-animations.hxx
new file mode 100644
index 000000000..24654abb8
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-animations.hxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <sax/fshelper.hxx>
+
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+
+#include "epptooxml.hxx"
+
+namespace oox::core
+{
+void WriteAnimations(const ::sax_fastparser::FSHelperPtr& pFS,
+ const css::uno::Reference<css::drawing::XDrawPage>& rXDrawPage,
+ PowerPointExport& rExport);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-epptbase.cxx b/sd/source/filter/eppt/pptx-epptbase.cxx
new file mode 100644
index 000000000..690738996
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-epptbase.cxx
@@ -0,0 +1,1000 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "epptbase.hxx"
+#include "epptdef.hxx"
+#include "../ppt/pptanimations.hxx"
+
+#include <o3tl/any.hxx>
+#include <vcl/outdev.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/strbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/UnitConversion.hxx>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XMasterPageTarget.hpp>
+#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPages.hpp>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <com/sun/star/awt/FontFamily.hpp>
+#include <com/sun/star/awt/FontPitch.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/presentation/XPresentationPage.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+
+
+using namespace com::sun::star;
+
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::awt::FontFamily;
+using namespace ::com::sun::star::awt::FontPitch;
+using namespace ::com::sun::star::presentation;
+
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+using ::com::sun::star::drawing::XMasterPageTarget;
+using ::com::sun::star::drawing::XDrawPage;
+using ::com::sun::star::frame::XModel;
+using ::com::sun::star::style::XStyleFamiliesSupplier;
+using ::com::sun::star::style::XStyle;
+using ::com::sun::star::task::XStatusIndicator;
+using ::com::sun::star::text::XSimpleText;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+
+PHLayout const pPHLayout[] =
+{
+ { EppLayout::TITLESLIDE, { 0x0d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x10, true, true, false },
+ { EppLayout::TITLEANDBODYSLIDE, { 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TITLEANDBODYSLIDE, { 0x0d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x14, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x0e, true, true, true },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x0e, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x14, 0x0d, 0x0e, true, true, false },
+ { EppLayout::BLANKSLIDE, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x0e, false, false, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x0e, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x16, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x14, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x14, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TITLEANDBODYSLIDE, { 0x0d, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x15, 0x0d, 0x0e, true, false, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x16, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x16, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x0e, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TITLEANDBODYSLIDE, { 0x0d, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, false, false },
+ { EppLayout::RIGHTCOLUMN2ROWS, { 0x0d, 0x0e, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x13, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOROWSANDTITLE, { 0x0d, 0x13, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::LEFTCOLUMN2ROWS, { 0x0d, 0x13, 0x13, 0x0e, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TOPROW2COLUMN, { 0x0d, 0x13, 0x13, 0x0e, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOROWSANDTITLE, { 0x0d, 0x0e, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::FOUROBJECTS, { 0x0d, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, false, false },
+ { EppLayout::ONLYTITLE, { 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x0e, true, false, false },
+ { EppLayout::BLANKSLIDE, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x0e, false, false, false },
+ { EppLayout::TITLERIGHT2BODIESLEFT, { 0x11, 0x12, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x14, 0x11, 0x12, true, true, false },
+ { EppLayout::TITLERIGHTBODYLEFT, { 0x11, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x11, 0x12, true, true, false },
+ { EppLayout::TITLEANDBODYSLIDE, { 0x0d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x12, true, true, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x16, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x16, 0x0d, 0x12, true, true, false }
+};
+
+PPTWriterBase::PPTWriterBase()
+ : mbStatusIndicator(false)
+ , mbPresObj(false)
+ , mbEmptyPresObj(false)
+ , mbIsBackgroundDark(false)
+ , mnAngle(0)
+ , mnPages(0)
+ , mnMasterPages(0)
+ , maFraction(1, 576)
+ , maMapModeSrc(MapUnit::Map100thMM)
+ , maMapModeDest(MapUnit::MapInch, Point(), maFraction, maFraction)
+ , meLatestPageType(NORMAL)
+ , mpStyleSheet(nullptr)
+{
+ SAL_INFO("sd.eppt", "PPTWriterBase::PPTWriterBase()");
+}
+
+PPTWriterBase::PPTWriterBase( const Reference< XModel > & rXModel,
+ const Reference< XStatusIndicator > & rXStatInd )
+ : mXModel(rXModel)
+ , mXStatusIndicator(rXStatInd)
+ , mbStatusIndicator(false)
+ , mbPresObj(false)
+ , mbEmptyPresObj(false)
+ , mbIsBackgroundDark(false)
+ , mnAngle(0)
+ , mnPages(0)
+ , mnMasterPages(0)
+ , maFraction(1, 576)
+ , maMapModeSrc(MapUnit::Map100thMM)
+ , maMapModeDest(MapUnit::MapInch, Point(), maFraction, maFraction)
+ , meLatestPageType (NORMAL)
+ , mpStyleSheet(nullptr)
+{
+}
+
+PPTWriterBase::~PPTWriterBase()
+{
+ // Possibly unnecessary sanity check for mXStatusIndicator.is().
+ // In 3.3 we had a bug report of a crash where it was null,
+ // https://bugzilla.novell.com/show_bug.cgi?id=694119 (non-public,
+ // bug report, sorry).
+ if ( mbStatusIndicator && mXStatusIndicator.is() )
+ mXStatusIndicator->end();
+}
+
+void PPTWriterBase::exportPPT( const std::vector< css::beans::PropertyValue >& rMediaData )
+{
+ if ( !InitSOIface() )
+ return;
+
+ FontCollectionEntry aDefaultFontDesc( "Times New Roman",
+ ROMAN,
+ awt::FontPitch::VARIABLE,
+ RTL_TEXTENCODING_MS_1252 );
+ maFontCollection.GetId( aDefaultFontDesc ); // default is always times new roman
+
+ if ( !GetPageByIndex( 0, NOTICE ) )
+ return;
+
+ sal_Int32 nWidth = 21000;
+ if ( ImplGetPropertyValue( mXPagePropSet, "Width" ) )
+ mAny >>= nWidth;
+ sal_Int32 nHeight = 29700;
+ if ( ImplGetPropertyValue( mXPagePropSet, "Height" ) )
+ mAny >>= nHeight;
+
+ maNotesPageSize = MapSize( awt::Size( nWidth, nHeight ) );
+
+ if ( !GetPageByIndex( 0, MASTER ) )
+ return;
+
+ nWidth = 28000;
+ if ( ImplGetPropertyValue( mXPagePropSet, "Width" ) )
+ mAny >>= nWidth;
+ nHeight = 21000;
+ if ( ImplGetPropertyValue( mXPagePropSet, "Height" ) )
+ mAny >>= nHeight;
+ maDestPageSize = MapSize( awt::Size( nWidth, nHeight ) );
+ maPageSize = awt::Size(nWidth, nHeight);
+
+ SAL_INFO("sd.eppt", "call exportDocumentPre()");
+ exportPPTPre(rMediaData);
+
+ if ( !GetStyleSheets() )
+ return;
+
+ if ( !ImplCreateDocument() )
+ return;
+
+ sal_uInt32 i;
+
+ for ( i = 0; i < mnMasterPages; i++ )
+ {
+ if ( !CreateSlideMaster( i ) )
+ return;
+ }
+ if ( !CreateMainNotes() )
+ return;
+
+ for ( i = 0; i < mnPages; i++ )
+ {
+ SAL_INFO("sd.eppt", "call ImplCreateSlide( " << i << " )");
+ if ( !CreateSlide( i ) )
+ return;
+ }
+
+ for ( i = 0; i < mnPages; i++ )
+ {
+ if ( !CreateNotes( i ) )
+ return;
+ }
+
+ SAL_INFO("sd.eppt", "call exportDocumentPost()");
+ exportPPTPost();
+}
+
+bool PPTWriterBase::InitSOIface()
+{
+ while( true )
+ {
+ mXDrawPagesSupplier.set( mXModel, UNO_QUERY );
+ if ( !mXDrawPagesSupplier.is() )
+ break;
+
+ mXMasterPagesSupplier.set( mXModel, UNO_QUERY );
+ if ( !mXMasterPagesSupplier.is() )
+ break;
+ mXDrawPages = mXMasterPagesSupplier->getMasterPages();
+ if ( !mXDrawPages.is() )
+ break;
+ mnMasterPages = mXDrawPages->getCount();
+ mXDrawPages = mXDrawPagesSupplier->getDrawPages();
+ if( !mXDrawPages.is() )
+ break;
+ mnPages = mXDrawPages->getCount();
+ if ( !GetPageByIndex( 0, NORMAL ) )
+ break;
+
+ return true;
+ }
+ return false;
+}
+
+bool PPTWriterBase::GetPageByIndex( sal_uInt32 nIndex, PageType ePageType )
+{
+ while( true )
+ {
+ if ( ePageType != meLatestPageType )
+ {
+ switch( ePageType )
+ {
+ case NORMAL :
+ case NOTICE :
+ {
+ mXDrawPages = mXDrawPagesSupplier->getDrawPages();
+ if( !mXDrawPages.is() )
+ return false;
+ }
+ break;
+
+ case MASTER :
+ {
+ mXDrawPages = mXMasterPagesSupplier->getMasterPages();
+ if( !mXDrawPages.is() )
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ meLatestPageType = ePageType;
+ }
+ Any aAny( mXDrawPages->getByIndex( nIndex ) );
+ aAny >>= mXDrawPage;
+ if ( !mXDrawPage.is() )
+ break;
+ if ( ePageType == NOTICE )
+ {
+ Reference< XPresentationPage > aXPresentationPage( mXDrawPage, UNO_QUERY );
+ if ( !aXPresentationPage.is() )
+ break;
+ mXDrawPage = aXPresentationPage->getNotesPage();
+ if ( !mXDrawPage.is() )
+ break;
+ }
+ mXPagePropSet.set( mXDrawPage, UNO_QUERY );
+ if ( !mXPagePropSet.is() )
+ break;
+
+ if (GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark" ) )
+ aAny >>= mbIsBackgroundDark;
+
+ mXShapes = mXDrawPage;
+ if ( !mXShapes.is() )
+ break;
+
+ /* try to get the "real" background PropertySet. If the normal page is not supporting this property, it is
+ taken the property from the master */
+ bool bHasBackground = GetPropertyValue( aAny, mXPagePropSet, "Background", true );
+ if ( bHasBackground )
+ bHasBackground = ( aAny >>= mXBackgroundPropSet );
+ if ( !bHasBackground )
+ {
+ Reference< XMasterPageTarget > aXMasterPageTarget( mXDrawPage, UNO_QUERY );
+ if ( aXMasterPageTarget.is() )
+ {
+ Reference< XDrawPage > aXMasterDrawPage = aXMasterPageTarget->getMasterPage();
+ if ( aXMasterDrawPage.is() )
+ {
+ Reference< XPropertySet > aXMasterPagePropSet;
+ aXMasterPagePropSet.set( aXMasterDrawPage, UNO_QUERY );
+ if ( aXMasterPagePropSet.is() )
+ {
+ bool bBackground = GetPropertyValue( aAny, aXMasterPagePropSet, "Background" );
+ if ( bBackground )
+ {
+ aAny >>= mXBackgroundPropSet;
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool PPTWriterBase::CreateSlide( sal_uInt32 nPageNum )
+{
+ Any aAny;
+
+ if ( !GetPageByIndex( nPageNum, NORMAL ) )
+ return false;
+
+ sal_uInt32 nMasterNum = GetMasterIndex( NORMAL );
+ SetCurrentStyleSheet( nMasterNum );
+
+ Reference< XPropertySet > aXBackgroundPropSet;
+ bool bHasBackground = GetPropertyValue( aAny, mXPagePropSet, "Background" );
+ if ( bHasBackground )
+ bHasBackground = ( aAny >>= aXBackgroundPropSet );
+
+ sal_uInt16 nMode = 7; // Bit 1: Follow master objects, Bit 2: Follow master scheme, Bit 3: Follow master background
+ if ( bHasBackground )
+ nMode &=~4;
+
+/* sj: Don't know what's IsBackgroundVisible for, have to ask cl
+ if ( GetPropertyValue( aAny, mXPagePropSet, OUString( "IsBackgroundVisible" ) ) )
+ {
+ bool bBackgroundVisible;
+ if ( aAny >>= bBackgroundVisible )
+ {
+ if ( bBackgroundVisible )
+ nMode &= ~4;
+ }
+ }
+*/
+ if ( GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundObjectsVisible" ) )
+ {
+ bool bBackgroundObjectsVisible = false;
+ if ( aAny >>= bBackgroundObjectsVisible )
+ {
+ if ( !bBackgroundObjectsVisible )
+ nMode &= ~1;
+ }
+ }
+
+ ImplWriteSlide( nPageNum, nMasterNum, nMode, bHasBackground, aXBackgroundPropSet );
+
+ return true;
+};
+
+bool PPTWriterBase::CreateNotes( sal_uInt32 nPageNum )
+{
+ if ( !GetPageByIndex( nPageNum, NOTICE ) )
+ return false;
+ SetCurrentStyleSheet( GetMasterIndex( NORMAL ) );
+
+ ImplWriteNotes( nPageNum );
+
+ return true;
+};
+
+bool PPTWriterBase::CreateSlideMaster( sal_uInt32 nPageNum )
+{
+ if ( !GetPageByIndex( nPageNum, MASTER ) )
+ return false;
+ SetCurrentStyleSheet( nPageNum );
+
+ css::uno::Reference< css::beans::XPropertySet > aXBackgroundPropSet;
+ if (ImplGetPropertyValue(mXPagePropSet, "Background")) // load background shape
+ mAny >>= aXBackgroundPropSet;
+
+ ImplWriteSlideMaster( nPageNum, aXBackgroundPropSet );
+
+ return true;
+};
+
+sal_Int32 PPTWriterBase::GetLayoutOffset( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet )
+{
+ css::uno::Any aAny;
+ sal_Int32 nLayout = 20;
+ if ( GetPropertyValue( aAny, rXPropSet, "Layout", true ) )
+ aAny >>= nLayout;
+
+ SAL_INFO("sd.eppt", "GetLayoutOffset " << nLayout);
+
+ return nLayout;
+}
+
+sal_Int32 PPTWriterBase::GetLayoutOffsetFixed( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet )
+{
+ sal_Int32 nLayout = GetLayoutOffset( rXPropSet );
+
+ if ( ( nLayout >= 21 ) && ( nLayout <= 26 ) ) // NOTES _> HANDOUT6
+ nLayout = 20;
+ if ( ( nLayout >= 27 ) && ( nLayout <= 30 ) ) // VERTICAL LAYOUT
+ nLayout -= 6;
+ else if ( nLayout > 30 )
+ nLayout = 20;
+
+ return nLayout;
+}
+
+PHLayout const & PPTWriterBase::GetLayout( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet )
+{
+ return pPHLayout[ GetLayoutOffsetFixed( rXPropSet ) ];
+}
+
+PHLayout const & PPTWriterBase::GetLayout( sal_Int32 nOffset )
+{
+ if( nOffset >= 0 && nOffset < EPP_LAYOUT_SIZE )
+ return pPHLayout[ nOffset ];
+
+ SAL_INFO("sd.eppt", "asked " << nOffset << " for layout outside of 0, " << EPP_LAYOUT_SIZE << " array scope");
+
+ return pPHLayout[ 0 ];
+}
+
+sal_uInt32 PPTWriterBase::GetMasterIndex( PageType ePageType )
+{
+ sal_uInt32 nRetValue = 0;
+ css::uno::Reference< css::drawing::XMasterPageTarget >aXMasterPageTarget( mXDrawPage, css::uno::UNO_QUERY );
+
+ if ( aXMasterPageTarget.is() )
+ {
+ css::uno::Reference< css::drawing::XDrawPage >aXDrawPage = aXMasterPageTarget->getMasterPage();
+ if ( aXDrawPage.is() )
+ {
+ css::uno::Reference< css::beans::XPropertySet > aXPropertySet( aXDrawPage, css::uno::UNO_QUERY );
+ if ( aXPropertySet.is() )
+ {
+ if ( ImplGetPropertyValue( aXPropertySet, "Number" ) )
+ nRetValue |= *o3tl::doAccess<sal_Int16>(mAny);
+ if ( nRetValue & 0xffff ) // avoid overflow
+ nRetValue--;
+ }
+ }
+ }
+ if ( ePageType == NOTICE )
+ nRetValue += mnMasterPages;
+ return nRetValue;
+}
+
+void PPTWriterBase::SetCurrentStyleSheet( sal_uInt32 nPageNum )
+{
+ if ( nPageNum >= maStyleSheetList.size() )
+ nPageNum = 0;
+ mpStyleSheet = maStyleSheetList[ nPageNum ].get();
+}
+
+bool PPTWriterBase::GetStyleSheets()
+{
+ int nInstance, nLevel;
+ bool bRetValue = false;
+ sal_uInt32 nPageNum;
+
+ for ( nPageNum = 0; nPageNum < mnMasterPages; nPageNum++ )
+ {
+ Reference< XNamed >
+ aXNamed;
+
+ Reference< XNameAccess >
+ aXNameAccess;
+
+ Reference< XStyleFamiliesSupplier >
+ aXStyleFamiliesSupplier( mXModel, UNO_QUERY );
+
+ Reference< XPropertySet >
+ aXPropSet( mXModel, UNO_QUERY );
+
+ sal_uInt16 nDefaultTab = ( aXPropSet.is() && ImplGetPropertyValue( aXPropSet, "TabStop" ) )
+ ? static_cast<sal_uInt16>( convertMm100ToMasterUnit(*o3tl::doAccess<sal_Int32>(mAny)) )
+ : 1250;
+
+ maStyleSheetList.emplace_back( new PPTExStyleSheet( nDefaultTab, dynamic_cast<PPTExBulletProvider*>(this) ) );
+ SetCurrentStyleSheet( nPageNum );
+ if ( GetPageByIndex( nPageNum, MASTER ) )
+ aXNamed.set( mXDrawPage, UNO_QUERY );
+
+ if ( aXStyleFamiliesSupplier.is() )
+ aXNameAccess = aXStyleFamiliesSupplier->getStyleFamilies();
+
+ bRetValue = aXNamed.is() && aXNameAccess.is() && aXStyleFamiliesSupplier.is();
+ if ( bRetValue )
+ {
+ for ( nInstance = EPP_TEXTTYPE_Title; nInstance <= EPP_TEXTTYPE_CenterTitle; nInstance++ )
+ {
+ OUString aStyle;
+ OUString aFamily;
+ switch ( nInstance )
+ {
+ case EPP_TEXTTYPE_CenterTitle :
+ case EPP_TEXTTYPE_Title :
+ {
+ aStyle = "title";
+ aFamily = aXNamed->getName();
+ }
+ break;
+ case EPP_TEXTTYPE_Body :
+ {
+ aStyle = "outline1"; // SD_LT_SEPARATOR
+ aFamily = aXNamed->getName();
+ }
+ break;
+ case EPP_TEXTTYPE_Other :
+ {
+ aStyle = "standard";
+ aFamily = "graphics";
+ }
+ break;
+ case EPP_TEXTTYPE_CenterBody :
+ {
+ aStyle = "subtitle";
+ aFamily = aXNamed->getName();
+ }
+ break;
+ }
+ if ( !aStyle.isEmpty() && !aFamily.isEmpty() )
+ {
+ try
+ {
+ Reference< XNameAccess >xNameAccess;
+ if ( aXNameAccess->hasByName( aFamily ) )
+ {
+ Any aAny( aXNameAccess->getByName( aFamily ) );
+ xNameAccess.set(aAny, css::uno::UNO_QUERY);
+ if( xNameAccess.is() )
+ {
+ Reference< XNameAccess > aXFamily;
+ if ( aAny >>= aXFamily )
+ {
+ if ( aXFamily->hasByName( aStyle ) )
+ {
+ aAny = aXFamily->getByName( aStyle );
+ Reference< XStyle > xStyle(
+ aAny, css::uno::UNO_QUERY);
+ if( xStyle.is() )
+ {
+ Reference< XStyle > aXStyle;
+ aAny >>= aXStyle;
+ Reference< XPropertySet >
+ xPropSet( aXStyle, UNO_QUERY );
+ if( xPropSet.is() )
+ mpStyleSheet->SetStyleSheet( xPropSet, maFontCollection, nInstance, 0 );
+ for ( nLevel = 1; nLevel < 5; nLevel++ )
+ {
+ if ( nInstance == EPP_TEXTTYPE_Body )
+ {
+ sal_Unicode cTemp = aStyle[aStyle.getLength() - 1];
+ aStyle = aStyle.subView(0, aStyle.getLength() - 1) + OUStringChar(++cTemp);
+ if ( aXFamily->hasByName( aStyle ) )
+ {
+ aXFamily->getByName( aStyle ) >>= xStyle;
+ if( xStyle.is() )
+ {
+ Reference< XPropertySet >
+ xPropertySet( xStyle, UNO_QUERY );
+ if ( xPropertySet.is() )
+ mpStyleSheet->SetStyleSheet( xPropertySet, maFontCollection, nInstance, nLevel );
+ }
+ }
+ }
+ else
+ mpStyleSheet->SetStyleSheet( xPropSet, maFontCollection, nInstance, nLevel );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+
+ }
+ }
+ }
+ for ( ; nInstance <= EPP_TEXTTYPE_QuarterBody; nInstance++ )
+ {
+
+ }
+ }
+ }
+ return bRetValue;
+}
+
+bool PPTWriterBase::CreateMainNotes()
+{
+ if ( !GetPageByIndex( 0, NOTICE ) )
+ return false;
+ SetCurrentStyleSheet( 0 );
+
+ css::uno::Reference< css::drawing::XMasterPageTarget > aXMasterPageTarget( mXDrawPage, css::uno::UNO_QUERY );
+
+ if ( !aXMasterPageTarget.is() )
+ return false;
+
+ mXDrawPage = aXMasterPageTarget->getMasterPage();
+ if ( !mXDrawPage.is() )
+ return false;
+
+ mXPropSet.set( mXDrawPage, css::uno::UNO_QUERY );
+ if ( !mXPropSet.is() )
+ return false;
+
+ mXShapes = mXDrawPage;
+ if ( !mXShapes.is() )
+ return false;
+
+ return ImplCreateMainNotes();
+}
+
+awt::Size PPTWriterBase::MapSize( const awt::Size& rSize )
+{
+ Size aRetSize( OutputDevice::LogicToLogic( Size( rSize.Width, rSize.Height ), maMapModeSrc, maMapModeDest ) );
+
+ if ( !aRetSize.Width() )
+ aRetSize.AdjustWidth( 1 );
+ if ( !aRetSize.Height() )
+ aRetSize.AdjustHeight( 1 );
+ return awt::Size( aRetSize.Width(), aRetSize.Height() );
+}
+
+awt::Point PPTWriterBase::MapPoint( const awt::Point& rPoint )
+{
+ Point aRet( OutputDevice::LogicToLogic( Point( rPoint.X, rPoint.Y ), maMapModeSrc, maMapModeDest ) );
+ return awt::Point( aRet.X(), aRet.Y() );
+}
+
+::tools::Rectangle PPTWriterBase::MapRectangle( const awt::Rectangle& rRect )
+{
+ css::awt::Point aPoint( rRect.X, rRect.Y );
+ css::awt::Size aSize( rRect.Width, rRect.Height );
+ css::awt::Point aP( MapPoint( aPoint ) );
+ css::awt::Size aS( MapSize( aSize ) );
+ return ::tools::Rectangle( Point( aP.X, aP.Y ), Size( aS.Width, aS.Height ) );
+}
+
+bool PPTWriterBase::GetShapeByIndex( sal_uInt32 nIndex, bool bGroup )
+{
+ while(true)
+ {
+ if ( !bGroup || ( GetCurrentGroupLevel() == 0 ) )
+ {
+ Any aAny( mXShapes->getByIndex( nIndex ) );
+ aAny >>= mXShape;
+ }
+ else
+ {
+ Any aAny( GetCurrentGroupAccess()->getByIndex( GetCurrentGroupIndex() ) );
+ aAny >>= mXShape;
+ }
+ if ( !mXShape.is() )
+ break;
+
+ Any aAny( mXShape->queryInterface( cppu::UnoType<XPropertySet>::get()));
+ aAny >>= mXPropSet;
+
+ if ( !mXPropSet.is() )
+ break;
+ maPosition = MapPoint( mXShape->getPosition() );
+ maSize = MapSize( mXShape->getSize() );
+ maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
+
+ OStringBuffer aTypeBuffer(OUStringToOString(
+ mXShape->getShapeType(), RTL_TEXTENCODING_UTF8));
+ // remove "com.sun.star."
+ aTypeBuffer.remove(0, RTL_CONSTASCII_LENGTH("com.sun.star."));
+
+ sal_Int32 nPos = aTypeBuffer.toString().indexOf("Shape");
+ aTypeBuffer.remove(nPos, RTL_CONSTASCII_LENGTH("Shape"));
+ mType = aTypeBuffer.makeStringAndClear();
+
+ mbPresObj = mbEmptyPresObj = false;
+ if ( ImplGetPropertyValue( "IsPresentationObject" ) )
+ mAny >>= mbPresObj;
+
+ if ( mbPresObj && ImplGetPropertyValue( "IsEmptyPresentationObject" ) )
+ mAny >>= mbEmptyPresObj;
+
+ mnAngle = ( PropValue::GetPropertyValue( aAny,
+ mXPropSet, "RotateAngle", true ) )
+ ? *o3tl::doAccess<sal_Int32>(aAny)
+ : 0;
+
+ return true;
+ }
+ return false;
+}
+
+sal_Int8 PPTWriterBase::GetTransition( sal_Int16 nTransitionType, sal_Int16 nTransitionSubtype, FadeEffect eEffect,
+ sal_Int32 nTransitionFadeColor, sal_uInt8& nDirection )
+{
+ sal_Int8 nPPTTransitionType = 0;
+ nDirection = 0;
+
+ switch( nTransitionType )
+ {
+ case TransitionType::FADE :
+ {
+ if ( nTransitionSubtype == TransitionSubType::CROSSFADE )
+ nPPTTransitionType = PPT_TRANSITION_TYPE_SMOOTHFADE;
+ else if ( nTransitionSubtype == TransitionSubType::FADEOVERCOLOR )
+ {
+ if( nTransitionFadeColor == static_cast<sal_Int32>(COL_WHITE) )
+ nPPTTransitionType = PPT_TRANSITION_TYPE_FLASH;
+ else
+ nPPTTransitionType = PPT_TRANSITION_TYPE_FADE;
+ }
+ }
+ break;
+ case TransitionType::PUSHWIPE :
+ {
+ if (nTransitionSubtype == TransitionSubType::COMBVERTICAL ||
+ nTransitionSubtype == TransitionSubType::COMBHORIZONTAL)
+ {
+ nPPTTransitionType = PPT_TRANSITION_TYPE_COMB;
+ }
+ else
+ {
+ nPPTTransitionType = PPT_TRANSITION_TYPE_PUSH;
+ }
+ switch (nTransitionSubtype)
+ {
+ case TransitionSubType::FROMRIGHT: nDirection = 0; break;
+ case TransitionSubType::FROMBOTTOM: nDirection = 1; break;
+ case TransitionSubType::FROMLEFT: nDirection = 2; break;
+ case TransitionSubType::FROMTOP: nDirection = 3; break;
+ case TransitionSubType::COMBHORIZONTAL: nDirection = 0; break;
+ case TransitionSubType::COMBVERTICAL: nDirection = 1; break;
+ }
+ }
+ break;
+ case TransitionType::PINWHEELWIPE :
+ {
+ nPPTTransitionType = PPT_TRANSITION_TYPE_WHEEL;
+ switch( nTransitionSubtype )
+ {
+ case TransitionSubType::ONEBLADE: nDirection = 1; break;
+ case TransitionSubType::TWOBLADEVERTICAL : nDirection = 2; break;
+ case TransitionSubType::THREEBLADE : nDirection = 3; break;
+ case TransitionSubType::FOURBLADE: nDirection = 4; break;
+ case TransitionSubType::EIGHTBLADE: nDirection = 8; break;
+ }
+ }
+ break;
+ case TransitionType::FANWIPE :
+ {
+ nPPTTransitionType = PPT_TRANSITION_TYPE_WEDGE;
+ }
+ break;
+ case TransitionType::ELLIPSEWIPE :
+ {
+ switch( nTransitionSubtype ) {
+ case TransitionSubType::VERTICAL:
+ case TransitionSubType::HORIZONTAL:
+ // no ellipse or oval in PPT or OOXML, fallback to circle
+ default:
+ nPPTTransitionType = PPT_TRANSITION_TYPE_CIRCLE;
+ }
+ }
+ break;
+ case TransitionType::FOURBOXWIPE :
+ {
+ nPPTTransitionType = PPT_TRANSITION_TYPE_PLUS;
+ }
+ break;
+ case TransitionType::IRISWIPE :
+ {
+ switch( nTransitionSubtype ) {
+ case TransitionSubType::RECTANGLE:
+ nPPTTransitionType = PPT_TRANSITION_TYPE_ZOOM;
+ nDirection = (eEffect == FadeEffect_FADE_FROM_CENTER) ? 0 : 1;
+ break;
+ default:
+ nPPTTransitionType = PPT_TRANSITION_TYPE_DIAMOND;
+ break;
+ }
+ }
+ break;
+ case TransitionType::ZOOM:
+ {
+ switch(nTransitionSubtype)
+ {
+ case TransitionSubType::ROTATEIN:
+ nPPTTransitionType = PPT_TRANSITION_TYPE_NEWSFLASH;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ return nPPTTransitionType;
+}
+
+sal_Int8 PPTWriterBase::GetTransition( FadeEffect eEffect, sal_uInt8& nDirection )
+{
+ sal_Int8 nPPTTransitionType = 0;
+
+ switch ( eEffect )
+ {
+ default :
+ case FadeEffect_RANDOM :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_RANDOM;
+ break;
+
+ case FadeEffect_HORIZONTAL_STRIPES :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_VERTICAL_STRIPES :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_BLINDS;
+ break;
+
+ case FadeEffect_VERTICAL_CHECKERBOARD :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_HORIZONTAL_CHECKERBOARD :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_CHECKER;
+ break;
+
+ case FadeEffect_MOVE_FROM_UPPERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_UPPERRIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_LOWERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_LOWERRIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_TOP :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_LEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_BOTTOM :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_RIGHT :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_COVER;
+ break;
+
+ case FadeEffect_DISSOLVE :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_DISSOLVE;
+ break;
+
+ case FadeEffect_VERTICAL_LINES :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_HORIZONTAL_LINES :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_RANDOM_BARS;
+ break;
+
+ case FadeEffect_CLOSE_HORIZONTAL :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_OPEN_HORIZONTAL :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_CLOSE_VERTICAL :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_OPEN_VERTICAL :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_SPLIT;
+ break;
+
+ case FadeEffect_FADE_FROM_UPPERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_UPPERRIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_LOWERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_LOWERRIGHT :
+ nDirection += 4;
+ nPPTTransitionType = PPT_TRANSITION_TYPE_STRIPS;
+ break;
+
+ case FadeEffect_UNCOVER_TO_LOWERRIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_LOWERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_UPPERRIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_UPPERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_BOTTOM :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_RIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_TOP :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_LEFT :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_PULL;
+ break;
+
+ case FadeEffect_FADE_FROM_TOP :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_LEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_BOTTOM :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_RIGHT :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_WIPE;
+ break;
+
+ case FadeEffect_ROLL_FROM_TOP :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_ROLL_FROM_LEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_ROLL_FROM_BOTTOM :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_ROLL_FROM_RIGHT :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_WIPE;
+ break;
+
+ case FadeEffect_FADE_TO_CENTER :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_CENTER :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_ZOOM;
+ break;
+
+ case FadeEffect_NONE :
+ nDirection = 2;
+ break;
+ }
+
+ return nPPTTransitionType;
+}
+
+bool PPTWriterBase::ContainsOtherShapeThanPlaceholders()
+{
+ sal_uInt32 nShapes = mXShapes->getCount();
+ bool bOtherThanPlaceHolders = false;
+
+ if ( nShapes )
+ for ( sal_uInt32 nIndex = 0; ( nIndex < nShapes ) && !bOtherThanPlaceHolders; nIndex++ )
+ {
+ if ( GetShapeByIndex( nIndex, false ) && mType != "drawing.Page" )
+ {
+ if( mType == "presentation.Page" || mType == "presentation.Notes" )
+ {
+ Reference< XSimpleText > rXText( mXShape, UNO_QUERY );
+
+ if( rXText.is() && !rXText->getString().isEmpty() )
+ bOtherThanPlaceHolders = true;
+ }
+ else
+ bOtherThanPlaceHolders = true;
+ }
+ SAL_INFO("sd.eppt", "mType == " << mType);
+ }
+
+ return bOtherThanPlaceHolders;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx
new file mode 100644
index 000000000..6a338a6a6
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-epptooxml.cxx
@@ -0,0 +1,2594 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdio.h>
+#include <oox/drawingml/clrscheme.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/token/tokens.hxx>
+#include <oox/token/relationship.hxx>
+#include <oox/ole/vbaproject.hxx>
+#include "epptooxml.hxx"
+#include <oox/export/shapes.hxx>
+
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/xmltools.hxx>
+#include <sax/fshelper.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/UnitConversion.hxx>
+#include <tools/datetime.hxx>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/XDrawPages.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/geometry/RealPoint2D.hpp>
+#include <com/sun/star/office/XAnnotationEnumeration.hpp>
+#include <com/sun/star/office/XAnnotationAccess.hpp>
+#include <com/sun/star/presentation/AnimationSpeed.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/presentation/XCustomPresentationSupplier.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/presentation/XPresentationSupplier.hpp>
+#include <tools/diagnose_ex.h>
+
+#include <oox/export/utils.hxx>
+
+#include "pptx-animations.hxx"
+#include "../ppt/pptanimations.hxx"
+
+#include <i18nlangtag/languagetag.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svdogrp.hxx>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <utility>
+#if OSL_DEBUG_LEVEL > 1
+#include <com/sun/star/drawing/RectanglePoint.hpp>
+#endif
+
+// presentation namespaces
+#define PNMSS FSNS(XML_xmlns, XML_a), OUStringToOString(this->getNamespaceURL(OOX_NS(dml)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_p), OUStringToOString(this->getNamespaceURL(OOX_NS(ppt)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_r), OUStringToOString(this->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_p14), OUStringToOString(this->getNamespaceURL(OOX_NS(p14)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_p15), OUStringToOString(this->getNamespaceURL(OOX_NS(p15)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_mc), OUStringToOString(this->getNamespaceURL(OOX_NS(mce)), RTL_TEXTENCODING_UTF8).getStr()
+
+// presentationPr namespace
+#define PPRNMSS FSNS(XML_xmlns, XML_a), OUStringToOString(this->getNamespaceURL(OOX_NS(dml)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_r), OUStringToOString(this->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_p), OUStringToOString(this->getNamespaceURL(OOX_NS(ppt)), RTL_TEXTENCODING_UTF8).getStr()
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::geometry;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::office;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::ppt;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::beans::XPropertySetInfo;
+using ::sax_fastparser::FSHelperPtr;
+using namespace oox::drawingml;
+using namespace oox::core;
+
+#if OSL_DEBUG_LEVEL > 1
+void dump_pset(Reference< XPropertySet > const& rXPropSet);
+#endif
+
+namespace oox::core
+{
+
+class PowerPointShapeExport : public ShapeExport
+{
+ PowerPointExport& mrExport;
+ PageType mePageType;
+ bool mbMaster;
+public:
+ PowerPointShapeExport(FSHelperPtr pFS, ShapeHashMap* pShapeMap, PowerPointExport* pFB);
+ void SetMaster(bool bMaster);
+ void SetPageType(PageType ePageType);
+ ShapeExport& WriteNonVisualProperties(const Reference< XShape >& xShape) override;
+ ShapeExport& WriteTextShape(const Reference< XShape >& xShape) override;
+ ShapeExport& WriteUnknownShape(const Reference< XShape >& xShape) override;
+ ShapeExport& WritePlaceholderShape(const Reference< XShape >& xShape, PlaceholderType ePlaceholder);
+ /** Writes a placeholder shape that references the placeholder on the master slide */
+ ShapeExport& WritePlaceholderReferenceShape(PlaceholderType ePlaceholder, sal_Int32 nReferencedPlaceholderIdx, PageType ePageType, const Reference<XPropertySet>& rXPagePropSet);
+ ShapeExport& WritePageShape(const Reference< XShape >& xShape, PageType ePageType, bool bPresObj);
+ /** Writes textbody of a placeholder that references the placeholder on the master slide */
+ ShapeExport& WritePlaceholderReferenceTextBody(PlaceholderType ePlaceholder, PageType ePageType, const Reference<XPropertySet> xPagePropSet);
+
+ // helper parts
+ bool WritePlaceholder(const Reference< XShape >& xShape, PlaceholderType ePlaceholder, bool bMaster);
+};
+
+
+namespace
+{
+void WriteSndAc(const FSHelperPtr& pFS, const OUString& sSoundRelId, const OUString& sSoundName)
+{
+ pFS->startElementNS(XML_p, XML_sndAc);
+ pFS->startElementNS(XML_p, XML_stSnd);
+ pFS->singleElementNS(XML_p, XML_snd, FSNS(XML_r, XML_embed),
+ sax_fastparser::UseIf(sSoundRelId, !sSoundRelId.isEmpty()), XML_name,
+ sax_fastparser::UseIf(sSoundName, !sSoundName.isEmpty()));
+ pFS->endElement(FSNS(XML_p, XML_stSnd));
+ pFS->endElement(FSNS(XML_p, XML_sndAc));
+}
+
+const char* getPlaceholderTypeName(PlaceholderType ePlaceholder)
+{
+ switch (ePlaceholder)
+ {
+ case SlideImage:
+ return "sldImg";
+ case Notes:
+ return "body";
+ case Header:
+ return "hdr";
+ case Footer:
+ return "ftr";
+ case SlideNumber:
+ return "sldNum";
+ case DateAndTime:
+ return "dt";
+ case Outliner:
+ return "body";
+ case Title:
+ return "title";
+ case Subtitle:
+ return "subTitle";
+ default:
+ SAL_INFO("sd.eppt", "warning: unhandled placeholder type: " << ePlaceholder);
+ return "";
+ }
+}
+}
+}
+
+namespace {
+
+enum PPTXLayout
+{
+ LAYOUT_BLANK,
+ LAYOUT_TITLE_SLIDE,
+ LAYOUT_TITLE_CONTENT,
+ LAYOUT_TITLE_2CONTENT,
+ LAYOUT_TITLE,
+ LAYOUT_CENTERED_TEXT,
+ LAYOUT_TITLE_2CONTENT_CONTENT,
+ LAYOUT_TITLE_CONTENT_2CONTENT,
+ LAYOUT_TITLE_2CONTENT_OVER_CONTENT,
+ LAYOUT_TITLE_CONTENT_OVER_CONTENT,
+ LAYOUT_TITLE_4CONTENT,
+ LAYOUT_TITLE_6CONTENT,
+ LAYOUT_SIZE
+};
+
+struct PPTXLayoutInfo
+{
+ int nType;
+ const char* sName;
+ const char* sType;
+};
+
+}
+
+const PPTXLayoutInfo aLayoutInfo[LAYOUT_SIZE] =
+{
+ { 20, "Blank Slide", "blank" },
+ { 0, "Title Slide", "tx" },
+ { 1, "Title, Content", "obj" },
+ { 3, "Title, 2 Content", "twoObj" },
+ { 19, "Title Only", "titleOnly" },
+ { 32, "Centered Text", "objOnly" }, // not exactly, but close
+ { 15, "Title, 2 Content and Content", "twoObjAndObj" },
+ { 12, "Title Content and 2 Content", "objAndTwoObj" },
+ { 16, "Title, 2 Content over Content", "twoObjOverTx" }, // not exactly, but close
+ { 14, "Title, Content over Content", "objOverTx" }, // not exactly, but close
+ { 18, "Title, 4 Content", "fourObj" },
+ { 34, "Title, 6 Content", "blank" } // not defined => blank
+};
+
+int PowerPointExport::GetPPTXLayoutId(int nOffset)
+{
+ int nId = LAYOUT_BLANK;
+
+ SAL_INFO("sd.eppt", "GetPPTXLayoutId " << nOffset);
+
+ switch (nOffset)
+ {
+ case 0:
+ nId = LAYOUT_TITLE_SLIDE;
+ break;
+ case 1:
+ nId = LAYOUT_TITLE_CONTENT;
+ break;
+ case 3:
+ nId = LAYOUT_TITLE_2CONTENT;
+ break;
+ case 19:
+ nId = LAYOUT_TITLE;
+ break;
+ case 15:
+ nId = LAYOUT_TITLE_2CONTENT_CONTENT;
+ break;
+ case 12:
+ nId = LAYOUT_TITLE_CONTENT_2CONTENT;
+ break;
+ case 16:
+ nId = LAYOUT_TITLE_2CONTENT_OVER_CONTENT;
+ break;
+ case 14:
+ nId = LAYOUT_TITLE_CONTENT_OVER_CONTENT;
+ break;
+ case 18:
+ nId = LAYOUT_TITLE_4CONTENT;
+ break;
+ case 32:
+ nId = LAYOUT_CENTERED_TEXT;
+ break;
+ case 34:
+ nId = LAYOUT_TITLE_6CONTENT;
+ break;
+ case 20:
+ default:
+ nId = LAYOUT_BLANK;
+ break;
+ }
+
+ return nId;
+}
+
+PowerPointShapeExport::PowerPointShapeExport(FSHelperPtr pFS, ShapeHashMap* pShapeMap,
+ PowerPointExport* pFB)
+ : ShapeExport(XML_p, std::move(pFS), pShapeMap, pFB)
+ , mrExport(*pFB)
+ , mePageType(UNDEFINED)
+ , mbMaster(false)
+{
+}
+
+void PowerPointShapeExport::SetMaster(bool bMaster)
+{
+ mbMaster = bMaster;
+}
+
+void PowerPointShapeExport::SetPageType(PageType ePageType)
+{
+ mePageType = ePageType;
+}
+
+ShapeExport& PowerPointShapeExport::WriteNonVisualProperties(const Reference< XShape >&)
+{
+ GetFS()->singleElementNS(XML_p, XML_nvPr);
+
+ return *this;
+}
+
+ShapeExport& PowerPointShapeExport::WriteTextShape(const Reference< XShape >& xShape)
+{
+ OUString sShapeType = xShape->getShapeType();
+
+ SAL_INFO("sd.eppt", "shape(text) : " << sShapeType.toUtf8());
+
+ if (sShapeType == "com.sun.star.drawing.TextShape" || sShapeType == "com.sun.star.drawing.GraphicObjectShape")
+ {
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.DateTimeShape")
+ {
+ if (!WritePlaceholder(xShape, DateAndTime, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.FooterShape")
+ {
+ if (!WritePlaceholder(xShape, Footer, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.HeaderShape")
+ {
+ if (!WritePlaceholder(xShape, Header, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.NotesShape")
+ {
+ if (mePageType == NOTICE && mrExport.GetPresObj())
+ WritePlaceholderShape(xShape, Notes);
+ else
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.OutlinerShape")
+ {
+ if (!WritePlaceholder(xShape, Outliner, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.SlideNumberShape")
+ {
+ if (!WritePlaceholder(xShape, SlideNumber, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.TitleTextShape")
+ {
+ if (!WritePlaceholder(xShape, Title, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else
+ SAL_WARN("sd.eppt", "PowerPointShapeExport::WriteTextShape: shape of type '" << sShapeType << "' is ignored");
+
+ return *this;
+}
+
+ShapeExport& PowerPointShapeExport::WriteUnknownShape(const Reference< XShape >& xShape)
+{
+ OUString sShapeType = xShape->getShapeType();
+
+ SAL_INFO("sd.eppt", "shape(unknown): " << sShapeType.toUtf8());
+
+ if (sShapeType == "com.sun.star.presentation.PageShape")
+ {
+ WritePageShape(xShape, mePageType, mrExport.GetPresObj());
+ }
+ else if (sShapeType == "com.sun.star.presentation.SubtitleShape")
+ {
+ if(mePageType != MASTER)
+ {
+ if (!WritePlaceholder(xShape, Subtitle, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ }
+ else
+ SAL_WARN("sd.eppt", "unknown shape not handled: " << sShapeType.toUtf8());
+
+ return *this;
+}
+
+PowerPointExport::PowerPointExport(const Reference< XComponentContext >& rContext, const uno::Sequence<uno::Any>& rArguments)
+ : XmlFilterBase(rContext)
+ , mnLayoutFileIdMax(1)
+ , mnSlideIdMax(1 << 8)
+ , mnSlideMasterIdMax(1U << 31)
+ , mnAnimationNodeIdMax(1)
+ , mnDiagramId(1)
+ , mbCreateNotes(false)
+ , mnPlaceholderIndexMax(1)
+{
+ comphelper::SequenceAsHashMap aArgumentsMap(rArguments);
+ mbPptm = aArgumentsMap.getUnpackedValueOrDefault("IsPPTM", false);
+ mbExportTemplate = aArgumentsMap.getUnpackedValueOrDefault("IsTemplate", false);
+}
+
+PowerPointExport::~PowerPointExport()
+{
+}
+
+void PowerPointExport::writeDocumentProperties()
+{
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(mXModel, uno::UNO_QUERY);
+ uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
+
+ if (xDocProps.is())
+ {
+ bool bSecurityOptOpenReadOnly = false;
+ uno::Reference< lang::XMultiServiceFactory > xFactory(mXModel, uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet > xSettings(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
+ try
+ {
+ xSettings->getPropertyValue("LoadReadonly") >>= bSecurityOptOpenReadOnly;
+ }
+ catch( Exception& )
+ {
+ }
+ exportDocumentProperties(xDocProps, bSecurityOptOpenReadOnly);
+ }
+
+ exportCustomFragments();
+}
+
+bool PowerPointExport::importDocument() noexcept
+{
+ return false;
+}
+
+bool PowerPointExport::exportDocument()
+{
+ DrawingML::PushExportGraphics();
+ maShapeMap.clear();
+
+ mXModel = getModel();
+
+ //write document properties
+ writeDocumentProperties();
+
+ addRelation(oox::getRelationship(Relationship::OFFICEDOCUMENT), u"ppt/presentation.xml");
+
+ OUString aMediaType;
+ if (mbPptm)
+ {
+ if (mbExportTemplate)
+ {
+ aMediaType = "application/vnd.ms-powerpoint.template.macroEnabled.main+xml";
+ }
+ else
+ {
+ aMediaType = "application/vnd.ms-powerpoint.presentation.macroEnabled.main+xml";
+ }
+ }
+ else
+ {
+ if (mbExportTemplate)
+ {
+ aMediaType = "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml";
+ }
+ else
+ {
+ aMediaType = "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml";
+ }
+ }
+
+ mPresentationFS = openFragmentStreamWithSerializer("ppt/presentation.xml", aMediaType);
+
+ addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::THEME),
+ u"theme/theme1.xml");
+
+ mPresentationFS->startElementNS(XML_p, XML_presentation, PNMSS);
+
+ mXStatusIndicator = getStatusIndicator();
+
+ std::vector< PropertyValue > aProperties;
+ PropertyValue aProperty;
+ aProperty.Name = "BaseURI";
+ aProperty.Value <<= getFileUrl();
+ aProperties.push_back(aProperty);
+
+ exportPPT(aProperties);
+
+ mPresentationFS->singleElementNS(XML_p, XML_sldSz,
+ XML_cx, OString::number(PPTtoEMU(maDestPageSize.Width)),
+ XML_cy, OString::number(PPTtoEMU(maDestPageSize.Height)));
+ // for some reason if added before slides list it will not load the slides (alas with error reports) in mso
+ mPresentationFS->singleElementNS(XML_p, XML_notesSz,
+ XML_cx, OString::number(PPTtoEMU(maNotesPageSize.Width)),
+ XML_cy, OString::number(PPTtoEMU(maNotesPageSize.Height)));
+
+ WriteCustomSlideShow();
+
+ WritePresentationProps();
+
+ WriteAuthors();
+
+ WriteVBA();
+
+ WriteModifyVerifier();
+
+ mPresentationFS->endElementNS(XML_p, XML_presentation);
+ mPresentationFS.reset();
+ // Free all FSHelperPtr, to flush data before committing storage
+ mpSlidesFSArray.clear();
+
+ commitStorage();
+
+ DrawingML::PopExportGraphics();
+ maShapeMap.clear();
+ maAuthors.clear();
+ maRelId.clear();
+
+ return true;
+}
+
+::oox::ole::VbaProject* PowerPointExport::implCreateVbaProject() const
+{
+ return new ::oox::ole::VbaProject(getComponentContext(), getModel(), u"Impress");
+}
+
+void PowerPointExport::WriteCustomSlideShow()
+{
+ Reference<XCustomPresentationSupplier> aXCPSup(mXModel, css::uno::UNO_QUERY);
+ if (!aXCPSup.is() || !aXCPSup->getCustomPresentations()->hasElements())
+ return;
+
+ mPresentationFS->startElementNS(XML_p, XML_custShowLst);
+
+ Reference<XDrawPagesSupplier> xDPS(getModel(), uno::UNO_QUERY_THROW);
+ Reference<XDrawPages> xDrawPages(xDPS->getDrawPages(), uno::UNO_SET_THROW);
+ Reference<XNameContainer> aXNameCont(aXCPSup->getCustomPresentations());
+ const Sequence<OUString> aNameSeq(aXNameCont->getElementNames());
+
+ OUString sRelId;
+ sal_uInt32 nCustomShowIndex = 0;
+ sal_Int32 nSlideCount = xDrawPages->getCount();
+
+ for (OUString const& customShowName : aNameSeq)
+ {
+ mPresentationFS->startElementNS(XML_p, XML_custShow, XML_name, customShowName, XML_id,
+ OUString::number(nCustomShowIndex++));
+
+ mAny = aXNameCont->getByName(customShowName);
+ Reference<XIndexContainer> aXIContainer;
+ if (mAny >>= aXIContainer)
+ {
+ mPresentationFS->startElementNS(XML_p, XML_sldLst);
+
+ sal_Int32 nCustomShowSlideCount = aXIContainer->getCount();
+ for (sal_Int32 i = 0; i < nCustomShowSlideCount; ++i)
+ {
+ Reference<XDrawPage> aXCustomShowDrawPage;
+ aXIContainer->getByIndex(i) >>= aXCustomShowDrawPage;
+ Reference<XNamed> aXName(aXCustomShowDrawPage, UNO_QUERY_THROW);
+ OUString sCustomShowSlideName = aXName->getName();
+
+ for (sal_Int32 j = 0; j < nSlideCount; ++j)
+ {
+ Reference<XDrawPage> xDrawPage;
+ xDrawPages->getByIndex(j) >>= xDrawPage;
+ Reference<XNamed> xNamed(xDrawPage, UNO_QUERY_THROW);
+ OUString sSlideName = xNamed->getName();
+
+ if (sCustomShowSlideName == sSlideName)
+ {
+ sRelId = maRelId[j];
+ break;
+ }
+ }
+ mPresentationFS->singleElementNS(XML_p, XML_sld, FSNS(XML_r, XML_id), sRelId);
+ }
+ mPresentationFS->endElementNS(XML_p, XML_sldLst);
+ }
+ mPresentationFS->endElementNS(XML_p, XML_custShow);
+ }
+ mPresentationFS->endElementNS(XML_p, XML_custShowLst);
+}
+
+void PowerPointExport::ImplWriteBackground(const FSHelperPtr& pFS, const Reference< XPropertySet >& rXPropSet)
+{
+ FillStyle aFillStyle(FillStyle_NONE);
+ if (ImplGetPropertyValue(rXPropSet, "FillStyle"))
+ mAny >>= aFillStyle;
+
+ if (aFillStyle == FillStyle_NONE ||
+ aFillStyle == FillStyle_HATCH)
+ return;
+
+ pFS->startElementNS(XML_p, XML_bg);
+ pFS->startElementNS(XML_p, XML_bgPr);
+
+ PowerPointShapeExport aDML(pFS, &maShapeMap, this);
+ aDML.SetBackgroundDark(mbIsBackgroundDark);
+ aDML.WriteFill(rXPropSet);
+
+ pFS->endElementNS(XML_p, XML_bgPr);
+ pFS->endElementNS(XML_p, XML_bg);
+}
+
+#define MAIN_GROUP \
+ "<p:nvGrpSpPr>\
+ <p:cNvPr id=\"1\" name=\"\"/>\
+ <p:cNvGrpSpPr/>\
+ <p:nvPr/>\
+ </p:nvGrpSpPr>\
+ <p:grpSpPr>\
+ <a:xfrm>\
+ <a:off x=\"0\" y=\"0\"/>\
+ <a:ext cx=\"0\" cy=\"0\"/>\
+ <a:chOff x=\"0\" y=\"0\"/>\
+ <a:chExt cx=\"0\" cy=\"0\"/>\
+ </a:xfrm>\
+ </p:grpSpPr>"
+
+const char* PowerPointExport::GetSideDirection(sal_uInt8 nDirection)
+{
+ const char* pDirection = nullptr;
+
+ switch (nDirection)
+ {
+ case 0:
+ pDirection = "l";
+ break;
+ case 1:
+ pDirection = "u";
+ break;
+ case 2:
+ pDirection = "r";
+ break;
+ case 3:
+ pDirection = "d";
+ break;
+ }
+
+ return pDirection;
+}
+
+const char* PowerPointExport::GetCornerDirection(sal_uInt8 nDirection)
+{
+ const char* pDirection = nullptr;
+
+ switch (nDirection)
+ {
+ case 4:
+ pDirection = "lu";
+ break;
+ case 5:
+ pDirection = "ru";
+ break;
+ case 6:
+ pDirection = "ld";
+ break;
+ case 7:
+ pDirection = "rd";
+ break;
+ }
+
+ return pDirection;
+}
+
+const char* PowerPointExport::Get8Direction(sal_uInt8 nDirection)
+{
+ const char* pDirection = GetSideDirection(nDirection);
+
+ if (!pDirection)
+ pDirection = GetCornerDirection(nDirection);
+
+ return pDirection;
+}
+
+void PowerPointExport::WriteTransition(const FSHelperPtr& pFS)
+{
+ FadeEffect eFadeEffect = FadeEffect_NONE;
+ if (ImplGetPropertyValue(mXPagePropSet, "Effect"))
+ mAny >>= eFadeEffect;
+
+ sal_Int16 nTransitionType = 0, nTransitionSubtype = 0;
+ sal_Int8 nPPTTransitionType = 0;
+ sal_uInt8 nDirection = 0;
+
+ OUString sSoundUrl;
+ OUString sSoundRelId;
+ OUString sSoundName;
+
+ if (ImplGetPropertyValue(mXPagePropSet, "TransitionType") && (mAny >>= nTransitionType) &&
+ ImplGetPropertyValue(mXPagePropSet, "TransitionSubtype") && (mAny >>= nTransitionSubtype))
+ {
+ // FADEOVERCOLOR with black -> fade, with white -> flash
+ sal_Int32 nTransitionFadeColor = 0;
+ if( ImplGetPropertyValue(mXPagePropSet, "TransitionFadeColor"))
+ mAny >>= nTransitionFadeColor;
+ nPPTTransitionType = GetTransition(nTransitionType, nTransitionSubtype, eFadeEffect, nTransitionFadeColor, nDirection);
+ }
+
+ if (!nPPTTransitionType && eFadeEffect != FadeEffect_NONE)
+ nPPTTransitionType = GetTransition(eFadeEffect, nDirection);
+
+ if (ImplGetPropertyValue(mXPagePropSet, "Sound") && (mAny >>= sSoundUrl))
+ embedEffectAudio(pFS, sSoundUrl, sSoundRelId, sSoundName);
+
+ bool bOOXmlSpecificTransition = false;
+
+ sal_Int32 nTransition = 0;
+ const char* pDirection = nullptr;
+ const char* pOrientation = nullptr;
+ const char* pThruBlk = nullptr;
+ const char* pSpokes = nullptr;
+
+ char pSpokesTmp[2] = "0";
+
+ // p14
+ sal_Int32 nTransition14 = 0;
+ const char* pDirection14 = nullptr;
+ const char* pInverted = nullptr;
+ const char* pPattern = nullptr; // diamond or hexagon
+
+ //p15
+ const char* pPresetTransition = nullptr;
+
+ if (!nPPTTransitionType)
+ {
+ switch (nTransitionType)
+ {
+ case animations::TransitionType::BARWIPE:
+ {
+ if (nTransitionSubtype == animations::TransitionSubType::FADEOVERCOLOR)
+ {
+ nTransition = XML_cut;
+ pThruBlk = "true";
+ bOOXmlSpecificTransition = true;
+ }
+ break;
+ }
+ case animations::TransitionType::MISCSHAPEWIPE:
+ {
+ switch (nTransitionSubtype)
+ {
+ case animations::TransitionSubType::TOPTOBOTTOM: // Turn around
+ nTransition = XML_fade;
+ nTransition14 = XML_flip;
+ pDirection14 = "l";
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::BOTTOMRIGHT: // Rochade
+ nTransition = XML_fade;
+ nTransition14 = XML_switch;
+ pDirection14 = "r";
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::VERTICAL: // Vortex
+ nTransition = XML_fade;
+ nTransition14 = XML_vortex;
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::HORIZONTAL: // Ripple
+ nTransition = XML_fade;
+ nTransition14 = XML_ripple;
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::LEFTTORIGHT: // Fall
+ nTransition = XML_fade;
+ pPresetTransition = "fallOver";
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::CORNERSIN: // Inside turning cube
+ pInverted = "true";
+ [[fallthrough]];
+ case animations::TransitionSubType::CORNERSOUT: // Outside turning cube
+ nTransition = XML_fade;
+ nTransition14 = XML_prism;
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::DIAMOND: // Glitter
+ nTransition = XML_fade;
+ nTransition14 = XML_glitter;
+ pDirection14 = "l";
+ pPattern = "hexagon";
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::HEART: // Honeycomb
+ nTransition = XML_fade;
+ nTransition14 = XML_honeycomb;
+ bOOXmlSpecificTransition = true;
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ AnimationSpeed animationSpeed = AnimationSpeed_MEDIUM;
+ const char* speed = nullptr;
+ sal_Int32 advanceTiming = -1;
+ sal_Int32 changeType = 0;
+
+ sal_Int32 nTransitionDuration = -1;
+ bool isTransitionDurationSet = false;
+
+ // try to use TransitionDuration instead of old Speed property
+ if (ImplGetPropertyValue(mXPagePropSet, "TransitionDuration"))
+ {
+ double fTransitionDuration = -1.0;
+ mAny >>= fTransitionDuration;
+ if (fTransitionDuration >= 0)
+ {
+ nTransitionDuration = fTransitionDuration * 1000.0;
+
+ // override values because in MS formats meaning of fast/medium/slow is different
+ if (nTransitionDuration <= 500)
+ {
+ // fast is default
+ speed = nullptr;
+ }
+ else if (nTransitionDuration >= 1000)
+ {
+ speed = "slow";
+ }
+ else
+ {
+ speed = "med";
+ }
+
+ bool isStandardValue = nTransitionDuration == 500
+ || nTransitionDuration == 750
+ || nTransitionDuration == 1000;
+
+ if(!isStandardValue)
+ isTransitionDurationSet = true;
+ }
+ }
+ else if (ImplGetPropertyValue(mXPagePropSet, "Speed"))
+ {
+ mAny >>= animationSpeed;
+
+ switch (animationSpeed)
+ {
+ default:
+ case AnimationSpeed_MEDIUM:
+ speed = "med";
+ break;
+ case AnimationSpeed_SLOW:
+ speed = "slow";
+ break;
+ case AnimationSpeed_FAST:
+ break;
+ }
+ }
+
+ // check if we resolved what transition to export or time is set
+ if (!nPPTTransitionType && !bOOXmlSpecificTransition && !isTransitionDurationSet)
+ return;
+
+ if (ImplGetPropertyValue(mXPagePropSet, "Change"))
+ mAny >>= changeType;
+
+ // 1 means automatic, 2 half automatic - not sure what it means - at least I don't see it in UI
+ if (changeType == 1 && ImplGetPropertyValue(mXPagePropSet, "Duration"))
+ mAny >>= advanceTiming;
+
+ if (!bOOXmlSpecificTransition)
+ {
+ switch (nPPTTransitionType)
+ {
+ case PPT_TRANSITION_TYPE_BLINDS:
+ nTransition = XML_blinds;
+ pDirection = (nDirection == 0) ? "vert" : "horz";
+ break;
+ case PPT_TRANSITION_TYPE_CHECKER:
+ nTransition = XML_checker;
+ pDirection = (nDirection == 1) ? "vert" : "horz";
+ break;
+ case PPT_TRANSITION_TYPE_CIRCLE:
+ nTransition = XML_circle;
+ break;
+ case PPT_TRANSITION_TYPE_COMB:
+ nTransition = XML_comb;
+ pDirection = (nDirection == 1) ? "vert" : "horz";
+ break;
+ case PPT_TRANSITION_TYPE_COVER:
+ nTransition = XML_cover;
+ pDirection = Get8Direction(nDirection);
+ break;
+ case PPT_TRANSITION_TYPE_DIAMOND:
+ nTransition = XML_diamond;
+ break;
+ case PPT_TRANSITION_TYPE_DISSOLVE:
+ nTransition = XML_dissolve;
+ break;
+ case PPT_TRANSITION_TYPE_FADE:
+ nTransition = XML_fade;
+ pThruBlk = "true";
+ break;
+ case PPT_TRANSITION_TYPE_SMOOTHFADE:
+ nTransition = XML_fade;
+ break;
+ case PPT_TRANSITION_TYPE_NEWSFLASH:
+ nTransition = XML_newsflash;
+ break;
+ case PPT_TRANSITION_TYPE_PLUS:
+ nTransition = XML_plus;
+ break;
+ case PPT_TRANSITION_TYPE_PULL:
+ nTransition = XML_pull;
+ pDirection = Get8Direction(nDirection);
+ break;
+ case PPT_TRANSITION_TYPE_PUSH:
+ nTransition = XML_push;
+ pDirection = GetSideDirection(nDirection);
+ break;
+ case PPT_TRANSITION_TYPE_RANDOM:
+ nTransition = XML_random;
+ break;
+ case PPT_TRANSITION_TYPE_RANDOM_BARS:
+ nTransition = XML_randomBar;
+ pDirection = (nDirection == 1) ? "vert" : "horz";
+ break;
+ case PPT_TRANSITION_TYPE_SPLIT:
+ nTransition = XML_split;
+ pDirection = (nDirection & 1) ? "in" : "out";
+ pOrientation = (nDirection < 2) ? "horz" : "vert";
+ break;
+ case PPT_TRANSITION_TYPE_STRIPS:
+ nTransition = XML_strips;
+ pDirection = GetCornerDirection(nDirection);
+ break;
+ case PPT_TRANSITION_TYPE_WEDGE:
+ nTransition = XML_wedge;
+ break;
+ case PPT_TRANSITION_TYPE_WHEEL:
+ nTransition = XML_wheel;
+ if (nDirection != 4 && nDirection <= 9)
+ {
+ pSpokesTmp[0] = '0' + nDirection;
+ pSpokes = pSpokesTmp;
+ }
+ break;
+ case PPT_TRANSITION_TYPE_WIPE:
+ nTransition = XML_wipe;
+ pDirection = GetSideDirection(nDirection);
+ break;
+ case PPT_TRANSITION_TYPE_ZOOM:
+ nTransition = XML_zoom;
+ pDirection = (nDirection == 1) ? "in" : "out";
+ break;
+ case PPT_TRANSITION_TYPE_FLASH:
+ nTransition14 = XML_flash;
+ nTransition = XML_fade;
+ bOOXmlSpecificTransition = true;
+ break;
+ // coverity[dead_error_line] - following conditions exist to avoid compiler warning
+ case PPT_TRANSITION_TYPE_NONE:
+ default:
+ nTransition = 0;
+ break;
+ }
+ }
+
+ bool isAdvanceTimingSet = advanceTiming != -1;
+ if (nTransition14 || pPresetTransition || isTransitionDurationSet)
+ {
+ const char* pRequiresNS = (nTransition14 || isTransitionDurationSet) ? "p14" : "p15";
+
+ pFS->startElement(FSNS(XML_mc, XML_AlternateContent));
+ pFS->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, pRequiresNS);
+
+ if(isTransitionDurationSet && isAdvanceTimingSet)
+ {
+ pFS->startElementNS(XML_p, XML_transition,
+ XML_spd, speed,
+ XML_advTm, OString::number(advanceTiming * 1000),
+ FSNS(XML_p14, XML_dur), OString::number(nTransitionDuration));
+ }
+ else if(isTransitionDurationSet)
+ {
+ pFS->startElementNS(XML_p, XML_transition,
+ XML_spd, speed,
+ FSNS(XML_p14, XML_dur), OString::number(nTransitionDuration));
+ }
+ else if(isAdvanceTimingSet)
+ {
+ pFS->startElementNS(XML_p, XML_transition,
+ XML_spd, speed,
+ XML_advTm, OString::number(advanceTiming * 1000));
+ }
+ else
+ {
+ pFS->startElementNS(XML_p, XML_transition, XML_spd, speed);
+ }
+
+ if (nTransition14)
+ {
+ pFS->singleElementNS(XML_p14, nTransition14,
+ XML_isInverted, pInverted,
+ XML_dir, pDirection14,
+ XML_pattern, pPattern);
+ }
+ else if (pPresetTransition)
+ {
+ pFS->singleElementNS(XML_p15, XML_prstTrans,
+ XML_prst, pPresetTransition);
+ }
+ else if (isTransitionDurationSet && nTransition)
+ {
+ pFS->singleElementNS(XML_p, nTransition,
+ XML_dir, pDirection,
+ XML_orient, pOrientation,
+ XML_spokes, pSpokes,
+ XML_thruBlk, pThruBlk);
+ }
+
+ if (!sSoundRelId.isEmpty())
+ WriteSndAc(pFS, sSoundRelId, sSoundName);
+
+ pFS->endElement(FSNS(XML_p, XML_transition));
+
+ pFS->endElement(FSNS(XML_mc, XML_Choice));
+ pFS->startElement(FSNS(XML_mc, XML_Fallback));
+ }
+
+ pFS->startElementNS(XML_p, XML_transition,
+ XML_spd, speed,
+ XML_advTm, sax_fastparser::UseIf(OString::number(advanceTiming * 1000), isAdvanceTimingSet));
+
+ if (nTransition)
+ {
+ pFS->singleElementNS(XML_p, nTransition,
+ XML_dir, pDirection,
+ XML_orient, pOrientation,
+ XML_spokes, pSpokes,
+ XML_thruBlk, pThruBlk);
+ }
+
+ if (!sSoundRelId.isEmpty())
+ WriteSndAc(pFS, sSoundRelId, sSoundName);
+
+ pFS->endElementNS(XML_p, XML_transition);
+
+ if (nTransition14 || pPresetTransition || isTransitionDurationSet)
+ {
+ pFS->endElement(FSNS(XML_mc, XML_Fallback));
+ pFS->endElement(FSNS(XML_mc, XML_AlternateContent));
+ }
+}
+
+static OUString lcl_GetInitials(const OUString& sName)
+{
+ OUStringBuffer sRet;
+
+ if (!sName.isEmpty())
+ {
+ sRet.append(sName[0]);
+ sal_Int32 nStart = 0, nOffset;
+
+ while ((nOffset = sName.indexOf(' ', nStart)) != -1)
+ {
+ if (nOffset + 1 < sName.getLength())
+ sRet.append(sName[ nOffset + 1 ]);
+ nStart = nOffset + 1;
+ }
+ }
+
+ return sRet.makeStringAndClear();
+}
+
+void PowerPointExport::WriteAuthors()
+{
+ if (maAuthors.empty())
+ return;
+
+ FSHelperPtr pFS = openFragmentStreamWithSerializer("ppt/commentAuthors.xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.commentAuthors+xml");
+ addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::COMMENTAUTHORS),
+ u"commentAuthors.xml");
+
+ pFS->startElementNS(XML_p, XML_cmAuthorLst,
+ FSNS(XML_xmlns, XML_p), getNamespaceURL(OOX_NS(ppt)));
+
+ for (const AuthorsMap::value_type& i : maAuthors)
+ {
+ pFS->singleElementNS(XML_p, XML_cmAuthor,
+ XML_id, OString::number(i.second.nId),
+ XML_name, i.first,
+ XML_initials, lcl_GetInitials(i.first),
+ XML_lastIdx, OString::number(i.second.nLastIndex),
+ XML_clrIdx, OString::number(i.second.nId));
+ }
+
+ pFS->endElementNS(XML_p, XML_cmAuthorLst);
+}
+
+sal_Int32 PowerPointExport::GetAuthorIdAndLastIndex(const OUString& sAuthor, sal_Int32& nLastIndex)
+{
+ if (maAuthors.count(sAuthor) <= 0)
+ {
+ struct AuthorComments aAuthorComments;
+
+ aAuthorComments.nId = maAuthors.size();
+ aAuthorComments.nLastIndex = 0;
+
+ maAuthors[ sAuthor ] = aAuthorComments;
+ }
+
+ nLastIndex = ++maAuthors[ sAuthor ].nLastIndex;
+
+ return maAuthors[ sAuthor ].nId;
+}
+
+void PowerPointExport::WritePresentationProps()
+{
+ Reference<XPresentationSupplier> xPresentationSupplier(mXModel, uno::UNO_QUERY);
+ if (!xPresentationSupplier.is())
+ return;
+
+ Reference<beans::XPropertySet> xPresentationProps(xPresentationSupplier->getPresentation(),
+ uno::UNO_QUERY);
+ bool bEndlessVal = xPresentationProps->getPropertyValue("IsEndless").get<bool>();
+ bool bChangeManually = xPresentationProps->getPropertyValue("IsAutomatic").get<bool>();
+ OUString sFirstPage = xPresentationProps->getPropertyValue("FirstPage").get<OUString>();
+ OUString sCustomShow = xPresentationProps->getPropertyValue("CustomShow").get<OUString>();
+
+ FSHelperPtr pFS = openFragmentStreamWithSerializer(
+ "ppt/presProps.xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.presProps+xml");
+
+ addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::PRESPROPS), u"presProps.xml");
+
+ pFS->startElementNS(XML_p, XML_presentationPr, PPRNMSS);
+
+ pFS->startElementNS(XML_p, XML_showPr, XML_loop, sax_fastparser::UseIf("1", bEndlessVal),
+ XML_useTimings, sax_fastparser::UseIf("0", bChangeManually),
+ XML_showNarration, "1");
+
+ Reference<drawing::XDrawPagesSupplier> xDPS(mXModel, uno::UNO_QUERY_THROW);
+ Reference<drawing::XDrawPages> xDrawPages(xDPS->getDrawPages(), uno::UNO_SET_THROW);
+ if (!sFirstPage.isEmpty())
+ {
+ sal_Int32 nStartSlide = 1;
+ sal_Int32 nEndSlide = xDrawPages->getCount();
+ for (sal_Int32 i = 0; i < nEndSlide; i++)
+ {
+ Reference<drawing::XDrawPage> xDrawPage;
+ xDrawPages->getByIndex(i) >>= xDrawPage;
+ Reference<container::XNamed> xNamed(xDrawPage, uno::UNO_QUERY_THROW);
+ if (xNamed->getName() == sFirstPage)
+ {
+ nStartSlide = i + 1;
+ break;
+ }
+ }
+
+ pFS->singleElementNS(XML_p, XML_sldRg, XML_st, OUString::number(nStartSlide), XML_end,
+ OUString::number(nEndSlide));
+ }
+
+ if (!sCustomShow.isEmpty())
+ {
+ css::uno::Reference<css::presentation::XCustomPresentationSupplier>
+ XCustPresentationSupplier(mXModel, css::uno::UNO_QUERY_THROW);
+ css::uno::Reference<css::container::XNameContainer> mxCustShows;
+ mxCustShows = XCustPresentationSupplier->getCustomPresentations();
+ const css::uno::Sequence<OUString> aNameSeq(mxCustShows->getElementNames());
+
+ sal_Int32 nCustShowIndex = 0;
+ for (sal_Int32 i = 0; i < aNameSeq.getLength(); i++)
+ {
+ if (aNameSeq[i] == sCustomShow)
+ {
+ nCustShowIndex = i;
+ break;
+ }
+ }
+
+ pFS->singleElementNS(XML_p, XML_custShow, XML_id, OUString::number(nCustShowIndex));
+ }
+
+ pFS->endElementNS(XML_p, XML_showPr);
+
+ pFS->endElementNS(XML_p, XML_presentationPr);
+}
+
+bool PowerPointExport::WriteComments(sal_uInt32 nPageNum)
+{
+ Reference< XAnnotationAccess > xAnnotationAccess(mXDrawPage, uno::UNO_QUERY);
+ if (xAnnotationAccess.is())
+ {
+ Reference< XAnnotationEnumeration > xAnnotationEnumeration(xAnnotationAccess->createAnnotationEnumeration());
+
+ if (xAnnotationEnumeration->hasMoreElements())
+ {
+ FSHelperPtr pFS = openFragmentStreamWithSerializer(
+ "ppt/comments/comment" + OUString::number(nPageNum + 1) + ".xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.comments+xml");
+
+ pFS->startElementNS(XML_p, XML_cmLst,
+ FSNS(XML_xmlns, XML_p), this->getNamespaceURL(OOX_NS(ppt)));
+
+ do
+ {
+ Reference< XAnnotation > xAnnotation(xAnnotationEnumeration->nextElement());
+ util::DateTime aDateTime(xAnnotation->getDateTime());
+ RealPoint2D aRealPoint2D(xAnnotation->getPosition());
+ Reference< XText > xText(xAnnotation->getTextRange());
+ sal_Int32 nLastIndex;
+ sal_Int32 nId = GetAuthorIdAndLastIndex(xAnnotation->getAuthor(), nLastIndex);
+ char cDateTime[sizeof("-32768-65535-65535T65535:65535:65535.4294967295")];
+ // reserve enough space for hypothetical max length
+
+ snprintf(cDateTime, sizeof cDateTime, "%02" SAL_PRIdINT32 "-%02" SAL_PRIuUINT32 "-%02" SAL_PRIuUINT32 "T%02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ".%09" SAL_PRIuUINT32, sal_Int32(aDateTime.Year), sal_uInt32(aDateTime.Month), sal_uInt32(aDateTime.Day), sal_uInt32(aDateTime.Hours), sal_uInt32(aDateTime.Minutes), sal_uInt32(aDateTime.Seconds), aDateTime.NanoSeconds);
+
+ pFS->startElementNS(XML_p, XML_cm,
+ XML_authorId, OString::number(nId),
+ XML_dt, cDateTime,
+ XML_idx, OString::number(nLastIndex));
+
+ pFS->singleElementNS(XML_p, XML_pos,
+ XML_x, OString::number(std::round(convertMm100ToMasterUnit(aRealPoint2D.X * 100))),
+ XML_y, OString::number(std::round(convertMm100ToMasterUnit(aRealPoint2D.Y * 100))));
+
+ pFS->startElementNS(XML_p, XML_text);
+ pFS->write(xText->getString());
+ pFS->endElementNS(XML_p, XML_text);
+
+ pFS->endElementNS(XML_p, XML_cm);
+
+ }
+ while (xAnnotationEnumeration->hasMoreElements());
+
+ pFS->endElementNS(XML_p, XML_cmLst);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void PowerPointExport::WriteVBA()
+{
+ if (!mbPptm)
+ return;
+
+ uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(getModel(), uno::UNO_QUERY);
+ if (!xStorageBasedDocument.is())
+ return;
+
+ uno::Reference<embed::XStorage> xDocumentStorage = xStorageBasedDocument->getDocumentStorage();
+ OUString aMacrosName("_MS_VBA_Macros");
+ if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aMacrosName))
+ return;
+
+ const sal_Int32 nOpenMode = embed::ElementModes::READ;
+ uno::Reference<io::XInputStream> xMacrosStream(xDocumentStorage->openStreamElement(aMacrosName, nOpenMode), uno::UNO_QUERY);
+ if (!xMacrosStream.is())
+ return;
+
+ uno::Reference<io::XOutputStream> xOutputStream = openFragmentStream("ppt/vbaProject.bin", "application/vnd.ms-office.vbaProject");
+ comphelper::OStorageHelper::CopyInputToOutput(xMacrosStream, xOutputStream);
+
+ // Write the relationship.
+ addRelation(mPresentationFS->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT), u"vbaProject.bin");
+}
+
+void PowerPointExport::WriteModifyVerifier()
+{
+ Sequence<PropertyValue> aInfo;
+
+ try
+ {
+ Reference<lang::XMultiServiceFactory> xFactory(mXModel, UNO_QUERY);
+ Reference<XPropertySet> xDocSettings(
+ xFactory->createInstance("com.sun.star.document.Settings"), UNO_QUERY);
+ xDocSettings->getPropertyValue("ModifyPasswordInfo") >>= aInfo;
+ }
+ catch (const Exception&)
+ {
+ }
+
+ if (aInfo.hasElements())
+ {
+ OUString sAlgorithm, sSalt, sHash;
+ sal_Int32 nCount = 0;
+ for (auto& prop : aInfo)
+ {
+ if (prop.Name == "algorithm-name")
+ prop.Value >>= sAlgorithm;
+ else if (prop.Name == "salt")
+ prop.Value >>= sSalt;
+ else if (prop.Name == "iteration-count")
+ prop.Value >>= nCount;
+ else if (prop.Name == "hash")
+ prop.Value >>= sHash;
+ }
+ if (!sAlgorithm.isEmpty() && !sSalt.isEmpty() && !sHash.isEmpty())
+ {
+ sal_Int32 nAlgorithmSid = 0;
+ if (sAlgorithm == "MD2")
+ nAlgorithmSid = 1;
+ else if (sAlgorithm == "MD4")
+ nAlgorithmSid = 2;
+ else if (sAlgorithm == "MD5")
+ nAlgorithmSid = 3;
+ else if (sAlgorithm == "SHA-1")
+ nAlgorithmSid = 4;
+ else if (sAlgorithm == "MAC")
+ nAlgorithmSid = 5;
+ else if (sAlgorithm == "RIPEMD")
+ nAlgorithmSid = 6;
+ else if (sAlgorithm == "RIPEMD-160")
+ nAlgorithmSid = 7;
+ else if (sAlgorithm == "HMAC")
+ nAlgorithmSid = 9;
+ else if (sAlgorithm == "SHA-256")
+ nAlgorithmSid = 12;
+ else if (sAlgorithm == "SHA-384")
+ nAlgorithmSid = 13;
+ else if (sAlgorithm == "SHA-512")
+ nAlgorithmSid = 14;
+
+ if (nAlgorithmSid != 0)
+ mPresentationFS->singleElementNS(XML_p, XML_modifyVerifier,
+ XML_cryptProviderType, "rsaAES",
+ XML_cryptAlgorithmClass, "hash",
+ XML_cryptAlgorithmType, "typeAny",
+ XML_cryptAlgorithmSid, OString::number(nAlgorithmSid).getStr(),
+ XML_spinCount, OString::number(nCount).getStr(),
+ XML_saltData, sSalt.toUtf8().getStr(),
+ XML_hashData, sHash.toUtf8().getStr());
+ }
+ }
+}
+
+void PowerPointExport::ImplWriteSlide(sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 /* nMode */,
+ bool bHasBackground, Reference< XPropertySet > const& aXBackgroundPropSet)
+{
+ SAL_INFO("sd.eppt", "write slide: " << nPageNum << "\n----------------");
+
+ // slides list
+ if (nPageNum == 0)
+ mPresentationFS->startElementNS(XML_p, XML_sldIdLst);
+
+ // add explicit relation of presentation to this slide
+ OUString sRelId = addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDE),
+ OUStringConcatenation("slides/slide" + OUString::number(nPageNum + 1) +".xml"));
+
+ mPresentationFS->singleElementNS(XML_p, XML_sldId,
+ XML_id, OString::number(GetNewSlideId()),
+ FSNS(XML_r, XML_id), sRelId);
+
+ maRelId.push_back(sRelId);
+
+ if (nPageNum == mnPages - 1)
+ mPresentationFS->endElementNS(XML_p, XML_sldIdLst);
+
+ FSHelperPtr pFS = openFragmentStreamWithSerializer(
+ "ppt/slides/slide" + OUString::number(nPageNum + 1) + ".xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.slide+xml");
+
+ if (mpSlidesFSArray.size() < mnPages)
+ mpSlidesFSArray.resize(mnPages);
+ mpSlidesFSArray[ nPageNum ] = pFS;
+
+ const char* pShow = nullptr;
+ const char* pShowMasterShape = nullptr;
+
+ if (ImplGetPropertyValue(mXPagePropSet, "Visible"))
+ {
+ bool bShow(false);
+ if ((mAny >>= bShow) && !bShow)
+ pShow = "0";
+ }
+
+ if (ImplGetPropertyValue(mXPagePropSet, "IsBackgroundObjectsVisible"))
+ {
+ bool bShowMasterShape(false);
+ if ((mAny >>= bShowMasterShape) && !bShowMasterShape)
+ pShowMasterShape = "0";
+ }
+
+ pFS->startElementNS(XML_p, XML_sld, PNMSS, XML_show, pShow, XML_showMasterSp, pShowMasterShape);
+
+ pFS->startElementNS(XML_p, XML_cSld);
+
+ // background
+ if (bHasBackground)
+ {
+ ImplWriteBackground(pFS, aXBackgroundPropSet);
+ }
+
+ WriteShapeTree(pFS, NORMAL, false);
+
+ pFS->endElementNS(XML_p, XML_cSld);
+
+ WriteTransition(pFS);
+ WriteAnimations(pFS, mXDrawPage, *this);
+
+ pFS->endElementNS(XML_p, XML_sld);
+
+ // add implicit relation to slide layout
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDELAYOUT),
+ OUStringConcatenation("../slideLayouts/slideLayout" +
+ OUString::number(GetLayoutFileId(GetPPTXLayoutId(GetLayoutOffset(mXPagePropSet)), nMasterNum)) +
+ ".xml"));
+
+ if (WriteComments(nPageNum))
+ // add implicit relation to slide comments
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::COMMENTS),
+ OUStringConcatenation("../comments/comment" + OUString::number(nPageNum + 1) + ".xml"));
+
+ SAL_INFO("sd.eppt", "----------------");
+}
+
+void PowerPointExport::ImplWriteNotes(sal_uInt32 nPageNum)
+{
+ if (!mbCreateNotes || !ContainsOtherShapeThanPlaceholders())
+ return;
+
+ SAL_INFO("sd.eppt", "write Notes " << nPageNum << "\n----------------");
+
+ FSHelperPtr pFS = openFragmentStreamWithSerializer(
+ "ppt/notesSlides/notesSlide" +
+ OUString::number(nPageNum + 1) +
+ ".xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml");
+
+ pFS->startElementNS(XML_p, XML_notes, PNMSS);
+
+ pFS->startElementNS(XML_p, XML_cSld);
+
+ WriteShapeTree(pFS, NOTICE, false);
+
+ pFS->endElementNS(XML_p, XML_cSld);
+
+ pFS->endElementNS(XML_p, XML_notes);
+
+ // add implicit relation to slide
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDE),
+ OUStringConcatenation("../slides/slide" + OUString::number(nPageNum + 1) + ".xml"));
+
+ // add slide implicit relation to notes
+ if (nPageNum < mpSlidesFSArray.size())
+ addRelation(mpSlidesFSArray[ nPageNum ]->getOutputStream(),
+ oox::getRelationship(Relationship::NOTESSLIDE),
+ OUStringConcatenation("../notesSlides/notesSlide" + OUString::number(nPageNum + 1) + ".xml"));
+
+ // add implicit relation to notes master
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::NOTESMASTER),
+ u"../notesMasters/notesMaster1.xml");
+
+ SAL_INFO("sd.eppt", "-----------------");
+}
+
+void PowerPointExport::AddLayoutIdAndRelation(const FSHelperPtr& pFS, sal_Int32 nLayoutFileId)
+{
+ // add implicit relation of slide master to slide layout
+ OUString sRelId = addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDELAYOUT),
+ OUStringConcatenation("../slideLayouts/slideLayout" + OUString::number(nLayoutFileId) + ".xml"));
+
+ pFS->singleElementNS(XML_p, XML_sldLayoutId,
+ XML_id, OString::number(GetNewSlideMasterId()),
+ FSNS(XML_r, XML_id), sRelId);
+}
+
+void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPropertySet > const& aXBackgroundPropSet)
+{
+ SAL_INFO("sd.eppt", "write master slide: " << nPageNum << "\n--------------");
+
+ // slides list
+ if (nPageNum == 0)
+ mPresentationFS->startElementNS(XML_p, XML_sldMasterIdLst);
+
+ OUString sRelId = addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDEMASTER),
+ OUStringConcatenation("slideMasters/slideMaster" + OUString::number(nPageNum + 1) + ".xml"));
+
+ mPresentationFS->singleElementNS(XML_p, XML_sldMasterId,
+ XML_id, OString::number(GetNewSlideMasterId()),
+ FSNS(XML_r, XML_id), sRelId);
+
+ if (nPageNum == mnMasterPages - 1)
+ mPresentationFS->endElementNS(XML_p, XML_sldMasterIdLst);
+
+ FSHelperPtr pFS =
+ openFragmentStreamWithSerializer("ppt/slideMasters/slideMaster" +
+ OUString::number(nPageNum + 1) + ".xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml");
+
+ SdrPage* pMasterPage = SdPage::getImplementation(mXDrawPage);
+ svx::Theme* pTheme = nullptr;
+ if (pMasterPage)
+ {
+ pTheme = pMasterPage->getSdrPageProperties().GetTheme();
+ }
+
+ // write theme per master
+ WriteTheme(nPageNum, pTheme);
+
+ // add implicit relation to the presentation theme
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::THEME),
+ OUStringConcatenation("../theme/theme" + OUString::number(nPageNum + 1) + ".xml"));
+
+ pFS->startElementNS(XML_p, XML_sldMaster, PNMSS);
+
+ pFS->startElementNS(XML_p, XML_cSld);
+
+ if (aXBackgroundPropSet)
+ ImplWriteBackground(pFS, aXBackgroundPropSet);
+ WriteShapeTree(pFS, MASTER, true);
+
+ pFS->endElementNS(XML_p, XML_cSld);
+
+ // color map - now it uses colors from hardcoded theme, once we eventually generate theme, this might need update
+ pFS->singleElementNS(XML_p, XML_clrMap,
+ XML_bg1, "lt1",
+ XML_bg2, "lt2",
+ XML_tx1, "dk1",
+ XML_tx2, "dk2",
+ XML_accent1, "accent1",
+ XML_accent2, "accent2",
+ XML_accent3, "accent3",
+ XML_accent4, "accent4",
+ XML_accent5, "accent5",
+ XML_accent6, "accent6",
+ XML_hlink, "hlink",
+ XML_folHlink, "folHlink");
+
+ // use master's id type as they have same range, mso does that as well
+ pFS->startElementNS(XML_p, XML_sldLayoutIdLst);
+
+ for (int i = 0; i < LAYOUT_SIZE; i++)
+ {
+ sal_Int32 nLayoutFileId = GetLayoutFileId(i, nPageNum);
+ if (nLayoutFileId > 0)
+ {
+ AddLayoutIdAndRelation(pFS, nLayoutFileId);
+ }
+ else
+ {
+ ImplWritePPTXLayout(i, nPageNum);
+ AddLayoutIdAndRelation(pFS, GetLayoutFileId(i, nPageNum));
+ }
+ }
+
+ pFS->endElementNS(XML_p, XML_sldLayoutIdLst);
+
+ pFS->endElementNS(XML_p, XML_sldMaster);
+
+ SAL_INFO("sd.eppt", "----------------");
+}
+
+sal_Int32 PowerPointExport::GetLayoutFileId(sal_Int32 nOffset, sal_uInt32 nMasterNum)
+{
+ SAL_INFO("sd.eppt", "GetLayoutFileId offset: " << nOffset << " master: " << nMasterNum);
+ if (mLayoutInfo[ nOffset ].mnFileIdArray.size() <= nMasterNum)
+ return 0;
+
+ return mLayoutInfo[ nOffset ].mnFileIdArray[ nMasterNum ];
+}
+
+void PowerPointExport::ImplWritePPTXLayout(sal_Int32 nOffset, sal_uInt32 nMasterNum)
+{
+ SAL_INFO("sd.eppt", "write layout: " << nOffset);
+
+ Reference< drawing::XDrawPagesSupplier > xDPS(getModel(), uno::UNO_QUERY);
+ Reference< drawing::XDrawPages > xDrawPages = xDPS->getDrawPages();
+ Reference< drawing::XDrawPage > xSlide = xDrawPages->insertNewByIndex(xDrawPages->getCount());
+
+#ifdef DEBUG
+ if (xSlide.is())
+ printf("new page created\n");
+#endif
+
+ Reference< beans::XPropertySet > xPropSet(xSlide, uno::UNO_QUERY);
+ xPropSet->setPropertyValue("Layout", Any(short(aLayoutInfo[ nOffset ].nType)));
+#if OSL_DEBUG_LEVEL > 1
+ dump_pset(xPropSet);
+#endif
+ mXPagePropSet.set(xSlide, UNO_QUERY);
+ mXShapes = xSlide;
+
+ if (mLayoutInfo[ nOffset ].mnFileIdArray.size() < mnMasterPages)
+ {
+ mLayoutInfo[ nOffset ].mnFileIdArray.resize(mnMasterPages);
+ }
+
+ if (mLayoutInfo[ nOffset ].mnFileIdArray[ nMasterNum ] != 0)
+ return;
+
+ FSHelperPtr pFS
+ = openFragmentStreamWithSerializer("ppt/slideLayouts/slideLayout" +
+ OUString::number(mnLayoutFileIdMax) + ".xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml");
+
+ // add implicit relation of slide layout to slide master
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDEMASTER),
+ OUStringConcatenation("../slideMasters/slideMaster" + OUString::number(nMasterNum + 1) + ".xml"));
+
+ pFS->startElementNS(XML_p, XML_sldLayout,
+ PNMSS,
+ XML_type, aLayoutInfo[ nOffset ].sType,
+ XML_preserve, "1");
+
+ pFS->startElementNS(XML_p, XML_cSld,
+ XML_name, aLayoutInfo[ nOffset ].sName);
+ //pFS->write( MINIMAL_SPTREE ); // TODO: write actual shape tree
+ WriteShapeTree(pFS, LAYOUT, true);
+
+ pFS->endElementNS(XML_p, XML_cSld);
+
+ pFS->endElementNS(XML_p, XML_sldLayout);
+
+ mLayoutInfo[ nOffset ].mnFileIdArray[ nMasterNum ] = mnLayoutFileIdMax;
+
+ mnLayoutFileIdMax ++;
+
+ xDrawPages->remove(xSlide);
+}
+
+void PowerPointExport::WriteShapeTree(const FSHelperPtr& pFS, PageType ePageType, bool bMaster)
+{
+ PowerPointShapeExport aDML(pFS, &maShapeMap, this);
+ aDML.SetMaster(bMaster);
+ aDML.SetPageType(ePageType);
+ aDML.SetBackgroundDark(mbIsBackgroundDark);
+
+ pFS->startElementNS(XML_p, XML_spTree);
+ pFS->write(MAIN_GROUP);
+
+ ResetGroupTable(mXShapes->getCount());
+
+ while (GetNextGroupEntry())
+ {
+
+ sal_uInt32 nGroups = GetGroupsClosed();
+ for (sal_uInt32 i = 0; i < nGroups; i++)
+ {
+ SAL_INFO("sd.eppt", "leave group");
+ }
+
+ if (GetShapeByIndex(GetCurrentGroupIndex(), true))
+ {
+ SAL_INFO("sd.eppt", "mType: " << mType);
+ const SdrObjGroup* pDiagramCandidate(dynamic_cast<const SdrObjGroup*>(SdrObject::getSdrObjectFromXShape(mXShape)));
+ const bool bIsDiagram(nullptr != pDiagramCandidate && pDiagramCandidate->isDiagram());
+
+ if (bIsDiagram)
+ WriteDiagram(pFS, aDML, mXShape, mnDiagramId++);
+ else
+ aDML.WriteShape(mXShape);
+ }
+ }
+
+ if ( ePageType == NORMAL || ePageType == LAYOUT )
+ WritePlaceholderReferenceShapes(aDML, ePageType);
+ pFS->endElementNS(XML_p, XML_spTree);
+}
+
+ShapeExport& PowerPointShapeExport::WritePageShape(const Reference< XShape >& xShape, PageType ePageType, bool bPresObj)
+{
+ if ((ePageType == NOTICE && bPresObj) || ePageType == LAYOUT || ePageType == MASTER)
+ return WritePlaceholderShape(xShape, SlideImage);
+
+ return WriteTextShape(xShape);
+}
+
+bool PowerPointShapeExport::WritePlaceholder(const Reference< XShape >& xShape, PlaceholderType ePlaceholder, bool bMaster)
+{
+ SAL_INFO("sd.eppt", "WritePlaceholder " << bMaster << " " << ShapeExport::NonEmptyText(xShape));
+ if (!xShape)
+ return false;
+ try
+ {
+ Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
+ if (xShapeProps->getPropertyValue("IsPresentationObject").get<bool>())
+ {
+ WritePlaceholderShape(xShape, ePlaceholder);
+
+ return true;
+ }
+ }
+ catch (Exception&)
+ {
+ return false;
+ }
+ return false;
+}
+
+ShapeExport& PowerPointShapeExport::WritePlaceholderShape(const Reference< XShape >& xShape, PlaceholderType ePlaceholder)
+{
+ Reference<XPropertySet> xProps(xShape, UNO_QUERY);
+ bool bUseBackground(false);
+ if (xProps.is() && xProps->getPropertySetInfo()->hasPropertyByName("FillUseSlideBackground"))
+ xProps->getPropertyValue("FillUseSlideBackground") >>= bUseBackground;
+
+ if (bUseBackground)
+ mpFS->startElementNS(XML_p, XML_sp, XML_useBgFill, "1");
+ else
+ mpFS->startElementNS(XML_p, XML_sp);
+
+ // non visual shape properties
+ mpFS->startElementNS(XML_p, XML_nvSpPr);
+ const OString aPlaceholderID("PlaceHolder " + OString::number(mnShapeIdMax++));
+ WriteNonVisualDrawingProperties(xShape, aPlaceholderID.getStr());
+ mpFS->startElementNS(XML_p, XML_cNvSpPr);
+ mpFS->singleElementNS(XML_a, XML_spLocks, XML_noGrp, "1");
+ mpFS->endElementNS(XML_p, XML_cNvSpPr);
+ mpFS->startElementNS(XML_p, XML_nvPr);
+
+ bool bUsePlaceholderIndex
+ = ePlaceholder == Footer || ePlaceholder == DateAndTime || ePlaceholder == SlideNumber;
+ const char* pType = getPlaceholderTypeName(ePlaceholder);
+
+ SAL_INFO("sd.eppt", "write placeholder " << pType);
+ if (bUsePlaceholderIndex)
+ {
+ mpFS->singleElementNS(
+ XML_p, XML_ph, XML_type, pType, XML_idx,
+ OString::number(
+ static_cast<PowerPointExport*>(GetFB())->CreateNewPlaceholderIndex(xShape)));
+ }
+ else
+ {
+ if ((mePageType == PageType::LAYOUT || mePageType == PageType::NORMAL)
+ && ePlaceholder == Outliner)
+ mpFS->singleElementNS(XML_p, XML_ph);
+ else
+ mpFS->singleElementNS(XML_p, XML_ph, XML_type, pType);
+ }
+ mpFS->endElementNS(XML_p, XML_nvPr);
+ mpFS->endElementNS(XML_p, XML_nvSpPr);
+
+ // visual shape properties
+ mpFS->startElementNS(XML_p, XML_spPr);
+ WriteShapeTransformation(xShape, XML_a);
+ WritePresetShape("rect");
+ if (xProps.is())
+ {
+ WriteBlipFill(xProps, "Graphic");
+ // Do not forget to export the visible properties.
+ WriteFill( xProps );
+ WriteOutline( xProps );
+ WriteShapeEffects( xProps );
+
+ bool bHas3DEffectinShape = false;
+ uno::Sequence<beans::PropertyValue> grabBag;
+ if (xProps->getPropertySetInfo()->hasPropertyByName("InteropGrabBag"))
+ xProps->getPropertyValue("InteropGrabBag") >>= grabBag;
+
+ for (auto const& it : std::as_const(grabBag))
+ if (it.Name == "3DEffectProperties")
+ bHas3DEffectinShape = true;
+
+ if( bHas3DEffectinShape)
+ Write3DEffects( xProps, /*bIsText=*/false );
+ }
+ mpFS->endElementNS(XML_p, XML_spPr);
+
+ WriteTextBox(xShape, XML_p, /*bWritePropertiesAsLstStyles=*/bUsePlaceholderIndex);
+
+ mpFS->endElementNS(XML_p, XML_sp);
+
+ return *this;
+}
+
+ShapeExport& PowerPointShapeExport::WritePlaceholderReferenceShape(
+ PlaceholderType ePlaceholder, sal_Int32 nReferencedPlaceholderIdx, PageType ePageType,
+ const Reference<XPropertySet>& rXPagePropSet)
+{
+ mpFS->startElementNS(XML_p, XML_sp);
+
+ // non visual shape properties
+ mpFS->startElementNS(XML_p, XML_nvSpPr);
+ const OString aPlaceholderID("PlaceHolder " + OString::number(mnShapeIdMax++));
+ GetFS()->singleElementNS(XML_p, XML_cNvPr, XML_id, OString::number(mnShapeIdMax), XML_name,
+ aPlaceholderID.getStr());
+
+ mpFS->startElementNS(XML_p, XML_cNvSpPr);
+ mpFS->singleElementNS(XML_a, XML_spLocks, XML_noGrp, "1");
+ mpFS->endElementNS(XML_p, XML_cNvSpPr);
+ mpFS->startElementNS(XML_p, XML_nvPr);
+
+ const char* pType = getPlaceholderTypeName(ePlaceholder);
+ mpFS->singleElementNS(XML_p, XML_ph, XML_type, pType, XML_idx,
+ OString::number(nReferencedPlaceholderIdx));
+ mpFS->endElementNS(XML_p, XML_nvPr);
+ mpFS->endElementNS(XML_p, XML_nvSpPr);
+
+ // visual shape properties
+ mpFS->startElementNS(XML_p, XML_spPr);
+ mpFS->endElementNS(XML_p, XML_spPr);
+
+ WritePlaceholderReferenceTextBody(ePlaceholder, ePageType, rXPagePropSet);
+
+ mpFS->endElementNS(XML_p, XML_sp);
+
+ return *this;
+}
+
+ShapeExport& PowerPointShapeExport::WritePlaceholderReferenceTextBody(
+ PlaceholderType ePlaceholder, PageType ePageType, const Reference<XPropertySet> xPagePropSet)
+{
+ mpFS->startElementNS(XML_p, XML_txBody);
+ mpFS->singleElementNS(XML_a, XML_bodyPr);
+ mpFS->startElementNS(XML_a, XML_p);
+
+ switch (ePlaceholder)
+ {
+ case Header:
+ break;
+ case Footer:
+ {
+ OUString aFooterText;
+ if (ePageType == LAYOUT)
+ {
+ aFooterText = "Footer";
+ }
+ else
+ {
+ xPagePropSet->getPropertyValue("FooterText") >>= aFooterText;
+ }
+ mpFS->startElementNS(XML_a, XML_r);
+ mpFS->startElementNS(XML_a, XML_t);
+ mpFS->writeEscaped(aFooterText);
+ mpFS->endElementNS(XML_a, XML_t);
+ mpFS->endElementNS(XML_a, XML_r);
+ break;
+ }
+ case SlideNumber:
+ {
+ OUString aSlideNum;
+ sal_Int32 nSlideNum = 0;
+ if (ePageType == LAYOUT)
+ {
+ aSlideNum = "<#>";
+ }
+ else
+ {
+ xPagePropSet->getPropertyValue("Number") >>= nSlideNum;
+ aSlideNum = OUString::number(nSlideNum);
+ }
+ OString aUUID(comphelper::xml::generateGUIDString());
+ mpFS->startElementNS(XML_a, XML_fld, XML_id, aUUID.getStr(), XML_type, "slidenum");
+ mpFS->startElementNS(XML_a, XML_t);
+ mpFS->writeEscaped(aSlideNum);
+ mpFS->endElementNS(XML_a, XML_t);
+ mpFS->endElementNS(XML_a, XML_fld);
+ break;
+ }
+ case DateAndTime:
+ {
+ OUString aDateTimeType = "datetime1";
+ bool bIsDateTimeFixed = false;
+ xPagePropSet->getPropertyValue("IsDateTimeFixed") >>= bIsDateTimeFixed;
+
+ OUString aDateTimeText = "Date";
+ const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag();
+
+ if(ePageType != LAYOUT && !bIsDateTimeFixed)
+ {
+ sal_Int32 nDateTimeFormat = 0;
+ xPagePropSet->getPropertyValue("DateTimeFormat") >>= nDateTimeFormat;
+
+ // 4 LSBs represent the date
+ SvxDateFormat eDate = static_cast<SvxDateFormat>(nDateTimeFormat & 0x0f);
+ // the 4 bits after the date bits represent the time
+ SvxTimeFormat eTime = static_cast<SvxTimeFormat>(nDateTimeFormat >> 4);
+ aDateTimeType = GetDatetimeTypeFromDateTime(eDate, eTime);
+
+ if (aDateTimeType == "datetime")
+ aDateTimeType = "datetime1";
+
+ ::DateTime aDateTime( ::DateTime::SYSTEM );
+
+ aDateTimeText = SvxDateTimeField::GetFormatted(
+ aDateTime, aDateTime, eDate,
+ eTime, *(SD_MOD()->GetNumberFormatter()),
+ rLanguageTag.getLanguageType());
+ }
+
+ if(!bIsDateTimeFixed)
+ {
+ OString aUUID(comphelper::xml::generateGUIDString());
+ mpFS->startElementNS(XML_a, XML_fld, XML_id, aUUID.getStr(), XML_type, aDateTimeType);
+ }
+ else
+ {
+ xPagePropSet->getPropertyValue("DateTimeText") >>= aDateTimeText;
+ mpFS->startElementNS(XML_a, XML_r);
+ }
+
+ mpFS->startElementNS(XML_a, XML_rPr, XML_lang, rLanguageTag.getBcp47MS());
+ mpFS->endElementNS(XML_a, XML_rPr);
+
+ mpFS->startElementNS(XML_a, XML_t);
+ mpFS->writeEscaped(aDateTimeText);
+ mpFS->endElementNS(XML_a, XML_t);
+
+ mpFS->endElementNS(XML_a, bIsDateTimeFixed ? XML_r : XML_fld);
+ break;
+ }
+ default:
+ SAL_INFO("sd.eppt", "warning: no defined textbody for referenced placeholder type: "
+ << ePlaceholder);
+ }
+ mpFS->endElementNS(XML_a, XML_p);
+ mpFS->endElementNS(XML_p, XML_txBody);
+
+ return *this;
+}
+
+#define SYS_COLOR_SCHEMES " <a:dk1>\
+ <a:sysClr val=\"windowText\" lastClr=\"000000\"/>\
+ </a:dk1>\
+ <a:lt1>\
+ <a:sysClr val=\"window\" lastClr=\"FFFFFF\"/>\
+ </a:lt1>"
+
+#define MINIMAL_THEME " <a:fontScheme name=\"Office\">\
+ <a:majorFont>\
+ <a:latin typeface=\"Arial\"/>\
+ <a:ea typeface=\"DejaVu Sans\"/>\
+ <a:cs typeface=\"DejaVu Sans\"/>\
+ </a:majorFont>\
+ <a:minorFont>\
+ <a:latin typeface=\"Arial\"/>\
+ <a:ea typeface=\"DejaVu Sans\"/>\
+ <a:cs typeface=\"DejaVu Sans\"/>\
+ </a:minorFont>\
+ </a:fontScheme>\
+ <a:fmtScheme name=\"Office\">\
+ <a:fillStyleLst>\
+ <a:solidFill>\
+ <a:schemeClr val=\"phClr\"/>\
+ </a:solidFill>\
+ <a:gradFill rotWithShape=\"1\">\
+ <a:gsLst>\
+ <a:gs pos=\"0\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"50000\"/>\
+ <a:satMod val=\"300000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"35000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"37000\"/>\
+ <a:satMod val=\"300000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"100000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"15000\"/>\
+ <a:satMod val=\"350000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ </a:gsLst>\
+ <a:lin ang=\"16200000\" scaled=\"1\"/>\
+ </a:gradFill>\
+ <a:gradFill rotWithShape=\"1\">\
+ <a:gsLst>\
+ <a:gs pos=\"0\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"51000\"/>\
+ <a:satMod val=\"130000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"80000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"93000\"/>\
+ <a:satMod val=\"130000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"100000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"94000\"/>\
+ <a:satMod val=\"135000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ </a:gsLst>\
+ <a:lin ang=\"16200000\" scaled=\"0\"/>\
+ </a:gradFill>\
+ </a:fillStyleLst>\
+ <a:lnStyleLst>\
+ <a:ln w=\"6350\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\
+ <a:solidFill>\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"95000\"/>\
+ <a:satMod val=\"105000\"/>\
+ </a:schemeClr>\
+ </a:solidFill>\
+ <a:prstDash val=\"solid\"/>\
+ <a:miter/>\
+ </a:ln>\
+ <a:ln w=\"12700\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\
+ <a:solidFill>\
+ <a:schemeClr val=\"phClr\"/>\
+ </a:solidFill>\
+ <a:prstDash val=\"solid\"/>\
+ <a:miter/>\
+ </a:ln>\
+ <a:ln w=\"19050\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\
+ <a:solidFill>\
+ <a:schemeClr val=\"phClr\"/>\
+ </a:solidFill>\
+ <a:prstDash val=\"solid\"/>\
+ <a:miter/>\
+ </a:ln>\
+ </a:lnStyleLst>\
+ <a:effectStyleLst>\
+ <a:effectStyle>\
+ <a:effectLst/>\
+ </a:effectStyle>\
+ <a:effectStyle>\
+ <a:effectLst/>\
+ </a:effectStyle>\
+ <a:effectStyle>\
+ <a:effectLst>\
+ <a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">\
+ <a:srgbClr val=\"000000\">\
+ <a:alpha val=\"35000\"/>\
+ </a:srgbClr>\
+ </a:outerShdw>\
+ </a:effectLst>\
+ <a:scene3d>\
+ <a:camera prst=\"orthographicFront\">\
+ <a:rot lat=\"0\" lon=\"0\" rev=\"0\"/>\
+ </a:camera>\
+ <a:lightRig rig=\"threePt\" dir=\"t\">\
+ <a:rot lat=\"0\" lon=\"0\" rev=\"1200000\"/>\
+ </a:lightRig>\
+ </a:scene3d>\
+ <a:sp3d>\
+ <a:bevelT w=\"63500\" h=\"25400\"/>\
+ </a:sp3d>\
+ </a:effectStyle>\
+ </a:effectStyleLst>\
+ <a:bgFillStyleLst>\
+ <a:solidFill>\
+ <a:schemeClr val=\"phClr\"/>\
+ </a:solidFill>\
+ <a:gradFill rotWithShape=\"1\">\
+ <a:gsLst>\
+ <a:gs pos=\"0\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"40000\"/>\
+ <a:satMod val=\"350000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"40000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"45000\"/>\
+ <a:shade val=\"99000\"/>\
+ <a:satMod val=\"350000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"100000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"20000\"/>\
+ <a:satMod val=\"255000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ </a:gsLst>\
+ <a:path path=\"circle\">\
+ <a:fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\"/>\
+ </a:path>\
+ </a:gradFill>\
+ <a:gradFill rotWithShape=\"1\">\
+ <a:gsLst>\
+ <a:gs pos=\"0\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"80000\"/>\
+ <a:satMod val=\"300000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"100000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"30000\"/>\
+ <a:satMod val=\"200000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ </a:gsLst>\
+ <a:path path=\"circle\">\
+ <a:fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\"/>\
+ </a:path>\
+ </a:gradFill>\
+ </a:bgFillStyleLst>\
+ </a:fmtScheme>"
+
+void PowerPointExport::WriteDefaultColorSchemes(const FSHelperPtr& pFS)
+{
+ for (int nId = PredefinedClrSchemeId::dk2; nId != PredefinedClrSchemeId::Count; nId++)
+ {
+ OUString sName = PredefinedClrNames[static_cast<PredefinedClrSchemeId>(nId)];
+ sal_Int32 nColor = 0;
+
+ switch (nId)
+ {
+ case PredefinedClrSchemeId::dk2:
+ nColor = 0x1F497D;
+ break;
+ case PredefinedClrSchemeId::lt2:
+ nColor = 0xEEECE1;
+ break;
+ case PredefinedClrSchemeId::accent1:
+ nColor = 0x4F81BD;
+ break;
+ case PredefinedClrSchemeId::accent2:
+ nColor = 0xC0504D;
+ break;
+ case PredefinedClrSchemeId::accent3:
+ nColor = 0x9BBB59;
+ break;
+ case PredefinedClrSchemeId::accent4:
+ nColor = 0x8064A2;
+ break;
+ case PredefinedClrSchemeId::accent5:
+ nColor = 0x4BACC6;
+ break;
+ case PredefinedClrSchemeId::accent6:
+ nColor = 0xF79646;
+ break;
+ case PredefinedClrSchemeId::hlink:
+ nColor = 0x0000FF;
+ break;
+ case PredefinedClrSchemeId::folHlink:
+ nColor = 0x800080;
+ break;
+ }
+
+ OUString sOpenColorScheme = "<a:" + sName + ">";
+ pFS->write(sOpenColorScheme);
+
+ pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nColor));
+
+ OUString sCloseColorScheme = "</a:" + sName + ">";
+ pFS->write(sCloseColorScheme);
+ }
+}
+
+bool PowerPointExport::WriteColorSets(const FSHelperPtr& pFS, svx::Theme* pTheme)
+{
+ static std::map<PredefinedClrSchemeId, sal_Int32> aPredefinedClrTokens =
+ {
+ { dk1, XML_dk1 },
+ { lt1, XML_lt1 },
+ { dk2, XML_dk2 },
+ { lt2, XML_lt2 },
+ { accent1, XML_accent1 },
+ { accent2, XML_accent2 },
+ { accent3, XML_accent3 },
+ { accent4, XML_accent4 },
+ { accent5, XML_accent5 },
+ { accent6, XML_accent6 },
+ { hlink, XML_hlink },
+ { folHlink, XML_folHlink }
+ };
+
+ if (!pTheme)
+ {
+ return false;
+ }
+
+ svx::ColorSet* pColorSet = pTheme->GetColorSet();
+ if (!pColorSet)
+ {
+ return false;
+ }
+
+ for (int nId = PredefinedClrSchemeId::dk1; nId < PredefinedClrSchemeId::Count; nId++)
+ {
+ sal_Int32 nToken = aPredefinedClrTokens[static_cast<PredefinedClrSchemeId>(nId)];
+ pFS->startElementNS(XML_a, nToken);
+ pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(static_cast<sal_Int32>(pColorSet->getColor(nId))));
+ pFS->endElementNS(XML_a, nToken);
+ }
+
+ return true;
+}
+
+bool PowerPointExport::WriteColorSchemes(const FSHelperPtr& pFS, const OUString& rThemePath)
+{
+ try
+ {
+ uno::Reference<beans::XPropertySet> xDocProps(getModel(), uno::UNO_QUERY);
+ if (xDocProps.is())
+ {
+ uno::Reference<beans::XPropertySetInfo> xPropsInfo = xDocProps->getPropertySetInfo();
+
+ static const OUStringLiteral aGrabBagPropName = u"InteropGrabBag";
+ if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(aGrabBagPropName))
+ {
+ comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue(aGrabBagPropName));
+ uno::Sequence<beans::PropertyValue> aCurrentTheme;
+
+ aGrabBag.getValue(rThemePath) >>= aCurrentTheme;
+
+ if (!aCurrentTheme.hasElements())
+ return false;
+
+ // Order is important
+ for (int nId = PredefinedClrSchemeId::dk2; nId != PredefinedClrSchemeId::Count; nId++)
+ {
+ OUString sName = PredefinedClrNames[static_cast<PredefinedClrSchemeId>(nId)];
+ sal_Int32 nColor = 0;
+
+ for (auto aIt = std::cbegin(aCurrentTheme); aIt != std::cend(aCurrentTheme); aIt++)
+ {
+ if (aIt->Name == sName)
+ {
+ aIt->Value >>= nColor;
+ break;
+ }
+ }
+
+ OUString sOpenColorScheme ="<a:" + sName + ">";
+ pFS->write(sOpenColorScheme);
+
+ pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nColor));
+
+ OUString sCloseColorScheme = "</a:" + sName + ">";
+ pFS->write(sCloseColorScheme);
+ }
+
+ // TODO: write complete color schemes & only if successful, protection against partial export
+ return true;
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ SAL_WARN("writerfilter", "Failed to save documents grab bag");
+ }
+
+ return false;
+}
+
+void PowerPointExport::WriteTheme(sal_Int32 nThemeNum, svx::Theme* pTheme)
+{
+ OUString sThemePath = "ppt/theme/theme" + OUString::number(nThemeNum + 1) + ".xml";
+
+ FSHelperPtr pFS = openFragmentStreamWithSerializer(sThemePath,
+ "application/vnd.openxmlformats-officedocument.theme+xml");
+
+ OUString aThemeName("Office Theme");
+ if (pTheme)
+ {
+ aThemeName = pTheme->GetName();
+ }
+ pFS->startElementNS(XML_a, XML_theme,
+ FSNS(XML_xmlns, XML_a), this->getNamespaceURL(OOX_NS(dml)),
+ XML_name, aThemeName);
+
+ pFS->startElementNS(XML_a, XML_themeElements);
+ OUString aColorSchemeName("Office");
+ if (pTheme)
+ {
+ svx::ColorSet* pColorSet = pTheme->GetColorSet();
+ if (pColorSet)
+ {
+ aColorSchemeName = pColorSet->getName();
+ }
+ }
+ pFS->startElementNS(XML_a, XML_clrScheme, XML_name, aColorSchemeName);
+
+ if (!WriteColorSets(pFS, pTheme))
+ {
+ pFS->write(SYS_COLOR_SCHEMES);
+ if (!WriteColorSchemes(pFS, sThemePath))
+ {
+ // if style is not defined, try to use first one
+ if (!WriteColorSchemes(pFS, "ppt/theme/theme1.xml"))
+ {
+ // color schemes are required - use default values
+ WriteDefaultColorSchemes(pFS);
+ }
+ }
+ }
+
+ pFS->endElementNS(XML_a, XML_clrScheme);
+
+ // export remaining part
+ pFS->write(MINIMAL_THEME);
+
+ pFS->endElementNS(XML_a, XML_themeElements);
+ pFS->endElementNS(XML_a, XML_theme);
+}
+
+bool PowerPointExport::ImplCreateDocument()
+{
+ mbCreateNotes = false;
+
+ for (sal_uInt32 i = 0; i < mnPages; i++)
+ {
+ if (!GetPageByIndex(i, NOTICE))
+ return false;
+
+ if (ContainsOtherShapeThanPlaceholders())
+ {
+ mbCreateNotes = true;
+ break;
+ }
+ }
+
+ return true;
+}
+
+void PowerPointExport::WriteNotesMaster()
+{
+ SAL_INFO("sd.eppt", "write Notes master\n---------------");
+
+ mPresentationFS->startElementNS(XML_p, XML_notesMasterIdLst);
+
+ OUString sRelId = addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::NOTESMASTER),
+ u"notesMasters/notesMaster1.xml");
+
+ mPresentationFS->singleElementNS(XML_p, XML_notesMasterId,
+ FSNS(XML_r, XML_id), sRelId);
+
+ mPresentationFS->endElementNS(XML_p, XML_notesMasterIdLst);
+
+ FSHelperPtr pFS =
+ openFragmentStreamWithSerializer("ppt/notesMasters/notesMaster1.xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml");
+ // write theme per master
+ WriteTheme(mnMasterPages, nullptr);
+
+ // add implicit relation to the presentation theme
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::THEME),
+ OUStringConcatenation("../theme/theme" + OUString::number(mnMasterPages + 1) + ".xml"));
+
+ pFS->startElementNS(XML_p, XML_notesMaster, PNMSS);
+
+ pFS->startElementNS(XML_p, XML_cSld);
+
+ Reference< XPropertySet > aXBackgroundPropSet;
+ if (ImplGetPropertyValue(mXPagePropSet, "Background") &&
+ (mAny >>= aXBackgroundPropSet))
+ ImplWriteBackground(pFS, aXBackgroundPropSet);
+
+ WriteShapeTree(pFS, NOTICE, true);
+
+ pFS->endElementNS(XML_p, XML_cSld);
+
+ // color map - now it uses colors from hardcoded theme, once we eventually generate theme, this might need update
+ pFS->singleElementNS(XML_p, XML_clrMap,
+ XML_bg1, "lt1",
+ XML_bg2, "lt2",
+ XML_tx1, "dk1",
+ XML_tx2, "dk2",
+ XML_accent1, "accent1",
+ XML_accent2, "accent2",
+ XML_accent3, "accent3",
+ XML_accent4, "accent4",
+ XML_accent5, "accent5",
+ XML_accent6, "accent6",
+ XML_hlink, "hlink",
+ XML_folHlink, "folHlink");
+
+ pFS->endElementNS(XML_p, XML_notesMaster);
+
+ SAL_INFO("sd.eppt", "----------------");
+}
+
+void PowerPointExport::embedEffectAudio(const FSHelperPtr& pFS, const OUString& sUrl, OUString& sRelId, OUString& sName)
+{
+ comphelper::LifecycleProxy aProxy;
+
+ if (!sUrl.endsWithIgnoreAsciiCase(".wav"))
+ return;
+
+ uno::Reference<io::XInputStream> xAudioStream;
+ try
+ {
+ if (sUrl.startsWith("vnd.sun.star.Package:"))
+ {
+ uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(getModel(), uno::UNO_QUERY);
+ if (!xStorageBasedDocument.is())
+ return;
+
+ uno::Reference<embed::XStorage> xDocumentStorage = xStorageBasedDocument->getDocumentStorage();
+ if (!xDocumentStorage.is())
+ return;
+
+ uno::Reference<io::XStream> xStream = comphelper::OStorageHelper::GetStreamAtPackageURL(xDocumentStorage, sUrl,
+ css::embed::ElementModes::READ, aProxy);
+
+ if (xStream.is())
+ xAudioStream = xStream->getInputStream();
+ }
+ else
+ xAudioStream = comphelper::OStorageHelper::GetInputStreamFromURL(sUrl, getComponentContext());
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sd", "PowerPointExport::embedEffectAudio");
+ }
+
+ if (!xAudioStream.is())
+ return;
+
+ int nLastSlash = sUrl.lastIndexOf('/');
+ sName = sUrl.copy(nLastSlash >= 0 ? nLastSlash + 1 : 0);
+
+ OUString sPath = "../media/" + sName;
+ sRelId = addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::AUDIO), sPath);
+
+ uno::Reference<io::XOutputStream> xOutputStream = openFragmentStream(sPath.replaceAt(0, 2, u"/ppt"),
+ "audio/x-wav");
+
+ comphelper::OStorageHelper::CopyInputToOutput(xAudioStream, xOutputStream);
+}
+
+sal_Int32 PowerPointExport::GetShapeID(const Reference<XShape>& rXShape)
+{
+ return ShapeExport::GetShapeID(rXShape, &maShapeMap);
+}
+
+sal_Int32 PowerPointExport::GetNextAnimationNodeID()
+{
+ return mnAnimationNodeIdMax++;
+}
+
+bool PowerPointExport::ImplCreateMainNotes()
+{
+ if (mbCreateNotes)
+ WriteNotesMaster();
+
+ return true;
+}
+
+OUString PowerPointExport::getImplementationName()
+{
+ return "com.sun.star.comp.Impress.oox.PowerPointExport";
+}
+
+void PowerPointExport::WriteDiagram(const FSHelperPtr& pFS, PowerPointShapeExport& rDML, const css::uno::Reference<css::drawing::XShape>& rXShape, int nDiagramId)
+{
+ SAL_INFO("sd.eppt", "writing Diagram " + OUString::number(nDiagramId));
+ pFS->startElementNS(XML_p, XML_graphicFrame);
+ rDML.WriteDiagram(rXShape, nDiagramId);
+ pFS->endElementNS(XML_p, XML_graphicFrame);
+}
+
+void PowerPointExport::WritePlaceholderReferenceShapes(PowerPointShapeExport& rDML, PageType ePageType)
+{
+ bool bCheckProps = ePageType == NORMAL;
+ Reference<XShape> xShape;
+ Any aAny;
+ OUString aText;
+ if (ePageType == LAYOUT
+ || (bCheckProps && PropValue::GetPropertyValue(aAny, mXPagePropSet, "IsFooterVisible", true)
+ && aAny == true && GetPropertyValue(aAny, mXPagePropSet, "FooterText", true)
+ && (aAny >>= aText) && !aText.isEmpty()))
+ {
+ if ((xShape = GetReferencedPlaceholderXShape(Footer, ePageType)))
+ rDML.WritePlaceholderReferenceShape(Footer,
+ maPlaceholderShapeToIndexMap.find(xShape)->second,
+ ePageType, mXPagePropSet);
+ }
+
+ if (ePageType == LAYOUT
+ || (bCheckProps
+ && PropValue::GetPropertyValue(aAny, mXPagePropSet, "IsPageNumberVisible", true)
+ && aAny == true))
+ {
+ if ((xShape = GetReferencedPlaceholderXShape(SlideNumber, ePageType)))
+ rDML.WritePlaceholderReferenceShape(SlideNumber,
+ maPlaceholderShapeToIndexMap.find(xShape)->second,
+ ePageType, mXPagePropSet);
+ }
+
+ if (ePageType == LAYOUT
+ || (bCheckProps
+ && PropValue::GetPropertyValue(aAny, mXPagePropSet, "IsDateTimeVisible", true)
+ && aAny == true
+ && ((GetPropertyValue(aAny, mXPagePropSet, "DateTimeText", true) && (aAny >>= aText)
+ && !aText.isEmpty())
+ || mXPagePropSet->getPropertyValue("IsDateTimeFixed") == false)))
+ {
+ if ((xShape = GetReferencedPlaceholderXShape(DateAndTime, ePageType)))
+ rDML.WritePlaceholderReferenceShape(DateAndTime,
+ maPlaceholderShapeToIndexMap.find(xShape)->second,
+ ePageType, mXPagePropSet);
+ }
+}
+
+sal_Int32 PowerPointExport::CreateNewPlaceholderIndex(const css::uno::Reference<XShape> &rXShape)
+{
+ maPlaceholderShapeToIndexMap.insert({rXShape, mnPlaceholderIndexMax});
+ return mnPlaceholderIndexMax++;
+}
+
+Reference<XShape> PowerPointExport::GetReferencedPlaceholderXShape(const PlaceholderType eType,
+ PageType ePageType) const
+{
+ PresObjKind ePresObjKind = PresObjKind::NONE;
+ switch (eType)
+ {
+ case oox::core::None:
+ break;
+ case oox::core::SlideImage:
+ break;
+ case oox::core::Notes:
+ break;
+ case oox::core::Header:
+ ePresObjKind = PresObjKind::Header;
+ break;
+ case oox::core::Footer:
+ ePresObjKind = PresObjKind::Footer;
+ break;
+ case oox::core::SlideNumber:
+ ePresObjKind = PresObjKind::SlideNumber;
+ break;
+ case oox::core::DateAndTime:
+ ePresObjKind = PresObjKind::DateTime;
+ break;
+ case oox::core::Outliner:
+ break;
+ case oox::core::Title:
+ ePresObjKind = PresObjKind::Title;
+ break;
+ case oox::core::Subtitle:
+ break;
+ }
+ if (ePresObjKind != PresObjKind::NONE)
+ {
+ SdPage* pMasterPage;
+ if (ePageType == LAYOUT)
+ {
+ // since Layout pages do not have drawpages themselves - mXDrawPage is still the master they reference to..
+ pMasterPage = SdPage::getImplementation(mXDrawPage);
+ }
+ else
+ {
+ pMasterPage
+ = &static_cast<SdPage&>(SdPage::getImplementation(mXDrawPage)->TRG_GetMasterPage());
+ }
+ if (SdrObject* pMasterFooter = pMasterPage->GetPresObj(ePresObjKind))
+ return GetXShapeForSdrObject(pMasterFooter);
+ }
+ return nullptr;
+}
+
+// UNO component
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+css_comp_Impress_oox_PowerPointExport(uno::XComponentContext* rxCtxt,
+ uno::Sequence<css::uno::Any> const& rArguments)
+{
+ return cppu::acquire(new PowerPointExport(rxCtxt, rArguments));
+}
+
+#if OSL_DEBUG_LEVEL > 1
+void dump_pset(Reference< XPropertySet > const& rXPropSet)
+{
+ Reference< XPropertySetInfo > info = rXPropSet->getPropertySetInfo();
+ Sequence< beans::Property > props = info->getProperties();
+
+ for (int i=0; i < props.getLength(); i++)
+ {
+ OString name = OUStringToOString(props [i].Name, RTL_TEXTENCODING_UTF8);
+
+ Any value = rXPropSet->getPropertyValue(props [i].Name);
+
+ OUString strValue;
+ sal_Int32 intValue;
+ bool boolValue;
+ RectanglePoint pointValue;
+
+ if (value >>= strValue)
+ SAL_INFO("sd.eppt", name << " = \"" << strValue << "\"");
+ else if (value >>= intValue)
+ SAL_INFO("sd.eppt", name << " = " << intValue << "(hex : " << std::hex << intValue << ")");
+ else if (value >>= boolValue)
+ SAL_INFO("sd.eppt", name << " = " << boolValue << " (bool)");
+ else if (value >>= pointValue)
+ SAL_INFO("sd.eppt", name << " = " << static_cast<int>(pointValue) << " (RectanglePoint)");
+ else
+ SAL_INFO("sd.eppt", "??? <unhandled type>");
+ }
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-grouptable.cxx b/sd/source/filter/eppt/pptx-grouptable.cxx
new file mode 100644
index 000000000..bf91f2fb6
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-grouptable.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 "grouptable.hxx"
+
+using ::com::sun::star::container::XIndexAccess;
+
+GroupTable::GroupTable()
+ : mnIndex(0)
+ , mnGroupsClosed(0)
+{
+ mvGroupEntry.reserve(32);
+}
+
+GroupTable::~GroupTable()
+{
+}
+
+bool GroupTable::EnterGroup( css::uno::Reference< css::container::XIndexAccess > const & rXIndexAccessRef )
+{
+ bool bRet = false;
+ if ( rXIndexAccessRef.is() )
+ {
+ GroupEntry aNewGroup( rXIndexAccessRef );
+ if ( aNewGroup.mnCount )
+ {
+ mvGroupEntry.push_back( std::move(aNewGroup) );
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+sal_uInt32 GroupTable::GetGroupsClosed()
+{
+ sal_uInt32 nRet = mnGroupsClosed;
+ mnGroupsClosed = 0;
+ return nRet;
+}
+
+void GroupTable::ClearGroupTable()
+{
+ mvGroupEntry.clear();
+}
+
+void GroupTable::ResetGroupTable( sal_uInt32 nCount )
+{
+ ClearGroupTable();
+ mvGroupEntry.push_back( GroupEntry( nCount ) );
+}
+
+bool GroupTable::GetNextGroupEntry()
+{
+ while ( !mvGroupEntry.empty() )
+ {
+ mnIndex = mvGroupEntry.back().mnCurrentPos++;
+
+ if ( mvGroupEntry.back().mnCount > mnIndex )
+ return true;
+
+ mvGroupEntry.pop_back();
+
+ if ( !mvGroupEntry.empty() )
+ mnGroupsClosed++;
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-stylesheet.cxx b/sd/source/filter/eppt/pptx-stylesheet.cxx
new file mode 100644
index 000000000..459020278
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-stylesheet.cxx
@@ -0,0 +1,489 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "epptbase.hxx"
+#include "epptdef.hxx"
+#include "text.hxx"
+#include <tools/color.hxx>
+#include <tools/UnitConversion.hxx>
+#include <editeng/svxenum.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+using namespace ::com::sun::star;
+
+PPTExCharSheet::PPTExCharSheet( int nInstance )
+{
+ sal_uInt16 nFontHeight = 24;
+
+ for ( int nDepth = 0; nDepth < 5; nDepth++ )
+ {
+ PPTExCharLevel& rLev = maCharLevel[ nDepth ];
+ switch ( nInstance )
+ {
+ case EPP_TEXTTYPE_Title :
+ case EPP_TEXTTYPE_CenterTitle :
+ nFontHeight = 44;
+ break;
+ case EPP_TEXTTYPE_Body :
+ case EPP_TEXTTYPE_CenterBody :
+ case EPP_TEXTTYPE_HalfBody :
+ case EPP_TEXTTYPE_QuarterBody :
+ {
+ switch ( nDepth )
+ {
+ case 0 : nFontHeight = 32; break;
+ case 1 : nFontHeight = 28; break;
+ case 2 : nFontHeight = 24; break;
+ default :nFontHeight = 20; break;
+ }
+ }
+ break;
+ case EPP_TEXTTYPE_Notes :
+ nFontHeight = 12;
+ break;
+ case EPP_TEXTTYPE_notUsed :
+ case EPP_TEXTTYPE_Other :
+ nFontHeight = 24;
+ break;
+ }
+ rLev.mnFlags = 0;
+ rLev.mnFont = 0;
+ rLev.mnAsianOrComplexFont = 0xffff;
+ rLev.mnFontHeight = nFontHeight;
+ rLev.mnFontColor = 0;
+ rLev.mnEscapement = 0;
+ }
+}
+
+void PPTExCharSheet::SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ FontCollection& rFontCollection, int nLevel )
+{
+ PortionObj aPortionObj( rXPropSet, rFontCollection );
+
+ PPTExCharLevel& rLev = maCharLevel[ nLevel ];
+
+ if ( aPortionObj.meCharColor == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnFontColor = Color(ColorTransparency, aPortionObj.mnCharColor);
+ if ( aPortionObj.meCharEscapement == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnEscapement = aPortionObj.mnCharEscapement;
+ if ( aPortionObj.meCharHeight == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnFontHeight = aPortionObj.mnCharHeight;
+ if ( aPortionObj.meFontName == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnFont = aPortionObj.mnFont;
+ if ( aPortionObj.meAsianOrComplexFont == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnAsianOrComplexFont = aPortionObj.mnAsianOrComplexFont;
+ rLev.mnFlags = aPortionObj.mnCharAttr;
+}
+
+void PPTExCharSheet::Write( SvStream& rSt, sal_uInt16 nLev, bool bSimpleText,
+ const css::uno::Reference< css::beans::XPropertySet > & rPagePropSet )
+{
+ const PPTExCharLevel& rLev = maCharLevel[ nLev ];
+
+ sal_uInt32 nCharFlags = 0xefffff;
+ if ( bSimpleText )
+ nCharFlags = 0x7ffff;
+
+ rSt.WriteUInt32( nCharFlags )
+ .WriteUInt16( rLev.mnFlags )
+ .WriteUInt16( rLev.mnFont );
+
+ Color nFontColor = rLev.mnFontColor;
+ if ( nFontColor == COL_AUTO )
+ {
+ bool bIsDark = false;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, rPagePropSet, "IsBackgroundDark", true ) )
+ aAny >>= bIsDark;
+ nFontColor = Color(ColorTransparency, bIsDark ? 0xffffff : 0x000000);
+ }
+ nFontColor.SetAlpha(1);
+ if ( bSimpleText )
+ {
+ rSt.WriteUInt16( rLev.mnFontHeight )
+ .WriteUInt32( sal_uInt32(nFontColor) );
+ }
+ else
+ {
+ rSt.WriteUInt16( rLev.mnAsianOrComplexFont )
+ .WriteUInt16( 0xffff ) // unknown
+ .WriteUInt16( 0xffff ) // unknown
+ .WriteUInt16( rLev.mnFontHeight )
+ .WriteUInt32( sal_uInt32(nFontColor) )
+ .WriteUInt16( rLev.mnEscapement );
+ }
+}
+
+PPTExParaSheet::PPTExParaSheet( int nInstance, sal_uInt16 nDefaultTab, PPTExBulletProvider* pProv ) :
+ pBuProv ( pProv ),
+ mnInstance ( nInstance )
+{
+ bool bHasBullet = false;
+
+ sal_uInt16 nUpperDist = 0;
+ sal_uInt16 nBulletChar = 0x2022;
+ sal_uInt16 nBulletOfs = 0;
+ sal_uInt16 nTextOfs = 0;
+
+ for ( int nDepth = 0; nDepth < 5; nDepth++ )
+ {
+ PPTExParaLevel& rLev = maParaLevel[ nDepth ];
+ switch ( nInstance )
+ {
+ case EPP_TEXTTYPE_Title :
+ case EPP_TEXTTYPE_CenterTitle :
+ break;
+ case EPP_TEXTTYPE_Body :
+ case EPP_TEXTTYPE_CenterBody :
+ case EPP_TEXTTYPE_HalfBody :
+ case EPP_TEXTTYPE_QuarterBody :
+ {
+ bHasBullet = true;
+ nUpperDist = 0x14;
+ }
+ break;
+ case EPP_TEXTTYPE_Notes :
+ nUpperDist = 0x1e;
+ break;
+
+ }
+ switch ( nDepth )
+ {
+ case 0 :
+ {
+ nBulletChar = 0x2022;
+ nBulletOfs = 0;
+ nTextOfs = bHasBullet ? 0xd8 : 0;
+ }
+ break;
+ case 1 :
+ {
+ nBulletChar = 0x2013;
+ nBulletOfs = 0x120;
+ nTextOfs = 0x1d4;
+ }
+ break;
+ case 2 :
+ {
+ nBulletChar = 0x2022;
+ nBulletOfs = 0x240;
+ nTextOfs = 0x2d0;
+ }
+ break;
+ case 3 :
+ {
+ nBulletChar = 0x2013;
+ nBulletOfs = 0x360;
+ nTextOfs = 0x3f0;
+ }
+ break;
+ case 4 :
+ {
+ nBulletChar = 0xbb;
+ nBulletOfs = 0x480;
+ nTextOfs = 0x510;
+ }
+ break;
+ }
+ rLev.mbIsBullet = bHasBullet;
+ rLev.mnBulletChar = nBulletChar;
+ rLev.mnBulletFont = 0;
+ rLev.mnBulletHeight = 100;
+ rLev.mnBulletColor = 0;
+ rLev.mnAdjust = 0;
+ rLev.mnLineFeed = 100;
+ rLev.mnLowerDist = 0;
+ rLev.mnUpperDist = nUpperDist;
+ rLev.mnTextOfs = nTextOfs;
+ rLev.mnBulletOfs = nBulletOfs;
+ rLev.mnDefaultTab = nDefaultTab;
+ rLev.mnAsianSettings = 2;
+ rLev.mnBiDi = 0;
+
+ rLev.mbExtendedBulletsUsed = false;
+ rLev.mnBulletId = 0xffff;
+ rLev.mnBulletStart = 0;
+ rLev.mnMappedNumType = 0;
+ rLev.mnNumberingType = 0;
+ }
+}
+
+void PPTExParaSheet::SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ FontCollection& rFontCollection, int nLevel, const PPTExCharLevel& rCharLevel )
+{
+ ParagraphObj aParagraphObj( rXPropSet, pBuProv );
+ aParagraphObj.CalculateGraphicBulletSize( rCharLevel.mnFontHeight );
+ PPTExParaLevel& rLev = maParaLevel[ nLevel ];
+
+ if ( aParagraphObj.meTextAdjust == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnAdjust = aParagraphObj.mnTextAdjust;
+ if ( aParagraphObj.meLineSpacing == css::beans::PropertyState_DIRECT_VALUE )
+ {
+ sal_Int16 nLineSpacing = aParagraphObj.mnLineSpacing;
+ if ( nLineSpacing > 0 ) // if nLinespacing is < 0 the linespacing is an absolute spacing
+ {
+ bool bFixedLineSpacing = false;
+ uno::Any aAny = rXPropSet->getPropertyValue("FontIndependentLineSpacing");
+ if( !(aAny >>= bFixedLineSpacing) || !bFixedLineSpacing )
+ {
+ const FontCollectionEntry* pDesc = rFontCollection.GetById( rCharLevel.mnFont );
+ if ( pDesc )
+ nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
+ }
+ }
+ else
+ {
+ if ( rCharLevel.mnFontHeight > static_cast<sal_uInt16>( static_cast<double>(-nLineSpacing) * 0.001 * 72.0 / 2.54 ) ) // 1/100mm to point
+ {
+ const FontCollectionEntry* pDesc = rFontCollection.GetById( rCharLevel.mnFont );
+ if ( pDesc )
+ nLineSpacing = static_cast<sal_Int16>( 100.0 * pDesc->Scaling + 0.5 );
+ else
+ nLineSpacing = 100;
+ }
+ else
+ nLineSpacing = static_cast<sal_Int16>(convertMm100ToMasterUnit(nLineSpacing));
+ }
+ rLev.mnLineFeed = nLineSpacing;
+ }
+ if ( aParagraphObj.meLineSpacingBottom == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnLowerDist = aParagraphObj.mnLineSpacingBottom;
+ if ( aParagraphObj.meLineSpacingTop == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnUpperDist = aParagraphObj.mnLineSpacingTop;
+ if ( aParagraphObj.meForbiddenRules == css::beans::PropertyState_DIRECT_VALUE )
+ {
+ rLev.mnAsianSettings &=~1;
+ if ( aParagraphObj.mbForbiddenRules )
+ rLev.mnAsianSettings |= 1;
+ }
+ if ( aParagraphObj.meParagraphPunctation == css::beans::PropertyState_DIRECT_VALUE )
+ {
+ rLev.mnAsianSettings &=~4;
+ if ( aParagraphObj.mbParagraphPunctation )
+ rLev.mnAsianSettings |= 4;
+ }
+
+ if ( aParagraphObj.meBiDi == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnBiDi = aParagraphObj.mnBiDi;
+
+ rLev.mbIsBullet = aParagraphObj.mbIsBullet; //( ( aParagraphObj.nBulletFlags & 1 ) != 0 );
+
+ if ( nLevel )
+ return;
+
+ if (!(aParagraphObj.bExtendedParameters &&
+ aParagraphObj.meBullet == css::beans::PropertyState_DIRECT_VALUE))
+ return;
+
+ for ( sal_Int16 i = 0; i < 5; i++ )
+ {
+ PPTExParaLevel& rLevel = maParaLevel[ i ];
+ if ( i )
+ aParagraphObj.ImplGetNumberingLevel( pBuProv, i, false, false );
+ rLevel.mnTextOfs = aParagraphObj.nTextOfs;
+ rLevel.mnBulletOfs = static_cast<sal_uInt16>(aParagraphObj.nBulletOfs);
+ rLevel.mnBulletChar = aParagraphObj.cBulletId;
+ FontCollectionEntry aFontDescEntry( aParagraphObj.aFontDesc.Name, aParagraphObj.aFontDesc.Family,
+ aParagraphObj.aFontDesc.Pitch, aParagraphObj.aFontDesc.CharSet );
+ rLevel.mnBulletFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDescEntry ));
+ rLevel.mnBulletHeight = aParagraphObj.nBulletRealSize;
+ rLevel.mnBulletColor = aParagraphObj.nBulletColor;
+
+ rLevel.mbExtendedBulletsUsed = aParagraphObj.bExtendedBulletsUsed;
+ rLevel.mnBulletId = aParagraphObj.nBulletId;
+ rLevel.mnNumberingType = aParagraphObj.nNumberingType;
+ rLevel.mnBulletStart = aParagraphObj.nStartWith;
+ rLevel.mnMappedNumType = aParagraphObj.nMappedNumType;
+ }
+}
+
+void PPTExParaSheet::Write( SvStream& rSt, sal_uInt16 nLev, bool bSimpleText,
+ const css::uno::Reference< css::beans::XPropertySet > & rPagePropSet )
+{
+ const PPTExParaLevel& rLev = maParaLevel[ nLev ];
+
+ if ( maParaLevel[ 0 ].mbExtendedBulletsUsed || maParaLevel[ 1 ].mbExtendedBulletsUsed ||
+ maParaLevel[ 2 ].mbExtendedBulletsUsed || maParaLevel[ 3 ].mbExtendedBulletsUsed ||
+ maParaLevel[ 4 ].mbExtendedBulletsUsed )
+ {
+ SvStream& rOut = pBuProv->aBuExMasterStream;
+ if ( !nLev )
+ {
+ rOut.WriteUInt32( ( EPP_PST_ExtendedParagraphMasterAtom << 16 ) | ( mnInstance << 4 ) )
+ .WriteUInt32( 5 * 16 + 2 )
+ .WriteUInt16( 5 ); // depth
+ }
+ sal_uInt16 nBulletId = rLev.mnBulletId;
+ if ( rLev.mnNumberingType != SVX_NUM_BITMAP )
+ nBulletId = 0xffff;
+ rOut.WriteUInt32( 0x03800000 )
+ .WriteUInt16( nBulletId )
+ .WriteUInt32( rLev.mnMappedNumType )
+ .WriteUInt16( rLev.mnBulletStart )
+ .WriteUInt32( 0 );
+ }
+
+ sal_uInt32 nParaFlags = 0x3ffdff;
+ sal_uInt16 nBulletFlags = ( rLev.mbIsBullet ) ? 0xf : 0xe;
+
+ if ( nLev )
+ nParaFlags &= 0x207fff;
+ if ( bSimpleText )
+ nParaFlags &= 0x7fff;
+ sal_uInt32 nBulletColor = rLev.mnBulletColor;
+ if ( nBulletColor == sal_uInt32(COL_AUTO) )
+ {
+ bool bIsDark = false;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, rPagePropSet, "IsBackgroundDark", true ) )
+ aAny >>= bIsDark;
+ nBulletColor = bIsDark ? 0xffffff : 0x000000;
+ }
+ nBulletColor &= 0xffffff;
+ nBulletColor |= 0xfe000000;
+ rSt.WriteUInt32( nParaFlags )
+ .WriteUInt16( nBulletFlags )
+ .WriteUInt16( rLev.mnBulletChar )
+ .WriteUInt16( rLev.mnBulletFont )
+ .WriteUInt16( rLev.mnBulletHeight )
+ .WriteUInt32( nBulletColor )
+ .WriteUInt16( rLev.mnAdjust )
+ .WriteUInt16( rLev.mnLineFeed )
+ .WriteUInt16( rLev.mnUpperDist )
+ .WriteUInt16( rLev.mnLowerDist )
+ .WriteUInt16( rLev.mnTextOfs )
+ .WriteUInt16( rLev.mnBulletOfs );
+
+ if ( bSimpleText || nLev )
+ {
+ if ( nParaFlags & 0x200000 )
+ rSt.WriteUInt16( rLev.mnBiDi );
+ }
+ else
+ {
+ rSt.WriteUInt16( rLev.mnDefaultTab )
+ .WriteUInt16( 0 )
+ .WriteUInt16( 0 )
+ .WriteUInt16( rLev.mnAsianSettings )
+ .WriteUInt16( rLev.mnBiDi );
+ }
+}
+
+PPTExStyleSheet::PPTExStyleSheet( sal_uInt16 nDefaultTab, PPTExBulletProvider* pBuProv )
+{
+ for ( int nInstance = EPP_TEXTTYPE_Title; nInstance <= EPP_TEXTTYPE_QuarterBody; nInstance++ )
+ {
+ if (nInstance != EPP_TEXTTYPE_notUsed)
+ {
+ mpParaSheet[ nInstance ].reset(new PPTExParaSheet( nInstance, nDefaultTab, pBuProv ));
+ mpCharSheet[ nInstance ].reset(new PPTExCharSheet( nInstance ));
+ }
+ }
+}
+
+PPTExStyleSheet::~PPTExStyleSheet()
+{
+}
+
+void PPTExStyleSheet::SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ FontCollection& rFontCollection, int nInstance, int nLevel )
+{
+ if ( nInstance == EPP_TEXTTYPE_notUsed )
+ return;
+ mpCharSheet[ nInstance ]->SetStyleSheet( rXPropSet, rFontCollection, nLevel );
+ mpParaSheet[ nInstance ]->SetStyleSheet( rXPropSet, rFontCollection, nLevel, mpCharSheet[ nInstance ]->maCharLevel[ nLevel ] );
+}
+
+bool PPTExStyleSheet::IsHardAttribute( sal_uInt32 nInstance, sal_uInt32 nLevel, PPTExTextAttr eAttr, sal_uInt32 nValue )
+{
+ assert(nInstance < PPTEX_STYLESHEETENTRIES && nLevel < 5);
+
+ const PPTExParaLevel& rPara = mpParaSheet[ nInstance ]->maParaLevel[ nLevel ];
+ const PPTExCharLevel& rChar = mpCharSheet[ nInstance ]->maCharLevel[ nLevel ];
+
+ sal_uInt32 nFlag = 0;
+
+ switch ( eAttr )
+ {
+ case ParaAttr_BulletOn : return ( rPara.mbIsBullet ) ? nValue == 0 : nValue != 0;
+ case ParaAttr_BuHardFont :
+ case ParaAttr_BulletFont : return ( rPara.mnBulletFont != nValue );
+ case ParaAttr_BuHardColor :
+ case ParaAttr_BulletColor : return ( rPara.mnBulletColor != nValue );
+ case ParaAttr_BuHardHeight :
+ case ParaAttr_BulletHeight : return ( rPara.mnBulletHeight != nValue );
+ case ParaAttr_BulletChar : return ( rPara.mnBulletChar != nValue );
+ case ParaAttr_Adjust : return ( rPara.mnAdjust != nValue );
+ case ParaAttr_LineFeed : return ( rPara.mnLineFeed != nValue );
+ case ParaAttr_UpperDist : return ( rPara.mnUpperDist != nValue );
+ case ParaAttr_LowerDist : return ( rPara.mnLowerDist != nValue );
+ case ParaAttr_TextOfs : return ( rPara.mnTextOfs != nValue );
+ case ParaAttr_BulletOfs : return ( rPara.mnBulletOfs != nValue );
+ case ParaAttr_DefaultTab : return ( rPara.mnDefaultTab != nValue );
+ case ParaAttr_BiDi : return ( rPara.mnBiDi != nValue );
+ case CharAttr_Bold : nFlag = 1; break;
+ case CharAttr_Italic : nFlag = 2; break;
+ case CharAttr_Underline : nFlag = 4; break;
+ case CharAttr_Shadow : nFlag = 16; break;
+ case CharAttr_Strikeout : nFlag = 256; break;
+ case CharAttr_Embossed : nFlag = 512; break;
+ case CharAttr_Font : return ( rChar.mnFont != nValue );
+ case CharAttr_AsianOrComplexFont : return ( rChar.mnAsianOrComplexFont != nValue );
+ case CharAttr_Symbol : return true;
+ case CharAttr_FontHeight : return ( rChar.mnFontHeight != nValue );
+ case CharAttr_FontColor : return ( rChar.mnFontColor != Color(ColorTransparency, nValue) );
+ case CharAttr_Escapement : return ( rChar.mnEscapement != nValue );
+ default:
+ break;
+ }
+ if ( nFlag )
+ {
+ if ( rChar.mnFlags & nFlag )
+ return ( ( nValue & nFlag ) == 0 );
+ else
+ return ( ( nValue & nFlag ) != 0 );
+ }
+ return true;
+}
+
+// the TxCFStyleAtom stores the text properties that are used
+// when creating new objects in PowerPoint.
+
+void PPTExStyleSheet::WriteTxCFStyleAtom( SvStream& rSt )
+{
+ const PPTExCharLevel& rCharStyle = mpCharSheet[ EPP_TEXTTYPE_Other ]->maCharLevel[ 0 ];
+
+ sal_uInt16 const nFlags = 0x60 // ??
+ | 0x02 // fontsize;
+ | 0x04; // fontcolor
+
+ sal_uInt32 nCharFlags = rCharStyle.mnFlags;
+ nCharFlags &= CharAttr_Italic | CharAttr_Bold | CharAttr_Underline | CharAttr_Shadow;
+
+ rSt.WriteUInt32( EPP_TxCFStyleAtom << 16 ) // recordheader
+ .WriteUInt32( SizeOfTxCFStyleAtom() - 8 )
+ .WriteUInt16( 0x80 | nCharFlags )
+ .WriteUInt16( nFlags )
+ .WriteUInt16( nCharFlags )
+ .WriteInt32( -1 ) // ?
+ .WriteUInt16( rCharStyle.mnFontHeight )
+ .WriteUInt32( sal_uInt32(rCharStyle.mnFontColor) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-text.cxx b/sd/source/filter/eppt/pptx-text.cxx
new file mode 100644
index 000000000..85c37f77d
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-text.cxx
@@ -0,0 +1,1400 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "text.hxx"
+
+#include <com/sun/star/awt/CharSet.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XIndexReplace.hpp>
+#include <com/sun/star/i18n/BreakIterator.hpp>
+#include <com/sun/star/i18n/ScriptDirection.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/text/FontRelief.hpp>
+#include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/style/LineSpacing.hpp>
+#include <com/sun/star/style/LineSpacingMode.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/style/TabStop.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <editeng/svxenum.hxx>
+#include <editeng/frmdir.hxx>
+#include <filter/msfilter/util.hxx>
+#include <i18nutil/scripttypedetector.hxx>
+#include <o3tl/any.hxx>
+#include <svl/languageoptions.hxx>
+#include <osl/diagnose.h>
+#include <i18nlangtag/languagetag.hxx>
+#include <tools/UnitConversion.hxx>
+
+#include <vcl/settings.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace css;
+
+static css::uno::Reference< css::i18n::XBreakIterator > xPPTBreakIter;
+
+PortionObj::PortionObj(const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ FontCollection& rFontCollection)
+ : meCharColor(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meCharHeight(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meFontName(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meAsianOrComplexFont(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meCharEscapement(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , mnCharAttrHard(0)
+ , mnCharColor(0)
+ , mnCharAttr(0)
+ , mnFont(0)
+ , mnAsianOrComplexFont(0xffff)
+ , mnTextSize(0)
+ , mbLastPortion(true)
+{
+ mXPropSet = rXPropSet;
+
+ ImplGetPortionValues( rFontCollection, false );
+}
+
+PortionObj::PortionObj(css::uno::Reference< css::text::XTextRange > & rXTextRange,
+ bool bLast, FontCollection& rFontCollection)
+ : meCharColor(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meCharHeight(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meFontName(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meAsianOrComplexFont(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meCharEscapement(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , mnCharAttrHard(0)
+ , mnCharColor(0)
+ , mnCharAttr(0)
+ , mnCharHeight(0)
+ , mnFont(0)
+ , mnAsianOrComplexFont(0xffff)
+ , mnCharEscapement(0)
+ , mbLastPortion(bLast)
+{
+ OUString aString( rXTextRange->getString() );
+ OUString aURL;
+
+ mnTextSize = aString.getLength();
+ if ( bLast )
+ mnTextSize++;
+
+ if ( !mnTextSize )
+ return;
+
+ bool bRTL_endingParen = false;
+ mpFieldEntry = nullptr;
+ sal_uInt32 nFieldType = 0;
+
+ mXPropSet.set( rXTextRange, css::uno::UNO_QUERY );
+ mXPropState.set( rXTextRange, css::uno::UNO_QUERY );
+
+ bool bPropSetsValid = ( mXPropSet.is() && mXPropState.is() );
+ if ( bPropSetsValid )
+ nFieldType = ImplGetTextField( rXTextRange, mXPropSet, aURL );
+ if ( nFieldType )
+ {
+ mpFieldEntry.reset( new FieldEntry( nFieldType, 0, mnTextSize ) );
+ if ( nFieldType >> 28 == 4 )
+ {
+ mpFieldEntry->aRepresentation = aString;
+ mpFieldEntry->aFieldUrl = aURL;
+ }
+ }
+ bool bSymbol = false;
+
+ if ( bPropSetsValid && ImplGetPropertyValue( "CharFontCharSet", false ) )
+ {
+ sal_Int16 nCharset = 0;
+ mAny >>= nCharset;
+ if ( nCharset == css::awt::CharSet::SYMBOL )
+ bSymbol = true;
+ }
+ if ( mpFieldEntry && ( nFieldType & 0x800000 ) ) // placeholder ?
+ {
+ mnTextSize = 1;
+ if ( bLast )
+ mnTextSize++;
+ mpText.reset( new sal_uInt16[ mnTextSize ] );
+ mpText[ 0 ] = 0x2a;
+ }
+ else
+ {
+ // For i39516 - a closing parenthesis that ends an RTL string is displayed backwards by PPT
+ // Solution: add a Unicode Right-to-Left Mark, following the method described in i18024
+ if (bLast && !aString.isEmpty()
+ && aString[aString.getLength() - 1] == ')'
+ && FontCollection::GetScriptDirection(aString) == css::i18n::ScriptDirection::RIGHT_TO_LEFT)
+ {
+ mnTextSize++;
+ bRTL_endingParen = true;
+ }
+ mpText.reset( new sal_uInt16[ mnTextSize ] );
+ sal_uInt16 nChar;
+ for ( sal_Int32 i = 0; i < aString.getLength(); i++ )
+ {
+ nChar = static_cast<sal_uInt16>(aString[ i ]);
+ if ( nChar == 0xa )
+ nChar++;
+ else if ( !bSymbol )
+ {
+ switch ( nChar )
+ {
+ // Currency
+ case 128: nChar = 0x20AC; break;
+ // Punctuation and other
+ case 130: nChar = 0x201A; break;// SINGLE LOW-9 QUOTATION MARK
+ case 131: nChar = 0x0192; break;// LATIN SMALL LETTER F WITH HOOK
+ case 132: nChar = 0x201E; break;// DOUBLE LOW-9 QUOTATION MARK
+ // LOW DOUBLE PRIME QUOTATION MARK
+ case 133: nChar = 0x2026; break;// HORIZONTAL ELLIPSES
+ case 134: nChar = 0x2020; break;// DAGGER
+ case 135: nChar = 0x2021; break;// DOUBLE DAGGER
+ case 136: nChar = 0x02C6; break;// MODIFIER LETTER CIRCUMFLEX ACCENT
+ case 137: nChar = 0x2030; break;// PER MILLE SIGN
+ case 138: nChar = 0x0160; break;// LATIN CAPITAL LETTER S WITH CARON
+ case 139: nChar = 0x2039; break;// SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ case 140: nChar = 0x0152; break;// LATIN CAPITAL LIGATURE OE
+ case 142: nChar = 0x017D; break;// LATIN CAPITAL LETTER Z WITH CARON
+ case 145: nChar = 0x2018; break;// LEFT SINGLE QUOTATION MARK
+ // MODIFIER LETTER TURNED COMMA
+ case 146: nChar = 0x2019; break;// RIGHT SINGLE QUOTATION MARK
+ // MODIFIER LETTER APOSTROPHE
+ case 147: nChar = 0x201C; break;// LEFT DOUBLE QUOTATION MARK
+ // REVERSED DOUBLE PRIME QUOTATION MARK
+ case 148: nChar = 0x201D; break;// RIGHT DOUBLE QUOTATION MARK
+ // REVERSED DOUBLE PRIME QUOTATION MARK
+ case 149: nChar = 0x2022; break;// BULLET
+ case 150: nChar = 0x2013; break;// EN DASH
+ case 151: nChar = 0x2014; break;// EM DASH
+ case 152: nChar = 0x02DC; break;// SMALL TILDE
+ case 153: nChar = 0x2122; break;// TRADE MARK SIGN
+ case 154: nChar = 0x0161; break;// LATIN SMALL LETTER S WITH CARON
+ case 155: nChar = 0x203A; break;// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ case 156: nChar = 0x0153; break;// LATIN SMALL LIGATURE OE
+ case 158: nChar = 0x017E; break;// LATIN SMALL LETTER Z WITH CARON
+ case 159: nChar = 0x0178; break;// LATIN CAPITAL LETTER Y WITH DIAERESIS
+ }
+ }
+ mpText[ i ] = nChar;
+ }
+ }
+ if ( bRTL_endingParen )
+ mpText[ mnTextSize - 2 ] = 0x200F; // Unicode Right-to-Left mark
+
+ if ( bLast )
+ mpText[ mnTextSize - 1 ] = 0xd;
+
+ if ( bPropSetsValid )
+ ImplGetPortionValues( rFontCollection, true );
+}
+
+PortionObj::PortionObj( const PortionObj& rPortionObj )
+: PropStateValue( rPortionObj )
+{
+ ImplConstruct( rPortionObj );
+}
+
+PortionObj::~PortionObj()
+{
+ ImplClear();
+}
+
+void PortionObj::Write( SvStream* pStrm, bool bLast )
+{
+ sal_uInt32 nCount = mnTextSize;
+ if ( bLast && mbLastPortion )
+ nCount--;
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ pStrm->WriteUInt16( mpText[ i ] );
+}
+
+void PortionObj::ImplGetPortionValues( FontCollection& rFontCollection, bool bGetPropStateValue )
+{
+
+ bool bOk = ImplGetPropertyValue( "CharFontName", bGetPropStateValue );
+ meFontName = ePropState;
+ if ( bOk )
+ {
+ FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
+ sal_uInt32 nCount = rFontCollection.GetCount();
+ mnFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
+ if ( mnFont == nCount )
+ {
+ FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
+ if ( ImplGetPropertyValue( "CharFontCharSet", false ) )
+ mAny >>= rFontDesc.CharSet;
+ if ( ImplGetPropertyValue( "CharFontFamily", false ) )
+ mAny >>= rFontDesc.Family;
+ if ( ImplGetPropertyValue( "CharFontPitch", false ) )
+ mAny >>= rFontDesc.Pitch;
+ }
+ }
+
+ sal_Int16 nScriptType = SvtLanguageOptions::FromSvtScriptTypeToI18N( SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ) );
+ if ( mpText && mnTextSize && xPPTBreakIter.is() )
+ {
+ OUString sT( reinterpret_cast<sal_Unicode *>(mpText.get()), mnTextSize );
+ nScriptType = xPPTBreakIter->getScriptType( sT, 0 );
+ }
+ if ( nScriptType != css::i18n::ScriptType::COMPLEX )
+ {
+ bOk = ImplGetPropertyValue( "CharFontNameAsian", bGetPropStateValue );
+ meAsianOrComplexFont = ePropState;
+ if ( bOk )
+ {
+ FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
+ sal_uInt32 nCount = rFontCollection.GetCount();
+ mnAsianOrComplexFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
+ if ( mnAsianOrComplexFont == nCount )
+ {
+ FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
+ if ( ImplGetPropertyValue( "CharFontCharSetAsian", false ) )
+ mAny >>= rFontDesc.CharSet;
+ if ( ImplGetPropertyValue( "CharFontFamilyAsian", false ) )
+ mAny >>= rFontDesc.Family;
+ if ( ImplGetPropertyValue( "CharFontPitchAsian", false ) )
+ mAny >>= rFontDesc.Pitch;
+ }
+ }
+ }
+ else
+ {
+ bOk = ImplGetPropertyValue( "CharFontNameComplex", bGetPropStateValue );
+ meAsianOrComplexFont = ePropState;
+ if ( bOk )
+ {
+ FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
+ sal_uInt32 nCount = rFontCollection.GetCount();
+ mnAsianOrComplexFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
+ if ( mnAsianOrComplexFont == nCount )
+ {
+ FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
+ if ( ImplGetPropertyValue( "CharFontCharSetComplex", false ) )
+ mAny >>= rFontDesc.CharSet;
+ if ( ImplGetPropertyValue( "CharFontFamilyComplex", false ) )
+ mAny >>= rFontDesc.Family;
+ if ( ImplGetPropertyValue( "CharFontPitchComplex", false ) )
+ mAny >>= rFontDesc.Pitch;
+ }
+ }
+ }
+
+ OUString aCharHeightName, aCharWeightName, aCharLocaleName, aCharPostureName;
+ switch( nScriptType )
+ {
+ case css::i18n::ScriptType::ASIAN :
+ {
+ aCharHeightName = "CharHeightAsian";
+ aCharWeightName = "CharWeightAsian";
+ aCharLocaleName = "CharLocaleAsian";
+ aCharPostureName = "CharPostureAsian";
+ break;
+ }
+ case css::i18n::ScriptType::COMPLEX :
+ {
+ aCharHeightName = "CharHeightComplex";
+ aCharWeightName = "CharWeightComplex";
+ aCharLocaleName = "CharLocaleComplex";
+ aCharPostureName = "CharPostureComplex";
+ break;
+ }
+ default:
+ {
+ aCharHeightName = "CharHeight";
+ aCharWeightName = "CharWeight";
+ aCharLocaleName = "CharLocale";
+ aCharPostureName = "CharPosture";
+ break;
+ }
+ }
+
+ mnCharHeight = 24;
+ if ( GetPropertyValue( mAny, mXPropSet, aCharHeightName ) )
+ {
+ float fVal(0.0);
+ if ( mAny >>= fVal )
+ {
+ mnCharHeight = static_cast<sal_uInt16>( fVal + 0.5 );
+ meCharHeight = GetPropertyState( mXPropSet, aCharHeightName );
+ }
+ }
+ if ( GetPropertyValue( mAny, mXPropSet, aCharWeightName ) )
+ {
+ float fFloat(0.0);
+ if ( mAny >>= fFloat )
+ {
+ if ( fFloat >= css::awt::FontWeight::SEMIBOLD )
+ mnCharAttr |= 1;
+ if ( GetPropertyState( mXPropSet, aCharWeightName ) == css::beans::PropertyState_DIRECT_VALUE )
+ mnCharAttrHard |= 1;
+ }
+ }
+ if ( GetPropertyValue( mAny, mXPropSet, aCharLocaleName ) )
+ {
+ css::lang::Locale eLocale;
+ if ( mAny >>= eLocale )
+ meCharLocale = eLocale;
+ }
+ if ( GetPropertyValue( mAny, mXPropSet, aCharPostureName ) )
+ {
+ css::awt::FontSlant aFS;
+ if ( mAny >>= aFS )
+ {
+ switch( aFS )
+ {
+ case css::awt::FontSlant_OBLIQUE :
+ case css::awt::FontSlant_ITALIC :
+ mnCharAttr |= 2;
+ break;
+ default:
+ break;
+ }
+ if ( GetPropertyState( mXPropSet, aCharPostureName ) == css::beans::PropertyState_DIRECT_VALUE )
+ mnCharAttrHard |= 2;
+ }
+ }
+
+ if ( ImplGetPropertyValue( "CharUnderline", bGetPropStateValue ) )
+ {
+ sal_Int16 nVal(0);
+ mAny >>= nVal;
+ switch ( nVal )
+ {
+ case css::awt::FontUnderline::SINGLE :
+ case css::awt::FontUnderline::DOUBLE :
+ case css::awt::FontUnderline::DOTTED :
+ mnCharAttr |= 4;
+ }
+ }
+ if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
+ mnCharAttrHard |= 4;
+
+ if ( ImplGetPropertyValue( "CharShadowed", bGetPropStateValue ) )
+ {
+ bool bBool(false);
+ mAny >>= bBool;
+ if ( bBool )
+ mnCharAttr |= 0x10;
+ }
+ if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
+ mnCharAttrHard |= 16;
+
+ if ( ImplGetPropertyValue( "CharRelief", bGetPropStateValue ) )
+ {
+ sal_Int16 nVal(0);
+ mAny >>= nVal;
+ if ( nVal != css::text::FontRelief::NONE )
+ mnCharAttr |= 512;
+ }
+ if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
+ mnCharAttrHard |= 512;
+
+ if ( ImplGetPropertyValue( "CharColor", bGetPropStateValue ) )
+ {
+ sal_uInt32 nSOColor = *( o3tl::doAccess<sal_uInt32>(mAny) );
+ mnCharColor = nSOColor & 0xff00ff00; // green and hibyte
+ mnCharColor |= static_cast<sal_uInt8>(nSOColor) << 16; // red and blue is switched
+ mnCharColor |= static_cast<sal_uInt8>( nSOColor >> 16 );
+ }
+ meCharColor = ePropState;
+
+ mnCharEscapement = 0;
+ if ( ImplGetPropertyValue( "CharEscapement", bGetPropStateValue ) )
+ {
+ mAny >>= mnCharEscapement;
+ if ( mnCharEscapement > 100 )
+ mnCharEscapement = 33;
+ else if ( mnCharEscapement < -100 )
+ mnCharEscapement = -33;
+ }
+ meCharEscapement = ePropState;
+}
+
+void PortionObj::ImplClear()
+{
+ mpFieldEntry.reset();
+ mpText.reset();
+}
+
+void PortionObj::ImplConstruct( const PortionObj& rPortionObj )
+{
+ meCharColor = rPortionObj.meCharColor;
+ meCharHeight = rPortionObj.meCharHeight;
+ meFontName = rPortionObj.meFontName;
+ meAsianOrComplexFont = rPortionObj.meAsianOrComplexFont;
+ meCharEscapement = rPortionObj.meCharEscapement;
+ meCharLocale = rPortionObj.meCharLocale;
+ mnCharAttrHard = rPortionObj.mnCharAttrHard;
+
+ mbLastPortion = rPortionObj.mbLastPortion;
+ mnTextSize = rPortionObj.mnTextSize;
+ mnCharColor = rPortionObj.mnCharColor;
+ mnCharEscapement = rPortionObj.mnCharEscapement;
+ mnCharAttr = rPortionObj.mnCharAttr;
+ mnCharHeight = rPortionObj.mnCharHeight;
+ mnFont = rPortionObj.mnFont;
+ mnAsianOrComplexFont = rPortionObj.mnAsianOrComplexFont;
+
+ if ( rPortionObj.mpText )
+ {
+ mpText.reset( new sal_uInt16[ mnTextSize ] );
+ memcpy( mpText.get(), rPortionObj.mpText.get(), mnTextSize << 1 );
+ }
+
+ if ( rPortionObj.mpFieldEntry )
+ mpFieldEntry.reset( new FieldEntry( *( rPortionObj.mpFieldEntry ) ) );
+}
+
+sal_uInt32 PortionObj::ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition )
+{
+ if ( mpFieldEntry && ( !mpFieldEntry->nFieldStartPos ) )
+ {
+ mpFieldEntry->nFieldStartPos += nCurrentTextPosition;
+ mpFieldEntry->nFieldEndPos += nCurrentTextPosition;
+ }
+ return mnTextSize;
+}
+
+// Return: 0 = no TextField
+// bit28->31 text field type :
+// 1 = Date
+// 2 = Time
+// 3 = SlideNumber
+// 4 = Url
+// 5 = DateTime
+// 6 = header
+// 7 = footer
+// bit24->27 text field sub type (optional)
+// 23-> PPT Textfield needs a placeholder
+
+sal_uInt32 PortionObj::ImplGetTextField( css::uno::Reference< css::text::XTextRange > & ,
+ const css::uno::Reference< css::beans::XPropertySet > & rXPropSet, OUString& rURL )
+{
+ sal_uInt32 nRetValue = 0;
+ sal_Int32 nFormat;
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, rXPropSet, "TextPortionType", true ) )
+ {
+ auto aTextFieldType = o3tl::doAccess<OUString>(aAny);
+ if ( *aTextFieldType == "TextField" )
+ {
+ if ( GetPropertyValue( aAny, rXPropSet, *aTextFieldType, true ) )
+ {
+ css::uno::Reference< css::text::XTextField > aXTextField;
+ if ( aAny >>= aXTextField )
+ {
+ if ( aXTextField.is() )
+ {
+ css::uno::Reference< css::beans::XPropertySet > xFieldPropSet( aXTextField, css::uno::UNO_QUERY );
+ if ( xFieldPropSet.is() )
+ {
+ OUString aFieldKind( aXTextField->getPresentation( true ) );
+ if ( aFieldKind == "Date" )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
+ {
+ bool bBool = false;
+ aAny >>= bBool;
+ if ( !bBool ) // Fixed DateFields does not exist in PPT
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "Format", true ) )
+ {
+ nFormat = *o3tl::doAccess<sal_Int32>(aAny);
+ switch ( nFormat )
+ {
+ default:
+ case 5 :
+ case 4 :
+ case 2 : nFormat = 0; break;
+ case 8 :
+ case 9 :
+ case 3 : nFormat = 1; break;
+ case 7 :
+ case 6 : nFormat = 2; break;
+ }
+ nRetValue |= ( ( ( 1 << 4 ) | nFormat ) << 24 ) | 0x800000;
+ }
+ }
+ }
+ }
+ else if ( aFieldKind == "URL" )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "URL", true ) )
+ rURL = *o3tl::doAccess<OUString>(aAny);
+ nRetValue = 4 << 28;
+ }
+ else if ( aFieldKind == "Page" )
+ {
+ nRetValue = 3 << 28 | 0x800000;
+ }
+ else if ( aFieldKind == "Pages" )
+ {
+
+ }
+ else if ( aFieldKind == "Time" )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
+ {
+ bool bBool = false;
+ aAny >>= bBool;
+ if ( !bBool )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
+ {
+ nFormat = *o3tl::doAccess<sal_Int32>(aAny);
+ nRetValue |= ( ( ( 2 << 4 ) | nFormat ) << 24 ) | 0x800000;
+ }
+ }
+ }
+ }
+ else if ( aFieldKind == "File" )
+ {
+
+ }
+ else if ( aFieldKind == "Table" )
+ {
+
+ }
+ else if ( aFieldKind == "ExtTime" )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
+ {
+ bool bBool = false;
+ aAny >>= bBool;
+ if ( !bBool )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "Format", true ) )
+ {
+ nFormat = *o3tl::doAccess<sal_Int32>(aAny);
+ switch ( nFormat )
+ {
+ default:
+ case 6 :
+ case 7 :
+ case 8 :
+ case 2 : nFormat = 12; break;
+ case 3 : nFormat = 9; break;
+ case 5 :
+ case 4 : nFormat = 10; break;
+
+ }
+ nRetValue |= ( ( ( 2 << 4 ) | nFormat ) << 24 ) | 0x800000;
+ }
+ }
+ }
+ }
+ else if ( aFieldKind == "ExtFile" )
+ {
+
+ }
+ else if ( aFieldKind == "Author" )
+ {
+
+ }
+ else if ( aFieldKind == "DateTime" )
+ {
+ nRetValue = 5 << 28 | 0x800000;
+ }
+ else if ( aFieldKind == "Header" )
+ {
+ nRetValue = 6 << 28 | 0x800000;
+ }
+ else if ( aFieldKind == "Footer" )
+ {
+ nRetValue = 7 << 28 | 0x800000;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return nRetValue;
+}
+
+PortionObj& PortionObj::operator=( const PortionObj& rPortionObj )
+{
+ if ( this != &rPortionObj )
+ {
+ ImplClear();
+ ImplConstruct( rPortionObj );
+ }
+ return *this;
+}
+
+ParagraphObj::ParagraphObj(const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ PPTExBulletProvider* pProv)
+ : mnTextSize(0)
+ , mbFirstParagraph(false)
+ , mbLastParagraph(false)
+ , meBullet(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , mnTextAdjust(0)
+ , mnLineSpacing(0)
+ , mbFixedLineSpacing(false)
+ , mnLineSpacingTop(0)
+ , mnLineSpacingBottom(0)
+ , mbForbiddenRules(false)
+ , mbParagraphPunctation(false)
+ , mnBiDi(0)
+{
+ mXPropSet = rXPropSet;
+
+ bExtendedParameters = false;
+
+ nDepth = 0;
+ nBulletFlags = 0;
+ nParaFlags = 0;
+
+ ImplGetParagraphValues( pProv, false );
+}
+
+ParagraphObj::ParagraphObj(css::uno::Reference< css::text::XTextContent > const & rXTextContent,
+ ParaFlags aParaFlags, FontCollection& rFontCollection, PPTExBulletProvider& rProv )
+ : mnTextSize(0)
+ , mbIsBullet(false)
+ , mbFirstParagraph( aParaFlags.bFirstParagraph )
+ , mbLastParagraph( aParaFlags.bLastParagraph )
+ , meBullet(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meTextAdjust(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meLineSpacing(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meLineSpacingTop(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meLineSpacingBottom(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meForbiddenRules(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meParagraphPunctation(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meBiDi(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , mnTextAdjust(0)
+ , mnLineSpacing(0)
+ , mbFixedLineSpacing(false)
+ , mnLineSpacingTop(0)
+ , mnLineSpacingBottom(0)
+ , mbForbiddenRules(false)
+ , mbParagraphPunctation(false)
+ , mnBiDi(0)
+{
+ bExtendedParameters = false;
+
+ nDepth = 0;
+ nBulletFlags = 0;
+ nParaFlags = 0;
+
+ mXPropSet.set( rXTextContent, css::uno::UNO_QUERY );
+
+ mXPropState.set( rXTextContent, css::uno::UNO_QUERY );
+
+ if ( !(mXPropSet.is() && mXPropState.is()) )
+ return;
+
+ css::uno::Reference< css::container::XEnumerationAccess > aXTextPortionEA( rXTextContent, css::uno::UNO_QUERY );
+ if ( aXTextPortionEA.is() )
+ {
+ css::uno::Reference< css::container::XEnumeration > aXTextPortionE( aXTextPortionEA->createEnumeration() );
+ if ( aXTextPortionE.is() )
+ {
+ while ( aXTextPortionE->hasMoreElements() )
+ {
+ css::uno::Reference< css::text::XTextRange > aXCursorText;
+ css::uno::Any aAny( aXTextPortionE->nextElement() );
+ if ( aAny >>= aXCursorText )
+ {
+ std::unique_ptr<PortionObj> pPortionObj(new PortionObj( aXCursorText, !aXTextPortionE->hasMoreElements(), rFontCollection ));
+ if ( pPortionObj->Count() )
+ mvPortions.push_back( std::move(pPortionObj) );
+ }
+ }
+ }
+ }
+ ImplGetParagraphValues( &rProv, true );
+}
+
+ParagraphObj::~ParagraphObj()
+{
+ ImplClear();
+}
+
+void ParagraphObj::Write( SvStream* pStrm )
+{
+ for ( std::vector<std::unique_ptr<PortionObj> >::iterator it = mvPortions.begin(); it != mvPortions.end(); ++it )
+ (*it)->Write( pStrm, mbLastParagraph );
+}
+
+void ParagraphObj::ImplClear()
+{
+ mvPortions.clear();
+}
+
+void ParagraphObj::CalculateGraphicBulletSize( sal_uInt16 nFontHeight )
+{
+ if ( ( nNumberingType != SVX_NUM_BITMAP ) || ( nBulletId == 0xffff ) )
+ return;
+
+ // calculate the bullet real size for this graphic
+ if ( aBuGraSize.Width() && aBuGraSize.Height() )
+ {
+ double fCharHeight = nFontHeight;
+ double fLen = aBuGraSize.Height();
+ fCharHeight = fCharHeight * 0.2540;
+ double fQuo = fLen / fCharHeight;
+ nBulletRealSize = static_cast<sal_Int16>( fQuo + 0.5 );
+ if ( static_cast<sal_uInt16>(nBulletRealSize) > 400 )
+ nBulletRealSize = 400;
+ }
+}
+
+void ParagraphObj::ImplGetNumberingLevel( PPTExBulletProvider* pBuProv, sal_Int16 nNumberingDepth, bool bIsBullet, bool bGetPropStateValue )
+{
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, mXPropSet, "ParaLeftMargin" ) )
+ {
+ sal_Int32 nVal(0);
+ if ( aAny >>= nVal )
+ nTextOfs = convertMm100ToMasterUnit(nVal);
+ }
+ if ( GetPropertyValue( aAny, mXPropSet, "ParaFirstLineIndent" ) )
+ {
+ if ( aAny >>= nBulletOfs )
+ nBulletOfs = convertMm100ToMasterUnit(nBulletOfs);
+ }
+ if ( GetPropertyValue( aAny, mXPropSet, "NumberingIsNumber" ) )
+ aAny >>= bNumberingIsNumber;
+
+ css::uno::Reference< css::container::XIndexReplace > aXIndexReplace;
+
+ if ( bIsBullet && ImplGetPropertyValue( "NumberingRules", bGetPropStateValue ) )
+ {
+ if ( ( mAny >>= aXIndexReplace ) && nNumberingDepth < aXIndexReplace->getCount() )
+ {
+ mAny = aXIndexReplace->getByIndex( nNumberingDepth );
+ auto aPropertySequence = o3tl::doAccess<css::uno::Sequence<css::beans::PropertyValue>>(mAny);
+
+ if ( aPropertySequence->hasElements() )
+ {
+ bExtendedParameters = true;
+ nBulletRealSize = 100;
+ nMappedNumType = 0;
+
+ uno::Reference<graphic::XGraphic> xGraphic;
+ for ( const css::beans::PropertyValue& rPropValue : *aPropertySequence )
+ {
+ OUString aPropName( rPropValue.Name );
+ if ( aPropName == "NumberingType" )
+ nNumberingType = static_cast<SvxNumType>(*o3tl::doAccess<sal_Int16>(rPropValue.Value));
+ else if ( aPropName == "Adjust" )
+ nHorzAdjust = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
+ else if ( aPropName == "BulletChar" )
+ {
+ OUString aString( *o3tl::doAccess<OUString>(rPropValue.Value) );
+ if ( !aString.isEmpty() )
+ cBulletId = aString[ 0 ];
+ }
+ else if ( aPropName == "BulletFont" )
+ {
+ aFontDesc = *o3tl::doAccess<css::awt::FontDescriptor>(rPropValue.Value);
+
+ // Our numbullet dialog has set the wrong textencoding for our "StarSymbol" font,
+ // instead of a Unicode encoding the encoding RTL_TEXTENCODING_SYMBOL was used.
+ // Because there might exist a lot of damaged documents I added this two lines
+ // which fixes the bullet problem for the export.
+ if ( aFontDesc.Name.equalsIgnoreAsciiCase("StarSymbol") )
+ aFontDesc.CharSet = RTL_TEXTENCODING_MS_1252;
+
+ }
+ else if ( aPropName == "GraphicBitmap" )
+ {
+ auto xBitmap = rPropValue.Value.get<uno::Reference<awt::XBitmap>>();
+ xGraphic.set(xBitmap, uno::UNO_QUERY);
+ }
+ else if ( aPropName == "GraphicSize" )
+ {
+ if (auto aSize = o3tl::tryAccess<css::awt::Size>(rPropValue.Value))
+ {
+ // don't cast awt::Size to Size as on 64-bits they are not the same.
+ aBuGraSize.setWidth( aSize->Width );
+ aBuGraSize.setHeight( aSize->Height );
+ }
+ }
+ else if ( aPropName == "StartWith" )
+ nStartWith = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
+ else if ( aPropName == "LeftMargin" )
+ nTextOfs += convertMm100ToMasterUnit(*o3tl::doAccess<sal_Int32>(rPropValue.Value));
+ else if ( aPropName == "FirstLineOffset" )
+ nBulletOfs += convertMm100ToMasterUnit(*o3tl::doAccess<sal_Int32>(rPropValue.Value));
+ else if ( aPropName == "BulletColor" )
+ {
+ sal_uInt32 nSOColor = *o3tl::doAccess<sal_uInt32>(rPropValue.Value);
+ nBulletColor = nSOColor & 0xff00ff00; // green and hibyte
+ nBulletColor |= static_cast<sal_uInt8>(nSOColor) << 16; // red
+ nBulletColor |= static_cast<sal_uInt8>( nSOColor >> 16 ) | 0xfe000000; // blue
+ }
+ else if ( aPropName == "BulletRelSize" )
+ {
+ nBulletRealSize = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
+ nParaFlags |= 0x40;
+ nBulletFlags |= 8;
+ }
+ else if ( aPropName == "Prefix" )
+ sPrefix = *o3tl::doAccess<OUString>(rPropValue.Value);
+ else if ( aPropName == "Suffix" )
+ sSuffix = *o3tl::doAccess<OUString>(rPropValue.Value);
+#ifdef DBG_UTIL
+ else if ( aPropName != "SymbolTextDistance" && aPropName != "GraphicBitmap" )
+ {
+ OSL_FAIL( "Unknown Property" );
+ }
+#endif
+ }
+
+ if (xGraphic.is())
+ {
+ if ( aBuGraSize.Width() && aBuGraSize.Height() )
+ {
+ nBulletId = pBuProv->GetId(xGraphic, aBuGraSize );
+ if ( nBulletId != 0xffff )
+ bExtendedBulletsUsed = true;
+ }
+ else
+ {
+ nNumberingType = SVX_NUM_NUMBER_NONE;
+ }
+ }
+
+ CalculateGraphicBulletSize( ( mvPortions.empty() ) ? 24 : mvPortions.front()->mnCharHeight );
+
+ switch( nNumberingType )
+ {
+ case SVX_NUM_NUMBER_NONE : nParaFlags |= 0xf; break;
+
+ case SVX_NUM_CHAR_SPECIAL : // Bullet
+ {
+ if ( IsStarSymbol(aFontDesc.Name) )
+ {
+ rtl_TextEncoding eChrSet = aFontDesc.CharSet;
+ cBulletId = msfilter::util::bestFitOpenSymbolToMSFont(cBulletId, eChrSet, aFontDesc.Name);
+ aFontDesc.CharSet = eChrSet;
+ }
+
+ if ( !aFontDesc.Name.isEmpty() )
+ {
+ nParaFlags |= 0x90; // we define the font and charset
+ }
+
+ [[fallthrough]];
+ }
+ case SVX_NUM_CHARS_UPPER_LETTER : // count from a-z, aa - az, ba - bz, ...
+ case SVX_NUM_CHARS_LOWER_LETTER :
+ case SVX_NUM_ROMAN_UPPER :
+ case SVX_NUM_ROMAN_LOWER :
+ case SVX_NUM_ARABIC :
+ case SVX_NUM_PAGEDESC : // numbering from the page template
+ case SVX_NUM_BITMAP :
+ case SVX_NUM_CHARS_UPPER_LETTER_N : // count from a-z, aa-zz, aaa-zzz
+ case SVX_NUM_CHARS_LOWER_LETTER_N :
+ case SVX_NUM_NUMBER_UPPER_ZH:
+ case SVX_NUM_CIRCLE_NUMBER:
+ case SVX_NUM_NUMBER_UPPER_ZH_TW:
+ case SVX_NUM_NUMBER_LOWER_ZH:
+ case SVX_NUM_FULL_WIDTH_ARABIC:
+ {
+ if ( nNumberingType != SVX_NUM_CHAR_SPECIAL )
+ {
+ bExtendedBulletsUsed = true;
+ if ( nNumberingDepth & 1 )
+ cBulletId = 0x2013; // defaulting bullet characters for ppt97
+ else if ( nNumberingDepth == 4 )
+ cBulletId = 0xbb;
+ else
+ cBulletId = 0x2022;
+
+ switch( nNumberingType )
+ {
+ case SVX_NUM_CHARS_UPPER_LETTER :
+ case SVX_NUM_CHARS_UPPER_LETTER_N :
+ {
+ if ( sSuffix == ")" )
+ {
+ if ( sPrefix == "(" )
+ nMappedNumType = 0xa0001; // (A)
+ else
+ nMappedNumType = 0xb0001; // A)
+ }
+ else
+ nMappedNumType = 0x10001; // A.
+ }
+ break;
+ case SVX_NUM_CHARS_LOWER_LETTER :
+ case SVX_NUM_CHARS_LOWER_LETTER_N :
+ {
+ if ( sSuffix == ")" )
+ {
+ if ( sPrefix == "(" )
+ nMappedNumType = 0x80001; // (a)
+ else
+ nMappedNumType = 0x90001; // a)
+ }
+ else
+ nMappedNumType = 0x00001; // a.
+ }
+ break;
+ case SVX_NUM_ROMAN_UPPER :
+ {
+ if ( sSuffix == ")" )
+ {
+ if ( sPrefix == "(" )
+ nMappedNumType = 0xe0001; // (I)
+ else
+ nMappedNumType = 0xf0001; // I)
+ }
+ else
+ nMappedNumType = 0x70001; // I.
+ }
+ break;
+ case SVX_NUM_ROMAN_LOWER :
+ {
+ if ( sSuffix == ")" )
+ {
+ if ( sPrefix == "(" )
+ nMappedNumType = 0x40001; // (i)
+ else
+ nMappedNumType = 0x50001; // i)
+ }
+ else
+ nMappedNumType = 0x60001; // i.
+ }
+ break;
+ case SVX_NUM_ARABIC :
+ {
+ if ( sSuffix == ")" )
+ {
+ if ( sPrefix == "(" )
+ nMappedNumType = 0xc0001; // (1)
+ else
+ nMappedNumType = 0x20001; // 1)
+ }
+ else
+ {
+ if ( sSuffix.isEmpty() && sPrefix.isEmpty() )
+ nMappedNumType = 0xd0001; // 1
+ else
+ nMappedNumType = 0x30001; // 1.
+ }
+ }
+ break;
+ case SVX_NUM_NUMBER_UPPER_ZH :
+ {
+ if ( !sSuffix.isEmpty() )
+ nMappedNumType = 0x110001; // Simplified Chinese with single-byte period.
+ else
+ nMappedNumType = 0x100001; // Simplified Chinese.
+ }
+ break;
+ case SVX_NUM_CIRCLE_NUMBER :
+ {
+ nMappedNumType = 0x120001; // Double byte circle numbers.
+ }
+ break;
+ case SVX_NUM_NUMBER_UPPER_ZH_TW :
+ {
+ if ( !sSuffix.isEmpty() )
+ nMappedNumType = 0x160001; // Traditional Chinese with single-byte period.
+ else
+ nMappedNumType = 0x150001; // Traditional Chinese.
+ }
+ break;
+ case SVX_NUM_NUMBER_LOWER_ZH :
+ {
+ if ( sSuffix == u"\uff0e" )
+ nMappedNumType = 0x260001; // Japanese with double-byte period.
+ else if ( !sSuffix.isEmpty() )
+ nMappedNumType = 0x1B0001; // Japanese/Korean with single-byte period.
+ else
+ nMappedNumType = 0x1A0001; // Japanese/Korean.
+ }
+ break;
+ case SVX_NUM_FULL_WIDTH_ARABIC :
+ {
+ if ( !sSuffix.isEmpty() )
+ nMappedNumType = 0x1D0001; // Double-byte Arabic numbers with double-byte period.
+ else
+ nMappedNumType = 0x1C0001; // Double-byte Arabic numbers.
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ nParaFlags |= 0x2f;
+ nBulletFlags |= 6;
+ if ( mbIsBullet && bNumberingIsNumber )
+ nBulletFlags |= 1;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+ nBulletOfs = nTextOfs + nBulletOfs;
+ if ( nBulletOfs < 0 )
+ nBulletOfs = 0;
+}
+
+void ParagraphObj::ImplGetParagraphValues( PPTExBulletProvider* pBuProv, bool bGetPropStateValue )
+{
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, mXPropSet, "NumberingLevel", true ) )
+ {
+ if ( bGetPropStateValue )
+ meBullet = GetPropertyState( mXPropSet, "NumberingLevel" );
+ nDepth = *o3tl::doAccess<sal_Int16>(aAny);
+
+ if ( nDepth < 0 )
+ {
+ mbIsBullet = false;
+ nDepth = 0;
+ }
+ else
+ {
+ if ( nDepth > 4 )
+ nDepth = 4;
+ mbIsBullet = true;
+ }
+ }
+ else
+ {
+ nDepth = 0;
+ mbIsBullet = false;
+ }
+ ImplGetNumberingLevel( pBuProv, nDepth, mbIsBullet, bGetPropStateValue );
+
+ if ( ImplGetPropertyValue( "ParaTabStops", bGetPropStateValue ) )
+ maTabStop = *o3tl::doAccess<css::uno::Sequence<css::style::TabStop>>(mAny);
+ sal_Int16 eTextAdjust = sal_Int16(css::style::ParagraphAdjust_LEFT);
+ if ( GetPropertyValue( aAny, mXPropSet, "ParaAdjust", bGetPropStateValue ) )
+ aAny >>= eTextAdjust;
+ switch ( static_cast<css::style::ParagraphAdjust>(eTextAdjust) )
+ {
+ case css::style::ParagraphAdjust_CENTER :
+ mnTextAdjust = 1;
+ break;
+ case css::style::ParagraphAdjust_RIGHT :
+ mnTextAdjust = 2;
+ break;
+ case css::style::ParagraphAdjust_BLOCK :
+ mnTextAdjust = 3;
+ break;
+ default :
+ case css::style::ParagraphAdjust_LEFT :
+ mnTextAdjust = 0;
+ break;
+ }
+ meTextAdjust = ePropState;
+
+ if ( ImplGetPropertyValue( "ParaLineSpacing", bGetPropStateValue ) )
+ {
+ css::style::LineSpacing aLineSpacing
+ = *o3tl::doAccess<css::style::LineSpacing>(mAny);
+ switch ( aLineSpacing.Mode )
+ {
+ case css::style::LineSpacingMode::FIX :
+ mnLineSpacing = static_cast<sal_Int16>(-( aLineSpacing.Height ) );
+ mbFixedLineSpacing = true;
+ break;
+ case css::style::LineSpacingMode::MINIMUM :
+ case css::style::LineSpacingMode::LEADING :
+ mnLineSpacing = static_cast<sal_Int16>(-( aLineSpacing.Height ) );
+ mbFixedLineSpacing = false;
+ break;
+
+ case css::style::LineSpacingMode::PROP :
+ default:
+ mnLineSpacing = aLineSpacing.Height;
+ break;
+ }
+ }
+ meLineSpacing = ePropState;
+
+ if ( ImplGetPropertyValue( "ParaBottomMargin", bGetPropStateValue ) )
+ {
+ double fSpacing = *o3tl::doAccess<sal_uInt32>(mAny) + convertMasterUnitToMm100(1.0) - 1;
+ mnLineSpacingBottom = std::round(-convertMm100ToMasterUnit(fSpacing));
+ }
+ meLineSpacingBottom = ePropState;
+
+ if ( ImplGetPropertyValue( "ParaTopMargin", bGetPropStateValue ) )
+ {
+ double fSpacing = *o3tl::doAccess<sal_uInt32>(mAny) + convertMasterUnitToMm100(1.0) - 1;
+ mnLineSpacingTop = std::round(-convertMm100ToMasterUnit(fSpacing));
+ }
+ meLineSpacingTop = ePropState;
+
+ if ( ImplGetPropertyValue( "ParaIsForbiddenRules", bGetPropStateValue ) )
+ mAny >>= mbForbiddenRules;
+ meForbiddenRules = ePropState;
+
+ if ( ImplGetPropertyValue( "ParaIsHangingPunctuation", bGetPropStateValue ) )
+ mAny >>= mbParagraphPunctation;
+ meParagraphPunctation = ePropState;
+
+ mnBiDi = 0;
+ if ( ImplGetPropertyValue( "WritingMode", bGetPropStateValue ) )
+ {
+ sal_Int16 nWritingMode = 0;
+ mAny >>= nWritingMode;
+
+ SvxFrameDirection eWritingMode = static_cast<SvxFrameDirection>(nWritingMode);
+ if ( ( eWritingMode == SvxFrameDirection::Horizontal_RL_TB )
+ || ( eWritingMode == SvxFrameDirection::Vertical_RL_TB ) )
+ {
+ mnBiDi = 1;
+ }
+ }
+ meBiDi = ePropState;
+}
+
+void ParagraphObj::ImplConstruct( const ParagraphObj& rParagraphObj )
+{
+ mbIsBullet = rParagraphObj.mbIsBullet;
+ meBullet = rParagraphObj.meBullet;
+ meTextAdjust = rParagraphObj.meTextAdjust;
+ meLineSpacing = rParagraphObj.meLineSpacing;
+ meLineSpacingTop = rParagraphObj.meLineSpacingTop;
+ meLineSpacingBottom = rParagraphObj.meLineSpacingBottom;
+ meForbiddenRules = rParagraphObj.meForbiddenRules;
+ meParagraphPunctation = rParagraphObj.meParagraphPunctation;
+ meBiDi =rParagraphObj.meBiDi;
+ mbFixedLineSpacing = rParagraphObj.mbFixedLineSpacing;
+ mnTextSize = rParagraphObj.mnTextSize;
+ mnTextAdjust = rParagraphObj.mnTextAdjust;
+ mnLineSpacing = rParagraphObj.mnLineSpacing;
+ mnLineSpacingTop = rParagraphObj.mnLineSpacingTop;
+ mnLineSpacingBottom = rParagraphObj.mnLineSpacingBottom;
+ mbFirstParagraph = rParagraphObj.mbFirstParagraph;
+ mbLastParagraph = rParagraphObj.mbLastParagraph;
+ mbParagraphPunctation = rParagraphObj.mbParagraphPunctation;
+ mbForbiddenRules = rParagraphObj.mbForbiddenRules;
+ mnBiDi = rParagraphObj.mnBiDi;
+
+ for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = rParagraphObj.begin(); it != rParagraphObj.end(); ++it )
+ mvPortions.push_back( std::make_unique<PortionObj>( **it ) );
+
+ maTabStop = rParagraphObj.maTabStop;
+ bExtendedParameters = rParagraphObj.bExtendedParameters;
+ nParaFlags = rParagraphObj.nParaFlags;
+ nBulletFlags = rParagraphObj.nBulletFlags;
+ sPrefix = rParagraphObj.sPrefix;
+ sSuffix = rParagraphObj.sSuffix;
+ sGraphicUrl = rParagraphObj.sGraphicUrl; // String to a graphic
+ aBuGraSize = rParagraphObj.aBuGraSize;
+ nNumberingType = rParagraphObj.nNumberingType; // this is actually a SvxEnum
+ nHorzAdjust = rParagraphObj.nHorzAdjust;
+ nBulletColor = rParagraphObj.nBulletColor;
+ nBulletOfs = rParagraphObj.nBulletOfs;
+ nStartWith = rParagraphObj.nStartWith; // start of numbering
+ nTextOfs = rParagraphObj.nTextOfs;
+ nBulletRealSize = rParagraphObj.nBulletRealSize; // scale in percent
+ nDepth = rParagraphObj.nDepth; // actual depth
+ cBulletId = rParagraphObj.cBulletId; // if Numbering Type == CharSpecial
+ aFontDesc = rParagraphObj.aFontDesc;
+
+ bExtendedBulletsUsed = rParagraphObj.bExtendedBulletsUsed;
+ nBulletId = rParagraphObj.nBulletId;
+}
+
+sal_uInt32 ParagraphObj::ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition )
+{
+ mnTextSize = 0;
+ for ( std::vector<std::unique_ptr<PortionObj> >::iterator it = mvPortions.begin(); it != mvPortions.end(); ++it )
+ mnTextSize += (*it)->ImplCalculateTextPositions( nCurrentTextPosition + mnTextSize );
+ return mnTextSize;
+}
+
+ParagraphObj& ParagraphObj::operator=( const ParagraphObj& rParagraphObj )
+{
+ if ( this != &rParagraphObj )
+ {
+ ImplClear();
+ ImplConstruct( rParagraphObj );
+ }
+ return *this;
+}
+
+struct ImplTextObj
+{
+ sal_uInt32 mnTextSize;
+ int mnInstance;
+ std::vector<std::unique_ptr<ParagraphObj>> maList;
+ bool mbHasExtendedBullets;
+
+ explicit ImplTextObj( int nInstance );
+};
+
+ImplTextObj::ImplTextObj( int nInstance )
+ : mnTextSize(0),
+ mnInstance(nInstance),
+ mbHasExtendedBullets(false)
+{
+}
+
+TextObj::TextObj( css::uno::Reference< css::text::XSimpleText > const & rXTextRef,
+ int nInstance, FontCollection& rFontCollection, PPTExBulletProvider& rProv ):
+ mpImplTextObj(std::make_shared<ImplTextObj>(nInstance))
+{
+ css::uno::Reference< css::container::XEnumerationAccess > aXTextParagraphEA( rXTextRef, css::uno::UNO_QUERY );
+
+ if ( aXTextParagraphEA.is() )
+ {
+ css::uno::Reference< css::container::XEnumeration > aXTextParagraphE( aXTextParagraphEA->createEnumeration() );
+ if ( aXTextParagraphE.is() )
+ {
+ ParaFlags aParaFlags;
+ while ( aXTextParagraphE->hasMoreElements() )
+ {
+ css::uno::Reference< css::text::XTextContent > aXParagraph;
+ css::uno::Any aAny( aXTextParagraphE->nextElement() );
+ if ( aAny >>= aXParagraph )
+ {
+ if ( !aXTextParagraphE->hasMoreElements() )
+ aParaFlags.bLastParagraph = true;
+ std::unique_ptr<ParagraphObj> pPara(new ParagraphObj( aXParagraph, aParaFlags, rFontCollection, rProv ));
+ mpImplTextObj->mbHasExtendedBullets |= pPara->bExtendedBulletsUsed;
+ mpImplTextObj->maList.push_back( std::move(pPara) );
+ aParaFlags.bFirstParagraph = false;
+ }
+ }
+ }
+ }
+ ImplCalculateTextPositions();
+}
+
+void TextObj::ImplCalculateTextPositions()
+{
+ mpImplTextObj->mnTextSize = 0;
+ for ( sal_uInt32 i = 0; i < ParagraphCount(); ++i )
+ mpImplTextObj->mnTextSize += GetParagraph(i)->ImplCalculateTextPositions( mpImplTextObj->mnTextSize );
+}
+
+ParagraphObj* TextObj::GetParagraph(int idx)
+{
+ return mpImplTextObj->maList[idx].get();
+}
+
+sal_uInt32 TextObj::ParagraphCount() const
+{
+ return mpImplTextObj->maList.size();
+}
+
+sal_uInt32 TextObj::Count() const
+{
+ return mpImplTextObj->mnTextSize;
+}
+
+int TextObj::GetInstance() const
+{
+ return mpImplTextObj->mnInstance;
+}
+
+bool TextObj::HasExtendedBullets() const
+{
+ return mpImplTextObj->mbHasExtendedBullets;
+}
+
+void FontCollectionEntry::ImplInit( const OUString& rName )
+{
+ OUString aSubstName( GetSubsFontName( rName, SubsFontFlags::ONLYONE | SubsFontFlags::MS ) );
+ if ( !aSubstName.isEmpty() )
+ {
+ Name = aSubstName;
+ }
+ else
+ {
+ Name = rName;
+ }
+}
+
+FontCollection::~FontCollection()
+{
+ pVDev.disposeAndClear();
+ xPPTBreakIter = nullptr;
+}
+
+FontCollection::FontCollection() :
+ pVDev ( nullptr )
+{
+ xPPTBreakIter = css::i18n::BreakIterator::create( ::comphelper::getProcessComponentContext() );
+}
+
+short FontCollection::GetScriptDirection( std::u16string_view rString )
+{
+ short nRet = ScriptTypeDetector::getScriptDirection( rString, 0, css::i18n::ScriptDirection::NEUTRAL );
+ return nRet;
+}
+
+sal_uInt32 FontCollection::GetId( FontCollectionEntry& rEntry )
+{
+ if( !rEntry.Name.isEmpty() )
+ {
+ const sal_uInt32 nFonts = maFonts.size();
+
+ for( sal_uInt32 i = 0; i < nFonts; i++ )
+ {
+ const FontCollectionEntry* pEntry = GetById( i );
+ if( pEntry->Name == rEntry.Name )
+ return i;
+ }
+ vcl::Font aFont;
+ aFont.SetCharSet( rEntry.CharSet );
+ aFont.SetFamilyName( rEntry.Original );
+ aFont.SetFontHeight( 100 );
+
+ if ( !pVDev )
+ pVDev = VclPtr<VirtualDevice>::Create();
+
+ pVDev->SetFont( aFont );
+ FontMetric aMetric( pVDev->GetFontMetric() );
+
+ sal_uInt16 nTxtHeight = static_cast<sal_uInt16>(aMetric.GetAscent()) + static_cast<sal_uInt16>(aMetric.GetDescent());
+
+ if ( nTxtHeight )
+ {
+ double fScaling = static_cast<double>(nTxtHeight) / 120.0;
+ if ( ( fScaling > 0.50 ) && ( fScaling < 1.5 ) )
+ rEntry.Scaling = fScaling;
+ }
+
+ maFonts.push_back(rEntry);
+ return nFonts;
+ }
+ return 0;
+}
+
+const FontCollectionEntry* FontCollection::GetById( sal_uInt32 nId )
+{
+ return nId < maFonts.size() ? &maFonts[nId] : nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/text.hxx b/sd/source/filter/eppt/text.hxx
new file mode 100644
index 000000000..ee2fc537c
--- /dev/null
+++ b/sd/source/filter/eppt/text.hxx
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "epptbase.hxx"
+
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <editeng/svxenum.hxx>
+#include <vector>
+#include <memory>
+
+namespace com::sun::star {
+ namespace awt { struct FontDescriptor; }
+ namespace beans { class XPropertyState; }
+ namespace text { class XTextRange; class XTextContent; class XSimpleText; }
+ namespace style { struct TabStop; }
+}
+
+struct SOParagraph
+{
+ bool bExtendedParameters;
+ sal_uInt32 nParaFlags;
+ sal_Int16 nBulletFlags;
+ OUString sPrefix;
+ OUString sSuffix;
+ OUString sGraphicUrl; // String to a graphic
+ Size aBuGraSize;
+ SvxNumType nNumberingType;
+ sal_uInt32 nHorzAdjust;
+ sal_uInt32 nBulletColor;
+ sal_Int32 nBulletOfs;
+ sal_Int16 nStartWith; // start of numbering
+ sal_Int16 nTextOfs;
+ sal_Int16 nBulletRealSize; // scale in percent
+ sal_Int16 nDepth; // actual depth
+ sal_Unicode cBulletId; // if Numbering Type == CharSpecial
+ css::awt::FontDescriptor aFontDesc;
+
+ bool bExtendedBulletsUsed;
+ sal_uInt16 nBulletId;
+ sal_uInt32 nMappedNumType;
+ bool bNumberingIsNumber;
+
+ SOParagraph()
+ : bExtendedParameters(false)
+ , nParaFlags(0)
+ , nBulletFlags(0)
+ , nNumberingType(SVX_NUM_NUMBER_NONE)
+ , nHorzAdjust(0)
+ , nBulletColor(0)
+ , nBulletOfs(0)
+ , nStartWith(0)
+ , nTextOfs(0)
+ , nBulletRealSize(0)
+ , nDepth(0)
+ , cBulletId(0)
+ , bExtendedBulletsUsed(false)
+ , nBulletId(0xffff)
+ , nMappedNumType(0)
+ , bNumberingIsNumber(true)
+ {
+ }
+};
+
+class PropStateValue : public PropValue
+{
+public:
+ PropStateValue()
+ : PropValue()
+ , ePropState(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ {
+ }
+protected:
+ css::beans::PropertyState ePropState;
+ css::uno::Reference < css::beans::XPropertyState > mXPropState;
+
+ bool ImplGetPropertyValue( const OUString& rString, bool bGetPropertyState );
+};
+
+struct FieldEntry
+{
+ sal_uInt32 nFieldType;
+ sal_uInt32 nFieldStartPos;
+ sal_uInt32 nFieldEndPos;
+ OUString aRepresentation;
+ OUString aFieldUrl;
+
+ FieldEntry( sal_uInt32 nType, sal_uInt32 nStart, sal_uInt32 nEnd )
+ : nFieldType(nType),
+ nFieldStartPos(nStart),
+ nFieldEndPos(nEnd)
+ {
+ }
+};
+
+class PortionObj final : public PropStateValue
+{
+
+ friend class ParagraphObj;
+
+ void ImplClear();
+ void ImplConstruct( const PortionObj& rPortionObj );
+ static sal_uInt32 ImplGetTextField( css::uno::Reference< css::text::XTextRange > & rXTextRangeRef,
+ const css::uno::Reference< css::beans::XPropertySet > & rXPropSetRef, OUString& rURL );
+ sal_uInt32 ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition );
+ void ImplGetPortionValues( FontCollection& rFontCollection, bool bGetPropStateValue );
+
+ public:
+
+ css::beans::PropertyState meCharColor;
+ css::beans::PropertyState meCharHeight;
+ css::beans::PropertyState meFontName;
+ css::beans::PropertyState meAsianOrComplexFont;
+ css::beans::PropertyState meCharEscapement;
+ css::lang::Locale meCharLocale;
+ sal_uInt16 mnCharAttrHard;
+
+ sal_uInt32 mnCharColor;
+ sal_uInt16 mnCharAttr;
+ sal_uInt16 mnCharHeight;
+ sal_uInt16 mnFont;
+ sal_uInt16 mnAsianOrComplexFont;
+ sal_Int16 mnCharEscapement;
+
+ sal_uInt32 mnTextSize;
+ bool mbLastPortion;
+
+ std::unique_ptr<sal_uInt16[]> mpText;
+ std::unique_ptr<FieldEntry> mpFieldEntry;
+
+ PortionObj( css::uno::Reference< css::text::XTextRange > & rXTextRangeRef,
+ bool bLast, FontCollection& rFontCollection );
+ PortionObj( const css::uno::Reference< css::beans::XPropertySet > & rXPropSetRef,
+ FontCollection& rFontCollection );
+ PortionObj( const PortionObj& rPortionObj );
+ ~PortionObj();
+
+ void Write( SvStream* pStrm, bool bLast );
+ sal_uInt32 Count() const { return mnTextSize; };
+
+ PortionObj& operator=( const PortionObj& rPortionObj );
+};
+
+struct ParaFlags
+{
+ bool bFirstParagraph : 1;
+ bool bLastParagraph : 1;
+
+ ParaFlags() { bFirstParagraph = true; bLastParagraph = false; };
+};
+
+class ParagraphObj : public PropStateValue, public SOParagraph
+{
+ friend class TextObj;
+ friend struct PPTExParaSheet;
+
+ std::vector<std::unique_ptr<PortionObj> > mvPortions;
+
+ protected:
+
+ void ImplConstruct( const ParagraphObj& rParagraphObj );
+ void ImplClear();
+ sal_uInt32 ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition );
+ void ImplGetParagraphValues( PPTExBulletProvider* pBuProv, bool bGetPropStateValue );
+ void ImplGetNumberingLevel( PPTExBulletProvider* pBuProv, sal_Int16 nDepth, bool bIsBullet, bool bGetPropStateValue );
+
+ public:
+
+ css::uno::Sequence< css::style::TabStop > maTabStop;
+
+ sal_uInt32 mnTextSize;
+
+ bool mbIsBullet;
+ bool mbFirstParagraph;
+ bool mbLastParagraph;
+
+ css::beans::PropertyState meBullet;
+ css::beans::PropertyState meTextAdjust;
+ css::beans::PropertyState meLineSpacing;
+ css::beans::PropertyState meLineSpacingTop;
+ css::beans::PropertyState meLineSpacingBottom;
+ css::beans::PropertyState meForbiddenRules;
+ css::beans::PropertyState meParagraphPunctation;
+ css::beans::PropertyState meBiDi;
+
+ sal_uInt16 mnTextAdjust;
+ sal_Int16 mnLineSpacing;
+ bool mbFixedLineSpacing;
+ sal_Int16 mnLineSpacingTop;
+ sal_Int16 mnLineSpacingBottom;
+ bool mbForbiddenRules;
+ bool mbParagraphPunctation;
+ sal_uInt16 mnBiDi;
+
+ ParagraphObj( css::uno::Reference< css::text::XTextContent > const & rXTextContentRef,
+ ParaFlags, FontCollection& rFontCollection,
+ PPTExBulletProvider& rBuProv );
+ ParagraphObj( const ParagraphObj& rParargraphObj ) = delete;
+ ParagraphObj( const css::uno::Reference< css::beans::XPropertySet > & rXPropSetRef,
+ PPTExBulletProvider* pBuProv );
+
+ bool empty() const { return mvPortions.empty(); }
+
+ const PortionObj& front() const { return *mvPortions.front(); }
+
+ std::vector<std::unique_ptr<PortionObj> >::const_iterator begin() const { return mvPortions.begin(); }
+ std::vector<std::unique_ptr<PortionObj> >::const_iterator end() const { return mvPortions.end(); }
+
+ void CalculateGraphicBulletSize( sal_uInt16 nFontHeight );
+ ~ParagraphObj();
+
+ void Write( SvStream* pStrm );
+ sal_uInt32 CharacterCount() const { return mnTextSize; };
+
+ ParagraphObj& operator=( const ParagraphObj& rParagraphObj );
+};
+
+struct ImplTextObj;
+
+class TextObj
+{
+ std::shared_ptr<ImplTextObj> mpImplTextObj;
+ void ImplCalculateTextPositions();
+
+public:
+ TextObj( css::uno::Reference< css::text::XSimpleText > const &
+ rXText, int nInstance, FontCollection& rFontCollection, PPTExBulletProvider& rBuProv );
+
+ ParagraphObj* GetParagraph(int idx);
+ sal_uInt32 ParagraphCount() const;
+ sal_uInt32 Count() const;
+ int GetInstance() const;
+ bool HasExtendedBullets() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/grf/sdgrffilter.cxx b/sd/source/filter/grf/sdgrffilter.cxx
new file mode 100644
index 000000000..46ed24f3b
--- /dev/null
+++ b/sd/source/filter/grf/sdgrffilter.cxx
@@ -0,0 +1,304 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/GraphicExportFilter.hpp>
+
+#include <vcl/errinf.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/sfxuno.hxx>
+#include <svx/svdograf.hxx>
+
+#include <strings.hrc>
+#include <DrawViewShell.hxx>
+#include <DrawDocShell.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/svapp.hxx>
+
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <sdresid.hxx>
+#include <sdgrffilter.hxx>
+#include <ViewShellBase.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/task/XInteractionRequest.hpp>
+#include <com/sun/star/drawing/GraphicFilterRequest.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::graphic;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::ucb;
+using namespace com::sun::star::ui::dialogs;
+using namespace ::sfx2;
+
+namespace {
+
+class SdGRFFilter_ImplInteractionHdl : public ::cppu::WeakImplHelper< css::task::XInteractionHandler >
+{
+ css::uno::Reference< css::task::XInteractionHandler > m_xInter;
+ ErrCode nFilterError;
+
+ public:
+
+ explicit SdGRFFilter_ImplInteractionHdl( css::uno::Reference< css::task::XInteractionHandler > const & xInteraction ) :
+ m_xInter( xInteraction ),
+ nFilterError( ERRCODE_NONE )
+ {}
+
+ ErrCode const & GetErrorCode() const { return nFilterError; };
+
+ virtual void SAL_CALL handle( const css::uno::Reference< css::task::XInteractionRequest >& ) override;
+};
+
+}
+
+void SdGRFFilter_ImplInteractionHdl::handle( const css::uno::Reference< css::task::XInteractionRequest >& xRequest )
+{
+ if( !m_xInter.is() )
+ return;
+
+ css::drawing::GraphicFilterRequest aErr;
+ if ( xRequest->getRequest() >>= aErr )
+ nFilterError = ErrCode(aErr.ErrCode);
+ else
+ m_xInter->handle( xRequest );
+}
+
+
+SdGRFFilter::SdGRFFilter( SfxMedium& rMedium, ::sd::DrawDocShell& rDocShell ) :
+ SdFilter( rMedium, rDocShell )
+{
+}
+
+SdGRFFilter::~SdGRFFilter()
+{
+}
+
+void SdGRFFilter::HandleGraphicFilterError( ErrCode nFilterError, ErrCode nStreamError )
+{
+ if (ERRCODE_NONE != nStreamError)
+ {
+ ErrorHandler::HandleError(nStreamError);
+ return;
+ }
+
+ TranslateId pId;
+
+ if( nFilterError == ERRCODE_GRFILTER_OPENERROR )
+ pId = STR_IMPORT_GRFILTER_OPENERROR;
+ else if( nFilterError == ERRCODE_GRFILTER_IOERROR )
+ pId = STR_IMPORT_GRFILTER_IOERROR;
+ else if( nFilterError == ERRCODE_GRFILTER_FORMATERROR )
+ pId = STR_IMPORT_GRFILTER_FORMATERROR;
+ else if( nFilterError == ERRCODE_GRFILTER_VERSIONERROR )
+ pId = STR_IMPORT_GRFILTER_VERSIONERROR;
+ else if( nFilterError == ERRCODE_GRFILTER_TOOBIG )
+ pId = STR_IMPORT_GRFILTER_TOOBIG;
+ else if( nFilterError == ERRCODE_NONE )
+ ;
+ else
+ pId = STR_IMPORT_GRFILTER_FILTERERROR;
+
+ if (pId && pId == STR_IMPORT_GRFILTER_IOERROR)
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::Ok, pId ? SdResId(pId) : OUString()));
+ xErrorBox->run();
+ }
+}
+
+bool SdGRFFilter::Import()
+{
+ Graphic aGraphic;
+ const OUString aFileName( mrMedium.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ const sal_uInt16 nFilter = rGraphicFilter.GetImportFormatNumberForTypeName( mrMedium.GetFilter()->GetTypeName() );
+ bool bRet = false;
+
+ SvStream* pIStm = mrMedium.GetInStream();
+ ErrCode nReturn = pIStm ? rGraphicFilter.ImportGraphic( aGraphic, aFileName, *pIStm, nFilter ) : ErrCode(1);
+
+ if( nReturn )
+ HandleGraphicFilterError( nReturn, rGraphicFilter.GetLastError() );
+ else
+ {
+ if( mrDocument.GetPageCount() == 0 )
+ mrDocument.CreateFirstPages();
+
+ SdPage* pPage = mrDocument.GetSdPage( 0, PageKind::Standard );
+ Point aPos;
+ Size aPagSize( pPage->GetSize() );
+ Size aGrfSize( OutputDevice::LogicToLogic( aGraphic.GetPrefSize(),
+ aGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)));
+
+ aPagSize.AdjustWidth( -(pPage->GetLeftBorder() + pPage->GetRightBorder()) );
+ aPagSize.AdjustHeight( -(pPage->GetUpperBorder() + pPage->GetLowerBorder()) );
+
+ // scale to fit page
+ if ( ( ( aGrfSize.Height() > aPagSize.Height() ) || ( aGrfSize.Width() > aPagSize.Width() ) ) &&
+ aGrfSize.Height() && aPagSize.Height() )
+ {
+ double fGrfWH = static_cast<double>(aGrfSize.Width()) / aGrfSize.Height();
+ double fWinWH = static_cast<double>(aPagSize.Width()) / aPagSize.Height();
+
+ // adjust graphic to page size (scales)
+ if( fGrfWH < fWinWH )
+ {
+ aGrfSize.setWidth( static_cast<tools::Long>( aPagSize.Height() * fGrfWH ) );
+ aGrfSize.setHeight( aPagSize.Height() );
+ }
+ else if( fGrfWH > 0.F )
+ {
+ aGrfSize.setWidth( aPagSize.Width() );
+ aGrfSize.setHeight( static_cast<tools::Long>( aPagSize.Width() / fGrfWH ) );
+ }
+ }
+
+ // set output rectangle for graphic
+ aPos.setX( ( ( aPagSize.Width() - aGrfSize.Width() ) >> 1 ) + pPage->GetLeftBorder() );
+ aPos.setY( ( ( aPagSize.Height() - aGrfSize.Height() ) >> 1 ) + pPage->GetUpperBorder() );
+
+ pPage->InsertObject(
+ new SdrGrafObj(
+ pPage->getSdrModelFromSdrPage(),
+ aGraphic,
+ ::tools::Rectangle(aPos, aGrfSize)));
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+bool SdGRFFilter::Export()
+{
+ // SJ: todo: error handling, the GraphicExportFilter does not support proper errorhandling
+ bool bRet = false;
+
+ uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ uno::Reference< drawing::XGraphicExportFilter > xExporter = drawing::GraphicExportFilter::create( xContext );
+
+ SdPage* pPage = nullptr;
+ sd::DrawViewShell* pDrawViewShell = dynamic_cast<::sd::DrawViewShell* >(mrDocShell.GetViewShell() );
+
+ PageKind ePageKind = PageKind::Standard;
+ if( pDrawViewShell )
+ {
+ ePageKind = pDrawViewShell->GetPageKind();
+ if( PageKind::Handout == ePageKind )
+ pPage = mrDocument.GetSdPage( 0, PageKind::Handout );
+ else
+ pPage = pDrawViewShell->GetActualPage();
+ }
+ else
+ pPage = mrDocument.GetSdPage( 0, PageKind::Standard );
+
+ if ( pPage )
+ {
+ // taking the 'correct' page number, seems that there might exist a better method to archive this
+ pPage = mrDocument.GetSdPage( pPage->GetPageNum() ? ( pPage->GetPageNum() - 1 ) >> 1 : 0, ePageKind );
+ if ( pPage )
+ {
+ uno::Reference< lang::XComponent > xSource( pPage->getUnoPage(), uno::UNO_QUERY );
+ SfxItemSet* pSet = mrMedium.GetItemSet();
+ if ( pSet && xSource.is() )
+ {
+ const OUString aTypeName( mrMedium.GetFilter()->GetTypeName() );
+ GraphicFilter &rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ const sal_uInt16 nFilter = rGraphicFilter.GetExportFormatNumberForTypeName( aTypeName );
+ if ( nFilter != GRFILTER_FORMAT_NOTFOUND )
+ {
+ uno::Reference< task::XInteractionHandler > xInteractionHandler;
+
+ beans::PropertyValues aArgs;
+ TransformItems( SID_SAVEASDOC, *pSet, aArgs );
+
+ static const OUStringLiteral sFilterName( u"FilterName" );
+ OUString sShortName( rGraphicFilter.GetExportFormatShortName( nFilter ) );
+
+ bool bFilterNameFound = false;
+ for ( auto& rArg : asNonConstRange(aArgs) )
+ {
+ OUString& rStr = rArg.Name;
+ if ( rStr == sFilterName )
+ {
+ bFilterNameFound = true;
+ rArg.Value <<= sShortName;
+ }
+ else if ( rStr == "InteractionHandler" )
+ {
+ uno::Reference< task::XInteractionHandler > xHdl;
+ if ( rArg.Value >>= xHdl )
+ {
+ xInteractionHandler = new SdGRFFilter_ImplInteractionHdl( xHdl );
+ rArg.Value <<= xInteractionHandler;
+ }
+ }
+ }
+ if ( !bFilterNameFound )
+ {
+ sal_Int32 nCount = aArgs.getLength();
+ aArgs.realloc( nCount + 1 );
+ auto pArgs = aArgs.getArray();
+ pArgs[ nCount ].Name = sFilterName;
+ pArgs[ nCount ].Value <<= sShortName;
+ }
+
+ // take selection if needed
+ if( ( SfxItemState::SET == pSet->GetItemState( SID_SELECTION ) )
+ && pSet->Get( SID_SELECTION ).GetValue()
+ && pDrawViewShell )
+ {
+ uno::Reference< view::XSelectionSupplier > xSelectionSupplier(
+ pDrawViewShell->GetViewShellBase().GetController(), uno::UNO_QUERY );
+ if ( xSelectionSupplier.is() )
+ {
+ uno::Any aSelection( xSelectionSupplier->getSelection() );
+ uno::Reference< lang::XComponent > xSelection;
+ if ( aSelection >>= xSelection )
+ xSource = xSelection;
+ }
+ }
+ xExporter->setSourceDocument( xSource );
+ bRet = xExporter->filter( aArgs );
+ if ( !bRet && xInteractionHandler.is() )
+ SdGRFFilter::HandleGraphicFilterError(
+ static_cast< SdGRFFilter_ImplInteractionHdl* >( xInteractionHandler.get() )->GetErrorCode(),
+ rGraphicFilter.GetLastError() );
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/html/HtmlOptionsDialog.cxx b/sd/source/filter/html/HtmlOptionsDialog.cxx
new file mode 100644
index 000000000..78939dc4d
--- /dev/null
+++ b/sd/source/filter/html/HtmlOptionsDialog.cxx
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <com/sun/star/document/XExporter.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::document;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::ui::dialogs;
+
+#include <pres.hxx>
+#include <sdabstdlg.hxx>
+
+namespace {
+
+class SdHtmlOptionsDialog : public cppu::WeakImplHelper
+<
+ XExporter,
+ XExecutableDialog,
+ XPropertyAccess,
+ XInitialization,
+ XServiceInfo
+>
+{
+ Sequence< PropertyValue > maMediaDescriptor;
+ Sequence< PropertyValue > maFilterDataSequence;
+ DocumentType meDocType;
+
+public:
+
+ SdHtmlOptionsDialog();
+
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any > & aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertyAccess
+ virtual Sequence< PropertyValue > SAL_CALL getPropertyValues() override;
+ virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< css::beans::PropertyValue > & aProps ) override;
+
+ // XExecuteDialog
+ virtual sal_Int16 SAL_CALL execute() override;
+ virtual void SAL_CALL setTitle( const OUString& aTitle ) override;
+
+ // XExporter
+ virtual void SAL_CALL setSourceDocument( const css::uno::Reference< css::lang::XComponent >& xDoc ) override;
+
+};
+
+}
+
+SdHtmlOptionsDialog::SdHtmlOptionsDialog() :
+ meDocType ( DocumentType::Draw )
+{
+}
+
+void SAL_CALL SdHtmlOptionsDialog::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL SdHtmlOptionsDialog::release() noexcept
+{
+ OWeakObject::release();
+}
+
+// XInitialization
+void SAL_CALL SdHtmlOptionsDialog::initialize( const Sequence< Any > & )
+{
+}
+
+// XServiceInfo
+OUString SAL_CALL SdHtmlOptionsDialog::getImplementationName()
+{
+ return "com.sun.star.comp.draw.SdHtmlOptionsDialog";
+}
+
+sal_Bool SAL_CALL SdHtmlOptionsDialog::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > SAL_CALL SdHtmlOptionsDialog::getSupportedServiceNames()
+{
+ return { "com.sun.star.ui.dialog.FilterOptionsDialog" };
+}
+
+// XPropertyAccess
+Sequence< PropertyValue > SdHtmlOptionsDialog::getPropertyValues()
+{
+ auto pProp = std::find_if(std::cbegin(maMediaDescriptor), std::cend(maMediaDescriptor),
+ [](const PropertyValue& rProp) { return rProp.Name == "FilterData"; });
+ auto i = static_cast<sal_Int32>(std::distance(std::cbegin(maMediaDescriptor), pProp));
+ sal_Int32 nCount = maMediaDescriptor.getLength();
+ if ( i == nCount )
+ maMediaDescriptor.realloc( ++nCount );
+
+ // the "FilterData" Property is an Any that will contain our PropertySequence of Values
+ auto& el = maMediaDescriptor.getArray()[ i ];
+ el.Name = "FilterData";
+ el.Value <<= maFilterDataSequence;
+ return maMediaDescriptor;
+}
+
+void SdHtmlOptionsDialog::setPropertyValues( const Sequence< PropertyValue > & aProps )
+{
+ maMediaDescriptor = aProps;
+
+ auto pProp = std::find_if(std::cbegin(maMediaDescriptor), std::cend(maMediaDescriptor),
+ [](const PropertyValue& rProp) { return rProp.Name == "FilterData"; });
+ if (pProp != std::cend(maMediaDescriptor))
+ pProp->Value >>= maFilterDataSequence;
+}
+
+// XExecutableDialog
+void SdHtmlOptionsDialog::setTitle( const OUString& )
+{
+}
+
+sal_Int16 SdHtmlOptionsDialog::execute()
+{
+ sal_Int16 nRet = ExecutableDialogResults::CANCEL;
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSdPublishingDlg> pDlg(pFact->CreateSdPublishingDlg(nullptr /*TODO*/, meDocType));
+ if( pDlg->Execute() )
+ {
+ pDlg->GetParameterSequence( maFilterDataSequence );
+ nRet = ExecutableDialogResults::OK;
+ }
+ else
+ {
+ nRet = ExecutableDialogResults::CANCEL;
+ }
+ return nRet;
+}
+
+// XEmporter
+void SdHtmlOptionsDialog::setSourceDocument( const Reference< XComponent >& xDoc )
+{
+ // try to set the corresponding metric unit
+ Reference< XServiceInfo > xServiceInfo(xDoc, UNO_QUERY);
+ if ( xServiceInfo.is() )
+ {
+ if ( xServiceInfo->supportsService( "com.sun.star.presentation.PresentationDocument" ) )
+ {
+ meDocType = DocumentType::Impress;
+ return;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.drawing.DrawingDocument" ) )
+ {
+ meDocType = DocumentType::Draw;
+ return;
+ }
+ }
+ throw IllegalArgumentException();
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_draw_SdHtmlOptionsDialog_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SdHtmlOptionsDialog());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/html/buttonset.cxx b/sd/source/filter/html/buttonset.cxx
new file mode 100644
index 000000000..3929f7422
--- /dev/null
+++ b/sd/source/filter/html/buttonset.cxx
@@ -0,0 +1,290 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+#include <com/sun/star/io/XStream.hpp>
+
+#include <o3tl/safeint.hxx>
+#include <osl/file.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/oslfile2streamwrap.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/image.hxx>
+#include <unotools/pathoptions.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <memory>
+
+#include "buttonset.hxx"
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::graphic;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+
+namespace {
+
+class ButtonsImpl
+{
+public:
+ explicit ButtonsImpl( const OUString& rURL );
+
+ Reference< XInputStream > getInputStream( const OUString& rName );
+
+ bool getGraphic( const Reference< XGraphicProvider >& xGraphicProvider, const OUString& rName, Graphic& rGraphic );
+
+ bool copyGraphic( const OUString& rName, const OUString& rPath );
+
+private:
+ Reference< XStorage > mxStorage;
+};
+
+}
+
+ButtonsImpl::ButtonsImpl( const OUString& rURL )
+{
+ try
+ {
+ mxStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL( ZIP_STORAGE_FORMAT_STRING, rURL, ElementModes::READ );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::ButtonsImpl::ButtonsImpl()" );
+ }
+}
+
+Reference< XInputStream > ButtonsImpl::getInputStream( const OUString& rName )
+{
+ Reference< XInputStream > xInputStream;
+ if( mxStorage.is() ) try
+ {
+ Reference< XStream > xStream( mxStorage->openStreamElement( rName, ElementModes::READ ) );
+ if( xStream.is() )
+ xInputStream = xStream->getInputStream();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::ButtonsImpl::getInputStream()" );
+ }
+ return xInputStream;
+}
+
+bool ButtonsImpl::getGraphic( const Reference< XGraphicProvider >& xGraphicProvider, const OUString& rName, Graphic& rGraphic )
+{
+ Reference< XInputStream > xInputStream( getInputStream( rName ) );
+ if( xInputStream.is() && xGraphicProvider.is() ) try
+ {
+ Sequence< PropertyValue > aMediaProperties{ comphelper::makePropertyValue(
+ "InputStream", xInputStream) };
+ Reference< XGraphic > xGraphic( xGraphicProvider->queryGraphic( aMediaProperties ) );
+
+ if( xGraphic.is() )
+ {
+ rGraphic = Graphic( xGraphic );
+ return true;
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::ButtonsImpl::getGraphic()" );
+ }
+ return false;
+}
+
+bool ButtonsImpl::copyGraphic( const OUString& rName, const OUString& rPath )
+{
+ Reference< XInputStream > xInput( getInputStream( rName ) );
+ if( xInput.is() ) try
+ {
+ osl::File::remove( rPath );
+ osl::File aOutputFile( rPath );
+ if( aOutputFile.open( osl_File_OpenFlag_Write|osl_File_OpenFlag_Create ) == osl::FileBase::E_None )
+ {
+ Reference< XOutputStream > xOutput( new comphelper::OSLOutputStreamWrapper( aOutputFile ) );
+ comphelper::OStorageHelper::CopyInputToOutput( xInput, xOutput );
+ return true;
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::ButtonsImpl::copyGraphic()" );
+ }
+
+ return false;
+}
+
+class ButtonSetImpl
+{
+public:
+ ButtonSetImpl();
+
+ int getCount() const;
+
+ bool getPreview( int nSet, const std::vector< OUString >& rButtons, Image& rImage );
+ bool exportButton( int nSet, const OUString& rPath, const OUString& rName );
+
+ void scanForButtonSets( const OUString& rPath );
+
+ Reference< XGraphicProvider > const & getGraphicProvider();
+
+ std::vector< std::shared_ptr< ButtonsImpl > > maButtons;
+ Reference< XGraphicProvider > mxGraphicProvider;
+};
+
+ButtonSetImpl::ButtonSetImpl()
+{
+ static const char sSubPath[] = "/wizard/web/buttons" ;
+
+ OUString sSharePath = SvtPathOptions().GetConfigPath() +
+ sSubPath;
+ scanForButtonSets( sSharePath );
+
+ OUString sUserPath = SvtPathOptions().GetUserConfigPath() +
+ sSubPath;
+ scanForButtonSets( sUserPath );
+}
+
+void ButtonSetImpl::scanForButtonSets( const OUString& rPath )
+{
+ osl::Directory aDirectory( rPath );
+ if( aDirectory.open() != osl::FileBase::E_None )
+ return;
+
+ osl::DirectoryItem aItem;
+ while( aDirectory.getNextItem( aItem, 2211 ) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aStatus( osl_FileStatus_Mask_FileName|osl_FileStatus_Mask_FileURL );
+ if( aItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
+ {
+ OUString sFileName( aStatus.getFileName() );
+ if( sFileName.endsWithIgnoreAsciiCase( ".zip" ) )
+ maButtons.push_back( std::make_shared< ButtonsImpl >( aStatus.getFileURL() ) );
+ }
+ }
+}
+
+int ButtonSetImpl::getCount() const
+{
+ return maButtons.size();
+}
+
+bool ButtonSetImpl::getPreview( int nSet, const std::vector< OUString >& rButtons, Image& rImage )
+{
+ if( (nSet >= 0) && (o3tl::make_unsigned(nSet) < maButtons.size()))
+ {
+ ButtonsImpl& rSet = *maButtons[nSet];
+
+ std::vector< Graphic > aGraphics;
+
+ ScopedVclPtrInstance< VirtualDevice > pDev;
+ pDev->SetMapMode(MapMode(MapUnit::MapPixel));
+
+ Size aSize;
+ std::vector< OUString >::const_iterator aIter( rButtons.begin() );
+ while( aIter != rButtons.end() )
+ {
+ Graphic aGraphic;
+ if( !rSet.getGraphic( getGraphicProvider(), (*aIter++), aGraphic ) )
+ return false;
+
+ aGraphics.push_back(aGraphic);
+
+ Size aGraphicSize( aGraphic.GetSizePixel( pDev ) );
+ aSize.AdjustWidth(aGraphicSize.Width() );
+
+ if( aSize.Height() < aGraphicSize.Height() )
+ aSize.setHeight( aGraphicSize.Height() );
+
+ if( aIter != rButtons.end() )
+ aSize.AdjustWidth(3 );
+ }
+
+ pDev->SetOutputSizePixel( aSize );
+
+ Point aPos;
+
+ for( const Graphic& aGraphic : aGraphics )
+ {
+ aGraphic.Draw(*pDev, aPos);
+
+ aPos.AdjustX(aGraphic.GetSizePixel().Width() + 3 );
+ }
+
+ rImage = Image( pDev->GetBitmapEx( Point(), aSize ) );
+ return true;
+ }
+ return false;
+}
+
+bool ButtonSetImpl::exportButton( int nSet, const OUString& rPath, const OUString& rName )
+{
+ if( (nSet >= 0) && (o3tl::make_unsigned(nSet) < maButtons.size()))
+ {
+ ButtonsImpl& rSet = *maButtons[nSet];
+
+ return rSet.copyGraphic( rName, rPath );
+ }
+ return false;
+}
+
+Reference< XGraphicProvider > const & ButtonSetImpl::getGraphicProvider()
+{
+ if( !mxGraphicProvider.is() )
+ {
+ Reference< XComponentContext > xComponentContext = ::comphelper::getProcessComponentContext();
+ mxGraphicProvider = GraphicProvider::create(xComponentContext);
+ }
+ return mxGraphicProvider;
+}
+
+ButtonSet::ButtonSet()
+: mpImpl( new ButtonSetImpl() )
+{
+}
+
+ButtonSet::~ButtonSet()
+{
+}
+
+int ButtonSet::getCount() const
+{
+ return mpImpl->getCount();
+}
+
+bool ButtonSet::getPreview( int nSet, const std::vector< OUString >& rButtons, Image& rImage )
+{
+ return mpImpl->getPreview( nSet, rButtons, rImage );
+}
+
+bool ButtonSet::exportButton( int nSet, const OUString& rPath, const OUString& rName )
+{
+ return mpImpl->exportButton( nSet, rPath, rName );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/html/buttonset.hxx b/sd/source/filter/html/buttonset.hxx
new file mode 100644
index 000000000..4289c10e9
--- /dev/null
+++ b/sd/source/filter/html/buttonset.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sddllapi.h>
+
+#include <rtl/ustring.hxx>
+#include <vector>
+#include <memory>
+
+class Image;
+class ButtonSetImpl;
+
+class SD_DLLPUBLIC ButtonSet
+{
+public:
+ ButtonSet();
+ ~ButtonSet();
+
+ int getCount() const;
+
+ bool getPreview(int nSet, const std::vector<OUString>& rButtons, Image& rImage);
+ bool exportButton(int nSet, const OUString& rPath, const OUString& rName);
+
+private:
+ std::unique_ptr<ButtonSetImpl> mpImpl;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/html/htmlattr.cxx b/sd/source/filter/html/htmlattr.cxx
new file mode 100644
index 000000000..b89ac9b6b
--- /dev/null
+++ b/sd/source/filter/html/htmlattr.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "htmlattr.hxx"
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <vcl/outdev.hxx>
+
+SdHtmlAttrPreview::SdHtmlAttrPreview()
+{
+}
+
+SdHtmlAttrPreview::~SdHtmlAttrPreview()
+{
+}
+
+void SdHtmlAttrPreview::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect)
+{
+ ::tools::Rectangle aTextRect;
+ aTextRect.SetSize(GetOutputSizePixel());
+
+ rRenderContext.SetLineColor(m_aBackColor);
+ rRenderContext.SetFillColor(m_aBackColor);
+ rRenderContext.DrawRect(rRect);
+ rRenderContext.SetFillColor();
+
+ int nHeight = (aTextRect.Bottom() - aTextRect.Top()) >> 2;
+ aTextRect.SetBottom( nHeight + aTextRect.Top() );
+
+ rRenderContext.SetTextColor(m_aTextColor);
+ rRenderContext.DrawText(aTextRect, SdResId(STR_HTMLATTR_TEXT), DrawTextFlags::Center | DrawTextFlags::VCenter);
+
+ aTextRect.Move(0,nHeight);
+ rRenderContext.SetTextColor(m_aLinkColor);
+ rRenderContext.DrawText(aTextRect, SdResId(STR_HTMLATTR_LINK), DrawTextFlags::Center | DrawTextFlags::VCenter);
+
+ aTextRect.Move(0,nHeight);
+ rRenderContext.SetTextColor(m_aALinkColor);
+ rRenderContext.DrawText(aTextRect, SdResId(STR_HTMLATTR_ALINK), DrawTextFlags::Center | DrawTextFlags::VCenter);
+
+ aTextRect.Move(0,nHeight);
+ rRenderContext.SetTextColor(m_aVLinkColor);
+ rRenderContext.DrawText(aTextRect, SdResId(STR_HTMLATTR_VLINK), DrawTextFlags::Center | DrawTextFlags::VCenter);
+}
+
+void SdHtmlAttrPreview::SetColors(Color const & aBack, Color const & aText, Color const & aLink,
+ Color const & aVLink, Color const & aALink)
+{
+ m_aBackColor = aBack;
+ m_aTextColor = aText;
+ m_aLinkColor = aLink;
+ m_aVLinkColor = aVLink;
+ m_aALinkColor = aALink;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/html/htmlattr.hxx b/sd/source/filter/html/htmlattr.hxx
new file mode 100644
index 000000000..bf80b9e4b
--- /dev/null
+++ b/sd/source/filter/html/htmlattr.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/customweld.hxx>
+#include <tools/color.hxx>
+
+class SdHtmlAttrPreview final : public weld::CustomWidgetController
+{
+ Color m_aBackColor, m_aTextColor, m_aLinkColor;
+ Color m_aVLinkColor, m_aALinkColor;
+
+public:
+ SdHtmlAttrPreview();
+ virtual ~SdHtmlAttrPreview() override;
+
+ virtual void Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect) override;
+
+ void SetColors( Color const & aBack, Color const & aText, Color const & aLink,
+ Color const & aVLink, Color const & aALink );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/html/htmlex.cxx b/sd/source/filter/html/htmlex.cxx
new file mode 100644
index 000000000..072ac3c27
--- /dev/null
+++ b/sd/source/filter/html/htmlex.cxx
@@ -0,0 +1,3186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "htmlex.hxx"
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/drawing/GraphicExportFilter.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+
+#include <sal/log.hxx>
+#include <rtl/tencinfo.h>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/file.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <sfx2/frmhtmlw.hxx>
+#include <sfx2/progress.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svx/svditer.hxx>
+#include <vcl/imaprect.hxx>
+#include <vcl/imapcirc.hxx>
+#include <vcl/imappoly.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <svx/svdopath.hxx>
+#include <svtools/htmlout.hxx>
+#include <svtools/colorcfg.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/flditem.hxx>
+#include <svl/style.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <tools/urlobj.hxx>
+#include <svtools/sfxecode.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include "htmlpublishmode.hxx"
+#include <Outliner.hxx>
+#include <sdpage.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <anminfo.hxx>
+#include <sdresid.hxx>
+#include "buttonset.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::document;
+
+using namespace sdr::table;
+
+// get parameter from Itemset
+#define RESTOHTML( res ) StringToHTMLString(SdResId(res))
+
+const char * const pButtonNames[] =
+{
+ "first-inactive.png",
+ "first.png",
+ "left-inactive.png",
+ "left.png",
+ "right-inactive.png",
+ "right.png",
+ "last-inactive.png",
+ "last.png",
+ "home.png",
+ "text.png",
+ "expand.png",
+ "collapse.png",
+};
+
+#define BTN_FIRST_0 0
+#define BTN_FIRST_1 1
+#define BTN_PREV_0 2
+#define BTN_PREV_1 3
+#define BTN_NEXT_0 4
+#define BTN_NEXT_1 5
+#define BTN_LAST_0 6
+#define BTN_LAST_1 7
+#define BTN_INDEX 8
+#define BTN_TEXT 9
+#define BTN_MORE 10
+#define BTN_LESS 11
+
+namespace {
+
+// Helper class for the simple creation of files local/remote
+class EasyFile
+{
+private:
+ std::unique_ptr<SvStream> pOStm;
+ bool bOpen;
+
+public:
+
+ EasyFile();
+ ~EasyFile();
+
+ ErrCode createStream( const OUString& rUrl, SvStream*& rpStr );
+ void createFileName( const OUString& rUrl, OUString& rFileName );
+ void close();
+};
+
+}
+
+// Helper class for the embedding of text attributes into the html output
+class HtmlState
+{
+private:
+ bool mbColor;
+ bool mbWeight;
+ bool mbItalic;
+ bool mbUnderline;
+ bool mbStrike;
+ bool mbLink;
+ Color maColor;
+ Color maDefColor;
+ OUString maLink;
+ OUString maTarget;
+
+public:
+ explicit HtmlState( Color aDefColor );
+
+ OUString SetWeight( bool bWeight );
+ OUString SetItalic( bool bItalic );
+ OUString SetUnderline( bool bUnderline );
+ OUString SetColor( Color aColor );
+ OUString SetStrikeout( bool bStrike );
+ OUString SetLink( const OUString& aLink, const OUString& aTarget );
+ OUString Flush();
+};
+
+// close all still open tags
+OUString HtmlState::Flush()
+{
+ OUString aStr = SetWeight(false)
+ + SetItalic(false)
+ + SetUnderline(false)
+ + SetStrikeout(false)
+ + SetColor(maDefColor)
+ + SetLink("","");
+
+ return aStr;
+}
+
+// c'tor with default color for the page
+HtmlState::HtmlState( Color aDefColor )
+ : mbColor(false),
+ mbWeight(false),
+ mbItalic(false),
+ mbUnderline(false),
+ mbStrike(false),
+ mbLink(false),
+ maDefColor(aDefColor)
+{
+}
+
+// enables/disables bold print
+OUString HtmlState::SetWeight( bool bWeight )
+{
+ OUString aStr;
+
+ if(bWeight && !mbWeight)
+ aStr = "<b>";
+ else if(!bWeight && mbWeight)
+ aStr = "</b>";
+
+ mbWeight = bWeight;
+ return aStr;
+}
+
+// enables/disables italic
+
+OUString HtmlState::SetItalic( bool bItalic )
+{
+ OUString aStr;
+
+ if(bItalic && !mbItalic)
+ aStr = "<i>";
+ else if(!bItalic && mbItalic)
+ aStr = "</i>";
+
+ mbItalic = bItalic;
+ return aStr;
+}
+
+// enables/disables underlines
+
+OUString HtmlState::SetUnderline( bool bUnderline )
+{
+ OUString aStr;
+
+ if(bUnderline && !mbUnderline)
+ aStr = "<u>";
+ else if(!bUnderline && mbUnderline)
+ aStr = "</u>";
+
+ mbUnderline = bUnderline;
+ return aStr;
+}
+
+// enables/disables strike through
+OUString HtmlState::SetStrikeout( bool bStrike )
+{
+ OUString aStr;
+
+ if(bStrike && !mbStrike)
+ aStr = "<strike>";
+ else if(!bStrike && mbStrike)
+ aStr = "</strike>";
+
+ mbStrike = bStrike;
+ return aStr;
+}
+
+// Sets the specified text color
+OUString HtmlState::SetColor( Color aColor )
+{
+ OUString aStr;
+
+ if(mbColor && aColor == maColor)
+ return aStr;
+
+ if(mbColor)
+ {
+ aStr = "</font>";
+ mbColor = false;
+ }
+
+ if(aColor != maDefColor)
+ {
+ maColor = aColor;
+ aStr += "<font color=\"" + HtmlExport::ColorToHTMLString(aColor) + "\">";
+ mbColor = true;
+ }
+
+ return aStr;
+}
+
+// enables/disables a hyperlink
+OUString HtmlState::SetLink( const OUString& aLink, const OUString& aTarget )
+{
+ OUString aStr;
+
+ if(mbLink&&maLink == aLink&&maTarget==aTarget)
+ return aStr;
+
+ if(mbLink)
+ {
+ aStr = "</a>";
+ mbLink = false;
+ }
+
+ if (!aLink.isEmpty())
+ {
+ aStr += "<a href=\"" + aLink;
+ if (!aTarget.isEmpty())
+ {
+ aStr += "\" target=\"" + aTarget;
+ }
+ aStr += "\">";
+ mbLink = true;
+ maLink = aLink;
+ maTarget = aTarget;
+ }
+
+ return aStr;
+}
+namespace
+{
+
+OUString getParagraphStyle( const SdrOutliner* pOutliner, sal_Int32 nPara )
+{
+ SfxItemSet aParaSet( pOutliner->GetParaAttribs( nPara ) );
+
+ OUString sStyle;
+
+ if( aParaSet.GetItem<SvxFrameDirectionItem>( EE_PARA_WRITINGDIR )->GetValue() == SvxFrameDirection::Horizontal_RL_TB )
+ {
+
+ sStyle = "direction: rtl;";
+ }
+ else
+ {
+ // This is the default so don't write it out
+ // sStyle += "direction: ltr;";
+ }
+ return sStyle;
+}
+
+void lclAppendStyle(OUStringBuffer& aBuffer, std::u16string_view aTag, std::u16string_view aStyle)
+{
+ if (aStyle.empty())
+ aBuffer.append(OUString::Concat("<") + aTag + ">");
+ else
+ aBuffer.append(OUString::Concat("<") + aTag + " style=\"" + aStyle + "\">");
+}
+
+} // anonymous namespace
+
+constexpr OUStringLiteral gaHTMLHeader(
+ u"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
+ " \"http://www.w3.org/TR/html4/transitional.dtd\">\r\n"
+ "<html>\r\n<head>\r\n" );
+
+constexpr OUStringLiteral gaHTMLExtension = u"" STR_HTMLEXP_DEFAULT_EXTENSION;
+
+// constructor for the html export helper classes
+HtmlExport::HtmlExport(
+ const OUString& aPath,
+ const Sequence< PropertyValue >& rParams,
+ SdDrawDocument* pExpDoc,
+ sd::DrawDocShell* pDocShell )
+ : maPath( aPath ),
+ mpDoc(pExpDoc),
+ mpDocSh( pDocShell ),
+ meMode( PUBLISH_SINGLE_DOCUMENT ),
+ mbContentsPage(false),
+ mnButtonThema(-1),
+ mnWidthPixel( PUB_MEDRES_WIDTH ),
+ meFormat( FORMAT_JPG ),
+ mbNotes(false),
+ mnCompression( -1 ),
+ mbDownload( false ),
+ mbSlideSound(true),
+ mbHiddenSlides(true),
+ mbUserAttr(false),
+ maTextColor(COL_BLACK),
+ maBackColor(COL_WHITE),
+ mbDocColors(false),
+ maIndexUrl("index"),
+ meScript( SCRIPT_ASP ),
+ mpButtonSet( new ButtonSet() )
+{
+ bool bChange = mpDoc->IsChanged();
+
+ maIndexUrl += gaHTMLExtension;
+
+ InitExportParameters( rParams );
+
+ switch( meMode )
+ {
+ case PUBLISH_HTML:
+ case PUBLISH_FRAMES:
+ ExportHtml();
+ break;
+ case PUBLISH_WEBCAST:
+ ExportWebCast();
+ break;
+ case PUBLISH_KIOSK:
+ ExportKiosk();
+ break;
+ case PUBLISH_SINGLE_DOCUMENT:
+ ExportSingleDocument();
+ break;
+ }
+
+ mpDoc->SetChanged(bChange);
+}
+
+HtmlExport::~HtmlExport()
+{
+}
+
+// get common export parameters from item set
+void HtmlExport::InitExportParameters( const Sequence< PropertyValue >& rParams )
+{
+ mbImpress = mpDoc->GetDocumentType() == DocumentType::Impress;
+
+ OUString aStr;
+ for( const PropertyValue& rParam : rParams )
+ {
+ if ( rParam.Name == "PublishMode" )
+ {
+ sal_Int32 temp = 0;
+ rParam.Value >>= temp;
+ meMode = static_cast<HtmlPublishMode>(temp);
+ }
+ else if ( rParam.Name == "IndexURL" )
+ {
+ rParam.Value >>= aStr;
+ maIndexUrl = aStr;
+ }
+ else if ( rParam.Name == "Format" )
+ {
+ sal_Int32 temp = 0;
+ rParam.Value >>= temp;
+ meFormat = static_cast<PublishingFormat>(temp);
+ }
+ else if ( rParam.Name == "Compression" )
+ {
+ rParam.Value >>= aStr;
+ OUString aTmp( aStr );
+ if(!aTmp.isEmpty())
+ {
+ aTmp = aTmp.replaceFirst("%", "");
+ mnCompression = static_cast<sal_Int16>(aTmp.toInt32());
+ }
+ }
+ else if ( rParam.Name == "Width" )
+ {
+ sal_Int32 temp = 0;
+ rParam.Value >>= temp;
+ mnWidthPixel = static_cast<sal_uInt16>(temp);
+ }
+ else if ( rParam.Name == "UseButtonSet" )
+ {
+ sal_Int32 temp = 0;
+ rParam.Value >>= temp;
+ mnButtonThema = static_cast<sal_Int16>(temp);
+ }
+ else if ( rParam.Name == "IsExportNotes" )
+ {
+ if( mbImpress )
+ {
+ bool temp = false;
+ rParam.Value >>= temp;
+ mbNotes = temp;
+ }
+ }
+ else if ( rParam.Name == "IsExportContentsPage" )
+ {
+ bool temp = false;
+ rParam.Value >>= temp;
+ mbContentsPage = temp;
+ }
+ else if ( rParam.Name == "Author" )
+ {
+ rParam.Value >>= aStr;
+ maAuthor = aStr;
+ }
+ else if ( rParam.Name == "EMail" )
+ {
+ rParam.Value >>= aStr;
+ maEMail = aStr;
+ }
+ else if ( rParam.Name == "HomepageURL" )
+ {
+ rParam.Value >>= aStr;
+ maHomePage = aStr;
+ }
+ else if ( rParam.Name == "UserText" )
+ {
+ rParam.Value >>= aStr;
+ maInfo = aStr;
+ }
+ else if ( rParam.Name == "EnableDownload" )
+ {
+ bool temp = false;
+ rParam.Value >>= temp;
+ mbDownload = temp;
+ }
+ else if ( rParam.Name == "SlideSound" )
+ {
+ bool temp = true;
+ rParam.Value >>= temp;
+ mbSlideSound = temp;
+ }
+ else if ( rParam.Name == "HiddenSlides" )
+ {
+ bool temp = true;
+ rParam.Value >>= temp;
+ mbHiddenSlides = temp;
+ }
+ else if ( rParam.Name == "BackColor" )
+ {
+ Color temp;
+ rParam.Value >>= temp;
+ maBackColor = temp;
+ mbUserAttr = true;
+ }
+ else if ( rParam.Name == "TextColor" )
+ {
+ Color temp;
+ rParam.Value >>= temp;
+ maTextColor = temp;
+ mbUserAttr = true;
+ }
+ else if ( rParam.Name == "LinkColor" )
+ {
+ Color temp ;
+ rParam.Value >>= temp;
+ maLinkColor = temp;
+ mbUserAttr = true;
+ }
+ else if ( rParam.Name == "VLinkColor" )
+ {
+ Color temp;
+ rParam.Value >>= temp;
+ maVLinkColor = temp;
+ mbUserAttr = true;
+ }
+ else if ( rParam.Name == "ALinkColor" )
+ {
+ Color temp;
+ rParam.Value >>= temp;
+ maALinkColor = temp;
+ mbUserAttr = true;
+ }
+ else if ( rParam.Name == "IsUseDocumentColors" )
+ {
+ bool temp = false;
+ rParam.Value >>= temp;
+ mbDocColors = temp;
+ }
+ else if ( rParam.Name == "KioskSlideDuration" )
+ {
+ double temp = 0.0;
+ rParam.Value >>= temp;
+ mfSlideDuration = temp;
+ mbAutoSlide = true;
+ }
+ else if ( rParam.Name == "KioskEndless" )
+ {
+ bool temp = false;
+ rParam.Value >>= temp;
+ mbEndless = temp;
+ }
+ else if ( rParam.Name == "WebCastCGIURL" )
+ {
+ rParam.Value >>= aStr;
+ maCGIPath = aStr;
+ }
+ else if ( rParam.Name == "WebCastTargetURL" )
+ {
+ rParam.Value >>= aStr;
+ maURLPath = aStr;
+ }
+ else if ( rParam.Name == "WebCastScriptLanguage" )
+ {
+ rParam.Value >>= aStr;
+ if ( aStr == "asp" )
+ {
+ meScript = SCRIPT_ASP;
+ }
+ else
+ {
+ meScript = SCRIPT_PERL;
+ }
+ }
+ else
+ {
+ OSL_FAIL("Unknown property for html export detected!");
+ }
+ }
+
+ if( meMode == PUBLISH_KIOSK )
+ {
+ mbContentsPage = false;
+ mbNotes = false;
+
+ }
+
+ // calculate image sizes
+ SdPage* pPage = mpDoc->GetSdPage(0, PageKind::Standard);
+ Size aTmpSize( pPage->GetSize() );
+ double dRatio=static_cast<double>(aTmpSize.Width())/aTmpSize.Height();
+
+ mnHeightPixel = static_cast<sal_uInt16>(mnWidthPixel/dRatio);
+
+ // we come up with a destination...
+
+ INetURLObject aINetURLObj( maPath );
+ DBG_ASSERT( aINetURLObj.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+
+ maExportPath = aINetURLObj.GetPartBeforeLastName(); // with trailing '/'
+ maIndex = aINetURLObj.GetLastName();
+
+ mnSdPageCount = mpDoc->GetSdPageCount( PageKind::Standard );
+ for( sal_uInt16 nPage = 0; nPage < mnSdPageCount; nPage++ )
+ {
+ pPage = mpDoc->GetSdPage( nPage, PageKind::Standard );
+
+ if( mbHiddenSlides || !pPage->IsExcluded() )
+ {
+ maPages.push_back( pPage );
+ maNotesPages.push_back( mpDoc->GetSdPage( nPage, PageKind::Notes ) );
+ }
+ }
+ mnSdPageCount = maPages.size();
+
+ mbFrames = meMode == PUBLISH_FRAMES;
+
+ maDocFileName = maIndex;
+}
+
+void HtmlExport::ExportSingleDocument()
+{
+ SdrOutliner* pOutliner = mpDoc->GetInternalOutliner();
+
+ maPageNames.resize(mnSdPageCount);
+
+ mnPagesWritten = 0;
+ InitProgress(mnSdPageCount);
+
+ OUStringBuffer aStr(gaHTMLHeader);
+ aStr.append(DocumentMetadata());
+ aStr.append("\r\n");
+ aStr.append("</head>\r\n");
+ aStr.append(CreateBodyTag());
+
+ for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; ++nSdPage)
+ {
+ SdPage* pPage = maPages[nSdPage];
+ maPageNames[nSdPage] = pPage->GetName();
+
+ if( mbDocColors )
+ {
+ SetDocColors( pPage );
+ }
+
+ // page title
+ OUString sTitleText(CreateTextForTitle(pOutliner, pPage, pPage->GetPageBackgroundColor()));
+ OUString sStyle;
+
+ if (nSdPage != 0) // First page - no need for a page break here
+ sStyle += "page-break-before:always; ";
+ sStyle += getParagraphStyle(pOutliner, 0);
+
+ lclAppendStyle(aStr, u"h1", sStyle);
+
+ aStr.append(sTitleText);
+ aStr.append("</h1>\r\n");
+
+ // write outline text
+ aStr.append(CreateTextForPage( pOutliner, pPage, true, pPage->GetPageBackgroundColor() ));
+
+ // notes
+ if(mbNotes)
+ {
+ SdPage* pNotesPage = maNotesPages[ nSdPage ];
+ OUString aNotesStr( CreateTextForNotesPage( pOutliner, pNotesPage, maBackColor) );
+
+ if (!aNotesStr.isEmpty())
+ {
+ aStr.append("<br>\r\n<h3>");
+ aStr.append(RESTOHTML(STR_HTMLEXP_NOTES));
+ aStr.append(":</h3>\r\n");
+
+ aStr.append(aNotesStr);
+ }
+ }
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+
+ }
+
+ // close page
+ aStr.append("</body>\r\n</html>");
+
+ WriteHtml(maDocFileName, false, aStr.makeStringAndClear());
+
+ pOutliner->Clear();
+ ResetProgress();
+}
+
+// exports the (in the c'tor specified impress document) to html
+void HtmlExport::ExportHtml()
+{
+ if(mbUserAttr)
+ {
+ if( maTextColor == COL_AUTO )
+ {
+ if( !maBackColor.IsDark() )
+ maTextColor = COL_BLACK;
+ }
+ }
+ else if( mbDocColors )
+ {
+ // default colors for the color schema 'From Document'
+ SetDocColors();
+ maFirstPageColor = maBackColor;
+ }
+
+ // get name for downloadable presentation if needed
+ if( mbDownload )
+ {
+ // fade out separator search and extension
+ sal_Int32 nSepPos = maDocFileName.indexOf('.');
+ if (nSepPos != -1)
+ maDocFileName = maDocFileName.copy(0, nSepPos);
+
+ maDocFileName += ".odp";
+ }
+
+ sal_uInt16 nProgrCount = mnSdPageCount;
+ nProgrCount += mbImpress?mnSdPageCount:0;
+ nProgrCount += mbContentsPage?1:0;
+ nProgrCount += (mbFrames && mbNotes)?mnSdPageCount:0;
+ nProgrCount += mbFrames ? 8 : 0;
+ InitProgress( nProgrCount );
+
+ mpDocSh->SetWaitCursor( true );
+
+ // Exceptions are cool...
+
+ CreateFileNames();
+
+ // this is not a true while
+ while( true )
+ {
+ if( checkForExistingFiles() )
+ break;
+
+ if( !CreateImagesForPresPages() )
+ break;
+
+ if( mbContentsPage &&
+ !CreateImagesForPresPages( true ) )
+ break;
+
+ if( !CreateHtmlForPresPages() )
+ break;
+
+ if( mbImpress )
+ if( !CreateHtmlTextForPresPages() )
+ break;
+
+ if( mbFrames )
+ {
+ if( !CreateFrames() )
+ break;
+
+ if( !CreateOutlinePages() )
+ break;
+
+ if( !CreateNavBarFrames() )
+ break;
+
+ if( mbNotes && mbImpress )
+ if( !CreateNotesPages() )
+ break;
+
+ }
+
+ if( mbContentsPage )
+ if( !CreateContentPage() )
+ break;
+
+ CreateBitmaps();
+
+ mpDocSh->SetWaitCursor( false );
+ ResetProgress();
+
+ if( mbDownload )
+ SavePresentation();
+
+ return;
+ }
+
+ // if we get to this point the export was
+ // canceled by the user after an error
+ mpDocSh->SetWaitCursor( false );
+ ResetProgress();
+}
+
+void HtmlExport::SetDocColors( SdPage* pPage )
+{
+ if( pPage == nullptr )
+ pPage = mpDoc->GetSdPage(0, PageKind::Standard);
+
+ svtools::ColorConfig aConfig;
+ maVLinkColor = aConfig.GetColorValue(svtools::LINKSVISITED).nColor;
+ maALinkColor = aConfig.GetColorValue(svtools::LINKS).nColor;
+ maLinkColor = aConfig.GetColorValue(svtools::LINKS).nColor;
+ maTextColor = COL_BLACK;
+
+ SfxStyleSheet* pSheet = nullptr;
+
+ if( mpDoc->GetDocumentType() == DocumentType::Impress )
+ {
+ // default text color from the outline template of the first page
+ pSheet = pPage->GetStyleSheetForPresObj(PresObjKind::Outline);
+ if(pSheet == nullptr)
+ pSheet = pPage->GetStyleSheetForPresObj(PresObjKind::Text);
+ if(pSheet == nullptr)
+ pSheet = pPage->GetStyleSheetForPresObj(PresObjKind::Title);
+ }
+
+ if(pSheet == nullptr)
+ pSheet = mpDoc->GetDefaultStyleSheet();
+
+ if(pSheet)
+ {
+ SfxItemSet& rSet = pSheet->GetItemSet();
+ if(rSet.GetItemState(EE_CHAR_COLOR) == SfxItemState::SET)
+ maTextColor = rSet.GetItem<SvxColorItem>(EE_CHAR_COLOR)->GetValue();
+ }
+
+ // default background from the background of the master page of the first page
+ maBackColor = pPage->GetPageBackgroundColor();
+
+ if( maTextColor == COL_AUTO )
+ {
+ if( !maBackColor.IsDark() )
+ maTextColor = COL_BLACK;
+ }
+}
+
+void HtmlExport::InitProgress( sal_uInt16 nProgrCount )
+{
+ mpProgress.reset(new SfxProgress( mpDocSh, SdResId(STR_CREATE_PAGES), nProgrCount ));
+}
+
+void HtmlExport::ResetProgress()
+{
+ mpProgress.reset();
+}
+
+void HtmlExport::ExportKiosk()
+{
+ mnPagesWritten = 0;
+ InitProgress( 2*mnSdPageCount );
+
+ CreateFileNames();
+ if( !checkForExistingFiles() )
+ {
+ if( CreateImagesForPresPages() )
+ CreateHtmlForPresPages();
+ }
+
+ ResetProgress();
+}
+
+// Export Document with WebCast (TM) Technology
+void HtmlExport::ExportWebCast()
+{
+ mnPagesWritten = 0;
+ InitProgress( mnSdPageCount + 9 );
+
+ mpDocSh->SetWaitCursor( true );
+
+ CreateFileNames();
+
+ if (maCGIPath.isEmpty())
+ maCGIPath = ".";
+
+ if (!maCGIPath.endsWith("/"))
+ maCGIPath += "/";
+
+ if( meScript == SCRIPT_ASP )
+ {
+ maURLPath = "./";
+ }
+ else
+ {
+ if (maURLPath.isEmpty())
+ maURLPath = ".";
+
+ if (!maURLPath.endsWith("/"))
+ maURLPath += "/";
+ }
+
+ // this is not a true while
+ while(true)
+ {
+ if( checkForExistingFiles() )
+ break;
+
+ if(!CreateImagesForPresPages())
+ break;
+
+ if( meScript == SCRIPT_ASP )
+ {
+ if(!CreateASPScripts())
+ break;
+ }
+ else
+ {
+ if(!CreatePERLScripts())
+ break;
+ }
+
+ if(!CreateImageFileList())
+ break;
+
+ if(!CreateImageNumberFile())
+ break;
+
+ break;
+ }
+
+ mpDocSh->SetWaitCursor( false );
+ ResetProgress();
+}
+
+// Save the presentation as a downloadable file in the dest directory
+bool HtmlExport::SavePresentation()
+{
+ meEC.SetContext( STR_HTMLEXP_ERROR_CREATE_FILE, maDocFileName );
+
+ OUString aURL(maExportPath + maDocFileName);
+
+ mpDocSh->EnableSetModified();
+
+ try
+ {
+ uno::Reference< frame::XStorable > xStorable( mpDoc->getUnoModel(), uno::UNO_QUERY );
+ if( xStorable.is() )
+ {
+ uno::Sequence< beans::PropertyValue > aProperties{
+ comphelper::makePropertyValue("Overwrite", true),
+ comphelper::makePropertyValue("FilterName", OUString("impress8"))
+ };
+ xStorable->storeToURL( aURL, aProperties );
+
+ mpDocSh->EnableSetModified( false );
+
+ return true;
+ }
+ }
+ catch( Exception& )
+ {
+ }
+
+ mpDocSh->EnableSetModified( false );
+
+ return false;
+}
+
+// create image files
+bool HtmlExport::CreateImagesForPresPages( bool bThumbnail)
+{
+ try
+ {
+ Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+
+ Reference< drawing::XGraphicExportFilter > xGraphicExporter = drawing::GraphicExportFilter::create( xContext );
+
+ Sequence< PropertyValue > aFilterData(((meFormat==FORMAT_JPG)&&(mnCompression != -1))? 3 : 2);
+ auto pFilterData = aFilterData.getArray();
+ pFilterData[0].Name = "PixelWidth";
+ pFilterData[0].Value <<= static_cast<sal_Int32>(bThumbnail ? PUB_THUMBNAIL_WIDTH : mnWidthPixel );
+ pFilterData[1].Name = "PixelHeight";
+ pFilterData[1].Value <<= static_cast<sal_Int32>(bThumbnail ? PUB_THUMBNAIL_HEIGHT : mnHeightPixel);
+ if((meFormat==FORMAT_JPG)&&(mnCompression != -1))
+ {
+ pFilterData[2].Name = "Quality";
+ pFilterData[2].Value <<= static_cast<sal_Int32>(mnCompression);
+ }
+
+ OUString sFormat;
+ if( meFormat == FORMAT_PNG )
+ sFormat = "PNG";
+ else if( meFormat == FORMAT_GIF )
+ sFormat = "GIF";
+ else
+ sFormat = "JPG";
+
+ Sequence< PropertyValue > aDescriptor{
+ comphelper::makePropertyValue("URL", Any()),
+ comphelper::makePropertyValue("FilterName", sFormat),
+ comphelper::makePropertyValue("FilterData", aFilterData)
+ };
+ auto pDescriptor = aDescriptor.getArray();
+
+ for (sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
+ {
+ SdPage* pPage = maPages[ nSdPage ];
+
+ OUString aFull(maExportPath);
+ if (bThumbnail)
+ aFull += maThumbnailFiles[nSdPage];
+ else
+ aFull += maImageFiles[nSdPage];
+
+ pDescriptor[0].Value <<= aFull;
+
+ Reference< XComponent > xPage( pPage->getUnoPage(), UNO_QUERY );
+ xGraphicExporter->setSourceDocument( xPage );
+ xGraphicExporter->filter( aDescriptor );
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+ }
+ }
+ catch( Exception& )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// get SdrTextObject with layout text of this page
+SdrTextObj* HtmlExport::GetLayoutTextObject(SdrPage const * pPage)
+{
+ const size_t nObjectCount = pPage->GetObjCount();
+ SdrTextObj* pResult = nullptr;
+
+ for (size_t nObject = 0; nObject < nObjectCount; ++nObject)
+ {
+ SdrObject* pObject = pPage->GetObj(nObject);
+ if (pObject->GetObjInventor() == SdrInventor::Default &&
+ pObject->GetObjIdentifier() == SdrObjKind::OutlineText)
+ {
+ pResult = static_cast<SdrTextObj*>(pObject);
+ break;
+ }
+ }
+ return pResult;
+}
+
+// create HTML text version of impress pages
+OUString HtmlExport::CreateMetaCharset()
+{
+ OUString aStr;
+ const char *pCharSet = rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8 );
+ if ( pCharSet )
+ {
+ aStr = " <meta HTTP-EQUIV=CONTENT-TYPE CONTENT=\"text/html; charset=" +
+ OUString::createFromAscii(pCharSet) + "\">\r\n";
+ }
+ return aStr;
+}
+
+OUString HtmlExport::DocumentMetadata() const
+{
+ SvMemoryStream aStream;
+
+ uno::Reference<document::XDocumentProperties> xDocProps;
+ if (mpDocSh)
+ {
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ mpDocSh->GetModel(), uno::UNO_QUERY_THROW);
+ xDocProps.set(xDPS->getDocumentProperties());
+ }
+
+ SfxFrameHTMLWriter::Out_DocInfo(aStream, maDocFileName, xDocProps,
+ " ");
+
+ const sal_uInt64 nLen = aStream.GetSize();
+ OSL_ENSURE(nLen < o3tl::make_unsigned(SAL_MAX_INT32), "Stream can't fit in OString");
+ OString aData(static_cast<const char*>(aStream.GetData()), static_cast<sal_Int32>(nLen));
+
+ return OStringToOUString(aData, RTL_TEXTENCODING_UTF8);
+}
+
+bool HtmlExport::CreateHtmlTextForPresPages()
+{
+ bool bOk = true;
+
+ SdrOutliner* pOutliner = mpDoc->GetInternalOutliner();
+
+ for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount && bOk; nSdPage++)
+ {
+ SdPage* pPage = maPages[ nSdPage ];
+
+ if( mbDocColors )
+ {
+ SetDocColors( pPage );
+ }
+
+ // HTML head
+ OUStringBuffer aStr(gaHTMLHeader);
+ aStr.append(CreateMetaCharset());
+ aStr.append(" <title>");
+ aStr.append(StringToHTMLString(maPageNames[nSdPage]));
+ aStr.append("</title>\r\n");
+ aStr.append("</head>\r\n");
+ aStr.append(CreateBodyTag());
+
+ // navigation bar
+ aStr.append(CreateNavBar(nSdPage, true));
+
+ // page title
+ OUString sTitleText( CreateTextForTitle(pOutliner,pPage, pPage->GetPageBackgroundColor()) );
+ lclAppendStyle(aStr, u"h1", getParagraphStyle(pOutliner, 0));
+ aStr.append(sTitleText);
+ aStr.append("</h1>\r\n");
+
+ // write outline text
+ aStr.append(CreateTextForPage( pOutliner, pPage, true, pPage->GetPageBackgroundColor() ));
+
+ // notes
+ if(mbNotes)
+ {
+ SdPage* pNotesPage = maNotesPages[ nSdPage ];
+ OUString aNotesStr( CreateTextForNotesPage( pOutliner, pNotesPage, maBackColor) );
+
+ if (!aNotesStr.isEmpty())
+ {
+ aStr.append("<br>\r\n<h3>");
+ aStr.append(RESTOHTML(STR_HTMLEXP_NOTES));
+ aStr.append(":</h3>\r\n");
+
+ aStr.append(aNotesStr);
+ }
+ }
+
+ // close page
+ aStr.append("</body>\r\n</html>");
+
+ bOk = WriteHtml(maTextFiles[nSdPage], false, aStr.makeStringAndClear());
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+
+ }
+
+ pOutliner->Clear();
+
+ return bOk;
+}
+
+/** exports the given html data into a non unicode file in the current export path with
+ the given filename */
+bool HtmlExport::WriteHtml( const OUString& rFileName, bool bAddExtension, std::u16string_view rHtmlData )
+{
+ ErrCode nErr = ERRCODE_NONE;
+
+ OUString aFileName( rFileName );
+ if( bAddExtension )
+ aFileName += gaHTMLExtension;
+
+ meEC.SetContext( STR_HTMLEXP_ERROR_CREATE_FILE, rFileName );
+ EasyFile aFile;
+ SvStream* pStr;
+ OUString aFull(maExportPath + aFileName);
+ nErr = aFile.createStream(aFull , pStr);
+ if(nErr == ERRCODE_NONE)
+ {
+ OString aStr(OUStringToOString(rHtmlData, RTL_TEXTENCODING_UTF8));
+ pStr->WriteOString( aStr );
+ aFile.close();
+ }
+
+ if( nErr != ERRCODE_NONE )
+ ErrorHandler::HandleError(nErr);
+
+ return nErr == ERRCODE_NONE;
+}
+
+/** creates an outliner text for the title objects of a page
+ */
+OUString HtmlExport::CreateTextForTitle( SdrOutliner* pOutliner, SdPage* pPage, const Color& rBackgroundColor )
+{
+ SdrTextObj* pTO = static_cast<SdrTextObj*>(pPage->GetPresObj(PresObjKind::Title));
+ if(!pTO)
+ pTO = GetLayoutTextObject(pPage);
+
+ if (pTO && !pTO->IsEmptyPresObj())
+ {
+ OutlinerParaObject* pOPO = pTO->GetOutlinerParaObject();
+ if(pOPO && pOutliner->GetParagraphCount() != 0)
+ {
+ pOutliner->Clear();
+ pOutliner->SetText(*pOPO);
+ return ParagraphToHTMLString(pOutliner,0, rBackgroundColor);
+ }
+ }
+
+ return OUString();
+}
+
+// creates an outliner text for a page
+OUString HtmlExport::CreateTextForPage(SdrOutliner* pOutliner, SdPage const * pPage,
+ bool bHeadLine, const Color& rBackgroundColor)
+{
+ OUStringBuffer aStr;
+
+ for (size_t i = 0; i <pPage->GetObjCount(); ++i )
+ {
+ SdrObject* pObject = pPage->GetObj(i);
+ PresObjKind eKind = pPage->GetPresObjKind(pObject);
+
+ switch (eKind)
+ {
+ case PresObjKind::NONE:
+ {
+ if (pObject->GetObjIdentifier() == SdrObjKind::Group)
+ {
+ SdrObjGroup* pObjectGroup = static_cast<SdrObjGroup*>(pObject);
+ WriteObjectGroup(aStr, pObjectGroup, pOutliner, rBackgroundColor, false);
+ }
+ else if (pObject->GetObjIdentifier() == SdrObjKind::Table)
+ {
+ SdrTableObj* pTableObject = static_cast<SdrTableObj*>(pObject);
+ WriteTable(aStr, pTableObject, pOutliner, rBackgroundColor);
+ }
+ else
+ {
+ if (pObject->GetOutlinerParaObject())
+ {
+ WriteOutlinerParagraph(aStr, pOutliner, pObject->GetOutlinerParaObject(), rBackgroundColor, false);
+ }
+ }
+ }
+ break;
+
+ case PresObjKind::Table:
+ {
+ SdrTableObj* pTableObject = static_cast<SdrTableObj*>(pObject);
+ WriteTable(aStr, pTableObject, pOutliner, rBackgroundColor);
+ }
+ break;
+
+ case PresObjKind::Text:
+ case PresObjKind::Outline:
+ {
+ SdrTextObj* pTextObject = static_cast<SdrTextObj*>(pObject);
+ if (pTextObject->IsEmptyPresObj())
+ continue;
+ WriteOutlinerParagraph(aStr, pOutliner, pTextObject->GetOutlinerParaObject(), rBackgroundColor, bHeadLine);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return aStr.makeStringAndClear();
+}
+
+void HtmlExport::WriteTable(OUStringBuffer& aStr, SdrTableObj const * pTableObject, SdrOutliner* pOutliner, const Color& rBackgroundColor)
+{
+ CellPos aStart, aEnd;
+
+ aStart = SdrTableObj::getFirstCell();
+ aEnd = pTableObject->getLastCell();
+
+ sal_Int32 nColCount = pTableObject->getColumnCount();
+ aStr.append("<table>\r\n");
+ for (sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++)
+ {
+ aStr.append(" <tr>\r\n");
+ for (sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++)
+ {
+ aStr.append(" <td>\r\n");
+ sal_Int32 nCellIndex = nRow * nColCount + nCol;
+ SdrText* pText = pTableObject->getText(nCellIndex);
+
+ if (pText == nullptr)
+ continue;
+ WriteOutlinerParagraph(aStr, pOutliner, pText->GetOutlinerParaObject(), rBackgroundColor, false);
+ aStr.append(" </td>\r\n");
+ }
+ aStr.append(" </tr>\r\n");
+ }
+ aStr.append("</table>\r\n");
+}
+
+void HtmlExport::WriteObjectGroup(OUStringBuffer& aStr, SdrObjGroup const * pObjectGroup, SdrOutliner* pOutliner,
+ const Color& rBackgroundColor, bool bHeadLine)
+{
+ SdrObjListIter aGroupIterator(pObjectGroup->GetSubList(), SdrIterMode::DeepNoGroups);
+ while (aGroupIterator.IsMore())
+ {
+ SdrObject* pCurrentObject = aGroupIterator.Next();
+ if (pCurrentObject->GetObjIdentifier() == SdrObjKind::Group)
+ {
+ SdrObjGroup* pCurrentGroupObject = static_cast<SdrObjGroup*>(pCurrentObject);
+ WriteObjectGroup(aStr, pCurrentGroupObject, pOutliner, rBackgroundColor, bHeadLine);
+ }
+ else
+ {
+ OutlinerParaObject* pOutlinerParagraphObject = pCurrentObject->GetOutlinerParaObject();
+ if (pOutlinerParagraphObject != nullptr)
+ {
+ WriteOutlinerParagraph(aStr, pOutliner, pOutlinerParagraphObject, rBackgroundColor, bHeadLine);
+ }
+ }
+ }
+}
+
+void HtmlExport::WriteOutlinerParagraph(OUStringBuffer& aStr, SdrOutliner* pOutliner,
+ OutlinerParaObject const * pOutlinerParagraphObject,
+ const Color& rBackgroundColor, bool bHeadLine)
+{
+ if (pOutlinerParagraphObject == nullptr)
+ return;
+
+ pOutliner->SetText(*pOutlinerParagraphObject);
+
+ sal_Int32 nCount = pOutliner->GetParagraphCount();
+
+
+ sal_Int16 nCurrentDepth = -1;
+
+ for (sal_Int32 nIndex = 0; nIndex < nCount; nIndex++)
+ {
+ Paragraph* pParagraph = pOutliner->GetParagraph(nIndex);
+ if(pParagraph == nullptr)
+ continue;
+
+ const sal_Int16 nDepth = static_cast<sal_uInt16>(pOutliner->GetDepth(nIndex));
+ OUString aParaText = ParagraphToHTMLString(pOutliner, nIndex, rBackgroundColor);
+
+ if (aParaText.isEmpty())
+ continue;
+
+ if (nDepth < 0)
+ {
+ OUString aTag = bHeadLine ? OUString("h2") : OUString("p");
+ lclAppendStyle(aStr, aTag, getParagraphStyle(pOutliner, nIndex));
+
+ aStr.append(aParaText);
+ aStr.append("</" + aTag + ">\r\n");
+ }
+ else
+ {
+ while(nCurrentDepth < nDepth)
+ {
+ aStr.append("<ul>\r\n");
+ nCurrentDepth++;
+ }
+ while(nCurrentDepth > nDepth)
+ {
+ aStr.append("</ul>\r\n");
+ nCurrentDepth--;
+ }
+ lclAppendStyle(aStr, u"li", getParagraphStyle(pOutliner, nIndex));
+ aStr.append(aParaText);
+ aStr.append("</li>\r\n");
+ }
+ }
+ while(nCurrentDepth >= 0)
+ {
+ aStr.append("</ul>\r\n");
+ nCurrentDepth--;
+ }
+ pOutliner->Clear();
+}
+
+// creates an outliner text for a note page
+OUString HtmlExport::CreateTextForNotesPage( SdrOutliner* pOutliner,
+ SdPage* pPage,
+ const Color& rBackgroundColor )
+{
+ OUStringBuffer aStr;
+
+ SdrTextObj* pTO = static_cast<SdrTextObj*>(pPage->GetPresObj(PresObjKind::Notes));
+
+ if (pTO && !pTO->IsEmptyPresObj())
+ {
+ OutlinerParaObject* pOPO = pTO->GetOutlinerParaObject();
+ if (pOPO)
+ {
+ pOutliner->Clear();
+ pOutliner->SetText( *pOPO );
+
+ sal_Int32 nCount = pOutliner->GetParagraphCount();
+ for (sal_Int32 nPara = 0; nPara < nCount; nPara++)
+ {
+ lclAppendStyle(aStr, u"p", getParagraphStyle(pOutliner, nPara));
+ aStr.append(ParagraphToHTMLString(pOutliner, nPara, rBackgroundColor));
+ aStr.append("</p>\r\n");
+ }
+ }
+ }
+
+ return aStr.makeStringAndClear();
+}
+
+// converts a paragraph of the outliner to html
+OUString HtmlExport::ParagraphToHTMLString( SdrOutliner const * pOutliner, sal_Int32 nPara, const Color& rBackgroundColor )
+{
+ OUStringBuffer aStr;
+
+ if(nullptr == pOutliner)
+ return OUString();
+
+ // TODO: MALTE!!!
+ EditEngine& rEditEngine = *const_cast<EditEngine*>(&pOutliner->GetEditEngine());
+ bool bOldUpdateMode = rEditEngine.SetUpdateLayout(true);
+
+ Paragraph* pPara = pOutliner->GetParagraph(nPara);
+ if(nullptr == pPara)
+ return OUString();
+
+ HtmlState aState( (mbUserAttr || mbDocColors) ? maTextColor : COL_BLACK );
+ std::vector<sal_Int32> aPortionList;
+ rEditEngine.GetPortions( nPara, aPortionList );
+
+ sal_Int32 nPos1 = 0;
+ for( sal_Int32 nPos2 : aPortionList )
+ {
+ ESelection aSelection( nPara, nPos1, nPara, nPos2);
+
+ SfxItemSet aSet( rEditEngine.GetAttribs( aSelection ) );
+
+ OUString aPortion(StringToHTMLString(rEditEngine.GetText( aSelection )));
+
+ aStr.append(TextAttribToHTMLString( &aSet, &aState, rBackgroundColor ));
+ aStr.append(aPortion);
+
+ nPos1 = nPos2;
+ }
+ aStr.append(aState.Flush());
+ rEditEngine.SetUpdateLayout(bOldUpdateMode);
+
+ return aStr.makeStringAndClear();
+}
+
+// Depending on the attributes of the specified set and the specified
+// HtmlState, it creates the needed html tags in order to get the
+// attributes
+OUString HtmlExport::TextAttribToHTMLString( SfxItemSet const * pSet, HtmlState* pState, const Color& rBackgroundColor )
+{
+ OUStringBuffer aStr;
+
+ if(nullptr == pSet)
+ return OUString();
+
+ OUString aLink, aTarget;
+ if ( pSet->GetItemState( EE_FEATURE_FIELD ) == SfxItemState::SET )
+ {
+ const SvxFieldItem* pItem = pSet->GetItem<SvxFieldItem>( EE_FEATURE_FIELD );
+ if(pItem)
+ {
+ const SvxURLField* pURL = dynamic_cast<const SvxURLField*>( pItem->GetField() );
+ if(pURL)
+ {
+ aLink = pURL->GetURL();
+ aTarget = pURL->GetTargetFrame();
+ }
+ }
+ }
+
+ bool bTemp;
+ OUString aTemp;
+
+ if ( pSet->GetItemState( EE_CHAR_WEIGHT ) == SfxItemState::SET )
+ {
+ bTemp = pSet->Get( EE_CHAR_WEIGHT ).GetWeight() == WEIGHT_BOLD;
+ aTemp = pState->SetWeight( bTemp );
+ if( bTemp )
+ aStr.insert(0, aTemp);
+ else
+ aStr.append(aTemp);
+ }
+
+ if ( pSet->GetItemState( EE_CHAR_UNDERLINE ) == SfxItemState::SET )
+ {
+ bTemp = pSet->Get( EE_CHAR_UNDERLINE ).GetLineStyle() != LINESTYLE_NONE;
+ aTemp = pState->SetUnderline( bTemp );
+ if( bTemp )
+ aStr.insert(0, aTemp);
+ else
+ aStr.append(aTemp);
+ }
+
+ if ( pSet->GetItemState( EE_CHAR_STRIKEOUT ) == SfxItemState::SET )
+ {
+ bTemp = pSet->Get( EE_CHAR_STRIKEOUT ).GetStrikeout() != STRIKEOUT_NONE;
+ aTemp = pState->SetStrikeout( bTemp );
+ if( bTemp )
+ aStr.insert(0, aTemp);
+ else
+ aStr.append(aTemp);
+ }
+
+ if ( pSet->GetItemState( EE_CHAR_ITALIC ) == SfxItemState::SET )
+ {
+ bTemp = pSet->Get( EE_CHAR_ITALIC ).GetPosture() != ITALIC_NONE;
+ aTemp = pState->SetItalic( bTemp );
+ if( bTemp )
+ aStr.insert(0, aTemp);
+ else
+ aStr.append(aTemp);
+ }
+
+ if(mbDocColors)
+ {
+ if ( pSet->GetItemState( EE_CHAR_COLOR ) == SfxItemState::SET )
+ {
+ Color aTextColor = pSet->Get( EE_CHAR_COLOR ).GetValue();
+ if( aTextColor == COL_AUTO )
+ {
+ if( !rBackgroundColor.IsDark() )
+ aTextColor = COL_BLACK;
+ }
+ aStr.append(pState->SetColor( aTextColor ));
+ }
+ }
+
+ if (!aLink.isEmpty())
+ aStr.insert(0, pState->SetLink(aLink, aTarget));
+ else
+ aStr.append(pState->SetLink(aLink, aTarget));
+
+ return aStr.makeStringAndClear();
+}
+
+// create HTML wrapper for picture files
+bool HtmlExport::CreateHtmlForPresPages()
+{
+ bool bOk = true;
+
+ std::vector<SdrObject*> aClickableObjects;
+
+ for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount && bOk; nSdPage++)
+ {
+ // find clickable objects (also on the master page) and put it in the
+ // list. This in reverse order character order since in html the first
+ // area is taken in the case they overlap.
+ SdPage* pPage = maPages[ nSdPage ];
+
+ if( mbDocColors )
+ {
+ SetDocColors( pPage );
+ }
+
+ bool bMasterDone = false;
+
+ while (!bMasterDone)
+ {
+ // sal_True = backwards
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups, true);
+
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ SdAnimationInfo* pInfo = SdDrawDocument::GetAnimationInfo(pObject);
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(pObject);
+
+ if ((pInfo &&
+ (pInfo->meClickAction == presentation::ClickAction_BOOKMARK ||
+ pInfo->meClickAction == presentation::ClickAction_DOCUMENT ||
+ pInfo->meClickAction == presentation::ClickAction_PREVPAGE ||
+ pInfo->meClickAction == presentation::ClickAction_NEXTPAGE ||
+ pInfo->meClickAction == presentation::ClickAction_FIRSTPAGE ||
+ pInfo->meClickAction == presentation::ClickAction_LASTPAGE)) ||
+ pIMapInfo)
+ {
+ aClickableObjects.push_back(pObject);
+ }
+
+ pObject = aIter.Next();
+ }
+ // now to the master page or finishing
+ if (!pPage->IsMasterPage())
+ pPage = static_cast<SdPage*>(&(pPage->TRG_GetMasterPage()));
+ else
+ bMasterDone = true;
+ }
+
+ // HTML Head
+ OUStringBuffer aStr(gaHTMLHeader);
+ aStr.append(CreateMetaCharset());
+ aStr.append(" <title>" + StringToHTMLString(maPageNames[nSdPage]) + "</title>\r\n");
+
+ // insert timing information
+ pPage = maPages[ nSdPage ];
+ if( meMode == PUBLISH_KIOSK )
+ {
+ double fSecs = 0;
+ bool bEndless = false;
+ if( !mbAutoSlide )
+ {
+ if( pPage->GetPresChange() != PresChange::Manual )
+ {
+ fSecs = pPage->GetTime();
+ bEndless = mpDoc->getPresentationSettings().mbEndless;
+ }
+ }
+ else
+ {
+ fSecs = mfSlideDuration;
+ bEndless = mbEndless;
+ }
+
+ if( fSecs != 0 )
+ {
+ if( nSdPage < (mnSdPageCount-1) || bEndless )
+ {
+ aStr.append("<meta http-equiv=\"refresh\" content=\"");
+ aStr.append(fSecs);
+ aStr.append("; URL=");
+
+ int nPage = nSdPage + 1;
+ if( nPage == mnSdPageCount )
+ nPage = 0;
+
+ aStr.append(maHTMLFiles[nPage]);
+
+ aStr.append("\">\r\n");
+ }
+ }
+ }
+
+ aStr.append("</head>\r\n");
+
+ // HTML Body
+ aStr.append(CreateBodyTag());
+
+ if( mbSlideSound && pPage->IsSoundOn() )
+ aStr.append(InsertSound(pPage->GetSoundFile()));
+
+ // navigation bar
+ if(!mbFrames )
+ aStr.append(CreateNavBar(nSdPage, false));
+ // Image
+ aStr.append("<center>");
+ aStr.append("<img src=\"");
+ aStr.append(maImageFiles[nSdPage]);
+ aStr.append("\" alt=\"\"");
+
+ if (!aClickableObjects.empty())
+ aStr.append(" USEMAP=\"#map0\"");
+
+ aStr.append("></center>\r\n");
+
+ // notes
+ if(mbNotes && !mbFrames)
+ {
+ SdrOutliner* pOutliner = mpDoc->GetInternalOutliner();
+ SdPage* pNotesPage = maNotesPages[ nSdPage ];
+ OUString aNotesStr( CreateTextForNotesPage( pOutliner, pNotesPage, maBackColor) );
+ pOutliner->Clear();
+
+ if (!aNotesStr.isEmpty())
+ {
+ aStr.append("<h3>");
+ aStr.append(RESTOHTML(STR_HTMLEXP_NOTES));
+ aStr.append(":</h3><br>\r\n\r\n<p>");
+
+ aStr.append(aNotesStr);
+ aStr.append("\r\n</p>\r\n");
+ }
+ }
+
+ // create Imagemap if necessary
+ if (!aClickableObjects.empty())
+ {
+ aStr.append("<map name=\"map0\">\r\n");
+
+ for (SdrObject* pObject : aClickableObjects)
+ {
+ SdAnimationInfo* pInfo = SdDrawDocument::GetAnimationInfo(pObject);
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(pObject);
+
+ ::tools::Rectangle aRect(pObject->GetCurrentBoundRect());
+ Point aLogPos(aRect.TopLeft());
+ bool bIsSquare = aRect.GetWidth() == aRect.GetHeight();
+
+ sal_uLong nPageWidth = pPage->GetSize().Width() - pPage->GetLeftBorder() -
+ pPage->GetRightBorder();
+
+ // BoundRect is relative to the physical page origin, not the
+ // origin of ordinates
+ aRect.Move(-pPage->GetLeftBorder(), -pPage->GetUpperBorder());
+
+ double fLogicToPixel = static_cast<double>(mnWidthPixel) / nPageWidth;
+ aRect.SetLeft( static_cast<tools::Long>(aRect.Left() * fLogicToPixel) );
+ aRect.SetTop( static_cast<tools::Long>(aRect.Top() * fLogicToPixel) );
+ aRect.SetRight( static_cast<tools::Long>(aRect.Right() * fLogicToPixel) );
+ aRect.SetBottom( static_cast<tools::Long>(aRect.Bottom() * fLogicToPixel) );
+ tools::Long nRadius = aRect.GetWidth() / 2;
+
+ /**
+ insert areas into Imagemap of the object, if the object has
+ such an Imagemap
+ */
+ if (pIMapInfo)
+ {
+ const ImageMap& rIMap = pIMapInfo->GetImageMap();
+ sal_uInt16 nAreaCount = rIMap.GetIMapObjectCount();
+ for (sal_uInt16 nArea = 0; nArea < nAreaCount; nArea++)
+ {
+ IMapObject* pArea = rIMap.GetIMapObject(nArea);
+ IMapObjectType nType = pArea->GetType();
+ OUString aURL( pArea->GetURL() );
+
+ // if necessary, convert page and object names into the
+ // corresponding names of the html file
+ bool bIsMasterPage;
+ sal_uInt16 nPgNum = mpDoc->GetPageByName( aURL, bIsMasterPage );
+
+ if (nPgNum == SDRPAGE_NOTFOUND)
+ {
+ // is the bookmark an object?
+ SdrObject* pObj = mpDoc->GetObj( aURL );
+ if (pObj)
+ nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum();
+ }
+ if (nPgNum != SDRPAGE_NOTFOUND)
+ {
+ nPgNum = (nPgNum - 1) / 2; // SdrPageNum --> SdPageNum
+ aURL = CreatePageURL(nPgNum);
+ }
+
+ switch(nType)
+ {
+ case IMapObjectType::Rectangle:
+ {
+ ::tools::Rectangle aArea(static_cast<IMapRectangleObject*>(pArea)->
+ GetRectangle(false));
+
+ // conversion into pixel coordinates
+ aArea.Move(aLogPos.X() - pPage->GetLeftBorder(),
+ aLogPos.Y() - pPage->GetUpperBorder());
+ aArea.SetLeft( static_cast<tools::Long>(aArea.Left() * fLogicToPixel) );
+ aArea.SetTop( static_cast<tools::Long>(aArea.Top() * fLogicToPixel) );
+ aArea.SetRight( static_cast<tools::Long>(aArea.Right() * fLogicToPixel) );
+ aArea.SetBottom( static_cast<tools::Long>(aArea.Bottom() * fLogicToPixel) );
+
+ aStr.append(CreateHTMLRectArea(aArea, aURL));
+ }
+ break;
+
+ case IMapObjectType::Circle:
+ {
+ Point aCenter(static_cast<IMapCircleObject*>(pArea)->
+ GetCenter(false));
+ aCenter += Point(aLogPos.X() - pPage->GetLeftBorder(),
+ aLogPos.Y() - pPage->GetUpperBorder());
+ aCenter.setX( static_cast<tools::Long>(aCenter.X() * fLogicToPixel) );
+ aCenter.setY( static_cast<tools::Long>(aCenter.Y() * fLogicToPixel) );
+
+ sal_uLong nCircleRadius = static_cast<IMapCircleObject*>(pArea)->
+ GetRadius(false);
+ nCircleRadius = static_cast<sal_uLong>(nCircleRadius * fLogicToPixel);
+ aStr.append(CreateHTMLCircleArea(nCircleRadius,
+ aCenter.X(), aCenter.Y(),
+ aURL));
+ }
+ break;
+
+ case IMapObjectType::Polygon:
+ {
+ tools::Polygon aArea(static_cast<IMapPolygonObject*>(pArea)->GetPolygon(false));
+ aStr.append(CreateHTMLPolygonArea(::basegfx::B2DPolyPolygon(aArea.getB2DPolygon()),
+ Size(aLogPos.X() - pPage->GetLeftBorder(),
+ aLogPos.Y() - pPage->GetUpperBorder()),
+ fLogicToPixel, aURL));
+ }
+ break;
+
+ default:
+ {
+ SAL_INFO("sd", "unknown IMapObjectType");
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ if there is a presentation::ClickAction, determine bookmark
+ and create area for the whole object
+ */
+ if( pInfo )
+ {
+ OUString aHRef;
+ presentation::ClickAction eClickAction = pInfo->meClickAction;
+
+ switch( eClickAction )
+ {
+ case presentation::ClickAction_BOOKMARK:
+ {
+ bool bIsMasterPage;
+ sal_uInt16 nPgNum = mpDoc->GetPageByName( pInfo->GetBookmark(), bIsMasterPage );
+
+ if( nPgNum == SDRPAGE_NOTFOUND )
+ {
+ // is the bookmark an object?
+ SdrObject* pObj = mpDoc->GetObj(pInfo->GetBookmark());
+ if (pObj)
+ nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum();
+ }
+
+ if( SDRPAGE_NOTFOUND != nPgNum )
+ aHRef = CreatePageURL(( nPgNum - 1 ) / 2 );
+ }
+ break;
+
+ case presentation::ClickAction_DOCUMENT:
+ aHRef = pInfo->GetBookmark();
+ break;
+
+ case presentation::ClickAction_PREVPAGE:
+ {
+ sal_uLong nPage;
+
+ if (nSdPage == 0)
+ nPage = 0;
+ else
+ nPage = nSdPage - 1;
+
+ aHRef = CreatePageURL( static_cast<sal_uInt16>(nPage));
+ }
+ break;
+
+ case presentation::ClickAction_NEXTPAGE:
+ {
+ sal_uLong nPage;
+ if (nSdPage == mnSdPageCount - 1)
+ nPage = mnSdPageCount - 1;
+ else
+ nPage = nSdPage + 1;
+
+ aHRef = CreatePageURL( static_cast<sal_uInt16>(nPage));
+ }
+ break;
+
+ case presentation::ClickAction_FIRSTPAGE:
+ aHRef = CreatePageURL(0);
+ break;
+
+ case presentation::ClickAction_LASTPAGE:
+ aHRef = CreatePageURL(mnSdPageCount - 1);
+ break;
+
+ default:
+ break;
+ }
+
+ // and now the areas
+ if (!aHRef.isEmpty())
+ {
+ // a circle?
+ if (pObject->GetObjInventor() == SdrInventor::Default &&
+ pObject->GetObjIdentifier() == SdrObjKind::CircleOrEllipse &&
+ bIsSquare )
+ {
+ aStr.append(CreateHTMLCircleArea(aRect.GetWidth() / 2,
+ aRect.Left() + nRadius,
+ aRect.Top() + nRadius,
+ aHRef));
+ }
+ // a polygon?
+ else if (pObject->GetObjInventor() == SdrInventor::Default &&
+ (pObject->GetObjIdentifier() == SdrObjKind::PathLine ||
+ pObject->GetObjIdentifier() == SdrObjKind::PolyLine ||
+ pObject->GetObjIdentifier() == SdrObjKind::Polygon))
+ {
+ aStr.append(CreateHTMLPolygonArea(static_cast<SdrPathObj*>(pObject)->GetPathPoly(), Size(-pPage->GetLeftBorder(), -pPage->GetUpperBorder()), fLogicToPixel, aHRef));
+ }
+ // something completely different: use the BoundRect
+ else
+ {
+ aStr.append(CreateHTMLRectArea(aRect, aHRef));
+ }
+
+ }
+ }
+ }
+
+ aStr.append("</map>\r\n");
+ }
+ aClickableObjects.clear();
+
+ aStr.append("</body>\r\n</html>");
+
+ bOk = WriteHtml(maHTMLFiles[nSdPage], false, aStr.makeStringAndClear());
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+ }
+
+ return bOk;
+}
+
+// create overview pages
+bool HtmlExport::CreateContentPage()
+{
+ if( mbDocColors )
+ SetDocColors();
+
+ // html head
+ OUStringBuffer aStr(gaHTMLHeader);
+ aStr.append(CreateMetaCharset());
+ aStr.append(" <title>");
+ aStr.append(StringToHTMLString(maPageNames[0]));
+ aStr.append("</title>\r\n</head>\r\n");
+ aStr.append(CreateBodyTag());
+
+ // page head
+ aStr.append("<center>\r\n");
+
+ if(mbHeader)
+ {
+ aStr.append("<h1>");
+ aStr.append(getDocumentTitle());
+ aStr.append("</h1><br>\r\n");
+ }
+
+ aStr.append("<h2>");
+
+ // Solaris compiler bug workaround
+ if( mbFrames )
+ aStr.append(CreateLink(maFramePage,
+ RESTOHTML(STR_HTMLEXP_CLICKSTART)));
+ else
+ aStr.append(CreateLink(StringToHTMLString(maHTMLFiles[0]),
+ RESTOHTML(STR_HTMLEXP_CLICKSTART)));
+
+ aStr.append("</h2>\r\n</center>\r\n");
+
+ aStr.append("<center><table width=\"90%\"><tr>\r\n");
+
+ // table of content
+ aStr.append("<td valign=\"top\" align=\"left\" width=\"25%\">\r\n");
+ aStr.append("<h3>");
+ aStr.append(RESTOHTML(STR_HTMLEXP_CONTENTS));
+ aStr.append("</h3>");
+
+ for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
+ {
+ OUString aPageName = maPageNames[nSdPage];
+ aStr.append("<div align=\"left\">");
+ if(mbFrames)
+ aStr.append(StringToHTMLString(aPageName));
+ else
+ aStr.append(CreateLink(maHTMLFiles[nSdPage], aPageName));
+ aStr.append("</div>\r\n");
+ }
+ aStr.append("</td>\r\n");
+
+ // document information
+ aStr.append("<td valign=\"top\" align=\"left\" width=\"75%\">\r\n");
+
+ if (!maAuthor.isEmpty())
+ {
+ aStr.append("<p><strong>");
+ aStr.append(RESTOHTML(STR_HTMLEXP_AUTHOR));
+ aStr.append(":</strong> ");
+ aStr.append(StringToHTMLString(maAuthor));
+ aStr.append("</p>\r\n");
+ }
+
+ if (!maEMail.isEmpty())
+ {
+ aStr.append("<p><strong>");
+ aStr.append(RESTOHTML(STR_HTMLEXP_EMAIL));
+ aStr.append(":</strong> <a href=\"mailto:");
+ aStr.append(maEMail);
+ aStr.append("\">");
+ aStr.append(StringToHTMLString(maEMail));
+ aStr.append("</a></p>\r\n");
+ }
+
+ if (!maHomePage.isEmpty())
+ {
+ aStr.append("<p><strong>");
+ aStr.append(RESTOHTML(STR_HTMLEXP_HOMEPAGE));
+ aStr.append(":</strong> <a href=\"");
+ aStr.append(maHomePage);
+ aStr.append("\">");
+ aStr.append(StringToHTMLString(maHomePage));
+ aStr.append("</a> </p>\r\n");
+ }
+
+ if (!maInfo.isEmpty())
+ {
+ aStr.append("<p><strong>");
+ aStr.append(RESTOHTML(STR_HTMLEXP_INFO));
+ aStr.append(":</strong><br>\r\n");
+ aStr.append(StringToHTMLString(maInfo));
+ aStr.append("</p>\r\n");
+ }
+
+ if(mbDownload)
+ {
+ aStr.append("<p><a href=\"");
+ aStr.append(maDocFileName);
+ aStr.append("\">");
+ aStr.append(RESTOHTML(STR_HTMLEXP_DOWNLOAD));
+ aStr.append("</a></p>\r\n");
+ }
+
+ for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
+ {
+ OUString aText(
+ "<img src=\"" +
+ maThumbnailFiles[nSdPage] +
+ "\" width=\"256\" height=\"192\" alt=\"" +
+ StringToHTMLString(maPageNames[nSdPage]) +
+ "\">");
+
+ aStr.append(CreateLink(maHTMLFiles[nSdPage], aText));
+ aStr.append("\r\n");
+ }
+
+ aStr.append("</td></tr></table></center>\r\n");
+
+ aStr.append("</body>\r\n</html>");
+
+ bool bOk = WriteHtml(maIndex, false, aStr.makeStringAndClear());
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+
+ return bOk;
+}
+
+// create note pages (for frames)
+
+bool HtmlExport::CreateNotesPages()
+{
+ bool bOk = true;
+
+ SdrOutliner* pOutliner = mpDoc->GetInternalOutliner();
+ for( sal_uInt16 nSdPage = 0; bOk && nSdPage < mnSdPageCount; nSdPage++ )
+ {
+ SdPage* pPage = maNotesPages[nSdPage];
+ if( mbDocColors )
+ SetDocColors( pPage );
+
+ // Html head
+ OUStringBuffer aStr(gaHTMLHeader);
+ aStr.append(CreateMetaCharset());
+ aStr.append(" <title>");
+ aStr.append(StringToHTMLString(maPageNames[0]));
+ aStr.append("</title>\r\n</head>\r\n");
+ aStr.append(CreateBodyTag());
+
+ if(pPage)
+ aStr.append(CreateTextForNotesPage( pOutliner, pPage, maBackColor ));
+
+ aStr.append("</body>\r\n</html>");
+
+ OUString aFileName("note" + OUString::number(nSdPage));
+ bOk = WriteHtml(aFileName, true, aStr.makeStringAndClear());
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+ }
+
+ pOutliner->Clear();
+
+ return bOk;
+}
+
+// create outline pages (for frames)
+
+bool HtmlExport::CreateOutlinePages()
+{
+ bool bOk = true;
+
+ if( mbDocColors )
+ {
+ SetDocColors();
+ }
+
+ // page 0 will be the closed outline, page 1 the opened
+ for (sal_Int32 nPage = 0; nPage < (mbImpress?2:1) && bOk; ++nPage)
+ {
+ // Html head
+ OUStringBuffer aStr(gaHTMLHeader);
+ aStr.append(CreateMetaCharset());
+ aStr.append(" <title>");
+ aStr.append(StringToHTMLString(maPageNames[0]));
+ aStr.append("</title>\r\n</head>\r\n");
+ aStr.append(CreateBodyTag());
+
+ SdrOutliner* pOutliner = mpDoc->GetInternalOutliner();
+ for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
+ {
+ SdPage* pPage = maPages[ nSdPage ];
+
+ aStr.append("<div align=\"left\">");
+ OUString aLink("JavaScript:parent.NavigateAbs(" +
+ OUString::number(nSdPage) + ")");
+
+ OUString aTitle = CreateTextForTitle(pOutliner, pPage, maBackColor);
+ if (aTitle.isEmpty())
+ aTitle = maPageNames[nSdPage];
+
+ lclAppendStyle(aStr, u"p", getParagraphStyle(pOutliner, 0));
+ aStr.append(CreateLink(aLink, aTitle));
+ aStr.append("</p>");
+
+ if(nPage==1)
+ {
+ aStr.append(CreateTextForPage( pOutliner, pPage, false, maBackColor ));
+ }
+ aStr.append("</div>\r\n");
+ }
+ pOutliner->Clear();
+
+ aStr.append("</body>\r\n</html>");
+
+ OUString aFileName("outline" + OUString::number(nPage));
+ bOk = WriteHtml(aFileName, true, aStr.makeStringAndClear());
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+ }
+
+ return bOk;
+}
+
+// set file name
+void HtmlExport::CreateFileNames()
+{
+ // create lists with new file names
+ maHTMLFiles.resize(mnSdPageCount);
+ maImageFiles.resize(mnSdPageCount);
+ maThumbnailFiles.resize(mnSdPageCount);
+ maPageNames.resize(mnSdPageCount);
+ maTextFiles.resize(mnSdPageCount);
+
+ mbHeader = false; // headline on overview page?
+
+ for (sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
+ {
+ OUString aHTMLFileName;
+ if(nSdPage == 0 && !mbContentsPage && !mbFrames )
+ aHTMLFileName = maIndex;
+ else
+ {
+ aHTMLFileName = "img" + OUString::number(nSdPage) + gaHTMLExtension;
+ }
+
+ maHTMLFiles[nSdPage] = aHTMLFileName;
+
+ OUString aImageFileName = "img" + OUString::number(nSdPage);
+ if( meFormat==FORMAT_GIF )
+ aImageFileName += ".gif";
+ else if( meFormat==FORMAT_JPG )
+ aImageFileName += ".jpg";
+ else
+ aImageFileName += ".png";
+
+ maImageFiles[nSdPage] = aImageFileName;
+
+ OUString aThumbnailFileName = "thumb" + OUString::number(nSdPage);
+ if( meFormat!=FORMAT_JPG )
+ aThumbnailFileName += ".png";
+ else
+ aThumbnailFileName += ".jpg";
+
+ maThumbnailFiles[nSdPage] = aThumbnailFileName;
+
+ maTextFiles[nSdPage] = "text" + OUString::number(nSdPage) + gaHTMLExtension;
+
+ SdPage* pSdPage = maPages[ nSdPage ];
+
+ // get slide title from page name
+ maPageNames[nSdPage] = pSdPage->GetName();
+ }
+
+ if(!mbContentsPage && mbFrames)
+ maFramePage = maIndex;
+ else
+ {
+ maFramePage = "siframes" + gaHTMLExtension;
+ }
+}
+
+OUString const & HtmlExport::getDocumentTitle()
+{
+ // check for a title object in this page, if it's the first
+ // title it becomes this documents title for the content
+ // page
+ if( !mbHeader )
+ {
+ if(mbImpress)
+ {
+ // if there is a non-empty title object, use their first passage
+ // as page title
+ SdPage* pSdPage = mpDoc->GetSdPage(0, PageKind::Standard);
+ SdrObject* pTitleObj = pSdPage->GetPresObj(PresObjKind::Title);
+ if (pTitleObj && !pTitleObj->IsEmptyPresObj())
+ {
+ OutlinerParaObject* pParaObject = pTitleObj->GetOutlinerParaObject();
+ if (pParaObject)
+ {
+ const EditTextObject& rEditTextObject =
+ pParaObject->GetTextObject();
+ OUString aTest(rEditTextObject.GetText(0));
+ if (!aTest.isEmpty())
+ mDocTitle = aTest;
+ }
+ }
+
+ mDocTitle = mDocTitle.replace(0xff, ' ');
+ }
+
+ if (mDocTitle.isEmpty())
+ {
+ mDocTitle = maDocFileName;
+ sal_Int32 nDot = mDocTitle.indexOf('.');
+ if (nDot > 0)
+ mDocTitle = mDocTitle.copy(0, nDot);
+ }
+ mbHeader = true;
+ }
+
+ return mDocTitle;
+}
+
+constexpr OUStringLiteral JS_NavigateAbs =
+ u"function NavigateAbs( nPage )\r\n"
+ "{\r\n"
+ " frames[\"show\"].location.href = \"img\" + nPage + \".$EXT\";\r\n"
+ " //frames[\"notes\"].location.href = \"note\" + nPage + \".$EXT\";\r\n"
+ " nCurrentPage = nPage;\r\n"
+ " if(nCurrentPage==0)\r\n"
+ " {\r\n"
+ " frames[\"navbar1\"].location.href = \"navbar0.$EXT\";\r\n"
+ " }\r\n"
+ " else if(nCurrentPage==nPageCount-1)\r\n"
+ " {\r\n"
+ " frames[\"navbar1\"].location.href = \"navbar2.$EXT\";\r\n"
+ " }\r\n"
+ " else\r\n"
+ " {\r\n"
+ " frames[\"navbar1\"].location.href = \"navbar1.$EXT\";\r\n"
+ " }\r\n"
+ "}\r\n\r\n";
+
+constexpr OUStringLiteral JS_NavigateRel =
+ u"function NavigateRel( nDelta )\r\n"
+ "{\r\n"
+ " var nPage = parseInt(nCurrentPage) + parseInt(nDelta);\r\n"
+ " if( (nPage >= 0) && (nPage < nPageCount) )\r\n"
+ " {\r\n"
+ " NavigateAbs( nPage );\r\n"
+ " }\r\n"
+ "}\r\n\r\n";
+
+constexpr OUStringLiteral JS_ExpandOutline =
+ u"function ExpandOutline()\r\n"
+ "{\r\n"
+ " frames[\"navbar2\"].location.href = \"navbar4.$EXT\";\r\n"
+ " frames[\"outline\"].location.href = \"outline1.$EXT\";\r\n"
+ "}\r\n\r\n";
+
+constexpr OUStringLiteral JS_CollapseOutline =
+ u"function CollapseOutline()\r\n"
+ "{\r\n"
+ " frames[\"navbar2\"].location.href = \"navbar3.$EXT\";\r\n"
+ " frames[\"outline\"].location.href = \"outline0.$EXT\";\r\n"
+ "}\r\n\r\n";
+
+// create page with the frames
+
+bool HtmlExport::CreateFrames()
+{
+ OUString aTmp;
+ OUStringBuffer aStr(
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\"\r\n"
+ " \"http://www.w3.org/TR/html4/frameset.dtd\">\r\n"
+ "<html>\r\n<head>\r\n");
+
+ aStr.append(CreateMetaCharset());
+ aStr.append(" <title>");
+ aStr.append(StringToHTMLString(maPageNames[0]));
+ aStr.append("</title>\r\n");
+
+ aStr.append("<script type=\"text/javascript\">\r\n<!--\r\n");
+
+ aStr.append("var nCurrentPage = 0;\r\nvar nPageCount = ");
+ aStr.append(static_cast<sal_Int32>(mnSdPageCount));
+ aStr.append(";\r\n\r\n");
+
+ OUString aFunction = JS_NavigateAbs;
+
+ if(mbNotes)
+ {
+ aFunction = aFunction.replaceAll("//", "");
+ }
+
+ // substitute HTML file extension
+ OUString aPlaceHolder(".$EXT");
+ aFunction = aFunction.replaceAll(aPlaceHolder, gaHTMLExtension);
+ aStr.append(aFunction);
+
+ aTmp = JS_NavigateRel;
+ aTmp = aTmp.replaceAll(aPlaceHolder, gaHTMLExtension);
+ aStr.append(aTmp);
+
+ if(mbImpress)
+ {
+ aTmp = JS_ExpandOutline;
+ aTmp = aTmp.replaceAll(aPlaceHolder, gaHTMLExtension);
+ aStr.append(aTmp);
+
+ aTmp = JS_CollapseOutline;
+ aTmp = aTmp.replaceAll(aPlaceHolder, gaHTMLExtension);
+ aStr.append(aTmp);
+ }
+ aStr.append("// -->\r\n</script>\r\n");
+
+ aStr.append("</head>\r\n");
+
+ aStr.append("<frameset cols=\"*,");
+ aStr.append(static_cast<sal_Int32>(mnWidthPixel + 16));
+ aStr.append("\">\r\n");
+ if(mbImpress)
+ {
+ aStr.append(" <frameset rows=\"42,*\">\r\n");
+ aStr.append(" <frame src=\"navbar3");
+ aStr.append(gaHTMLExtension);
+ aStr.append("\" name=\"navbar2\" marginwidth=\"4\" marginheight=\"4\" scrolling=\"no\">\r\n");
+ }
+ aStr.append(" <frame src=\"outline0");
+ aStr.append(gaHTMLExtension);
+ aStr.append("\" name=\"outline\">\r\n");
+ if(mbImpress)
+ aStr.append(" </frameset>\r\n");
+
+ if(mbNotes)
+ {
+ aStr.append(" <frameset rows=\"42,");
+ aStr.append(static_cast<sal_Int32>(static_cast<double>(mnWidthPixel) * 0.75) + 16);
+ aStr.append(",*\">\r\n");
+ }
+ else
+ aStr.append(" <frameset rows=\"42,*\">\r\n");
+
+ aStr.append(" <frame src=\"navbar0");
+ aStr.append(gaHTMLExtension);
+ aStr.append("\" name=\"navbar1\" marginwidth=\"4\" marginheight=\"4\" scrolling=\"no\">\r\n");
+
+ aStr.append(" <frame src=\"");
+ aStr.append(maHTMLFiles[0]);
+ aStr.append("\" name=\"show\" marginwidth=\"4\" marginheight=\"4\">\r\n");
+
+ if(mbNotes)
+ {
+ aStr.append(" <frame src=\"note0");
+ aStr.append(gaHTMLExtension);
+ aStr.append("\" name=\"notes\">\r\n");
+ }
+ aStr.append(" </frameset>\r\n");
+
+ aStr.append("<noframes>\r\n");
+ aStr.append(CreateBodyTag());
+ aStr.append(RESTOHTML(STR_HTMLEXP_NOFRAMES));
+ aStr.append("\r\n</noframes>\r\n</frameset>\r\n</html>");
+
+ bool bOk = WriteHtml(maFramePage, false, aStr.makeStringAndClear());
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+
+ return bOk;
+}
+
+// create button bar for standard
+// we create the following html files
+// navbar0.htm navigation bar graphic for the first page
+// navbar1.htm navigation bar graphic for the second until second last page
+// navbar2.htm navigation bar graphic for the last page
+// navbar3.htm navigation outline closed
+// navbar4.htm navigation outline open
+bool HtmlExport::CreateNavBarFrames()
+{
+ bool bOk = true;
+ OUString aButton;
+
+ if( mbDocColors )
+ {
+ SetDocColors();
+ maBackColor = maFirstPageColor;
+ }
+
+ for( int nFile = 0; nFile < 3 && bOk; nFile++ )
+ {
+ OUStringBuffer aStr(gaHTMLHeader);
+ aStr.append(CreateMetaCharset());
+ aStr.append(" <title>");
+ aStr.append(StringToHTMLString(maPageNames[0]));
+ aStr.append("</title>\r\n</head>\r\n");
+ aStr.append(CreateBodyTag());
+ aStr.append("<center>\r\n");
+
+ // first page
+ aButton = SdResId(STR_HTMLEXP_FIRSTPAGE);
+ if(mnButtonThema != -1)
+ aButton = CreateImage(GetButtonName(nFile == 0 || mnSdPageCount == 1 ? BTN_FIRST_0 : BTN_FIRST_1),
+ aButton);
+
+ if(nFile != 0 && mnSdPageCount > 1)
+ aButton = CreateLink(u"JavaScript:parent.NavigateAbs(0)", aButton);
+
+ aStr.append(aButton);
+ aStr.append("\r\n");
+
+ // to the previous page
+ aButton = SdResId(STR_PUBLISH_BACK);
+ if(mnButtonThema != -1)
+ aButton = CreateImage(GetButtonName(nFile == 0 || mnSdPageCount == 1?
+ BTN_PREV_0:BTN_PREV_1),
+ aButton);
+
+ if(nFile != 0 && mnSdPageCount > 1)
+ aButton = CreateLink(u"JavaScript:parent.NavigateRel(-1)", aButton);
+
+ aStr.append(aButton);
+ aStr.append("\r\n");
+
+ // to the next page
+ aButton = SdResId(STR_PUBLISH_NEXT);
+ if(mnButtonThema != -1)
+ aButton = CreateImage(GetButtonName(nFile ==2 || mnSdPageCount == 1?
+ BTN_NEXT_0:BTN_NEXT_1),
+ aButton);
+
+ if(nFile != 2 && mnSdPageCount > 1)
+ aButton = CreateLink(u"JavaScript:parent.NavigateRel(1)", aButton);
+
+ aStr.append(aButton);
+ aStr.append("\r\n");
+
+ // to the last page
+ aButton = SdResId(STR_HTMLEXP_LASTPAGE);
+ if(mnButtonThema != -1)
+ aButton = CreateImage(GetButtonName(nFile ==2 || mnSdPageCount == 1?
+ BTN_LAST_0:BTN_LAST_1),
+ aButton);
+
+ if(nFile != 2 && mnSdPageCount > 1)
+ {
+ OUString aLink("JavaScript:parent.NavigateAbs(" +
+ OUString::number(mnSdPageCount-1) + ")");
+
+ aButton = CreateLink(aLink, aButton);
+ }
+
+ aStr.append(aButton);
+ aStr.append("\r\n");
+
+ // content
+ if (mbContentsPage)
+ {
+ aButton = SdResId(STR_PUBLISH_OUTLINE);
+ if(mnButtonThema != -1)
+ aButton = CreateImage(GetButtonName(BTN_INDEX), aButton);
+
+ // to the overview
+ aStr.append(CreateLink(maIndex, aButton, u"_top"));
+ aStr.append("\r\n");
+ }
+
+ // text mode
+ if(mbImpress)
+ {
+ aButton = SdResId(STR_HTMLEXP_SETTEXT);
+ if(mnButtonThema != -1)
+ aButton = CreateImage(GetButtonName(BTN_TEXT), aButton);
+
+ OUString aText0("text0" + gaHTMLExtension);
+ aStr.append(CreateLink(aText0, aButton, u"_top"));
+ aStr.append("\r\n");
+ }
+
+ // and finished...
+ aStr.append("</center>\r\n");
+ aStr.append("</body>\r\n</html>");
+
+ OUString aFileName("navbar" + OUString::number(nFile));
+
+ bOk = WriteHtml(aFileName, true, aStr.makeStringAndClear());
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+ }
+
+ // the navigation bar outliner closed...
+ if(bOk)
+ {
+ aButton = SdResId(STR_HTMLEXP_OUTLINE);
+ if(mnButtonThema != -1)
+ aButton = CreateImage(GetButtonName(BTN_MORE), aButton);
+
+ bOk = WriteHtml(
+ "navbar3", true,
+ OUStringConcatenation(
+ gaHTMLHeader + CreateMetaCharset() + " <title>"
+ + StringToHTMLString(maPageNames[0]) + "</title>\r\n</head>\r\n" + CreateBodyTag()
+ + CreateLink(u"JavaScript:parent.ExpandOutline()", aButton)
+ + "</body>\r\n</html>"));
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+ }
+
+ // ... and the outliner open
+ if( bOk )
+ {
+ aButton = SdResId(STR_HTMLEXP_NOOUTLINE);
+ if(mnButtonThema != -1)
+ aButton = CreateImage(GetButtonName(BTN_LESS), aButton);
+
+ bOk = WriteHtml(
+ "navbar4", true,
+ OUStringConcatenation(
+ gaHTMLHeader + CreateMetaCharset() + " <title>"
+ + StringToHTMLString(maPageNames[0]) + "</title>\r\n</head>\r\n" + CreateBodyTag()
+ + CreateLink(u"JavaScript:parent.CollapseOutline()", aButton)
+ + "</body>\r\n</html>"));
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+
+ }
+
+ return bOk;
+}
+
+// create button bar for standard
+OUString HtmlExport::CreateNavBar( sal_uInt16 nSdPage, bool bIsText ) const
+{
+ // prepare button bar
+ OUString aStrNavFirst(SdResId(STR_HTMLEXP_FIRSTPAGE));
+ OUString aStrNavPrev(SdResId(STR_PUBLISH_BACK));
+ OUString aStrNavNext(SdResId(STR_PUBLISH_NEXT));
+ OUString aStrNavLast(SdResId(STR_HTMLEXP_LASTPAGE));
+ OUString aStrNavContent(SdResId(STR_PUBLISH_OUTLINE));
+ OUString aStrNavText;
+ if( bIsText )
+ {
+ aStrNavText = SdResId(STR_HTMLEXP_SETGRAPHIC);
+ }
+ else
+ {
+ aStrNavText = SdResId(STR_HTMLEXP_SETTEXT);
+ }
+
+ if(!bIsText && mnButtonThema != -1)
+ {
+ if(nSdPage<1 || mnSdPageCount == 1)
+ {
+ aStrNavFirst = CreateImage(GetButtonName(BTN_FIRST_0), aStrNavFirst);
+ aStrNavPrev = CreateImage(GetButtonName(BTN_PREV_0), aStrNavPrev);
+ }
+ else
+ {
+ aStrNavFirst = CreateImage(GetButtonName(BTN_FIRST_1), aStrNavFirst);
+ aStrNavPrev = CreateImage(GetButtonName(BTN_PREV_1), aStrNavPrev);
+ }
+
+ if(nSdPage == mnSdPageCount-1 || mnSdPageCount == 1)
+ {
+ aStrNavNext = CreateImage(GetButtonName(BTN_NEXT_0), aStrNavNext);
+ aStrNavLast = CreateImage(GetButtonName(BTN_LAST_0), aStrNavLast);
+ }
+ else
+ {
+ aStrNavNext = CreateImage(GetButtonName(BTN_NEXT_1), aStrNavNext);
+ aStrNavLast = CreateImage(GetButtonName(BTN_LAST_1), aStrNavLast);
+ }
+
+ aStrNavContent = CreateImage(GetButtonName(BTN_INDEX), aStrNavContent);
+ aStrNavText = CreateImage(GetButtonName(BTN_TEXT), aStrNavText);
+ }
+
+ OUStringBuffer aStr("<center>\r\n"); //<table><tr>\r\n");
+
+ // first page
+ if(nSdPage > 0)
+ aStr.append(CreateLink( bIsText ? maTextFiles[0] : maHTMLFiles[0],aStrNavFirst));
+ else
+ aStr.append(aStrNavFirst);
+ aStr.append(' ');
+
+ // to Previous page
+ if(nSdPage > 0)
+ aStr.append(CreateLink( bIsText ? maTextFiles[nSdPage-1]
+ : maHTMLFiles[nSdPage-1], aStrNavPrev));
+ else
+ aStr.append(aStrNavPrev);
+ aStr.append(' ');
+
+ // to Next page
+ if(nSdPage < mnSdPageCount-1)
+ aStr.append(CreateLink( bIsText ? maTextFiles[nSdPage+1]
+ : maHTMLFiles[nSdPage+1], aStrNavNext));
+ else
+ aStr.append(aStrNavNext);
+ aStr.append(' ');
+
+ // to Last page
+ if(nSdPage < mnSdPageCount-1)
+ aStr.append(CreateLink( bIsText ? maTextFiles[mnSdPageCount-1]
+ : maHTMLFiles[mnSdPageCount-1],
+ aStrNavLast));
+ else
+ aStr.append(aStrNavLast);
+ aStr.append(' ');
+
+ // to Index page
+ if (mbContentsPage)
+ {
+ aStr.append(CreateLink(maIndex, aStrNavContent));
+ aStr.append(' ');
+ }
+
+ // Text/Graphics
+ if(mbImpress)
+ {
+ aStr.append(CreateLink( bIsText ? (mbFrames ? maFramePage : maHTMLFiles[nSdPage])
+ : maTextFiles[nSdPage], aStrNavText));
+
+ }
+
+ aStr.append("</center><br>\r\n");
+
+ return aStr.makeStringAndClear();
+}
+
+// export navigation graphics from button set
+void HtmlExport::CreateBitmaps()
+{
+ if(mnButtonThema == -1 || !mpButtonSet)
+ return;
+
+ for( int nButton = 0; nButton != SAL_N_ELEMENTS(pButtonNames); nButton++ )
+ {
+ if(!mbFrames && (nButton == BTN_MORE || nButton == BTN_LESS))
+ continue;
+
+ if(!mbImpress && (nButton == BTN_TEXT || nButton == BTN_MORE || nButton == BTN_LESS ))
+ continue;
+
+ OUString aFull = maExportPath + GetButtonName(nButton);
+ mpButtonSet->exportButton( mnButtonThema, aFull, GetButtonName(nButton) );
+ }
+}
+
+// creates the <body> tag, including the specified color attributes
+OUString HtmlExport::CreateBodyTag() const
+{
+ OUStringBuffer aStr( "<body" );
+
+ if( mbUserAttr || mbDocColors )
+ {
+ Color aTextColor( maTextColor );
+ if( (aTextColor == COL_AUTO) && (!maBackColor.IsDark()) )
+ aTextColor = COL_BLACK;
+
+ aStr.append(" text=\"");
+ aStr.append(ColorToHTMLString( aTextColor ));
+ aStr.append("\" bgcolor=\"");
+ aStr.append(ColorToHTMLString( maBackColor ));
+ aStr.append("\" link=\"");
+ aStr.append(ColorToHTMLString( maLinkColor ));
+ aStr.append("\" vlink=\"");
+ aStr.append(ColorToHTMLString( maVLinkColor ));
+ aStr.append("\" alink=\"");
+ aStr.append(ColorToHTMLString( maALinkColor ));
+ aStr.append("\"");
+ }
+
+ aStr.append(">\r\n");
+
+ return aStr.makeStringAndClear();
+}
+
+// creates a hyperlink
+OUString HtmlExport::CreateLink( std::u16string_view aLink,
+ std::u16string_view aText,
+ std::u16string_view aTarget )
+{
+ OUStringBuffer aStr( "<a href=\"" );
+ aStr.append(aLink);
+ if (!aTarget.empty())
+ {
+ aStr.append("\" target=\"");
+ aStr.append(aTarget);
+ }
+ aStr.append("\">");
+ aStr.append(aText);
+ aStr.append("</a>");
+
+ return aStr.makeStringAndClear();
+}
+
+// creates an image tag
+OUString HtmlExport::CreateImage( std::u16string_view aImage, std::u16string_view aAltText )
+{
+ OUStringBuffer aStr( "<img src=\"");
+ aStr.append(aImage);
+ aStr.append("\" border=0");
+
+ if (!aAltText.empty())
+ {
+ aStr.append(" alt=\"");
+ aStr.append(aAltText);
+ aStr.append('"');
+ }
+ else
+ {
+ // Agerskov: HTML 4.01 has to have an alt attribute even if it is an empty string
+ aStr.append(" alt=\"\"");
+ }
+
+ aStr.append('>');
+
+ return aStr.makeStringAndClear();
+}
+
+// create area for a circle; we expect pixel coordinates
+OUString HtmlExport::ColorToHTMLString( Color aColor )
+{
+ static const char hex[] = "0123456789ABCDEF";
+ OUStringBuffer aStr( "#xxxxxx" );
+ aStr[1] = hex[(aColor.GetRed() >> 4) & 0xf];
+ aStr[2] = hex[aColor.GetRed() & 0xf];
+ aStr[3] = hex[(aColor.GetGreen() >> 4) & 0xf];
+ aStr[4] = hex[aColor.GetGreen() & 0xf];
+ aStr[5] = hex[(aColor.GetBlue() >> 4) & 0xf];
+ aStr[6] = hex[aColor.GetBlue() & 0xf];
+
+ return aStr.makeStringAndClear();
+}
+
+// create area for a circle; we expect pixel coordinates
+OUString HtmlExport::CreateHTMLCircleArea( sal_uLong nRadius,
+ sal_uLong nCenterX,
+ sal_uLong nCenterY,
+ std::u16string_view rHRef )
+{
+ OUString aStr(
+ "<area shape=\"circle\" alt=\"\" coords=\"" +
+ OUString::number(nCenterX) + "," +
+ OUString::number(nCenterY) + "," +
+ OUString::number(nRadius) +
+ "\" href=\"" + rHRef + "\">\n");
+
+ return aStr;
+}
+
+// create area for a polygon; we expect pixel coordinates
+OUString HtmlExport::CreateHTMLPolygonArea( const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ Size aShift, double fFactor, std::u16string_view rHRef )
+{
+ OUStringBuffer aStr;
+ const sal_uInt32 nNoOfPolygons(rPolyPolygon.count());
+
+ for ( sal_uInt32 nXPoly = 0; nXPoly < nNoOfPolygons; nXPoly++ )
+ {
+ const ::basegfx::B2DPolygon& aPolygon = rPolyPolygon.getB2DPolygon(nXPoly);
+ const sal_uInt32 nNoOfPoints(aPolygon.count());
+
+ aStr.append("<area shape=\"polygon\" alt=\"\" coords=\"");
+
+ for ( sal_uInt32 nPoint = 0; nPoint < nNoOfPoints; nPoint++ )
+ {
+ const ::basegfx::B2DPoint aB2DPoint(aPolygon.getB2DPoint(nPoint));
+ Point aPnt(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
+ // coordinates are relative to the physical page origin, not the
+ // origin of ordinates
+ aPnt.Move(aShift.Width(), aShift.Height());
+
+ aPnt.setX( static_cast<tools::Long>(aPnt.X() * fFactor) );
+ aPnt.setY( static_cast<tools::Long>(aPnt.Y() * fFactor) );
+ aStr.append( OUString::number(aPnt.X()) + "," + OUString::number(aPnt.Y()) );
+
+ if (nPoint < nNoOfPoints - 1)
+ aStr.append(',');
+ }
+ aStr.append(OUString::Concat("\" href=\"") + rHRef + "\">\n");
+ }
+
+ return aStr.makeStringAndClear();
+}
+
+// create area for a rectangle; we expect pixel coordinates
+OUString HtmlExport::CreateHTMLRectArea( const ::tools::Rectangle& rRect,
+ std::u16string_view rHRef )
+{
+ OUString aStr(
+ "<area shape=\"rect\" alt=\"\" coords=\"" +
+ OUString::number(rRect.Left()) + "," +
+ OUString::number(rRect.Top()) + "," +
+ OUString::number(rRect.Right()) + "," +
+ OUString::number(rRect.Bottom()) +
+ "\" href=\"" + rHRef + "\">\n");
+
+ return aStr;
+}
+
+// escapes a string for html
+OUString HtmlExport::StringToHTMLString( const OUString& rString )
+{
+ SvMemoryStream aMemStm;
+ HTMLOutFuncs::Out_String( aMemStm, rString );
+ aMemStm.WriteChar( char(0) );
+ sal_Int32 nLength = strlen(static_cast<char const *>(aMemStm.GetData()));
+ return OUString( static_cast<char const *>(aMemStm.GetData()), nLength, RTL_TEXTENCODING_UTF8 );
+}
+
+// creates a URL for a specific page
+OUString HtmlExport::CreatePageURL( sal_uInt16 nPgNum )
+{
+ if(mbFrames)
+ {
+ return OUString("JavaScript:parent.NavigateAbs(" +
+ OUString::number(nPgNum) + ")");
+ }
+ else
+ return maHTMLFiles[nPgNum];
+}
+
+bool HtmlExport::CopyScript( std::u16string_view rPath, const OUString& rSource, const OUString& rDest, bool bUnix /* = false */ )
+{
+ INetURLObject aURL( SvtPathOptions().GetConfigPath() );
+ OUStringBuffer aScriptBuf;
+
+ aURL.Append( u"webcast" );
+ aURL.Append( rSource );
+
+ meEC.SetContext( STR_HTMLEXP_ERROR_OPEN_FILE, rSource );
+
+ ErrCode nErr = ERRCODE_NONE;
+ std::unique_ptr<SvStream> pIStm = ::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ );
+
+ if( pIStm )
+ {
+ OStringBuffer aLine;
+
+ while( pIStm->ReadLine( aLine ) )
+ {
+ aScriptBuf.appendAscii( aLine.getStr(), aLine.getLength() );
+ if( bUnix )
+ {
+ aScriptBuf.append("\n");
+ }
+ else
+ {
+ aScriptBuf.append("\r\n");
+ }
+ }
+
+ nErr = pIStm->GetError();
+ pIStm.reset();
+ }
+
+ if( nErr != ERRCODE_NONE )
+ {
+ ErrorHandler::HandleError( nErr );
+ return static_cast<bool>(nErr);
+ }
+
+ OUString aScript(aScriptBuf.makeStringAndClear());
+ aScript = aScript.replaceAll("$$1", getDocumentTitle());
+ aScript = aScript.replaceAll("$$2", RESTOHTML(STR_WEBVIEW_SAVE));
+ aScript = aScript.replaceAll("$$3", maCGIPath);
+ aScript = aScript.replaceAll("$$4", OUString::number(mnWidthPixel));
+ aScript = aScript.replaceAll("$$5", OUString::number(mnHeightPixel));
+
+ OUString aDest(rPath + rDest);
+
+ meEC.SetContext( STR_HTMLEXP_ERROR_CREATE_FILE, rDest );
+ // write script file
+ {
+ EasyFile aFile;
+ SvStream* pStr;
+ nErr = aFile.createStream(aDest, pStr);
+ if(nErr == ERRCODE_NONE)
+ {
+ OString aStr(OUStringToOString(aScript, RTL_TEXTENCODING_UTF8));
+ pStr->WriteOString( aStr );
+ aFile.close();
+ }
+ }
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+
+ if( nErr != ERRCODE_NONE )
+ ErrorHandler::HandleError( nErr );
+
+ return nErr == ERRCODE_NONE;
+}
+
+static const char * ASP_Scripts[] = { "common.inc", "webcast.asp", "show.asp", "savepic.asp", "poll.asp", "editpic.asp" };
+
+/** creates and saves the ASP scripts for WebShow */
+bool HtmlExport::CreateASPScripts()
+{
+ for(const char * p : ASP_Scripts)
+ {
+ OUString aScript = OUString::createFromAscii(p);
+
+ if(!CopyScript(maExportPath, aScript, aScript))
+ return false;
+ }
+
+ return CopyScript(maExportPath, "edit.asp", maIndex);
+}
+
+static const char *PERL_Scripts[] = { "webcast.pl", "common.pl", "editpic.pl", "poll.pl", "savepic.pl", "show.pl" };
+
+// creates and saves the PERL scripts for WebShow
+bool HtmlExport::CreatePERLScripts()
+{
+ for(const char * p : PERL_Scripts)
+ {
+ OUString aScript = OUString::createFromAscii(p);
+
+ if(!CopyScript(maExportPath, aScript, aScript, true))
+ return false;
+ }
+
+ if (!CopyScript(maExportPath, "edit.pl", maIndex, true))
+ return false;
+
+ if (!CopyScript(maExportPath, "index.pl", maIndexUrl, true))
+ return false;
+
+ return true;
+}
+
+// creates a list with names of the saved images
+bool HtmlExport::CreateImageFileList()
+{
+ OUStringBuffer aStr;
+ for( sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
+ {
+ aStr.append(static_cast<sal_Int32>(nSdPage + 1));
+ aStr.append(';');
+ aStr.append(maURLPath);
+ aStr.append(maImageFiles[nSdPage]);
+ aStr.append("\r\n");
+ }
+
+ bool bOk = WriteHtml("picture.txt", false, aStr.makeStringAndClear());
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+
+ return bOk;
+}
+
+// creates a file with the actual page number
+bool HtmlExport::CreateImageNumberFile()
+{
+ OUString aFileName("currpic.txt");
+ OUString aFull(maExportPath + aFileName);
+
+ meEC.SetContext( STR_HTMLEXP_ERROR_CREATE_FILE, aFileName );
+ EasyFile aFile;
+ SvStream* pStr;
+ ErrCode nErr = aFile.createStream(aFull, pStr);
+ if(nErr == ERRCODE_NONE)
+ {
+ pStr->WriteCharPtr( "1" );
+ aFile.close();
+ }
+
+ if (mpProgress)
+ mpProgress->SetState(++mnPagesWritten);
+
+ if( nErr != ERRCODE_NONE )
+ ErrorHandler::HandleError( nErr );
+
+ return nErr == ERRCODE_NONE;
+}
+
+OUString HtmlExport::InsertSound( const OUString& rSoundFile )
+{
+ if (rSoundFile.isEmpty())
+ return rSoundFile;
+
+ INetURLObject aURL( rSoundFile );
+ OUString aSoundFileName = aURL.getName();
+
+ DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+
+ OUString aStr("<embed src=\"" + aSoundFileName +
+ "\" hidden=\"true\" autostart=\"true\">");
+
+ CopyFile(rSoundFile, maExportPath + aSoundFileName);
+
+ return aStr;
+}
+
+bool HtmlExport::CopyFile( const OUString& rSourceFile, const OUString& rDestFile )
+{
+ meEC.SetContext( STR_HTMLEXP_ERROR_COPY_FILE, rSourceFile, rDestFile );
+ osl::FileBase::RC Error = osl::File::copy( rSourceFile, rDestFile );
+
+ if( Error != osl::FileBase::E_None )
+ {
+ ErrorHandler::HandleError(ErrCode(Error));
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool HtmlExport::checkFileExists( Reference< css::ucb::XSimpleFileAccess3 > const & xFileAccess, std::u16string_view aFileName )
+{
+ try
+ {
+ OUString url = maExportPath + aFileName;
+ return xFileAccess->exists( url );
+ }
+ catch( css::uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::HtmlExport::checkFileExists()" );
+ }
+
+ return false;
+}
+
+bool HtmlExport::checkForExistingFiles()
+{
+ bool bFound = false;
+
+ try
+ {
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ uno::Reference<ucb::XSimpleFileAccess3> xFA(ucb::SimpleFileAccess::create(xContext));
+
+ sal_uInt16 nSdPage;
+ for( nSdPage = 0; !bFound && (nSdPage < mnSdPageCount); nSdPage++)
+ {
+ if( checkFileExists( xFA, maImageFiles[nSdPage] ) ||
+ checkFileExists( xFA, maHTMLFiles[nSdPage] ) ||
+ checkFileExists( xFA, maThumbnailFiles[nSdPage] ) ||
+ checkFileExists( xFA, maPageNames[nSdPage] ) ||
+ checkFileExists( xFA, maTextFiles[nSdPage] ) )
+ {
+ bFound = true;
+ }
+ }
+
+ if( !bFound && mbDownload )
+ bFound = checkFileExists( xFA, maDocFileName );
+
+ if( !bFound && mbFrames )
+ bFound = checkFileExists( xFA, maFramePage );
+
+ if( bFound )
+ {
+ OUString aSystemPath;
+ osl::FileBase::getSystemPathFromFileURL( maExportPath, aSystemPath );
+ OUString aMsg(SdResId(STR_OVERWRITE_WARNING));
+ aMsg = aMsg.replaceFirst( "%FILENAME", aSystemPath );
+
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::YesNo,
+ aMsg));
+ xWarn->set_default_response(RET_YES);
+ bFound = (RET_NO == xWarn->run());
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::HtmlExport::checkForExistingFiles()" );
+ bFound = false;
+ }
+
+ return bFound;
+}
+
+OUString HtmlExport::GetButtonName( int nButton )
+{
+ return OUString::createFromAscii(pButtonNames[nButton]);
+}
+
+EasyFile::EasyFile() : bOpen(false)
+{
+}
+
+EasyFile::~EasyFile()
+{
+ if( bOpen )
+ close();
+}
+
+ErrCode EasyFile::createStream( const OUString& rUrl, SvStream* &rpStr )
+{
+ if(bOpen)
+ close();
+
+ OUString aFileName;
+ createFileName( rUrl, aFileName );
+
+ ErrCode nErr = ERRCODE_NONE;
+ pOStm = ::utl::UcbStreamHelper::CreateStream( aFileName, StreamMode::WRITE | StreamMode::TRUNC );
+ if( pOStm )
+ {
+ bOpen = true;
+ nErr = pOStm->GetError();
+ }
+ else
+ {
+ nErr = ERRCODE_SFX_CANTCREATECONTENT;
+ }
+
+ if( nErr != ERRCODE_NONE )
+ {
+ bOpen = false;
+ pOStm.reset();
+ }
+
+ rpStr = pOStm.get();
+
+ return nErr;
+}
+
+void EasyFile::createFileName( const OUString& rURL, OUString& rFileName )
+{
+ if( bOpen )
+ close();
+
+ INetURLObject aURL( rURL );
+
+ if( aURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ OUString aURLStr;
+ osl::FileBase::getFileURLFromSystemPath( rURL, aURLStr );
+ aURL = INetURLObject( aURLStr );
+ }
+ DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+ rFileName = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+}
+
+void EasyFile::close()
+{
+ pOStm.reset();
+ bOpen = false;
+}
+
+// This class helps reporting errors during file i/o
+HtmlErrorContext::HtmlErrorContext()
+ : ErrorContext(nullptr)
+{
+}
+
+bool HtmlErrorContext::GetString( ErrCode, OUString& rCtxStr )
+{
+ DBG_ASSERT(mpResId, "No error context set");
+ if (!mpResId)
+ return false;
+
+ rCtxStr = SdResId(mpResId);
+
+ rCtxStr = rCtxStr.replaceAll( "$(URL1)", maURL1 );
+ rCtxStr = rCtxStr.replaceAll( "$(URL2)", maURL2 );
+
+ return true;
+}
+
+void HtmlErrorContext::SetContext(TranslateId pResId, const OUString& rURL)
+{
+ mpResId = pResId;
+ maURL1 = rURL;
+ maURL2.clear();
+}
+
+void HtmlErrorContext::SetContext(TranslateId pResId, const OUString& rURL1, const OUString& rURL2 )
+{
+ mpResId = pResId;
+ maURL1 = rURL1;
+ maURL2 = rURL2;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/html/htmlex.hxx b/sd/source/filter/html/htmlex.hxx
new file mode 100644
index 000000000..5f6f06e49
--- /dev/null
+++ b/sd/source/filter/html/htmlex.hxx
@@ -0,0 +1,237 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <resltn.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/color.hxx>
+#include <tools/solar.h>
+#include <vcl/errinf.hxx>
+#include <unotools/resmgr.hxx>
+
+#include "htmlpublishmode.hxx"
+
+#include <memory>
+#include <string_view>
+#include <vector>
+
+namespace basegfx { class B2DPolyPolygon; }
+namespace com::sun::star::beans { struct PropertyValue; }
+namespace com::sun::star::ucb { class XSimpleFileAccess3; }
+namespace sd { class DrawDocShell; }
+namespace tools { class Rectangle; }
+
+#define PUB_LOWRES_WIDTH 640
+#define PUB_MEDRES_WIDTH 800
+#define PUB_HIGHRES_WIDTH 1024
+#define PUB_FHDRES_WIDTH 1920
+
+#define PUB_THUMBNAIL_WIDTH 256
+#define PUB_THUMBNAIL_HEIGHT 192
+
+class ErrCode;
+class OutlinerParaObject;
+class SfxItemSet;
+class Size;
+class SfxProgress;
+class SdrOutliner;
+class SdPage;
+class HtmlState;
+class SdrTextObj;
+class SdrObjGroup;
+namespace sdr::table { class SdrTableObj; }
+class SdrPage;
+class SdDrawDocument;
+class ButtonSet;
+
+class HtmlErrorContext : public ErrorContext
+{
+private:
+ TranslateId mpResId;
+ OUString maURL1;
+ OUString maURL2;
+
+public:
+ explicit HtmlErrorContext();
+
+ virtual bool GetString( ErrCode nErrId, OUString& rCtxStr ) override;
+
+ void SetContext(TranslateId pResId, const OUString& rURL);
+ void SetContext(TranslateId pResId, const OUString& rURL1, const OUString& rURL2);
+};
+
+/// this class exports an Impress Document as a HTML Presentation.
+class HtmlExport final
+{
+ std::vector< SdPage* > maPages;
+ std::vector< SdPage* > maNotesPages;
+
+ OUString maPath;
+
+ SdDrawDocument* mpDoc;
+ ::sd::DrawDocShell* mpDocSh;
+
+ HtmlErrorContext meEC;
+
+ HtmlPublishMode meMode;
+ std::unique_ptr<SfxProgress> mpProgress;
+ bool mbImpress;
+ sal_uInt16 mnSdPageCount;
+ sal_uInt16 mnPagesWritten;
+ bool mbContentsPage;
+ sal_Int16 mnButtonThema;
+ sal_uInt16 mnWidthPixel;
+ sal_uInt16 mnHeightPixel;
+ PublishingFormat meFormat;
+ bool mbHeader;
+ bool mbNotes;
+ bool mbFrames;
+ OUString maIndex;
+ OUString maEMail;
+ OUString maAuthor;
+ OUString maHomePage;
+ OUString maInfo;
+ sal_Int16 mnCompression;
+ OUString maDocFileName;
+ OUString maFramePage;
+ OUString mDocTitle;
+ bool mbDownload;
+
+ bool mbAutoSlide;
+ double mfSlideDuration;
+ bool mbSlideSound;
+ bool mbHiddenSlides;
+ bool mbEndless;
+
+ bool mbUserAttr;
+ Color maTextColor; ///< The following colors are used for the <body> tag if mbUserAttr is true.
+ Color maBackColor;
+ Color maLinkColor;
+ Color maVLinkColor;
+ Color maALinkColor;
+ Color maFirstPageColor;
+ bool mbDocColors;
+
+ std::vector<OUString> maHTMLFiles;
+ std::vector<OUString> maImageFiles;
+ std::vector<OUString> maThumbnailFiles;
+ std::vector<OUString> maPageNames;
+ std::vector<OUString> maTextFiles;
+
+ OUString maExportPath; ///< output directory or URL.
+ OUString maIndexUrl;
+ OUString maURLPath;
+ OUString maCGIPath;
+ PublishingScript meScript;
+
+ std::unique_ptr< ButtonSet > mpButtonSet;
+
+ static SdrTextObj* GetLayoutTextObject(SdrPage const * pPage);
+
+ void SetDocColors( SdPage* pPage = nullptr );
+
+ bool CreateImagesForPresPages( bool bThumbnails = false );
+ bool CreateHtmlTextForPresPages();
+ bool CreateHtmlForPresPages();
+ bool CreateContentPage();
+ void CreateFileNames();
+ void CreateBitmaps();
+ bool CreateOutlinePages();
+ bool CreateFrames();
+ bool CreateNotesPages();
+ bool CreateNavBarFrames();
+
+ bool CreateASPScripts();
+ bool CreatePERLScripts();
+ bool CreateImageFileList();
+ bool CreateImageNumberFile();
+
+ bool checkForExistingFiles();
+ bool checkFileExists( css::uno::Reference< css::ucb::XSimpleFileAccess3 > const & xFileAccess, std::u16string_view aFileName );
+
+ OUString const & getDocumentTitle();
+ bool SavePresentation();
+
+ static OUString CreateLink( std::u16string_view aLink, std::u16string_view aText,
+ std::u16string_view aTarget = std::u16string_view());
+ static OUString CreateImage( std::u16string_view aImage, std::u16string_view aAltText );
+ OUString CreateNavBar( sal_uInt16 nSdPage, bool bIsText ) const;
+ OUString CreateBodyTag() const;
+
+ OUString ParagraphToHTMLString( SdrOutliner const * pOutliner, sal_Int32 nPara, const Color& rBackgroundColor );
+ OUString TextAttribToHTMLString( SfxItemSet const * pSet, HtmlState* pState, const Color& rBackgroundColor );
+
+ OUString CreateTextForTitle( SdrOutliner* pOutliner, SdPage* pPage, const Color& rBackgroundColor );
+ OUString CreateTextForPage( SdrOutliner* pOutliner, SdPage const * pPage, bool bHeadLine, const Color& rBackgroundColor );
+ OUString CreateTextForNotesPage( SdrOutliner* pOutliner, SdPage* pPage, const Color& rBackgroundColor );
+
+ static OUString CreateHTMLCircleArea( sal_uLong nRadius, sal_uLong nCenterX,
+ sal_uLong nCenterY, std::u16string_view rHRef );
+ static OUString CreateHTMLPolygonArea( const ::basegfx::B2DPolyPolygon& rPolyPoly, Size aShift, double fFactor, std::u16string_view rHRef );
+ static OUString CreateHTMLRectArea( const ::tools::Rectangle& rRect,
+ std::u16string_view rHRef );
+
+ OUString CreatePageURL( sal_uInt16 nPgNum );
+
+ OUString InsertSound( const OUString& rSoundFile );
+ bool CopyFile( const OUString& rSourceFile, const OUString& rDestFile );
+ bool CopyScript( std::u16string_view rPath, const OUString& rSource, const OUString& rDest, bool bUnix = false );
+
+ void InitProgress( sal_uInt16 nProgrCount );
+ void ResetProgress();
+
+ /// Output only the charset metadata, title etc. will be handled separately.
+ static OUString CreateMetaCharset();
+
+ /// Output document metadata.
+ OUString DocumentMetadata() const;
+
+ void InitExportParameters( const css::uno::Sequence< css::beans::PropertyValue >& rParams);
+ void ExportHtml();
+ void ExportKiosk();
+ void ExportWebCast();
+ void ExportSingleDocument();
+
+ bool WriteHtml( const OUString& rFileName, bool bAddExtension, std::u16string_view rHtmlData );
+ static OUString GetButtonName( int nButton );
+
+ void WriteOutlinerParagraph(OUStringBuffer& aStr, SdrOutliner* pOutliner,
+ OutlinerParaObject const * pOutlinerParagraphObject,
+ const Color& rBackgroundColor, bool bHeadLine);
+
+ void WriteObjectGroup(OUStringBuffer& aStr, SdrObjGroup const * pObjectGroup,
+ SdrOutliner* pOutliner, const Color& rBackgroundColor, bool bHeadLine);
+
+ void WriteTable(OUStringBuffer& aStr, sdr::table::SdrTableObj const * pTableObject,
+ SdrOutliner* pOutliner, const Color& rBackgroundColor);
+
+ public:
+ HtmlExport(const OUString& aPath,
+ const css::uno::Sequence<css::beans::PropertyValue>& rParams,
+ SdDrawDocument* pExpDoc,
+ sd::DrawDocShell* pDocShell);
+
+ ~HtmlExport();
+
+ static OUString ColorToHTMLString( Color aColor );
+ static OUString StringToHTMLString( const OUString& rString );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/html/htmlpublishmode.hxx b/sd/source/filter/html/htmlpublishmode.hxx
new file mode 100644
index 000000000..3ba7eeb80
--- /dev/null
+++ b/sd/source/filter/html/htmlpublishmode.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+enum HtmlPublishMode
+{
+ PUBLISH_HTML,
+ PUBLISH_FRAMES,
+ PUBLISH_WEBCAST,
+ PUBLISH_KIOSK,
+ PUBLISH_SINGLE_DOCUMENT
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/html/pubdlg.cxx b/sd/source/filter/html/pubdlg.cxx
new file mode 100644
index 000000000..257021d96
--- /dev/null
+++ b/sd/source/filter/html/pubdlg.cxx
@@ -0,0 +1,1539 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <comphelper/sequence.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <vcl/FilterConfigItem.hxx>
+#include <vcl/image.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sal/log.hxx>
+#include <svtools/valueset.hxx>
+#include <svtools/colrdlg.hxx>
+#include <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/GenericTypeSerializer.hxx>
+#include <sdiocmpt.hxx>
+#include <sfx2/docfile.hxx>
+#include <pres.hxx>
+#include <unotools/useroptions.hxx>
+#include <unotools/pathoptions.hxx>
+
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <pubdlg.hxx>
+#include "htmlattr.hxx"
+#include "htmlex.hxx"
+#include "htmlpublishmode.hxx"
+#include <helpids.h>
+#include "buttonset.hxx"
+#include <strings.hxx>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+
+#define NOOFPAGES 6
+
+//ID for the config-data with the HTML-settings
+const sal_uInt16 nMagic = sal_uInt16(0x1977);
+
+// Key for the soffice.ini
+constexpr OUStringLiteral KEY_QUALITY = u"JPG-EXPORT-QUALITY";
+
+// The Help-IDs of the pages
+const char* const aPageHelpIds[NOOFPAGES] =
+{
+ HID_SD_HTMLEXPORT_PAGE1,
+ HID_SD_HTMLEXPORT_PAGE2,
+ HID_SD_HTMLEXPORT_PAGE3,
+ HID_SD_HTMLEXPORT_PAGE4,
+ HID_SD_HTMLEXPORT_PAGE5,
+ HID_SD_HTMLEXPORT_PAGE6
+};
+
+static SvStream& operator >> (SvStream& rIn, SdPublishingDesign& rDesign);
+
+static SvStream& WriteSdPublishingDesign(SvStream& rOut, const SdPublishingDesign& rDesign);
+
+// This class has all the settings for the HTML-export autopilot
+class SdPublishingDesign
+{
+public:
+ OUString m_aDesignName;
+
+ HtmlPublishMode m_eMode;
+
+ // special WebCast options
+ PublishingScript m_eScript;
+ OUString m_aCGI;
+ OUString m_aURL;
+
+ // special Kiosk options
+ bool m_bAutoSlide;
+ sal_uInt32 m_nSlideDuration;
+ bool m_bEndless;
+
+ // special HTML options
+ bool m_bContentPage;
+ bool m_bNotes;
+
+ // misc options
+ sal_uInt16 m_nResolution;
+ OUString m_aCompression;
+ PublishingFormat m_eFormat;
+ bool m_bSlideSound;
+ bool m_bHiddenSlides;
+
+ // title page information
+ OUString m_aAuthor;
+ OUString m_aEMail;
+ OUString m_aWWW;
+ OUString m_aMisc;
+ bool m_bDownload;
+ bool m_bCreated; // not used
+
+ // buttons and colorscheme
+ sal_Int16 m_nButtonThema;
+ bool m_bUserAttr;
+ Color m_aBackColor;
+ Color m_aTextColor;
+ Color m_aLinkColor;
+ Color m_aVLinkColor;
+ Color m_aALinkColor;
+ bool m_bUseAttribs;
+ bool m_bUseColor;
+
+ SdPublishingDesign();
+
+ bool operator ==(const SdPublishingDesign & rDesign) const;
+ friend SvStream& operator >> (SvStream& rIn, SdPublishingDesign& rDesign);
+ friend SvStream& WriteSdPublishingDesign(SvStream& rOut, const SdPublishingDesign& rDesign);
+};
+
+// load Default-settings
+SdPublishingDesign::SdPublishingDesign()
+ : m_eMode(PUBLISH_HTML)
+ , m_eScript(SCRIPT_ASP)
+ , m_bAutoSlide(true)
+ , m_nSlideDuration(15)
+ , m_bEndless(true)
+ , m_bContentPage(true)
+ , m_bNotes(true)
+ , m_nResolution(PUB_LOWRES_WIDTH)
+ , m_eFormat(FORMAT_PNG)
+ , m_bSlideSound(true)
+ , m_bHiddenSlides(false)
+ , m_bDownload(false)
+ , m_bCreated(false)
+ , m_nButtonThema(-1)
+ , m_bUserAttr(false)
+ , m_aBackColor(COL_WHITE)
+ , m_aTextColor(COL_BLACK)
+ , m_aLinkColor(COL_BLUE)
+ , m_aVLinkColor(COL_LIGHTGRAY)
+ , m_aALinkColor(COL_GRAY)
+ , m_bUseAttribs(true)
+ , m_bUseColor(true)
+{
+ FilterConfigItem aFilterConfigItem(u"Office.Common/Filter/Graphic/Export/JPG");
+ sal_Int32 nCompression = aFilterConfigItem.ReadInt32( KEY_QUALITY, 75 );
+ m_aCompression = OUString::number(nCompression) + "%";
+
+ SvtUserOptions aUserOptions;
+ m_aAuthor = aUserOptions.GetFirstName();
+ if (!m_aAuthor.isEmpty() && !aUserOptions.GetLastName().isEmpty())
+ m_aAuthor += " ";
+ m_aAuthor += aUserOptions.GetLastName();
+ m_aEMail = aUserOptions.GetEmail();
+}
+
+// Compares the values without paying attention to the name
+bool SdPublishingDesign::operator ==(const SdPublishingDesign & rDesign) const
+{
+ return
+ (
+ m_eMode == rDesign.m_eMode &&
+ m_nResolution == rDesign.m_nResolution &&
+ m_aCompression == rDesign.m_aCompression &&
+ m_eFormat == rDesign.m_eFormat &&
+ m_bHiddenSlides == rDesign.m_bHiddenSlides &&
+ ( // compare html options
+ (m_eMode != PUBLISH_HTML && m_eMode != PUBLISH_FRAMES) ||
+ (
+ m_bContentPage == rDesign.m_bContentPage &&
+ m_bNotes == rDesign.m_bNotes &&
+ m_aAuthor == rDesign.m_aAuthor &&
+ m_aEMail == rDesign.m_aEMail &&
+ m_aWWW == rDesign.m_aWWW &&
+ m_aMisc == rDesign.m_aMisc &&
+ m_bDownload == rDesign.m_bDownload &&
+ m_nButtonThema == rDesign.m_nButtonThema &&
+ m_bUserAttr == rDesign.m_bUserAttr &&
+ m_aBackColor == rDesign.m_aBackColor &&
+ m_aTextColor == rDesign.m_aTextColor &&
+ m_aLinkColor == rDesign.m_aLinkColor &&
+ m_aVLinkColor == rDesign.m_aVLinkColor &&
+ m_aALinkColor == rDesign.m_aALinkColor &&
+ m_bUseAttribs == rDesign.m_bUseAttribs &&
+ m_bSlideSound == rDesign.m_bSlideSound &&
+ m_bUseColor == rDesign.m_bUseColor
+ )
+ ) &&
+ ( // compare kiosk options
+ (m_eMode != PUBLISH_KIOSK) ||
+ (
+ m_bAutoSlide == rDesign.m_bAutoSlide &&
+ m_bSlideSound == rDesign.m_bSlideSound &&
+ (
+ !m_bAutoSlide ||
+ (
+ m_nSlideDuration == rDesign.m_nSlideDuration &&
+ m_bEndless == rDesign.m_bEndless
+ )
+ )
+ )
+ ) &&
+ ( // compare WebCast options
+ (m_eMode != PUBLISH_WEBCAST) ||
+ (
+ m_eScript == rDesign.m_eScript &&
+ (
+ m_eScript != SCRIPT_PERL ||
+ (
+ m_aURL == rDesign.m_aURL &&
+ m_aCGI == rDesign.m_aCGI
+ )
+ )
+ )
+ )
+ );
+}
+
+// Load the design from the stream
+SvStream& operator >> (SvStream& rIn, SdPublishingDesign& rDesign)
+{
+ SdIOCompat aIO(rIn, StreamMode::READ);
+
+ sal_uInt16 nTemp16;
+ tools::GenericTypeSerializer aSerializer(rIn);
+
+ rDesign.m_aDesignName = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn,
+ RTL_TEXTENCODING_UTF8);
+ rIn.ReadUInt16( nTemp16 );
+ rDesign.m_eMode = static_cast<HtmlPublishMode>(nTemp16);
+ rIn.ReadCharAsBool( rDesign.m_bContentPage );
+ rIn.ReadCharAsBool( rDesign.m_bNotes );
+ rIn.ReadUInt16( rDesign.m_nResolution );
+ rDesign.m_aCompression = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn,
+ RTL_TEXTENCODING_UTF8);
+ rIn.ReadUInt16( nTemp16 );
+ rDesign.m_eFormat = static_cast<PublishingFormat>(nTemp16);
+ rDesign.m_aAuthor = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn,
+ RTL_TEXTENCODING_UTF8);
+ rDesign.m_aEMail = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn,
+ RTL_TEXTENCODING_UTF8);
+ rDesign.m_aWWW = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn,
+ RTL_TEXTENCODING_UTF8);
+ rDesign.m_aMisc = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn,
+ RTL_TEXTENCODING_UTF8);
+ rIn.ReadCharAsBool( rDesign.m_bDownload );
+ rIn.ReadCharAsBool( rDesign.m_bCreated ); // not used
+ rIn.ReadInt16( rDesign.m_nButtonThema );
+ rIn.ReadCharAsBool( rDesign.m_bUserAttr );
+ aSerializer.readColor(rDesign.m_aBackColor);
+ aSerializer.readColor(rDesign.m_aTextColor);
+ aSerializer.readColor(rDesign.m_aLinkColor);
+ aSerializer.readColor(rDesign.m_aVLinkColor);
+ aSerializer.readColor(rDesign.m_aALinkColor);
+ rIn.ReadCharAsBool( rDesign.m_bUseAttribs );
+ rIn.ReadCharAsBool( rDesign.m_bUseColor );
+
+ rIn.ReadUInt16( nTemp16 );
+ rDesign.m_eScript = static_cast<PublishingScript>(nTemp16);
+ rDesign.m_aURL = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn,
+ RTL_TEXTENCODING_UTF8);
+ rDesign.m_aCGI = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn,
+ RTL_TEXTENCODING_UTF8);
+
+ rIn.ReadCharAsBool( rDesign.m_bAutoSlide );
+ rIn.ReadUInt32( rDesign.m_nSlideDuration );
+ rIn.ReadCharAsBool( rDesign.m_bEndless );
+ rIn.ReadCharAsBool( rDesign.m_bSlideSound );
+ rIn.ReadCharAsBool( rDesign.m_bHiddenSlides );
+
+ return rIn;
+}
+
+// Set the design to the stream
+SvStream& WriteSdPublishingDesign(SvStream& rOut, const SdPublishingDesign& rDesign)
+{
+ // The last parameter is the versionnumber of the code
+ SdIOCompat aIO(rOut, StreamMode::WRITE, 0);
+
+ tools::GenericTypeSerializer aSerializer(rOut);
+
+ // Name
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, rDesign.m_aDesignName,
+ RTL_TEXTENCODING_UTF8);
+
+ rOut.WriteUInt16( rDesign.m_eMode );
+ rOut.WriteBool( rDesign.m_bContentPage );
+ rOut.WriteBool( rDesign.m_bNotes );
+ rOut.WriteUInt16( rDesign.m_nResolution );
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, rDesign.m_aCompression,
+ RTL_TEXTENCODING_UTF8);
+ rOut.WriteUInt16( rDesign.m_eFormat );
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, rDesign.m_aAuthor,
+ RTL_TEXTENCODING_UTF8);
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, rDesign.m_aEMail,
+ RTL_TEXTENCODING_UTF8);
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, rDesign.m_aWWW,
+ RTL_TEXTENCODING_UTF8);
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, rDesign.m_aMisc,
+ RTL_TEXTENCODING_UTF8);
+ rOut.WriteBool( rDesign.m_bDownload );
+ rOut.WriteBool( rDesign.m_bCreated ); // not used
+ rOut.WriteInt16( rDesign.m_nButtonThema );
+ rOut.WriteBool( rDesign.m_bUserAttr );
+ aSerializer.writeColor(rDesign.m_aBackColor);
+ aSerializer.writeColor(rDesign.m_aTextColor);
+ aSerializer.writeColor(rDesign.m_aLinkColor);
+ aSerializer.writeColor(rDesign.m_aVLinkColor);
+ aSerializer.writeColor(rDesign.m_aALinkColor);
+ rOut.WriteBool( rDesign.m_bUseAttribs );
+ rOut.WriteBool( rDesign.m_bUseColor );
+
+ rOut.WriteUInt16( rDesign.m_eScript );
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, rDesign.m_aURL,
+ RTL_TEXTENCODING_UTF8);
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, rDesign.m_aCGI,
+ RTL_TEXTENCODING_UTF8);
+
+ rOut.WriteBool( rDesign.m_bAutoSlide );
+ rOut.WriteUInt32( rDesign.m_nSlideDuration );
+ rOut.WriteBool( rDesign.m_bEndless );
+ rOut.WriteBool( rDesign.m_bSlideSound );
+ rOut.WriteBool( rDesign.m_bHiddenSlides );
+
+ return rOut;
+}
+
+namespace {
+
+// Dialog for the entry of the name of the design
+class SdDesignNameDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::Entry> m_xEdit;
+ std::unique_ptr<weld::Button> m_xBtnOK;
+
+public:
+ SdDesignNameDlg(weld::Window* pWindow, const OUString& aName );
+ OUString GetDesignName() const;
+ DECL_LINK(ModifyHdl, weld::Entry&, void);
+};
+
+}
+
+// SdPublishingDlg Methods
+
+SdPublishingDlg::SdPublishingDlg(weld::Window* pWindow, DocumentType eDocType)
+ : GenericDialogController(pWindow, "modules/simpress/ui/publishingdialog.ui", "PublishingDialog")
+ , m_xPage1_Designs(m_xBuilder->weld_tree_view("designsTreeview"))
+ , m_xPage2_Standard_FB(m_xBuilder->weld_image("standardFBImage"))
+ , m_xPage2_Frames_FB(m_xBuilder->weld_image("framesFBImage"))
+ , m_xPage2_Kiosk_FB(m_xBuilder->weld_image("kioskFBImage"))
+ , m_xPage2_WebCast_FB(m_xBuilder->weld_image("webCastFBImage"))
+ , m_xPage4_Misc(m_xBuilder->weld_text_view("miscTextview"))
+ , m_xButtonSet(new ButtonSet())
+ , m_xLastPageButton(m_xBuilder->weld_button("lastPageButton"))
+ , m_xNextPageButton(m_xBuilder->weld_button("nextPageButton"))
+ , m_xFinishButton(m_xBuilder->weld_button("finishButton"))
+ , aAssistentFunc(NOOFPAGES)
+ , m_bButtonsDirty(true)
+ , m_bDesignListDirty(false)
+ , m_pDesign(nullptr)
+{
+ m_bImpress = eDocType == DocumentType::Impress;
+
+ Size aSize(m_xPage2_Standard_FB->get_approximate_digit_width() * 12,
+ m_xPage2_Standard_FB->get_text_height() * 6);
+ m_xPage2_Standard_FB->set_size_request(aSize.Width(), aSize.Height());
+ m_xPage2_Frames_FB->set_size_request(aSize.Width(), aSize.Height());
+ m_xPage2_Kiosk_FB->set_size_request(aSize.Width(), aSize.Height());
+ m_xPage2_WebCast_FB->set_size_request(aSize.Width(), aSize.Height());
+
+ m_xPage4_Misc->set_size_request(m_xPage4_Misc->get_approximate_digit_width() * 40,
+ m_xPage4_Misc->get_height_rows(8));
+
+ m_xPage1_Designs->set_size_request(m_xPage4_Misc->get_approximate_digit_width() * 40,
+ m_xPage4_Misc->get_height_rows(8));
+
+ //Lock down the preferred size based on the
+ //initial max-size configuration
+ aSize = m_xDialog->get_preferred_size();
+ m_xDialog->set_size_request(aSize.Width(), aSize.Height());
+
+ CreatePages();
+ Load();
+
+ // sets the output page
+ aAssistentFunc.GotoPage(1);
+ m_xLastPageButton->set_sensitive(false);
+
+ // button assignment
+ m_xFinishButton->connect_clicked(LINK(this,SdPublishingDlg,FinishHdl));
+ m_xLastPageButton->connect_clicked(LINK(this,SdPublishingDlg,LastPageHdl));
+ m_xNextPageButton->connect_clicked(LINK(this,SdPublishingDlg,NextPageHdl));
+
+ m_xPage1_NewDesign->connect_toggled(LINK(this,SdPublishingDlg,DesignHdl));
+ m_xPage1_OldDesign->connect_toggled(LINK(this,SdPublishingDlg,DesignHdl));
+ m_xPage1_Designs->connect_changed(LINK(this,SdPublishingDlg,DesignSelectHdl));
+ m_xPage1_DelDesign->connect_clicked(LINK(this,SdPublishingDlg,DesignDeleteHdl));
+
+ m_xPage2_Standard->connect_toggled(LINK(this,SdPublishingDlg,BaseHdl));
+ m_xPage2_Frames->connect_toggled(LINK(this,SdPublishingDlg,BaseHdl));
+ m_xPage2_SingleDocument->connect_toggled(LINK(this,SdPublishingDlg,BaseHdl));
+ m_xPage2_Kiosk->connect_toggled(LINK(this,SdPublishingDlg,BaseHdl));
+ m_xPage2_WebCast->connect_toggled(LINK(this,SdPublishingDlg,BaseHdl));
+
+ m_xPage2_Content->connect_toggled(LINK(this,SdPublishingDlg,ContentHdl));
+
+ m_xPage2_ASP->connect_toggled(LINK(this,SdPublishingDlg,WebServerHdl));
+ m_xPage2_PERL->connect_toggled(LINK(this,SdPublishingDlg,WebServerHdl));
+ m_xPage2_Index->set_text("index" STR_HTMLEXP_DEFAULT_EXTENSION);
+ m_xPage2_CGI->set_text("/cgi-bin/");
+
+ m_xPage3_Png->connect_toggled(LINK(this,SdPublishingDlg, GfxFormatHdl));
+ m_xPage3_Gif->connect_toggled(LINK(this,SdPublishingDlg, GfxFormatHdl));
+ m_xPage3_Jpg->connect_toggled(LINK(this,SdPublishingDlg, GfxFormatHdl));
+ m_xPage3_Quality->set_sensitive(false);
+
+ m_xPage3_Resolution_1->connect_toggled(LINK(this,SdPublishingDlg, ResolutionHdl ));
+ m_xPage3_Resolution_2->connect_toggled(LINK(this,SdPublishingDlg, ResolutionHdl ));
+ m_xPage3_Resolution_3->connect_toggled(LINK(this,SdPublishingDlg, ResolutionHdl ));
+ m_xPage3_Resolution_4->connect_toggled(LINK(this, SdPublishingDlg, ResolutionHdl));
+
+ m_xPage2_ChgDefault->connect_toggled(LINK(this,SdPublishingDlg, SlideChgHdl));
+ m_xPage2_ChgAuto->connect_toggled(LINK(this,SdPublishingDlg, SlideChgHdl));
+
+ m_xPage5_Buttons->SetSelectHdl(LINK(this,SdPublishingDlg, ButtonsHdl ));
+ m_xPage5_Buttons->SetStyle( m_xPage5_Buttons->GetStyle() | WB_VSCROLL );
+
+ m_xPage6_Back->connect_clicked(LINK(this,SdPublishingDlg, ColorHdl ));
+ m_xPage6_Text->connect_clicked(LINK(this,SdPublishingDlg, ColorHdl ));
+ m_xPage6_Link->connect_clicked(LINK(this,SdPublishingDlg, ColorHdl ));
+ m_xPage6_VLink->connect_clicked(LINK(this,SdPublishingDlg, ColorHdl ));
+ m_xPage6_ALink->connect_clicked(LINK(this,SdPublishingDlg, ColorHdl ));
+
+ m_xPage6_DocColors->set_active(true);
+
+ m_xPage3_Quality->append_text( "25%" );
+ m_xPage3_Quality->append_text( "50%" );
+ m_xPage3_Quality->append_text( "75%" );
+ m_xPage3_Quality->append_text( "100%" );
+
+ m_xPage5_Buttons->SetColCount();
+ m_xPage5_Buttons->SetLineCount( 4 );
+ m_xPage5_Buttons->SetExtraSpacing( 1 );
+
+ for( const auto& rDesign : m_aDesignList )
+ m_xPage1_Designs->append_text(rDesign.m_aDesignName);
+
+ SetDefaults();
+
+ m_xDialog->set_help_id(aPageHelpIds[0]);
+
+ m_xNextPageButton->grab_focus();
+}
+
+SdPublishingDlg::~SdPublishingDlg()
+{
+}
+
+// Generate dialog controls and embed them in the pages
+void SdPublishingDlg::CreatePages()
+{
+ // Page 1
+ m_xPage1 = m_xBuilder->weld_container("page1");
+ m_xPage1_Title = m_xBuilder->weld_label("assignLabel");
+ m_xPage1_NewDesign = m_xBuilder->weld_radio_button("newDesignRadiobutton");
+ m_xPage1_OldDesign = m_xBuilder->weld_radio_button("oldDesignRadiobutton");
+ m_xPage1_DelDesign = m_xBuilder->weld_button("delDesingButton");
+ m_xPage1_Desc = m_xBuilder->weld_label("descLabel");
+ aAssistentFunc.InsertControl(1, m_xPage1.get());
+ aAssistentFunc.InsertControl(1, m_xPage1_Title.get());
+ aAssistentFunc.InsertControl(1, m_xPage1_NewDesign.get());
+ aAssistentFunc.InsertControl(1, m_xPage1_OldDesign.get());
+ aAssistentFunc.InsertControl(1, m_xPage1_Designs.get());
+ aAssistentFunc.InsertControl(1, m_xPage1_DelDesign.get());
+ aAssistentFunc.InsertControl(1, m_xPage1_Desc.get());
+
+ // Page 2
+ m_xPage2 = m_xBuilder->weld_container("page2");
+ m_xPage2Frame2 = m_xBuilder->weld_container("page2.2");
+ m_xPage2Frame3 = m_xBuilder->weld_container("page2.3");
+ m_xPage2Frame4 = m_xBuilder->weld_container("page2.4");
+ m_xPage2_Title = m_xBuilder->weld_label("publicationLabel");
+ m_xPage2_Standard = m_xBuilder->weld_radio_button("standardRadiobutton");
+ m_xPage2_Frames = m_xBuilder->weld_radio_button("framesRadiobutton");
+ m_xPage2_SingleDocument = m_xBuilder->weld_radio_button("singleDocumentRadiobutton");
+ m_xPage2_Kiosk = m_xBuilder->weld_radio_button("kioskRadiobutton");
+ m_xPage2_WebCast = m_xBuilder->weld_radio_button("webCastRadiobutton");
+ aAssistentFunc.InsertControl(2, m_xPage2.get());
+ aAssistentFunc.InsertControl(2, m_xPage2Frame2.get());
+ aAssistentFunc.InsertControl(2, m_xPage2Frame3.get());
+ aAssistentFunc.InsertControl(2, m_xPage2Frame4.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Title.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Standard.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Frames.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_SingleDocument.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Kiosk.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_WebCast.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Standard_FB.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Frames_FB.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Kiosk_FB.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_WebCast_FB.get());
+
+ m_xPage2_Title_Html = m_xBuilder->weld_label( "htmlOptionsLabel");
+ m_xPage2_Content = m_xBuilder->weld_check_button("contentCheckbutton");
+ m_xPage2_Notes = m_xBuilder->weld_check_button("notesCheckbutton");
+ aAssistentFunc.InsertControl(2, m_xPage2_Title_Html.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Content.get());
+ if (m_bImpress)
+ aAssistentFunc.InsertControl(2, m_xPage2_Notes.get());
+
+ m_xPage2_Title_WebCast = m_xBuilder->weld_label("webCastLabel");
+ m_xPage2_ASP = m_xBuilder->weld_radio_button("ASPRadiobutton");
+ m_xPage2_PERL = m_xBuilder->weld_radio_button("perlRadiobutton");
+ m_xPage2_URL_txt = m_xBuilder->weld_label("URLTxtLabel");
+ m_xPage2_URL = m_xBuilder->weld_entry("URLEntry");
+ m_xPage2_CGI_txt = m_xBuilder->weld_label("CGITxtLabel");
+ m_xPage2_CGI = m_xBuilder->weld_entry("CGIEntry");
+ m_xPage2_Index_txt = m_xBuilder->weld_label("indexTxtLabel");
+ m_xPage2_Index = m_xBuilder->weld_entry("indexEntry");
+ m_xPage2_Title_Kiosk = m_xBuilder->weld_label("kioskLabel");
+ m_xPage2_ChgDefault = m_xBuilder->weld_radio_button("chgDefaultRadiobutton");
+ m_xPage2_ChgAuto = m_xBuilder->weld_radio_button("chgAutoRadiobutton");
+ m_xPage2_Duration_txt = m_xBuilder->weld_label("durationTxtLabel");
+ m_xPage2_Duration = m_xBuilder->weld_formatted_spin_button("durationSpinbutton");
+ m_xFormatter.reset(new weld::TimeFormatter(*m_xPage2_Duration));
+ m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
+ m_xPage2_Endless = m_xBuilder->weld_check_button("endlessCheckbutton");
+ aAssistentFunc.InsertControl(2, m_xPage2_Title_WebCast.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Index_txt.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Index.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_ASP.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_PERL.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_URL_txt.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_URL.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_CGI_txt.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_CGI.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Title_Kiosk.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_ChgDefault.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_ChgAuto.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Duration_txt.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Duration.get());
+ aAssistentFunc.InsertControl(2, m_xPage2_Endless.get());
+
+ // Page 3
+ m_xPage3 = m_xBuilder->weld_container("page3");
+ m_xPage3_Title1 = m_xBuilder->weld_label("saveImgAsLabel");
+ m_xPage3_Png = m_xBuilder->weld_radio_button("pngRadiobutton");
+ m_xPage3_Gif = m_xBuilder->weld_radio_button("gifRadiobutton");
+ m_xPage3_Jpg = m_xBuilder->weld_radio_button("jpgRadiobutton");
+ m_xPage3_Quality_txt = m_xBuilder->weld_label("qualityTxtLabel");
+ m_xPage3_Quality= m_xBuilder->weld_combo_box("qualityCombobox");
+ m_xPage3_Title2 = m_xBuilder->weld_label("monitorResolutionLabel");
+ m_xPage3_Resolution_1 = m_xBuilder->weld_radio_button("resolution1Radiobutton");
+ m_xPage3_Resolution_2 = m_xBuilder->weld_radio_button("resolution2Radiobutton");
+ m_xPage3_Resolution_3 = m_xBuilder->weld_radio_button("resolution3Radiobutton");
+ m_xPage3_Resolution_4 = m_xBuilder->weld_radio_button("resolution4Radiobutton");
+ m_xPage3_Title3 = m_xBuilder->weld_label("effectsLabel");
+ m_xPage3_SldSound = m_xBuilder->weld_check_button("sldSoundCheckbutton");
+ m_xPage3_HiddenSlides = m_xBuilder->weld_check_button("hiddenSlidesCheckbutton");
+ aAssistentFunc.InsertControl(3, m_xPage3.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Title1.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Png.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Gif.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Jpg.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Quality_txt.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Quality.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Title2.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Resolution_1.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Resolution_2.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Resolution_3.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Resolution_4.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_Title3.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_SldSound.get());
+ aAssistentFunc.InsertControl(3, m_xPage3_HiddenSlides.get());
+
+ // Page 4
+ m_xPage4 = m_xBuilder->weld_container("page4");
+ m_xPage4_Title1 = m_xBuilder->weld_label("infTitlePageLabel");
+ m_xPage4_Author_txt = m_xBuilder->weld_label("authorTxtLabel");
+ m_xPage4_Author = m_xBuilder->weld_entry("authorEntry");
+ m_xPage4_Email_txt = m_xBuilder->weld_label("emailTxtLabel");
+ m_xPage4_Email = m_xBuilder->weld_entry("emailEntry");
+ m_xPage4_WWW_txt = m_xBuilder->weld_label("wwwTxtLabel");
+ m_xPage4_WWW = m_xBuilder->weld_entry("wwwEntry");
+ m_xPage4_Title2 = m_xBuilder->weld_label("addInformLabel");
+ m_xPage4_Download = m_xBuilder->weld_check_button("downloadCheckbutton");
+ aAssistentFunc.InsertControl(4, m_xPage4.get());
+ aAssistentFunc.InsertControl(4, m_xPage4_Title1.get());
+ aAssistentFunc.InsertControl(4, m_xPage4_Author_txt.get());
+ aAssistentFunc.InsertControl(4, m_xPage4_Author.get());
+ aAssistentFunc.InsertControl(4, m_xPage4_Email_txt.get());
+ aAssistentFunc.InsertControl(4, m_xPage4_Email.get());
+ aAssistentFunc.InsertControl(4, m_xPage4_WWW_txt.get());
+ aAssistentFunc.InsertControl(4, m_xPage4_WWW.get());
+ aAssistentFunc.InsertControl(4, m_xPage4_Title2.get());
+ aAssistentFunc.InsertControl(4, m_xPage4_Misc.get());
+ if(m_bImpress)
+ aAssistentFunc.InsertControl(4, m_xPage4_Download.get());
+
+ // Page 5
+ m_xPage5 = m_xBuilder->weld_container("page5");
+ m_xPage5_Title = m_xBuilder->weld_label("buttonStyleLabel");
+ m_xPage5_TextOnly = m_xBuilder->weld_check_button("textOnlyCheckbutton");
+ m_xPage5_Buttons.reset(new ValueSet(m_xBuilder->weld_scrolled_window("buttonsDrawingareawin", true)));
+ m_xPage5_ButtonsWnd.reset(new weld::CustomWeld(*m_xBuilder, "buttonsDrawingarea", *m_xPage5_Buttons));
+ aAssistentFunc.InsertControl(5, m_xPage5.get());
+ aAssistentFunc.InsertControl(5, m_xPage5_Title.get());
+ aAssistentFunc.InsertControl(5, m_xPage5_TextOnly.get());
+ aAssistentFunc.InsertControl(5, m_xPage5_Buttons->GetDrawingArea());
+
+ // Page 6
+ m_xPage6 = m_xBuilder->weld_container("page6");
+ m_xPage6_Title = m_xBuilder->weld_label("selectColorLabel");
+ m_xPage6_Default = m_xBuilder->weld_radio_button("defaultRadiobutton");
+ m_xPage6_User = m_xBuilder->weld_radio_button("userRadiobutton");
+ m_xPage6_Back = m_xBuilder->weld_button("backButton");
+ m_xPage6_Text = m_xBuilder->weld_button("textButton");
+ m_xPage6_Link = m_xBuilder->weld_button("linkButton");
+ m_xPage6_VLink = m_xBuilder->weld_button("vLinkButton");
+ m_xPage6_ALink = m_xBuilder->weld_button("aLinkButton");
+ m_xPage6_DocColors = m_xBuilder->weld_radio_button("docColorsRadiobutton");
+ m_xPage6_Preview.reset(new SdHtmlAttrPreview);
+ m_xPage6_PreviewWnd.reset(new weld::CustomWeld(*m_xBuilder, "previewDrawingarea", *m_xPage6_Preview));
+ aAssistentFunc.InsertControl(6, m_xPage6.get());
+ aAssistentFunc.InsertControl(6, m_xPage6_Title.get());
+ aAssistentFunc.InsertControl(6, m_xPage6_DocColors.get());
+ aAssistentFunc.InsertControl(6, m_xPage6_Default.get());
+ aAssistentFunc.InsertControl(6, m_xPage6_User.get());
+ aAssistentFunc.InsertControl(6, m_xPage6_Text.get());
+ aAssistentFunc.InsertControl(6, m_xPage6_Link.get());
+ aAssistentFunc.InsertControl(6, m_xPage6_ALink.get());
+ aAssistentFunc.InsertControl(6, m_xPage6_VLink.get());
+ aAssistentFunc.InsertControl(6, m_xPage6_Back.get());
+ aAssistentFunc.InsertControl(6, m_xPage6_Preview->GetDrawingArea());
+}
+
+// Initialize dialog with default-values
+void SdPublishingDlg::SetDefaults()
+{
+ SdPublishingDesign aDefault;
+ SetDesign(&aDefault);
+
+ m_xPage1_NewDesign->set_active(true);
+ m_xPage1_OldDesign->set_active(false);
+ UpdatePage();
+}
+
+// Feed the SfxItemSet with the settings of the dialog
+void SdPublishingDlg::GetParameterSequence( Sequence< PropertyValue >& rParams )
+{
+ std::vector< PropertyValue > aProps;
+
+ PropertyValue aValue;
+
+ // Page 2
+ aValue.Name = "PublishMode";
+
+ HtmlPublishMode ePublishMode;
+ if (m_xPage2_Frames->get_active())
+ ePublishMode = PUBLISH_FRAMES;
+ else if (m_xPage2_SingleDocument->get_active())
+ ePublishMode = PUBLISH_SINGLE_DOCUMENT;
+ else if (m_xPage2_Kiosk->get_active())
+ ePublishMode = PUBLISH_KIOSK;
+ else if (m_xPage2_WebCast->get_active())
+ ePublishMode = PUBLISH_WEBCAST;
+ else
+ ePublishMode = PUBLISH_HTML;
+
+ aValue.Value <<= static_cast<sal_Int32>(ePublishMode);
+ aProps.push_back( aValue );
+
+ aValue.Name = "IsExportContentsPage";
+ aValue.Value <<= m_xPage2_Content->get_active();
+ aProps.push_back( aValue );
+
+ if(m_bImpress)
+ {
+ aValue.Name = "IsExportNotes";
+ aValue.Value <<= m_xPage2_Notes->get_active();
+ aProps.push_back( aValue );
+ }
+
+ if( m_xPage2_WebCast->get_active() )
+ {
+ aValue.Name = "WebCastScriptLanguage";
+ if( m_xPage2_ASP->get_active() )
+ aValue.Value <<= OUString( "asp" );
+ else
+ aValue.Value <<= OUString( "perl" );
+ aProps.push_back( aValue );
+
+ aValue.Name = "WebCastCGIURL";
+ aValue.Value <<= m_xPage2_CGI->get_text();
+ aProps.push_back( aValue );
+
+ aValue.Name = "WebCastTargetURL";
+ aValue.Value <<= m_xPage2_URL->get_text();
+ aProps.push_back( aValue );
+ }
+ aValue.Name = "IndexURL";
+ aValue.Value <<= m_xPage2_Index->get_text();
+ aProps.push_back( aValue );
+
+ if( m_xPage2_Kiosk->get_active() && m_xPage2_ChgAuto->get_active() )
+ {
+ aValue.Name = "KioskSlideDuration";
+ aValue.Value <<= static_cast<sal_uInt32>(m_xFormatter->GetTime().GetMSFromTime()) / 1000;
+ aProps.push_back( aValue );
+
+ aValue.Name = "KioskEndless";
+ aValue.Value <<= m_xPage2_Endless->get_active();
+ aProps.push_back( aValue );
+ }
+
+ // Page 3
+
+ aValue.Name = "Width";
+ sal_Int32 nTmpWidth = PUB_LOWRES_WIDTH;
+ if( m_xPage3_Resolution_2->get_active() )
+ nTmpWidth = PUB_MEDRES_WIDTH;
+ else if( m_xPage3_Resolution_3->get_active() )
+ nTmpWidth = PUB_HIGHRES_WIDTH;
+ else if (m_xPage3_Resolution_4->get_active())
+ nTmpWidth = PUB_FHDRES_WIDTH;
+
+ aValue.Value <<= nTmpWidth;
+ aProps.push_back( aValue );
+
+ aValue.Name = "Compression";
+ aValue.Value <<= m_xPage3_Quality->get_active_text();
+ aProps.push_back( aValue );
+
+ aValue.Name = "Format";
+ sal_Int32 nFormat;
+ if( m_xPage3_Png->get_active() )
+ nFormat = static_cast<sal_Int32>(FORMAT_PNG);
+ else if( m_xPage3_Gif->get_active() )
+ nFormat = static_cast<sal_Int32>(FORMAT_GIF);
+ else
+ nFormat = static_cast<sal_Int32>(FORMAT_JPG);
+ aValue.Value <<= nFormat;
+ aProps.push_back( aValue );
+
+ aValue.Name = "SlideSound";
+ aValue.Value <<= m_xPage3_SldSound->get_active();
+ aProps.push_back( aValue );
+
+ aValue.Name = "HiddenSlides";
+ aValue.Value <<= m_xPage3_HiddenSlides->get_active();
+ aProps.push_back( aValue );
+
+ // Page 4
+ aValue.Name = "Author";
+ aValue.Value <<= m_xPage4_Author->get_text();
+ aProps.push_back( aValue );
+
+ aValue.Name = "EMail";
+ aValue.Value <<= m_xPage4_Email->get_text();
+ aProps.push_back( aValue );
+
+ // try to guess protocol for user's homepage
+ INetURLObject aHomeURL( m_xPage4_WWW->get_text(),
+ INetProtocol::Http, // default proto is HTTP
+ INetURLObject::EncodeMechanism::All );
+
+ aValue.Name = "HomepageURL";
+ aValue.Value <<= aHomeURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ aProps.push_back( aValue );
+
+ aValue.Name = "UserText";
+ aValue.Value <<= m_xPage4_Misc->get_text();
+ aProps.push_back( aValue );
+
+ if( m_bImpress )
+ {
+ aValue.Name = "EnableDownload";
+ aValue.Value <<= m_xPage4_Download->get_active();
+ aProps.push_back( aValue );
+ }
+
+ // Page 5
+ if( !m_xPage5_TextOnly->get_active() )
+ {
+ aValue.Name = "UseButtonSet";
+ aValue.Value <<= static_cast<sal_Int32>(m_xPage5_Buttons->GetSelectedItemId() - 1);
+ aProps.push_back( aValue );
+ }
+
+ // Page 6
+ if( m_xPage6_User->get_active() )
+ {
+ aValue.Name = "BackColor";
+ aValue.Value <<= m_aBackColor;
+ aProps.push_back( aValue );
+
+ aValue.Name = "TextColor";
+ aValue.Value <<= m_aTextColor;
+ aProps.push_back( aValue );
+
+ aValue.Name = "LinkColor";
+ aValue.Value <<= m_aLinkColor;
+ aProps.push_back( aValue );
+
+ aValue.Name = "VLinkColor";
+ aValue.Value <<= m_aVLinkColor;
+ aProps.push_back( aValue );
+
+ aValue.Name = "ALinkColor";
+ aValue.Value <<= m_aALinkColor;
+ aProps.push_back( aValue );
+ }
+
+ if( m_xPage6_DocColors->get_active() )
+ {
+ aValue.Name = "IsUseDocumentColors";
+ aValue.Value <<= true;
+ aProps.push_back( aValue );
+ }
+
+ rParams = comphelper::containerToSequence(aProps);
+}
+
+// Clickhandler for the radiobuttons of the design-selection
+IMPL_LINK( SdPublishingDlg, DesignHdl, weld::Toggleable&, rButton, void )
+{
+ if (!rButton.get_active())
+ return;
+
+ if (m_xPage1_NewDesign->get_active())
+ {
+ m_xPage1_NewDesign->set_active(true); // because of DesignDeleteHdl
+ m_xPage1_OldDesign->set_active(false);
+ m_xPage1_Designs->set_sensitive(false);
+ m_xPage1_DelDesign->set_sensitive(false);
+ m_pDesign = nullptr;
+
+ SdPublishingDesign aDefault;
+ SetDesign(&aDefault);
+ }
+ else
+ {
+ m_xPage1_NewDesign->set_active(false);
+ m_xPage1_Designs->set_sensitive(true);
+ m_xPage1_DelDesign->set_sensitive(true);
+
+ if (m_xPage1_Designs->get_selected_index() == -1)
+ m_xPage1_Designs->select(0);
+
+ const sal_Int32 nPos = m_xPage1_Designs->get_selected_index();
+ m_pDesign = &m_aDesignList[nPos];
+ DBG_ASSERT(m_pDesign, "No Design? That's not allowed (CL)");
+
+ if(m_pDesign)
+ SetDesign(m_pDesign);
+ }
+}
+
+// Clickhandler for the choice of one design
+IMPL_LINK_NOARG(SdPublishingDlg, DesignSelectHdl, weld::TreeView&, void)
+{
+ const sal_Int32 nPos = m_xPage1_Designs->get_selected_index();
+ m_pDesign = &m_aDesignList[nPos];
+ DBG_ASSERT(m_pDesign, "No Design? That's not allowed (CL)");
+
+ if(m_pDesign)
+ SetDesign(m_pDesign);
+
+ UpdatePage();
+}
+
+// Clickhandler for the delete of one design
+IMPL_LINK_NOARG(SdPublishingDlg, DesignDeleteHdl, weld::Button&, void)
+{
+ const sal_Int32 nPos = m_xPage1_Designs->get_selected_index();
+
+ std::vector<SdPublishingDesign>::iterator iter = m_aDesignList.begin()+nPos;
+
+ DBG_ASSERT(iter != m_aDesignList.end(), "No Design? That's not allowed (CL)");
+
+ m_xPage1_Designs->remove(nPos);
+
+ if(m_pDesign == &(*iter))
+ DesignHdl(*m_xPage1_NewDesign);
+
+ m_aDesignList.erase(iter);
+
+ m_bDesignListDirty = true;
+
+ UpdatePage();
+}
+
+// Clickhandler for the other servertypes
+IMPL_LINK(SdPublishingDlg, WebServerHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+
+ bool bASP = m_xPage2_ASP->get_active();
+ m_xPage2_ASP->set_sensitive( bASP );
+ m_xPage2_PERL->set_sensitive( !bASP );
+ UpdatePage();
+}
+
+// Clickhandler for the Radiobuttons of the graphicformat choice
+IMPL_LINK(SdPublishingDlg, GfxFormatHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+
+ m_xPage3_Png->set_sensitive(m_xPage3_Png->get_active());
+ m_xPage3_Gif->set_sensitive(m_xPage3_Gif->get_active());
+ m_xPage3_Jpg->set_sensitive(m_xPage3_Jpg->get_active());
+ m_xPage3_Quality->set_sensitive(m_xPage3_Jpg->get_active());
+}
+
+// Clickhandler for the Radiobuttons Standard/Frames
+IMPL_LINK(SdPublishingDlg, BaseHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+
+ UpdatePage();
+}
+
+// Clickhandler for the Checkbox of the Title page
+IMPL_LINK_NOARG(SdPublishingDlg, ContentHdl, weld::Toggleable&, void)
+{
+ if(m_xPage2_Content->get_active())
+ {
+ if(!aAssistentFunc.IsEnabled(4))
+ {
+ aAssistentFunc.EnablePage(4);
+ UpdatePage();
+ }
+ }
+ else
+ {
+ if(aAssistentFunc.IsEnabled(4))
+ {
+ aAssistentFunc.DisablePage(4);
+ UpdatePage();
+ }
+ }
+}
+
+// Clickhandler for the Resolution Radiobuttons
+IMPL_LINK( SdPublishingDlg, ResolutionHdl, weld::Toggleable&, rButton, void )
+{
+ if (!rButton.get_active())
+ return;
+ m_xPage3_Resolution_1->set_sensitive(m_xPage3_Resolution_1->get_active());
+ m_xPage3_Resolution_2->set_sensitive(m_xPage3_Resolution_2->get_active());
+ m_xPage3_Resolution_3->set_sensitive(m_xPage3_Resolution_3->get_active());
+ m_xPage3_Resolution_4->set_sensitive(m_xPage3_Resolution_4->get_active());
+}
+
+// Clickhandler for the ValueSet with the bitmap-buttons
+IMPL_LINK_NOARG(SdPublishingDlg, ButtonsHdl, ValueSet*, void)
+{
+ // if one bitmap-button is chosen, then disable TextOnly
+ m_xPage5_TextOnly->set_active(false);
+}
+
+// Fill the SfxItemSet with the settings of the dialog
+IMPL_LINK( SdPublishingDlg, ColorHdl, weld::Button&, rButton, void)
+{
+ SvColorDialog aDlg;
+
+ if (&rButton == m_xPage6_Back.get())
+ {
+ aDlg.SetColor( m_aBackColor );
+ if(aDlg.Execute(m_xDialog.get()) == RET_OK )
+ m_aBackColor = aDlg.GetColor();
+ }
+ else if (&rButton == m_xPage6_Text.get())
+ {
+ aDlg.SetColor( m_aTextColor );
+ if(aDlg.Execute(m_xDialog.get()) == RET_OK )
+ m_aTextColor = aDlg.GetColor();
+ }
+ else if (&rButton == m_xPage6_Link.get())
+ {
+ aDlg.SetColor( m_aLinkColor );
+ if(aDlg.Execute(m_xDialog.get()) == RET_OK )
+ m_aLinkColor = aDlg.GetColor();
+ }
+ else if (&rButton == m_xPage6_VLink.get())
+ {
+ aDlg.SetColor( m_aVLinkColor );
+ if(aDlg.Execute(m_xDialog.get()) == RET_OK )
+ m_aVLinkColor = aDlg.GetColor();
+ }
+ else if (&rButton == m_xPage6_ALink.get())
+ {
+ aDlg.SetColor( m_aALinkColor );
+ if(aDlg.Execute(m_xDialog.get()) == RET_OK )
+ m_aALinkColor = aDlg.GetColor();
+ }
+
+ m_xPage6_User->set_active(true);
+ m_xPage6_Preview->SetColors( m_aBackColor, m_aTextColor, m_aLinkColor,
+ m_aVLinkColor, m_aALinkColor );
+ m_xPage6_Preview->Invalidate();
+}
+
+IMPL_LINK(SdPublishingDlg, SlideChgHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+ UpdatePage();
+}
+
+// Clickhandler for the Ok Button
+IMPL_LINK_NOARG(SdPublishingDlg, FinishHdl, weld::Button&, void)
+{
+ //End
+ SdPublishingDesign aDesign;
+ GetDesign(&aDesign);
+
+ bool bSave = false;
+
+ if(m_xPage1_OldDesign->get_active() && m_pDesign)
+ {
+ // are there changes?
+ if(!(aDesign == *m_pDesign))
+ bSave = true;
+ }
+ else
+ {
+ SdPublishingDesign aDefaultDesign;
+ if(!(aDefaultDesign == aDesign))
+ bSave = true;
+ }
+
+ if(bSave)
+ {
+ OUString aName;
+ if(m_pDesign)
+ aName = m_pDesign->m_aDesignName;
+
+ bool bRetry;
+ do
+ {
+ bRetry = false;
+
+ SdDesignNameDlg aDlg(m_xDialog.get(), aName);
+
+ if (aDlg.run() == RET_OK)
+ {
+ aDesign.m_aDesignName = aDlg.GetDesignName();
+
+ auto iter = std::find_if(m_aDesignList.begin(), m_aDesignList.end(),
+ [&aDesign](const SdPublishingDesign& rDesign) { return rDesign.m_aDesignName == aDesign.m_aDesignName; });
+
+ if (iter != m_aDesignList.end())
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Error, VclButtonsType::YesNo,
+ SdResId(STR_PUBDLG_SAMENAME)));
+ bRetry = xErrorBox->run() == RET_NO;
+
+ if(!bRetry)
+ m_aDesignList.erase(iter);
+ }
+
+ if(!bRetry)
+ {
+ m_aDesignList.push_back(aDesign);
+ m_bDesignListDirty = true;
+ }
+ }
+ }
+ while(bRetry);
+ }
+
+ if(m_bDesignListDirty)
+ Save();
+
+ m_xDialog->response(RET_OK);
+}
+
+// Refresh the dialogs when changing from pages
+void SdPublishingDlg::ChangePage()
+{
+ int nPage = aAssistentFunc.GetCurrentPage();
+ m_xDialog->set_help_id(aPageHelpIds[nPage-1]);
+
+ UpdatePage();
+
+ if (m_xNextPageButton->get_sensitive())
+ m_xNextPageButton->grab_focus();
+ else
+ m_xFinishButton->grab_focus();
+}
+
+void SdPublishingDlg::UpdatePage()
+{
+ m_xNextPageButton->set_sensitive(!aAssistentFunc.IsLastPage());
+ m_xLastPageButton->set_sensitive(!aAssistentFunc.IsFirstPage());
+
+ int nPage = aAssistentFunc.GetCurrentPage();
+
+ switch( nPage )
+ {
+ case 1:
+ if(m_xPage1_NewDesign->get_active())
+ {
+ m_xPage1_Designs->set_sensitive(false);
+ m_xPage1_DelDesign->set_sensitive(false);
+ }
+
+ if(m_aDesignList.empty())
+ m_xPage1_OldDesign->set_sensitive(false);
+ break;
+ case 2:
+ m_xPage2_Frames_FB->set_visible(m_xPage2_Frames->get_active());
+ m_xPage2_Standard_FB->set_visible(m_xPage2_Standard->get_active());
+ m_xPage2_Kiosk_FB->set_visible(m_xPage2_Kiosk->get_active());
+ m_xPage2_WebCast_FB->set_visible(m_xPage2_WebCast->get_active());
+
+ if( m_xPage2_WebCast->get_active() )
+ {
+ m_xPage2Frame4->show();
+ m_xPage2_Title_WebCast->show();
+ m_xPage2_ASP->show();
+ m_xPage2_PERL->show();
+ m_xPage2_URL_txt->show();
+ m_xPage2_URL->show();
+ m_xPage2_CGI_txt->show();
+ m_xPage2_CGI->show();
+ m_xPage2_Index_txt->show();
+ m_xPage2_Index->show();
+
+ bool bPerl = m_xPage2_PERL->get_active();
+ m_xPage2_Index->set_sensitive(bPerl);
+ m_xPage2_Index_txt->set_sensitive(bPerl);
+ m_xPage2_URL_txt->set_sensitive(bPerl);
+ m_xPage2_URL->set_sensitive(bPerl);
+ m_xPage2_CGI_txt->set_sensitive(bPerl);
+ m_xPage2_CGI->set_sensitive(bPerl);
+ }
+ else
+ {
+ m_xPage2Frame4->hide();
+ m_xPage2_Title_WebCast->hide();
+ m_xPage2_ASP->hide();
+ m_xPage2_PERL->hide();
+ m_xPage2_URL_txt->hide();
+ m_xPage2_URL->hide();
+ m_xPage2_CGI_txt->hide();
+ m_xPage2_CGI->hide();
+ m_xPage2_Index->hide();
+ m_xPage2_Index_txt->hide();
+ }
+
+ if( m_xPage2_Kiosk->get_active() )
+ {
+ m_xPage2Frame3->show();
+ m_xPage2_Title_Kiosk->show();
+ m_xPage2_ChgDefault->show();
+ m_xPage2_ChgAuto->show();
+ m_xPage2_Duration_txt->show();
+ m_xPage2_Duration->show();
+ m_xPage2_Endless->show();
+ bool bAuto = m_xPage2_ChgAuto->get_active();
+ m_xPage2_Duration->set_sensitive(bAuto);
+ m_xPage2_Endless->set_sensitive(bAuto);
+ }
+ else
+ {
+ m_xPage2Frame3->hide();
+ m_xPage2_Title_Kiosk->hide();
+ m_xPage2_ChgDefault->hide();
+ m_xPage2_ChgAuto->hide();
+ m_xPage2_Duration->hide();
+ m_xPage2_Duration_txt->hide();
+ m_xPage2_Endless->hide();
+ }
+
+ if( m_xPage2_Standard->get_active() || m_xPage2_Frames->get_active() )
+ {
+ m_xPage2Frame2->show();
+ m_xPage2_Title_Html->show();
+ m_xPage2_Content->show();
+ if(m_bImpress)
+ m_xPage2_Notes->show();
+ }
+ else
+ {
+ m_xPage2Frame2->hide();
+ m_xPage2_Title_Html->hide();
+ m_xPage2_Content->hide();
+ if(m_bImpress)
+ m_xPage2_Notes->hide();
+ }
+ break;
+ case 3:
+ if( m_xPage2_Kiosk->get_active() || m_xPage2_WebCast->get_active() )
+ m_xNextPageButton->set_sensitive(false);
+
+ if( m_xPage2_WebCast->get_active() )
+ m_xPage3_SldSound->set_sensitive(false);
+
+ m_xPage3_Quality->set_sensitive(m_xPage3_Jpg->get_active());
+
+ break;
+ case 5:
+ if( m_bButtonsDirty )
+ LoadPreviewButtons();
+ break;
+ }
+}
+
+/** loads the html buttons from the button sets, creates a preview and fills the
+ itemset for page 5
+ */
+void SdPublishingDlg::LoadPreviewButtons()
+{
+ if (!m_xButtonSet)
+ return;
+
+ const int nButtonCount = 8;
+ static const char *pButtonNames[nButtonCount] =
+ {
+ "first.png",
+ "left.png",
+ "right.png",
+ "last.png",
+ "home.png",
+ "text.png",
+ "expand.png",
+ "collapse.png",
+ };
+
+ std::vector< OUString > aButtonNames;
+ for(const char * p : pButtonNames)
+ aButtonNames.push_back( OUString::createFromAscii( p ) );
+
+ int nSetCount = m_xButtonSet->getCount();
+
+ int nHeight = 32;
+ Image aImage;
+ for( int nSet = 0; nSet < nSetCount; ++nSet )
+ {
+ if( m_xButtonSet->getPreview( nSet, aButtonNames, aImage ) )
+ {
+ m_xPage5_Buttons->InsertItem( static_cast<sal_uInt16>(nSet)+1, aImage );
+ if( nHeight < aImage.GetSizePixel().Height() )
+ nHeight = aImage.GetSizePixel().Height();
+ }
+ }
+
+ m_xPage5_Buttons->SetItemHeight( nHeight );
+ m_bButtonsDirty = false;
+}
+
+// Clickhandler for the Forward Button
+IMPL_LINK_NOARG(SdPublishingDlg, NextPageHdl, weld::Button&, void)
+{
+ aAssistentFunc.NextPage();
+ ChangePage();
+}
+
+// Sets the Controls in the dialog to the settings in the design
+void SdPublishingDlg::SetDesign( SdPublishingDesign const * pDesign )
+{
+ if(!pDesign)
+ return;
+
+ m_xPage2_Standard->set_sensitive(pDesign->m_eMode == PUBLISH_HTML);
+ m_xPage2_Frames->set_sensitive(pDesign->m_eMode == PUBLISH_FRAMES);
+ m_xPage2_Kiosk->set_sensitive(pDesign->m_eMode == PUBLISH_KIOSK );
+ m_xPage2_WebCast->set_sensitive(pDesign->m_eMode == PUBLISH_WEBCAST );
+
+ m_xPage2_Content->set_sensitive(pDesign->m_bContentPage);
+ if(pDesign->m_bContentPage)
+ aAssistentFunc.EnablePage(4);
+ else
+ aAssistentFunc.DisablePage(4);
+
+ if(m_bImpress)
+ m_xPage2_Notes->set_sensitive(pDesign->m_bNotes);
+
+ m_xPage2_ASP->set_sensitive(pDesign->m_eScript == SCRIPT_ASP);
+ m_xPage2_PERL->set_sensitive(pDesign->m_eScript == SCRIPT_PERL);
+ m_xPage2_CGI->set_text(pDesign->m_aCGI);
+ m_xPage2_URL->set_text(pDesign->m_aURL);
+
+ m_xPage2_ChgDefault->set_sensitive( !pDesign->m_bAutoSlide );
+ m_xPage2_ChgAuto->set_sensitive( pDesign->m_bAutoSlide );
+
+ tools::Time aTime( tools::Time::EMPTY );
+ aTime.MakeTimeFromMS( pDesign->m_nSlideDuration * 1000 );
+ m_xFormatter->SetTime(aTime);
+
+ m_xPage2_Endless->set_sensitive( pDesign->m_bEndless );
+
+ m_xPage3_Png->set_sensitive(pDesign->m_eFormat == FORMAT_PNG);
+ m_xPage3_Gif->set_sensitive(pDesign->m_eFormat == FORMAT_GIF);
+ m_xPage3_Jpg->set_sensitive(pDesign->m_eFormat == FORMAT_JPG);
+ m_xPage3_Quality->set_sensitive(pDesign->m_eFormat == FORMAT_JPG);
+
+ m_xPage3_Quality->set_entry_text(pDesign->m_aCompression);
+ m_xPage3_Resolution_1->set_sensitive(pDesign->m_nResolution == PUB_LOWRES_WIDTH);
+ m_xPage3_Resolution_2->set_sensitive(pDesign->m_nResolution == PUB_MEDRES_WIDTH);
+ m_xPage3_Resolution_3->set_sensitive(pDesign->m_nResolution == PUB_HIGHRES_WIDTH);
+ m_xPage3_Resolution_4->set_sensitive(pDesign->m_nResolution == PUB_FHDRES_WIDTH);
+
+ m_xPage3_SldSound->set_sensitive( pDesign->m_bSlideSound );
+ m_xPage3_HiddenSlides->set_sensitive( pDesign->m_bHiddenSlides );
+
+ m_xPage4_Author->set_text(pDesign->m_aAuthor);
+ m_xPage4_Email->set_text(pDesign->m_aEMail);
+ m_xPage4_WWW->set_text(pDesign->m_aWWW);
+ m_xPage4_Misc->set_text(pDesign->m_aMisc);
+ if(m_bImpress)
+ m_xPage4_Download->set_sensitive(pDesign->m_bDownload);
+
+ m_xPage5_TextOnly->set_sensitive(pDesign->m_nButtonThema == -1);
+ if(pDesign->m_nButtonThema != -1)
+ {
+ if(m_bButtonsDirty)
+ LoadPreviewButtons();
+ m_xPage5_Buttons->SelectItem(pDesign->m_nButtonThema + 1);
+ }
+ else
+ m_xPage5_Buttons->SetNoSelection();
+
+ m_xPage6_User->set_sensitive(pDesign->m_bUserAttr);
+ m_aBackColor = pDesign->m_aBackColor;
+ m_aTextColor = pDesign->m_aTextColor;
+ m_aLinkColor = pDesign->m_aLinkColor;
+ m_aVLinkColor = pDesign->m_aVLinkColor;
+ m_aALinkColor = pDesign->m_aALinkColor;
+
+ m_xPage6_DocColors->set_sensitive(pDesign->m_bUseColor);
+
+ m_xPage6_Preview->SetColors( m_aBackColor, m_aTextColor, m_aLinkColor,
+ m_aVLinkColor, m_aALinkColor );
+ m_xPage6_Preview->Invalidate();
+
+ UpdatePage();
+}
+
+// Transfer the status of the Design Dialog Controls
+void SdPublishingDlg::GetDesign( SdPublishingDesign* pDesign )
+{
+ if(!pDesign)
+ return;
+
+ pDesign->m_eMode = m_xPage2_Standard->get_active()?PUBLISH_HTML:
+ m_xPage2_Frames->get_active()?PUBLISH_FRAMES:
+ m_xPage2_Kiosk->get_active()?PUBLISH_KIOSK:
+ PUBLISH_WEBCAST;
+
+ pDesign->m_bContentPage = m_xPage2_Content->get_active();
+ if(m_bImpress)
+ pDesign->m_bNotes = m_xPage2_Notes->get_active();
+
+ if( m_xPage3_Gif->get_active() )
+ pDesign->m_eFormat = FORMAT_GIF;
+ else if( m_xPage3_Jpg->get_active() )
+ pDesign->m_eFormat = FORMAT_JPG;
+ else
+ pDesign->m_eFormat = FORMAT_PNG;
+
+ pDesign->m_aCompression = m_xPage3_Quality->get_active_text();
+
+ if (m_xPage3_Resolution_1->get_active())
+ pDesign->m_nResolution = PUB_LOWRES_WIDTH;
+ else if (m_xPage3_Resolution_2->get_active())
+ pDesign->m_nResolution = PUB_MEDRES_WIDTH;
+ else if (m_xPage3_Resolution_3->get_active())
+ pDesign->m_nResolution = PUB_HIGHRES_WIDTH;
+ else
+ pDesign->m_nResolution = PUB_FHDRES_WIDTH;
+
+ pDesign->m_bSlideSound = m_xPage3_SldSound->get_active();
+ pDesign->m_bHiddenSlides = m_xPage3_HiddenSlides->get_active();
+
+ pDesign->m_aAuthor = m_xPage4_Author->get_text();
+ pDesign->m_aEMail = m_xPage4_Email->get_text();
+ pDesign->m_aWWW = m_xPage4_WWW->get_text();
+ pDesign->m_aMisc = m_xPage4_Misc->get_text();
+ pDesign->m_bDownload = m_bImpress && m_xPage4_Download->get_active();
+
+ if(m_xPage5_TextOnly->get_active())
+ pDesign->m_nButtonThema = -1;
+ else
+ pDesign->m_nButtonThema = m_xPage5_Buttons->GetSelectedItemId() - 1;
+
+ pDesign->m_bUserAttr = m_xPage6_User->get_active();
+ pDesign->m_aBackColor = m_aBackColor;
+ pDesign->m_aTextColor = m_aTextColor;
+ pDesign->m_aLinkColor = m_aLinkColor;
+ pDesign->m_aVLinkColor = m_aVLinkColor;
+ pDesign->m_aALinkColor = m_aALinkColor;
+ pDesign->m_bUseColor = m_xPage6_DocColors->get_active();
+
+ pDesign->m_eScript = m_xPage2_ASP->get_active()?SCRIPT_ASP:SCRIPT_PERL;
+ pDesign->m_aCGI = m_xPage2_CGI->get_text();
+ pDesign->m_aURL = m_xPage2_URL->get_text();
+
+ pDesign->m_bAutoSlide = m_xPage2_ChgAuto->get_active();
+ pDesign->m_nSlideDuration = static_cast<sal_uInt32>(m_xFormatter->GetTime().GetMSFromTime()) / 1000;
+ pDesign->m_bEndless = m_xPage2_Endless->get_active();
+}
+
+// Clickhandler for the back Button
+IMPL_LINK_NOARG(SdPublishingDlg, LastPageHdl, weld::Button&, void)
+{
+ aAssistentFunc.PreviousPage();
+ ChangePage();
+}
+
+// Load Designs
+void SdPublishingDlg::Load()
+{
+ m_bDesignListDirty = false;
+
+ INetURLObject aURL( SvtPathOptions().GetUserConfigPath() );
+ aURL.Append( u"designs.sod" );
+
+ // check if file exists, SfxMedium shows an errorbox else
+ {
+ std::unique_ptr<SvStream> pIStm = ::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ );
+
+ bool bOk = pIStm && ( pIStm->GetError() == ERRCODE_NONE);
+
+ if( !bOk )
+ return;
+ }
+
+ SfxMedium aMedium( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ | StreamMode::NOCREATE );
+
+ SvStream* pStream = aMedium.GetInStream();
+
+ if( !pStream )
+ return;
+
+ sal_uInt16 aCheck;
+ pStream->ReadUInt16( aCheck );
+
+ if(aCheck != nMagic)
+ return;
+
+ SdIOCompat aIO(*pStream, StreamMode::READ);
+
+ sal_uInt16 nDesigns(0);
+ pStream->ReadUInt16(nDesigns);
+
+ // there has to at least be a sal_uInt16 header in each design
+ const size_t nMaxRecords = pStream->remainingSize() / sizeof(sal_uInt16);
+ if (nDesigns > nMaxRecords)
+ {
+ SAL_WARN("sd", "Parsing error: " << nMaxRecords <<
+ " max possible entries, but " << nDesigns << " claimed, truncating");
+ nDesigns = nMaxRecords;
+ }
+
+ for( sal_uInt16 nIndex = 0;
+ pStream->GetError() == ERRCODE_NONE && nIndex < nDesigns;
+ nIndex++ )
+ {
+ SdPublishingDesign aDesign;
+ *pStream >> aDesign;
+
+ m_aDesignList.push_back(aDesign);
+ }
+}
+
+// Save Designs
+bool SdPublishingDlg::Save()
+{
+ INetURLObject aURL( SvtPathOptions().GetUserConfigPath() );
+ aURL.Append( u"designs.sod" );
+ SfxMedium aMedium( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::TRUNC );
+
+ SvStream* pStream = aMedium.GetOutStream();
+
+ if( !pStream )
+ return false;
+
+ pStream->WriteUInt16( nMagic );
+
+ // Destroys the SdIOCompat before the Stream is being distributed
+ {
+ SdIOCompat aIO(*pStream, StreamMode::WRITE, 0);
+
+ sal_uInt16 nDesigns = static_cast<sal_uInt16>(m_aDesignList.size());
+ pStream->WriteUInt16( nDesigns );
+
+ for( sal_uInt16 nIndex = 0;
+ pStream->GetError() == ERRCODE_NONE && nIndex < nDesigns;
+ nIndex++ )
+ WriteSdPublishingDesign( *pStream, m_aDesignList[nIndex] );
+ }
+
+ aMedium.Close();
+ aMedium.Commit();
+
+ return( aMedium.GetError() == ERRCODE_NONE );
+}
+
+// SdDesignNameDlg Methods
+SdDesignNameDlg::SdDesignNameDlg(weld::Window* pWindow, const OUString& rName)
+ : GenericDialogController(pWindow, "modules/sdraw/ui/namedesign.ui", "NameDesignDialog")
+ , m_xEdit(m_xBuilder->weld_entry("entry"))
+ , m_xBtnOK(m_xBuilder->weld_button("ok"))
+{
+ m_xEdit->connect_changed(LINK(this, SdDesignNameDlg, ModifyHdl ));
+ m_xEdit->set_text(rName);
+ m_xBtnOK->set_sensitive(!rName.isEmpty());
+}
+
+OUString SdDesignNameDlg::GetDesignName() const
+{
+ return m_xEdit->get_text();
+}
+
+IMPL_LINK_NOARG(SdDesignNameDlg, ModifyHdl, weld::Entry&, void)
+{
+ m_xBtnOK->set_sensitive(!m_xEdit->get_text().isEmpty());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/html/sdhtmlfilter.cxx b/sd/source/filter/html/sdhtmlfilter.cxx
new file mode 100644
index 000000000..f7a3bc10f
--- /dev/null
+++ b/sd/source/filter/html/sdhtmlfilter.cxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/sfxsids.hrc>
+
+#include "htmlex.hxx"
+#include <sdhtmlfilter.hxx>
+
+SdHTMLFilter::SdHTMLFilter(SfxMedium& rMedium, ::sd::DrawDocShell& rDocShell)
+ : SdFilter(rMedium, rDocShell)
+{
+}
+
+SdHTMLFilter::~SdHTMLFilter() {}
+
+bool SdHTMLFilter::Export()
+{
+ mrMedium.Close();
+ mrMedium.Commit();
+
+ SfxItemSet* pSet = mrMedium.GetItemSet();
+
+ css::uno::Sequence<css::beans::PropertyValue> aParams;
+
+ if (const SfxUnoAnyItem* pItem = pSet->GetItemIfSet(SID_FILTER_DATA, false))
+ pItem->GetValue() >>= aParams;
+
+ HtmlExport aExport(mrMedium.GetName(), aParams, &mrDocument, &mrDocShell);
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/pdf/sdpdffilter.cxx b/sd/source/filter/pdf/sdpdffilter.cxx
new file mode 100644
index 000000000..002c1c5db
--- /dev/null
+++ b/sd/source/filter/pdf/sdpdffilter.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 <sal/config.h>
+
+#include <sfx2/docfile.hxx>
+#include <svx/svdograf.hxx>
+#include <o3tl/safeint.hxx>
+
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <sdpdffilter.hxx>
+
+#include <vcl/graph.hxx>
+#include <vcl/pdfread.hxx>
+
+#include <Annotation.hxx>
+
+#include <com/sun/star/office/XAnnotation.hpp>
+#include <com/sun/star/text/XText.hpp>
+
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+using namespace css;
+
+SdPdfFilter::SdPdfFilter(SfxMedium& rMedium, sd::DrawDocShell& rDocShell)
+ : SdFilter(rMedium, rDocShell)
+{
+}
+
+SdPdfFilter::~SdPdfFilter() {}
+
+bool SdPdfFilter::Import()
+{
+ const OUString aFileName(
+ mrMedium.GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::NONE));
+
+ std::vector<vcl::PDFGraphicResult> aGraphics;
+ if (vcl::ImportPDFUnloaded(aFileName, aGraphics) == 0)
+ return false;
+
+ bool bWasLocked = mrDocument.isLocked();
+ mrDocument.setLock(true);
+ const bool bSavedUndoEnabled = mrDocument.IsUndoEnabled();
+ mrDocument.EnableUndo(false);
+
+ // Add as many pages as we need up-front.
+ mrDocument.CreateFirstPages();
+ for (size_t i = 0; i < aGraphics.size() - 1; ++i)
+ {
+ mrDocument.DuplicatePage(0);
+ }
+
+ for (vcl::PDFGraphicResult const& rPDFGraphicResult : aGraphics)
+ {
+ const Graphic& rGraphic = rPDFGraphicResult.GetGraphic();
+ const Size& aSizeHMM = rPDFGraphicResult.GetSize();
+
+ const sal_Int32 nPageNumber = rGraphic.getPageNumber();
+ assert(nPageNumber >= 0 && o3tl::make_unsigned(nPageNumber) < aGraphics.size());
+
+ // Create the page and insert the Graphic.
+ SdPage* pPage = mrDocument.GetSdPage(nPageNumber, PageKind::Standard);
+ if (!pPage) // failed to duplicate page, out of memory?
+ return false;
+
+ // Make the page size match the rendered image.
+ pPage->SetSize(aSizeHMM);
+
+ SdrGrafObj* pSdrGrafObj = new SdrGrafObj(pPage->getSdrModelFromSdrPage(), rGraphic,
+ tools::Rectangle(Point(), aSizeHMM));
+
+ pSdrGrafObj->SetResizeProtect(true);
+ pSdrGrafObj->SetMoveProtect(true);
+
+ pPage->InsertObject(pSdrGrafObj);
+
+ for (auto const& rPDFAnnotation : rPDFGraphicResult.GetAnnotations())
+ {
+ uno::Reference<office::XAnnotation> xAnnotation;
+ pPage->createAnnotation(xAnnotation);
+
+ xAnnotation->setAuthor(rPDFAnnotation.maAuthor);
+
+ uno::Reference<text::XText> xText(xAnnotation->getTextRange());
+ xText->setString(rPDFAnnotation.maText);
+ // position is in mm not 100thmm
+ geometry::RealPoint2D aUnoPosition(rPDFAnnotation.maRectangle.getMinX() / 100.0,
+ rPDFAnnotation.maRectangle.getMinY() / 100.00);
+ geometry::RealSize2D aUnoSize(rPDFAnnotation.maRectangle.getWidth() / 100.0,
+ rPDFAnnotation.maRectangle.getHeight() / 100.00);
+ xAnnotation->setPosition(aUnoPosition);
+ xAnnotation->setSize(aUnoSize);
+ xAnnotation->setDateTime(rPDFAnnotation.maDateTime);
+
+ if (rPDFAnnotation.mpMarker)
+ {
+ auto* pAnnotation = static_cast<sd::Annotation*>(xAnnotation.get());
+ pAnnotation->createCustomAnnotationMarker();
+ sd::CustomAnnotationMarker& rCustomAnnotationMarker
+ = pAnnotation->getCustomAnnotationMarker();
+
+ rCustomAnnotationMarker.maLineColor = rPDFAnnotation.maColor;
+
+ if (rPDFAnnotation.meSubType == vcl::pdf::PDFAnnotationSubType::Polygon)
+ {
+ auto* pMarker = static_cast<vcl::pdf::PDFAnnotationMarkerPolygon*>(
+ rPDFAnnotation.mpMarker.get());
+ rCustomAnnotationMarker.mnLineWidth = pMarker->mnWidth;
+ rCustomAnnotationMarker.maFillColor = pMarker->maFillColor;
+ rCustomAnnotationMarker.maPolygons.push_back(pMarker->maPolygon);
+ }
+ else if (rPDFAnnotation.meSubType == vcl::pdf::PDFAnnotationSubType::Square)
+ {
+ auto* pMarker = static_cast<vcl::pdf::PDFAnnotationMarkerSquare*>(
+ rPDFAnnotation.mpMarker.get());
+ basegfx::B2DPolygon aPoly
+ = basegfx::utils::createPolygonFromRect(rPDFAnnotation.maRectangle);
+ rCustomAnnotationMarker.mnLineWidth = pMarker->mnWidth;
+ rCustomAnnotationMarker.maFillColor = pMarker->maFillColor;
+ rCustomAnnotationMarker.maPolygons.push_back(aPoly);
+ }
+ else if (rPDFAnnotation.meSubType == vcl::pdf::PDFAnnotationSubType::Circle)
+ {
+ auto* pMarker = static_cast<vcl::pdf::PDFAnnotationMarkerCircle*>(
+ rPDFAnnotation.mpMarker.get());
+
+ basegfx::B2DPoint rCenter = rPDFAnnotation.maRectangle.getCenter();
+ double fRadiusX = rPDFAnnotation.maRectangle.getWidth() / 2;
+ double fRadiusY = rPDFAnnotation.maRectangle.getHeight() / 2;
+
+ basegfx::B2DPolygon aPoly
+ = basegfx::utils::createPolygonFromEllipse(rCenter, fRadiusX, fRadiusY);
+ rCustomAnnotationMarker.mnLineWidth = pMarker->mnWidth;
+ rCustomAnnotationMarker.maFillColor = pMarker->maFillColor;
+ rCustomAnnotationMarker.maPolygons.push_back(aPoly);
+ }
+ else if (rPDFAnnotation.meSubType == vcl::pdf::PDFAnnotationSubType::Ink)
+ {
+ auto* pMarker = static_cast<vcl::pdf::PDFAnnotationMarkerInk*>(
+ rPDFAnnotation.mpMarker.get());
+ rCustomAnnotationMarker.maPolygons.insert(
+ rCustomAnnotationMarker.maPolygons.end(), pMarker->maStrokes.begin(),
+ pMarker->maStrokes.end());
+ rCustomAnnotationMarker.mnLineWidth = pMarker->mnWidth;
+ rCustomAnnotationMarker.maFillColor = pMarker->maFillColor;
+ }
+ else if (rPDFAnnotation.meSubType == vcl::pdf::PDFAnnotationSubType::Highlight)
+ {
+ if (!rCustomAnnotationMarker.maLineColor.IsTransparent())
+ rCustomAnnotationMarker.maLineColor.SetAlpha(255 - 0x90);
+ auto* pMarker = static_cast<vcl::pdf::PDFAnnotationMarkerHighlight*>(
+ rPDFAnnotation.mpMarker.get());
+ rCustomAnnotationMarker.maPolygons.insert(
+ rCustomAnnotationMarker.maPolygons.end(), pMarker->maQuads.begin(),
+ pMarker->maQuads.end());
+ rCustomAnnotationMarker.mnLineWidth = 1;
+ rCustomAnnotationMarker.maFillColor = rPDFAnnotation.maColor;
+ if (!rCustomAnnotationMarker.maFillColor.IsTransparent())
+ rCustomAnnotationMarker.maFillColor.SetAlpha(255 - 0x90);
+ }
+ else if (rPDFAnnotation.meSubType == vcl::pdf::PDFAnnotationSubType::Line)
+ {
+ auto* pMarker = static_cast<vcl::pdf::PDFAnnotationMarkerLine*>(
+ rPDFAnnotation.mpMarker.get());
+
+ basegfx::B2DPolygon aPoly;
+ aPoly.append(pMarker->maLineStart);
+ aPoly.append(pMarker->maLineEnd);
+ rCustomAnnotationMarker.maPolygons.push_back(aPoly);
+
+ rCustomAnnotationMarker.mnLineWidth = pMarker->mnWidth;
+ rCustomAnnotationMarker.maFillColor = COL_TRANSPARENT;
+ }
+ }
+ }
+ }
+ mrDocument.setLock(bWasLocked);
+ mrDocument.EnableUndo(bSavedUndoEnabled);
+ return true;
+}
+
+bool SdPdfFilter::Export() { return false; }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/ppt97animations.cxx b/sd/source/filter/ppt/ppt97animations.cxx
new file mode 100644
index 000000000..db3a960a7
--- /dev/null
+++ b/sd/source/filter/ppt/ppt97animations.cxx
@@ -0,0 +1,682 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ppt97animations.hxx"
+
+#include <svx/svdobj.hxx>
+#include <sdpage.hxx>
+#include <tools/stream.hxx>
+#include <svx/unoapi.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <CustomAnimationPreset.hxx>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
+
+using namespace ::com::sun::star;
+
+void Ppt97AnimationInfoAtom::ReadStream( SvStream& rIn )
+{
+ sal_uInt32 nTmp;
+ rIn.ReadUInt32( nTmp );
+ nDimColor = Color(ColorTransparency, nTmp);
+ rIn.ReadUInt32( nFlags );
+ rIn.ReadUInt32( nSoundRef );
+ rIn.ReadInt32( nDelayTime );
+ rIn.ReadUInt16( nOrderID );
+ rIn.ReadUInt16( nSlideCount );
+ rIn.ReadUChar( nBuildType );
+ rIn.ReadUChar( nFlyMethod );
+ rIn.ReadUChar( nFlyDirection );
+ rIn.ReadUChar( nAfterEffect );
+ rIn.ReadUChar( nSubEffect );
+ rIn.ReadUChar( nOLEVerb );
+ rIn.ReadUChar( nUnknown1 );
+ rIn.ReadUChar( nUnknown2 );
+}
+
+Ppt97Animation::Ppt97Animation( SvStream& rInputStream )
+ : m_aAtom()
+ , m_bDirtyCache(true)
+ , m_bHasSpecialDuration(false)
+ , m_fDurationInSeconds(0.001)
+{
+ m_aAtom.ReadStream( rInputStream );
+}
+
+bool Ppt97Animation::operator < ( const Ppt97Animation& rAnimation ) const
+{
+ return m_aAtom.nOrderID < rAnimation.m_aAtom.nOrderID;
+}
+bool Ppt97Animation::operator > ( const Ppt97Animation& rAnimation ) const
+{
+ return m_aAtom.nOrderID > rAnimation.m_aAtom.nOrderID;
+}
+bool Ppt97Animation::HasEffect() const
+{
+ return m_aAtom.nBuildType != 0;
+}
+bool Ppt97Animation::HasParagraphEffect() const
+{
+ return m_aAtom.nBuildType > 1;
+}
+sal_Int32 Ppt97Animation::GetParagraphLevel() const
+{
+ sal_Int32 nParagraphLevel = 0;
+ if(m_aAtom.nBuildType>1)
+ nParagraphLevel = m_aAtom.nBuildType-1;
+ return nParagraphLevel;
+}
+bool Ppt97Animation::HasSoundEffect() const
+{
+ return m_aAtom.nSoundRef && m_aAtom.nFlags & 0x0010;
+}
+bool Ppt97Animation::HasStopPreviousSound() const
+{
+ return m_aAtom.nFlags & 0x0040;
+}
+bool Ppt97Animation::HasReverseOrder() const
+{
+ return m_aAtom.nFlags & 0x001;
+}
+bool Ppt97Animation::HasAnimateAssociatedShape() const
+{
+ return m_aAtom.nFlags & 0x004000;
+}
+bool Ppt97Animation::HasAfterEffect() const
+{
+ return m_aAtom.nAfterEffect != 0;
+}
+bool Ppt97Animation::HasAfterEffect_ChangeColor() const
+{
+ return m_aAtom.nAfterEffect == 1;
+}
+bool Ppt97Animation::HasAfterEffect_DimAtNextEffect() const
+{
+ return m_aAtom.nAfterEffect == 2;
+}
+#ifdef FUTURE
+bool Ppt97Animation::HasAfterEffect_DimAfterEffect() const
+{
+ return m_aAtom.nAfterEffect == 3;
+}
+#endif
+void Ppt97Animation::SetSoundFileUrl( const OUString& rSoundFileUrl )
+{
+ m_aSoundFileUrl = rSoundFileUrl;
+}
+
+double Ppt97Animation::GetDelayTimeInSeconds() const
+{
+ return m_aAtom.nDelayTime != 0X7FFFFFFF ? m_aAtom.nDelayTime/1000.0 : 0.0;
+}
+
+bool Ppt97Animation::GetSpecialDuration( double& rfDurationInSeconds ) const
+{
+ UpdateCacheData();
+ if( m_bHasSpecialDuration )
+ rfDurationInSeconds = m_fDurationInSeconds;
+ return m_bHasSpecialDuration;
+}
+
+bool Ppt97Animation::GetSpecialTextIterationDelay( double& rfTextIterationDelay ) const
+{
+ bool bRet = false;
+ switch(GetTextAnimationType())
+ {
+ case presentation::TextAnimationType::BY_LETTER:
+ rfTextIterationDelay = 0.075;
+ bRet = true;
+ break;
+ case presentation::TextAnimationType::BY_WORD:
+ rfTextIterationDelay = 0.3;
+ bRet = true;
+ break;
+ default:
+ break;
+ }
+ return bRet;
+}
+
+void Ppt97Animation::SetDimColor( Color nDimColor )
+{
+ m_aAtom.nDimColor = nDimColor;
+}
+void Ppt97Animation::SetAnimateAssociatedShape( bool bAnimate )
+{
+ if( !bAnimate )
+ {
+ //the appear effect cannot be animated without text
+ if( GetPresetId() == "ooo-entrance-appear" )
+ return;
+ //the random effect may be the appear effect and then has the same problem
+ if( GetPresetId() == "ooo-entrance-random" )
+ {
+ //this case is not 100% correct -> feel free to complete
+ //i consider this case as seldom and not that problematic and a simple correct fix is not in sight
+ SAL_INFO("sd", "you tried to deselect the animation of the form for random animation-> this has been refused");
+ return;
+ }
+
+ }
+
+ if(bAnimate)
+ m_aAtom.nFlags = m_aAtom.nFlags | 0x004000;
+ else if( HasAnimateAssociatedShape() )
+ {
+ m_aAtom.nFlags = m_aAtom.nFlags ^ 0x004000;
+ }
+}
+
+sal_Int16 Ppt97Animation::GetEffectNodeType() const //see css::presentation::EffectNodeType
+{
+ sal_Int16 nRet = presentation::EffectNodeType::ON_CLICK;
+ if( m_aAtom.nFlags & 0x04 )
+ {
+ nRet = presentation::EffectNodeType::AFTER_PREVIOUS;
+ }
+ return nRet;
+}
+
+sal_Int16 Ppt97Animation::GetTextAnimationType() const
+{
+ sal_Int16 nRet = presentation::TextAnimationType::BY_PARAGRAPH;
+ switch( m_aAtom.nSubEffect )
+ {
+ case 0:
+ break;
+ case 2:
+ nRet = presentation::TextAnimationType::BY_LETTER;
+ break;
+ default:
+ nRet = presentation::TextAnimationType::BY_WORD;
+ break;
+ }
+ return nRet;
+}
+OUString const & Ppt97Animation::GetPresetId() const
+{
+ UpdateCacheData();
+ return m_aPresetId;
+}
+OUString const & Ppt97Animation::GetPresetSubType() const
+{
+ UpdateCacheData();
+ return m_aSubType;
+}
+
+void Ppt97Animation::ClearCacheData() const
+{
+ m_aPresetId.clear();
+ m_aSubType.clear();
+ m_bHasSpecialDuration = false;
+ m_fDurationInSeconds = 0.001;
+}
+void Ppt97Animation::UpdateCacheData() const
+{
+ if( !m_bDirtyCache )
+ return;
+
+ ClearCacheData();
+
+ if( !HasEffect() )
+ {
+ m_bDirtyCache = false;
+ return;
+ }
+
+ switch( m_aAtom.nFlyMethod )
+ {
+ case 0x0:
+ m_aPresetId = "ooo-entrance-appear"; // --- appear ---
+ break;
+ case 0x01:
+ m_aPresetId = "ooo-entrance-random"; // --- random ---
+ break;
+ case 0x02: // --- blinds effect ---
+ {
+ switch ( m_aAtom.nFlyDirection )
+ {
+ case 0x0:
+ m_aPresetId = "ooo-entrance-venetian-blinds";
+ m_aSubType = "horizontal"; // horizontal
+ break;
+ case 0x1:
+ m_aPresetId = "ooo-entrance-venetian-blinds";
+ m_aSubType = "vertical"; // vertical
+ break;
+ }
+ }
+ break;
+ case 0x03: // --- (hor/ver) shifted appear ---
+ {
+ switch ( m_aAtom.nFlyDirection )
+ {
+ case 0x0:
+ m_aPresetId = "ooo-entrance-checkerboard";
+ m_aSubType = "across"; // vertical ???
+ break;
+ case 0x1:
+ m_aPresetId = "ooo-entrance-checkerboard";
+ m_aSubType = "downward"; // horizontal ???
+ break;
+ }
+ }
+ break;
+ case 0x05:
+ m_aPresetId = "ooo-entrance-dissolve-in";
+ break;
+ case 0x08: // --- (hor/ver) lines ---
+ {
+ switch ( m_aAtom.nFlyDirection )
+ {
+ case 0x0:
+ m_aPresetId = "ooo-entrance-random-bars";
+ m_aSubType = "vertical"; // horizontal ???
+ break;
+ case 0x1:
+ m_aPresetId = "ooo-entrance-random-bars";
+ m_aSubType = "horizontal"; // vertical ???
+ break;
+ }
+ }
+ break;
+ case 0x09: // --- diagonal ---
+ {
+ switch ( m_aAtom.nFlyDirection )
+ {
+ case 0x4:
+ m_aPresetId = "ooo-entrance-diagonal-squares";
+ m_aSubType = "left-to-top"; // to left top
+ break;
+ case 0x5:
+ m_aPresetId = "ooo-entrance-diagonal-squares";
+ m_aSubType = "right-to-top"; // to right top
+ break;
+ case 0x6:
+ m_aPresetId = "ooo-entrance-diagonal-squares";
+ m_aSubType = "left-to-bottom"; // to left bottom
+ break;
+ case 0x7:
+ m_aPresetId = "ooo-entrance-diagonal-squares";
+ m_aSubType = "right-to-bottom"; // to right bottom
+ break;
+ }
+ }
+ break;
+ case 0x0a: // --- roll/wipe ---
+ {
+ switch ( m_aAtom.nFlyDirection )
+ {
+ case 0x0:
+ m_aPresetId = "ooo-entrance-wipe";
+ m_aSubType = "from-right"; // from right
+ break;
+ case 0x1:
+ m_aPresetId = "ooo-entrance-wipe";
+ m_aSubType = "from-bottom"; // from bottom
+ break;
+ case 0x2:
+ m_aPresetId = "ooo-entrance-wipe";
+ m_aSubType = "from-left"; // from left
+ break;
+ case 0x3:
+ m_aPresetId = "ooo-entrance-wipe";
+ m_aSubType = "from-top"; // from top
+ break;
+ }
+ }
+ break;
+ case 0x0b: //--- fade in ---
+ {
+ switch ( m_aAtom.nFlyDirection )
+ {
+ case 0x0:
+ m_aPresetId = "ooo-entrance-box";
+ m_aSubType = "out"; // from center
+ break;
+ case 0x1:
+ m_aPresetId = "ooo-entrance-box";
+ m_aSubType = "in"; // to center
+ break;
+ }
+ }
+ break;
+ case 0x0c: // --- text effects ---
+ {
+ switch ( m_aAtom.nFlyDirection )
+ {
+ case 0x0:
+ m_aPresetId = "ooo-entrance-fly-in";
+ m_aSubType = "from-left";
+
+ break;
+ case 0x1:
+ m_aPresetId = "ooo-entrance-fly-in";
+ m_aSubType = "from-top";
+ break;
+ case 0x2:
+ m_aPresetId = "ooo-entrance-fly-in";
+ m_aSubType = "from-right";
+ break;
+ case 0x3:
+ m_aPresetId = "ooo-entrance-fly-in";
+ m_aSubType = "from-bottom";
+ break;
+ case 0x4:
+ m_aPresetId = "ooo-entrance-fly-in";
+ m_aSubType = "from-top-left";
+ break;
+ case 0x5:
+ m_aPresetId = "ooo-entrance-fly-in";
+ m_aSubType = "from-top-right";
+ break;
+ case 0x6:
+ m_aPresetId = "ooo-entrance-fly-in";
+ m_aSubType = "from-bottom-left";
+ break;
+ case 0x7:
+ m_aPresetId = "ooo-entrance-fly-in";
+ m_aSubType = "from-bottom-right";
+ break;
+ case 0x8: // -- short text effects --
+ m_aPresetId = "ooo-entrance-peek-in";
+ m_aSubType = "from-left";
+ break;
+ case 0x9:
+ m_aPresetId = "ooo-entrance-peek-in";
+ m_aSubType = "from-bottom";
+ break;
+ case 0xa:
+ m_aPresetId = "ooo-entrance-peek-in";
+ m_aSubType = "from-right";
+ break;
+ case 0xb:
+ m_aPresetId = "ooo-entrance-peek-in";
+ m_aSubType = "from-top";
+ break;
+ case 0xc: // -- slow text effects --
+ {
+ m_aPresetId = "ooo-entrance-fly-in-slow";
+ m_aSubType = "from-left";
+ }
+ break;
+ case 0xd:
+ {
+ m_aPresetId = "ooo-entrance-fly-in-slow";
+ m_aSubType = "from-top";
+ }
+ break;
+ case 0xe:
+ {
+ m_aPresetId = "ooo-entrance-fly-in-slow";
+ m_aSubType = "from-right";
+ }
+ break;
+ case 0xf:
+ {
+ m_aPresetId = "ooo-entrance-fly-in-slow";
+ m_aSubType = "from-bottom";
+ }
+ break;
+ case 0x10: // --- zoom ---
+ m_aPresetId = "ooo-entrance-zoom";
+ m_aSubType = "in";
+ break;
+ case 0x11:
+ m_aPresetId = "ooo-entrance-zoom";
+ m_aSubType = "in-slightly";
+ break;
+ case 0x12:
+ m_aPresetId = "ooo-entrance-zoom";
+ m_aSubType = "out";
+ break;
+ case 0x13:
+ m_aPresetId = "ooo-entrance-zoom";
+ m_aSubType = "out-slightly";
+ break;
+ case 0x14:
+ m_aPresetId = "ooo-entrance-zoom";
+ m_aSubType = "in-from-screen-center";
+ break;
+ case 0x15:
+ m_aPresetId = "ooo-entrance-zoom";
+ m_aSubType = "out-from-screen-center";
+ break;
+ case 0x16: // --- stretch ---
+ m_aPresetId = "ooo-entrance-stretchy";
+ m_aSubType = "across";
+ break;
+ case 0x17:
+ m_aPresetId = "ooo-entrance-stretchy";
+ m_aSubType = "from-left";
+ break;
+ case 0x18:
+ m_aPresetId = "ooo-entrance-stretchy";
+ m_aSubType = "from-top";
+ break;
+ case 0x19:
+ m_aPresetId = "ooo-entrance-stretchy";
+ m_aSubType = "from-right";
+ break;
+ case 0x1a:
+ m_aPresetId = "ooo-entrance-stretchy";
+ m_aSubType = "from-bottom";
+ break;
+ case 0x1b: // --- rotate ---
+ m_aPresetId = "ooo-entrance-swivel";
+ m_aSubType = "vertical";
+ break;
+ case 0x1c: // --- spirale ---
+ m_aPresetId = "ooo-entrance-spiral-in";
+ break;
+ }
+ }
+ break;
+ case 0x0d: // --- open/close ---
+ {
+ switch ( m_aAtom.nFlyDirection )
+ {
+ case 0x0:
+ m_aPresetId = "ooo-entrance-split";
+ m_aSubType = "horizontal-out"; //horizontal open
+ break;
+ case 0x1:
+ m_aPresetId = "ooo-entrance-split";
+ m_aSubType = "horizontal-in"; //horizontal close
+ break;
+ case 0x2:
+ m_aPresetId = "ooo-entrance-split";
+ m_aSubType = "vertical-out"; // vertical open
+ break;
+ case 0x3:
+ m_aPresetId = "ooo-entrance-split";
+ m_aSubType = "vertical-in"; // vertical close
+ break;
+ }
+ }
+ break;
+ case 0x0e: // --- blink ---
+ {
+ m_aPresetId = "ooo-entrance-flash-once";
+ switch ( m_aAtom.nFlyDirection )
+ {
+ case 0x0: //fast
+ m_fDurationInSeconds = 0.075;
+ m_bHasSpecialDuration = true;
+ break;
+ case 0x1: //medium
+ m_fDurationInSeconds = 0.5;
+ m_bHasSpecialDuration = true;
+ break;
+ case 0x2: //slow
+ m_fDurationInSeconds = 1.0;
+ m_bHasSpecialDuration = true;
+ break;
+ }
+ }
+ break;
+ default:
+ {
+ m_aPresetId = "ooo-entrance-appear";
+ OSL_FAIL("no effect mapped");
+ }
+ break;
+ }
+ m_bDirtyCache = false;
+}
+
+void Ppt97Animation::createAndSetCustomAnimationEffect( SdrObject* pObj )
+{
+
+ if( !HasEffect() )
+ return;
+ if( !pObj || !pObj->getSdrPageFromSdrObject() )
+ {
+ OSL_FAIL("no valid SdrObject or page found for ppt import");
+ return;
+ }
+
+ uno::Reference< drawing::XShape > xShape = GetXShapeForSdrObject( pObj );
+ if( !xShape.is() )
+ {
+ OSL_FAIL("no XShape interface found for ppt import");
+ return;
+ }
+ ::sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
+ if( !pMainSequence )
+ {
+ OSL_FAIL("no MainSequence found for ppt import");
+ return;
+ }
+
+ const ::sd::CustomAnimationPresets& rPresets( ::sd::CustomAnimationPresets::getCustomAnimationPresets() );
+ ::sd::CustomAnimationPresetPtr pPreset( rPresets.getEffectDescriptor( GetPresetId() ) );
+ if( !pPreset )
+ {
+ OSL_FAIL("no suitable preset found for ppt import");
+ return;
+ }
+
+ //--------------start doing something
+
+ //1. ------ create an effect from the presets ------
+ ::sd::CustomAnimationEffectPtr pEffect = std::make_shared<::sd::CustomAnimationEffect>( pPreset->create( GetPresetSubType() ) );
+
+ //2. ------ adapt the created effect ------
+
+ // set the shape targeted by this effect
+ pEffect->setTarget( css::uno::Any( xShape ) );
+
+ pEffect->setBegin( GetDelayTimeInSeconds() );
+
+ // some effects need a different duration than that of the mapped preset effect
+ double fDurationInSeconds = 1.0; //in seconds
+ if( GetSpecialDuration( fDurationInSeconds ) )
+ pEffect->setDuration( fDurationInSeconds );
+
+ // set after effect
+ if( HasAfterEffect() )
+ {
+ pEffect->setHasAfterEffect( true );
+ if( HasAfterEffect_ChangeColor() )
+ pEffect->setDimColor( uno::Any( GetDimColor() ) );
+ else
+ pEffect->setAfterEffectOnNext( HasAfterEffect_DimAtNextEffect() );
+ }
+
+ // set sound effect
+ if( HasSoundEffect() )
+ pEffect->createAudio( uno::Any( m_aSoundFileUrl ) );
+
+ // text iteration
+ pEffect->setIterateType( GetTextAnimationType() );
+
+ // some effects need a different delay between text iteration than that of the mapped preset effect
+ double fTextIterationDelay = 1.0;
+ if( GetSpecialTextIterationDelay( fTextIterationDelay ) )
+ pEffect->setIterateInterval( fTextIterationDelay );
+
+ // is the effect started on click or after the last effect (Another possible value is EffectNodeType::WITH_PREVIOUS )
+ pEffect->setNodeType( GetEffectNodeType() );
+
+ //set stop sound effect
+ if( HasStopPreviousSound() )
+ pEffect->setStopAudio();
+
+ // append the effect to the main sequence
+ if( !HasParagraphEffect() )
+ {
+ // TODO: !HasAnimateAssociatedShape() can possibly have this set to ONLY_TEXT - see i#42737
+ pEffect->setTargetSubItem( presentation::ShapeAnimationSubType::AS_WHOLE );
+ }
+
+ //3. ------ put the created effect to the model and do some last changes fro paragraph effects ------
+ pMainSequence->append( pEffect );
+ if( HasParagraphEffect() )
+ {
+ sal_Int32 nParagraphLevel = GetParagraphLevel();
+ double fDelaySeconds = GetDelayTimeInSeconds();
+ bool bAnimateAssociatedShape = HasAnimateAssociatedShape();//or only text
+ bool bTextReverse = HasReverseOrder();
+
+ // now create effects for each paragraph
+ ::sd::CustomAnimationTextGroupPtr pGroup = pMainSequence->
+ createTextGroup( pEffect, nParagraphLevel, fDelaySeconds, bAnimateAssociatedShape, bTextReverse );
+
+ if( pGroup )
+ {
+ const ::sd::EffectSequence& rEffects = pGroup->getEffects();
+
+ ::sd::CustomAnimationEffectPtr pLastEffect;
+ sal_Int32 nIndex = 0;
+ for( const auto& rxEffect : rEffects )
+ {
+ ::sd::CustomAnimationEffectPtr pGroupEffect(rxEffect);
+
+ ////todo? if( nIndex > 1 && pLastEffect && HasSoundEffect() )
+ //// pLastEffect->setStopAudio();
+ if( nIndex < 2 )
+ {
+ pGroupEffect->setNodeType( GetEffectNodeType() );
+ }
+ else if( nIndex > 0 )
+ {
+ bool bAtParagraphBegin = false;
+ if(!bTextReverse)
+ bAtParagraphBegin = pGroupEffect->getParaDepth() < nParagraphLevel;
+ else
+ bAtParagraphBegin = !pLastEffect || pLastEffect->getParaDepth() < nParagraphLevel;
+ if( bAtParagraphBegin )
+ pGroupEffect->setNodeType( GetEffectNodeType() );
+ else if( GetTextAnimationType() == presentation::TextAnimationType::BY_PARAGRAPH )
+ pGroupEffect->setNodeType( presentation::EffectNodeType::WITH_PREVIOUS );
+ else
+ pGroupEffect->setNodeType( presentation::EffectNodeType::AFTER_PREVIOUS );
+ }
+ pLastEffect = pGroupEffect;
+ nIndex++;
+ }
+ }
+ }
+ pMainSequence->rebuild();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/ppt97animations.hxx b/sd/source/filter/ppt/ppt97animations.hxx
new file mode 100644
index 000000000..1811d93a3
--- /dev/null
+++ b/sd/source/filter/ppt/ppt97animations.hxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <tools/color.hxx>
+
+class SdrObject;
+class SvStream;
+
+/// helper class for reading PPT AnimationInfoAtom
+class Ppt97AnimationInfoAtom
+{
+ friend class Ppt97Animation;
+
+//-- member
+ Color nDimColor;
+ sal_uInt32 nFlags; ///< 0x0004: time instead of click
+ sal_uInt32 nSoundRef;
+ sal_Int32 nDelayTime; ///< 1/1000 sec
+ sal_uInt16 nOrderID;
+ sal_uInt16 nSlideCount;
+ sal_uInt8 nBuildType;
+ sal_uInt8 nFlyMethod;
+ sal_uInt8 nFlyDirection;
+ sal_uInt8 nAfterEffect; ///< nAfterEffect: 0: none; 1: change color; 2: dim on next effect; 3: dim after effect;
+ sal_uInt8 nSubEffect;
+ sal_uInt8 nOLEVerb;
+
+ // unknown, because whole size needs to be 28
+ sal_uInt8 nUnknown1;
+ sal_uInt8 nUnknown2;
+
+//-- methods
+ void ReadStream( SvStream& rIn );
+/*
+ nFlags:
+ decimal / hexadecimal / binary
+ 1040 0x00000410 10000010000 mouseclick
+ 17428 0x00004414 100010000010100 after previous 0 sec (animate form)
+ 17412 0x00004404 100010000000100 after previous 0 sec
+ 1088 0x00000440 10001000000 stop previous sound and mouseclick
+ 1044 0x00000414 10000010100 play sound automatic
+ 1041 0x00000411 10000010001
+ | | | | | |
+ | | | | | reverse order
+ | | | | after previous
+ | | | sound
+ | | stop previous sound
+ | ?
+ animate form
+
+ nAfterEffect:
+ 1: color
+ 0: nothing
+ 3: hide after animation
+ 2: hide at next mouse click
+*/
+};
+
+/** this is a helping class for import of PPT 97 animations
+ 1. use the constructor Ppt97Animation( SvStream& rIn ) to import information from the stream
+ 2. use the set methods to modify and complete the data
+ 3. use the method createAndSetCustomAnimationEffect( ) to create an effect in sd model
+ */
+class Ppt97Animation
+{
+
+public: //public methods
+ explicit Ppt97Animation( SvStream& rIn );
+
+ bool operator < ( const Ppt97Animation& rAnimation ) const;//later is greater
+ bool operator > ( const Ppt97Animation& rAnimation ) const;//later is greater
+
+ //get methods
+ bool HasEffect() const;
+ bool HasParagraphEffect() const;
+ bool HasSoundEffect() const;
+ sal_Int32 GetDimColor() const { return static_cast<sal_Int32>(m_aAtom.nDimColor);}
+ sal_uInt32 GetSoundRef() const { return m_aAtom.nSoundRef;}
+ /// @return true if the shape should be animated in addition to the text
+ bool HasAnimateAssociatedShape() const;
+
+ //set methods
+ void SetDimColor( Color nDimColor );
+ void SetSoundFileUrl( const OUString& rSoundFileUrl );
+ void SetAnimateAssociatedShape( bool bAnimate ); //true if the shape should be animated in addition to the text
+
+ //action methods
+ /** this method creates a CustomAnimationEffect for the given SdrObject
+ from internal data and stores the created effect at the draw model
+ */
+ void createAndSetCustomAnimationEffect( SdrObject* pObj );
+
+private: //private methods
+
+ //read methods
+ OUString const & GetPresetId() const;
+ OUString const & GetPresetSubType() const;
+ bool HasAfterEffect() const;
+ bool HasAfterEffect_ChangeColor() const;
+ bool HasAfterEffect_DimAtNextEffect() const;
+ bool HasStopPreviousSound() const;
+
+ /// @return true if the text paragraphs should be animated in reverse order
+ bool HasReverseOrder() const;
+
+ ///paragraph level that is animated ( that paragraph and higher levels )
+ sal_Int32 GetParagraphLevel() const;
+
+ ///@see css::presentation::TextAnimationType
+ sal_Int16 GetTextAnimationType() const;
+
+ ///@see css::presentation::EffectNodeType
+ sal_Int16 GetEffectNodeType() const;
+
+ /// @return -1 for start on mouseclick or >= 0 for a delay in seconds for automatic start
+ double GetDelayTimeInSeconds() const;
+ bool GetSpecialDuration( double& rfDurationInSeconds ) const;
+ bool GetSpecialTextIterationDelay( double& rfTextIterationDelay ) const;
+
+ void UpdateCacheData() const;
+ void ClearCacheData() const;
+
+private: //private member
+ //input information:
+ Ppt97AnimationInfoAtom m_aAtom; ///< pure input from stream
+ OUString m_aSoundFileUrl; ///< this needs to be set in addition from outside as this class has not the knowledge to translate the sound bits to a file url
+
+ //cached generated output information:
+ mutable bool m_bDirtyCache;
+ mutable OUString m_aPresetId; // m_aPresetId and m_aSubType match to the values in sd/xml/effects.xml
+ mutable OUString m_aSubType;
+ mutable bool m_bHasSpecialDuration;
+ mutable double m_fDurationInSeconds;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/pptanimations.hxx b/sd/source/filter/ppt/pptanimations.hxx
new file mode 100644
index 000000000..7fda1bb68
--- /dev/null
+++ b/sd/source/filter/ppt/pptanimations.hxx
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Any.h>
+
+#include <map>
+#include <sal/types.h>
+
+class SvStream;
+
+namespace ppt
+{
+
+// old transition types
+#define PPT_TRANSITION_TYPE_NONE 0
+#define PPT_TRANSITION_TYPE_RANDOM 1
+#define PPT_TRANSITION_TYPE_BLINDS 2
+#define PPT_TRANSITION_TYPE_CHECKER 3
+#define PPT_TRANSITION_TYPE_COVER 4
+#define PPT_TRANSITION_TYPE_DISSOLVE 5
+#define PPT_TRANSITION_TYPE_FADE 6
+#define PPT_TRANSITION_TYPE_PULL 7 // Uncover in MS-PPT Specs
+#define PPT_TRANSITION_TYPE_RANDOM_BARS 8
+#define PPT_TRANSITION_TYPE_STRIPS 9
+#define PPT_TRANSITION_TYPE_WIPE 10
+#define PPT_TRANSITION_TYPE_ZOOM 11 // Box In/Out in MS-PPT Specs
+#define PPT_TRANSITION_TYPE_SPLIT 13
+
+// effects, new in xp
+#define PPT_TRANSITION_TYPE_DIAMOND 17
+#define PPT_TRANSITION_TYPE_PLUS 18
+#define PPT_TRANSITION_TYPE_WEDGE 19
+#define PPT_TRANSITION_TYPE_PUSH 20
+#define PPT_TRANSITION_TYPE_COMB 21
+#define PPT_TRANSITION_TYPE_NEWSFLASH 22
+#define PPT_TRANSITION_TYPE_SMOOTHFADE 23 // Alpha Fade in MS-PPT Specs
+#define PPT_TRANSITION_TYPE_WHEEL 26
+#define PPT_TRANSITION_TYPE_CIRCLE 27
+
+// undocumented(?)
+#define PPT_TRANSITION_TYPE_FLASH 30
+
+// atoms
+#define DFF_msofbtAnimEvent 0xf125
+#define DFF_msofbtAnimNode 0xf127
+#define DFF_msofbtAnimTrigger 0xf128
+#define DFF_msofbtAnimValue 0xf129
+#define DFF_msofbtAnimateTarget 0xf12a
+#define DFF_msofbtAnimate 0xf12b
+#define DFF_msofbtAnimateColor 0xf12c
+#define DFF_msofbtAnimateFilter 0xf12d
+#define DFF_msofbtAnimateMotion 0xf12e
+#define DFF_msofbtAnimateRotation 0xf12f
+#define DFF_msofbtAnimateScale 0xf130
+#define DFF_msofbtAnimateSet 0xf131
+#define DFF_msofbtAnimCommand 0xf132
+#define DFF_msofbtAnimateTargetSettings 0xf133
+#define DFF_msofbtAnimateData 0xf134
+#define DFF_msofbtAnimateColorData 0xf135
+#define DFF_msofbtAnimateFilterData 0xf136
+#define DFF_msofbtAnimateMotionData 0xf137
+#define DFF_msofbtAnimateScaleData 0xf139
+#define DFF_msofbtAnimateSetData 0xf13a
+#define DFF_msofbtCommandData 0xf13b
+#define DFF_msofbtAnimateTargetElement 0xf13c
+#define DFF_msofbtAnimPropertySet 0xf13d
+#define DFF_msofbtAnimateAttributeNames 0xf13e
+#define DFF_msofbtAnimKeyPoints 0xf13f
+#define DFF_msofbtAnimIteration 0xf140
+#define DFF_msofbtAnimAction 0xf141 // correct name??
+#define DFF_msofbtAnimAttributeValue 0xf142
+#define DFF_msofbtAnimKeyTime 0xf143
+#define DFF_msofbtAnimGroup 0xf144
+#define DFF_msofbtAnimSubGoup 0xf145
+#define DFF_msofbtAnimateRotationData 0xf138
+#define DFF_msofbtAnimReference 0x2afb
+
+// property ids
+#define DFF_ANIM_ID 1
+#define DFF_ANIM_RUNTIMECONTEXT 2
+#define DFF_ANIM_PATH_EDIT_MODE 3
+#define DFF_ANIM_COLORSPACE 4
+#define DFF_ANIM_DIRECTION 5 // TODO: Conflict?
+#define DFF_ANIM_MASTERREL 5 // TODO: Conflict?
+#define DFF_ANIM_OVERRIDE 6
+#define DFF_ANIM_PRESET_ID 9
+#define DFF_ANIM_PRESET_SUB_TYPE 10
+#define DFF_ANIM_PRESET_CLASS 11
+#define DFF_ANIM_AFTEREFFECT 13
+#define DFF_ANIM_ENDAFTERSLIDE 15
+#define DFF_ANIM_TIMEFILTER 16
+#define DFF_ANIM_EVENT_FILTER 17
+#define DFF_ANIM_GROUP_ID 19
+#define DFF_ANIM_NODE_TYPE 20
+#define DFF_ANIM_VOLUME 22
+#define DFF_ANIM_PROPERTY_ID_COUNT (DFF_ANIM_VOLUME + 1)
+
+// property types
+#define DFF_ANIM_PROP_TYPE_BYTE 0
+#define DFF_ANIM_PROP_TYPE_INT32 1
+#define DFF_ANIM_PROP_TYPE_FLOAT 2
+#define DFF_ANIM_PROP_TYPE_UNISTRING 3
+
+#define DFF_ANIM_PRESS_CLASS_USER_DEFINED 0
+#define DFF_ANIM_PRESS_CLASS_ENTRANCE 1
+#define DFF_ANIM_PRESS_CLASS_EXIT 2
+#define DFF_ANIM_PRESS_CLASS_EMPHASIS 3
+#define DFF_ANIM_PRESS_CLASS_MOTIONPATH 4
+#define DFF_ANIM_PRESS_CLASS_OLE_ACTION 5
+#define DFF_ANIM_PRESS_CLASS_MEDIACALL 6
+
+// Effect node type.
+#define DFF_ANIM_NODE_TYPE_ON_CLICK 1
+#define DFF_ANIM_NODE_TYPE_WITH_PREVIOUS 2
+#define DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS 3
+#define DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE 4
+#define DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ 5
+#define DFF_ANIM_NODE_TYPE_CLICK_PARALLEL 6
+#define DFF_ANIM_NODE_TYPE_WITH_GROUP 7
+#define DFF_ANIM_NODE_TYPE_AFTER_GROUP 8
+#define DFF_ANIM_NODE_TYPE_TIMING_ROOT 9
+
+/* constants for fill entry in AnimationNode */
+const sal_Int32 mso_Anim_GroupType_PAR = 0;
+const sal_Int32 mso_Anim_GroupType_SEQ = 1;
+const sal_Int32 mso_Anim_GroupType_NODE = 3;
+const sal_Int32 mso_Anim_GroupType_MEDIA = 4;
+
+/* constants for fill entry in AnimationNode */
+const sal_Int32 mso_Anim_Fill_ALWAYS = 1;
+const sal_Int32 mso_Anim_Fill_WHENOFF = 2;
+const sal_Int32 mso_Anim_Fill_NEVER = 3;
+
+/* constants for fill entry in AnimationNode */
+const sal_Int32 mso_Anim_Fill_REMOVE = 1;
+const sal_Int32 mso_Anim_Fill_FREEZE = 2;
+const sal_Int32 mso_Anim_Fill_HOLD = 3;
+
+/* constants for behaviour entry in PPTAnimationNode */
+const sal_Int32 mso_Anim_Behaviour_FILTER = 24;
+const sal_Int32 mso_Anim_Behaviour_ANIMATION= 25;
+
+typedef ::std::map< sal_Int32, css::uno::Any > PropertySetMap_t;
+
+class PropertySet
+{
+public:
+ PropertySetMap_t maProperties;
+
+ bool hasProperty( sal_Int32 nProperty ) const;
+ css::uno::Any getProperty( sal_Int32 nProperty ) const;
+};
+
+/** this atom is the first entry in each animation group */
+struct AnimationNode
+{
+public:
+ /** see mso_Anim_GroupType_? */
+ sal_Int32 mnGroupType;
+
+ /** see mso_Anim_Restart_? */
+ sal_Int32 mnRestart;
+
+ /** see mso_Anim_Fill_? */
+ sal_Int32 mnFill;
+
+ /** see mso_Anim_Behaviour_? */
+ sal_Int32 mnNodeType;
+
+ /** duration of this group in 1000th seconds */
+ sal_Int32 mnDuration;
+
+ sal_Int32 mnU1, mnU3, mnU4;
+
+ AnimationNode()
+ : mnGroupType(0)
+ , mnRestart(0)
+ , mnFill(0)
+ , mnNodeType(0)
+ , mnDuration(0)
+ , mnU1(0), mnU3(0), mnU4(0)
+ {
+ }
+public:
+
+ friend SvStream& WriteAnimationNode(SvStream& rOut, AnimationNode const & rAtom);
+};
+
+} // namespace ppt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/pptatom.cxx b/sd/source/filter/ppt/pptatom.cxx
new file mode 100644
index 000000000..24d87f040
--- /dev/null
+++ b/sd/source/filter/ppt/pptatom.cxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/stream.hxx>
+#include "pptatom.hxx"
+
+using namespace ppt;
+
+Atom::Atom( const DffRecordHeader& rRecordHeader, SvStream& rStream )
+: mrStream( rStream )
+, maRecordHeader( rRecordHeader )
+, mpFirstChild( nullptr )
+, mpNextAtom( nullptr )
+{
+ if( isContainer() )
+ {
+ if( seekToContent() )
+ {
+ DffRecordHeader aChildHeader;
+
+ Atom* pLastAtom = nullptr;
+
+ // retrieve file size (to allow sanity checks)
+ sal_uInt64 const nStreamSize = mrStream.TellEnd();
+
+ while( mrStream.good()
+ && ( mrStream.Tell() < nStreamSize )
+ && ( mrStream.Tell() < maRecordHeader.GetRecEndFilePos() ) )
+ {
+ if (ReadDffRecordHeader(mrStream, aChildHeader))
+ {
+ Atom* pAtom = new Atom( aChildHeader, mrStream );
+
+ if( pLastAtom )
+ pLastAtom->mpNextAtom = pAtom;
+ if( mpFirstChild == nullptr )
+ mpFirstChild = pAtom;
+
+ pLastAtom = pAtom;
+ }
+ }
+ }
+ }
+
+ if (!maRecordHeader.SeekToEndOfRecord(mrStream))
+ mrStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
+}
+
+Atom::~Atom()
+{
+ Atom* pChild = mpFirstChild;
+ while( pChild )
+ {
+ Atom* pNextChild = pChild->mpNextAtom;
+ delete pChild;
+ pChild = pNextChild;
+ }
+}
+
+/** imports this atom and its child atoms */
+Atom* Atom::import( const DffRecordHeader& rRootRecordHeader, SvStream& rStCtrl )
+{
+ Atom* pRootAtom = new Atom( rRootRecordHeader, rStCtrl );
+
+ if( rStCtrl.GetError() == ERRCODE_NONE )
+ {
+ return pRootAtom;
+ }
+ else
+ {
+ delete pRootAtom;
+ return nullptr;
+ }
+}
+
+/** returns the next child atom after pLast with nRecType or NULL */
+const Atom* Atom::findNextChildAtom( sal_uInt16 nRecType, const Atom* pLast ) const
+{
+ Atom* pChild = pLast != nullptr ? pLast->mpNextAtom : mpFirstChild;
+ while( pChild && pChild->maRecordHeader.nRecType != nRecType )
+ {
+ pChild = pChild->mpNextAtom;
+ }
+
+ return pChild;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/pptatom.hxx b/sd/source/filter/ppt/pptatom.hxx
new file mode 100644
index 000000000..55ee7f687
--- /dev/null
+++ b/sd/source/filter/ppt/pptatom.hxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <filter/msfilter/dffrecordheader.hxx>
+
+namespace ppt
+{
+class Atom
+{
+public:
+ ~Atom();
+
+ /** imports this atom and its child atoms */
+ static Atom* import(const DffRecordHeader& rRootRecordHeader, SvStream& rStCtrl);
+
+ /** @return true if at least one atom with the given nRecType is found */
+ inline bool hasChildAtom(sal_uInt16 nRecType) const;
+
+ /** @return the first child atom with nRecType or NULL */
+ inline const Atom* findFirstChildAtom(sal_uInt16 nRecType) const;
+
+ /** @return the next child atom after pLast with nRecType or NULL */
+ const Atom* findNextChildAtom(sal_uInt16 nRecType, const Atom* pLast) const;
+
+ /** @return the first child atom or NULL */
+ inline const Atom* findFirstChildAtom() const;
+
+ /** @return the next child atom after pLast or NULL */
+ static inline const Atom* findNextChildAtom(const Atom* pLast);
+
+ /** @return true if this atom is a container */
+ inline bool isContainer() const;
+
+ /** seeks to the contents of this atom */
+ inline bool seekToContent() const;
+
+ /** @return the record type */
+ inline sal_uInt16 getType() const;
+
+ /** @return the record instance */
+ inline sal_uInt16 getInstance() const;
+
+ /** @return the record length */
+ inline sal_uInt32 getLength() const;
+
+private:
+ Atom(const DffRecordHeader& rRecordHeader, SvStream& rStCtrl);
+
+ SvStream& mrStream;
+ DffRecordHeader maRecordHeader;
+ Atom* mpFirstChild;
+ Atom* mpNextAtom;
+};
+
+inline bool Atom::hasChildAtom(sal_uInt16 nRecType) const
+{
+ return findFirstChildAtom(nRecType) != nullptr;
+}
+
+inline const Atom* Atom::findFirstChildAtom(sal_uInt16 nRecType) const
+{
+ return findNextChildAtom(nRecType, nullptr);
+}
+
+inline const Atom* Atom::findFirstChildAtom() const { return mpFirstChild; }
+
+inline const Atom* Atom::findNextChildAtom(const Atom* pLast)
+{
+ return pLast ? pLast->mpNextAtom : pLast;
+}
+
+inline bool Atom::isContainer() const { return maRecordHeader.IsContainer(); }
+
+inline bool Atom::seekToContent() const
+{
+ maRecordHeader.SeekToContent(mrStream);
+ return mrStream.GetError() == ERRCODE_NONE;
+}
+
+inline sal_uInt16 Atom::getType() const { return maRecordHeader.nRecType; }
+
+inline sal_uInt16 Atom::getInstance() const { return maRecordHeader.nRecInstance; }
+
+inline sal_uInt32 Atom::getLength() const { return maRecordHeader.nRecLen; }
+
+} // namespace ppt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/pptin.cxx b/sd/source/filter/ppt/pptin.cxx
new file mode 100644
index 000000000..305e1813a
--- /dev/null
+++ b/sd/source/filter/ppt/pptin.cxx
@@ -0,0 +1,2821 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/file.hxx>
+#include <sal/log.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <svl/urihelper.hxx>
+#include <svx/svxids.hrc>
+#include <filter/msfilter/svdfppt.hxx>
+#include <svx/svditer.hxx>
+#include <sfx2/docfile.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdlayer.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdtmfitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svl/style.hxx>
+#include <svl/intitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editeng.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+
+#include <sfx2/docinf.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include "pptin.hxx"
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <pres.hxx>
+#include <stlpool.hxx>
+#include <anminfo.hxx>
+#include <svx/gallery.hxx>
+#include <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/svdomedia.hxx>
+#include <svx/svdogrp.hxx>
+#include "propread.hxx"
+#include <cusshow.hxx>
+#include <xmloff/autolayout.hxx>
+
+#include <customshowlist.hxx>
+#include <sddll.hxx>
+
+#include <DrawDocShell.hxx>
+#include <FrameView.hxx>
+#include <unokywds.hxx>
+
+#include <unotools/fltrcfg.hxx>
+#include <sfx2/progress.hxx>
+#include <editeng/editstat.hxx>
+#include <unotools/pathoptions.hxx>
+
+#define MAX_USER_MOVE 2
+
+#include "pptanimations.hxx"
+#include "pptinanimations.hxx"
+#include "ppt97animations.hxx"
+
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <comphelper/string.hxx>
+#include <oox/ole/olehelper.hxx>
+
+#include <optional>
+
+#include <cassert>
+#include <memory>
+#include <string_view>
+
+using namespace ::com::sun::star;
+
+SdPPTImport::SdPPTImport( SdDrawDocument* pDocument, SvStream& rDocStream, SotStorage& rStorage, SfxMedium& rMedium )
+ : maParam(rDocStream)
+{
+#ifdef DBG_UTIL
+ std::unique_ptr<PropRead> pSummaryInformation(new PropRead( rStorage, "\005SummaryInformation" ));
+ if ( pSummaryInformation->IsValid() )
+ {
+ pSummaryInformation->Read();
+ sal_uInt8 const aPropSetGUID[ 16 ]
+ {
+ 0xe0, 0x85, 0x9f, 0xf2, 0xf9, 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9
+ };
+ Section* pSection = const_cast<Section*>(pSummaryInformation->GetSection( aPropSetGUID ));
+ if ( pSection )
+ {
+ PropItem aPropItem;
+ if ( pSection->GetProperty( PID_COMMENTS, aPropItem ) )
+ {
+ OUString aComment;
+ aPropItem.Read( aComment );
+ if ( aComment.indexOf( "Applixware" ) >= 0 )
+ {
+ maParam.nImportFlags |= PPT_IMPORTFLAGS_NO_TEXT_ASSERT;
+ }
+ }
+ }
+ }
+ pSummaryInformation.reset();
+#endif
+
+ tools::SvRef<SotStorageStream> pCurrentUserStream(rStorage.OpenSotStream("Current User", StreamMode::STD_READ));
+ if (pCurrentUserStream)
+ {
+ ReadPptCurrentUserAtom(*pCurrentUserStream, maParam.aCurrentUserAtom);
+ }
+
+ if( pDocument )
+ {
+ // iterate over all styles
+ SdStyleSheetPool* pStyleSheetPool = pDocument->GetSdStyleSheetPool();
+ std::shared_ptr<SfxStyleSheetIterator> aIter =
+ std::make_shared<SfxStyleSheetIterator>(pStyleSheetPool, SfxStyleFamily::All);
+
+ for (SfxStyleSheetBase *pSheet = aIter->First(); pSheet; pSheet = aIter->Next())
+ {
+ SfxItemSet& rSet = pSheet->GetItemSet();
+ // if autokerning is set in style, override it, ppt has no autokerning
+ if( rSet.GetItemState( EE_CHAR_PAIRKERNING, false ) == SfxItemState::SET )
+ rSet.ClearItem( EE_CHAR_PAIRKERNING );
+ }
+ }
+
+ pFilter.reset(new ImplSdPPTImport(pDocument, rStorage, rMedium, maParam));
+}
+
+bool SdPPTImport::Import()
+{
+ return pFilter->Import();
+}
+
+SdPPTImport::~SdPPTImport()
+{
+}
+
+ImplSdPPTImport::ImplSdPPTImport( SdDrawDocument* pDocument, SotStorage& rStorage_, SfxMedium& rMedium, PowerPointImportParam& rParam )
+ : SdrPowerPointImport(rParam, rMedium.GetBaseURL())
+ , mrMed(rMedium)
+ , mrStorage(rStorage_)
+ , mbDocumentFound(false)
+ , mnFilterOptions(0)
+ , mpDoc(pDocument)
+ , mePresChange(PresChange::Manual)
+ , mnBackgroundObjectsLayerID(0)
+{
+ if ( !m_bOk )
+ return;
+
+ mbDocumentFound = SeekToDocument( &maDocHd ); // maDocHd = the latest DocumentHeader
+ while ( SeekToRec( rStCtrl, PPT_PST_Document, nStreamLen, &maDocHd ) )
+ mbDocumentFound = true;
+
+ sal_uInt32 nDggContainerOfs = 0;
+
+ if ( mbDocumentFound )
+ {
+ sal_uInt64 nOldPos = rStCtrl.Tell();
+
+ mxPicturesStream = rStorage_.OpenSotStream( "Pictures", StreamMode::STD_READ );
+ pStData = mxPicturesStream.get();
+
+ rStCtrl.Seek( maDocHd.GetRecBegFilePos() + 8 );
+ sal_uLong nDocLen = maDocHd.GetRecEndFilePos();
+ DffRecordHeader aPPDGHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_PPDrawingGroup, nDocLen, &aPPDGHd ) )
+ {
+ sal_uLong nPPDGLen = aPPDGHd.GetRecEndFilePos();
+ if ( SeekToRec( rStCtrl, DFF_msofbtDggContainer, nPPDGLen ) )
+ nDggContainerOfs = rStCtrl.Tell();
+ }
+ rStCtrl.Seek( nOldPos );
+ }
+ sal_uInt32 nSvxMSDffOLEConvFlags2 = 0;
+
+ const SvtFilterOptions& rBasOpt = SvtFilterOptions::Get();
+ if ( rBasOpt.IsLoadPPointBasicCode() )
+ mnFilterOptions |= 1;
+ if ( rBasOpt.IsMathType2Math() )
+ nSvxMSDffOLEConvFlags2 |= OLE_MATHTYPE_2_STARMATH;
+ if ( rBasOpt.IsWinWord2Writer() )
+ nSvxMSDffOLEConvFlags2 |= OLE_WINWORD_2_STARWRITER;
+ if ( rBasOpt.IsExcel2Calc() )
+ nSvxMSDffOLEConvFlags2 |= OLE_EXCEL_2_STARCALC;
+ if ( rBasOpt.IsPowerPoint2Impress() )
+ nSvxMSDffOLEConvFlags2 |= OLE_POWERPOINT_2_STARIMPRESS;
+
+ InitSvxMSDffManager( nDggContainerOfs, pStData, nSvxMSDffOLEConvFlags2 );
+ SetSvxMSDffSettings( SVXMSDFF_SETTINGS_CROP_BITMAPS
+ | SVXMSDFF_SETTINGS_IMPORT_PPT );
+ SetModel( mpDoc, 576 );
+}
+
+// Dtor
+ImplSdPPTImport::~ImplSdPPTImport()
+{
+ pStData = nullptr;
+ mxPicturesStream.clear();
+}
+
+// Import
+bool ImplSdPPTImport::Import()
+{
+ if ( !m_bOk )
+ return false;
+
+ bool bWasLocked = pSdrModel->isLocked();
+ pSdrModel->setLock(true);
+ const bool bSavedUndoEnabled = pSdrModel->IsUndoEnabled();
+ pSdrModel->EnableUndo(false);
+
+ SdrOutliner& rOutl = mpDoc->GetDrawOutliner();
+ EEControlBits nControlWord = rOutl.GetEditEngine().GetControlWord();
+ nControlWord |= EEControlBits::ULSPACESUMMATION;
+ const_cast<EditEngine&>(rOutl.GetEditEngine()).SetControlWord( nControlWord );
+
+ SdrLayerAdmin& rAdmin = mpDoc->GetLayerAdmin();
+ mnBackgroundObjectsLayerID = rAdmin.GetLayerID( sUNO_LayerName_background_objects );
+
+ ::sd::DrawDocShell* pDocShell = mpDoc->GetDocSh();
+ if ( pDocShell )
+ SeekOle( pDocShell, mnFilterOptions );
+
+ // hyperlinks
+ std::unique_ptr<PropRead> pDInfoSec2(new PropRead( mrStorage, "\005DocumentSummaryInformation" ));
+ if ( pDInfoSec2->IsValid() )
+ {
+ PropItem aPropItem;
+
+ sal_uInt32 nType(0), nPropCount(0);
+
+ pDInfoSec2->Read();
+
+ sal_uInt8 const aPropSetGUID[ 16 ]
+ {
+ 0x02, 0xd5, 0xcd, 0xd5, 0x9c, 0x2e, 0x1b, 0x10, 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae
+ };
+ Section* pSection = const_cast<Section*>(pDInfoSec2->GetSection( aPropSetGUID ));
+ if ( pSection )
+ {
+ if ( pSection->GetProperty( PID_SLIDECOUNT, aPropItem ) )
+ {
+ aPropItem.ReadUInt32( nType );
+ if ( ( nType == VT_I4 ) || ( nType == VT_UI4 ) )
+ {
+ // examine PID_HEADINGPAIR to get the correct entry for PID_DOCPARTS
+ sal_uInt32 nSlideCount(0), nVecCount(0);
+ aPropItem.ReadUInt32( nSlideCount );
+ if ( nSlideCount && pSection->GetProperty( PID_HEADINGPAIR, aPropItem ) )
+ {
+ sal_uInt32 nSlideTitleIndex = 0, nSlideTitleCount = 0;
+
+ OUString aUString;
+
+ aPropItem.ReadUInt32( nType )
+ .ReadUInt32( nVecCount );
+
+ if ( ( nType == ( VT_VARIANT | VT_VECTOR ) ) && ( nVecCount ^ 1 ) )
+ {
+ nVecCount >>= 1;
+ sal_uInt32 nEntryCount = 0;
+ for (sal_uInt32 i = 0; i < nVecCount; ++i)
+ {
+ if ( !aPropItem.Read( aUString, VT_EMPTY, false ) )
+ break;
+ aPropItem.ReadUInt32( nType );
+ if ( ( nType != VT_I4 ) && ( nType != VT_UI4 ) )
+ break;
+ sal_uInt32 nTemp(0);
+ aPropItem.ReadUInt32( nTemp );
+ if ( aUString == "Slide Titles" || aUString == "Folientitel" )
+ {
+ nSlideTitleCount = nTemp;
+ nSlideTitleIndex = nEntryCount;
+ }
+ nEntryCount += nTemp;
+ }
+ }
+ if ( ( nSlideCount == nSlideTitleCount ) && pSection->GetProperty( PID_DOCPARTS, aPropItem ) )
+ {
+ aPropItem.ReadUInt32( nType )
+ .ReadUInt32( nVecCount );
+
+ bool bVecOk = ( ( nVecCount >= (nSlideTitleIndex + nSlideTitleCount) )
+ && ( nType == ( VT_LPSTR | VT_VECTOR ) ) );
+
+ if (bVecOk)
+ {
+ for (sal_uInt32 i = 0; i != nSlideTitleIndex; ++i)
+ {
+ sal_uInt32 nTemp(0);
+ aPropItem.ReadUInt32(nTemp);
+ if (!aPropItem.good())
+ {
+ bVecOk = false;
+ break;
+ }
+ auto nPos = aPropItem.Tell() + nTemp;
+ if (!checkSeek(aPropItem, nPos))
+ {
+ bVecOk = false;
+ break;
+ }
+ }
+ }
+ if (bVecOk)
+ {
+ for (sal_uInt32 i = 0; i < nSlideTitleCount; ++i)
+ {
+ if (!aPropItem.Read(aUString, nType, false))
+ break;
+
+ OUString aString( aUString );
+ if ( aString == "No Slide Title" )
+ aString.clear();
+ else
+ {
+ std::vector<OUString>::const_iterator pIter =
+ std::find(maSlideNameList.begin(),maSlideNameList.end(),aString);
+
+ if (pIter != maSlideNameList.end())
+ aString.clear();
+ }
+ maSlideNameList.push_back( aString );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ sal_uInt8 const aUserPropSetGUID[ 16 ]
+ {
+ 0x05, 0xd5, 0xcd, 0xd5, 0x9c, 0x2e, 0x1b, 0x10, 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae
+ };
+ pSection = const_cast<Section*>(pDInfoSec2->GetSection( aUserPropSetGUID ));
+ if ( pSection )
+ {
+ PropDictionary aDict;
+ pSection->GetDictionary(aDict);
+ if (!aDict.empty())
+ {
+ auto iter = aDict.find( OUString("_PID_HLINKS") );
+
+ if ( iter != aDict.end() )
+ {
+ if ( pSection->GetProperty( iter->second, aPropItem ) )
+ {
+ aPropItem.Seek( STREAM_SEEK_TO_BEGIN );
+ aPropItem.ReadUInt32( nType );
+ if ( nType == VT_BLOB )
+ {
+ sal_uInt32 nPropSize;
+ aPropItem.ReadUInt32( nPropSize )
+ .ReadUInt32( nPropCount );
+
+ if ( ! ( nPropCount % 6 ) )
+ {
+ sal_uInt32 i;
+
+ nPropCount /= 6; // 6 properties per hyperlink
+
+ for ( i = 0; i < nPropCount; i++ )
+ {
+ SdHyperlinkEntry aHyperlink;
+ aHyperlink.nIndex = 0;
+ aPropItem.ReadUInt32( nType );
+ if ( nType != VT_I4 )
+ break;
+ aPropItem.ReadInt32( aHyperlink.nPrivate1 )
+ .ReadUInt32( nType );
+ if ( nType != VT_I4 )
+ break;
+ aPropItem.ReadInt32( aHyperlink.nPrivate2 )
+ .ReadUInt32( nType );
+ if ( nType != VT_I4 )
+ break;
+ aPropItem.ReadInt32( aHyperlink.nPrivate3 )
+ .ReadUInt32( nType );
+ if ( nType != VT_I4 )
+ break;
+ aPropItem.ReadInt32( aHyperlink.nInfo );
+ if ( !aPropItem.Read( aHyperlink.aTarget ) )
+ break;
+
+ // Convert '\\' notation to 'smb://'
+ INetURLObject aUrl( aHyperlink.aTarget, INetProtocol::File );
+ aHyperlink.aTarget = aUrl.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ if ( !aPropItem.Read( aHyperlink.aSubAddress ) )
+ break;
+
+ if ( !aHyperlink.aSubAddress.isEmpty() ) // get the converted subaddress
+ {
+ sal_uInt32 nPageNumber = 0;
+ OUString aString( aHyperlink.aSubAddress );
+ OString aStringAry[ 3 ];
+ size_t nTokenCount = 0;
+ sal_Int32 nPos = 0;
+ do
+ {
+ aStringAry[nTokenCount] =
+ OUStringToOString(o3tl::getToken(aString, 0, ',', nPos ), RTL_TEXTENCODING_UTF8);
+ }
+ while ( ++nTokenCount < SAL_N_ELEMENTS(aStringAry) && nPos >= 0 );
+
+ bool bDocInternalSubAddress = false;
+
+ // first pass, searching for a SlideId
+ for( size_t nToken = 0; nToken < nTokenCount; ++nToken )
+ {
+ if (comphelper::string::isdigitAsciiString(aStringAry[nToken]))
+ {
+ sal_Int32 nNumber = aStringAry[ nToken ].toInt32();
+ if ( nNumber & ~0xff )
+ {
+ PptSlidePersistList* pPageList = GetPageList( PPT_SLIDEPAGE );
+ if ( pPageList )
+ {
+ sal_uInt16 nPage = pPageList->FindPage( nNumber );
+ if ( nPage != PPTSLIDEPERSIST_ENTRY_NOTFOUND )
+ {
+ nPageNumber = nPage;
+ bDocInternalSubAddress = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if ( !bDocInternalSubAddress )
+ { // second pass, searching for a SlideName
+ for ( size_t nToken = 0; nToken < nTokenCount; ++nToken )
+ {
+ OUString aToken(OStringToOUString(aStringAry[nToken], RTL_TEXTENCODING_UTF8));
+ std::vector<OUString>::const_iterator pIter =
+ std::find(maSlideNameList.begin(),maSlideNameList.end(),aToken);
+
+ if (pIter != maSlideNameList.end())
+ {
+ nPageNumber = pIter - maSlideNameList.begin();
+ bDocInternalSubAddress = true;
+ }
+ }
+ }
+ if ( !bDocInternalSubAddress )
+ { // third pass, searching for a slide number
+ for ( size_t nToken = 0; nToken < nTokenCount; ++nToken )
+ {
+ if (comphelper::string::isdigitAsciiString(aStringAry[nToken]))
+ {
+ sal_Int32 nNumber = aStringAry[ nToken ].toInt32();
+ if ( ( nNumber & ~0xff ) == 0 )
+ {
+ nPageNumber = static_cast<sal_uInt32>(nNumber) - 1;
+ bDocInternalSubAddress = true;
+ break;
+ }
+ }
+ }
+ }
+ // if a document internal sub address
+ if ( bDocInternalSubAddress )
+ {
+ if ( nPageNumber < maSlideNameList.size() )
+ aHyperlink.aConvSubString = maSlideNameList[ nPageNumber ];
+ if ( aHyperlink.aConvSubString.isEmpty() )
+ {
+ aHyperlink.aConvSubString = SdResId( STR_PAGE ) + " " + mpDoc->CreatePageNumValue( static_cast<sal_uInt16>(nPageNumber) + 1 );
+ }
+ } else {
+ // if sub address is given but not internal, use it as it is
+ if ( aHyperlink.aConvSubString.isEmpty() )
+ {
+ aHyperlink.aConvSubString = aString;
+ }
+ }
+ }
+ m_aHyperList.push_back( aHyperlink );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ pDInfoSec2.reset();
+
+ if ( mbDocumentFound )
+ {
+ rStCtrl.Seek( maDocHd.GetRecBegFilePos() + 8 );
+ // read hyperlist / set indices of the entries
+ DffRecordHeader aHyperHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_ExObjList, maDocHd.GetRecEndFilePos(), &aHyperHd ) )
+ {
+ sal_uInt32 nExObjHyperListLen = aHyperHd.GetRecEndFilePos();
+ for (SdHyperlinkEntry & entry : m_aHyperList)
+ {
+ DffRecordHeader aHyperE;
+ if ( !SeekToRec( rStCtrl, PPT_PST_ExHyperlink, nExObjHyperListLen, &aHyperE ) )
+ break;
+ if ( !SeekToRec( rStCtrl, PPT_PST_ExHyperlinkAtom, nExObjHyperListLen ) )
+ break;
+ rStCtrl.SeekRel( 8 );
+ rStCtrl.ReadUInt32( entry.nIndex );
+ if (!aHyperE.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+
+ if (m_aHyperList.size() == 0)
+ {
+ while(true)
+ {
+
+ DffRecordHeader aHyperE;
+ if (!SeekToRec(rStCtrl, PPT_PST_ExHyperlink, nExObjHyperListLen, &aHyperE))
+ break;
+ if (!SeekToRec(rStCtrl, PPT_PST_ExHyperlinkAtom, nExObjHyperListLen))
+ continue;
+
+ SdHyperlinkEntry aHyperlink;
+
+ OUString aURLText;
+ OUString aURLLink;
+ rStCtrl.SeekRel(8);
+ rStCtrl.ReadUInt32(aHyperlink.nIndex);
+
+ ReadString(aURLText);
+ ReadString(aURLLink);
+ aHyperlink.aTarget = aURLLink;
+ m_aHyperList.push_back(aHyperlink);
+ }
+ }
+ }
+ }
+
+ if (pDocShell)
+ {
+ Size aVisAreaSize;
+ switch ( m_aUserEditAtom.eLastViewType )
+ {
+ case PptViewTypeEnum::Notes:
+ case PptViewTypeEnum::NotesMaster:
+ aVisAreaSize = aDocAtom.GetNotesPageSize();
+ break;
+ default :
+ aVisAreaSize = aDocAtom.GetSlidesPageSize();
+ }
+ Scale( aVisAreaSize );
+ pDocShell->SetVisArea( ::tools::Rectangle( Point(), aVisAreaSize ) );
+ }
+
+ // create master pages:
+
+ std::unique_ptr<SfxProgress> xStbMgr;
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ xStbMgr.reset(new SfxProgress(pDocShell,
+ SdResId( STR_POWERPOINT_IMPORT),
+ m_pMasterPages->size() +
+ m_pSlidePages->size() + m_pNotePages->size()));
+ }
+
+ sal_uInt32 nImportedPages = 0;
+ {
+ sal_uInt16 nMasterCnt = GetPageCount( PPT_MASTERPAGE );
+
+ for ( sal_uInt16 nMasterNum = 0; nMasterNum < nMasterCnt; nMasterNum++ )
+ {
+ SetPageNum( nMasterNum, PPT_MASTERPAGE );
+ rtl::Reference<SdPage> pPage = static_cast<SdPage*>(MakeBlankPage( true ).get());
+ if ( pPage )
+ {
+ bool bNotesMaster = (*GetPageList( m_eCurrentPageKind ) )[ m_nCurrentPageNum ].bNotesMaster;
+ bool bStarDrawFiller = (*GetPageList( m_eCurrentPageKind ) )[ m_nCurrentPageNum ].bStarDrawFiller;
+
+ PageKind ePgKind = bNotesMaster ? PageKind::Notes : PageKind::Standard;
+ bool bHandout = (*GetPageList( m_eCurrentPageKind ) )[ m_nCurrentPageNum ].bHandoutMaster;
+ if ( bHandout )
+ ePgKind = PageKind::Handout;
+
+ pPage->SetPageKind( ePgKind );
+ pSdrModel->InsertMasterPage( pPage.get() );
+ if ( bNotesMaster && bStarDrawFiller )
+ pPage->SetAutoLayout( AUTOLAYOUT_NOTES, true );
+ if ( nMasterNum )
+ {
+ std::optional< sal_Int16 > oStartNumbering;
+ SfxStyleSheet* pSheet;
+ if ( nMasterNum == 1 )
+ {
+ // standardsheet
+ pSheet = static_cast<SfxStyleSheet*>(mpDoc->GetStyleSheetPool()->Find(SdResId(STR_STANDARD_STYLESHEET_NAME), SfxStyleFamily::Para ));
+ if ( pSheet )
+ {
+ SfxItemSet& rItemSet = pSheet->GetItemSet();
+ PPTParagraphObj aParagraph( *m_pPPTStyleSheet, TSS_Type::TextInShape, 0 );
+ PPTPortionObj aPortion( *m_pPPTStyleSheet, TSS_Type::TextInShape, 0 );
+ aParagraph.AppendPortion( aPortion );
+ aParagraph.ApplyTo( rItemSet, oStartNumbering, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ aPortion.ApplyTo( rItemSet, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ }
+ }
+
+ // PSEUDO
+ pSheet = static_cast<SfxStyleSheet*>(mpDoc->GetStyleSheetPool()->Find(SdResId(STR_PSEUDOSHEET_BACKGROUNDOBJECTS), SfxStyleFamily::Pseudo ));
+ if ( pSheet )
+ {
+ SfxItemSet& rItemSet = pSheet->GetItemSet();
+ PPTParagraphObj aParagraph( *m_pPPTStyleSheet, TSS_Type::TextInShape, 0 );
+ PPTPortionObj aPortion( *m_pPPTStyleSheet, TSS_Type::TextInShape, 0 );
+ aParagraph.AppendPortion( aPortion );
+ aParagraph.ApplyTo( rItemSet, oStartNumbering, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ aPortion.ApplyTo( rItemSet, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ }
+
+ // create layoutstylesheets, set layoutname and stylesheet
+ // (only on standard and not pages)
+
+ OUString aLayoutName( SdResId( STR_LAYOUT_DEFAULT_NAME ) );
+ if ( nMasterNum > 2 )
+ {
+ if ( ePgKind == PageKind::Standard )
+ { // standard page: create new presentation layout
+ aLayoutName = SdResId( STR_LAYOUT_DEFAULT_TITLE_NAME ) +
+ OUString::number( static_cast<sal_Int32>( ( nMasterNum + 1 ) / 2 - 1 ) );
+ static_cast<SdStyleSheetPool*>( mpDoc->GetStyleSheetPool() )->CreateLayoutStyleSheets( aLayoutName );
+ }
+ else // note page: use presentation layout of standard page
+ aLayoutName = static_cast<SdPage*>( mpDoc->GetMasterPage( nMasterNum - 1 ) )->GetName();
+ }
+ pPage->SetName( aLayoutName );
+ aLayoutName += SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE;
+ pPage->SetLayoutName( aLayoutName );
+
+ // set stylesheets
+ if ( pPage->GetPageKind() == PageKind::Standard )
+ {
+ TSS_Type nTitleInstance = TSS_Type::PageTitle;
+ TSS_Type nOutlinerInstance = TSS_Type::Body;
+ const PptSlideLayoutAtom* pSlideLayout = GetSlideLayoutAtom();
+ bool bSwapStyleSheet = pSlideLayout->eLayout == PptSlideLayout::TITLEMASTERSLIDE;
+ if ( bSwapStyleSheet )
+ {
+ nTitleInstance = TSS_Type::Title;
+ nOutlinerInstance = TSS_Type::Subtitle;
+ }
+
+ // titlestylesheet
+ pSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Title );
+ if ( pSheet )
+ {
+ SfxItemSet& rItemSet = pSheet->GetItemSet();
+ PPTParagraphObj aParagraph( *m_pPPTStyleSheet, nTitleInstance, 0 );
+ PPTPortionObj aPortion( *m_pPPTStyleSheet, nTitleInstance, 0 );
+ aParagraph.AppendPortion( aPortion );
+ aParagraph.ApplyTo( rItemSet, oStartNumbering, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ aPortion.ApplyTo( rItemSet, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ }
+
+ // outlinerstylesheet
+ sal_uInt16 nLevel;
+ PPTParagraphObj* pParagraphs[ 9 ];
+
+ for ( nLevel = 0; nLevel < 9; nLevel++ )
+ {
+ OUString aName = pPage->GetLayoutName() +
+ " " + OUString::number( nLevel + 1 );
+ SfxStyleSheet* pOutlineSheet = static_cast<SfxStyleSheet*>( mpDoc->GetStyleSheetPool()->Find( aName, SfxStyleFamily::Page ) );
+ DBG_ASSERT( pOutlineSheet, "Template for outline object not found" );
+ if ( pOutlineSheet )
+ {
+ pParagraphs[ nLevel ] = new PPTParagraphObj( *m_pPPTStyleSheet, nOutlinerInstance, nLevel );
+ SfxItemSet& rItemSet = pOutlineSheet->GetItemSet();
+ PPTPortionObj aPortion( *m_pPPTStyleSheet, nOutlinerInstance, nLevel );
+ pParagraphs[ nLevel ]->AppendPortion( aPortion );
+ pParagraphs[ nLevel ]->ApplyTo( rItemSet, oStartNumbering, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ aPortion.ApplyTo( rItemSet, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ }
+ else
+ pParagraphs[ nLevel ] = nullptr;
+ }
+ for ( nLevel = 0; nLevel < 9; delete pParagraphs[ nLevel++ ] ) ;
+
+ // subtitle stylesheet
+ pSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Text );
+ if ( pSheet )
+ {
+ SfxItemSet& rItemSet = pSheet->GetItemSet();
+ PPTParagraphObj aParagraph( *m_pPPTStyleSheet, TSS_Type::Subtitle, 0 );
+ PPTPortionObj aPortion( *m_pPPTStyleSheet, TSS_Type::Subtitle, 0 );
+ aParagraph.AppendPortion( aPortion );
+ aParagraph.ApplyTo( rItemSet, oStartNumbering, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ aPortion.ApplyTo( rItemSet, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ }
+ }
+ else if ( ePgKind == PageKind::Notes )
+ {
+ pSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Notes );
+ if ( pSheet )
+ {
+ SfxItemSet& rItemSet = pSheet->GetItemSet();
+ PPTParagraphObj aParagraph( *m_pPPTStyleSheet, TSS_Type::Notes, 0 );
+ PPTPortionObj aPortion( *m_pPPTStyleSheet, TSS_Type::Notes, 0 );
+ aParagraph.AppendPortion( aPortion );
+ aParagraph.ApplyTo( rItemSet, oStartNumbering, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ aPortion.ApplyTo( rItemSet, static_cast<SdrPowerPointImport&>(*this), TSS_Type::Unknown );
+ }
+ }
+ }
+ }
+ }
+ }
+ for (sal_uInt16 i = 0; i < mpDoc->GetMasterPageCount(); ++i)
+ {
+ SdPage *const pMPage(static_cast<SdPage*>(mpDoc->GetMasterPage(i)));
+ if (pMPage == nullptr)
+ break;
+ SetPageNum( i, PPT_MASTERPAGE );
+
+ // importing master page objects
+ PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind );
+ PptSlidePersistEntry* pPersist = ( pList && ( m_nCurrentPageNum < pList->size() ) )
+ ? &(*pList)[ m_nCurrentPageNum ] : nullptr;
+ if ( pPersist )
+ {
+ if ( pPersist->bStarDrawFiller && pPersist->bNotesMaster && ( m_nCurrentPageNum > 2 ) && ( ( m_nCurrentPageNum & 1 ) == 0 ) )
+ {
+ pSdrModel->DeleteMasterPage( m_nCurrentPageNum );
+ SdPage* pMasterPage2 = static_cast<SdPage*>(pSdrModel->GetMasterPage( 2 ));
+ rtl::Reference<SdPage> pNotesClone = static_cast<SdPage*>(pMasterPage2->CloneSdrPage(*pSdrModel).get());
+ pSdrModel->InsertMasterPage( pNotesClone.get(), m_nCurrentPageNum );
+ if ( pNotesClone )
+ {
+ OUString aLayoutName( static_cast<SdPage*>(pSdrModel->GetMasterPage( m_nCurrentPageNum - 1 ))->GetLayoutName() );
+ pNotesClone->SetPresentationLayout( aLayoutName, false, false );
+ pNotesClone->SetLayoutName( aLayoutName );
+ }
+ }
+ else if ( !pPersist->bStarDrawFiller )
+ {
+ PptSlidePersistEntry* pE = pPersist;
+ while( ( pE->aSlideAtom.nFlags & 4 ) && pE->aSlideAtom.nMasterId )
+ {
+ auto nOrigMasterId = pE->aSlideAtom.nMasterId;
+ sal_uInt16 nNextMaster = m_pMasterPages->FindPage(nOrigMasterId);
+ if ( nNextMaster == PPTSLIDEPERSIST_ENTRY_NOTFOUND )
+ break;
+ else
+ pE = &(*pList)[ nNextMaster ];
+ if (pE->aSlideAtom.nMasterId == nOrigMasterId)
+ {
+ SAL_WARN("filter.ms", "loop in atom chain");
+ break;
+ }
+ }
+ SdrObject* pObj = ImportPageBackgroundObject( *pMPage, pE->nBackgroundOffset ); // import background
+ if ( pObj )
+ pMPage->NbcInsertObject( pObj );
+
+ bool bNewAnimationsUsed = false;
+ ProcessData aProcessData( (*pList)[ m_nCurrentPageNum ], SdPageCapsule(pMPage) );
+ sal_uInt32 nOldFPos = rStCtrl.Tell();
+ DffRecordHeader aPageHd;
+ if ( SeekToCurrentPage( &aPageHd ) )
+ {
+ auto nEndRecPos = SanitizeEndPos(rStCtrl, aPageHd.GetRecEndFilePos());
+ while( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) )
+ {
+ DffRecordHeader aHd;
+ if (!ReadDffRecordHeader( rStCtrl, aHd ))
+ break;
+ switch( aHd.nRecType )
+ {
+ case PPT_PST_PPDrawing :
+ {
+ aHd.SeekToBegOfRecord( rStCtrl );
+ DffRecordHeader aPPDrawHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_PPDrawing, aHd.GetRecEndFilePos(), &aPPDrawHd ) )
+ {
+ sal_uInt32 nPPDrawEnd = aPPDrawHd.GetRecEndFilePos();
+ DffRecordHeader aEscherF002Hd;
+ if ( SeekToRec( rStCtrl, DFF_msofbtDgContainer, nPPDrawEnd, &aEscherF002Hd ) )
+ {
+ sal_uInt32 nEscherF002End = aEscherF002Hd.GetRecEndFilePos();
+ DffRecordHeader aEscherObjListHd;
+ if ( SeekToRec( rStCtrl, DFF_msofbtSpgrContainer, nEscherF002End, &aEscherObjListHd ) )
+ {
+ sal_uInt32 nObjCount = 0;
+ auto nListEndRecPos = SanitizeEndPos(rStCtrl, aEscherObjListHd.GetRecEndFilePos());
+ while( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nListEndRecPos ) )
+ {
+ DffRecordHeader aHd2;
+ ReadDffRecordHeader( rStCtrl, aHd2 );
+ if ( ( aHd2.nRecType == DFF_msofbtSpContainer ) || ( aHd2.nRecType == DFF_msofbtSpgrContainer ) )
+ {
+ if ( nObjCount++ ) // skipping the first object
+ {
+ ::tools::Rectangle aEmpty;
+ if (!aHd2.SeekToBegOfRecord(rStCtrl))
+ break;
+ SdrObject* pImpObj = ImportObj( rStCtrl, aProcessData, aEmpty, aEmpty, /*nCalledByGroup*/0, /*pShapeId*/ nullptr );
+ if ( pImpObj )
+ {
+ pImpObj->SetLayer( mnBackgroundObjectsLayerID );
+ pMPage->NbcInsertObject( pImpObj );
+ }
+ }
+ }
+ if (!aHd2.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case PPT_PST_ProgTags :
+ {
+ DffRecordHeader aProgTagHd;
+ if ( SeekToContentOfProgTag( 10, rStCtrl, aPageHd, aProgTagHd ) )
+ {
+ auto nTagEndRecPos = SanitizeEndPos(rStCtrl, aProgTagHd.GetRecEndFilePos());
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nTagEndRecPos ) )
+ {
+ DffRecordHeader aProgTagContentHd;
+ ReadDffRecordHeader( rStCtrl, aProgTagContentHd );
+ switch( aProgTagContentHd.nRecType )
+ {
+ case DFF_msofbtAnimGroup :
+ {
+ css::uno::Reference< css::drawing::XDrawPage > xPage( pMPage->getUnoPage(), css::uno::UNO_QUERY );
+ ppt::AnimationImporter aImporter( this, rStCtrl );
+ bNewAnimationsUsed = aImporter.import( xPage, aProgTagContentHd ) > 0;
+ }
+ break;
+ }
+ if (!aProgTagContentHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ }
+ }
+ break;
+ }
+ bool bSuccess = aHd.SeekToEndOfRecord(rStCtrl);
+ if (!bSuccess)
+ {
+ SAL_WARN("filter.ms", "Could not seek to end of record");
+ break;
+ }
+ }
+ }
+ rStCtrl.Seek( nOldFPos );
+ ImportPageEffect( pMPage, bNewAnimationsUsed );
+
+ // background object
+ pObj = pMPage->GetObj( 0 );
+ if ( pObj && pObj->GetObjIdentifier() == SdrObjKind::Rectangle )
+ {
+ if ( pMPage->GetPageKind() == PageKind::Standard )
+ {
+ // transform data from imported background object to new form
+ // and delete the object. It was used as container to transport
+ // the attributes of the MasterPage background fill
+ SfxStyleSheet* pSheet = pMPage->GetStyleSheetForMasterPageBackground();
+
+ if(pSheet)
+ {
+ // if we have a StyleSheet (for Masterpages), set attributes there and use it
+ pSheet->GetItemSet().ClearItem();
+ pSheet->GetItemSet().Put(pObj->GetMergedItemSet());
+ pMPage->getSdrPageProperties().ClearItem();
+ pMPage->getSdrPageProperties().SetStyleSheet(pSheet);
+ }
+ else
+ {
+ // without StyleSheet, set attributes directly. This
+ // should not be done at all and is an error (will be asserted by SdrPage)
+ pMPage->getSdrPageProperties().ClearItem();
+ pMPage->getSdrPageProperties().PutItemSet(pObj->GetMergedItemSet());
+ }
+
+ pMPage->RemoveObject(pObj->GetOrdNum());
+ SdrObject::Free(pObj);
+ }
+ }
+ }
+ }
+ if (xStbMgr)
+ xStbMgr->SetState( nImportedPages++ );
+ }
+
+ // importing slide pages
+ {
+ sal_uInt32 nOldFPos = rStCtrl.Tell();
+ PptPageKind ePageKind = m_eCurrentPageKind;
+ sal_uInt16 nPageNum = m_nCurrentPageNum;
+
+ rtl::Reference<SdPage> pHandoutPage = static_cast<SdPage*>(MakeBlankPage( false ).get());
+ pHandoutPage->SetPageKind( PageKind::Handout );
+ pSdrModel->InsertPage( pHandoutPage.get() );
+
+ sal_uInt16 nPageCnt = GetPageCount();
+ if ( nPageCnt )
+ {
+ for ( sal_uInt16 nPage = 0; nPage < nPageCnt; nPage++ )
+ {
+ mePresChange = PresChange::SemiAuto;
+ SetPageNum( nPage );
+ rtl::Reference<SdPage> pPage = static_cast<SdPage*>(MakeBlankPage( false ).get());
+ PptSlidePersistEntry* pMasterPersist = nullptr;
+ if ( HasMasterPage( nPage ) ) // try to get the LayoutName from the masterpage
+ {
+ sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind );
+ pPage->TRG_SetMasterPage(*pSdrModel->GetMasterPage(nMasterNum));
+ PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE );
+ if ( pPageList && nMasterNum < pPageList->size() )
+ pMasterPersist = &(*pPageList)[ nMasterNum ];
+ pPage->SetLayoutName(static_cast<SdPage&>(pPage->TRG_GetMasterPage()).GetLayoutName());
+ }
+ pPage->SetPageKind( PageKind::Standard );
+ pSdrModel->InsertPage( pPage.get() ); // SJ: #i29625# because of form controls, the
+ ImportPage( pPage.get(), pMasterPersist ); // page must be inserted before importing
+ SetHeaderFooterPageSettings( pPage.get(), pMasterPersist );
+ // CWS preseng01: pPage->SetPageKind( PageKind::Standard );
+
+ DffRecordHeader aPageHd;
+ if ( SeekToCurrentPage( &aPageHd ) )
+ {
+ bool bNewAnimationsUsed = false;
+
+ aPageHd.SeekToContent( rStCtrl );
+ auto nEndRecPos = SanitizeEndPos(rStCtrl, aPageHd.GetRecEndFilePos());
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) )
+ {
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rStCtrl, aHd );
+ switch ( aHd.nRecType )
+ {
+ case PPT_PST_ProgTags :
+ {
+ DffRecordHeader aProgTagHd;
+ if ( SeekToContentOfProgTag( 10, rStCtrl, aPageHd, aProgTagHd ) )
+ {
+ auto nHdEndRecPos = SanitizeEndPos(rStCtrl, aProgTagHd.GetRecEndFilePos());
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nHdEndRecPos ) )
+ {
+ DffRecordHeader aProgTagContentHd;
+ ReadDffRecordHeader( rStCtrl, aProgTagContentHd );
+ switch( aProgTagContentHd.nRecType )
+ {
+ case DFF_msofbtAnimGroup :
+ {
+ css::uno::Reference< css::drawing::XDrawPage > xPage( pPage->getUnoPage(), css::uno::UNO_QUERY );
+ ppt::AnimationImporter aImporter( this, rStCtrl );
+ bNewAnimationsUsed = aImporter.import( xPage, aProgTagContentHd ) > 0;
+ }
+ break;
+
+ case PPT_PST_HashCodeAtom : // ???
+ break;
+
+ case PPT_PST_SlideTime10Atom : // ??? don't know, this atom is always 8 bytes big
+ break; // and is appearing in nearly every l10 progtag
+ }
+ if (!aProgTagContentHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ }
+ }
+ break;
+
+ case PPT_PST_HeadersFooters :
+ case PPT_PST_PPDrawing :
+ default:
+ break;
+ }
+
+ if (!aHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ ImportPageEffect( pPage.get(), bNewAnimationsUsed );
+ }
+
+ // creating the corresponding note page
+ m_eCurrentPageKind = PPT_NOTEPAGE;
+ rtl::Reference<SdPage> pNotesPage = static_cast<SdPage*>(MakeBlankPage( false ).get());
+ sal_uInt16 nNotesMasterNum = GetMasterPageIndex( nPage ) + 1;
+ sal_uInt32 nNotesPageId = GetNotesPageId( nPage );
+ if ( nNotesPageId )
+ {
+ nImportedPages++;
+ sal_uInt16 nNotesPageIndex = m_pNotePages->FindPage( nNotesPageId );
+ if ( nNotesPageIndex == PPTSLIDEPERSIST_ENTRY_NOTFOUND )
+ nNotesPageIndex = 0;
+ SetPageNum( nNotesPageIndex, PPT_NOTEPAGE );
+ PptSlidePersistEntry* pMasterPersist2 = nullptr;
+ if ( HasMasterPage( nNotesPageIndex, PPT_NOTEPAGE ) ) // try to get the LayoutName from the masterpage
+ {
+ pNotesPage->TRG_SetMasterPage(*pSdrModel->GetMasterPage(nNotesMasterNum));
+ PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE );
+ if ( pPageList && nNotesMasterNum < pPageList->size() )
+ pMasterPersist2 = &(*pPageList)[ nNotesMasterNum ];
+ pNotesPage->SetLayoutName( static_cast<SdPage&>(pNotesPage->TRG_GetMasterPage()).GetLayoutName() );
+ }
+ pNotesPage->SetPageKind( PageKind::Notes );
+ pNotesPage->TRG_SetMasterPage(*pSdrModel->GetMasterPage(nNotesMasterNum));
+ pSdrModel->InsertPage( pNotesPage.get() ); // SJ: #i29625# because of form controls, the
+ ImportPage( pNotesPage.get(), pMasterPersist2 ); // page must be inserted before importing
+ SetHeaderFooterPageSettings( pNotesPage.get(), pMasterPersist2 );
+ pNotesPage->SetAutoLayout( AUTOLAYOUT_NOTES );
+ }
+ else
+ {
+ pNotesPage->SetPageKind( PageKind::Notes );
+ pNotesPage->TRG_SetMasterPage(*pSdrModel->GetMasterPage(nNotesMasterNum));
+ pNotesPage->SetAutoLayout( AUTOLAYOUT_NOTES, true );
+ pSdrModel->InsertPage( pNotesPage.get() );
+ SdrObject* pPageObj = pNotesPage->GetPresObj( PresObjKind::Page );
+ if ( pPageObj )
+ static_cast<SdrPageObj*>(pPageObj)->SetReferencedPage(pSdrModel->GetPage(( nPage << 1 ) + 1));
+ }
+
+ if (xStbMgr)
+ xStbMgr->SetState( nImportedPages++ );
+ }
+ }
+ else
+ {
+ // that can happen by document templates
+ m_eCurrentPageKind = PPT_SLIDEPAGE;
+ rtl::Reference<SdPage> pPage = static_cast<SdPage*>(MakeBlankPage( false ).get());
+ pSdrModel->InsertPage( pPage.get() );
+
+ // #i37397#, trying to set the title master for the first page
+ sal_uInt16 nMaster, nMasterCount = pSdrModel->GetMasterPageCount();
+ SdPage* pFoundMaster = nullptr;
+ for ( nMaster = 1; nMaster < nMasterCount; nMaster++ )
+ {
+ SdPage* pMaster = static_cast<SdPage*>( pSdrModel->GetMasterPage( nMaster ) );
+ if ( pMaster->GetPageKind() == PageKind::Standard )
+ {
+ SetPageNum( nMaster, PPT_MASTERPAGE );
+ if ( !pFoundMaster )
+ pFoundMaster = pMaster;
+ else if ( GetSlideLayoutAtom()->eLayout == PptSlideLayout::TITLEMASTERSLIDE )
+ pFoundMaster = pMaster;
+ if ( GetSlideLayoutAtom()->eLayout == PptSlideLayout::TITLEMASTERSLIDE )
+ break;
+ }
+ }
+ if ( pFoundMaster )
+ {
+ pPage->TRG_SetMasterPage( *pFoundMaster );
+ pPage->SetLayoutName( pFoundMaster->GetLayoutName() );
+ }
+ pPage->SetAutoLayout( AUTOLAYOUT_TITLE, true, true );
+
+ m_eCurrentPageKind = PPT_NOTEPAGE;
+ rtl::Reference<SdrPage> pNPage = MakeBlankPage( false );
+ pSdrModel->InsertPage( pNPage.get() );
+ }
+ SetPageNum( nPageNum, ePageKind );
+ rStCtrl.Seek( nOldFPos );
+ }
+
+ // create handout and note pages
+ m_bOk = mpDoc->CreateMissingNotesAndHandoutPages();
+ if ( m_bOk )
+ {
+ for ( sal_uInt16 i = 0; i < mpDoc->GetSdPageCount( PageKind::Standard ); i++ )
+ {
+
+ // set AutoLayout
+ SetPageNum( i );
+ SdPage* pPage = mpDoc->GetSdPage( i, PageKind::Standard );
+ AutoLayout eAutoLayout = AUTOLAYOUT_NONE;
+ const PptSlideLayoutAtom* pSlideLayout = GetSlideLayoutAtom();
+ if ( pSlideLayout )
+ {
+ switch ( pSlideLayout->eLayout ) // presentation layout for standard pages
+ {
+ case PptSlideLayout::TITLEANDBODYSLIDE :
+ {
+ eAutoLayout = AUTOLAYOUT_TITLE_CONTENT;
+ PptPlaceholder nID1 = pSlideLayout->aPlaceholderId[ 1 ];
+ switch ( nID1 )
+ {
+ case PptPlaceholder::BODY :
+ eAutoLayout = AUTOLAYOUT_TITLE_CONTENT;
+ break;
+ case PptPlaceholder::TABLE :
+ eAutoLayout = AUTOLAYOUT_TAB;
+ break;
+ case PptPlaceholder::ORGANISZATIONCHART :
+ eAutoLayout = AUTOLAYOUT_ORG;
+ break;
+ case PptPlaceholder::GRAPH :
+ eAutoLayout = AUTOLAYOUT_CHART;
+ break;
+ case PptPlaceholder::OBJECT :
+ eAutoLayout = AUTOLAYOUT_OBJ;
+ break;
+ case PptPlaceholder::VERTICALTEXTBODY :
+ eAutoLayout = AUTOLAYOUT_TITLE_VCONTENT;
+ break;
+ default: break;
+ }
+ }
+ break;
+
+ case PptSlideLayout::TWOCOLUMNSANDTITLE :
+ {
+ eAutoLayout = AUTOLAYOUT_TITLE_2CONTENT;
+ PptPlaceholder nID1 = pSlideLayout->aPlaceholderId[ 1 ];
+ PptPlaceholder nID2 = pSlideLayout->aPlaceholderId[ 2 ];
+ if ( nID1 == PptPlaceholder::BODY && nID2 == PptPlaceholder::GRAPH )
+ eAutoLayout = AUTOLAYOUT_TEXTCHART;
+ else if ( nID1 == PptPlaceholder::GRAPH && nID2 == PptPlaceholder::BODY )
+ eAutoLayout = AUTOLAYOUT_CHARTTEXT;
+ else if ( nID1 == PptPlaceholder::BODY && nID2 == PptPlaceholder::CLIPART )
+ eAutoLayout = AUTOLAYOUT_TEXTCLIP;
+ else if ( nID1 == PptPlaceholder::CLIPART && nID2 == PptPlaceholder::BODY )
+ eAutoLayout = AUTOLAYOUT_CLIPTEXT;
+ else if ( nID1 == PptPlaceholder::CLIPART && nID2 == PptPlaceholder::VERTICALTEXTBODY )
+ eAutoLayout = AUTOLAYOUT_TITLE_2VTEXT;
+ else if ( ( nID1 == PptPlaceholder::BODY )
+ && ( ( nID2 == PptPlaceholder::OBJECT ) || ( nID2 == PptPlaceholder::MEDIACLIP ) ) )
+ eAutoLayout = AUTOLAYOUT_TEXTOBJ;
+ else if ( ( nID2 == PptPlaceholder::BODY )
+ && ( ( nID1 == PptPlaceholder::OBJECT ) || ( nID1 == PptPlaceholder::MEDIACLIP ) ) )
+ eAutoLayout = AUTOLAYOUT_OBJTEXT;
+ else if ( ( nID1 == PptPlaceholder::OBJECT ) && ( nID2 == PptPlaceholder::OBJECT ) )
+ eAutoLayout = AUTOLAYOUT_OBJ;
+ }
+ break;
+
+ case PptSlideLayout::TWOROWSANDTITLE :
+ {
+ eAutoLayout = AUTOLAYOUT_TITLE_2CONTENT;
+ PptPlaceholder nID1 = pSlideLayout->aPlaceholderId[ 1 ];
+ PptPlaceholder nID2 = pSlideLayout->aPlaceholderId[ 2 ];
+ if ( nID1 == PptPlaceholder::BODY && nID2 == PptPlaceholder::OBJECT )
+ eAutoLayout = AUTOLAYOUT_TEXTOVEROBJ;
+ else if ( nID1 == PptPlaceholder::OBJECT && nID2 == PptPlaceholder::BODY )
+ eAutoLayout = AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT;
+ }
+ break;
+
+ case PptSlideLayout::TITLESLIDE :
+ eAutoLayout = AUTOLAYOUT_TITLE;
+ break;
+ case PptSlideLayout::ONLYTITLE :
+ eAutoLayout = AUTOLAYOUT_TITLE_ONLY;
+ break;
+ case PptSlideLayout::RIGHTCOLUMN2ROWS :
+ eAutoLayout = AUTOLAYOUT_TITLE_CONTENT_2CONTENT;
+ break;
+ case PptSlideLayout::LEFTCOLUMN2ROWS :
+ eAutoLayout = AUTOLAYOUT_TITLE_2CONTENT_CONTENT;
+ break;
+ case PptSlideLayout::TOPROW2COLUMN :
+ eAutoLayout = AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT;
+ break;
+ case PptSlideLayout::FOUROBJECTS :
+ eAutoLayout = AUTOLAYOUT_TITLE_4CONTENT;
+ break;
+ case PptSlideLayout::BIGOBJECT :
+ eAutoLayout = AUTOLAYOUT_OBJ;
+ break;
+ case PptSlideLayout::TITLERIGHTBODYLEFT :
+ eAutoLayout = AUTOLAYOUT_VTITLE_VCONTENT;
+ break;
+ case PptSlideLayout::TITLERIGHT2BODIESLEFT :
+ eAutoLayout = AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT;
+ break;
+
+ case PptSlideLayout::BOTTOMROW2COLUMNS :
+ case PptSlideLayout::BLANKSLIDE :
+ case PptSlideLayout::MASTERSLIDE : // layout of the standard and title master page
+ case PptSlideLayout::TITLEMASTERSLIDE :
+ case PptSlideLayout::MASTERNOTES : // layout of the note master page
+ case PptSlideLayout::NOTESTITLEBODY : // presentation layout for note pages
+ case PptSlideLayout::HANDOUTLAYOUT : // presentation layout for handout
+ eAutoLayout = AUTOLAYOUT_NONE;
+ break;
+ }
+ if ( eAutoLayout != AUTOLAYOUT_NONE )
+ pPage->SetAutoLayout( eAutoLayout );
+ }
+ }
+
+ // handout master page: auto layout
+ SdPage* pHandoutMPage = mpDoc->GetMasterSdPage( 0, PageKind::Handout );
+ pHandoutMPage->SetAutoLayout( AUTOLAYOUT_HANDOUT6, true, true );
+ }
+
+ sal_uInt32 nSlideCount = GetPageCount();
+ for ( sal_uInt32 i = 0; ( i < nSlideCount) && ( i < maSlideNameList.size() ); i++ )
+ {
+ SdPage* pPage = mpDoc->GetSdPage( i, PageKind::Standard );
+ OUString &aName = maSlideNameList[ i ];
+ if ( pPage )
+ {
+ if ( !aName.isEmpty() )
+ pPage->SetName( aName );
+ else
+ aName = pPage->GetName();
+ }
+ }
+ if ( mbDocumentFound )
+ {
+ mpDoc->SetSummationOfParagraphs();
+ if ( pDocShell )
+ {
+ ::sd::FrameView* pFrameView = mpDoc->GetFrameView( 0 );
+ if ( !pFrameView )
+ {
+ std::vector<std::unique_ptr<sd::FrameView>> &rViews = mpDoc->GetFrameViewList();
+ pFrameView = new ::sd::FrameView( mpDoc );
+ rViews.push_back( std::unique_ptr<sd::FrameView>(pFrameView) );
+ }
+ sal_uInt16 nSelectedPage = 0;
+ PageKind ePageKind = PageKind::Standard;
+ EditMode eEditMode = EditMode::Page;
+
+ switch ( m_aUserEditAtom.eLastViewType )
+ {
+ case PptViewTypeEnum::Outline:
+ {
+ SfxItemSet* pSet = mrMed.GetItemSet();
+ if ( pSet )
+ pSet->Put( SfxUInt16Item( SID_VIEW_ID, 3 ) );
+ }
+ break;
+ case PptViewTypeEnum::SlideSorter:
+ {
+ SfxItemSet* pSet = mrMed.GetItemSet();
+ if ( pSet )
+ pSet->Put( SfxUInt16Item( SID_VIEW_ID, 2 ) );
+ }
+ break;
+ case PptViewTypeEnum::TitleMaster:
+ nSelectedPage = 1;
+ [[fallthrough]];
+ case PptViewTypeEnum::SlideMaster:
+ {
+ ePageKind = PageKind::Standard;
+ eEditMode = EditMode::MasterPage;
+ }
+ break;
+ case PptViewTypeEnum::NotesMaster:
+ eEditMode = EditMode::MasterPage;
+ [[fallthrough]];
+ case PptViewTypeEnum::Notes:
+ ePageKind = PageKind::Notes;
+ break;
+ case PptViewTypeEnum::Handout:
+ ePageKind = PageKind::Handout;
+ break;
+ default :
+ case PptViewTypeEnum::Slide:
+ break;
+ }
+ pFrameView->SetPageKind( ePageKind );
+ pFrameView->SetSelectedPage( nSelectedPage );
+ pFrameView->SetViewShEditMode( eEditMode );
+ }
+ DffRecordHeader aCustomShowHeader;
+ // read and set custom show
+ rStCtrl.Seek( maDocHd.GetRecBegFilePos() + 8 );
+ if ( SeekToRec( rStCtrl, PPT_PST_NamedShows, maDocHd.GetRecEndFilePos(), &aCustomShowHeader ) )
+ {
+ DffRecordHeader aCuHeader;
+ while( SeekToRec( rStCtrl, PPT_PST_NamedShow, aCustomShowHeader.GetRecEndFilePos(), &aCuHeader ) )
+ {
+ DffRecordHeader aContent;
+ if ( SeekToRec( rStCtrl, PPT_PST_CString, aCuHeader.GetRecEndFilePos(), &aContent ) )
+ {
+ OUString aCuShow;
+ aContent.SeekToBegOfRecord( rStCtrl );
+ if ( ReadString( aCuShow ) )
+ {
+ if ( SeekToRec( rStCtrl, PPT_PST_NamedShowSlides, aCuHeader.GetRecEndFilePos(), &aContent ) )
+ {
+ PptSlidePersistList* pPageList = GetPageList( PPT_SLIDEPAGE );
+ const auto nRemainingSize = rStCtrl.remainingSize();
+ sal_uInt32 nBCount = aContent.nRecLen;
+ if (nBCount > nRemainingSize)
+ {
+ SAL_WARN("filter.ms", "page number data len longer than remaining stream size");
+ nBCount = nRemainingSize;
+ }
+ sal_uInt32 nSCount = nBCount >> 2;
+
+ if ( pPageList && nSCount )
+ {
+ SdCustomShowList* pList = mpDoc->GetCustomShowList( true );
+ if ( pList )
+ {
+ std::unique_ptr<SdCustomShow> pSdCustomShow(new SdCustomShow);
+ pSdCustomShow->SetName( aCuShow );
+ sal_uInt32 nFound = 0;
+ for ( sal_uInt32 nS = 0; nS < nSCount; nS++ )
+ {
+ sal_uInt32 nPageNumber;
+ rStCtrl.ReadUInt32( nPageNumber );
+ sal_uInt16 nPage = pPageList->FindPage( nPageNumber );
+ if ( nPage != PPTSLIDEPERSIST_ENTRY_NOTFOUND )
+ {
+ SdPage* pPage = mpDoc->GetSdPage( nPage, PageKind::Standard );
+ if ( pPage )
+ {
+ pSdCustomShow->PagesVector().push_back( pPage );
+ nFound++;
+ }
+ }
+ }
+ if ( nFound )
+ pList->push_back( std::move(pSdCustomShow) );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // this is defaulted, maybe there is no SSDocInfoAtom
+ OUStringBuffer aCustomShow;
+ sal_uInt32 nFlags = 1; // Bit 0: Auto advance
+ sal_uInt16 nStartSlide = 0;
+
+ // read the pres. configuration
+ rStCtrl.Seek( maDocHd.GetRecBegFilePos() + 8 );
+ if ( SeekToRec( rStCtrl, PPT_PST_SSDocInfoAtom, maDocHd.GetRecEndFilePos(), &aCustomShowHeader ) )
+ {
+ sal_uInt32 nPenColor = 0x1000000;
+ sal_Int32 nRestartTime = 0x7fffffff;
+ sal_Int16 nEndSlide = 0;
+ rStCtrl.ReadUInt32( nPenColor )
+ .ReadInt32( nRestartTime )
+ .ReadUInt16( nStartSlide )
+ .ReadInt16( nEndSlide );
+
+ sal_Unicode nChar;
+ for ( sal_uInt32 i2 = 0; i2 < 32; i2++ )
+ {
+ rStCtrl.ReadUtf16( nChar );
+ if ( nChar )
+ aCustomShow.append( nChar );
+ else
+ {
+ rStCtrl.SeekRel( ( 31 - i2 ) << 1 );
+ break;
+ }
+ }
+ rStCtrl.ReadUInt32( nFlags );
+ }
+ // set the current custom show
+ if ( !aCustomShow.isEmpty() )
+ {
+ SdCustomShowList* pList = mpDoc->GetCustomShowList();
+ if ( pList )
+ {
+ SdCustomShow* pPtr = nullptr;
+ OUString aCustomShowStr = aCustomShow.makeStringAndClear();
+ for( pPtr = pList->First(); pPtr; pPtr = pList->Next() )
+ {
+ if ( pPtr->GetName() == aCustomShowStr )
+ break;
+ }
+ if ( !pPtr )
+ pList->First();
+ }
+ }
+ sd::PresentationSettings& rPresSettings = mpDoc->getPresentationSettings();
+
+ rPresSettings.mbManual = ( nFlags & 1 ) == 0;
+ rPresSettings.mbAnimationAllowed = ( nFlags & 2 ) == 0;
+ rPresSettings.mbAll = ( nFlags & 4 ) == 0;
+ rPresSettings.mbCustomShow = ( nFlags & 8 ) != 0;
+ rPresSettings.mbEndless = ( nFlags & 0x80 ) != 0;
+ rPresSettings.mbFullScreen = ( nFlags & 0x10 ) == 0;
+
+ if ( nStartSlide && ( nStartSlide <= GetPageCount() ) )
+ {
+ SdPage* pPage = mpDoc->GetSdPage( nStartSlide - 1, PageKind::Standard );
+ if ( pPage )
+ rPresSettings.maPresPage = pPage->GetName();
+ }
+ }
+
+ xStbMgr.reset();
+
+ // read DocumentProperties
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ mpDoc->GetObjectShell()->GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps
+ = xDPS->getDocumentProperties();
+ sfx2::LoadOlePropertySet(xDocProps, &mrStorage);
+ xDocProps->setTemplateName(OUString());
+
+ pSdrModel->setLock(bWasLocked);
+ pSdrModel->EnableUndo(bSavedUndoEnabled);
+ return m_bOk;
+}
+
+void ImplSdPPTImport::SetHeaderFooterPageSettings( SdPage* pPage, const PptSlidePersistEntry* pMasterPersist )
+{
+ sal_uInt32 i;
+ PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind );
+ if ( ( !pList ) || ( pList->size() <= m_nCurrentPageNum ) )
+ return;
+ PptSlidePersistEntry& rSlidePersist = (*pList)[ m_nCurrentPageNum ];
+ HeaderFooterEntry* pHFE = rSlidePersist.xHeaderFooterEntry.get();
+ if (!pHFE)
+ return;
+
+ for ( i = 0; i < 4; i++ )
+ {
+ bool bVisible = pHFE->IsToDisplay( i );
+ if ( ( m_eCurrentPageKind == PPT_SLIDEPAGE )
+ && ( rSlidePersist.aSlideAtom.aLayout.eLayout == PptSlideLayout::TITLESLIDE )
+ && ( aDocAtom.bTitlePlaceholdersOmitted ) )
+ {
+ bVisible = false;
+ }
+ if ( bVisible && pMasterPersist )
+ {
+ sal_uInt32 nPosition = pHFE->NeedToImportInstance( i, rSlidePersist );
+ if ( nPosition )
+ {
+ ::tools::Rectangle aEmpty;
+ bVisible = false;
+ rStCtrl.Seek( nPosition );
+ ProcessData aProcessData( rSlidePersist, SdPageCapsule(pPage) );
+ SdrObject* pObj = ImportObj( rStCtrl, aProcessData, aEmpty, aEmpty, /*nCalledByGroup*/0, /*pShapeId*/nullptr );
+ if ( pObj )
+ pPage->NbcInsertObject( pObj, 0 );
+ }
+ }
+ OUString aPlaceHolderString = pHFE->pPlaceholder[ i ];
+
+ sd::HeaderFooterSettings rHeaderFooterSettings( pPage->getHeaderFooterSettings() );
+ switch( i )
+ {
+ case 0 :
+ {
+ rHeaderFooterSettings.mbDateTimeVisible = bVisible;
+ rHeaderFooterSettings.mbDateTimeIsFixed = ( pHFE->nAtom & 0x20000 ) == 0;
+ rHeaderFooterSettings.maDateTimeText = aPlaceHolderString;
+ SvxDateFormat eDateFormat;
+ SvxTimeFormat eTimeFormat;
+ PPTFieldEntry::GetDateTime( pHFE->nAtom & 0xff, eDateFormat, eTimeFormat );
+ rHeaderFooterSettings.meDateFormat = eDateFormat;
+ rHeaderFooterSettings.meTimeFormat = eTimeFormat;
+ }
+ break;
+ case 1 :
+ {
+ rHeaderFooterSettings.mbHeaderVisible = bVisible;
+ rHeaderFooterSettings.maHeaderText = aPlaceHolderString;
+ }
+ break;
+ case 2 :
+ {
+ rHeaderFooterSettings.mbFooterVisible = bVisible;
+ rHeaderFooterSettings.maFooterText = aPlaceHolderString;
+ }
+ break;
+ case 3 :
+ {
+ rHeaderFooterSettings.mbSlideNumberVisible = bVisible;
+ }
+ break;
+ }
+ pPage->setHeaderFooterSettings( rHeaderFooterSettings );
+ }
+}
+
+namespace {
+
+// Import of pages
+struct Ppt97AnimationStlSortHelper
+{
+ bool operator()( const std::pair< SdrObject*, Ppt97AnimationPtr >& p1, const std::pair< SdrObject*, Ppt97AnimationPtr >& p2 );
+};
+
+}
+
+bool Ppt97AnimationStlSortHelper::operator()( const std::pair< SdrObject*, Ppt97AnimationPtr >& p1, const std::pair< SdrObject*, Ppt97AnimationPtr >& p2 )
+{
+ if( !p1.second || !p2.second )
+ return p1.second.get() < p2.second.get();
+ if( *p1.second < *p2.second )
+ return true;
+ if( *p1.second > *p2.second )
+ return false;
+ return p1.first->GetOrdNum() < p2.first->GetOrdNum();
+}
+
+void ImplSdPPTImport::ImportPageEffect( SdPage* pPage, const bool bNewAnimationsUsed )
+{
+ sal_uInt64 nOldFilePos = rStCtrl.Tell();
+
+ // set PageKind at page (up to now only PageKind::Standard or PageKind::Notes)
+ if ( pPage->GetPageKind() == PageKind::Standard )
+ {
+ PptSlidePersistList* pPersistList = GetPageList( m_eCurrentPageKind );
+ PptSlidePersistEntry* pActualSlidePersist = ( pPersistList && ( m_nCurrentPageNum < pPersistList->size() ) )
+ ? &(*pPersistList)[ m_nCurrentPageNum ] : nullptr;
+
+ if ( pActualSlidePersist && ( m_eCurrentPageKind == PPT_SLIDEPAGE ) )
+ {
+ if ( ! ( pActualSlidePersist->aSlideAtom.nFlags & 1 ) ) // do not follow master objects ?
+ {
+ if(pPage->TRG_HasMasterPage())
+ {
+ SdrLayerIDSet aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers();
+ aVisibleLayers.Set(mnBackgroundObjectsLayerID, false);
+ pPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+ }
+ }
+ }
+ DffRecordHeader aPageRecHd;
+ if ( SeekToCurrentPage( &aPageRecHd ) )
+ {
+ sal_uLong nPageRecEnd = SanitizeEndPos(rStCtrl, aPageRecHd.GetRecEndFilePos());
+
+ bool bTryTwice = ( m_eCurrentPageKind == PPT_SLIDEPAGE );
+ bool bSSSlideInfoAtom = false;
+ while ( true )
+ {
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nPageRecEnd ) )
+ {
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rStCtrl, aHd );
+ switch ( aHd.nRecType )
+ {
+ case PPT_PST_SSSlideInfoAtom:
+ {
+ bSSSlideInfoAtom = true;
+ if ( m_eCurrentPageKind == PPT_MASTERPAGE )
+ {
+ if ( pActualSlidePersist )
+ pActualSlidePersist->aPersistAtom.nReserved = aHd.GetRecBegFilePos();
+ }
+ else
+ {
+ sal_Int8 nDirection, nTransitionType, nByteDummy, nSpeed;
+ sal_Int16 nBuildFlags;
+ sal_Int32 nSlideTime, nSoundRef;
+ rStCtrl.ReadInt32( nSlideTime ) // time to show (in Ticks)
+ .ReadInt32( nSoundRef ) // Index of SoundCollection
+ .ReadSChar( nDirection ) // direction of fade effect
+ .ReadSChar( nTransitionType ) // fade effect
+ .ReadInt16( nBuildFlags ) // Buildflags (s.u.)
+ .ReadSChar( nSpeed ) // speed (slow, medium, fast)
+ .ReadSChar( nByteDummy ).ReadSChar( nByteDummy ).ReadSChar( nByteDummy );
+
+ switch ( nTransitionType )
+ {
+ case PPT_TRANSITION_TYPE_BLINDS :
+ {
+ if ( nDirection == 0 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_VERTICAL_STRIPES ); // fade vertical
+ else if ( nDirection == 1 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_HORIZONTAL_STRIPES ); // fade horizontal
+ }
+ break;
+ case PPT_TRANSITION_TYPE_CHECKER :
+ {
+ if ( nDirection == 0 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_HORIZONTAL_CHECKERBOARD ); // fade vertical with offset ??
+ else if ( nDirection == 1 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_VERTICAL_CHECKERBOARD ); // fade horizontal with offset ??
+ }
+ break;
+ case PPT_TRANSITION_TYPE_COVER :
+ {
+ if ( nDirection == 0 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_MOVE_FROM_RIGHT ); // overlay from right
+ else if ( nDirection == 1 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_MOVE_FROM_BOTTOM ); // overlay from bottom
+ else if ( nDirection == 2 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_MOVE_FROM_LEFT ); // overlay from left
+ else if ( nDirection == 3 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_MOVE_FROM_TOP ); // overlay from top
+ else if ( nDirection == 4 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_MOVE_FROM_LOWERRIGHT ); // overlay from bottom right ??
+ else if ( nDirection == 5 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_MOVE_FROM_LOWERLEFT ); // overlay from bottom left ??
+ else if ( nDirection == 6 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_MOVE_FROM_UPPERRIGHT ); // overlay from top right
+ else if ( nDirection == 7 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_MOVE_FROM_UPPERLEFT ); // overlay from top left ??
+ }
+ break;
+ case PPT_TRANSITION_TYPE_NONE :
+ {
+ if ( nBuildFlags )
+ {
+ if ( nDirection == 0 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_NONE ); // direct
+ else if ( nDirection == 1 )
+ {
+ pPage->setTransitionType( animations::TransitionType::BARWIPE );
+ pPage->setTransitionSubtype( animations::TransitionSubType::FADEOVERCOLOR );
+ pPage->setTransitionFadeColor( 0 );
+ }
+ }
+ else
+ pPage->setTransitionType( 0 );
+ }
+ break;
+ case PPT_TRANSITION_TYPE_DISSOLVE :
+ pPage->SetFadeEffect(css::presentation::FadeEffect_DISSOLVE); // dissolve
+ break;
+ case PPT_TRANSITION_TYPE_RANDOM_BARS :
+ {
+ if ( nDirection == 0 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_HORIZONTAL_LINES ); // horizontal lines
+ else if ( nDirection == 1 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_VERTICAL_LINES ); // vertical lines
+ }
+ break;
+ case PPT_TRANSITION_TYPE_SPLIT :
+ {
+ if ( nDirection == 0 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_OPEN_VERTICAL ); // open horizontal ??
+ else if ( nDirection == 1 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_CLOSE_VERTICAL ); // close horizontal ??
+ else if ( nDirection == 2 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_OPEN_HORIZONTAL ); // open vertical ??
+ else if ( nDirection == 3 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_CLOSE_HORIZONTAL ); // close vertical ??
+ }
+ break;
+ case PPT_TRANSITION_TYPE_STRIPS :
+ {
+ if ( nDirection == 4 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_FADE_FROM_LOWERRIGHT ); // diagonal to top left
+ else if ( nDirection == 5 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_FADE_FROM_LOWERLEFT ); // diagonal to top right
+ else if ( nDirection == 6 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_FADE_FROM_UPPERRIGHT ); // diagonal to bottom left
+ else if ( nDirection == 7 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_FADE_FROM_UPPERLEFT ); // diagonal to bottom right
+ }
+ break;
+ case PPT_TRANSITION_TYPE_PULL :
+ {
+ if ( nDirection == 0 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_UNCOVER_TO_LEFT ); // uncover to left
+ else if ( nDirection == 1 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_UNCOVER_TO_TOP ); // uncover to top
+ else if ( nDirection == 2 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_UNCOVER_TO_RIGHT ); // uncover to right
+ else if ( nDirection == 3 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_UNCOVER_TO_BOTTOM ); // uncover to bottom
+ else if ( nDirection == 4 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_UNCOVER_TO_UPPERLEFT ); // uncover to top left
+ else if ( nDirection == 5 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_UNCOVER_TO_UPPERRIGHT ); // uncover to top right
+ else if ( nDirection == 6 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_UNCOVER_TO_LOWERLEFT ); // uncover to bottom left
+ else if ( nDirection == 7 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_UNCOVER_TO_LOWERRIGHT ); // uncover to bottom right
+ }
+ break;
+ case PPT_TRANSITION_TYPE_WIPE :
+ {
+ if ( nDirection == 0 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_FADE_FROM_RIGHT ); // roll from right
+ else if ( nDirection == 1 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_FADE_FROM_BOTTOM ); // roll from bottom
+ else if ( nDirection == 2 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_FADE_FROM_LEFT ); // roll from left
+ else if ( nDirection == 3 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_FADE_FROM_TOP ); // roll from top
+ }
+ break;
+ case PPT_TRANSITION_TYPE_RANDOM :
+ pPage->SetFadeEffect( css::presentation::FadeEffect_RANDOM ); // automatic
+ break;
+ case PPT_TRANSITION_TYPE_FADE :
+ {
+ pPage->setTransitionType( animations::TransitionType::FADE );
+ pPage->setTransitionSubtype( animations::TransitionSubType::FADEOVERCOLOR );
+ pPage->setTransitionFadeColor( 0 );
+ }
+ break;
+ case PPT_TRANSITION_TYPE_ZOOM :
+ {
+ if ( nDirection == 0 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_FADE_FROM_CENTER ); // fade from center
+ else if ( nDirection == 1 )
+ pPage->SetFadeEffect( css::presentation::FadeEffect_FADE_TO_CENTER ); // fade from the outside
+ }
+ break;
+ case PPT_TRANSITION_TYPE_DIAMOND :
+ {
+ pPage->setTransitionType( animations::TransitionType::IRISWIPE );
+ pPage->setTransitionSubtype( animations::TransitionSubType::DIAMOND );
+ }
+ break;
+ case PPT_TRANSITION_TYPE_PLUS :
+ {
+ pPage->setTransitionType( animations::TransitionType::FOURBOXWIPE );
+ pPage->setTransitionSubtype( animations::TransitionSubType::CORNERSOUT );
+ }
+ break;
+ case PPT_TRANSITION_TYPE_CIRCLE :
+ {
+ pPage->setTransitionType( animations::TransitionType::ELLIPSEWIPE );
+ pPage->setTransitionSubtype( animations::TransitionSubType::CIRCLE );
+ }
+ break;
+ case PPT_TRANSITION_TYPE_WEDGE :
+ {
+ pPage->setTransitionType( animations::TransitionType::FANWIPE );
+ pPage->setTransitionSubtype( animations::TransitionSubType::CENTERTOP );
+ }
+ break;
+ case PPT_TRANSITION_TYPE_WHEEL :
+ {
+ pPage->setTransitionType( animations::TransitionType::PINWHEELWIPE );
+ sal_Int16 nSubType;
+ switch( nDirection )
+ {
+ default:
+ case 1 : nSubType = animations::TransitionSubType::ONEBLADE; break;
+ case 2 : nSubType = animations::TransitionSubType::TWOBLADEVERTICAL; break;
+ case 3 : nSubType = animations::TransitionSubType::THREEBLADE; break;
+ case 4 : nSubType = animations::TransitionSubType::FOURBLADE; break;
+ case 8 : nSubType = animations::TransitionSubType::EIGHTBLADE; break;
+ }
+ pPage->setTransitionSubtype( nSubType );
+ }
+ break;
+ case PPT_TRANSITION_TYPE_PUSH :
+ {
+ pPage->setTransitionType( animations::TransitionType::PUSHWIPE );
+ sal_Int16 nSubType;
+ switch( nDirection )
+ {
+ default:
+ case 0 : nSubType = animations::TransitionSubType::FROMRIGHT; break;
+ case 1 : nSubType = animations::TransitionSubType::FROMBOTTOM; break;
+ case 2 : nSubType = animations::TransitionSubType::FROMLEFT; break;
+ case 3 : nSubType = animations::TransitionSubType::FROMTOP; break;
+ }
+ pPage->setTransitionSubtype( nSubType );
+ }
+ break;
+ case PPT_TRANSITION_TYPE_COMB :
+ {
+ pPage->setTransitionType( animations::TransitionType::PUSHWIPE );
+ pPage->setTransitionSubtype( nDirection ? animations::TransitionSubType::COMBVERTICAL : animations::TransitionSubType::COMBHORIZONTAL );
+ }
+ break;
+ case PPT_TRANSITION_TYPE_NEWSFLASH :
+ {
+ pPage->setTransitionType( animations::TransitionType::ZOOM );
+ pPage->setTransitionSubtype( animations::TransitionSubType::ROTATEIN );
+ }
+ break;
+ case PPT_TRANSITION_TYPE_SMOOTHFADE :
+ {
+ pPage->setTransitionType( animations::TransitionType::FADE );
+ pPage->setTransitionSubtype( animations::TransitionSubType::CROSSFADE );
+ }
+ break;
+ }
+
+ if ( nSpeed == 0 )
+ pPage->setTransitionDuration( 1.0 ); // slow
+ else if ( nSpeed == 1 )
+ pPage->setTransitionDuration( 0.75 ); // medium
+ else if ( nSpeed == 2 )
+ pPage->setTransitionDuration( 0.5 ); // fast
+
+ if ( nBuildFlags & 0x400 ) // slidechange by time
+ { // time to show (in Ticks)
+ pPage->SetPresChange( PresChange::Auto );
+ pPage->SetTime( nSlideTime / 1000.0 );
+ }
+ else
+ pPage->SetPresChange( mePresChange );
+
+ if ( nBuildFlags & 4 )
+ pPage->SetExcluded( true ); // don't show slide
+ if ( nBuildFlags & 16 )
+ { // slide with sound effect
+ pPage->SetSound( true );
+ OUString aSoundFile( ReadSound( nSoundRef ) );
+ pPage->SetSoundFile( aSoundFile );
+ }
+ if ( nBuildFlags & ( 1 << 6 ) ) // Loop until next sound
+ pPage->SetLoopSound( true );
+ if ( nBuildFlags & ( 1 << 8 ) ) // Stop the previous sound
+ pPage->SetStopSound( true );
+ break;
+ }
+ }
+ }
+ if (!aHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ if ( bTryTwice && !bSSSlideInfoAtom )
+ {
+ bTryTwice = false;
+ if ( HasMasterPage( m_nCurrentPageNum, m_eCurrentPageKind ) )
+ {
+ sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind );
+ PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE );
+ if ( pPageList && ( nMasterNum < pPageList->size() ) )
+ {
+ assert( !pPageList->is_null( nMasterNum ) );
+ const PptSlidePersistEntry& rE = (*pPageList)[ nMasterNum ];
+ sal_uInt32 nOfs = rE.aPersistAtom.nReserved;
+ if ( nOfs )
+ {
+ rStCtrl.Seek( nOfs );
+ nPageRecEnd = nOfs + 16;
+ continue;
+ }
+ }
+
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if ( !bNewAnimationsUsed )
+ {
+ std::vector< std::pair< SdrObject*, Ppt97AnimationPtr > > aAnimationsOnThisPage;
+
+ // add effects from page in correct order
+ SdrObjListIter aSdrIter( pPage, SdrIterMode::Flat );
+ while ( aSdrIter.IsMore() )
+ {
+ SdrObject* pObj = aSdrIter.Next();
+ tAnimationMap::iterator aFound = maAnimations.find( pObj );
+ if( aFound != maAnimations.end() )
+ {
+ std::pair< SdrObject*, Ppt97AnimationPtr > aPair( (*aFound).first, (*aFound).second );
+ aAnimationsOnThisPage.push_back( aPair );
+ }
+ }
+
+ std::sort( aAnimationsOnThisPage.begin(), aAnimationsOnThisPage.end(), Ppt97AnimationStlSortHelper() );
+
+ for( auto& rEntry : aAnimationsOnThisPage )
+ {
+ Ppt97AnimationPtr pPpt97Animation = rEntry.second;
+ if( pPpt97Animation )
+ pPpt97Animation->createAndSetCustomAnimationEffect( rEntry.first );
+ }
+ }
+ rStCtrl.Seek( nOldFilePos );
+}
+
+// import of sounds
+
+// Not only the sounds are imported as string, they are also inserted to
+// the gallery if they are not already there.
+OUString ImplSdPPTImport::ReadSound(sal_uInt32 nSoundRef) const
+{
+ OUString aRetval;
+ sal_uInt32 nOldPos = rStCtrl.Tell();
+ DffRecordHeader aDocHd;
+ if ( SeekToDocument( &aDocHd ) )
+ {
+ sal_uInt32 nSoundLen = aDocHd.GetRecEndFilePos();
+ DffRecordHeader aSoundBlockRecHd;
+ if( SeekToRec( rStCtrl, PPT_PST_SoundCollection, nSoundLen, &aSoundBlockRecHd ) )
+ {
+ sal_uInt32 nDataLen = aSoundBlockRecHd.GetRecEndFilePos();
+ DffRecordHeader aSoundRecHd;
+ bool bRefStrValid = false;
+ bool bDone = false;
+
+ while( !bDone && SeekToRec( rStCtrl, PPT_PST_Sound, nDataLen, &aSoundRecHd ) )
+ {
+ sal_uInt32 nStrLen = aSoundRecHd.GetRecEndFilePos();
+ OUString aRefStr;
+ sal_uInt32 nOldPos2 = rStCtrl.Tell();
+ if ( SeekToRec( rStCtrl, PPT_PST_CString, nStrLen, nullptr, 2 ) )
+ {
+ if ( ReadString( aRefStr ) )
+ bRefStrValid = true;
+ }
+ if ( bRefStrValid )
+ {
+ if ( std::u16string_view(OUString::number(nSoundRef)) == aRefStr )
+ {
+ rStCtrl.Seek( nOldPos2 );
+ if ( SeekToRec( rStCtrl, PPT_PST_CString, nStrLen ) )
+ {
+ ReadString( aRetval );
+ bDone = true;
+ }
+ }
+ }
+ if ( bDone )
+ {
+ // Check if this sound file already exists.
+ // If not, it is exported to our local sound directory.
+ bool bSoundExists = false;
+ ::std::vector< OUString > aSoundList;
+
+ GalleryExplorer::FillObjList( GALLERY_THEME_SOUNDS, aSoundList );
+ GalleryExplorer::FillObjList( GALLERY_THEME_USERSOUNDS, aSoundList );
+
+ for( size_t n = 0; ( n < aSoundList.size() ) && !bSoundExists; ++n )
+ {
+ INetURLObject aURL( aSoundList[ n ] );
+
+ if (aURL.GetLastName() == aRetval)
+ {
+ aRetval = aSoundList[ n ];
+ bSoundExists = true;
+ }
+ }
+
+ aSoundList.clear();
+
+ if ( !bSoundExists )
+ {
+ rStCtrl.Seek( nOldPos2 );
+ DffRecordHeader aSoundDataRecHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_SoundData, nStrLen, &aSoundDataRecHd ) )
+ {
+ OUString aGalleryDir;
+ if (utl::ConfigManager::IsFuzzing())
+ osl_getTempDirURL(&aGalleryDir.pData);
+ else
+ aGalleryDir = SvtPathOptions().GetGalleryPath();
+ // Use last token delimited by ';'. copy(lastIndexOf+1) works whether
+ // string is empty or not and whether ';' is there or not.
+ INetURLObject aGalleryUserSound( aGalleryDir.subView(aGalleryDir.lastIndexOf(';')+1) );
+
+ aGalleryUserSound.Append( aRetval );
+ const auto nRemainingSize = rStCtrl.remainingSize();
+ sal_uInt32 nSoundDataLen = aSoundDataRecHd.nRecLen;
+ if (nSoundDataLen > nRemainingSize)
+ {
+ SAL_WARN("filter.ms", "sound data len longer than remaining stream size");
+ nSoundDataLen = nRemainingSize;
+ }
+ std::vector<sal_uInt8> aBuf(nSoundDataLen);
+
+ rStCtrl.ReadBytes(aBuf.data(), nSoundDataLen);
+ std::unique_ptr<SvStream> pOStm = ::utl::UcbStreamHelper::CreateStream( aGalleryUserSound.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::TRUNC );
+
+ if( pOStm )
+ {
+ pOStm->WriteBytes(aBuf.data(), nSoundDataLen);
+
+ if( pOStm->GetError() == ERRCODE_NONE )
+ {
+ GalleryExplorer::InsertURL( GALLERY_THEME_USERSOUNDS, aGalleryUserSound.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ aRetval = aGalleryUserSound.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+ }
+ }
+ }
+ }
+ if ( !bDone )
+ {
+ if (!aSoundRecHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ }
+ }
+ }
+ rStCtrl.Seek( nOldPos );
+ return aRetval;
+}
+
+// media object import, the return value is the url to the media object
+OUString ImplSdPPTImport::ReadMedia( sal_uInt32 nMediaRef ) const
+{
+ OUString aRetVal;
+ DffRecordHeader* pHd( const_cast<ImplSdPPTImport*>(this)->aDocRecManager.GetRecordHeader( PPT_PST_ExObjList ) );
+ if ( pHd )
+ {
+ pHd->SeekToContent( rStCtrl );
+ auto nEndRecPos = SanitizeEndPos(rStCtrl, pHd->GetRecEndFilePos());
+ while ( ( rStCtrl.Tell() < nEndRecPos ) && aRetVal.isEmpty() )
+ {
+ DffRecordHeader aHdMovie;
+ ReadDffRecordHeader( rStCtrl, aHdMovie );
+ switch( aHdMovie.nRecType )
+ {
+ case PPT_PST_ExAviMovie :
+ case PPT_PST_ExMCIMovie :
+ {
+ DffRecordHeader aExVideoHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_ExVideo, aHdMovie.GetRecEndFilePos(), &aExVideoHd ) )
+ {
+ DffRecordHeader aExMediaAtomHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_ExMediaAtom, aExVideoHd.GetRecEndFilePos(), &aExMediaAtomHd ) )
+ {
+ sal_uInt32 nRef;
+ rStCtrl.ReadUInt32( nRef );
+ if ( nRef == nMediaRef )
+ {
+ aExVideoHd.SeekToContent( rStCtrl );
+ auto nHdEndRecPos = SanitizeEndPos(rStCtrl, aExVideoHd.GetRecEndFilePos());
+ while (rStCtrl.Tell() < nHdEndRecPos)
+ {
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rStCtrl, aHd );
+ switch( aHd.nRecType )
+ {
+ case PPT_PST_CString :
+ {
+ aHd.SeekToBegOfRecord( rStCtrl );
+ OUString aStr;
+ if ( ReadString( aStr ) )
+ {
+ if( osl::FileBase::getFileURLFromSystemPath( aStr, aRetVal )
+ == osl::FileBase::E_None )
+ {
+ aRetVal = INetURLObject( aRetVal ).GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+ }else{
+ aRetVal = aStr;
+ }
+ }
+ }
+ break;
+ }
+ if (!aHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ if (!aHdMovie.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ }
+ return aRetVal;
+}
+
+// import of objects
+void ImplSdPPTImport::FillSdAnimationInfo( SdAnimationInfo* pInfo, PptInteractiveInfoAtom const * pIAtom, const OUString& aMacroName )
+{
+ // set local information into pInfo
+ if( pIAtom->nSoundRef )
+ {
+ pInfo->SetBookmark( ReadSound( pIAtom->nSoundRef ) ); // path to sound file in MS DOS notation
+ pInfo->meClickAction = css::presentation::ClickAction_SOUND; // RunProgramAction
+ }
+
+ switch ( pIAtom->nAction )
+ {
+
+ case 0x02 : // RunProgramAction
+ {
+ pInfo->meClickAction = css::presentation::ClickAction_PROGRAM;
+ pInfo->SetBookmark( aMacroName ); // program name in aBookmark
+ }
+ break;
+ case 0x03 : // JumpAction
+ {
+ switch( pIAtom->nJump )
+ {
+ case 0x01 :
+ pInfo->meClickAction = css::presentation::ClickAction_NEXTPAGE; // Next slide
+ break;
+ case 0x02 :
+ pInfo->meClickAction = css::presentation::ClickAction_PREVPAGE; // Previous slide
+ break;
+ case 0x03 :
+ pInfo->meClickAction = css::presentation::ClickAction_FIRSTPAGE; // First slide
+ break;
+ case 0x04 :
+ pInfo->meClickAction = css::presentation::ClickAction_LASTPAGE; // last Slide
+ break;
+ case 0x05 :
+ pInfo->meClickAction = css::presentation::ClickAction_PREVPAGE; // Last slide viewed
+ break;
+ case 0x06 :
+ pInfo->meClickAction = css::presentation::ClickAction_STOPPRESENTATION; // End show
+ break;
+ default :
+ pInfo->meClickAction = css::presentation::ClickAction_NONE; // 0x00: no action, else unknown
+ break;
+ }
+ }
+ break;
+ case 0x04 :
+ {
+ SdHyperlinkEntry* pPtr = nullptr;
+ for (SdHyperlinkEntry & entry : m_aHyperList) {
+ if ( entry.nIndex == pIAtom->nExHyperlinkId ) {
+ pPtr = &entry;
+ break;
+ }
+ }
+ if ( pPtr )
+ {
+ switch( pIAtom->nHyperlinkType )
+ {
+ case 9:
+ case 8: // hyperlink : URL
+ {
+ if ( !pPtr->aTarget.isEmpty() )
+ {
+ ::sd::DrawDocShell* pDocShell = mpDoc->GetDocSh();
+ SfxMedium* pMedium = pDocShell ? pDocShell->GetMedium() : nullptr;
+ if (pMedium)
+ {
+ OUString aBaseURL = pMedium->GetBaseURL();
+ OUString aBookmarkURL( pInfo->GetBookmark() );
+ INetURLObject aURL( pPtr->aTarget );
+ if( INetProtocol::NotValid == aURL.GetProtocol()
+ && (osl::FileBase::getFileURLFromSystemPath(
+ pPtr->aTarget, aBookmarkURL)
+ != osl::FileBase::E_None) )
+ aBookmarkURL.clear();
+ if( aBookmarkURL.isEmpty() )
+ aBookmarkURL = URIHelper::SmartRel2Abs( INetURLObject(aBaseURL), pPtr->aTarget, URIHelper::GetMaybeFileHdl() );
+ pInfo->SetBookmark( aBookmarkURL );
+ pInfo->meClickAction = css::presentation::ClickAction_PROGRAM;
+ }
+ }
+ }
+ break;
+
+ case 10:
+ break;
+
+ case 7: // hyperlink to a page
+ {
+ if ( !pPtr->aConvSubString.isEmpty() )
+ {
+ pInfo->meClickAction = css::presentation::ClickAction_BOOKMARK;
+ pInfo->SetBookmark( pPtr->aConvSubString );
+ }
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case 0x05 : // OLEAction ( OLEVerb to use, 0==first, 1==second, .. )
+ case 0x06 : // MediaAction
+ case 0x07 : // CustomShowAction
+ default : // 0x00: no action, else unknown action
+ break;
+ }
+}
+
+SdrObject* ImplSdPPTImport::ApplyTextObj( PPTTextObj* pTextObj, SdrTextObj* pObj, SdPageCapsule pPageCapsule,
+ SfxStyleSheet* pSheet, SfxStyleSheet** ppStyleSheetAry ) const
+{
+ SdPage * pPage = static_cast<SdPage *>(pPageCapsule.page);
+ SfxStyleSheet* pStyleSheetAry[ 9 ];
+ SdrTextObj* pText = pObj;
+ SdrObject* pRet = pText;
+
+ ppStyleSheetAry = nullptr;
+
+ PresObjKind ePresKind = PresObjKind::NONE;
+ PptOEPlaceholderAtom* pPlaceHolder = pTextObj->GetOEPlaceHolderAtom();
+ OUString aPresentationText;
+ if ( pPlaceHolder )
+ {
+ switch( pPlaceHolder->nPlaceholderId )
+ {
+ case PptPlaceholder::MASTERNOTESSLIDEIMAGE :
+ case PptPlaceholder::MASTERCENTEREDTITLE :
+ case PptPlaceholder::MASTERTITLE :
+ {
+ ePresKind = PresObjKind::Title;
+ aPresentationText = pPage->GetPresObjText( ePresKind );
+ }
+ break;
+ case PptPlaceholder::MASTERBODY :
+ {
+ ePresKind = PresObjKind::Outline;
+ aPresentationText = pPage->GetPresObjText( ePresKind );
+ }
+ break;
+ case PptPlaceholder::MASTERSUBTITLE :
+ {
+ ePresKind = PresObjKind::Text;
+ aPresentationText = pPage->GetPresObjText( ePresKind );
+ }
+ break;
+ case PptPlaceholder::MASTERNOTESBODYIMAGE :
+ {
+ ePresKind = PresObjKind::Notes;
+ aPresentationText = pPage->GetPresObjText( ePresKind );
+ }
+ break;
+ case PptPlaceholder::MASTERDATE : ePresKind = PresObjKind::DateTime; break;
+ case PptPlaceholder::MASTERSLIDENUMBER : ePresKind = PresObjKind::SlideNumber;break;
+ case PptPlaceholder::MASTERFOOTER : ePresKind = PresObjKind::Footer; break;
+ case PptPlaceholder::MASTERHEADER : ePresKind = PresObjKind::Header; break;
+ default: break;
+ }
+ }
+ switch ( pTextObj->GetDestinationInstance() )
+ {
+ case TSS_Type::PageTitle :
+ case TSS_Type::Title :
+ {
+ pSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Title );
+ if ( pSheet )
+ static_cast<SdrAttrObj*>(pText)->SdrAttrObj::NbcSetStyleSheet( pSheet, true );
+ DBG_ASSERT( pSheet, "ImplSdPPTImport::ApplyTextObj -> could not get stylesheet for titleobject (SJ)" );
+ }
+ break;
+ case TSS_Type::Subtitle :
+ {
+ pSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Text );
+ if ( pSheet )
+ static_cast<SdrAttrObj*>(pText)->SdrAttrObj::NbcSetStyleSheet( pSheet, true );
+ DBG_ASSERT( pSheet, "ImplSdPPTImport::ApplyTextObj -> could not get stylesheet for subtitleobject (SJ)" );
+ }
+ break;
+ case TSS_Type::Body :
+ case TSS_Type::HalfBody :
+ case TSS_Type::QuarterBody :
+ {
+ for ( sal_uInt16 nLevel = 9; nLevel; nLevel-- )
+ {
+ OUString aName = pPage->GetLayoutName() + " " + OUString::number( nLevel );
+ pSheet = static_cast<SfxStyleSheet*>(mpDoc->GetStyleSheetPool()->Find( aName, SfxStyleFamily::Page ));
+ if ( pSheet )
+ pText->StartListening( *pSheet );
+ pStyleSheetAry[ nLevel - 1 ] = pSheet;
+ }
+ DBG_ASSERT( pSheet, "ImplSdPPTImport::ApplyTextObj -> could not get stylesheet for outlinerobject (SJ)" );
+ if ( pSheet )
+ static_cast<SdrAttrObj*>(pText)->SdrAttrObj::NbcSetStyleSheet( pSheet, true );
+ ppStyleSheetAry = &pStyleSheetAry[ 0 ];
+ }
+ break;
+ case TSS_Type::Notes :
+ {
+ if ( pPlaceHolder && ( ( pPlaceHolder->nPlaceholderId == PptPlaceholder::NOTESSLIDEIMAGE )
+ || ( pPlaceHolder->nPlaceholderId == PptPlaceholder::MASTERNOTESSLIDEIMAGE ) ) )
+ {
+ pSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Title );
+ if ( pSheet )
+ static_cast<SdrAttrObj*>(pText)->SdrAttrObj::NbcSetStyleSheet( pSheet, true );
+ DBG_ASSERT( pSheet, "ImplSdPPTImport::ApplyTextObj -> could not get stylesheet for titleobject (SJ)" );
+ }
+ else
+ {
+ pSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Notes );
+ DBG_ASSERT( pSheet, "ImplSdPPTImport::ApplyTextObj -> could not get stylesheet for notesobj (SJ)" );
+ if ( pSheet )
+ static_cast<SdrAttrObj*>(pText)->SdrAttrObj::NbcSetStyleSheet( pSheet, true );
+ }
+ }
+ break;
+ case TSS_Type::Unused :
+ case TSS_Type::TextInShape :
+ {
+ switch( ePresKind )
+ {
+ case PresObjKind::DateTime :
+ case PresObjKind::SlideNumber :
+ case PresObjKind::Footer :
+ case PresObjKind::Header :
+ pSheet = static_cast<SfxStyleSheet*>(mpDoc->GetStyleSheetPool()->Find(SdResId(STR_PSEUDOSHEET_BACKGROUNDOBJECTS), SfxStyleFamily::Pseudo ));
+ break;
+ default :
+ pSheet = static_cast<SfxStyleSheet*>(mpDoc->GetStyleSheetPool()->Find(SdResId(STR_STANDARD_STYLESHEET_NAME), SfxStyleFamily::Para ));
+ }
+ }
+ break;
+ default: break;
+ }
+
+ pText = static_cast<SdrTextObj*>(SdrPowerPointImport::ApplyTextObj( pTextObj, pText, pPageCapsule, pSheet, ppStyleSheetAry ));
+
+ if ( pPlaceHolder && pPlaceHolder->nPlaceholderId != PptPlaceholder::NONE )
+ {
+ if ( m_eCurrentPageKind == PPT_MASTERPAGE )
+ {
+ bool bCreatePlaceHolder = ( pTextObj->GetInstance() != TSS_Type::Unused );
+ bool bIsHeaderFooter = ( ePresKind == PresObjKind::Header) || (ePresKind == PresObjKind::Footer)
+ || (ePresKind == PresObjKind::DateTime) || (ePresKind == PresObjKind::SlideNumber);
+ if ( bCreatePlaceHolder && ( pTextObj->GetInstance() == TSS_Type::TextInShape ) )
+ bCreatePlaceHolder = bIsHeaderFooter;
+ if ( bCreatePlaceHolder )
+ {
+ if ( !bIsHeaderFooter )
+ {
+ pText->SetNotVisibleAsMaster( true );
+ pText->SetEmptyPresObj( true );
+ }
+ pText->SetUserCall( pPage );
+ pPage->InsertPresObj( pText, ePresKind );
+ SdrOutliner* pOutl = nullptr;
+ if ( pTextObj->GetInstance() == TSS_Type::Notes )
+ pOutl = GetDrawOutliner( pText );
+ if ( !aPresentationText.isEmpty() )
+ pPage->SetObjText( pText, pOutl, ePresKind, aPresentationText );
+
+ if ( pPage->GetPageKind() != PageKind::Notes && pPage->GetPageKind() != PageKind::Handout)
+ {
+ SfxStyleSheet* pSheet2( pPage->GetStyleSheetForPresObj( ePresKind ) );
+ if ( pSheet2 )
+ {
+ SfxItemSet& rItemSet = pSheet2->GetItemSet();
+ rItemSet.Put( pText->GetMergedItem( SDRATTR_TEXT_LEFTDIST ) );
+ rItemSet.Put( pText->GetMergedItem( SDRATTR_TEXT_RIGHTDIST ) );
+ rItemSet.Put( pText->GetMergedItem( SDRATTR_TEXT_UPPERDIST ) );
+ rItemSet.Put( pText->GetMergedItem( SDRATTR_TEXT_LOWERDIST ) );
+ rItemSet.Put( pText->GetMergedItem( SDRATTR_TEXT_VERTADJUST ) );
+ rItemSet.Put( pText->GetMergedItem( SDRATTR_TEXT_HORZADJUST ) );
+ if ( pTextObj->GetInstance() == TSS_Type::Title
+ || pTextObj->GetInstance() == TSS_Type::Subtitle)
+ {
+ rItemSet.Put( pText->GetMergedItemSet() );
+ }
+ }
+ }
+
+ SfxItemSet aTempAttr( mpDoc->GetPool() );
+ SdrMetricItem aMinHeight( makeSdrTextMinFrameHeightItem(pText->GetLogicRect().GetSize().Height()) );
+ aTempAttr.Put( aMinHeight );
+ SdrOnOffItem aAutoGrowHeight( makeSdrTextAutoGrowHeightItem(false) );
+ aTempAttr.Put( aAutoGrowHeight );
+ pText->SetMergedItemSet(aTempAttr);
+ }
+ else
+ {
+ pRet = nullptr;
+ }
+ }
+ else
+ {
+ const PptSlideLayoutAtom* pSlideLayout = GetSlideLayoutAtom();
+ if ( pSlideLayout || ( m_eCurrentPageKind == PPT_NOTEPAGE ) )
+ {
+ sal_uInt32 nPlacementId = pPlaceHolder->nPlacementId;
+ PptPlaceholder nPlaceholderId = pPlaceHolder->nPlaceholderId;
+ PresObjKind ePresObjKind = PresObjKind::NONE;
+ bool bEmptyPresObj = true;
+ bool bVertical = false;
+ if ( ( pTextObj->GetShapeType() == mso_sptRectangle ) || ( pTextObj->GetShapeType() == mso_sptTextBox ) )
+ {
+ //if a placeholder with some custom attribute,the pTextObj will keep those attr,whose text size is zero,
+ //so sdPage should renew a PresObj to process placeholder.
+ bEmptyPresObj = ( pTextObj->Count() == 0 ) || ( pTextObj->Count() == 1 && pTextObj->First()->GetTextSize() == 0 );
+ switch ( nPlaceholderId )
+ {
+ case PptPlaceholder::NOTESBODY : ePresObjKind = PresObjKind::Notes; break;
+ case PptPlaceholder::VERTICALTEXTTITLE :
+ bVertical = true;
+ [[fallthrough]];
+ case PptPlaceholder::TITLE : ePresObjKind = PresObjKind::Title; break;
+ case PptPlaceholder::VERTICALTEXTBODY :
+ bVertical = true;
+ [[fallthrough]];
+ case PptPlaceholder::BODY : ePresObjKind = PresObjKind::Outline; break;
+ case PptPlaceholder::CENTEREDTITLE : ePresObjKind = PresObjKind::Title; break;
+ case PptPlaceholder::SUBTITLE : ePresObjKind = PresObjKind::Text; break; // PresObjKind::Outline
+
+ default :
+ {
+ if ( pTextObj->Count() == 0 )
+ {
+ switch ( nPlaceholderId )
+ {
+ case PptPlaceholder::MEDIACLIP :
+ case PptPlaceholder::OBJECT : ePresObjKind = PresObjKind::Object; break;
+ case PptPlaceholder::GRAPH : ePresObjKind = PresObjKind::Chart; break;
+ case PptPlaceholder::TABLE : ePresObjKind = PresObjKind::Table; break;
+ case PptPlaceholder::CLIPART : ePresObjKind = PresObjKind::Graphic; break;
+ case PptPlaceholder::ORGANISZATIONCHART : ePresObjKind = PresObjKind::OrgChart; break;
+ default: break;
+ }
+ }
+ };
+ }
+ }
+ else if ( pTextObj->GetShapeType() == mso_sptPictureFrame )
+ {
+ if ( !pTextObj->Count() && dynamic_cast< const SdrGrafObj *>( pObj ) != nullptr )
+ {
+ bEmptyPresObj = false;
+ switch ( nPlaceholderId )
+ {
+ case PptPlaceholder::MEDIACLIP :
+ case PptPlaceholder::OBJECT : ePresObjKind = PresObjKind::Object; break;
+ case PptPlaceholder::GRAPH : ePresObjKind = PresObjKind::Chart; break;
+ case PptPlaceholder::TABLE : ePresObjKind = PresObjKind::Calc; break;
+ case PptPlaceholder::CLIPART : ePresObjKind = PresObjKind::Graphic; break;
+ case PptPlaceholder::ORGANISZATIONCHART : ePresObjKind = PresObjKind::OrgChart; break;
+ default: break;
+ }
+ }
+ }
+ if ( ePresObjKind != PresObjKind::NONE )
+ {
+ if ( !bEmptyPresObj )
+ {
+ pPage->InsertPresObj( pRet, ePresObjKind );
+ }
+ else
+ {
+ SdrObject* pPresObj = pPage->CreatePresObj( ePresObjKind, bVertical, pText->GetLogicRect() );
+ pPresObj->SetUserCall( pPage );
+
+ SfxItemSet aSet( pSdrModel->GetItemPool() );
+ ApplyAttributes( rStCtrl, aSet );
+ pPresObj->SetLogicRect(pText->GetLogicRect());
+ ApplyTextAnchorAttributes( *pTextObj, aSet );
+ //set custom font attribute of the placeholder
+ if ( pTextObj->Count() == 1 )
+ {
+ PPTParagraphObj* pPara = pTextObj->First();
+ if ( pPara && pPara->GetTextSize() == 0 )
+ {
+ if ( PPTPortionObj * pPor = pPara->First() )
+ {
+ pPor->ApplyTo(aSet, const_cast<SdrPowerPointImport&>(static_cast<SdrPowerPointImport const &>(*this)), pTextObj->GetDestinationInstance());
+ }
+ }
+ }
+ pPresObj->SetMergedItemSet(aSet);
+
+ if ((m_eCurrentPageKind != PPT_NOTEPAGE) && (nPlacementId != 0xffffffff) && pPage->TRG_HasMasterPage())
+ {
+ SdrObject* pTitleObj = static_cast<SdPage&>(pPage->TRG_GetMasterPage()).GetPresObj( PresObjKind::Title );
+ SdrObject* pOutlineObj = static_cast<SdPage&>(pPage->TRG_GetMasterPage()).GetPresObj( PresObjKind::Outline );
+
+ ::tools::Rectangle aTitleRect;
+ ::tools::Rectangle aOutlineRect;
+ Size aOutlineSize;
+
+ if ( pTitleObj )
+ aTitleRect = pTitleObj->GetLogicRect();
+ if ( pOutlineObj )
+ {
+ aOutlineRect = pOutlineObj->GetLogicRect();
+ aOutlineSize = aOutlineRect.GetSize();
+ }
+ ::tools::Rectangle aLogicRect( pPresObj->GetLogicRect() );
+ Size aLogicSize( aLogicRect.GetSize() );
+
+ switch ( nPlacementId )
+ {
+ case 0 : // position in title area
+ {
+ if ( aLogicRect != aTitleRect )
+ pPresObj->SetUserCall( nullptr );
+ }
+ break;
+
+ case 1:
+ {
+ if ( pSlideLayout->eLayout == PptSlideLayout::TITLEANDBODYSLIDE )
+ { // position in outline area
+ if ( aLogicRect != aOutlineRect )
+ pPresObj->SetUserCall( nullptr );
+ }
+ else if ( pSlideLayout->eLayout == PptSlideLayout::TWOCOLUMNSANDTITLE )
+ { // position in outline area left
+ if (std::abs(aLogicRect.Left() - aOutlineRect.Left()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Top() - aOutlineRect.Top()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Bottom() - aOutlineRect.Bottom()) > MAX_USER_MOVE ||
+ aOutlineSize.Width() == 0 ||
+ static_cast<double>(aLogicSize.Width()) / aOutlineSize.Width() < 0.48 ||
+ static_cast<double>(aLogicSize.Width()) / aOutlineSize.Width() > 0.5)
+ {
+ pPresObj->SetUserCall(nullptr);
+ }
+ }
+ else if ( pSlideLayout->eLayout == PptSlideLayout::TWOROWSANDTITLE )
+ { // position in outline area top
+ if (std::abs(aLogicRect.Left() - aOutlineRect.Left()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Top() - aOutlineRect.Top()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Right() - aOutlineRect.Right()) > MAX_USER_MOVE)
+ {
+ pPresObj->SetUserCall( nullptr );
+ }
+ }
+ else if (std::abs(aLogicRect.Left() - aOutlineRect.Left()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Top() - aOutlineRect.Top()) > MAX_USER_MOVE)
+ { // position in outline area top left
+ pPresObj->SetUserCall( nullptr );
+ }
+ }
+ break;
+
+ case 2:
+ {
+ if ( pSlideLayout->eLayout == PptSlideLayout::TWOCOLUMNSANDTITLE )
+ { // position in outline area right
+ if (std::abs(aLogicRect.Right() - aOutlineRect.Right()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Top() - aOutlineRect.Top()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Bottom() - aOutlineRect.Bottom()) > MAX_USER_MOVE ||
+ aOutlineSize.Width() == 0 ||
+ static_cast<double>(aLogicSize.Width()) / aOutlineSize.Width() < 0.48 ||
+ static_cast<double>(aLogicSize.Width()) / aOutlineSize.Width() > 0.5)
+ {
+ pPresObj->SetUserCall( nullptr );
+ }
+ }
+ else if ( pSlideLayout->eLayout == PptSlideLayout::TWOROWSANDTITLE )
+ { // position in outline area bottom
+ if (std::abs(aLogicRect.Left() - aOutlineRect.Left()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Bottom() - aOutlineRect.Bottom()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Right() - aOutlineRect.Right()) > MAX_USER_MOVE)
+ {
+ pPresObj->SetUserCall( nullptr );
+ }
+ }
+ else if (std::abs(aLogicRect.Right() - aOutlineRect.Right()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Top() - aOutlineRect.Top()) > MAX_USER_MOVE)
+ { // position in outline area top right
+ pPresObj->SetUserCall(nullptr);
+ }
+ }
+ break;
+
+ case 3:
+ { // position in outline area bottom left
+ if (std::abs(aLogicRect.Left() - aOutlineRect.Left()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Bottom() - aOutlineRect.Bottom()) > MAX_USER_MOVE)
+ {
+ pPresObj->SetUserCall( nullptr );
+ }
+ }
+ break;
+
+ case 4:
+ { // position in outline area bottom right
+ if (std::abs(aLogicRect.Right() - aOutlineRect.Right()) > MAX_USER_MOVE ||
+ std::abs(aLogicRect.Bottom() - aOutlineRect.Bottom()) > MAX_USER_MOVE)
+ {
+ pObj->SetUserCall( nullptr );
+ }
+ }
+ break;
+ }
+ }
+ pRet = nullptr; // return zero cause this obj was already inserted by CreatePresObj
+ }
+ }
+ else if ( !pTextObj->Count() )
+ pRet = nullptr;
+ }
+ }
+ }
+ if ( pRet != pText )
+ {
+ SdrObject* pFree( pText );
+ SdrObject::Free( pFree );
+ }
+ return pRet;
+}
+
+SdrObject* ImplSdPPTImport::ProcessObj( SvStream& rSt, DffObjData& rData, SvxMSDffClientData& rClientData, ::tools::Rectangle& rTextRect, SdrObject* pRet )
+{
+ SdrObject* pObj = SdrPowerPointImport::ProcessObj( rSt, rData, rClientData, rTextRect, pRet );
+
+ // read animation effect of object
+ if ( pObj )
+ {
+ // further setup placeholder objects
+ if (dynamic_cast<const SdrPageObj*>(pObj))
+ {
+ const ProcessData& rProcessData=static_cast<const ProcessData&>(rClientData);
+ if(rProcessData.pPage.page)
+ static_cast<SdPage *>(rProcessData.pPage.page)->InsertPresObj(
+ pObj, PresObjKind::Page );
+ }
+
+ DffRecordHeader aMasterShapeHd;
+
+ if ( maShapeRecords.SeekToContent( rSt, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) )
+ {
+ bool bInhabitanceChecked = false;
+ bool bAnimationInfoFound = false;
+
+ DffRecordHeader& rHdClientData = *maShapeRecords.Current();
+ while( true )
+ {
+ sal_uInt32 nClientDataLen = SanitizeEndPos(rSt, rHdClientData.GetRecEndFilePos());
+ DffRecordHeader aHd;
+ do
+ {
+ ReadDffRecordHeader( rSt, aHd );
+ sal_uInt32 nHdRecEnd = aHd.GetRecEndFilePos();
+ switch ( aHd.nRecType )
+ {
+ case PPT_PST_AnimationInfo :
+ {
+ DffRecordHeader aHdAnimInfoAtom;
+ if ( SeekToRec( rSt, PPT_PST_AnimationInfoAtom, nHdRecEnd, &aHdAnimInfoAtom ) )
+ {
+ // read data from stream
+ Ppt97AnimationPtr pAnimation = std::make_shared<Ppt97Animation>( rSt );
+ // store animation information
+ if( pAnimation->HasEffect() )
+ {
+ // translate color to RGB
+ pAnimation->SetDimColor( MSO_CLR_ToColor(pAnimation->GetDimColor()) );
+ // translate sound bits to file url
+ if( pAnimation->HasSoundEffect() )
+ pAnimation->SetSoundFileUrl( ReadSound( pAnimation->GetSoundRef() ) );
+
+ bool bDontAnimateInvisibleShape = false;
+ {
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(pObj);
+
+ if( pTextObj && pTextObj->HasText() &&
+ dynamic_cast< SdrObjGroup *>( pObj ) == nullptr &&
+ pAnimation->HasAnimateAssociatedShape() )
+ {
+ const SfxItemSet& rObjItemSet = pObj->GetMergedItemSet();
+
+ drawing::FillStyle eFillStyle = rObjItemSet.Get(XATTR_FILLSTYLE).GetValue();
+ drawing::LineStyle eLineStyle = rObjItemSet.Get(XATTR_LINESTYLE).GetValue();
+
+ if ( ( eFillStyle == drawing::FillStyle_NONE ) && ( eLineStyle == drawing::LineStyle_NONE ) )
+ bDontAnimateInvisibleShape = true;
+ }
+ }
+ if( bDontAnimateInvisibleShape )
+ pAnimation->SetAnimateAssociatedShape(false);
+
+ //maybe some actions necessary to ensure that animations on master pages are played before animations on normal pages
+ //maybe todo in future: bool bIsEffectOnMasterPage = !bInhabitanceChecked;?
+
+ maAnimations[pObj] = pAnimation;
+
+ bAnimationInfoFound = true;
+ }
+ }
+ }
+ break;
+ case PPT_PST_InteractiveInfo:
+ {
+ sal_uInt32 nOldFilePos2 = rSt.Tell();
+ OUString aMacroName;
+
+ if(SeekToRec( rSt, PPT_PST_CString, nHdRecEnd ) )
+ ReadString(aMacroName);
+
+ rSt.Seek( nOldFilePos2 );
+ DffRecordHeader aHdInteractiveInfoAtom;
+ if ( SeekToRec( rSt, PPT_PST_InteractiveInfoAtom, nHdRecEnd, &aHdInteractiveInfoAtom ) )
+ {
+ PptInteractiveInfoAtom aInteractiveInfoAtom;
+ ReadPptInteractiveInfoAtom( rSt, aInteractiveInfoAtom );
+
+ // interactive object
+ SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pObj, true);
+
+ FillSdAnimationInfo( pInfo, &aInteractiveInfoAtom, aMacroName );
+ if ( aInteractiveInfoAtom.nAction == 6 ) // Sj -> media action
+ {
+ rHdClientData.SeekToContent( rStCtrl );
+ DffRecordHeader aObjRefAtomHd;
+ if ( SeekToRec( rSt, PPT_PST_ExObjRefAtom, nHdRecEnd, &aObjRefAtomHd ) )
+ {
+ sal_uInt32 nRef;
+ rSt.ReadUInt32( nRef );
+ OUString aMediaURL( ReadMedia( nRef ) );
+ if ( aMediaURL.isEmpty() )
+ aMediaURL = ReadSound( nRef );
+ if ( !aMediaURL.isEmpty() )
+ {
+ SdrMediaObj* pMediaObj = new SdrMediaObj(
+ pObj->getSdrModelFromSdrObject(),
+ pObj->GetSnapRect());
+ pMediaObj->SetMergedItemSet( pObj->GetMergedItemSet() );
+
+ //--remove object from maAnimations list and add the new object instead
+ Ppt97AnimationPtr pAnimation;
+ {
+ tAnimationMap::iterator aFound = maAnimations.find( pObj );
+ if( aFound != maAnimations.end() )
+ {
+ pAnimation = (*aFound).second;
+ maAnimations.erase(aFound);
+ }
+ maAnimations[pMediaObj] = pAnimation;
+ }
+
+ SdrObject::Free( pObj );
+ pObj = pMediaObj; // SJ: hoping that pObj is not inserted in any list
+ pMediaObj->setURL( aMediaURL, ""/*TODO?*/ );
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ if (!aHd.SeekToEndOfRecord(rSt))
+ break;
+ }
+ while( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nClientDataLen ) );
+
+ if ( bInhabitanceChecked || bAnimationInfoFound )
+ break;
+ bInhabitanceChecked = true;
+ if ( ! ( IsProperty( DFF_Prop_hspMaster ) && SeekToShape( rSt, &rClientData, GetPropertyValue( DFF_Prop_hspMaster, 0 ) ) ) )
+ break;
+ ReadDffRecordHeader( rSt, aMasterShapeHd );
+ if ( !SeekToRec( rSt, DFF_msofbtClientData, aMasterShapeHd.GetRecEndFilePos(), &aMasterShapeHd ) )
+ break;
+ aMasterShapeHd.SeekToContent( rSt );
+ rHdClientData = aMasterShapeHd;
+ }
+ }
+ }
+ return pObj;
+}
+
+bool
+ImplSdPPTImport::ReadFormControl( tools::SvRef<SotStorage>& rSrc1, css::uno::Reference< css::form::XFormComponent > & rFormComp ) const
+{
+ uno::Reference< frame::XModel > xModel;
+ if ( mpDoc->GetDocSh() )
+ {
+ xModel = mpDoc->GetDocSh()->GetModel();
+ oox::ole::MSConvertOCXControls aCtrlImporter( xModel );
+ return aCtrlImporter.ReadOCXStorage( rSrc1, rFormComp );
+ }
+ return false;
+}
+
+// exported function
+extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool ImportPPT(
+ SdDrawDocument* pDocument, SvStream& rDocStream, SotStorage& rStorage, SfxMedium& rMedium )
+{
+ std::unique_ptr<SdPPTImport> pImport( new SdPPTImport( pDocument, rDocStream, rStorage, rMedium ));
+ return pImport->Import();
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportPPT(SvStream &rStream)
+{
+ bool bRet = false;
+ try
+ {
+ tools::SvRef<SotStorage> xStorage(new SotStorage(rStream));
+ if (xStorage->GetError())
+ return false;
+
+ tools::SvRef<SotStorageStream> xDocStream(xStorage->OpenSotStream( "PowerPoint Document", StreamMode::STD_READ));
+ if ( !xDocStream.is() )
+ return false;
+
+ SdDLL::Init();
+
+ SfxMedium aSrcMed("", StreamMode::STD_READ);
+
+ xDocStream->SetVersion(xStorage->GetVersion());
+ xDocStream->SetCryptMaskKey(xStorage->GetKey());
+
+ ::sd::DrawDocShellRef xDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress);
+ SdDrawDocument *pDoc = xDocShRef->GetDoc();
+
+ try
+ {
+ bRet = ImportPPT(pDoc, *xDocStream, *xStorage, aSrcMed);
+ }
+ catch (...)
+ {
+ }
+
+ xDocShRef->DoClose();
+ }
+ catch (...)
+ {
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/pptin.hxx b/sd/source/filter/ppt/pptin.hxx
new file mode 100644
index 000000000..39eff2890
--- /dev/null
+++ b/sd/source/filter/ppt/pptin.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <filter/msfilter/svdfppt.hxx>
+#include <diadef.h>
+#include <sot/storage.hxx>
+#include <svx/svdtypes.hxx>
+#include <memory>
+
+class SdDrawDocument;
+class SfxMedium;
+
+/*************************************************************************
+|*
+|* local import
+|*
+\************************************************************************/
+
+class SdPage;
+class SdAnimationInfo;
+class Ppt97Animation;
+
+typedef std::shared_ptr< Ppt97Animation > Ppt97AnimationPtr;
+typedef ::std::map < SdrObject*, Ppt97AnimationPtr > tAnimationMap;
+
+class ImplSdPPTImport : public SdrPowerPointImport
+{
+ tools::SvRef<SotStorageStream> mxPicturesStream;
+ SfxMedium& mrMed;
+ SotStorage& mrStorage;
+ DffRecordHeader maDocHd;
+ std::vector<OUString> maSlideNameList;
+ bool mbDocumentFound;
+ sal_uInt32 mnFilterOptions;
+ SdDrawDocument* mpDoc;
+ PresChange mePresChange;
+ SdrLayerID mnBackgroundObjectsLayerID;
+
+ tAnimationMap maAnimations;
+ void SetHeaderFooterPageSettings( SdPage* pPage, const PptSlidePersistEntry* pMasterPersist );
+ void ImportPageEffect( SdPage* pPage, const bool bNewAnimationsUsed );
+
+ void FillSdAnimationInfo( SdAnimationInfo* pInfo, PptInteractiveInfoAtom const * pIAtom, const OUString& aMacroName );
+
+ virtual SdrObject* ProcessObj( SvStream& rSt, DffObjData& rData, SvxMSDffClientData& rClientData, ::tools::Rectangle& rTextRect, SdrObject* pObj ) override;
+ virtual SdrObject* ApplyTextObj( PPTTextObj* pTextObj, SdrTextObj* pText, SdPageCapsule pPage,
+ SfxStyleSheet*, SfxStyleSheet** ) const override;
+
+public:
+
+ OUString ReadSound( sal_uInt32 nSoundRef ) const;
+ OUString ReadMedia( sal_uInt32 nMediaRef ) const;
+
+ ImplSdPPTImport( SdDrawDocument* pDoc, SotStorage& rStorage, SfxMedium& rMed, PowerPointImportParam& );
+ virtual ~ImplSdPPTImport() override;
+
+ bool Import();
+ virtual bool ReadFormControl( tools::SvRef<SotStorage>& rSrc1, css::uno::Reference< css::form::XFormComponent > & rFormComp ) const override;
+};
+
+class SdPPTImport
+{
+ PowerPointImportParam maParam;
+ std::unique_ptr<ImplSdPPTImport> pFilter;
+
+public:
+
+ SdPPTImport( SdDrawDocument* pDoc, SvStream& rDocStream, SotStorage& rStorage, SfxMedium& rMed );
+ ~SdPPTImport();
+
+ bool Import();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/pptinanimations.cxx b/sd/source/filter/ppt/pptinanimations.cxx
new file mode 100644
index 000000000..ff49054dd
--- /dev/null
+++ b/sd/source/filter/ppt/pptinanimations.cxx
@@ -0,0 +1,3294 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/animations/AnimationRestart.hpp>
+#include <com/sun/star/animations/Timing.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/AnimationEndSync.hpp>
+#include <com/sun/star/animations/Command.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+#include <com/sun/star/animations/AnimationCalcMode.hpp>
+#include <com/sun/star/animations/AnimationValueType.hpp>
+#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
+#include <com/sun/star/animations/XIterateContainer.hpp>
+#include <com/sun/star/animations/XAnimateSet.hpp>
+#include <com/sun/star/animations/XAnimationNode.hpp>
+#include <com/sun/star/animations/XAudio.hpp>
+#include <com/sun/star/animations/XCommand.hpp>
+#include <com/sun/star/animations/XTransitionFilter.hpp>
+#include <com/sun/star/animations/XAnimateColor.hpp>
+#include <com/sun/star/animations/XAnimateMotion.hpp>
+#include <com/sun/star/animations/XAnimateTransform.hpp>
+#include <com/sun/star/animations/ValuePair.hpp>
+#include <com/sun/star/animations/AnimationColorSpace.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/EffectPresetClass.hpp>
+#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
+#include <com/sun/star/presentation/EffectCommands.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+#include <comphelper/processfactory.hxx>
+#include <oox/helper/addtosequence.hxx>
+#include <oox/ppt/pptfilterhelpers.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+
+#include <svx/svdotext.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <animations.hxx>
+#include "pptanimations.hxx"
+#include "pptinanimations.hxx"
+#include "pptatom.hxx"
+#include "pptin.hxx"
+#include <randomnode.hxx>
+
+#include <algorithm>
+#include <memory>
+
+using ::com::sun::star::beans::NamedValue;
+using ::com::sun::star::container::XEnumerationAccess;
+using ::com::sun::star::container::XEnumeration;
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::presentation;
+
+namespace ppt
+{
+
+static SvStream& operator>>(SvStream& rIn, AnimationNode& rNode )
+{
+ rIn.ReadInt32( rNode.mnU1 );
+ rIn.ReadInt32( rNode.mnRestart );
+ rIn.ReadInt32( rNode.mnGroupType );
+ rIn.ReadInt32( rNode.mnFill );
+ rIn.ReadInt32( rNode.mnU3 );
+ rIn.ReadInt32( rNode.mnU4 );
+ rIn.ReadInt32( rNode.mnDuration );
+ rIn.ReadInt32( rNode.mnNodeType );
+
+ return rIn;
+}
+
+bool PropertySet::hasProperty( sal_Int32 nProperty ) const
+{
+ return maProperties.find( nProperty ) != maProperties.end();
+}
+
+Any PropertySet::getProperty( sal_Int32 nProperty ) const
+{
+ PropertySetMap_t::const_iterator aIter( maProperties.find( nProperty ) );
+ if( aIter != maProperties.end() )
+ return (*aIter).second;
+ else
+ return Any();
+}
+
+AnimationImporter::AnimationImporter( ImplSdPPTImport* pPPTImport, SvStream& rStCtrl )
+: mpPPTImport( pPPTImport ), mrStCtrl( rStCtrl )
+{
+}
+
+int AnimationImporter::import( const Reference< XDrawPage >& xPage, const DffRecordHeader& rProgTagContentHd )
+{
+ int nNodes = 0;
+
+#ifdef DBG_ANIM_LOG
+ static int ppt_anim_debug_stream_number = 1;
+ OUString ppt_anim_debug_filename("ppt-animation-import-debug-output-");
+ ppt_anim_debug_filename += OUString::number(ppt_anim_debug_stream_number++);
+ ppt_anim_debug_filename += ".xml";
+ mpFile = fopen( OUStringToOString( ppt_anim_debug_filename, RTL_TEXTENCODING_UTF8).getStr() , "w+" );
+#endif
+ dump("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+
+ Reference< XAnimationNodeSupplier > xNodeSupplier( xPage, UNO_QUERY );
+ if( xNodeSupplier.is() )
+ {
+ mxRootNode = xNodeSupplier->getAnimationNode();
+ if( mxRootNode.is() )
+ {
+ Reference< XAnimationNode > xParent;
+
+ std::unique_ptr<Atom> pAtom(Atom::import( rProgTagContentHd, mrStCtrl ));
+ if( pAtom )
+ {
+ nNodes = importAnimationContainer( pAtom.get(), xParent );
+ }
+
+ std::for_each( maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
+ sd::stl_process_after_effect_node_func );
+ }
+ }
+
+#ifdef DBG_ANIM_LOG
+ fclose( mpFile );
+#endif
+
+ return nNodes;
+}
+
+Reference< XAnimationNode > AnimationImporter::createNode( const Atom* pAtom, const AnimationNode& rNode )
+{
+ const char* pServiceName = nullptr;
+
+ switch( rNode.mnGroupType )
+ {
+ case mso_Anim_GroupType_PAR:
+ if( pAtom->hasChildAtom( DFF_msofbtAnimIteration ) )
+ pServiceName = "com.sun.star.animations.IterateContainer";
+ else
+ pServiceName = "com.sun.star.animations.ParallelTimeContainer";
+ break;
+ case mso_Anim_GroupType_SEQ:
+ pServiceName = "com.sun.star.animations.SequenceTimeContainer";
+ break;
+ case mso_Anim_GroupType_NODE:
+ {
+ switch( rNode.mnNodeType )
+ {
+ case mso_Anim_Behaviour_FILTER:
+ case mso_Anim_Behaviour_ANIMATION:
+ if( pAtom->hasChildAtom( DFF_msofbtAnimateSet ) )
+ pServiceName = "com.sun.star.animations.AnimateSet";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateColor ) )
+ pServiceName = "com.sun.star.animations.AnimateColor";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateScale ) )
+ pServiceName = "com.sun.star.animations.AnimateTransform";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateRotation ) )
+ pServiceName = "com.sun.star.animations.AnimateTransform";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateMotion ) )
+ pServiceName = "com.sun.star.animations.AnimateMotion";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateFilter ) )
+ pServiceName = "com.sun.star.animations.TransitionFilter";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimCommand ) )
+ pServiceName = "com.sun.star.animations.Command";
+ else
+ pServiceName = "com.sun.star.animations.Animate";
+ break;
+ }
+ break;
+ }
+ case mso_Anim_GroupType_MEDIA:
+ pServiceName = "com.sun.star.animations.Audio";
+ break;
+
+ default:
+ pServiceName = "com.sun.star.animations.Animate";
+ break;
+ }
+
+ Reference< XAnimationNode > xNode;
+ if( pServiceName )
+ {
+ Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ const OUString aServiceName( OUString::createFromAscii(pServiceName) );
+ Reference< XInterface > xFac( xContext->getServiceManager()->createInstanceWithContext(aServiceName, xContext) );
+ xNode.set(xFac , UNO_QUERY );
+ }
+
+ DBG_ASSERT( xNode.is(), "sd::AnimationImporter::createNode(), node creation failed!" );
+ return xNode;
+}
+
+static bool is_random( const AnimationNode& rNode, const PropertySet& rSet, sal_Int32& rPresetClass )
+{
+ if( rNode.mnGroupType != mso_Anim_GroupType_PAR )
+ return false;
+
+ if( !rSet.hasProperty( DFF_ANIM_PRESET_ID ) || !rSet.hasProperty( DFF_ANIM_PRESET_CLASS ) )
+ return false;
+
+ sal_Int32 nPresetId = 0;
+ if( !(rSet.getProperty( DFF_ANIM_PRESET_ID ) >>= nPresetId) || (nPresetId != 24) )
+ return false;
+
+ sal_Int32 nPresetClass = 0;
+ if( !(rSet.getProperty( DFF_ANIM_PRESET_CLASS ) >>= nPresetClass) )
+ return false;
+
+ switch( nPresetClass )
+ {
+ case DFF_ANIM_PRESS_CLASS_ENTRANCE: rPresetClass = EffectPresetClass::ENTRANCE; return true;
+ case DFF_ANIM_PRESS_CLASS_EXIT: rPresetClass = EffectPresetClass::EXIT; return true;
+ }
+ return false;
+}
+
+int AnimationImporter::importAnimationContainer( const Atom* pAtom, const Reference< XAnimationNode >& xParent )
+{
+ int nNodes = 0;
+ if( pAtom->seekToContent() )
+ {
+ AnimationNode aNode;
+ const Atom* pAnimationNodeAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimNode );
+ if( pAnimationNodeAtom && pAnimationNodeAtom->seekToContent() )
+ mrStCtrl >> aNode;
+
+ PropertySet aSet;
+ const Atom* pAnimationPropertySetAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimPropertySet );
+ if( pAnimationPropertySetAtom )
+ importPropertySetContainer( pAnimationPropertySetAtom, aSet );
+
+ Reference< XAnimationNode > xNode;
+
+ if( xParent.is() )
+ {
+ sal_Int32 nPresetClass;
+ if( is_random( aNode, aSet, nPresetClass ) )
+ {
+ // create a random animation node with the given preset class
+ xNode.set( sd::RandomAnimationNode_createInstance( static_cast<sal_Int16>(nPresetClass) ), UNO_QUERY );
+ }
+
+ if( !xNode.is() )
+ {
+ // create a node for the given atom
+ xNode = createNode( pAtom, aNode );
+ }
+ }
+ else
+ {
+ // if we have no parent we fill the root node
+ xNode = mxRootNode;
+ }
+
+ // import if we have a node and it's not random
+ if( xNode.is() )
+ {
+ fillNode( xNode, aNode, aSet );
+
+ switch( aNode.mnGroupType )
+ {
+ case mso_Anim_GroupType_PAR:
+ {
+ dump( "<par" );
+ dump( aNode );
+ dump( aSet );
+ nNodes += importTimeContainer( pAtom, xNode );
+ dump( "</par>\n" );
+
+ // for iteration containers, map target from children to iteration
+ Reference< XIterateContainer > xIter( xNode, UNO_QUERY );
+ if( xIter.is() )
+ {
+ double fDuration = 0.0;
+ Any aTarget, aEmpty;
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimate > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( xChildNode.is() )
+ {
+ double fChildBegin = 0.0;
+ double fChildDuration = 0.0;
+ xChildNode->getBegin() >>= fChildBegin;
+ xChildNode->getDuration() >>= fChildDuration;
+
+ fChildDuration += fChildBegin;
+ if( fChildDuration > fDuration )
+ fDuration = fChildDuration;
+
+ if( !aTarget.hasValue() )
+ aTarget = xChildNode->getTarget();
+
+ xChildNode->setTarget( aEmpty );
+ }
+ }
+ }
+ }
+
+ xIter->setTarget( aTarget );
+
+ double fIterateInterval = xIter->getIterateInterval() * fDuration / 100;
+ xIter->setIterateInterval( fIterateInterval );
+ }
+ }
+ break;
+
+ case mso_Anim_GroupType_SEQ:
+ {
+ dump( "<seq" );
+ dump( aNode );
+ dump( aSet );
+ nNodes += importTimeContainer( pAtom, xNode );
+ dump( "</seq>\n" );
+
+ if( aSet.hasProperty( DFF_ANIM_NODE_TYPE ) )
+ {
+ sal_Int32 nPPTNodeType = 0;
+ if( aSet.getProperty( DFF_ANIM_NODE_TYPE ) >>= nPPTNodeType )
+ {
+ switch(nPPTNodeType)
+ {
+ case DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE:
+ oox::ppt::fixMainSequenceTiming( xNode );
+ break;
+ case DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ:
+ oox::ppt::fixInteractiveSequenceTiming( xNode );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case mso_Anim_GroupType_NODE:
+ {
+#ifdef DBG_ANIM_LOG
+ if( pAtom->hasChildAtom( DFF_msofbtAnimateSet ) )
+ {
+ dump( "<set" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateColor ) )
+ {
+ dump( "<animateColor" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateScale ) )
+ {
+ dump( "<animateScale" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateRotation ) )
+ {
+ dump( "<animateRotation" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateMotion ) )
+ {
+ dump( "<animateMotion" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimate ) )
+ {
+ dump( "<animate" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateFilter ) )
+ {
+ dump( "<animateFilter" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimCommand ) )
+ {
+ dump( "<command" );
+ }
+ else
+ {
+ OSL_FAIL( "unknown node atom!" );
+ dump_atom_header( pAtom, true, false );
+ dump_atom( pAtom );
+ dump_atom_header( pAtom, false, false );
+ break;
+ }
+ dump( aNode );
+ dump( aSet );
+#endif
+ int nANCNodes = importAnimationNodeContainer( pAtom, xNode );
+ if( !convertAnimationNode( xNode, xParent ) )
+ xNode = nullptr;
+ else
+ nNodes += nANCNodes;
+ dump( "/>\n");
+
+ }
+ break;
+
+ case mso_Anim_GroupType_MEDIA:
+ {
+ dump( "<audio" );
+ dump( aNode );
+ dump( aSet );
+ nNodes += importAudioContainer( pAtom, xNode );
+ dump( "</audio>\n" );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "unknown group atom!" );
+
+ dump_atom_header( pAtom, true, false );
+ dump_atom( pAtom );
+ dump_atom_header( pAtom, false, false );
+ break;
+
+ }
+ }
+
+ if( xParent.is() && xNode.is() )
+ {
+ Reference< XTimeContainer > xParentContainer( xParent, UNO_QUERY );
+ DBG_ASSERT( xParentContainer.is(), "parent is no container, then why do I have a child here?" );
+ if( xParentContainer.is() )
+ {
+ xParentContainer->appendChild( xNode );
+ }
+ }
+ }
+
+ return nNodes;
+}
+
+bool AnimationImporter::convertAnimationNode( const Reference< XAnimationNode >& xNode, const Reference< XAnimationNode >& xParent )
+{
+ Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
+ if( !xAnimate.is() )
+ return true;
+
+ if( !xAnimate->getTarget().hasValue() )
+ return false;
+
+ const sal_Int16 nNodeType = xNode->getType();
+
+ if( nNodeType == AnimationNodeType::TRANSITIONFILTER )
+ return true;
+
+ OUString aAttributeName( xAnimate->getAttributeName() );
+
+ if( (nNodeType == AnimationNodeType::SET) && aAttributeName == "fill.on" )
+ return false;
+
+ const oox::ppt::ImplAttributeNameConversion* p = oox::ppt::getAttributeConversionList();
+
+ oox::ppt::AnimationAttributeEnum eAttribute = oox::ppt::AnimationAttributeEnum::UNKNOWN;
+
+ if( (nNodeType == AnimationNodeType::ANIMATEMOTION) ||
+ (nNodeType == AnimationNodeType::ANIMATETRANSFORM) )
+ {
+ aAttributeName.clear();
+ }
+ else
+ {
+ while( p->mpMSName )
+ {
+ if( aAttributeName.equalsAscii( p->mpMSName ) )
+ break;
+
+ p++;
+ }
+
+ DBG_ASSERT( p->mpMSName || aAttributeName.isEmpty(), "sd::AnimationImporter::convertAnimationNode(), unknown attribute!" );
+#ifdef DBG_ANIM_LOG
+ if( p->mpMSName == 0 ) dump( "<error text=\"sd::AnimationImporter::convertAnimationNode(), unknown attribute!\"/>\n" );
+#endif
+
+ eAttribute = p->meAttribute;
+
+ if( p->mpAPIName )
+ aAttributeName = OUString::createFromAscii( p->mpAPIName );
+ }
+
+ xAnimate->setAttributeName( aAttributeName );
+
+ if(eAttribute != oox::ppt::AnimationAttributeEnum::UNKNOWN)
+ {
+ Any aAny( xAnimate->getFrom() );
+ if( aAny.hasValue() )
+ {
+ if(oox::ppt::convertAnimationValue(eAttribute, aAny))
+ xAnimate->setFrom( aAny );
+ }
+
+ aAny = xAnimate->getBy();
+ if( aAny.hasValue() )
+ {
+ if(oox::ppt::convertAnimationValue(eAttribute, aAny))
+ xAnimate->setBy( aAny );
+ }
+
+ aAny = xAnimate->getTo();
+ if( aAny.hasValue() )
+ {
+ if(oox::ppt::convertAnimationValue(eAttribute, aAny))
+ xAnimate->setTo( aAny );
+ }
+
+ Sequence< Any > aValues( xAnimate->getValues() );
+ if( aValues.hasElements() )
+ {
+ for( Any& rValue : asNonConstRange(aValues) )
+ oox::ppt::convertAnimationValue(eAttribute, rValue);
+
+ xAnimate->setValues( aValues );
+ }
+
+ OUString aFormula( xAnimate->getFormula() );
+ if( !aFormula.isEmpty() )
+ {
+ if(oox::ppt::convertMeasure(aFormula))
+ xAnimate->setFormula( aFormula );
+ }
+ }
+
+ // check for after-effect
+ Sequence< NamedValue > aUserData( xNode->getUserData() );
+ NamedValue* pLastValue = aUserData.getArray();
+ sal_Int32 nRemoved = 0;
+
+ bool bAfterEffect = false;
+ sal_Int32 nMasterRel = 0;
+ for( const NamedValue& rValue : std::as_const(aUserData) )
+ {
+ if ( rValue.Name == "after-effect" )
+ {
+ rValue.Value >>= bAfterEffect;
+ nRemoved++;
+ }
+ else if ( rValue.Name == "master-rel" )
+ {
+ rValue.Value >>= nMasterRel;
+ nRemoved++;
+ }
+ else
+ {
+ if( nRemoved )
+ *pLastValue = rValue;
+ pLastValue++;
+ }
+ }
+
+ if( nRemoved )
+ {
+ aUserData.realloc( aUserData.getLength() - nRemoved );
+ xNode->setUserData( aUserData );
+ }
+
+ // if it's an after effect node, add it to the list for
+ // later processing
+ // after effect nodes are not inserted at their import
+ // position, so return false in this case
+ if( bAfterEffect )
+ {
+ if( nMasterRel != 2 )
+ {
+ Event aEvent;
+
+ aEvent.Source <<= xParent;
+ aEvent.Trigger = EventTrigger::END_EVENT;
+ aEvent.Repeat = 0;
+
+ xNode->setBegin( Any( aEvent ) );
+ }
+
+ // add to after effect nodes for later processing
+ sd::AfterEffectNode aNode( xNode, xParent, nMasterRel == 2 );
+ maAfterEffectNodes.push_back( aNode );
+ return false;
+ }
+
+ return true;
+}
+
+void AnimationImporter::fillNode( Reference< XAnimationNode > const & xNode, const AnimationNode& rNode, const PropertySet& rSet )
+{
+ bool bAfterEffect = false;
+
+ // attribute Restart
+ if( rNode.mnRestart )
+ {
+ sal_Int16 nRestart = AnimationRestart::DEFAULT;
+ switch( rNode.mnRestart )
+ {
+ case 1: nRestart = AnimationRestart::ALWAYS; break;
+ case 2: nRestart = AnimationRestart::WHEN_NOT_ACTIVE; break;
+ case 3: nRestart = AnimationRestart::NEVER; break;
+ }
+ xNode->setRestart( nRestart );
+ }
+
+ // attribute Fill
+ if( rNode.mnFill )
+ {
+ sal_Int16 nFill = AnimationFill::DEFAULT;
+ switch( rNode.mnFill )
+ {
+ case 1: nFill = AnimationFill::REMOVE; break;
+ case 2: nFill = AnimationFill::FREEZE; break;
+ case 3: nFill = AnimationFill::HOLD; break;
+ case 4: nFill = AnimationFill::TRANSITION; break;
+ }
+ xNode->setFill( nFill );
+ }
+
+ // attribute Duration
+ if( rNode.mnDuration )
+ {
+ Any aDuration;
+ if( rNode.mnDuration > 0 )
+ {
+ aDuration <<= rNode.mnDuration / 1000.0;
+ }
+ else if( rNode.mnDuration < 0 )
+ {
+ aDuration <<= Timing_INDEFINITE;
+ }
+ xNode->setDuration( aDuration );
+ }
+
+ // TODO: DFF_ANIM_PATH_EDIT_MODE
+
+ // set user data
+ Sequence< NamedValue > aUserData;
+
+ // attribute Type
+ if( rSet.hasProperty( DFF_ANIM_NODE_TYPE ) )
+ {
+ sal_Int32 nPPTNodeType = 0;
+ if( rSet.getProperty( DFF_ANIM_NODE_TYPE ) >>= nPPTNodeType )
+ {
+ sal_Int16 nNodeType = css::presentation::EffectNodeType::DEFAULT;
+ switch( nPPTNodeType )
+ {
+ case DFF_ANIM_NODE_TYPE_CLICK_PARALLEL: [[fallthrough]];
+ case DFF_ANIM_NODE_TYPE_ON_CLICK: nNodeType = css::presentation::EffectNodeType::ON_CLICK; break;
+ case DFF_ANIM_NODE_TYPE_WITH_GROUP: [[fallthrough]];
+ case DFF_ANIM_NODE_TYPE_WITH_PREVIOUS: nNodeType = css::presentation::EffectNodeType::WITH_PREVIOUS; break;
+ case DFF_ANIM_NODE_TYPE_AFTER_GROUP: [[fallthrough]];
+ case DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS: nNodeType = css::presentation::EffectNodeType::AFTER_PREVIOUS; break;
+ case DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE: nNodeType = css::presentation::EffectNodeType::MAIN_SEQUENCE; break;
+ case DFF_ANIM_NODE_TYPE_TIMING_ROOT: nNodeType = css::presentation::EffectNodeType::TIMING_ROOT; break;
+ case DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ:nNodeType = css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE; break;
+ }
+
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "node-type";
+ pUserData[nSize].Value <<= nNodeType;
+ }
+ }
+
+ if( rSet.hasProperty( DFF_ANIM_GROUP_ID ) )
+ {
+ sal_Int32 nGroupId;
+ if( rSet.getProperty( DFF_ANIM_GROUP_ID ) >>= nGroupId )
+ {
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "group-id";
+ pUserData[nSize].Value <<= nGroupId;
+ }
+ }
+
+ sal_Int16 nEffectPresetClass = EffectPresetClass::CUSTOM;
+ sal_Int32 nPresetId = 0;
+
+ if( rSet.hasProperty( DFF_ANIM_PRESET_CLASS ) )
+ {
+ sal_Int32 nPresetClass = 0;
+ if ( rSet.getProperty( DFF_ANIM_PRESET_CLASS ) >>= nPresetClass )
+ {
+ switch( nPresetClass )
+ {
+ case DFF_ANIM_PRESS_CLASS_ENTRANCE: nEffectPresetClass = EffectPresetClass::ENTRANCE; break;
+ case DFF_ANIM_PRESS_CLASS_EXIT: nEffectPresetClass = EffectPresetClass::EXIT; break;
+ case DFF_ANIM_PRESS_CLASS_EMPHASIS: nEffectPresetClass = EffectPresetClass::EMPHASIS; break;
+ case DFF_ANIM_PRESS_CLASS_MOTIONPATH: nEffectPresetClass = EffectPresetClass::MOTIONPATH; break;
+ case DFF_ANIM_PRESS_CLASS_OLE_ACTION: nEffectPresetClass = EffectPresetClass::OLEACTION; break;
+ case DFF_ANIM_PRESS_CLASS_MEDIACALL: nEffectPresetClass = EffectPresetClass::MEDIACALL; break;
+ }
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "preset-class";
+ pUserData[nSize].Value <<= nEffectPresetClass;
+ }
+ }
+
+ if( rSet.hasProperty( DFF_ANIM_PRESET_ID ) )
+ {
+ if( rSet.getProperty( DFF_ANIM_PRESET_ID ) >>= nPresetId )
+ {
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "preset-id";
+
+ const oox::ppt::preset_mapping* p = oox::ppt::preset_mapping::getList();
+ while( p->mpStrPresetId && ((p->mnPresetClass != nEffectPresetClass) || (p->mnPresetId != nPresetId )) )
+ p++;
+
+ if( p->mpStrPresetId )
+ {
+ pUserData[nSize].Value <<= OUString::createFromAscii( p->mpStrPresetId );
+ }
+ else
+ {
+ OUStringBuffer sBuffer;
+ sBuffer.append( "ppt_" );
+ switch( nEffectPresetClass )
+ {
+ case EffectPresetClass::ENTRANCE: sBuffer.append( "entrance_" ); break;
+ case EffectPresetClass::EXIT: sBuffer.append( "exit_" ); break;
+ case EffectPresetClass::EMPHASIS: sBuffer.append( "emphasis_" ); break;
+ case EffectPresetClass::MOTIONPATH: sBuffer.append( "motionpath_" ); break;
+ case EffectPresetClass::OLEACTION: sBuffer.append( "oleaction_" ); break;
+ case EffectPresetClass::MEDIACALL: sBuffer.append( "mediacall_" ); break;
+ }
+ sBuffer.append( nPresetId );
+
+ pUserData[nSize].Value <<= sBuffer.makeStringAndClear();
+ }
+ }
+ }
+
+ if( rSet.hasProperty( DFF_ANIM_PRESET_SUB_TYPE ) )
+ {
+ sal_Int32 nPresetSubType = 0;
+ if( rSet.getProperty( DFF_ANIM_PRESET_SUB_TYPE ) >>= nPresetSubType )
+ {
+ if( nPresetSubType )
+ {
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "preset-sub-type";
+ pUserData[nSize].Value <<= oox::ppt::getConvertedSubType( nEffectPresetClass, nPresetId, nPresetSubType );
+ }
+ }
+ }
+
+ if( rSet.hasProperty( DFF_ANIM_AFTEREFFECT ) )
+ {
+ if( rSet.getProperty( DFF_ANIM_AFTEREFFECT ) >>= bAfterEffect )
+ {
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "after-effect";
+ pUserData[nSize].Value <<= bAfterEffect;
+ }
+ }
+
+ if( bAfterEffect && rSet.hasProperty( DFF_ANIM_MASTERREL ) )
+ {
+ sal_Int32 nMasterRel = 2;
+ if( rSet.getProperty( DFF_ANIM_MASTERREL ) >>= nMasterRel )
+ {
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "master-rel";
+ pUserData[nSize].Value <<= nMasterRel;
+ }
+ }
+
+ xNode->setUserData( aUserData );
+
+ // TODO: DFF_ANIM_ID
+ if( rSet.hasProperty( DFF_ANIM_ID ) )
+ {
+ OUString aString;
+ rSet.getProperty( DFF_ANIM_ID ) >>= aString;
+ //if( !aString.isEmpty() )
+ //{
+ //}
+ }
+
+ // TODO: DFF_ANIM_EVENT_FILTER
+ if( rSet.hasProperty( DFF_ANIM_EVENT_FILTER ) )
+ {
+ OUString aString;
+ rSet.getProperty( DFF_ANIM_EVENT_FILTER ) >>= aString;
+ //if( !aString.isEmpty() )
+ //{
+ //}
+ }
+
+ // DFF_ANIM_TIMEFILTER
+ if( rSet.hasProperty( DFF_ANIM_TIMEFILTER ) )
+ {
+ Reference< XAnimate > xAnim( xNode, UNO_QUERY );
+ if( xAnim.is() )
+ {
+ OUString aString;
+ rSet.getProperty( DFF_ANIM_TIMEFILTER ) >>= aString;
+ if( !aString.isEmpty() )
+ {
+ sal_Int32 nElements = 1; // a non empty string has at least one value
+
+ sal_Int32 fromIndex = 0;
+ while(true)
+ {
+ fromIndex = aString.indexOf( ';', fromIndex );
+ if( fromIndex == -1 )
+ break;
+
+ fromIndex++;
+ nElements++;
+ }
+
+ Sequence< TimeFilterPair > aTimeFilter( nElements );
+
+ TimeFilterPair* pValues = aTimeFilter.getArray();
+ sal_Int32 nIndex = 0;
+ while( (nElements--) && (nIndex >= 0) )
+ {
+ const std::u16string_view aToken( o3tl::getToken(aString, 0, ';', nIndex ) );
+
+ size_t nPos = aToken.find( ',' );
+ if( nPos != std::u16string_view::npos )
+ {
+ pValues->Time = o3tl::toDouble(aToken.substr( 0, nPos ));
+ pValues->Progress = o3tl::toDouble(aToken.substr( nPos+1 ));
+ }
+ pValues++;
+ }
+
+ xAnim->setTimeFilter( aTimeFilter );
+ }
+ }
+ }
+
+// TODO: DFF_ANIM_ENDAFTERSLIDE / DFF_ANIM_VOLUME handling. git history has sample code
+ Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
+ if( !xColor.is() )
+ return;
+
+ if( rSet.hasProperty( DFF_ANIM_DIRECTION ) )
+ {
+ bool bDirection = false;
+ if( rSet.getProperty( DFF_ANIM_DIRECTION ) >>= bDirection )
+ xColor->setDirection( !bDirection );
+ }
+
+ if( rSet.hasProperty( DFF_ANIM_COLORSPACE ) )
+ {
+ sal_Int32 nColorSpace = 0;
+ rSet.getProperty( DFF_ANIM_COLORSPACE ) >>= nColorSpace;
+ xColor->setColorInterpolation( (nColorSpace == 0) ? AnimationColorSpace::RGB : AnimationColorSpace::HSL );
+ }
+}
+
+int AnimationImporter::importTimeContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ int nNodes = 0;
+
+ DBG_ASSERT( pAtom && xNode.is(), "invalid call to ppt::AnimationImporter::importTimeContainer()!");
+ if( pAtom && xNode.is() )
+ {
+ importAnimationEvents( pAtom, xNode );
+ importAnimationValues( pAtom, xNode );
+ importAnimationActions( pAtom, xNode );
+
+ dump(">\n");
+
+ // import sub containers
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimNode:
+ case DFF_msofbtAnimEvent:
+ case DFF_msofbtAnimValue:
+ case DFF_msofbtAnimAction:
+ case DFF_msofbtAnimPropertySet:
+ break;
+
+ case DFF_msofbtAnimSubGoup :
+ {
+ if( pChildAtom->hasChildAtom( DFF_msofbtAnimCommand ) )
+ {
+ Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ Reference< XAnimationNode > xChildNode( Command::create(xContext), UNO_QUERY_THROW );
+ nNodes += importAnimationNodeContainer( pChildAtom, xChildNode );
+ Reference< XTimeContainer > xParentContainer( xNode, UNO_QUERY );
+ if( xParentContainer.is() && xChildNode.is() )
+ xParentContainer->appendChild( xChildNode );
+ }
+ else
+ {
+ nNodes += importAnimationContainer( pChildAtom, xNode );
+ }
+ }
+ break;
+ case DFF_msofbtAnimGroup :
+ {
+ nNodes += importAnimationContainer( pChildAtom, xNode );
+ }
+ break;
+ case DFF_msofbtAnimIteration:
+ {
+ if( pChildAtom->seekToContent() )
+ {
+ float fInterval(0.0);
+ sal_Int32 nTextUnitEffect(0), nU1(0), nU2(0), nU3(0);
+
+ mrStCtrl.ReadFloat( fInterval ).ReadInt32( nTextUnitEffect ).ReadInt32( nU1 ).ReadInt32( nU2 ).ReadInt32( nU3 );
+
+ Reference< XIterateContainer > xIter( xNode, UNO_QUERY );
+ if( xIter.is() )
+ {
+ sal_Int16 nIterateType = TextAnimationType::BY_PARAGRAPH;
+ switch( nTextUnitEffect )
+ {
+ case 1: nIterateType = TextAnimationType::BY_WORD; break;
+ case 2: nIterateType = TextAnimationType::BY_LETTER; break;
+ }
+ xIter->setIterateType( nIterateType );
+ xIter->setIterateInterval( static_cast<double>(fInterval) );
+ }
+
+ nNodes++;
+
+ dump( "<iterate" );
+ dump( " iterateType=\"%s\"", (nTextUnitEffect == 0) ? "byElement" : (nTextUnitEffect == 1) ? "byWord" : "byLetter" );
+ dump( " iterateInterval=\"%g\"", fInterval );
+ dump( " u1=\"%ld\"", nU1 );
+ dump( " u2=\"%ld\"", nU2 );
+ dump( " u3=\"%ld\"/>\n", nU3 );
+ }
+ }
+ break;
+
+ case 0xf136:
+ {
+#ifdef DBG_ANIM_LOG
+ sal_uInt32 nU1, nU2;
+ mrStCtrl.ReadUInt32(nU1).ReadUInt32(nU2);
+
+ fprintf( mpFile, "<unknown_0xf136 nU1=\"%" SAL_PRIdINT32 "\" nU2=\"%" SAL_PRIdINT32 "\"/>\n", nU1, nU2 );
+#endif
+ }
+ break;
+
+ default:
+ {
+ dump_atom_header( pChildAtom, true, false );
+ dump_atom( pChildAtom );
+ dump_atom_header( pChildAtom, false, false );
+ }
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+ }
+
+ return nNodes;
+}
+
+int AnimationImporter::importAnimationNodeContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ int nNodes = 0;
+
+ DBG_ASSERT( pAtom && xNode.is(), "invalid call to ppt::AnimationImporter::importAnimationNodeContainer()!");
+ if( pAtom && xNode.is() )
+ {
+ importAnimationEvents( pAtom, xNode );
+ importAnimationValues( pAtom, xNode );
+ importAnimationActions( pAtom, xNode );
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ nNodes ++;
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimNode:
+ case DFF_msofbtAnimEvent:
+ case DFF_msofbtAnimValue:
+ case DFF_msofbtAnimAction:
+ case DFF_msofbtAnimPropertySet:
+ break;
+
+ case DFF_msofbtAnimateFilter:
+ importAnimateFilterContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimateSet:
+ importAnimateSetContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimate:
+ importAnimateContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimateScale:
+ importAnimateScaleContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimateColor:
+ importAnimateColorContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimateRotation:
+ importAnimateRotationContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimateMotion:
+ importAnimateMotionContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimCommand:
+ importCommandContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ {
+ nNodes --;
+ dump_atom_header( pChildAtom, true, false );
+ dump_atom( pChildAtom );
+ dump_atom_header( pChildAtom, false, false );
+ }
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+ }
+
+ return nNodes;
+}
+
+void AnimationImporter::importAnimateFilterContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateFilter && xFilter.is(), "invalid call to ppt::AnimationImporter::importAnimateFilterContainer()!");
+ if( !(pAtom && xFilter.is()) )
+ return;
+
+ sal_uInt32 nBits = 0;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateFilterData:
+ {
+ sal_uInt32 transition(0);
+ mrStCtrl.ReadUInt32( nBits );
+ mrStCtrl.ReadUInt32( transition );
+
+ if( nBits & 1 )
+ xFilter->setMode( transition == 0 );
+
+ dump( " transition=\"%s\"", (transition == 0) ? "in" : "out" );
+ }
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ if( (nBits & 2 ) && ( pChildAtom->getInstance() == 1 ) )
+ {
+ Any aAny;
+ if ( importAttributeValue( pChildAtom, aAny ) )
+ {
+ OUString filter;
+ aAny >>= filter;
+
+ dump( " filter=\"%s\"", filter );
+
+ const oox::ppt::transition* pTransition = oox::ppt::transition::find( filter );
+ if( pTransition )
+ {
+ xFilter->setTransition( pTransition->mnType );
+ xFilter->setSubtype( pTransition->mnSubType );
+ xFilter->setDirection( pTransition->mbDirection );
+ }
+ else
+ {
+ OSL_FAIL( "unknown transition!" );
+ }
+ }
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAnimateAttributeTargetContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateTarget, "invalid call to ppt::AnimationImporter::importAnimateAttributeTargetContainer()!");
+
+ Any aTarget;
+
+ Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
+
+ bool bWrongContext = false;
+
+ if( pAtom )
+ {
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimPropertySet:
+ {
+ PropertySet aSet;
+ importPropertySetContainer( pChildAtom, aSet );
+ if( aSet.hasProperty( DFF_ANIM_RUNTIMECONTEXT ) )
+ {
+ OUString aContext;
+ if( aSet.getProperty( DFF_ANIM_RUNTIMECONTEXT ) >>= aContext )
+ {
+ if( aContext != "PPT" )
+ bWrongContext = true;
+ }
+ }
+
+ dump( aSet );
+ }
+ break;
+
+ case DFF_msofbtAnimateTargetSettings:
+ {
+ if( xAnimate.is() )
+ {
+ sal_uInt32 nBits(0);
+ sal_uInt32 nAdditive(0);
+ sal_uInt32 nAccumulate(0);
+ sal_uInt32 nTransformType(0);
+
+ mrStCtrl.ReadUInt32( nBits ).ReadUInt32( nAdditive ).ReadUInt32( nAccumulate ).ReadUInt32( nTransformType );
+
+ // nBits %0001: additive, %0010: accumulate, %0100: attributeName, %1000: transformtype
+ // nAdditive 0 = base, 1 = sum, 2 = replace, 3 = multiply, 4 = none
+ // nAccumulate 0 = none, 1 = always
+ // nTransformType 0: "property" else "image"
+
+ if( nBits & 3 && xAnimate.is() )
+ {
+ if( nBits & 1 )
+ {
+ sal_Int16 nTemp = AnimationAdditiveMode::BASE;
+ switch( nAdditive )
+ {
+ case 1: nTemp = AnimationAdditiveMode::SUM; break;
+ case 2: nTemp = AnimationAdditiveMode::REPLACE; break;
+ case 3: nTemp = AnimationAdditiveMode::MULTIPLY; break;
+ case 4: nTemp = AnimationAdditiveMode::NONE; break;
+ }
+ xAnimate->setAdditive( nTemp );
+ }
+
+ if( nBits & 2 )
+ {
+ xAnimate->setAccumulate( nAccumulate == 0 );
+ }
+ }
+#ifdef DBG_ANIM_LOG
+ if( nBits & 1 )
+ fprintf( mpFile, " additive=\"%s\"", (nAdditive == 0) ? "base" : (nAdditive == 2) ? "replace" : (nAdditive == 1) ? "sum" : (nAdditive == 3 ) ? "multiply" : (nAdditive == 4) ? "none" : "unknown" );
+
+ if( nBits & 2 )
+ fprintf( mpFile, " accumulate=\"%s\"", (nAccumulate == 0) ? "none" : "always" );
+
+ if( nBits & 8 )
+ fprintf( mpFile, " transformType=\"%s\"", (nTransformType == 0) ? "property" : "image" );
+#endif
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateAttributeNames:
+ {
+ if( xAnimate.is() )
+ {
+ OUString aAttributeName;
+ importAttributeNamesContainer( pChildAtom, aAttributeName );
+ if( xAnimate.is() )
+ xAnimate->setAttributeName( aAttributeName );
+ dump( " attributeName=\"%s\"", aAttributeName );
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTargetElement:
+ {
+ sal_Int16 nSubType;
+ importTargetElementContainer( pChildAtom, aTarget, nSubType );
+ if( xAnimate.is() )
+ xAnimate->setSubItem( nSubType );
+
+ dump( " target=\"" );
+ dump_target( aTarget );
+ dump( "\"" );
+ }
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+ }
+
+ if( bWrongContext )
+ aTarget.clear();
+
+ if( xAnimate.is() )
+ xAnimate->setTarget( aTarget );
+ else
+ {
+ Reference< XCommand > xCommand( xNode, UNO_QUERY );
+ if( xCommand.is() )
+ xCommand->setTarget( aTarget );
+ }
+}
+
+sal_Int16 AnimationImporter::implGetColorSpace( sal_Int32 nMode, sal_Int32 /*nA*/, sal_Int32 /*nB*/, sal_Int32 /*nC*/ )
+{
+ switch( nMode )
+ {
+ case 2: // index
+ default:
+ case 0: // rgb
+ return AnimationColorSpace::RGB;
+
+ case 1: // hsl
+ return AnimationColorSpace::HSL;
+ }
+}
+
+Any AnimationImporter::implGetColorAny( sal_Int32 nMode, sal_Int32 nA, sal_Int32 nB, sal_Int32 nC )
+{
+ switch( nMode )
+ {
+ case 0: // rgb
+ {
+ dump( "rgb(%ld", nA );
+ dump( ",%ld", nB );
+ dump( ",%ld)", nC );
+ Color aColor( static_cast<sal_uInt8>(nA), static_cast<sal_uInt8>(nB), static_cast<sal_uInt8>(nC) );
+ return Any( static_cast<sal_Int32>(aColor.GetRGBColor()) );
+ }
+ case 1: // hsl
+ {
+ dump( "hsl(%ld", nA );
+ dump( ",%ld", nB );
+ dump( ",%ld)", nC );
+ Sequence< double > aHSL{ nA * 360.0/255.0,
+ nB / 255.0,
+ nC / 255.0 };
+ return Any( aHSL );
+ }
+
+ case 2: // index
+ {
+ Color aColor;
+ mpPPTImport->GetColorFromPalette(static_cast<sal_uInt16>(nA), aColor );
+ dump( "index(%ld", nA );
+ dump( " [%ld", static_cast<sal_Int32>(aColor.GetRed()) );
+ dump( ",%ld", static_cast<sal_Int32>(aColor.GetGreen()) );
+ dump( ",%ld])", static_cast<sal_Int32>(aColor.GetBlue()) );
+ return Any( static_cast<sal_Int32>(aColor.GetRGBColor()) );
+ }
+
+ default:
+ {
+ dump( "unknown_%ld(", nMode );
+ dump( "%ld", nA );
+ dump( ",%ld", nB );
+ dump( ",%ld)", nC );
+ OSL_FAIL( "ppt::implGetColorAny(), unhandled color type" );
+
+ Any aAny;
+ return aAny;
+ }
+ }
+}
+
+void AnimationImporter::importAnimateColorContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateColor && xColor.is(), "invalid call to ppt::AnimationImporter::importAnimateColorContainer()!");
+ if( !(pAtom && xColor.is()) )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateColorData:
+ {
+ sal_uInt32 nBits;
+ sal_Int32 nByMode, nByA, nByB, nByC;
+ sal_Int32 nFromMode, nFromA, nFromB, nFromC;
+ sal_Int32 nToMode, nToA, nToB, nToC;
+ mrStCtrl.ReadUInt32( nBits );
+ mrStCtrl.ReadInt32( nByMode ).ReadInt32( nByA ).ReadInt32( nByB ).ReadInt32( nByC );
+ mrStCtrl.ReadInt32( nFromMode ).ReadInt32( nFromA ).ReadInt32( nFromB ).ReadInt32( nFromC );
+ mrStCtrl.ReadInt32( nToMode ).ReadInt32( nToA ).ReadInt32( nToB ).ReadInt32( nToC );
+
+ if (!mrStCtrl.good())
+ {
+ SAL_WARN("filter.ms", "DFF_msofbtAnimateColorData: short read");
+ break;
+ }
+
+ if( nBits & 1 )
+ {
+ dump( " by=\"" );
+ xColor->setBy( implGetColorAny( nByMode, nByA, nByB, nByC ) );
+ xColor->setColorInterpolation( implGetColorSpace( nByMode, nByA, nByB, nByC ) );
+ dump( "\"");
+ }
+
+ if( nBits & 2 )
+ {
+ dump( " from=\"" );
+ xColor->setFrom( implGetColorAny( nFromMode, nFromA, nFromB, nFromC ) );
+ xColor->setColorInterpolation( implGetColorSpace( nFromMode, nFromA, nFromB, nFromC ) );
+ dump( "\"");
+ }
+
+ if( nBits & 4 )
+ {
+ dump( " to=\"" );
+ xColor->setTo( implGetColorAny( nToMode, nToA, nToB, nToC ) );
+ xColor->setColorInterpolation( implGetColorSpace( nToMode, nToA, nToB, nToC ) );
+ dump( "\"");
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAnimateSetContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateSet > xSet( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateSet && xSet.is(), "invalid call to ppt::AnimationImporter::importAnimateSetContainer()!");
+ if( !(pAtom && xSet.is()) )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateSetData:
+ {
+ sal_Int32 nU1, nU2;
+ mrStCtrl.ReadInt32( nU1 ).ReadInt32( nU2 );
+
+ dump( " set_1=\"%ld\"", nU1 );
+ dump( " set_2=\"%ld\"", nU2 );
+ }
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ Any aTo;
+ if ( importAttributeValue( pChildAtom, aTo ) )
+ {
+ xSet->setTo( aTo );
+
+ dump( " value=\"" );
+ dump( aTo );
+ dump( "\"" );
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAnimateContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimate > xAnim( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimate && xAnim.is(), "invalid call to ppt::AnimationImporter::importAnimateContainer()!");
+ if( !(pAtom && xAnim.is()) )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateData:
+ {
+ sal_uInt32 nCalcmode(0), nBits(0), nValueType(0);
+ mrStCtrl.ReadUInt32( nCalcmode ).ReadUInt32( nBits ).ReadUInt32( nValueType );
+
+ if( nBits & 0x08 )
+ {
+ sal_Int16 n = (nCalcmode == 1) ? AnimationCalcMode::LINEAR : /* (nCalcmode == 2) ? AnimationCalcMode::FORMULA : */ AnimationCalcMode::DISCRETE;
+ xAnim->setCalcMode( n );
+ dump( " calcmode=\"%s\"", (nCalcmode == 0) ? "discrete" : (nCalcmode == 1) ? "linear" : (nCalcmode == 2) ? "formula" : "unknown" );
+ }
+
+ if( nBits & 0x30 )
+ {
+ sal_Int16 n = (nValueType == 1) ? AnimationValueType::NUMBER : (nValueType == 2 ) ? AnimationValueType::COLOR : AnimationValueType::STRING;
+ xAnim->setValueType( n );
+ dump( " valueType=\"%s\"", (nValueType == 0) ? "string" : (nValueType == 1) ? "number" : (nValueType == 2) ? "color" : "unknown" );
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimKeyPoints:
+ importAnimateKeyPoints( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ Any a;
+ if ( importAttributeValue( pChildAtom, a ) )
+ {
+ switch( pChildAtom->getInstance() )
+ {
+ case 1: xAnim->setBy( a ); dump( " by=\"" ); break;
+ case 2: xAnim->setFrom( a ); dump( " from=\"" ); break;
+ case 3: xAnim->setTo( a ); dump( " to=\"" ); break;
+ default:
+ dump( " unknown_value=\"" );
+ }
+
+ dump( a );
+ dump( "\"" );
+ }
+ }
+ break;
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAnimateMotionContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateMotion > xMotion( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateMotion && xMotion.is(), "invalid call to ppt::AnimationImporter::importAnimateMotionContainer()!");
+ if( !(pAtom && xMotion.is()) )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateMotionData:
+ {
+ sal_uInt32 nBits, nOrigin;
+ float fByX, fByY, fFromX, fFromY, fToX, fToY;
+
+ mrStCtrl.ReadUInt32( nBits ).ReadFloat( fByX ).ReadFloat( fByY ).ReadFloat( fFromX ).ReadFloat( fFromY ).ReadFloat( fToX ).ReadFloat( fToY ).ReadUInt32( nOrigin );
+
+#ifdef DBG_ANIM_LOG
+ if( nBits & 1 )
+ fprintf( mpFile, " by=\"%g,%g\"", (double)fByX, (double)fByY );
+
+ if( nBits & 2 )
+ fprintf( mpFile, " from=\"%g,%g\"", (double)fFromX, (double)fFromY );
+
+ if( nBits & 4 )
+ fprintf( mpFile, " to=\"%g,%g\"", (double)fToX, (double)fToY );
+
+ if( nBits & 8 )
+ fprintf( mpFile, " origin=\"%s\"", (nOrigin == 1) ? "parent" : (nOrigin == 2) ? "layout" : "unknown" );
+
+#endif
+ }
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ Any aPath;
+ if ( importAttributeValue( pChildAtom, aPath ) )
+ {
+ OUString aStr;
+ if ( aPath >>= aStr )
+ {
+ // E can appear inside a number, so we only check for its presence at the end
+ aStr = aStr.trim();
+ if (aStr.endsWith("E"))
+ aStr = aStr.copy(0, aStr.getLength() - 1);
+ aStr = aStr.trim();
+ aPath <<= aStr;
+ xMotion->setPath( aPath );
+ dump( " path=\"" );
+ dump( aPath );
+ dump( "\"" );
+ }
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importCommandContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XCommand > xCommand( xNode, UNO_QUERY );
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimCommand && xCommand.is(), "invalid call to ppt::AnimationImporter::importCommandContainer()!");
+ if( !(pAtom && xCommand.is()) )
+ return;
+
+ sal_Int32 nBits = 0;
+ Any aValue;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtCommandData:
+ {
+ sal_Int32 nCommandType;
+ // looks like U1 is a bitset, bit 1 enables the type and bit 2 enables
+ // a propertyvalue that follows
+ mrStCtrl.ReadInt32( nBits );
+ mrStCtrl.ReadInt32( nCommandType );
+
+ if( nBits & 1 )
+ {
+ dump( " type=\"%s\"", (nCommandType == 0) ? "event" : ( nCommandType == 1) ? "call" : "verb" );
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ if ( importAttributeValue( pChildAtom, aValue ) )
+ {
+ if( nBits & 2 )
+ {
+ dump( " cmd=\"" );
+ dump( aValue );
+ dump( "\"" );
+ }
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+
+ if( !(nBits & 3) )
+ return;
+
+ OUString aParam;
+ aValue >>= aParam;
+
+ sal_Int16 nCommand = EffectCommands::CUSTOM;
+
+ NamedValue aParamValue;
+
+ if ( aParam == "onstopaudio" )
+ {
+ nCommand = EffectCommands::STOPAUDIO;
+ }
+ else if ( aParam == "play" )
+ {
+ nCommand = EffectCommands::PLAY;
+ }
+ else if( aParam.startsWith( "playFrom" ) )
+ {
+ const std::u16string_view aMediaTime( aParam.subView( 9, aParam.getLength() - 10 ) );
+ rtl_math_ConversionStatus eStatus;
+ double fMediaTime = ::rtl::math::stringToDouble( aMediaTime, u'.', u',', &eStatus );
+ if( eStatus == rtl_math_ConversionStatus_Ok )
+ {
+ aParamValue.Name = "MediaTime";
+ aParamValue.Value <<= fMediaTime;
+ }
+ nCommand = EffectCommands::PLAY;
+ }
+ else if ( aParam == "togglePause" )
+ {
+ nCommand = EffectCommands::TOGGLEPAUSE;
+ }
+ else if ( aParam == "stop" )
+ {
+ nCommand = EffectCommands::STOP;
+ }
+
+ xCommand->setCommand( nCommand );
+ if( nCommand == EffectCommands::CUSTOM )
+ {
+ OSL_FAIL("sd::AnimationImporter::importCommandContainer(), unknown command!");
+ aParamValue.Name = "UserDefined";
+ aParamValue.Value <<= aParam;
+ }
+
+ if( aParamValue.Value.hasValue() )
+ {
+ Sequence< NamedValue > aParamSeq( &aParamValue, 1 );
+ xCommand->setParameter( Any( aParamSeq ) );
+ }
+}
+
+int AnimationImporter::importAudioContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ int nNodes = 0;
+
+ Reference< XAudio > xAudio( xNode, UNO_QUERY );
+ DBG_ASSERT( pAtom && xAudio.is() &&
+ ( (pAtom->getType() == DFF_msofbtAnimGroup) ||
+ (pAtom->getType() == DFF_msofbtAnimSubGoup) ), "invalid call to ppt::AnimationImporter::importAudioContainer()!");
+ if( pAtom && xAudio.is() )
+ {
+ importAnimationEvents( pAtom, xNode );
+ importAnimationValues( pAtom, xNode );
+ importAnimationActions( pAtom, xNode );
+
+ dump(">\n");
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimNode:
+ case DFF_msofbtAnimEvent:
+ case DFF_msofbtAnimValue:
+ case DFF_msofbtAnimAction:
+ case DFF_msofbtAnimPropertySet:
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ Any aValue;
+ if ( importAttributeValue( pChildAtom, aValue ) )
+ {
+ nNodes ++;
+ dump( " value=\"" );
+ dump( aValue );
+ dump( "\"" );
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTargetElement:
+ {
+ sal_Int16 nSubType;
+ Any aSource;
+ importTargetElementContainer( pChildAtom, aSource, nSubType );
+ if( xAudio.is() ) {
+ xAudio->setSource( aSource );
+ nNodes ++;
+ }
+ }
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+
+ // TODO: What to do with them?
+ Any aEmpty;
+ xAudio->setBegin( aEmpty );
+ xAudio->setEnd( aEmpty );
+ }
+
+ return nNodes;
+}
+
+void AnimationImporter::importAnimateScaleContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateScale && xTransform.is(), "invalid call to ppt::AnimationImporter::importAnimateScaleContainer()!");
+ if( !(pAtom && xTransform.is()) )
+ return;
+
+ xTransform->setTransformType( AnimationTransformType::SCALE );
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateScaleData:
+ {
+ sal_uInt32 nBits(0), nZoomContents(0);
+ float fByX(0.0), fByY(0.0), fFromX(0.0), fFromY(0.0), fToX(0.0), fToY(0.0);
+
+ // nBits %001: by, %010: from, %100: to, %1000: zoomContents(bool)
+ mrStCtrl.ReadUInt32( nBits ).ReadFloat( fByX ).ReadFloat( fByY ).ReadFloat( fFromX ).ReadFloat( fFromY ).ReadFloat( fToX ).ReadFloat( fToY ).ReadUInt32( nZoomContents );
+
+ ValuePair aPair;
+ // 'from' value
+ if( nBits & 2 )
+ {
+ aPair.First <<= static_cast<double>(fFromX) / 100.0;
+ aPair.Second <<= static_cast<double>(fFromY) / 100.0;
+ xTransform->setFrom( Any( aPair ) );
+ }
+
+ // 'to' value
+ if( nBits & 4 )
+ {
+ aPair.First <<= static_cast<double>(fToX) / 100.0;
+ aPair.Second <<= static_cast<double>(fToY) / 100.0;
+ xTransform->setTo( Any( aPair ) );
+ }
+
+ // 'by' value
+ if( nBits & 1 )
+ {
+ aPair.First <<= static_cast<double>(fByX) / 100.0;
+ aPair.Second <<= static_cast<double>(fByY) / 100.0;
+
+ if( nBits & 2 )
+ {
+ // 'from' value given, import normally
+ xTransform->setBy( Any( aPair ) );
+ }
+ else
+ {
+ // mapping 'by' to 'to', if no 'from' is
+ // given. This is due to a non-conformity in
+ // PPT, which exports animateScale effects
+ // with a sole 'by' value, but with the
+ // semantics of a sole 'to' animation
+ xTransform->setTo( Any( aPair ) );
+ }
+ }
+
+#ifdef DBG_ANIM_LOG
+ if( nBits & 1 )
+ fprintf( mpFile, " by=\"%g,%g\"", (double)fByX, (double)fByY );
+
+ if( nBits & 2 )
+ fprintf( mpFile, " from=\"%g,%g\"", (double)fFromX, (double)fFromY );
+
+ if( nBits & 4 )
+ fprintf( mpFile, " to=\"%g,%g\"", (double)fToX, (double)fToY );
+
+ if( nBits & 8 )
+ fprintf( mpFile, " zoomContents=\"%s\"", nZoomContents ? "true" : "false" );
+#endif
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAnimateRotationContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateRotation && xTransform.is(), "invalid call to ppt::AnimationImporter::importAnimateRotationContainer()!");
+ if( !(pAtom && xTransform.is()) )
+ return;
+
+ xTransform->setTransformType( AnimationTransformType::ROTATE );
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateRotationData:
+ {
+ sal_uInt32 nBits(0), nU1(0);
+ float fBy(0.0), fFrom(0.0), fTo(0.0);
+
+ // nBits %001: by, %010: from, %100: to, %1000: zoomContents(bool)
+ mrStCtrl.ReadUInt32( nBits ).ReadFloat( fBy ).ReadFloat( fFrom ).ReadFloat( fTo ).ReadUInt32( nU1 );
+
+ if( nBits & 1 )
+ xTransform->setBy( Any( static_cast<double>(fBy) ) );
+
+ if( nBits & 2 )
+ xTransform->setFrom( Any( static_cast<double>(fFrom) ) );
+
+ if( nBits & 4 )
+ xTransform->setTo( Any( static_cast<double>(fTo) ) );
+
+#ifdef DBG_ANIM_LOG
+ if( nBits & 1 )
+ fprintf( mpFile, " by=\"%g\"", (double)fBy );
+
+ if( nBits & 2 )
+ fprintf( mpFile, " from=\"%g\"", (double)fFrom );
+
+ if( nBits & 4 )
+ fprintf( mpFile, " to=\"%g\"", (double)fTo );
+
+ if( nU1 )
+ fprintf( mpFile, " rotation_1=\"%" SAL_PRIdINT32 "\"", nU1 );
+#endif
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAttributeNamesContainer( const Atom* pAtom, OUString& rAttributeNames )
+{
+ OUStringBuffer aNames;
+
+ DBG_ASSERT( pAtom && (pAtom->getType() == DFF_msofbtAnimateAttributeNames), "invalid call to ppt::AnimationImporter::importAttributeName()!" );
+ if( pAtom )
+ {
+ const Atom* pAttributeValueAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimAttributeValue );
+
+ while( pAttributeValueAtom )
+ {
+ Any aAny;
+ if ( importAttributeValue( pAttributeValueAtom, aAny ) )
+ {
+ OUString aName;
+ if( aAny >>= aName )
+ {
+ if( !aNames.isEmpty() )
+ aNames.append( ';' );
+
+ aNames.append( aName );
+ }
+ }
+ else
+ {
+ OSL_FAIL( "error during ppt::AnimationImporter::importAttributeName()!" );
+ }
+
+ pAttributeValueAtom = pAtom->findNextChildAtom( DFF_msofbtAnimAttributeValue, pAttributeValueAtom );
+ }
+ }
+
+ rAttributeNames = aNames.makeStringAndClear();
+}
+
+void AnimationImporter::importAnimationValues( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ DBG_ASSERT( pAtom, "invalid call to ppt::AnimationImporter::importAnimationValues()!" );
+
+ if( !pAtom )
+ return;
+
+ const Atom* pValueAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimValue );
+
+ while( pValueAtom && pValueAtom->seekToContent() )
+ {
+ sal_uInt32 nType(0);
+ mrStCtrl.ReadUInt32( nType );
+ switch( nType )
+ {
+ case 0:
+ {
+ float fRepeat(0.0);
+ mrStCtrl.ReadFloat( fRepeat );
+ xNode->setRepeatCount( (fRepeat < (float(3.40282346638528860e+38))) ? Any( static_cast<double>(fRepeat) ) : Any( Timing_INDEFINITE ) );
+
+#ifdef DBG_ANIM_LOG
+ if( (fRepeat < ((float)3.40282346638528860e+38)) )
+ {
+ dump( " repeat=\"%g\"", (double)fRepeat );
+ }
+ else
+ {
+ dump( " repeat=\"indefinite\"" );
+ }
+#endif
+ }
+ break;
+
+ case 3:
+ {
+ float faccelerate(0.0);
+ mrStCtrl.ReadFloat( faccelerate );
+ xNode->setAcceleration( faccelerate );
+ dump( " accelerate=\"%g\"", static_cast<double>(faccelerate) );
+ }
+ break;
+
+ case 4:
+ {
+ float fdecelerate(0.0);
+ mrStCtrl.ReadFloat( fdecelerate );
+ xNode->setDecelerate( fdecelerate );
+ dump( " decelerate=\"%g\"", static_cast<double>(fdecelerate) );
+ }
+ break;
+
+ case 5:
+ {
+ sal_Int32 nAutoreverse(0);
+ mrStCtrl.ReadInt32( nAutoreverse );
+ xNode->setAutoReverse( nAutoreverse != 0 );
+ dump( " autoreverse=\"%#lx\"", nAutoreverse );
+ }
+ break;
+
+ default:
+ {
+ sal_uInt32 nUnknown;
+ mrStCtrl.ReadUInt32( nUnknown );
+#ifdef DBG_ANIM_LOG
+ fprintf(mpFile, " attribute_%d=\"%#lx\"", nType, nUnknown );
+#endif
+ }
+ break;
+ }
+
+ pValueAtom = pAtom->findNextChildAtom( DFF_msofbtAnimValue, pValueAtom );
+ }
+}
+
+void AnimationImporter::importAnimateKeyPoints( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimate > xAnim( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimKeyPoints && xAnim.is(), "invalid call to ppt::AnimationImporter::importAnimateKeyPoints()!" );
+
+ if( !(pAtom && xAnim.is()) )
+ return;
+
+ // first count keytimes
+ const Atom* pIter = nullptr;
+ int nKeyTimes = 0;
+
+ while( (pIter = pAtom->findNextChildAtom( DFF_msofbtAnimKeyTime, pIter )) != nullptr )
+ nKeyTimes++;
+
+ Sequence< double > aKeyTimes( nKeyTimes );
+ auto aKeyTimesRange = asNonConstRange(aKeyTimes);
+ Sequence< Any > aValues( nKeyTimes );
+ auto aValuesRange = asNonConstRange(aValues);
+ OUString aFormula;
+
+ pIter = pAtom->findFirstChildAtom(DFF_msofbtAnimKeyTime);
+ bool bToNormalize = false;
+ for( int nKeyTime = 0; (nKeyTime < nKeyTimes) && pIter; nKeyTime++ )
+ {
+ if( pIter->seekToContent() )
+ {
+ sal_Int32 nTemp(0);
+ mrStCtrl.ReadInt32(nTemp);
+ double fTemp = static_cast<double>(nTemp) / 1000.0;
+ aKeyTimesRange[nKeyTime] = fTemp;
+ if( fTemp == -1 )
+ bToNormalize = true;
+
+ const Atom* pValue = Atom::findNextChildAtom(pIter);
+ if( pValue && pValue->getType() == DFF_msofbtAnimAttributeValue )
+ {
+ Any aValue1, aValue2;
+ if( importAttributeValue( pValue, aValue1 ) )
+ {
+ pValue = Atom::findNextChildAtom(pValue);
+ if( pValue && pValue->getType() == DFF_msofbtAnimAttributeValue )
+ {
+ // Any occurrence of the formula becomes the formula of the whole list.
+ if (importAttributeValue(pValue, aValue2) && aFormula.isEmpty())
+ aValue2 >>= aFormula;
+ }
+ aValuesRange[nKeyTime] = aValue1;
+ }
+ }
+ }
+ pIter = pAtom->findNextChildAtom(DFF_msofbtAnimKeyTime, pIter);
+ }
+
+#ifdef DBG_ANIM_LOG
+ dump( " keyTimes=\"" );
+ for( int i=0; i<nKeyTimes; ++i )
+ dump( "%f;", aKeyTimes[i] );
+
+ if( !aFormula.isEmpty() )
+ {
+ dump( "formula=\"%s", aFormula );
+ }
+
+ dump( "\" values=\"" );
+ double nVal;
+ OUString aStr;
+ for( int i=0; i<nKeyTimes; ++i )
+ {
+ if( i != 0 )
+ dump( ";" );
+
+ if( aValues[i] >>= aStr )
+ dump( "%s",
+ OUStringToOString( aStr,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ else if( aValues[i] >>= nVal )
+ dump( "%f", nVal );
+ else
+ {
+ ValuePair aValuePair;
+
+ if( aValues[i] >>= aValuePair )
+ {
+ if( aValuePair.First >>= aStr )
+ dump( "%s",
+ OUStringToOString( aStr,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ else if( aValuePair.First >>= nVal )
+ dump( "%f", nVal );
+ else
+ dump( "%X", (sal_Int64)&aValuePair.First );
+
+ if( aValuePair.Second >>= aStr )
+ dump( ",%s",
+ OUStringToOString( aStr,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ else if( aValuePair.Second >>= nVal )
+ dump( ",%f", nVal );
+ else
+ dump( ",%X", (sal_Int64)&aValuePair.Second );
+ }
+ }
+ }
+ dump( "\"" );
+#endif
+ if( bToNormalize && nKeyTimes >= 2 )
+ {
+ // if TimeAnimationValueList contains time -1000, key points must be evenly distributed between 0 and 1 ([MS-PPT] 2.8.31)
+ for( int nKeyTime = 0; nKeyTime < nKeyTimes; ++nKeyTime )
+ {
+ aKeyTimesRange[nKeyTime] = static_cast<double>(nKeyTime) / static_cast<double>(nKeyTimes - 1);
+ }
+ }
+
+ if (aValues.getLength() != aKeyTimes.getLength())
+ throw css::io::WrongFormatException();
+
+ xAnim->setKeyTimes( aKeyTimes );
+ xAnim->setValues( aValues );
+ xAnim->setFormula( aFormula );
+}
+
+bool AnimationImporter::importAttributeValue( const Atom* pAtom, Any& rAny )
+{
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimAttributeValue, "invalid call to ppt::AnimationImporter::importAttributeValue()!" );
+
+ bool bOk = false;
+
+ if( pAtom && pAtom->seekToContent() )
+ {
+ sal_uInt32 nRecLen = pAtom->getLength();
+ if ( nRecLen >= 1 )
+ {
+ sal_Int8 nType(0);
+ mrStCtrl.ReadSChar( nType );
+ switch( nType )
+ {
+ case DFF_ANIM_PROP_TYPE_BYTE :
+ {
+ if ( nRecLen == 2 )
+ {
+ sal_uInt8 nByte(0);
+ mrStCtrl.ReadUChar( nByte );
+ rAny <<= nByte;
+
+ bOk = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PROP_TYPE_INT32 :
+ {
+ if ( nRecLen == 5 )
+ {
+ sal_uInt32 nInt32(0);
+ mrStCtrl.ReadUInt32( nInt32 );
+ rAny <<= nInt32;
+
+ bOk = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PROP_TYPE_FLOAT:
+ {
+ if( nRecLen == 5 )
+ {
+ float fFloat(0.0);
+ mrStCtrl.ReadFloat( fFloat );
+ rAny <<= static_cast<double>(fFloat);
+
+ bOk = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PROP_TYPE_UNISTRING :
+ {
+ if ( ( nRecLen & 1 ) && ( nRecLen > 1 ) )
+ {
+ OUString aOUString = SvxMSDffManager::MSDFFReadZString( mrStCtrl, nRecLen - 1, true );
+ rAny <<= aOUString;
+
+ bOk = true;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ DBG_ASSERT( bOk, "invalid value inside ppt::AnimationImporter::importAttributeValue()!" );
+ return bOk;
+}
+
+void AnimationImporter::importAnimationEvents( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ DBG_ASSERT( xNode.is() && pAtom, "invalid call to ppt::AnimationImporter::importAnimationEvents()!" );
+
+ Any aBegin, aEnd, aNext, aPrev;
+
+ const Atom* pEventAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimEvent );
+ while( pEventAtom )
+ {
+ Any* pEvents = nullptr;
+
+ switch( pEventAtom->getInstance() )
+ {
+ case 1: pEvents = &aBegin; break;
+ case 2: pEvents = &aEnd; break;
+ case 3: pEvents = &aNext; break;
+ case 4: pEvents = &aPrev; break;
+ }
+
+ if( pEvents )
+ {
+ Event aEvent;
+ aEvent.Trigger = EventTrigger::NONE;
+ aEvent.Repeat = 0;
+
+ const Atom* pChildAtom = pEventAtom->findFirstChildAtom();
+
+ while( pChildAtom && pChildAtom->seekToContent() )
+ {
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimTrigger:
+ {
+ sal_Int32 nU1(0), nTrigger(0), nU3(0), nBegin(0);
+ mrStCtrl.ReadInt32( nU1 );
+ mrStCtrl.ReadInt32( nTrigger );
+ mrStCtrl.ReadInt32( nU3 );
+ mrStCtrl.ReadInt32( nBegin );
+
+ switch( nTrigger )
+ {
+ case 0: aEvent.Trigger = EventTrigger::NONE; break;
+ case 1: aEvent.Trigger = EventTrigger::ON_BEGIN; break;
+ case 2: aEvent.Trigger = EventTrigger::ON_END; break;
+ case 3: aEvent.Trigger = EventTrigger::BEGIN_EVENT; break;
+ case 4: aEvent.Trigger = EventTrigger::END_EVENT; break;
+ case 5: aEvent.Trigger = EventTrigger::ON_CLICK; break;
+ case 6: aEvent.Trigger = EventTrigger::ON_DBL_CLICK; break;
+ case 7: aEvent.Trigger = EventTrigger::ON_MOUSE_ENTER; break;
+ case 8: aEvent.Trigger = EventTrigger::ON_MOUSE_LEAVE; break;
+ case 9: aEvent.Trigger = EventTrigger::ON_NEXT; break;
+ case 10: aEvent.Trigger = EventTrigger::ON_PREV; break;
+ case 11: aEvent.Trigger = EventTrigger::ON_STOP_AUDIO; break;
+ }
+
+ if( (nBegin != 0) || (aEvent.Trigger == EventTrigger::NONE) )
+ aEvent.Offset = (nBegin == -1) ? Any( Timing_INDEFINITE ) : Any( nBegin / 1000.0 );
+ }
+ break;
+ case DFF_msofbtAnimateTargetElement:
+ {
+ sal_Int16 nSubType;
+ importTargetElementContainer( pChildAtom, aEvent.Source, nSubType );
+ }
+ break;
+ default:
+ {
+ OSL_FAIL("unknown atom inside ppt::AnimationImporter::importAnimationEvents()!");
+ }
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+
+ *pEvents = oox::addToSequence( *pEvents, (aEvent.Trigger == EventTrigger::NONE) ? aEvent.Offset : Any( aEvent ) );
+ }
+
+ pEventAtom = pAtom->findNextChildAtom( DFF_msofbtAnimEvent, pEventAtom );
+ }
+
+ xNode->setBegin( aBegin );
+ xNode->setEnd( aEnd );
+ // TODO: xNode->setNext( aNext );
+ // TODO: xNode->setPrev( aNext );
+
+#ifdef DBG_ANIM_LOG
+ if( aBegin.hasValue() )
+ {
+ dump( " begin=\"" );
+ dump( aBegin );
+ dump( "\"" );
+ }
+
+ if( aEnd.hasValue() )
+ {
+ dump( " end=\"" );
+ dump( aEnd );
+ dump( "\"" );
+ }
+
+ if( aNext.hasValue() )
+ {
+ dump( " next=\"" );
+ dump( aNext );
+ dump( "\"" );
+ }
+
+ if( aPrev.hasValue() )
+ {
+ dump( " prev=\"" );
+ dump( aPrev );
+ dump( "\"" );
+ }
+#endif
+}
+
+void AnimationImporter::importAnimationActions( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ DBG_ASSERT( pAtom && xNode.is(), "invalid call to ppt::AnimationImporter::importAnimationActions()!");
+
+ if( !pAtom )
+ return;
+
+ const Atom* pActionAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimAction );
+
+ if( !(pActionAtom && pActionAtom->seekToContent()) )
+ return;
+
+ sal_Int32 nConcurrent(0), nNextAction(0), nEndSync(0), nU4(0), nU5(0);
+ mrStCtrl.ReadInt32( nConcurrent );
+ mrStCtrl.ReadInt32( nNextAction );
+ mrStCtrl.ReadInt32( nEndSync );
+ mrStCtrl.ReadInt32( nU4 );
+ mrStCtrl.ReadInt32( nU5 );
+
+ if( nEndSync == 1 )
+ xNode->setEndSync( Any( AnimationEndSync::ALL ) );
+
+#ifdef DBG_ANIM_LOG
+ dump( " concurrent=\"%s\"", nConcurrent == 0 ? "disabled" : (nConcurrent == 1 ? "enabled" : "unknown") );
+
+ dump( " nextAction=\"%s\"", nNextAction == 0 ? "none" : (nNextAction == 1 ? "seek" : "unknown") );
+
+ if( nEndSync != 0 )
+ {
+ dump( " endSync=\"%s\"", nEndSync == 1 ? "all" : "unknown" );
+ }
+
+ dump( " action_4=\"%#lx\"", nU4 );
+ dump( " action_5=\"%#lx\"", nU5 );
+#endif
+}
+
+void AnimationImporter::importTargetElementContainer( const Atom* pAtom, Any& rTarget, sal_Int16& rSubType )
+{
+ rSubType = ShapeAnimationSubType::AS_WHOLE;
+ sal_Int32 nRefMode = -1;
+
+ DBG_ASSERT( pAtom && (pAtom->getType() == DFF_msofbtAnimateTargetElement), "invalid call to ppt::AnimationImporter::importTargetElementContainer()!" );
+ if( !pAtom )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+ while( pChildAtom && pChildAtom->seekToContent() )
+ {
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimReference:
+ {
+ sal_Int32 nRefType(0), nRefId(0);
+ sal_Int32 begin(0), end(0);
+ mrStCtrl.ReadInt32( nRefMode );
+ mrStCtrl.ReadInt32( nRefType );
+ mrStCtrl.ReadInt32( nRefId );
+ mrStCtrl.ReadInt32( begin );
+ mrStCtrl.ReadInt32( end );
+
+ switch( nRefType )
+ {
+ case 1: // shape
+ {
+ SdrObject* pSdrObject = mpPPTImport->getShapeForId( nRefId );
+ if( pSdrObject == nullptr )
+ break;
+
+ rTarget <<= pSdrObject->getUnoShape();
+
+ switch( nRefMode )
+ {
+ case 6: rSubType = ShapeAnimationSubType::ONLY_BACKGROUND; break;
+ case 8: rSubType = ShapeAnimationSubType::ONLY_TEXT; break;
+ case 2: // one paragraph
+ {
+ if((begin == -1) && (end == -1))
+ break;
+
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pSdrObject );
+ if(!pTextObj)
+ break;
+
+ const OutlinerParaObject* pOPO = pTextObj->GetOutlinerParaObject();
+ if( pOPO == nullptr )
+ break;
+
+ const EditTextObject& rEditTextObject = pOPO->GetTextObject();
+
+ const sal_Int32 nParaCount = rEditTextObject.GetParagraphCount();
+
+ sal_Int32 nPara = 0;
+
+ while( (nPara < nParaCount) && (begin > 0) )
+ {
+ sal_Int32 nParaLength = rEditTextObject.GetText( nPara ).getLength() + 1;
+ begin -= nParaLength;
+ end -= nParaLength;
+ nPara++;
+ }
+
+ if( nPara < nParaCount )
+ {
+ ParagraphTarget aParaTarget;
+ rTarget >>= aParaTarget.Shape;
+ /* FIXME: Paragraph should be sal_Int32 as well */
+ aParaTarget.Paragraph = static_cast<sal_Int16>(nPara);
+ rTarget <<= aParaTarget;
+
+ rSubType = ShapeAnimationSubType::ONLY_TEXT;
+ dump( " paragraph %d,", nPara);
+ dump( " %d characters", end );
+ }
+ }
+ }
+ }
+ break;
+
+ case 2: // sound
+ {
+ OUString aSoundURL( mpPPTImport->ReadSound( nRefId ) );
+ rTarget <<= aSoundURL;
+ dump( " srcRef=\"%s\"", aSoundURL );
+ }
+ break;
+ case 3: // audio object
+ case 4: // video object
+ {
+ SdrObject* pSdrObject = mpPPTImport->getShapeForId( nRefId );
+ if( pSdrObject == nullptr )
+ break;
+
+ rTarget <<= pSdrObject->getUnoShape();
+ }
+ break;
+ default:
+ OSL_FAIL("unknown reference type");
+ }
+
+ }
+ break;
+ case 0x2b01:
+ {
+ sal_Int32 nU1;
+ mrStCtrl.ReadInt32( nU1 );
+ }
+ break;
+ default:
+ OSL_FAIL("unknown atom inside ppt::AnimationImporter::importTargetElementContainer()!");
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+
+ }
+}
+
+void AnimationImporter::importPropertySetContainer( const Atom* pAtom, PropertySet& rSet )
+{
+ DBG_ASSERT( pAtom && (pAtom->getType() == DFF_msofbtAnimPropertySet), "invalid call to ppt::AnimationImporter::importPropertySetContainer()!" );
+
+ if( !pAtom )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+ while( pChildAtom )
+ {
+ if( pChildAtom->getType() == DFF_msofbtAnimAttributeValue )
+ {
+ Any aAny;
+ (void)importAttributeValue( pChildAtom, aAny );
+ rSet.maProperties[ pChildAtom->getInstance() ] = aAny;
+ }
+ else
+ {
+ OSL_FAIL("unknown atom inside ppt::AnimationImporter::importPropertySetContainer()!");
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+#ifdef DBG_ANIM_LOG
+void AnimationImporter::dump_atom_header( const Atom* pAtom, bool bOpen, bool bAppend )
+{
+ if( pAtom )
+ {
+ const char* pTitle;
+
+ switch( pAtom->getType() )
+ {
+ case DFF_msofbtAnimEvent: pTitle = "AnimEvent"; break;
+ case DFF_msofbtAnimTrigger: pTitle = "AnimTrigger"; break;
+ case DFF_msofbtAnimateMotion: pTitle = "AnimateMotion"; break;
+ case DFF_msofbtAnimPropertySet: pTitle = "AnimPropertySet"; break;
+ case DFF_msofbtAnimateAttributeNames: pTitle = "AnimAttributeName"; break;
+ case DFF_msofbtAnimAttributeValue: pTitle = "AnimAttributeValue"; break;
+ case DFF_msofbtAnimGroup: pTitle = "AnimGroup"; break;
+ case DFF_msofbtAnimNode: pTitle = "AnimNode"; break;
+ case DFF_msofbtAnimValue: pTitle = "AnimValue"; break;
+ case DFF_msofbtAnimateFilter: pTitle = "animateFilter"; break;
+ case DFF_msofbtAnimate: pTitle = "animate"; break;
+ case DFF_msofbtAnimateSet: pTitle = "set"; break;
+ case DFF_msofbtAnimKeyTime: pTitle = "AnimKeyTime"; break;
+ case DFF_msofbtAnimKeyPoints: pTitle = "AnimKeyPoints"; break;
+ case DFF_msofbtAnimReference: pTitle = "AnimReference"; break;
+ case DFF_msofbtAnimateTargetElement: pTitle = "AnimTargetElementContainer"; break;
+ case DFF_msofbtAnimAction: pTitle = "AnimAction"; break;
+ case DFF_msofbtAnimCommand: pTitle = "AnimCommand"; break;
+ case DFF_msofbtAnimateTarget: pTitle = "TransformationTarget"; break;
+ case DFF_msofbtAnimateTargetSettings: pTitle = "TransformationTargetSettings"; break;
+ case DFF_msofbtAnimIteration: pTitle = "iterate"; break;
+ case DFF_msofbtAnimateColorData: pTitle = "colorData"; break;
+ case DFF_msofbtAnimateScaleData: pTitle = "scaleData"; break;
+ case DFF_msofbtAnimateSetData: pTitle = "setData"; break;
+
+ default:
+ {
+ static char buffer[128];
+ sprintf( buffer, "unknown_%#x", pAtom->getType() );
+ pTitle = buffer;
+ }
+ }
+
+ if( bOpen )
+ {
+ fprintf(mpFile, "<%s", pTitle );
+
+ fprintf(mpFile, " instance=\"%hu\"%s",
+ pAtom->getInstance(),
+ bAppend ? "" : ">\n");
+ }
+ else
+ {
+ if( bAppend )
+ fprintf(mpFile,"/>\n");
+ else
+ fprintf(mpFile, "</%s>\n", pTitle );
+ }
+ }
+}
+
+void AnimationImporter::dump( sal_uInt32 nLen, bool bNewLine )
+{
+ char * faul = "0123456789abcdef";
+
+ sal_uInt32 i = 0;
+ int b = 0;
+ char nData;
+
+ for( i = 0; i < nLen; i++ )
+ {
+ mrStCtrl.ReadChar(nData);
+
+ fprintf( mpFile, "%c%c ", faul[ (nData >> 4) & 0x0f ], faul[ nData & 0x0f ] );
+
+ b++;
+ if( bNewLine && (b == 32) )
+ {
+ fprintf(mpFile,"\n");
+ b = 0;
+ }
+ }
+ if( (b != 0) && bNewLine )
+ fprintf(mpFile,"\n");
+}
+
+void AnimationImporter::dump_atom( const Atom* pAtom, bool bNewLine )
+{
+ if( pAtom )
+ {
+ if( pAtom->isContainer() )
+ {
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+ while( pChildAtom )
+ {
+ if( pChildAtom->getType() == DFF_msofbtAnimAttributeValue )
+ {
+ fprintf(mpFile, "<attributeValue instance=\"%hu\"", pChildAtom->getInstance() );
+
+ Any aValue;
+ if( importAttributeValue( pChildAtom, aValue ) )
+ {
+ sal_Int32 nInt;
+ OUString aString;
+ double fDouble;
+
+ if( aValue >>= nInt )
+ {
+ fprintf(mpFile, " value=\"%" SAL_PRIdINT32 "\"", nInt );
+ }
+ else if( aValue >>= aString )
+ {
+ fprintf(mpFile, " value=\"%s\"",
+ OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr());
+ }
+ else if( aValue >>= fDouble )
+ {
+ fprintf(mpFile, " value=\"%g\"", fDouble );
+ }
+ }
+ else
+ {
+ if( pChildAtom->seekToContent() )
+ {
+ fprintf(mpFile, " value=\"" );
+ dump_atom( pChildAtom, false );
+ fprintf(mpFile, "\"");
+ }
+ }
+
+ fprintf(mpFile, "/>\n" );
+ }
+ else
+ {
+ dump_atom_header( pChildAtom, true, pChildAtom->getType() == DFF_msofbtAnimAttributeValue );
+ dump_atom( pChildAtom );
+ dump_atom_header( pChildAtom, false, pChildAtom->getType() == DFF_msofbtAnimAttributeValue );
+ }
+
+ pChildAtom = Atom::findNextChildAtom(pChildAtom);
+ }
+ }
+ else if( pAtom->seekToContent() )
+ {
+ dump( pAtom->getLength(), bNewLine );
+ }
+ }
+}
+
+void AnimationImporter::dump_anim_group( const Atom* pAtom, const AnimationNode& rNode, const PropertySet& rSet, bool bOpen )
+{
+ fprintf( mpFile, bOpen ? "<" : "</" );
+
+ switch( rNode.mnGroupType )
+ {
+ case mso_Anim_GroupType_PAR:
+ fprintf( mpFile, "par" );
+ break;
+ case mso_Anim_GroupType_SEQ:
+ fprintf( mpFile, "seq" );
+ break;
+ case mso_Anim_GroupType_NODE:
+ switch( rNode.mnNodeType )
+ {
+ case mso_Anim_Behaviour_FILTER:
+ fprintf( mpFile, "animateFilter" );
+ break;
+ case mso_Anim_Behaviour_ANIMATION:
+ if( pAtom->hasChildAtom( DFF_msofbtAnimateSet ) )
+ fprintf( mpFile, "set" );
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateColor ) )
+ fprintf( mpFile, "animateColor" );
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateScale ) )
+ fprintf( mpFile, "animateScale" );
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateRotation ) )
+ fprintf( mpFile, "animateRotation" );
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateMotion ) )
+ fprintf( mpFile, "animateMotion" );
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimCommand ) )
+ fprintf( mpFile, "command" );
+ else
+ fprintf( mpFile, "animation" );
+ break;
+ default:
+ {
+ fprintf( mpFile, "unknown_node_%#lx", rNode.mnNodeType );
+ }
+ break;
+ }
+ break;
+ case mso_Anim_GroupType_MEDIA:
+ fprintf( mpFile, "media" );
+ break;
+ default:
+ fprintf( mpFile, "unknown_group_%#lx", rNode.mnGroupType );
+ break;
+ }
+
+ if( bOpen )
+ {
+ dump( rNode );
+ dump( rSet );
+ }
+
+ fprintf(mpFile,">\n");
+}
+
+void AnimationImporter::dump( const AnimationNode& rNode )
+{
+ // dump animation node
+ if( rNode.mnRestart != 0 )
+ {
+ fprintf(mpFile," restart=\"%s\"",
+ rNode.mnRestart == 1 ? "always" : (rNode.mnRestart == 2 ? "whenOff" : (rNode.mnRestart == 3 ? "never" : "unknown")) );
+ }
+
+ if( rNode.mnFill )
+ {
+ fprintf(mpFile," fill=\"%s\"",
+ rNode.mnFill == 1 ? "remove" : (rNode.mnFill == 3 ? "hold" : (rNode.mnFill == 2 ? "freeze" : "unknown")) );
+ }
+
+ if( rNode.mnDuration > 0 )
+ {
+ double fSeconds = rNode.mnDuration;
+ fSeconds /= 1000.0;
+ fprintf(mpFile, " dur=\"%g\"", fSeconds);
+ }
+ else if( rNode.mnDuration < 0 )
+ {
+ fprintf(mpFile, " dur=\"indefinite\"" );
+ }
+
+ if( rNode.mnU1 ) fprintf(mpFile," u1=\"%#lx\"", rNode.mnU1);
+ if( rNode.mnU3 ) fprintf(mpFile," u3=\"%#lx\"", rNode.mnU3);
+ if( rNode.mnU4 ) fprintf(mpFile," u4=\"%#lx\"", rNode.mnU4);
+}
+
+void AnimationImporter::dump( Any& rAny )
+{
+ Sequence< Any > aSeq;
+ sal_Int32 nInt;
+ double fDouble;
+ OUString aString;
+ sal_Bool bBool;
+ Event aEvent;
+ Timing aTiming;
+
+ if( rAny >>= aSeq )
+ {
+ const sal_Int32 nSize = aSeq.getLength();
+ sal_Int32 nIndex = 0;
+ while( nIndex < nSize )
+ {
+ dump( aSeq[nIndex++] );
+ if(nIndex < nSize)
+ fprintf( mpFile, "," );
+ }
+ }
+ else if( rAny >>= aString )
+ {
+ fprintf( mpFile, "%s", OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+ }
+ else if( rAny >>= nInt )
+ {
+ fprintf( mpFile, "%" SAL_PRIdINT32, nInt );
+ }
+ else if( rAny >>= bBool )
+ {
+ fprintf( mpFile, "%s", bBool ? "true" : "false" );
+ }
+ else if( rAny >>= fDouble )
+ {
+ fprintf( mpFile, "%g", fDouble );
+ }
+ else if( rAny >>= aTiming )
+ {
+ fprintf( mpFile, "%s", aTiming == (Timing_INDEFINITE) ? "indefinite" : "media" );
+ }
+ else if( rAny >>= aEvent )
+ {
+ if( aEvent.Trigger != EventTrigger::NONE )
+ {
+ static const char* triggers[] =
+ {
+ "none","onbegin","onend","begin",
+ "end","onclick","ondoubleclick","onmouseenter",
+ "onmouseleave","onpptnext","onpptprev","onstopaudio"
+ };
+
+ if( aEvent.Source.hasValue() )
+ {
+ dump_target( aEvent.Source );
+ dump( "." );
+ }
+
+ dump( triggers[ aEvent.Trigger ] );
+ }
+
+ if( aEvent.Offset.hasValue() )
+ {
+ double fOffset;
+ if( aEvent.Offset >>= fOffset )
+ fprintf( mpFile, "%g", fOffset );
+ else
+ dump( "indefinite" );
+ }
+ }
+}
+
+void AnimationImporter::dump( const PropertySet& rSet )
+{
+ // dump property set
+
+ for( const auto& rProp : rSet.maProperties )
+ {
+ bool bKnown = false;
+
+ const sal_Int32 nInstance = rProp.first;
+ Any aAny( rProp.second );
+
+ switch ( nInstance )
+ {
+ case DFF_ANIM_COLORSPACE:
+ {
+ sal_Int32 nColorSpace;
+ if( aAny >>= nColorSpace )
+ {
+ fprintf( mpFile, " colorSpace=\"%s\"", (nColorSpace == 0) ? "rgb" : (nColorSpace == 1) ? "hsl" : "unknown" );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_DIRECTION:
+ {
+ sal_Bool bDirection;
+ if( aAny >>= bDirection )
+ {
+ fprintf( mpFile, " direction=\"%s\"", bDirection ? "cclockwise" : "clockwise" );
+ bKnown = true;
+ }
+ else
+ {
+ sal_Int32 nMasterRel;
+ if( aAny >>= nMasterRel )
+ {
+ fprintf( mpFile, " direction=\"%s\"", nMasterRel == 0 ? "sameClick" : ( nMasterRel == 2 ? "nextClick" : "lastClick" ) );
+ bKnown = true;
+ }
+ }
+ }
+ break;
+
+ case DFF_ANIM_OVERRIDE: // TODO
+ {
+ sal_Int32 nOverride;
+ if( aAny >>= nOverride )
+ {
+ fprintf( mpFile, " override=\"%s\"", (nOverride == 1) ? "childStyle" : (nOverride == 0) ? "normal" : "unknown" );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PATH_EDIT_MODE:
+ {
+ sal_Bool bPathEditMode;
+ if( aAny >>= bPathEditMode )
+ {
+ fprintf( mpFile, " pptPathEditMode=\"%s\"", bPathEditMode ? "relative" : "fixed" );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PRESET_ID :
+ {
+ sal_Int32 nPresetId ;
+ if( aAny >>= nPresetId )
+ {
+ fprintf(mpFile, " presetid=\"%" SAL_PRIdINT32 "\"", nPresetId );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PRESET_SUB_TYPE :
+ {
+ sal_Int32 nPointsType ;
+ if( aAny >>= nPointsType )
+ {
+ fprintf(mpFile, " presetSubType=\"%" SAL_PRIdINT32 "\"", nPointsType );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PRESET_CLASS :
+ {
+ sal_Int32 nPresetClass;
+ if ( aAny >>= nPresetClass )
+ {
+ const char* pMode;
+ switch( nPresetClass )
+ {
+ case DFF_ANIM_PRESS_CLASS_USER_DEFINED: pMode = "userdefined"; break;
+ case DFF_ANIM_PRESS_CLASS_ENTRANCE: pMode = "entrance"; break;
+ case DFF_ANIM_PRESS_CLASS_EXIT: pMode = "exit"; break;
+ case DFF_ANIM_PRESS_CLASS_EMPHASIS: pMode = "emphasis"; break;
+ case DFF_ANIM_PRESS_CLASS_MOTIONPATH: pMode = "motionpath"; break;
+ case DFF_ANIM_PRESS_CLASS_OLE_ACTION: pMode = "oleaction"; break;
+ case DFF_ANIM_PRESS_CLASS_MEDIACALL: pMode = "mediacall"; break;
+ default:
+ pMode = nullptr;
+ break;
+ }
+
+ if (pMode)
+ fprintf(mpFile, " class=\"%s\"", pMode);
+ else
+ fprintf(mpFile, " class =\"%" SAL_PRIdINT32 "\"", nPresetClass);
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_NODE_TYPE :
+ {
+ sal_Int32 nNodeType;
+ if ( aAny >>= nNodeType )
+ {
+ const char* pNode;
+ switch( nNodeType )
+ {
+ case DFF_ANIM_NODE_TYPE_ON_CLICK: pNode = "onclick"; break;
+ case DFF_ANIM_NODE_TYPE_WITH_PREVIOUS: pNode = "withprevious"; break;
+ case DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS: pNode = "afterprevious"; break;
+ case DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE: pNode = "mainsequence"; break;
+ case DFF_ANIM_NODE_TYPE_TIMING_ROOT: pNode = "timingroot"; break;
+ case DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ:pNode = "interactivesequence"; break;
+ default :
+ {
+ static char buffer[128];
+ sprintf( buffer, "%" SAL_PRIdINT32, nNodeType );
+ pNode = buffer;
+ }
+ break;
+ }
+
+ fprintf(mpFile, " nodeType=\"%s\"", pNode);
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_GROUP_ID:
+ {
+ sal_Int32 nGroupId;
+ if ( aAny >>= nGroupId )
+ {
+ fprintf( mpFile, " groupId=\"%" SAL_PRIdINT32 "\"", nGroupId );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_ID:
+ {
+ OUString aString;
+ if( aAny >>= aString )
+ {
+ fprintf( mpFile, " id=\"%s\"",
+ OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_EVENT_FILTER:
+ {
+ OUString aString;
+ if( aAny >>= aString )
+ {
+ fprintf( mpFile, " eventFilter=\"%s\"",
+ OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_ENDAFTERSLIDE:
+ {
+ sal_Int32 nEndAfterSlide;
+ if( aAny >>= nEndAfterSlide )
+ {
+ fprintf(mpFile, " endAfterSlide=\"%" SAL_PRIdINT32 "\"", nEndAfterSlide );
+ bKnown = true;
+ }
+ }
+
+ case DFF_ANIM_TIMEFILTER:
+ {
+ OUString aString;
+ if( aAny >>= aString )
+ {
+ fprintf( mpFile, " timeFilter=\"%s\"",
+ OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_RUNTIMECONTEXT:
+ {
+ OUString aString;
+ if( aAny >>= aString )
+ {
+ fprintf( mpFile, " runtimeContext=\"%s\"",
+ OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_VOLUME:
+ {
+ double fVolume(0.0);
+ if( aAny >>= fVolume )
+ {
+ fprintf( mpFile, " volume=\"%g%%\"", (double)(fVolume * 100.0) );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_AFTEREFFECT:
+ {
+ sal_Bool bAfterEffect;
+ if( aAny >>= bAfterEffect )
+ {
+ fprintf( mpFile, "afterEffect=\"%s\"", bAfterEffect ? "true" : "false" );
+ bKnown = true;
+ }
+ }
+ break;
+
+ }
+
+ if( !bKnown )
+ {
+ fprintf( mpFile, " unknown_%" SAL_PRIdINT32 "=\"", nInstance );
+ dump( aAny );
+ fprintf( mpFile, "\"" );
+ }
+ }
+}
+
+void AnimationImporter::dump_target( Any& rAny )
+{
+ Any aSource, aSourceData;
+ Sequence< Any > aSeq;
+ if( rAny >>= aSeq )
+ {
+ if( aSeq.getLength() >= 1 ) aSource = aSeq[0];
+ if( aSeq.getLength() >= 2 ) aSourceData = aSeq[1];
+ }
+ else
+ {
+ aSource = rAny;
+ }
+
+ Reference< XShape > xShape;
+ aSource >>= xShape;
+ if( xShape.is() )
+ {
+ OUString aStr( xShape->getShapeType() );
+ dump( aStr );
+
+ if( aSourceData.hasValue() )
+ {
+ dump( "(" );
+ dump( aSourceData );
+ dump( ")" );
+ }
+ }
+}
+
+void AnimationImporter::dump( const char * pText )
+{
+ fprintf( mpFile, "%s", pText );
+}
+
+void AnimationImporter::dump( const OUString& rString )
+{
+ fprintf( mpFile, OUStringToOString(rString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+}
+
+void AnimationImporter::dump( const char * pText, sal_Int64 nInt )
+{
+ fprintf( mpFile, pText, nInt );
+}
+
+void AnimationImporter::dump( const char * pText, sal_Int32 nInt )
+{
+ fprintf( mpFile, pText, nInt );
+}
+
+void AnimationImporter::dump( const char * pText, double fDouble )
+{
+ fprintf( mpFile, pText, fDouble );
+}
+
+void AnimationImporter::dump( const char * pText, const char * pText2 )
+{
+ fprintf( mpFile, pText, pText2 );
+}
+
+void AnimationImporter::dump( const char * pText, const OUString& rString )
+{
+ fprintf( mpFile, pText, OUStringToOString(rString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+}
+
+#else
+
+void AnimationImporter::dump_atom_header( const Atom* , bool , bool )
+{
+}
+
+void AnimationImporter::dump_atom( const Atom* , bool )
+{
+}
+
+void AnimationImporter::dump_target( css::uno::Any& )
+{
+}
+
+void AnimationImporter::dump( css::uno::Any& )
+{
+}
+
+void AnimationImporter::dump( const PropertySet& )
+{
+}
+
+void AnimationImporter::dump( const AnimationNode& )
+{
+}
+
+void AnimationImporter::dump( const char * )
+{
+}
+
+void AnimationImporter::dump( const char * , sal_Int32 )
+{
+}
+
+void AnimationImporter::dump( const char * , double )
+{
+}
+
+void AnimationImporter::dump( const char * , const char * )
+{
+}
+
+void AnimationImporter::dump( const char * , std::u16string_view )
+{
+}
+
+#endif
+
+} // namespace ppt;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/pptinanimations.hxx b/sd/source/filter/ppt/pptinanimations.hxx
new file mode 100644
index 000000000..ed79144b9
--- /dev/null
+++ b/sd/source/filter/ppt/pptinanimations.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <vector>
+#include <animations.hxx>
+
+#ifdef DBG_ANIM_LOG
+#include <stdio.h>
+#endif
+
+namespace com::sun::star::animations { class XAnimationNode; }
+namespace com::sun::star::drawing { class XDrawPage; }
+namespace ppt { struct AnimationNode; }
+
+class DffRecordHeader;
+class SvStream;
+class ImplSdPPTImport;
+
+namespace ppt
+{
+class PropertySet;
+class Atom;
+
+class AnimationImporter
+{
+public:
+ AnimationImporter( ImplSdPPTImport* pPPTImport, SvStream& rStCtrl );
+
+ int import( const css::uno::Reference< css::drawing::XDrawPage >& xPage, const DffRecordHeader& rProgTagContentHd );
+
+private:
+ int importAnimationContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xParent );
+ int importTimeContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ int importAnimationNodeContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+
+ void importAnimateSetContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importAnimateFilterContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importAnimateContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importAnimateScaleContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importAnimateColorContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importAnimateRotationContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importAnimateMotionContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importCommandContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ int importAudioContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+
+ void importAnimationEvents( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importAnimationValues( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importAnimationActions( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importAnimateAttributeTargetContainer( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+
+ void importAnimateKeyPoints( const Atom* pAtom, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void importPropertySetContainer( const Atom* pAtom,PropertySet& rSet );
+ bool importAttributeValue( const Atom* pAtom, css::uno::Any& rAny );
+ void importAttributeNamesContainer( const Atom* pAtom, OUString& rAttributeNames );
+ void importTargetElementContainer( const Atom* pAtom, css::uno::Any& rTarget, sal_Int16& nSubType );
+
+ static void fillNode( css::uno::Reference< css::animations::XAnimationNode > const & xTiming, const AnimationNode& rNode, const PropertySet& rSet );
+ static css::uno::Reference< css::animations::XAnimationNode > createNode( const Atom* pAtom, const AnimationNode& rNode );
+
+ bool convertAnimationNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode, const css::uno::Reference< css::animations::XAnimationNode >& xParent );
+ css::uno::Any implGetColorAny( sal_Int32 nMode, sal_Int32 nA, sal_Int32 nB, sal_Int32 nC );
+ static sal_Int16 implGetColorSpace( sal_Int32 nMode, sal_Int32 nA, sal_Int32 nB, sal_Int32 nC );
+
+private:
+ css::uno::Reference< css::animations::XAnimationNode > mxRootNode;
+
+ ImplSdPPTImport* mpPPTImport;
+ SvStream& mrStCtrl;
+
+ std::vector< sd::AfterEffectNode > maAfterEffectNodes;
+
+#ifdef DBG_ANIM_LOG
+ FILE * mpFile;
+ void dump_anim_group( const Atom* pAtom, const AnimationNode& rNode, const PropertySet& rSet, bool bOpen );
+ void dump( const OUString& rString );
+ void dump( sal_uInt32 nLen, bool bNewLine = true );
+#endif
+
+ static void dump_atom_header( const Atom* pAtom, bool bOpen, bool bAppend );
+ static void dump_atom( const Atom* pAtom, bool bNewLine = true );
+ static void dump_target( css::uno::Any& rAny );
+ static void dump( css::uno::Any& rAny );
+ static void dump( const PropertySet& rSet );
+ static void dump( const AnimationNode& rNode );
+ static void dump( const char * pText );
+ static void dump( const char * pText, sal_Int32 nInt );
+ void dump( const char * pText, sal_Int64 nInt );
+ static void dump( const char * pText, double fDouble );
+ static void dump( const char * pText, const char * pText2 );
+ static void dump( const char * pText, std::u16string_view rString );
+};
+
+} // namespace ppt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/propread.cxx b/sd/source/filter/ppt/propread.cxx
new file mode 100644
index 000000000..c82c0d791
--- /dev/null
+++ b/sd/source/filter/ppt/propread.cxx
@@ -0,0 +1,615 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "propread.hxx"
+#include <rtl/tencinfo.h>
+#include <rtl/textenc.h>
+#include <sal/log.hxx>
+#include <o3tl/sorted_vector.hxx>
+#include <osl/diagnose.h>
+#include <memory>
+
+PropEntry::PropEntry( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize ) :
+ mnId ( nId ),
+ mnSize ( nBufSize ),
+ mpBuf ( new sal_uInt8[ nBufSize ] )
+{
+ memcpy( mpBuf.get(), pBuf, nBufSize );
+};
+
+PropEntry::PropEntry( const PropEntry& rProp ) :
+ mnId ( rProp.mnId ),
+ mnSize ( rProp.mnSize ),
+ mpBuf ( new sal_uInt8[ mnSize ] )
+{
+ memcpy( mpBuf.get(), rProp.mpBuf.get(), mnSize );
+};
+
+PropEntry& PropEntry::operator=(const PropEntry& rPropEntry)
+{
+ if ( this != &rPropEntry )
+ {
+ mnId = rPropEntry.mnId;
+ mnSize = rPropEntry.mnSize;
+ mpBuf.reset( new sal_uInt8[ mnSize ] );
+ memcpy( mpBuf.get(), rPropEntry.mpBuf.get(), mnSize );
+ }
+ return *this;
+}
+
+void PropItem::Clear()
+{
+ Seek( STREAM_SEEK_TO_BEGIN );
+ delete[] static_cast<sal_uInt8*>(SwitchBuffer());
+}
+
+static sal_Int32 lcl_getMaxSafeStrLen(sal_uInt32 nSize)
+{
+ nSize -= 1; //Drop NULL terminator
+
+ //If it won't fit in a string, clip it to the max size that does
+ if (nSize > SAL_MAX_INT32)
+ nSize = SAL_MAX_INT32;
+
+ return static_cast< sal_Int32 >( nSize );
+}
+
+bool PropItem::Read( OUString& rString, sal_uInt32 nStringType, bool bAlign )
+{
+ sal_uInt32 nType, nItemPos;
+ bool bRetValue = false;
+
+ nItemPos = Tell();
+
+ if ( nStringType == VT_EMPTY )
+ {
+ nType = VT_NULL; // Initialize in case stream fails.
+ ReadUInt32( nType );
+ }
+ else
+ nType = nStringType & VT_TYPEMASK;
+
+ sal_uInt32 nItemSize(0); // Initialize in case stream fails.
+ ReadUInt32(nItemSize);
+
+ switch( nType )
+ {
+ case VT_LPSTR :
+ {
+ if (nItemSize)
+ {
+ auto nMaxSizePossible = remainingSize();
+ if (nItemSize > nMaxSizePossible)
+ {
+ SAL_WARN("sd.filter", "String of Len " << nItemSize << " claimed, only " << nMaxSizePossible << " possible");
+ nItemSize = nMaxSizePossible;
+ }
+ }
+
+ if (nItemSize)
+ {
+ try
+ {
+ std::unique_ptr<char[]> pString( new char[ nItemSize ] );
+ if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
+ {
+ nItemSize >>= 1;
+ if ( nItemSize > 1 )
+ {
+ sal_Unicode* pWString = reinterpret_cast<sal_Unicode*>(pString.get());
+ for (sal_uInt32 i = 0; i < nItemSize; ++i)
+ ReadUtf16( pWString[ i ] );
+ rString = OUString(pWString, lcl_getMaxSafeStrLen(nItemSize));
+ }
+ else
+ rString.clear();
+ bRetValue = true;
+ }
+ else
+ {
+ SvMemoryStream::ReadBytes(pString.get(), nItemSize);
+ if ( pString[ nItemSize - 1 ] == 0 )
+ {
+ if ( nItemSize > 1 )
+ rString = OUString(pString.get(), rtl_str_getLength(pString.get()), mnTextEnc);
+ else
+ rString.clear();
+ bRetValue = true;
+ }
+ }
+ }
+ catch( const std::bad_alloc& )
+ {
+ OSL_FAIL( "sd PropItem::Read bad alloc" );
+ }
+ }
+ if ( bAlign )
+ SeekRel( ( 4 - ( nItemSize & 3 ) ) & 3 ); // dword align
+ }
+ break;
+
+ case VT_LPWSTR :
+ {
+ if (nItemSize)
+ {
+ auto nMaxSizePossible = remainingSize() / sizeof(sal_Unicode);
+ if (nItemSize > nMaxSizePossible)
+ {
+ SAL_WARN("sd.filter", "String of Len " << nItemSize << " claimed, only " << nMaxSizePossible << " possible");
+ nItemSize = nMaxSizePossible;
+ }
+ }
+
+ if (nItemSize)
+ {
+ try
+ {
+ std::unique_ptr<sal_Unicode[]> pString( new sal_Unicode[ nItemSize ] );
+ for (sal_uInt32 i = 0; i < nItemSize; ++i)
+ ReadUtf16( pString[ i ] );
+ if ( pString[ nItemSize - 1 ] == 0 )
+ {
+ if ( static_cast<sal_uInt16>(nItemSize) > 1 )
+ rString = OUString(pString.get(), lcl_getMaxSafeStrLen(nItemSize));
+ else
+ rString.clear();
+ bRetValue = true;
+ }
+ }
+ catch( const std::bad_alloc& )
+ {
+ OSL_FAIL( "sd PropItem::Read bad alloc" );
+ }
+ }
+ if ( bAlign && ( nItemSize & 1 ) )
+ SeekRel( 2 ); // dword align
+ }
+ break;
+ }
+ if ( !bRetValue )
+ Seek( nItemPos );
+ return bRetValue;
+}
+
+PropItem& PropItem::operator=( PropItem& rPropItem )
+{
+ if ( this != &rPropItem )
+ {
+ Seek( STREAM_SEEK_TO_BEGIN );
+ delete[] static_cast<sal_uInt8*>(SwitchBuffer());
+
+ mnTextEnc = rPropItem.mnTextEnc;
+ SvMemoryStream::WriteBytes(rPropItem.GetData(), rPropItem.TellEnd());
+ }
+ return *this;
+}
+
+Section::Section( const Section& rSection )
+ : mnTextEnc(rSection.mnTextEnc)
+{
+ for ( int i = 0; i < 16; i++ )
+ aFMTID[ i ] = rSection.aFMTID[ i ];
+ for(const std::unique_ptr<PropEntry>& rEntry : rSection.maEntries)
+ maEntries.push_back(std::make_unique<PropEntry>(*rEntry));
+}
+
+Section::Section( const sal_uInt8* pFMTID ) : mnTextEnc(RTL_TEXTENCODING_MS_1252)
+{
+ for ( int i = 0; i < 16; i++ )
+ aFMTID[ i ] = pFMTID[ i ];
+}
+
+bool Section::GetProperty( sal_uInt32 nId, PropItem& rPropItem )
+{
+ if ( nId )
+ {
+ auto iter = std::find_if(maEntries.begin(), maEntries.end(),
+ [nId](const std::unique_ptr<PropEntry>& rxEntry) { return rxEntry->mnId == nId; });
+
+ if (iter != maEntries.end())
+ {
+ rPropItem.Clear();
+ rPropItem.SetTextEncoding( mnTextEnc );
+ rPropItem.WriteBytes( (*iter)->mpBuf.get(), (*iter)->mnSize );
+ rPropItem.Seek( STREAM_SEEK_TO_BEGIN );
+ return true;
+ }
+ }
+ return false;
+}
+
+void Section::AddProperty( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize )
+{
+ // just a simple id check
+
+ if ( !nId )
+ return;
+ if ( nId == 0xffffffff )
+ nId = 0;
+
+ // do not allow same PropId's, sort
+ auto iter = std::find_if(maEntries.begin(), maEntries.end(),
+ [nId](const std::unique_ptr<PropEntry>& rxEntry) { return rxEntry->mnId >= nId; });
+ if (iter != maEntries.end())
+ {
+ if ( (*iter)->mnId == nId )
+ (*iter).reset(new PropEntry( nId, pBuf, nBufSize ));
+ else
+ maEntries.insert( iter, std::make_unique<PropEntry>( nId, pBuf, nBufSize ));
+ }
+ else
+ {
+ maEntries.push_back( std::make_unique<PropEntry>( nId, pBuf, nBufSize ) );
+ }
+}
+
+void Section::GetDictionary(PropDictionary& rDict)
+{
+ auto iter = std::find_if(maEntries.begin(), maEntries.end(),
+ [](const std::unique_ptr<PropEntry>& rxEntry) { return rxEntry->mnId == 0; });
+
+ if (iter == maEntries.end())
+ return;
+
+ SvMemoryStream aStream( (*iter)->mpBuf.get(), (*iter)->mnSize, StreamMode::READ );
+ aStream.Seek( STREAM_SEEK_TO_BEGIN );
+ sal_uInt32 nDictCount(0);
+ aStream.ReadUInt32( nDictCount );
+ for (sal_uInt32 i = 0; i < nDictCount; ++i)
+ {
+ sal_uInt32 nId(0), nSize(0);
+ aStream.ReadUInt32(nId).ReadUInt32(nSize);
+ if (!aStream.good() || nSize > aStream.remainingSize())
+ break;
+ if (mnTextEnc == RTL_TEXTENCODING_UCS2)
+ nSize >>= 1;
+ if (!nSize)
+ continue;
+ OUString aString;
+ try
+ {
+ if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
+ {
+ std::unique_ptr<sal_Unicode[]> pWString( new sal_Unicode[nSize] );
+ for (sal_uInt32 j = 0; j < nSize; ++j)
+ aStream.ReadUtf16(pWString[j]);
+ aString = OUString(pWString.get(), lcl_getMaxSafeStrLen(nSize));
+ }
+ else
+ {
+ std::unique_ptr<char[]> pString( new char[nSize] );
+ aStream.ReadBytes(pString.get(), nSize);
+ aString = OUString(pString.get(), lcl_getMaxSafeStrLen(nSize), mnTextEnc);
+ }
+ }
+ catch( const std::bad_alloc& )
+ {
+ OSL_FAIL( "sd Section::GetDictionary bad alloc" );
+ }
+ if (aString.isEmpty())
+ break;
+ rDict.insert( std::make_pair(aString,nId) );
+ }
+}
+
+void Section::Read( SotStorageStream *pStrm )
+{
+ sal_uInt32 nSecOfs = pStrm->Tell();
+ sal_uInt32 nStrmSize = pStrm->remainingSize();
+
+ mnTextEnc = RTL_TEXTENCODING_MS_1252;
+ sal_uInt32 nSecSize(0), nPropCount(0);
+ pStrm->ReadUInt32(nSecSize).ReadUInt32(nPropCount);
+ if (nSecSize > nStrmSize)
+ {
+ SAL_WARN("sd.filter", "Section Len " << nSecSize << " claimed, only " << nStrmSize << " possible");
+ nSecSize = nStrmSize;
+ }
+
+ while (nPropCount--)
+ {
+ sal_uInt32 nPropId(0), nPropOfs(0);
+ pStrm->ReadUInt32(nPropId).ReadUInt32(nPropOfs);
+ if (!pStrm->good())
+ break;
+ auto nCurrent = pStrm->Tell();
+ sal_uInt64 nOffset = nPropOfs + nSecOfs;
+ if (!checkSeek(*pStrm, nOffset))
+ break;
+ if ( nPropId ) // do not read dictionary
+ {
+ sal_uInt32 nPropType(0), nVectorCount(0);
+ pStrm->ReadUInt32(nPropType);
+
+ sal_uInt32 nPropSize = 4;
+ if ( nPropType & VT_VECTOR )
+ {
+ pStrm->ReadUInt32( nVectorCount );
+ nPropType &=~VT_VECTOR;
+ nPropSize += 4;
+ }
+ else
+ nVectorCount = 1;
+
+ bool bVariant = ( nPropType == VT_VARIANT );
+
+ o3tl::sorted_vector<sal_uInt64> aVisitedOffsets;
+
+ for (sal_uInt32 i = 0; nPropSize && i < nVectorCount && pStrm->good(); ++i)
+ {
+ if ( bVariant )
+ {
+ pStrm->ReadUInt32( nPropType );
+ nPropSize += 4;
+ }
+ sal_uInt32 nTemp(0);
+ switch( nPropType )
+ {
+ case VT_UI1 :
+ nPropSize++;
+ break;
+
+ case VT_I2 :
+ case VT_UI2 :
+ case VT_BOOL :
+ nPropSize += 2;
+ break;
+
+ case VT_I4 :
+ case VT_R4 :
+ case VT_UI4 :
+ case VT_ERROR :
+ nPropSize += 4;
+ break;
+
+ case VT_I8 :
+ case VT_R8 :
+ case VT_CY :
+ case VT_UI8 :
+ case VT_DATE :
+ case VT_FILETIME :
+ nPropSize += 8;
+ break;
+
+ case VT_BSTR :
+ pStrm->ReadUInt32( nTemp );
+ nPropSize += ( nTemp + 4 );
+ break;
+
+ case VT_LPSTR :
+ pStrm->ReadUInt32( nTemp );
+ nPropSize += ( nTemp + 4 );
+ break;
+
+ case VT_LPWSTR :
+ {
+ pStrm->ReadUInt32( nTemp );
+ // looks like these are aligned to 4 bytes
+ sal_uInt32 nLength = nPropOfs + nSecOfs + nPropSize + ( nTemp << 1 ) + 4;
+ nPropSize += ( nTemp << 1 ) + 4 + (nLength % 4);
+ }
+ break;
+
+ case VT_BLOB_OBJECT :
+ case VT_BLOB :
+ case VT_CF :
+ pStrm->ReadUInt32( nTemp );
+ nPropSize += ( nTemp + 4 );
+ break;
+
+ case VT_CLSID :
+ case VT_STREAM :
+ case VT_STORAGE :
+ case VT_STREAMED_OBJECT :
+ case VT_STORED_OBJECT :
+ case VT_VARIANT :
+ case VT_VECTOR :
+ default :
+ nPropSize = 0;
+ }
+ if ( nPropSize )
+ {
+ if ( ( nVectorCount - i ) > 1 )
+ {
+ nOffset = nPropOfs + nSecOfs + nPropSize;
+ if (!checkSeek(*pStrm, nOffset))
+ break;
+ // inserts returns false if an equivalent element already existed
+ if (!aVisitedOffsets.insert(nOffset).second)
+ {
+ SAL_WARN("sd.filter", "loop in Section::Read property list");
+ break;
+ }
+ }
+ }
+ else
+ break;
+ }
+ if ( nPropSize )
+ {
+ if ( nPropSize > nStrmSize )
+ {
+ break;
+ }
+ pStrm->Seek( nPropOfs + nSecOfs );
+ // make sure we don't overflow the section size
+ if( nPropSize > nSecSize - nSecOfs )
+ nPropSize = nSecSize - nSecOfs;
+ std::unique_ptr<sal_uInt8[]> pBuf( new sal_uInt8[ nPropSize ] );
+ nPropSize = pStrm->ReadBytes(pBuf.get(), nPropSize);
+ AddProperty( nPropId, pBuf.get(), nPropSize );
+ }
+ if ( nPropId == 1 )
+ {
+ PropItem aPropItem;
+ if ( GetProperty( 1, aPropItem ) )
+ {
+ aPropItem.ReadUInt32( nPropType );
+ if ( nPropType == VT_I2 )
+ {
+ sal_uInt16 nCodePage(0);
+ aPropItem.ReadUInt16(nCodePage);
+
+ if ( nCodePage == 1200 )
+ {
+ mnTextEnc = RTL_TEXTENCODING_UCS2;
+ }
+ else
+ {
+ mnTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
+ if ( mnTextEnc == RTL_TEXTENCODING_DONTKNOW )
+ mnTextEnc = RTL_TEXTENCODING_MS_1252;
+ }
+ }
+ else
+ {
+ mnTextEnc = RTL_TEXTENCODING_MS_1252;
+ }
+ }
+ }
+ }
+ else
+ {
+ sal_uInt32 nDictCount(0);
+ pStrm->ReadUInt32(nDictCount);
+ auto nMaxRecordsPossible = pStrm->remainingSize() / (sizeof(sal_uInt32)*2);
+ if (nDictCount > nMaxRecordsPossible)
+ {
+ SAL_WARN("sd.filter", "Dictionary count of " << nDictCount << " claimed, only " << nMaxRecordsPossible << " possible");
+ nDictCount = nMaxRecordsPossible;
+ }
+ for (sal_uInt32 i = 0; i < nDictCount; ++i)
+ {
+ sal_uInt32 nSize(0);
+ pStrm->ReadUInt32( nSize ).ReadUInt32( nSize );
+ if (!pStrm->good())
+ break;
+ sal_uInt64 nPos = pStrm->Tell() + nSize;
+ if (!checkSeek(*pStrm, nPos))
+ break;
+ }
+ sal_uInt32 nSize = pStrm->Tell();
+ pStrm->Seek( nPropOfs + nSecOfs );
+ nSize -= pStrm->Tell();
+ if ( nSize > nStrmSize )
+ {
+ break;
+ }
+ std::unique_ptr<sal_uInt8[]> pBuf( new sal_uInt8[ nSize ] );
+ nSize = pStrm->ReadBytes(pBuf.get(), nSize);
+ AddProperty( 0xffffffff, pBuf.get(), nSize );
+ }
+ pStrm->Seek(nCurrent);
+ }
+ pStrm->Seek(nSecOfs + nSecSize);
+}
+
+Section& Section::operator=( const Section& rSection )
+{
+ if ( this != &rSection )
+ {
+ memcpy( static_cast<void*>(aFMTID), static_cast<void const *>(rSection.aFMTID), 16 );
+
+ for(const std::unique_ptr<PropEntry>& rEntry : rSection.maEntries)
+ maEntries.push_back(std::make_unique<PropEntry>(*rEntry));
+ }
+ return *this;
+}
+
+PropRead::PropRead( SotStorage& rStorage, const OUString& rName ) :
+ mbStatus ( false ),
+ mnByteOrder ( 0xfffe )
+{
+ if ( rStorage.IsStream( rName ) )
+ {
+ mpSvStream = rStorage.OpenSotStream( rName, StreamMode::STD_READ );
+ if ( mpSvStream.is() )
+ {
+ mpSvStream->SetEndian( SvStreamEndian::LITTLE );
+ memset( mApplicationCLSID, 0, 16 );
+ mbStatus = true;
+ }
+ }
+}
+
+const Section* PropRead::GetSection( const sal_uInt8* pFMTID )
+{
+ auto it = std::find_if(maSections.begin(), maSections.end(),
+ [&pFMTID](const std::unique_ptr<Section>& rxSection) { return memcmp( rxSection->GetFMTID(), pFMTID, 16 ) == 0; });
+ if (it != maSections.end())
+ return it->get();
+ return nullptr;
+}
+
+void PropRead::Read()
+{
+ maSections.clear();
+
+ if ( !mbStatus )
+ return;
+
+ sal_uInt16 mnVersionLo;
+ sal_uInt16 mnVersionHi;
+ sal_uInt16 mnFormat;
+ mpSvStream->ReadUInt16( mnByteOrder ).ReadUInt16( mnFormat ).ReadUInt16( mnVersionLo ).ReadUInt16( mnVersionHi );
+ if ( mnByteOrder != 0xfffe )
+ return;
+
+ std::vector<sal_uInt8> aSectCLSID(16);
+ mpSvStream->ReadBytes(mApplicationCLSID, 16);
+ sal_uInt32 nSections(0);
+ mpSvStream->ReadUInt32(nSections);
+ if ( nSections > 2 ) // sj: PowerPoint documents are containing max 2 sections
+ {
+ mbStatus = false;
+ }
+ else
+ for ( sal_uInt32 i = 0; i < nSections; i++ )
+ {
+ mpSvStream->ReadBytes(aSectCLSID.data(), aSectCLSID.size());
+ sal_uInt32 nSectionOfs(0);
+ mpSvStream->ReadUInt32( nSectionOfs );
+ sal_uInt32 nCurrent = mpSvStream->Tell();
+ if (checkSeek(*mpSvStream, nSectionOfs))
+ {
+ Section aSection(aSectCLSID.data());
+ aSection.Read(mpSvStream.get());
+ maSections.push_back(std::make_unique<Section>(aSection));
+ }
+ mpSvStream->Seek( nCurrent );
+ }
+}
+
+PropRead& PropRead::operator=( const PropRead& rPropRead )
+{
+ if ( this != &rPropRead )
+ {
+ mbStatus = rPropRead.mbStatus;
+ mpSvStream = rPropRead.mpSvStream;
+
+ mnByteOrder = rPropRead.mnByteOrder;
+ memcpy( mApplicationCLSID, rPropRead.mApplicationCLSID, 16 );
+
+ for(const std::unique_ptr<Section>& rSection : rPropRead.maSections)
+ maSections.push_back(std::make_unique<Section>(*rSection));
+ }
+ return *this;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/ppt/propread.hxx b/sd/source/filter/ppt/propread.hxx
new file mode 100644
index 000000000..402a04624
--- /dev/null
+++ b/sd/source/filter/ppt/propread.hxx
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <map>
+#include <vector>
+#include <memory>
+
+#include <sal/types.h>
+#include <sot/storage.hxx>
+#include <tools/stream.hxx>
+
+// SummaryInformation
+#define PID_TITLE 0x02
+#define PID_SUBJECT 0x03
+#define PID_AUTHOR 0x04
+#define PID_KEYWORDS 0x05
+#define PID_COMMENTS 0x06
+#define PID_TEMPLATE 0x07
+#define PID_LASTAUTHOR 0x08
+#define PID_REVNUMBER 0x09
+#define PID_CREATE_DTM 0x0c
+
+// DocumentSummaryInformation
+#define PID_SLIDECOUNT 0x07
+#define PID_HEADINGPAIR 0x0c
+#define PID_DOCPARTS 0x0d
+
+#define VT_EMPTY 0
+#define VT_NULL 1
+#define VT_I2 2
+#define VT_I4 3
+#define VT_R4 4
+#define VT_R8 5
+#define VT_CY 6
+#define VT_DATE 7
+#define VT_BSTR 8
+#define VT_UI4 9
+#define VT_ERROR 10
+#define VT_BOOL 11
+#define VT_VARIANT 12
+#define VT_DECIMAL 14
+#define VT_I1 16
+#define VT_UI1 17
+#define VT_UI2 18
+#define VT_I8 20
+#define VT_UI8 21
+#define VT_INT 22
+#define VT_UINT 23
+#define VT_LPSTR 30
+#define VT_LPWSTR 31
+#define VT_FILETIME 64
+#define VT_BLOB 65
+#define VT_STREAM 66
+#define VT_STORAGE 67
+#define VT_STREAMED_OBJECT 68
+#define VT_STORED_OBJECT 69
+#define VT_BLOB_OBJECT 70
+#define VT_CF 71
+#define VT_CLSID 72
+#define VT_VECTOR 0x1000
+#define VT_ARRAY 0x2000
+#define VT_BYREF 0x4000
+#define VT_TYPEMASK 0xFFF
+
+typedef std::map<OUString,sal_uInt32> PropDictionary;
+
+struct PropEntry
+{
+ sal_uInt32 mnId;
+ sal_uInt32 mnSize;
+ std::unique_ptr<sal_uInt8[]> mpBuf;
+
+ PropEntry( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize );
+ PropEntry( const PropEntry& rProp );
+
+ PropEntry& operator=(const PropEntry& rPropEntry);
+};
+
+class PropItem : public SvMemoryStream
+{
+ sal_uInt16 mnTextEnc;
+
+public:
+ PropItem()
+ : mnTextEnc(RTL_TEXTENCODING_DONTKNOW)
+ {
+ }
+ void Clear();
+
+ void SetTextEncoding( sal_uInt16 nTextEnc ){ mnTextEnc = nTextEnc; };
+ bool Read( OUString& rString, sal_uInt32 nType = VT_EMPTY, bool bDwordAlign = true );
+ PropItem& operator=( PropItem& rPropItem );
+};
+
+class Section final
+{
+ sal_uInt16 mnTextEnc;
+ std::vector<std::unique_ptr<PropEntry> > maEntries;
+
+ sal_uInt8 aFMTID[ 16 ];
+
+ void AddProperty( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize );
+
+ public:
+ explicit Section( const sal_uInt8* pFMTID );
+ Section( const Section& rSection );
+
+ Section& operator=( const Section& rSection );
+ bool GetProperty( sal_uInt32 nId, PropItem& rPropItem );
+ void GetDictionary( PropDictionary& rDict );
+ const sal_uInt8* GetFMTID() const { return aFMTID; };
+ void Read( SotStorageStream* pStrm );
+};
+
+class PropRead
+{
+ bool mbStatus;
+ tools::SvRef<SotStorageStream> mpSvStream;
+
+ sal_uInt16 mnByteOrder;
+ sal_uInt8 mApplicationCLSID[ 16 ];
+ std::vector<std::unique_ptr<Section> > maSections;
+
+ public:
+ PropRead( SotStorage& rSvStorage, const OUString& rName );
+
+ PropRead& operator=( const PropRead& rPropRead );
+ const Section* GetSection( const sal_uInt8* pFMTID );
+ bool IsValid() const { return mbStatus; };
+ void Read();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/sdfilter.cxx b/sd/source/filter/sdfilter.cxx
new file mode 100644
index 000000000..11ad11d76
--- /dev/null
+++ b/sd/source/filter/sdfilter.cxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <map>
+
+#include <osl/module.hxx>
+#include <tools/svlibrary.h>
+#include <sfx2/docfile.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svl/itemset.hxx>
+
+#include <DrawDocShell.hxx>
+
+#include <pres.hxx>
+#include <sdfilter.hxx>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::task;
+
+
+SdFilter::SdFilter( SfxMedium& rMedium, ::sd::DrawDocShell& rDocShell )
+: mxModel( rDocShell.GetModel() )
+, mrMedium( rMedium )
+, mrDocShell( rDocShell )
+, mrDocument( *rDocShell.GetDoc() )
+, mbIsDraw( rDocShell.GetDocumentType() == DocumentType::Draw )
+{
+}
+
+SdFilter::~SdFilter()
+{
+}
+
+OUString SdFilter::ImplGetFullLibraryName( std::u16string_view rLibraryName )
+{
+ return OUString(SVLIBRARY("?")).replaceFirst( "?", rLibraryName );
+}
+
+#ifndef DISABLE_DYNLOADING
+
+static std::map<OUString, std::unique_ptr<osl::Module>> g_SdModuleMap;
+
+extern "C" { static void thisModule() {} }
+
+oslGenericFunction SdFilter::GetLibrarySymbol( const OUString& rLibraryName, const OUString &rFnSymbol )
+{
+ osl::Module *pMod = nullptr;
+ auto it = g_SdModuleMap.find(rLibraryName);
+ if (it != g_SdModuleMap.end())
+ pMod = it->second.get();
+
+ if (!pMod)
+ {
+ pMod = new osl::Module;
+ if (pMod->loadRelative(&thisModule, ImplGetFullLibraryName(rLibraryName),
+ SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_LAZY))
+ g_SdModuleMap[rLibraryName] = std::unique_ptr<osl::Module>(pMod);
+ else
+ {
+ delete pMod;
+ pMod = nullptr;
+ }
+ }
+ if (!pMod)
+ return nullptr;
+ else
+ return pMod->getFunctionSymbol(rFnSymbol);
+}
+
+void SdFilter::Preload()
+{
+ (void)GetLibrarySymbol("sdfilt", "ImportPPT");
+ (void)GetLibrarySymbol("icg", "ImportCGM");
+}
+
+#endif
+
+void SdFilter::CreateStatusIndicator()
+{
+ // The status indicator must be retrieved from the provided medium arguments
+ const SfxUnoAnyItem* pStatusBarItem =
+ mrMedium.GetItemSet()->GetItem(SID_PROGRESS_STATUSBAR_CONTROL);
+
+ if ( pStatusBarItem )
+ pStatusBarItem->GetValue() >>= mxStatusIndicator;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/sdpptwrp.cxx b/sd/source/filter/sdpptwrp.cxx
new file mode 100644
index 000000000..59829f854
--- /dev/null
+++ b/sd/source/filter/sdpptwrp.cxx
@@ -0,0 +1,377 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <filter/msfilter/msoleexp.hxx>
+#include <svx/svxerr.hxx>
+#include <unotools/fltrcfg.hxx>
+#include <unotools/streamwrap.hxx>
+#include <sot/storage.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/packages/XPackageEncryption.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <sdpptwrp.hxx>
+#include <DrawDocShell.hxx>
+#include <sfx2/frame.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::frame;
+
+typedef sal_Bool ( *ExportPPTPointer )( const std::vector< css::beans::PropertyValue >&, tools::SvRef<SotStorage> const&,
+ Reference< XModel > const &,
+ Reference< XStatusIndicator > const &,
+ SvMemoryStream*, sal_uInt32 nCnvrtFlags );
+
+typedef sal_Bool ( *ImportPPTPointer )( SdDrawDocument*, SvStream&, SotStorage&, SfxMedium& );
+
+typedef sal_Bool ( *SaveVBAPointer )( SfxObjectShell&, SvMemoryStream*& );
+
+#ifdef DISABLE_DYNLOADING
+
+extern "C" sal_Bool ExportPPT( const std::vector< css::beans::PropertyValue >&, tools::SvRef<SotStorage> const&,
+ Reference< XModel > const &,
+ Reference< XStatusIndicator > const &,
+ SvMemoryStream*, sal_uInt32 nCnvrtFlags );
+
+extern "C" sal_Bool ImportPPT( SdDrawDocument*, SvStream&, SotStorage&, SfxMedium& );
+
+extern "C" sal_Bool SaveVBA( SfxObjectShell&, SvMemoryStream*& );
+
+#endif
+
+
+SdPPTFilter::SdPPTFilter( SfxMedium& rMedium, ::sd::DrawDocShell& rDocShell ) :
+ SdFilter( rMedium, rDocShell ),
+ pBas ( nullptr )
+{
+}
+
+SdPPTFilter::~SdPPTFilter()
+{
+ delete pBas; // deleting the compressed basic storage
+}
+
+static void lcl_getListOfStreams(SotStorage * pStorage, comphelper::SequenceAsHashMap& aStreamsData, const OUString& sPrefix)
+{
+ SvStorageInfoList aElements;
+ pStorage->FillInfoList(&aElements);
+ for (const auto & aElement : aElements)
+ {
+ OUString sStreamFullName = sPrefix.getLength() ? sPrefix + "/" + aElement.GetName() : aElement.GetName();
+ if (aElement.IsStorage())
+ {
+ tools::SvRef<SotStorage> xSubStorage = pStorage->OpenSotStorage(aElement.GetName(), StreamMode::STD_READ | StreamMode::SHARE_DENYALL);
+ lcl_getListOfStreams(xSubStorage.get(), aStreamsData, sStreamFullName);
+ }
+ else
+ {
+ // Read stream
+ tools::SvRef<SotStorageStream> rStream = pStorage->OpenSotStream(aElement.GetName(), StreamMode::READ | StreamMode::SHARE_DENYALL);
+ if (rStream.is())
+ {
+ sal_Int32 nStreamSize = rStream->GetSize();
+ Sequence< sal_Int8 > oData;
+ oData.realloc(nStreamSize);
+ sal_Int32 nReadBytes = rStream->ReadBytes(oData.getArray(), nStreamSize);
+ if (nStreamSize == nReadBytes)
+ aStreamsData[sStreamFullName] <<= oData;
+ }
+ }
+ }
+}
+
+static tools::SvRef<SotStorage> lcl_DRMDecrypt(const SfxMedium& rMedium, const tools::SvRef<SotStorage>& rStorage, std::shared_ptr<SvStream>& rNewStorageStrm)
+{
+ tools::SvRef<SotStorage> aNewStorage;
+
+ // We have DRM encrypted storage. We should try to decrypt it first, if we can
+ Sequence< Any > aArguments;
+ Reference<XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
+ Reference< css::packages::XPackageEncryption > xPackageEncryption(
+ xComponentContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.comp.oox.crypto.DRMDataSpace", aArguments, xComponentContext), UNO_QUERY);
+
+ if (!xPackageEncryption.is())
+ {
+ // We do not know how to decrypt this
+ return aNewStorage;
+ }
+
+ comphelper::SequenceAsHashMap aStreamsData;
+ lcl_getListOfStreams(rStorage.get(), aStreamsData, "");
+
+ try {
+ Sequence<NamedValue> aStreams = aStreamsData.getAsConstNamedValueList();
+ if (!xPackageEncryption->readEncryptionInfo(aStreams))
+ {
+ // We failed with decryption
+ return aNewStorage;
+ }
+
+ tools::SvRef<SotStorageStream> rContentStream = rStorage->OpenSotStream("\011DRMContent", StreamMode::READ | StreamMode::SHARE_DENYALL);
+ if (!rContentStream.is())
+ {
+ return aNewStorage;
+ }
+
+ rNewStorageStrm = std::make_shared<SvMemoryStream>();
+
+ Reference<css::io::XInputStream > xInputStream(new utl::OSeekableInputStreamWrapper(rContentStream.get(), false));
+ Reference<css::io::XOutputStream > xDecryptedStream(new utl::OSeekableOutputStreamWrapper(*rNewStorageStrm));
+
+ if (!xPackageEncryption->decrypt(xInputStream, xDecryptedStream))
+ {
+ // We failed with decryption
+ return aNewStorage;
+ }
+
+ rNewStorageStrm->Seek(0);
+
+ // Further reading is done from new document
+ aNewStorage = new SotStorage(*rNewStorageStrm);
+
+ // Set the media descriptor data
+ Sequence<NamedValue> aEncryptionData = xPackageEncryption->createEncryptionData("");
+ rMedium.GetItemSet()->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, Any(aEncryptionData)));
+ }
+ catch (const std::exception&)
+ {
+ return aNewStorage;
+ }
+
+ return aNewStorage;
+}
+
+bool SdPPTFilter::Import()
+{
+ bool bRet = false;
+ std::shared_ptr<SvStream> aDecryptedStorageStrm;
+ tools::SvRef<SotStorage> pStorage = new SotStorage( mrMedium.GetInStream(), false );
+ if( !pStorage->GetError() )
+ {
+ /* check if there is a dualstorage, then the
+ document is probably a PPT95 containing PPT97 */
+ tools::SvRef<SotStorage> xDualStorage;
+ OUString sDualStorage( "PP97_DUALSTORAGE" );
+ if ( pStorage->IsContained( sDualStorage ) )
+ {
+ xDualStorage = pStorage->OpenSotStorage( sDualStorage, StreamMode::STD_READ );
+ pStorage = xDualStorage;
+ }
+ if (pStorage->IsContained("\011DRMContent"))
+ {
+ // Document is DRM encrypted
+ pStorage = lcl_DRMDecrypt(mrMedium, pStorage, aDecryptedStorageStrm);
+ }
+ tools::SvRef<SotStorageStream> pDocStream(pStorage->OpenSotStream( "PowerPoint Document" , StreamMode::STD_READ ));
+ if( pDocStream )
+ {
+ pDocStream->SetVersion( pStorage->GetVersion() );
+ pDocStream->SetCryptMaskKey(pStorage->GetKey());
+
+ if ( pStorage->IsStream( "EncryptedSummary" ) )
+ mrMedium.SetError(ERRCODE_SVX_READ_FILTER_PPOINT);
+ else
+ {
+#ifdef DISABLE_DYNLOADING
+ ImportPPTPointer pPPTImport = ImportPPT;
+#else
+ ImportPPTPointer pPPTImport = reinterpret_cast< ImportPPTPointer >(
+ SdFilter::GetLibrarySymbol(mrMedium.GetFilter()->GetUserData(), "ImportPPT"));
+#endif
+
+ if ( pPPTImport )
+ bRet = pPPTImport( &mrDocument, *pDocStream, *pStorage, mrMedium );
+
+ if ( !bRet )
+ mrMedium.SetError(SVSTREAM_WRONGVERSION);
+ }
+ }
+ }
+
+ return bRet;
+}
+
+bool SdPPTFilter::Export()
+{
+ bool bRet = false;
+
+ if( mxModel.is() )
+ {
+#ifdef DISABLE_DYNLOADING
+ ExportPPTPointer PPTExport = ExportPPT;
+#else
+ ExportPPTPointer PPTExport = reinterpret_cast< ExportPPTPointer >(
+ SdFilter::GetLibrarySymbol(mrMedium.GetFilter()->GetUserData(), "ExportPPT"));
+#endif
+
+ if( PPTExport)
+ {
+ sal_uInt32 nCnvrtFlags = 0;
+ const SvtFilterOptions& rFilterOptions = SvtFilterOptions::Get();
+ if ( rFilterOptions.IsMath2MathType() )
+ nCnvrtFlags |= OLE_STARMATH_2_MATHTYPE;
+ if ( rFilterOptions.IsWriter2WinWord() )
+ nCnvrtFlags |= OLE_STARWRITER_2_WINWORD;
+ if ( rFilterOptions.IsCalc2Excel() )
+ nCnvrtFlags |= OLE_STARCALC_2_EXCEL;
+ if ( rFilterOptions.IsImpress2PowerPoint() )
+ nCnvrtFlags |= OLE_STARIMPRESS_2_POWERPOINT;
+ if ( rFilterOptions.IsEnablePPTPreview() )
+ nCnvrtFlags |= 0x8000;
+
+ CreateStatusIndicator();
+
+ //OUString sBaseURI( "BaseURI");
+ std::vector< PropertyValue > aProperties;
+ PropertyValue aProperty;
+ aProperty.Name = "BaseURI";
+ aProperty.Value <<= mrMedium.GetBaseURL( true );
+ aProperties.push_back( aProperty );
+
+ SvStream * pOutputStrm = mrMedium.GetOutStream();
+
+ Sequence< NamedValue > aEncryptionData;
+ Reference< css::packages::XPackageEncryption > xPackageEncryption;
+ const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(mrMedium.GetItemSet(), SID_ENCRYPTIONDATA, false);
+ std::shared_ptr<SvStream> pMediaStrm;
+ if (pEncryptionDataItem && (pEncryptionDataItem->GetValue() >>= aEncryptionData))
+ {
+ ::comphelper::SequenceAsHashMap aHashData(aEncryptionData);
+ OUString sCryptoType = aHashData.getUnpackedValueOrDefault("CryptoType", OUString());
+
+ if (sCryptoType.getLength())
+ {
+ Reference<XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
+ Sequence<Any> aArguments{
+ Any(NamedValue("Binary", Any(true))) };
+ xPackageEncryption.set(
+ xComponentContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.comp.oox.crypto." + sCryptoType, aArguments, xComponentContext), UNO_QUERY);
+
+ if (xPackageEncryption.is())
+ {
+ // We have an encryptor. Export document into memory stream and encrypt it later
+ pMediaStrm = std::make_shared<SvMemoryStream>();
+ pOutputStrm = pMediaStrm.get();
+
+ // Temp removal of EncryptionData to avoid password protection triggering
+ mrMedium.GetItemSet()->ClearItem(SID_ENCRYPTIONDATA);
+ }
+ }
+ }
+
+ tools::SvRef<SotStorage> xStorRef = new SotStorage(pOutputStrm, false);
+
+ if (xStorRef.is())
+ {
+ bRet = PPTExport(aProperties, xStorRef, mxModel, mxStatusIndicator, pBas, nCnvrtFlags);
+ xStorRef->Commit();
+
+ if (xPackageEncryption.is())
+ {
+ // Perform DRM encryption
+ pOutputStrm->Seek(0);
+
+ xPackageEncryption->setupEncryption(aEncryptionData);
+
+ Reference<css::io::XInputStream > xInputStream(new utl::OSeekableInputStreamWrapper(pOutputStrm, false));
+ Sequence<NamedValue> aStreams = xPackageEncryption->encrypt(xInputStream);
+
+ tools::SvRef<SotStorage> xEncryptedRootStrg = new SotStorage(mrMedium.GetOutStream(), false);
+ for (const NamedValue & aStreamData : std::as_const(aStreams))
+ {
+ // To avoid long paths split and open substorages recursively
+ // Splitting paths manually, since comphelper::string::split is trimming special characters like \0x01, \0x09
+ tools::SvRef<SotStorage> pStorage = xEncryptedRootStrg.get();
+ OUString sFileName;
+ sal_Int32 idx = 0;
+ do
+ {
+ OUString sPathElem = aStreamData.Name.getToken(0, L'/', idx);
+ if (!sPathElem.isEmpty())
+ {
+ if (idx < 0)
+ {
+ sFileName = sPathElem;
+ }
+ else
+ {
+ pStorage = pStorage->OpenSotStorage(sPathElem);
+ }
+ }
+ } while (pStorage && idx >= 0);
+
+ if (!pStorage)
+ {
+ bRet = false;
+ break;
+ }
+
+ tools::SvRef<SotStorageStream> pStream = pStorage->OpenSotStream(sFileName);
+ if (!pStream)
+ {
+ bRet = false;
+ break;
+ }
+ Sequence<sal_Int8> aStreamContent;
+ aStreamData.Value >>= aStreamContent;
+ size_t nBytesWritten = pStream->WriteBytes(aStreamContent.getConstArray(), aStreamContent.getLength());
+ if (nBytesWritten != static_cast<size_t>(aStreamContent.getLength()))
+ {
+ bRet = false;
+ break;
+ }
+ }
+ xEncryptedRootStrg->Commit();
+
+ // Restore encryption data
+ mrMedium.GetItemSet()->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, Any(aEncryptionData)));
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void SdPPTFilter::PreSaveBasic()
+{
+ const SvtFilterOptions& rFilterOptions = SvtFilterOptions::Get();
+ if( rFilterOptions.IsLoadPPointBasicStorage() )
+ {
+#ifdef DISABLE_DYNLOADING
+ SaveVBAPointer pSaveVBA= SaveVBA;
+#else
+ SaveVBAPointer pSaveVBA = reinterpret_cast< SaveVBAPointer >(
+ SdFilter::GetLibrarySymbol(mrMedium.GetFilter()->GetUserData(), "SaveVBA"));
+#endif
+ if( pSaveVBA )
+ pSaveVBA( static_cast<SfxObjectShell&>(mrDocShell), pBas );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/xml/sdtransform.cxx b/sd/source/filter/xml/sdtransform.cxx
new file mode 100644
index 000000000..4e296eaf6
--- /dev/null
+++ b/sd/source/filter/xml/sdtransform.cxx
@@ -0,0 +1,368 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/style.hxx>
+#include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
+
+#include <svx/svdoutl.hxx>
+#include <editeng/xmlcnitm.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdogrp.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/outlobj.hxx>
+
+#include <drawdoc.hxx>
+#include "sdtransform.hxx"
+
+using namespace ::com::sun::star::style;
+
+namespace {
+
+class SdTransformOOo2xDocument
+{
+public:
+ explicit SdTransformOOo2xDocument( SdDrawDocument& rDocument );
+
+ void transform();
+
+ void transformMasterPages();
+ void transformDrawPages();
+
+ void transformStyles();
+ void transformStyles( SfxStyleFamily eFam );
+ void transformStyle( SfxStyleSheetBase& rSheet );
+
+ void transformShapes( SdrObjList const & rShapes );
+ void transformShape( SdrObject& rObj );
+
+ void transformTextShape( SdrTextObj& rTextShape );
+
+ bool getBulletState( const SfxItemSet& rSet, SfxStyleSheetBase* pSheet, bool& rState );
+ static bool getBulletState( const SfxItemSet& rSet, sal_uInt16 nWhich, bool& rState );
+
+ static bool transformItemSet( SfxItemSet& rSet, bool bNumbering );
+
+ static bool removeAlienAttributes( SfxItemSet& rSet );
+ static bool removeAlienAttributes( SfxItemSet& rSet, sal_uInt16 nWhich );
+
+ SdDrawDocument& mrDocument;
+ SdrOutliner& mrOutliner;
+};
+
+}
+
+/** transforms the given model from OOo 2.x to OOo 3.x. This maps
+ the deprecated EE_PARA_BULLETSTATE and clears the EE_PARA_LRSPACE
+ if used together with a EE_PARA_NUMBULLET */
+void TransformOOo2xDocument( SdDrawDocument* pDocument )
+{
+ if( pDocument )
+ {
+ SdTransformOOo2xDocument aTransformer( *pDocument );
+ aTransformer.transform();
+ }
+}
+
+constexpr OUStringLiteral gsEnableNumbering( u"enable-numbering" );
+constexpr OUStringLiteral gsTextNamespace( u"urn:oasis:names:tc:opendocument:xmlns:text:1.0" );
+constexpr OUStringLiteral gsTrue( u"true" );
+
+SdTransformOOo2xDocument::SdTransformOOo2xDocument( SdDrawDocument& rDocument )
+: mrDocument( rDocument )
+, mrOutliner( rDocument.GetDrawOutliner() )
+{
+}
+
+void SdTransformOOo2xDocument::transform()
+{
+ transformMasterPages();
+ transformDrawPages();
+ transformStyles();
+}
+
+void SdTransformOOo2xDocument::transformMasterPages()
+{
+ sal_uInt16 nMasterPageCount = mrDocument.GetMasterPageCount();
+ for( sal_uInt16 nMasterPage = 0; nMasterPage < nMasterPageCount; nMasterPage++ )
+ {
+ SdrObjList* pPage = mrDocument.GetMasterPage( nMasterPage );
+ if( pPage )
+ transformShapes( *pPage );
+ }
+}
+
+void SdTransformOOo2xDocument::transformDrawPages()
+{
+ sal_uInt16 nPageCount = mrDocument.GetPageCount();
+ for( sal_uInt16 nPage = 0; nPage < nPageCount; nPage++ )
+ {
+ SdrObjList* pPage = mrDocument.GetPage( nPage );
+ if( pPage )
+ transformShapes( *pPage );
+ }
+}
+
+void SdTransformOOo2xDocument::transformStyles()
+{
+ transformStyles( SfxStyleFamily::Para );
+ transformStyles( SfxStyleFamily::Page );
+}
+
+void SdTransformOOo2xDocument::transformStyles( SfxStyleFamily eFam )
+{
+
+ rtl::Reference< SfxStyleSheetBasePool > xStyleSheetPool( mrDocument.GetStyleSheetPool() );
+
+ SfxStyleSheetIterator aIter( xStyleSheetPool.get(), eFam );
+
+ SfxStyleSheetBase* pSheet = aIter.First();
+ while( pSheet )
+ {
+ transformStyle( *pSheet );
+ pSheet = aIter.Next();
+ }
+}
+
+void SdTransformOOo2xDocument::transformStyle( SfxStyleSheetBase& rSheet )
+{
+ SfxItemSet& rSet = rSheet.GetItemSet();
+
+ bool bState = false;
+ getBulletState( rSheet.GetItemSet(), rSheet.GetPool()->Find( rSheet.GetParent(), rSheet.GetFamily() ), bState );
+
+ transformItemSet( rSet, bState );
+ removeAlienAttributes( rSet );
+}
+
+void SdTransformOOo2xDocument::transformShapes( SdrObjList const & rShapes )
+{
+ const size_t nShapeCount = rShapes.GetObjCount();
+ for( size_t nShape = 0; nShape < nShapeCount; ++nShape )
+ {
+ SdrObject* pObj = rShapes.GetObj( nShape );
+ if( pObj )
+ transformShape( *pObj );
+ }
+}
+
+void SdTransformOOo2xDocument::transformShape( SdrObject& rObj )
+{
+ SdrTextObj* pTextShape = dynamic_cast< SdrTextObj* >( &rObj );
+ if( pTextShape )
+ {
+ transformTextShape( *pTextShape );
+ return;
+ }
+
+ SdrObjGroup* pGroupShape = dynamic_cast< SdrObjGroup* >( &rObj );
+ if( pGroupShape )
+ {
+ SdrObjList* pObjList = pGroupShape->GetSubList();
+ if( pObjList )
+ transformShapes( *pObjList );
+ return;
+ }
+}
+
+void SdTransformOOo2xDocument::transformTextShape( SdrTextObj& rTextShape )
+{
+
+ if(rTextShape.IsEmptyPresObj())
+ return;
+
+ OutlinerParaObject* pOPO = rTextShape.GetOutlinerParaObject();
+ if (!pOPO)
+ return;
+
+ mrOutliner.SetText( *pOPO );
+
+ sal_Int32 nCount = mrOutliner.GetParagraphCount();
+
+ bool bChange = false;
+
+ for(sal_Int32 nPara = 0; nPara < nCount; nPara++)
+ {
+ SfxItemSet aParaSet( mrOutliner.GetParaAttribs( nPara ) );
+
+ bool bItemChange = false;
+
+ bool bState = false;
+ const sal_Int16 nDepth = mrOutliner.GetDepth( nPara );
+ if( (nDepth != -1) && (!getBulletState( aParaSet, mrOutliner.GetStyleSheet( nPara ), bState ) || !bState) )
+ {
+ // disable bullet if text::enable-bullet="false" is found
+ if( (nDepth > 0 ) && (rTextShape.GetObjInventor() == SdrInventor::Default) && (rTextShape.GetObjIdentifier() == SdrObjKind::OutlineText) )
+ {
+ // for outline object and level > 0 burn in the style sheet because it will be changed to "outline 1"
+ SfxStyleSheet* pStyleSheet = mrOutliner.GetStyleSheet( nPara );
+
+ if( pStyleSheet )
+ {
+ // optimize me: only put items hard into paragraph that are not equal to "outline 1" style!
+ SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
+
+ SfxWhichIter aIter(aParaSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ // now set all none hard attributes from the style
+ while(nWhich)
+ {
+ if(SfxItemState::SET != aIter.GetItemState())
+ {
+ aParaSet.Put(rStyleSet.Get(nWhich));
+ bItemChange = true;
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+ }
+
+ mrOutliner.SetDepth( mrOutliner.GetParagraph( nPara ), -1 );
+
+ bChange = true;
+ }
+
+ bItemChange |= transformItemSet( aParaSet, bState );
+
+ bItemChange |= removeAlienAttributes( aParaSet );
+
+ if( bItemChange )
+ {
+ mrOutliner.SetParaAttribs( nPara, aParaSet );
+ bChange = true;
+ }
+ }
+
+ if( bChange )
+ rTextShape.SetOutlinerParaObject(mrOutliner.CreateParaObject());
+
+ mrOutliner.Clear();
+}
+
+bool SdTransformOOo2xDocument::getBulletState( const SfxItemSet& rSet, SfxStyleSheetBase* pSheet, bool& rState )
+{
+ if( getBulletState( rSet, EE_PARA_XMLATTRIBS, rState ) )
+ return true;
+
+ if( getBulletState( rSet, SDRATTR_XMLATTRIBUTES, rState ) )
+ return true;
+
+ if( pSheet && getBulletState( pSheet->GetItemSet(), pSheet->GetPool()->Find( pSheet->GetParent(), pSheet->GetFamily() ), rState ) )
+ return true;
+
+ return false;
+}
+
+bool SdTransformOOo2xDocument::getBulletState( const SfxItemSet& rSet, sal_uInt16 nWhich, bool& rState )
+{
+ if( rSet.GetItemState( nWhich ) == SfxItemState::SET )
+ {
+ const SvXMLAttrContainerItem& rAttr = *rSet.GetItem<SvXMLAttrContainerItem>( nWhich );
+
+ const sal_uInt16 nCount = rAttr.GetAttrCount();
+ for( sal_uInt16 nItem = 0; nItem < nCount; nItem++ )
+ {
+ if( ( rAttr.GetAttrLName( nItem ) == gsEnableNumbering ) && ( rAttr.GetAttrNamespace( nItem ) == gsTextNamespace ) )
+ {
+ const OUString& sValue( rAttr.GetAttrValue( nItem ) );
+ rState = sValue == gsTrue;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool SdTransformOOo2xDocument::transformItemSet( SfxItemSet& rSet, bool bNumbering )
+{
+ bool bRet = false;
+ const SvxLRSpaceItem* pItem = bNumbering ? rSet.GetItem<SvxLRSpaceItem>(EE_PARA_LRSPACE) : nullptr;
+ if (pItem)
+ {
+ SvxLRSpaceItem aItem(*pItem);
+ if( (aItem.GetLeft() != 0) || (aItem.GetTextFirstLineOffset() != 0) )
+ {
+ aItem.SetLeftValue( 0 );
+ aItem.SetTextFirstLineOffset( 0 );
+ rSet.Put( aItem );
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+bool SdTransformOOo2xDocument::removeAlienAttributes( SfxItemSet& rSet )
+{
+ bool b = removeAlienAttributes( rSet, EE_PARA_XMLATTRIBS );
+ b |= removeAlienAttributes( rSet, SDRATTR_XMLATTRIBUTES );
+ return b;
+}
+
+bool SdTransformOOo2xDocument::removeAlienAttributes( SfxItemSet& rSet, sal_uInt16 nWhich )
+{
+ if( rSet.GetItemState( nWhich ) == SfxItemState::SET )
+ {
+ const SvXMLAttrContainerItem& rAttr = *rSet.GetItem<SvXMLAttrContainerItem>( nWhich );
+
+ const sal_uInt16 nCount = rAttr.GetAttrCount();
+ for( sal_uInt16 nItem = 0; nItem < nCount; nItem++ )
+ {
+ if( ( rAttr.GetAttrLName( nItem ) == gsEnableNumbering ) && ( rAttr.GetAttrNamespace( nItem ) == gsTextNamespace ) )
+ {
+ if( nCount == 1 )
+ {
+ rSet.ClearItem( nWhich );
+ }
+ else
+ {
+ SvXMLAttrContainerItem aNewItem( nWhich );
+
+ const sal_uInt16 nFound = nItem;
+ for( nItem = 0; nItem < nCount; nItem++ )
+ {
+ if( nItem != nFound )
+ {
+ OUString const& rNamespace(rAttr.GetAttrNamespace(nItem));
+ OUString const& rPrefix(rAttr.GetAttrPrefix(nItem));
+ if (rPrefix.isEmpty())
+ {
+ aNewItem.AddAttr(rAttr.GetAttrLName(nItem), rAttr.GetAttrValue(nItem));
+ }
+ else
+ {
+ aNewItem.AddAttr(rPrefix, rNamespace, rAttr.GetAttrLName(nItem), rAttr.GetAttrValue(nItem));
+ }
+ }
+ }
+
+ rSet.Put( aNewItem );
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/xml/sdtransform.hxx b/sd/source/filter/xml/sdtransform.hxx
new file mode 100644
index 000000000..64bb1c0a1
--- /dev/null
+++ b/sd/source/filter/xml/sdtransform.hxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <drawdoc.hxx>
+
+void TransformOOo2xDocument(SdDrawDocument* pDocument);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/xml/sdxmlwrp.cxx b/sd/source/filter/xml/sdxmlwrp.cxx
new file mode 100644
index 000000000..90ef68e35
--- /dev/null
+++ b/sd/source/filter/xml/sdxmlwrp.cxx
@@ -0,0 +1,1056 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <officecfg/Office/Common.hxx>
+#include <vcl/errinf.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/xml/sax/SAXParseException.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <o3tl/string_view.hxx>
+#include <editeng/outlobj.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <Outliner.hxx>
+#include <unotools/streamwrap.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/xmlgrhlp.hxx>
+
+#include <DrawDocShell.hxx>
+
+#include <sdxmlwrp.hxx>
+#include <svx/xmleohlp.hxx>
+#include <com/sun/star/xml/sax/Parser.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/xml/sax/XFastParser.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/packages/WrongPasswordException.hpp>
+#include <com/sun/star/packages/zip/ZipIOException.hpp>
+
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+#include <comphelper/genericpropertyset.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <editeng/eeitem.hxx>
+
+// include necessary for XML progress bar at load time
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <svtools/sfxecode.hxx>
+
+#include <sddll.hxx>
+#include <sderror.hxx>
+#include <sdresid.hxx>
+#include "sdtransform.hxx"
+#include <strings.hrc>
+
+#include <sfx2/frame.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::document;
+using namespace comphelper;
+
+#define SD_XML_READERROR ErrCode(1234)
+
+char const sXML_export_impress_meta_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisMetaExporter";
+char const sXML_export_impress_styles_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisStylesExporter";
+char const sXML_export_impress_content_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisContentExporter";
+char const sXML_export_impress_settings_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisSettingsExporter";
+
+char const sXML_export_draw_meta_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisMetaExporter";
+char const sXML_export_draw_styles_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisStylesExporter";
+char const sXML_export_draw_content_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisContentExporter";
+char const sXML_export_draw_settings_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisSettingsExporter";
+
+char const sXML_import_impress_meta_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisMetaImporter";
+char const sXML_import_impress_styles_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisStylesImporter";
+char const sXML_import_impress_content_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisContentImporter";
+char const sXML_import_impress_settings_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisSettingsImporter";
+
+char const sXML_import_draw_meta_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisMetaImporter";
+char const sXML_import_draw_styles_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisStylesImporter";
+char const sXML_import_draw_content_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisContentImporter";
+char const sXML_import_draw_settings_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisSettingsImporter";
+
+// OOo
+char const sXML_import_impress_meta_ooo_service[] = "com.sun.star.comp.Impress.XMLMetaImporter";
+char const sXML_import_impress_styles_ooo_service[] = "com.sun.star.comp.Impress.XMLStylesImporter";
+char const sXML_import_impress_content_ooo_service[] = "com.sun.star.comp.Impress.XMLContentImporter";
+char const sXML_import_impress_settings_ooo_service[] = "com.sun.star.comp.Impress.XMLSettingsImporter";
+
+char const sXML_import_draw_meta_ooo_service[] = "com.sun.star.comp.Draw.XMLMetaImporter";
+char const sXML_import_draw_styles_ooo_service[] = "com.sun.star.comp.Draw.XMLStylesImporter";
+char const sXML_import_draw_content_ooo_service[] = "com.sun.star.comp.Draw.XMLContentImporter";
+char const sXML_import_draw_settings_ooo_service[] = "com.sun.star.comp.Draw.XMLSettingsImporter";
+
+namespace {
+
+struct XML_SERVICEMAP
+{
+ const char* mpService;
+ const char* mpStream;
+};
+
+struct XML_SERVICES
+{
+ const char* mpMeta;
+ const char* mpStyles;
+ const char* mpContent;
+ const char* mpSettings;
+};
+
+}
+
+static XML_SERVICES const * getServices( bool bImport, bool bDraw, sal_uLong nStoreVer )
+{
+ // Expect that export always sets nStoreVer to SOFFICE_FILEFORMAT_8.
+ assert(bImport || nStoreVer != SOFFICE_FILEFORMAT_60);
+
+ static XML_SERVICES const gServices[] =
+ {
+ { sXML_import_impress_meta_oasis_service, sXML_import_impress_styles_oasis_service, sXML_import_impress_content_oasis_service, sXML_import_impress_settings_oasis_service },
+ { sXML_import_draw_meta_oasis_service, sXML_import_draw_styles_oasis_service, sXML_import_draw_content_oasis_service, sXML_import_draw_settings_oasis_service },
+ { sXML_export_impress_meta_oasis_service, sXML_export_impress_styles_oasis_service, sXML_export_impress_content_oasis_service, sXML_export_impress_settings_oasis_service },
+ { sXML_export_draw_meta_oasis_service, sXML_export_draw_styles_oasis_service, sXML_export_draw_content_oasis_service, sXML_export_draw_settings_oasis_service },
+
+ { sXML_import_impress_meta_ooo_service, sXML_import_impress_styles_ooo_service, sXML_import_impress_content_ooo_service, sXML_import_impress_settings_ooo_service },
+ { sXML_import_draw_meta_ooo_service, sXML_import_draw_styles_ooo_service, sXML_import_draw_content_ooo_service, sXML_import_draw_settings_ooo_service },
+ };
+
+ return &gServices[ (bImport ? 0 : 2) + ((nStoreVer == SOFFICE_FILEFORMAT_60) ? 4 : 0) + (bDraw ? 1 : 0 ) ];
+}
+
+
+SdXMLFilter::SdXMLFilter( SfxMedium& rMedium, ::sd::DrawDocShell& rDocShell, SdXMLFilterMode eFilterMode, sal_uLong nStoreVer ) :
+ SdFilter( rMedium, rDocShell ), meFilterMode( eFilterMode ), mnStoreVer( nStoreVer )
+{
+}
+
+SdXMLFilter::~SdXMLFilter()
+{
+}
+
+namespace
+{
+
+ErrCode ReadThroughComponent(
+ const Reference<io::XInputStream>& xInputStream,
+ const Reference<XComponent>& xModelComponent,
+ const OUString& rStreamName,
+ Reference<uno::XComponentContext> const & rxContext,
+ const char* pFilterName,
+ const Sequence<Any>& rFilterArguments,
+ const OUString& rName,
+ bool bMustBeSuccessful,
+ bool bEncrypted )
+{
+ DBG_ASSERT(xInputStream.is(), "input stream missing");
+ DBG_ASSERT(xModelComponent.is(), "document missing");
+ DBG_ASSERT(rxContext.is(), "factory missing");
+ DBG_ASSERT(nullptr != pFilterName,"I need a service name for the component!");
+
+ SAL_INFO( "sd.filter", "ReadThroughComponent" );
+
+ // prepare ParserInputSource
+ xml::sax::InputSource aParserInput;
+ aParserInput.sSystemId = rName;
+ aParserInput.aInputStream = xInputStream;
+
+ // get filter
+ OUString aFilterName(OUString::createFromAscii(pFilterName));
+ // the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler
+ Reference< XInterface > xFilter(
+ rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(aFilterName, rFilterArguments, rxContext),
+ UNO_QUERY );
+ SAL_WARN_IF(!xFilter.is(), "sd.filter", "Can't instantiate filter component: " << aFilterName);
+ if( !xFilter.is() )
+ return SD_XML_READERROR;
+ Reference< xml::sax::XFastParser > xFastParser(xFilter, UNO_QUERY);
+ Reference< xml::sax::XDocumentHandler > xDocumentHandler;
+ if (!xFastParser)
+ xDocumentHandler.set(xFilter, UNO_QUERY);
+ if (!xFastParser && !xDocumentHandler)
+ {
+ SAL_WARN("sd", "service does not implement XFastParser or XDocumentHandler");
+ assert(false);
+ return SD_XML_READERROR;
+ }
+ SAL_INFO( "sd.filter", "" << pFilterName << " created" );
+
+ // connect model and filter
+ Reference < XImporter > xImporter( xFilter, UNO_QUERY );
+ xImporter->setTargetDocument( xModelComponent );
+
+ // finally, parser the stream
+ SAL_INFO( "sd.filter", "parsing stream" );
+ try
+ {
+ if (xFastParser)
+ xFastParser->parseStream( aParserInput );
+ else
+ {
+ Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(rxContext);
+ // connect parser and filter
+ xParser->setDocumentHandler( xDocumentHandler );
+ xParser->parseStream( aParserInput );
+ }
+ }
+ catch (const xml::sax::SAXParseException& r)
+ {
+ css::uno::Any ex( cppu::getCaughtException() );
+ // sax parser sends wrapped exceptions,
+ // try to find the original one
+ xml::sax::SAXException aSaxEx = *static_cast<xml::sax::SAXException const *>(&r);
+ bool bTryChild = true;
+
+ while( bTryChild )
+ {
+ xml::sax::SAXException aTmp;
+ if ( aSaxEx.WrappedException >>= aTmp )
+ aSaxEx = aTmp;
+ else
+ bTryChild = false;
+ }
+
+ packages::zip::ZipIOException aBrokenPackage;
+ if ( aSaxEx.WrappedException >>= aBrokenPackage )
+ return ERRCODE_IO_BROKENPACKAGE;
+
+ if( bEncrypted )
+ return ERRCODE_SFX_WRONGPASSWORD;
+
+ SAL_WARN( "sd.filter", "SAX parse exception caught while importing: " << exceptionToString(ex));
+
+ OUString sErr = OUString::number( r.LineNumber ) +
+ "," + OUString::number( r.ColumnNumber );
+
+ if (!rStreamName.isEmpty())
+ {
+ return *new TwoStringErrorInfo(
+ (bMustBeSuccessful ? ERR_FORMAT_FILE_ROWCOL
+ : WARN_FORMAT_FILE_ROWCOL),
+ rStreamName, sErr,
+ DialogMask::ButtonsOk | DialogMask::MessageError );
+ }
+ else
+ {
+ DBG_ASSERT( bMustBeSuccessful, "Warnings are not supported" );
+ return *new StringErrorInfo( ERR_FORMAT_ROWCOL, sErr,
+ DialogMask::ButtonsOk | DialogMask::MessageError );
+ }
+ }
+ catch (const xml::sax::SAXException& r)
+ {
+ css::uno::Any ex( cppu::getCaughtException() );
+ packages::zip::ZipIOException aBrokenPackage;
+ if ( r.WrappedException >>= aBrokenPackage )
+ return ERRCODE_IO_BROKENPACKAGE;
+
+ if( bEncrypted )
+ return ERRCODE_SFX_WRONGPASSWORD;
+
+ SAL_WARN( "sd.filter", "SAX exception caught while importing: " << exceptionToString(ex));
+ return SD_XML_READERROR;
+ }
+ catch (const packages::zip::ZipIOException&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd.filter", "Zip exception caught while importing");
+ return ERRCODE_IO_BROKENPACKAGE;
+ }
+ catch (const io::IOException&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd.filter", "IO exception caught while importing");
+ return SD_XML_READERROR;
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd.filter", "uno exception caught while importing");
+ return SD_XML_READERROR;
+ }
+
+ // success!
+ return ERRCODE_NONE;
+}
+
+ErrCode ReadThroughComponent(
+ const uno::Reference < embed::XStorage >& xStorage,
+ const Reference<XComponent>& xModelComponent,
+ const char* pStreamName,
+ Reference<uno::XComponentContext> const & rxContext,
+ const char* pFilterName,
+ const Sequence<Any>& rFilterArguments,
+ const OUString& rName,
+ bool bMustBeSuccessful )
+{
+ DBG_ASSERT(xStorage.is(), "Need storage!");
+ DBG_ASSERT(nullptr != pStreamName, "Please, please, give me a name!");
+
+ // open stream (and set parser input)
+ OUString sStreamName = OUString::createFromAscii(pStreamName);
+ bool bContainsStream = false;
+ try
+ {
+ bContainsStream = xStorage->isStreamElement(sStreamName);
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ }
+
+ if (!bContainsStream )
+ {
+ // stream name not found! return immediately with OK signal
+ return ERRCODE_NONE;
+ }
+
+ // set Base URL
+ uno::Reference< beans::XPropertySet > xInfoSet;
+ if( rFilterArguments.hasElements() )
+ rFilterArguments.getConstArray()[0] >>= xInfoSet;
+ DBG_ASSERT( xInfoSet.is(), "missing property set" );
+ if( xInfoSet.is() )
+ {
+ xInfoSet->setPropertyValue( "StreamName", Any( sStreamName ) );
+ }
+
+ try
+ {
+ // get input stream
+ Reference <io::XStream> xStream =
+ xStorage->openStreamElement( sStreamName, embed::ElementModes::READ );
+ Reference <beans::XPropertySet > xProps( xStream, uno::UNO_QUERY );
+ if ( !xStream.is() || ! xProps.is() )
+ return SD_XML_READERROR;
+
+ Any aAny = xProps->getPropertyValue( "Encrypted" );
+
+ bool bEncrypted = false;
+ aAny >>= bEncrypted;
+
+ Reference <io::XInputStream> xInputStream = xStream->getInputStream();
+
+ // read from the stream
+ return ReadThroughComponent(
+ xInputStream, xModelComponent, sStreamName, rxContext,
+ pFilterName, rFilterArguments,
+ rName, bMustBeSuccessful, bEncrypted );
+ }
+ catch (const packages::WrongPasswordException&)
+ {
+ return ERRCODE_SFX_WRONGPASSWORD;
+ }
+ catch (const packages::zip::ZipIOException&)
+ {
+ return ERRCODE_IO_BROKENPACKAGE;
+ }
+ catch (const uno::Exception&)
+ {}
+
+ return SD_XML_READERROR;
+}
+
+}
+
+//PresObjKind::Outlines in master pages are the preview of the outline styles
+//numbering format. Since fdo#78151 toggling bullets on and off changes
+//the style they are a preview of, previously toggling bullets on and off
+//would only affect the preview paragraph itself without an effect on the
+//style. i.e. previews of numbering which don't match the real numbering
+//they are supposed to be a preview of.
+//
+//But there exist documents which were saved previous to that modification
+//so here we detect such cases and fix them up to ensure the previews
+//numbering level matches that of the outline level it previews
+static void fixupOutlinePlaceholderNumberingDepths(SdDrawDocument* pDoc)
+{
+ for (sal_uInt16 i = 0; i < pDoc->GetMasterSdPageCount(PageKind::Standard); ++i)
+ {
+ SdPage *pMasterPage = pDoc->GetMasterSdPage(i, PageKind::Standard);
+ SdrObject* pMasterOutline = pMasterPage->GetPresObj(PresObjKind::Outline);
+ if (!pMasterOutline)
+ continue;
+ OutlinerParaObject* pOutlParaObj = pMasterOutline->GetOutlinerParaObject();
+ if (!pOutlParaObj)
+ continue;
+ SdOutliner* pOutliner = pDoc->GetInternalOutliner();
+ pOutliner->Clear();
+ pOutliner->SetText(*pOutlParaObj);
+ bool bInconsistent = false;
+ const sal_Int32 nParaCount = pOutliner->GetParagraphCount();
+ for (sal_Int32 j = 0; j < nParaCount; ++j)
+ {
+ //Make sure the depth of the paragraph matches that of the outline style it previews
+ const sal_Int16 nExpectedDepth = j;
+ if (nExpectedDepth != pOutliner->GetDepth(j))
+ {
+ Paragraph* p = pOutliner->GetParagraph(j);
+ pOutliner->SetDepth(p, nExpectedDepth);
+ bInconsistent = true;
+ }
+
+ //If the preview has hard-coded bullets/numbering then they must
+ //be stripped to reveal the true underlying styles attributes
+ SfxItemSet aAttrs(pOutliner->GetParaAttribs(j));
+ if (aAttrs.GetItemState(EE_PARA_NUMBULLET) == SfxItemState::SET)
+ {
+ aAttrs.ClearItem(EE_PARA_NUMBULLET);
+ pOutliner->SetParaAttribs(j, aAttrs);
+ bInconsistent = true;
+ }
+
+ }
+ if (bInconsistent)
+ {
+ SAL_WARN("sd.filter", "Fixing inconsistent outline numbering placeholder preview");
+ pMasterOutline->SetOutlinerParaObject(pOutliner->CreateParaObject(0, nParaCount));
+ }
+ pOutliner->Clear();
+ }
+}
+
+bool SdXMLFilter::Import( ErrCode& nError )
+{
+ ErrCode nRet = ERRCODE_NONE;
+
+ // Get service factory
+ Reference< uno::XComponentContext > rxContext =
+ comphelper::getProcessComponentContext();
+
+ SdDrawDocument* pDoc = mrDocShell.GetDoc();
+ bool const bWasUndo(pDoc->IsUndoEnabled());
+ pDoc->EnableUndo(false);
+ pDoc->NewOrLoadCompleted( DocCreationMode::New );
+ pDoc->CreateFirstPages();
+ pDoc->StopWorkStartupDelay();
+
+ mxModel->lockControllers();
+
+ /** property map for import info set */
+ static PropertyMapEntry const aImportInfoMap[] =
+ {
+ // necessary properties for XML progress bar at load time
+ { OUString("ProgressRange"), 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("ProgressMax"), 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("ProgressCurrent"), 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("Preview"), 0, cppu::UnoType<sal_Bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("PageLayouts"), 0, cppu::UnoType<container::XNameAccess>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("PrivateData"), 0, cppu::UnoType<XInterface>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("BaseURI"), 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StreamRelPath"), 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StreamName"), 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("BuildId"), 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("OrganizerMode"), 0, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("SourceStorage"), 0, cppu::UnoType<embed::XStorage>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ };
+
+ uno::Reference< beans::XPropertySet > xInfoSet( GenericPropertySet_CreateInstance( new PropertySetInfo( aImportInfoMap ) ) );
+ xInfoSet->setPropertyValue( "Preview" , uno::Any( mrDocShell.GetDoc()->IsStarDrawPreviewMode() ) );
+
+ // ---- get BuildId from parent container if available
+
+ uno::Reference< container::XChild > xChild( mxModel, uno::UNO_QUERY );
+ if( xChild.is() )
+ {
+ uno::Reference< beans::XPropertySet > xParentSet( xChild->getParent(), uno::UNO_QUERY );
+ if( xParentSet.is() )
+ {
+ uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xParentSet->getPropertySetInfo() );
+ OUString sPropName( "BuildId" );
+ if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(sPropName) )
+ {
+ xInfoSet->setPropertyValue( sPropName, xParentSet->getPropertyValue(sPropName) );
+ }
+ }
+ }
+
+ uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
+ rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
+ Reference< document::XEmbeddedObjectResolver > xObjectResolver;
+ rtl::Reference<SvXMLEmbeddedObjectHelper> xObjectHelper;
+
+ Reference< lang::XComponent > xModelComp = mxModel;
+
+ // try to get an XStatusIndicator from the Medium
+ {
+ SfxItemSet* pSet = mrMedium.GetItemSet();
+ if(pSet)
+ {
+ const SfxUnoAnyItem* pItem = pSet->GetItem(SID_PROGRESS_STATUSBAR_CONTROL);
+ if (pItem)
+ {
+ pItem->GetValue() >>= mxStatusIndicator;
+ }
+ }
+
+ if(mxStatusIndicator.is())
+ {
+ sal_Int32 nProgressRange(1000000);
+ OUString aMsg(SvxResId(RID_SVXSTR_DOC_LOAD));
+ mxStatusIndicator->start(aMsg, nProgressRange);
+
+ // set ProgressRange
+ uno::Any aProgRange;
+ aProgRange <<= nProgressRange;
+ xInfoSet->setPropertyValue( "ProgressRange" , aProgRange);
+
+ // set ProgressCurrent
+ uno::Any aProgCurrent;
+ aProgCurrent <<= sal_Int32(0);
+ xInfoSet->setPropertyValue( "ProgressCurrent" , aProgCurrent);
+ }
+ }
+
+ // get the input stream (storage or stream)
+
+ uno::Reference < embed::XStorage > xStorage = mrMedium.GetStorage();
+
+ xInfoSet->setPropertyValue( "SourceStorage", Any( xStorage ) );
+
+ if( !xStorage.is() )
+ nRet = SD_XML_READERROR;
+
+ if( ERRCODE_NONE == nRet )
+ {
+ xGraphicHelper = SvXMLGraphicHelper::Create( xStorage,
+ SvXMLGraphicHelperMode::Read );
+ xGraphicStorageHandler = xGraphicHelper.get();
+ xObjectHelper = SvXMLEmbeddedObjectHelper::Create(
+ xStorage, *pDoc->GetPersist(),
+ SvXMLEmbeddedObjectHelperMode::Read );
+ xObjectResolver = xObjectHelper.get();
+ }
+
+ // Set base URI
+ OUString const baseURI(mrMedium.GetBaseURL());
+ // needed for relative URLs, but in clipboard copy/paste there may be none
+ SAL_INFO_IF(baseURI.isEmpty(), "sd.filter", "SdXMLFilter: no base URL");
+ xInfoSet->setPropertyValue("BaseURI", Any(baseURI));
+
+ if( ERRCODE_NONE == nRet && SfxObjectCreateMode::EMBEDDED == mrDocShell.GetCreateMode() )
+ {
+ OUString aName;
+ if ( mrMedium.GetItemSet() )
+ {
+ const SfxStringItem* pDocHierarchItem =
+ mrMedium.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME);
+ if ( pDocHierarchItem )
+ aName = pDocHierarchItem->GetValue();
+ }
+ else
+ aName = "dummyObjectName" ;
+
+ if( !aName.isEmpty() )
+ xInfoSet->setPropertyValue( "StreamRelPath", Any( aName ) );
+ }
+
+ if (SdXMLFilterMode::Organizer == meFilterMode)
+ xInfoSet->setPropertyValue("OrganizerMode", uno::Any(true));
+
+ if( ERRCODE_NONE == nRet )
+ {
+
+ // prepare filter arguments
+ Sequence<Any> aFilterArgs( 4 );
+ Any *pArgs = aFilterArgs.getArray();
+ *pArgs++ <<= xInfoSet;
+ *pArgs++ <<= xGraphicStorageHandler;
+ *pArgs++ <<= xObjectResolver;
+ *pArgs++ <<= mxStatusIndicator;
+
+ Sequence<Any> aEmptyArgs( 2 );
+ pArgs = aEmptyArgs.getArray();
+ *pArgs++ <<= xInfoSet;
+ *pArgs++ <<= mxStatusIndicator;
+
+ const OUString aName( mrMedium.GetName() );
+
+ XML_SERVICES const * pServices = getServices( true, IsDraw(), mnStoreVer );
+
+ ErrCode nWarn = ERRCODE_NONE;
+ ErrCode nWarn2 = ERRCODE_NONE;
+ // read storage streams
+ // #i103539#: always read meta.xml for generator
+ nWarn = ReadThroughComponent(
+ xStorage, xModelComp, "meta.xml", rxContext,
+ pServices->mpMeta,
+ aEmptyArgs, aName, false );
+
+ if( meFilterMode != SdXMLFilterMode::Organizer )
+ {
+ nWarn2 = ReadThroughComponent(
+ xStorage, xModelComp, "settings.xml", rxContext,
+ pServices->mpSettings,
+ aFilterArgs, aName, false );
+ }
+
+ nRet = ReadThroughComponent(
+ xStorage, xModelComp, "styles.xml", rxContext,
+ pServices->mpStyles,
+ aFilterArgs, aName, true );
+
+ if( !nRet && (meFilterMode != SdXMLFilterMode::Organizer) )
+ nRet = ReadThroughComponent(
+ xStorage, xModelComp, "content.xml", rxContext,
+ pServices->mpContent,
+ aFilterArgs, aName, true );
+
+ if( !nRet )
+ {
+ if( nWarn )
+ nRet = nWarn;
+ else if( nWarn2 )
+ nRet = nWarn2;
+ }
+ }
+
+ if( xGraphicHelper )
+ xGraphicHelper->dispose();
+ xGraphicHelper.clear();
+ xGraphicStorageHandler = nullptr;
+ if( xObjectHelper.is() )
+ xObjectHelper->dispose();
+ xObjectHelper.clear();
+ xObjectResolver = nullptr;
+
+ if( mxStatusIndicator.is() )
+ mxStatusIndicator->end();
+
+ if( mxModel.is() )
+ mxModel->unlockControllers();
+
+ if( nRet == ERRCODE_NONE )
+ pDoc->UpdateAllLinks();
+
+ if( nRet.anyOf( ERRCODE_NONE, SD_XML_READERROR ) )
+ ;
+ else if( nRet == ERRCODE_IO_BROKENPACKAGE && xStorage.is() )
+ nError = ERRCODE_IO_BROKENPACKAGE;
+ else
+ {
+ // TODO/LATER: this is completely wrong! Filter code should never call ErrorHandler directly!
+ ErrorHandler::HandleError( nRet );
+ if( nRet.IsWarning() )
+ nRet = ERRCODE_NONE;
+ }
+
+ // clear unused named items from item pool
+
+ ::svx::DropUnusedNamedItems(mxModel);
+
+ // set BuildId on XModel for later OLE object loading
+ if( xInfoSet.is() )
+ {
+ uno::Reference< beans::XPropertySet > xModelSet( mxModel, uno::UNO_QUERY );
+ if( xModelSet.is() )
+ {
+ uno::Reference< beans::XPropertySetInfo > xModelSetInfo( xModelSet->getPropertySetInfo() );
+ static const OUStringLiteral sPropName( u"BuildId" );
+
+ OUString sBuildId;
+ xInfoSet->getPropertyValue(sPropName) >>= sBuildId;
+
+ if( xModelSetInfo.is() && xModelSetInfo->hasPropertyByName(sPropName) )
+ {
+ xModelSet->setPropertyValue( sPropName, Any( sBuildId ) );
+ }
+
+ bool bTransform = false;
+
+ if( nRet == ERRCODE_NONE )
+ {
+ if( !sBuildId.isEmpty() )
+ {
+ sal_Int32 nIndex = sBuildId.indexOf('$');
+ if( nIndex != -1 )
+ {
+ sal_Int32 nUPD = o3tl::toInt32(sBuildId.subView( 0, nIndex ));
+
+ if( nUPD == 300 )
+ {
+ sal_Int32 nBuildId = o3tl::toInt32(sBuildId.subView( nIndex+1 ));
+ if( (nBuildId > 0) && (nBuildId < 9316) )
+ bTransform = true; // treat OOo 3.0 beta1 as OOo 2.x
+ }
+ else if( (nUPD == 680) || ( nUPD >= 640 && nUPD <= 645 ) )
+ bTransform = true;
+ }
+ }
+ else
+ {
+ // check for binary formats
+ std::shared_ptr<const SfxFilter> pFilter = mrMedium.GetFilter();
+ if( pFilter )
+ {
+ OUString typeName(pFilter->GetRealTypeName());
+ if( typeName.startsWith( "impress_StarImpress" ) ||
+ typeName.startsWith( "draw_StarDraw" ) )
+ {
+ bTransform = true;
+ }
+ }
+ }
+ }
+
+ if( bTransform )
+ TransformOOo2xDocument( pDoc );
+ }
+ }
+
+ fixupOutlinePlaceholderNumberingDepths(pDoc);
+
+ pDoc->EnableUndo(bWasUndo);
+ mrDocShell.ClearUndoBuffer();
+ return nRet == ERRCODE_NONE;
+}
+
+bool SdXMLFilter::Export()
+{
+ rtl::Reference<SvXMLEmbeddedObjectHelper> xObjectHelper;
+ rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
+ bool bDocRet = false;
+
+ if( !mxModel.is() )
+ {
+ SAL_WARN( "sd.filter","Got NO Model in XMLExport");
+ return false;
+ }
+
+ bool bLocked = mxModel->hasControllersLocked();
+
+ try
+ {
+ mxModel->lockControllers();
+
+ uno::Reference< lang::XServiceInfo > xServiceInfo( mxModel, uno::UNO_QUERY );
+
+ if( !xServiceInfo.is() || !xServiceInfo->supportsService( "com.sun.star.drawing.GenericDrawingDocument" ) )
+ {
+ SAL_WARN( "sd.filter", "Model is no DrawingDocument in XMLExport" );
+ return false;
+ }
+
+ uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+
+ uno::Reference< xml::sax::XWriter > xWriter = xml::sax::Writer::create( xContext );
+
+ /** property map for export info set */
+ static PropertyMapEntry const aExportInfoMap[] =
+ {
+ { OUString("ProgressRange"), 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("ProgressMax"), 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("ProgressCurrent"), 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("UsePrettyPrinting"),0, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("PageLayoutNames"), 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("BaseURI"), 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StreamRelPath"), 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StreamName"), 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StyleNames"), 0, cppu::UnoType<Sequence<OUString>>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StyleFamilies"), 0, cppu::UnoType<Sequence<sal_Int32>>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("TargetStorage"), 0, cppu::UnoType<embed::XStorage>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ };
+
+ uno::Reference< beans::XPropertySet > xInfoSet( GenericPropertySet_CreateInstance( new PropertySetInfo( aExportInfoMap ) ) );
+
+ bool bUsePrettyPrinting = officecfg::Office::Common::Save::Document::PrettyPrinting::get();
+ xInfoSet->setPropertyValue( "UsePrettyPrinting", Any( bUsePrettyPrinting ) );
+
+ const uno::Reference < embed::XStorage >& xStorage = mrMedium.GetOutputStorage();
+
+ // Set base URI
+ OUString sPropName( "BaseURI" );
+ xInfoSet->setPropertyValue( sPropName, Any( mrMedium.GetBaseURL( true ) ) );
+
+ xInfoSet->setPropertyValue( "TargetStorage", Any( xStorage ) );
+
+ if( SfxObjectCreateMode::EMBEDDED == mrDocShell.GetCreateMode() )
+ {
+ OUString aName;
+ if ( mrMedium.GetItemSet() )
+ {
+ const SfxStringItem* pDocHierarchItem =
+ mrMedium.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME);
+ if ( pDocHierarchItem )
+ aName = pDocHierarchItem->GetValue();
+ }
+
+ if( !aName.isEmpty() )
+ {
+ sPropName = "StreamRelPath";
+ xInfoSet->setPropertyValue( sPropName, Any( aName ) );
+ }
+ }
+
+ // initialize descriptor
+ uno::Sequence< beans::PropertyValue > aDescriptor( 1 );
+ beans::PropertyValue* pProps = aDescriptor.getArray();
+
+ pProps[0].Name = "FileName";
+ pProps[0].Value <<= mrMedium.GetName();
+
+ {
+ uno::Reference< document::XEmbeddedObjectResolver > xObjectResolver;
+ uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
+
+ // create helper for graphic and ole export if we have a storage
+ if( xStorage.is() )
+ {
+ xObjectHelper = SvXMLEmbeddedObjectHelper::Create( xStorage, *mrDocShell.GetDoc()->GetPersist(), SvXMLEmbeddedObjectHelperMode::Write );
+ xObjectResolver = xObjectHelper.get();
+
+ xGraphicHelper = SvXMLGraphicHelper::Create( xStorage, SvXMLGraphicHelperMode::Write );
+ xGraphicStorageHandler = xGraphicHelper.get();
+ }
+
+ CreateStatusIndicator();
+ if(mxStatusIndicator.is())
+ {
+ sal_Int32 nProgressRange(1000000);
+ OUString aMsg(SdResId(STR_SAVE_DOC));
+ mxStatusIndicator->start(aMsg, nProgressRange);
+
+ // set ProgressRange
+ uno::Any aProgRange;
+ aProgRange <<= nProgressRange;
+ xInfoSet->setPropertyValue( "ProgressRange" , aProgRange);
+
+ // set ProgressCurrent
+ uno::Any aProgCurrent;
+ aProgCurrent <<= sal_Int32(0);
+ xInfoSet->setPropertyValue( "ProgressCurrent" , aProgCurrent);
+ }
+
+ XML_SERVICES const * pServiceNames = getServices( false, IsDraw(), mnStoreVer );
+
+ XML_SERVICEMAP aServices[5]; sal_uInt16 i = 0;
+ aServices[i ].mpService = pServiceNames->mpStyles;
+ aServices[i++].mpStream = "styles.xml";
+
+ aServices[i ].mpService = pServiceNames->mpContent;
+ aServices[i++].mpStream = "content.xml";
+
+ aServices[i ].mpService = pServiceNames->mpSettings;
+ aServices[i++].mpStream = "settings.xml";
+
+ if( mrDocShell.GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
+ {
+ aServices[i ].mpService = pServiceNames->mpMeta;
+ aServices[i++].mpStream = "meta.xml";
+ };
+
+ aServices[i].mpService = nullptr;
+ aServices[i].mpStream = nullptr;
+
+ XML_SERVICEMAP* pServices = aServices;
+
+ // doc export
+ do
+ {
+ SAL_INFO( "sd.filter", "exporting substream " << pServices->mpStream );
+
+ uno::Reference<io::XOutputStream> xDocOut;
+ if( xStorage.is() )
+ {
+ const OUString sDocName( OUString::createFromAscii( pServices->mpStream ) );
+ uno::Reference<io::XStream> xStream =
+ xStorage->openStreamElement( sDocName,
+ embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
+
+ DBG_ASSERT(xStream.is(), "Can't create output stream in package!");
+ if( !xStream.is() )
+ return false;
+
+ xDocOut = xStream->getOutputStream();
+ Reference <beans::XPropertySet > xProps( xStream, uno::UNO_QUERY );
+ if( !xDocOut.is() || !xProps.is() )
+ return false;
+
+ xProps->setPropertyValue( "MediaType", Any(OUString( "text/xml")));
+
+ // encrypt all streams
+ xProps->setPropertyValue( "UseCommonStoragePasswordEncryption",
+ uno::Any( true ) );
+
+ xInfoSet->setPropertyValue( "StreamName", Any( sDocName ) );
+ }
+
+ xWriter->setOutputStream( xDocOut );
+
+ uno::Sequence< uno::Any > aArgs( 2 + ( mxStatusIndicator.is() ? 1 : 0 ) + ( xGraphicStorageHandler.is() ? 1 : 0 ) + ( xObjectResolver.is() ? 1 : 0 ) );
+ uno::Any* pArgs = aArgs.getArray();
+ *pArgs++ <<= xInfoSet;
+ if (xGraphicStorageHandler.is())
+ *pArgs++ <<= xGraphicStorageHandler;
+ if (xObjectResolver.is())
+ *pArgs++ <<= xObjectResolver;
+ if (mxStatusIndicator.is())
+ *pArgs++ <<= mxStatusIndicator;
+
+ *pArgs <<= xWriter;
+
+ uno::Reference< document::XFilter > xFilter( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii( pServices->mpService ), aArgs, xContext ), uno::UNO_QUERY );
+ if( xFilter.is() )
+ {
+ uno::Reference< document::XExporter > xExporter( xFilter, uno::UNO_QUERY );
+ if( xExporter.is() )
+ {
+ xExporter->setSourceDocument( mxModel );
+ // outputstream will be closed by SAX parser
+ bDocRet = xFilter->filter( aDescriptor );
+ }
+ }
+
+ pServices++;
+ }
+ while( bDocRet && pServices->mpService );
+
+ if(mxStatusIndicator.is())
+ mxStatusIndicator->end();
+ }
+ }
+ catch (const uno::Exception &)
+ {
+ TOOLS_WARN_EXCEPTION( "sd.filter", "uno Exception caught while exporting");
+ bDocRet = false;
+ }
+ if ( !bLocked )
+ mxModel->unlockControllers();
+
+ if( xGraphicHelper )
+ xGraphicHelper->dispose();
+ xGraphicHelper.clear();
+
+ if( xObjectHelper )
+ xObjectHelper->dispose();
+ xObjectHelper.clear();
+
+ return bDocRet;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportFODP(SvStream &rStream)
+{
+ SdDLL::Init();
+
+ sd::DrawDocShellRef xDocSh(new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress));
+ xDocSh->DoInitNew();
+ uno::Reference<frame::XModel> xModel(xDocSh->GetModel());
+
+ uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(comphelper::getProcessServiceFactory());
+ uno::Reference<io::XInputStream> xStream(new ::utl::OSeekableInputStreamWrapper(rStream));
+ uno::Reference<uno::XInterface> xInterface(xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.XmlFilterAdaptor"), uno::UNO_SET_THROW);
+
+ css::uno::Sequence<OUString> aUserData
+ {
+ "com.sun.star.comp.filter.OdfFlatXml",
+ "",
+ "com.sun.star.comp.Impress.XMLOasisImporter",
+ "com.sun.star.comp.Impress.XMLOasisExporter",
+ "",
+ "",
+ "true"
+ };
+ uno::Sequence<beans::PropertyValue> aAdaptorArgs(comphelper::InitPropertySequence(
+ {
+ { "UserData", uno::Any(aUserData) },
+ }));
+ css::uno::Sequence<uno::Any> aOuterArgs{ uno::Any(aAdaptorArgs) };
+
+ uno::Reference<lang::XInitialization> xInit(xInterface, uno::UNO_QUERY_THROW);
+ xInit->initialize(aOuterArgs);
+
+ uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
+ {
+ { "InputStream", uno::Any(xStream) },
+ { "URL", uno::Any(OUString("private:stream")) },
+ }));
+ xImporter->setTargetDocument(xModel);
+
+ uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
+ //SetLoading hack because the document properties will be re-initted
+ //by the xml filter and during the init, while it's considered uninitialized,
+ //setting a property will inform the document it's modified, which attempts
+ //to update the properties, which throws cause the properties are uninitialized
+ xDocSh->SetLoading(SfxLoadedFlags::NONE);
+ bool ret = xFilter->filter(aArgs);
+ xDocSh->SetLoading(SfxLoadedFlags::ALL);
+
+ xDocSh->DoClose();
+
+ return ret;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportPPTX(SvStream &rStream)
+{
+ SdDLL::Init();
+
+ sd::DrawDocShellRef xDocSh(new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress));
+ xDocSh->DoInitNew();
+ uno::Reference<frame::XModel> xModel(xDocSh->GetModel());
+
+ uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(comphelper::getProcessServiceFactory());
+ uno::Reference<io::XInputStream> xStream(new utl::OSeekableInputStreamWrapper(rStream));
+
+ uno::Reference<document::XFilter> xFilter(xMultiServiceFactory->createInstance("com.sun.star.comp.oox.ppt.PowerPointImport"), uno::UNO_QUERY_THROW);
+
+ uno::Reference<document::XImporter> xImporter(xFilter, uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
+ {
+ { "InputStream", uno::Any(xStream) },
+ { "InputMode", uno::Any(true) },
+ }));
+ xImporter->setTargetDocument(xModel);
+
+ //SetLoading hack because the document properties will be re-initted
+ //by the xml filter and during the init, while it's considered uninitialized,
+ //setting a property will inform the document it's modified, which attempts
+ //to update the properties, which throws cause the properties are uninitialized
+ xDocSh->SetLoading(SfxLoadedFlags::NONE);
+ bool ret = false;
+ try
+ {
+ ret = xFilter->filter(aArgs);
+ }
+ catch (...)
+ {
+ }
+ xDocSh->SetLoading(SfxLoadedFlags::ALL);
+
+ xDocSh->DoClose();
+
+ return ret;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/helper/simplereferencecomponent.cxx b/sd/source/helper/simplereferencecomponent.cxx
new file mode 100644
index 000000000..740c2629b
--- /dev/null
+++ b/sd/source/helper/simplereferencecomponent.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <helper/simplereferencecomponent.hxx>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+using com::sun::star::uno::RuntimeException;
+using sd::SimpleReferenceComponent;
+
+SimpleReferenceComponent::SimpleReferenceComponent()
+ : m_nCount(0)
+ , mbDisposed(false)
+{
+}
+
+SimpleReferenceComponent::~SimpleReferenceComponent()
+{
+ OSL_ASSERT(m_nCount == 0);
+ OSL_ASSERT(mbDisposed);
+}
+
+void SimpleReferenceComponent::acquire() { osl_atomic_increment(&m_nCount); }
+
+void SimpleReferenceComponent::release()
+{
+ if ((1 == m_nCount) && !mbDisposed)
+ {
+ try
+ {
+ Dispose();
+ }
+ catch (RuntimeException const&) // don't break throw ()
+ {
+ TOOLS_WARN_EXCEPTION("sd", "");
+ }
+ }
+
+ if (osl_atomic_decrement(&m_nCount) == 0)
+ delete this;
+}
+
+void SimpleReferenceComponent::Dispose()
+{
+ if (!mbDisposed)
+ {
+ mbDisposed = true;
+ disposing();
+ }
+}
+
+void SimpleReferenceComponent::disposing() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessibleDocumentViewBase.cxx b/sd/source/ui/accessibility/AccessibleDocumentViewBase.cxx
new file mode 100644
index 000000000..c297184fa
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessibleDocumentViewBase.cxx
@@ -0,0 +1,773 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleDocumentViewBase.hxx>
+#include <com/sun/star/drawing/XDrawView.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <sfx2/objsh.hxx>
+#include <tools/debug.hxx>
+
+#include <cppuhelper/queryinterface.hxx>
+#include <svx/svdobj.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <Window.hxx>
+#include <OutlineViewShell.hxx>
+
+#include <svx/svdlayer.hxx>
+#include <editeng/editobj.hxx>
+#include <LayerTabBar.hxx>
+#include <svtools/colorcfg.hxx>
+#include <ViewShell.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <editeng/outlobj.hxx>
+#include <sdpage.hxx>
+#include <DrawViewShell.hxx>
+#include <PresentationViewShell.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+using ::com::sun::star::uno::Reference;
+
+namespace accessibility {
+
+//===== internal ============================================================
+AccessibleDocumentViewBase::AccessibleDocumentViewBase (
+ ::sd::Window* pSdWindow,
+ ::sd::ViewShell* pViewShell,
+ const uno::Reference<frame::XController>& rxController,
+ const uno::Reference<XAccessible>& rxParent)
+ : AccessibleContextBase (rxParent,
+ pViewShell->GetDoc()->GetDocumentType() == DocumentType::Impress ?
+ AccessibleRole::DOCUMENT_PRESENTATION :
+ AccessibleRole::DOCUMENT),
+ mxController (rxController),
+ maViewForwarder (
+ static_cast<SdrPaintView*>(pViewShell->GetView()),
+ *pSdWindow->GetOutDev())
+{
+ if (mxController.is())
+ mxModel = mxController->getModel();
+
+ // Fill the shape tree info.
+ maShapeTreeInfo.SetModelBroadcaster (
+ uno::Reference<document::XShapeEventBroadcaster>(
+ mxModel, uno::UNO_QUERY_THROW));
+ maShapeTreeInfo.SetController (mxController);
+ maShapeTreeInfo.SetSdrView (pViewShell->GetView());
+ maShapeTreeInfo.SetWindow (pSdWindow);
+ maShapeTreeInfo.SetViewForwarder (&maViewForwarder);
+
+ mxWindow = ::VCLUnoHelper::GetInterface (pSdWindow);
+ mpViewShell = pViewShell;
+}
+
+AccessibleDocumentViewBase::~AccessibleDocumentViewBase()
+{
+ // At this place we should be disposed. You may want to add a
+ // corresponding assertion into the destructor of a derived class.
+}
+
+void AccessibleDocumentViewBase::Init()
+{
+ // Finish the initialization of the shape tree info container.
+ maShapeTreeInfo.SetDocumentWindow (this);
+
+ // Register as window listener to stay up to date with its size and
+ // position.
+ mxWindow->addWindowListener (this);
+ // Register as focus listener to
+ mxWindow->addFocusListener (this);
+
+ // Determine the list of shapes on the current page.
+ uno::Reference<drawing::XShapes> xShapeList;
+ uno::Reference<drawing::XDrawView> xView (mxController, uno::UNO_QUERY);
+ if (xView.is())
+ xShapeList = xView->getCurrentPage();
+
+ // Register this object as dispose event listener at the model.
+ if (mxModel.is())
+ mxModel->addEventListener (
+ static_cast<awt::XWindowListener*>(this));
+
+ // Register as property change listener at the controller.
+ uno::Reference<beans::XPropertySet> xSet (mxController, uno::UNO_QUERY);
+ if (xSet.is())
+ xSet->addPropertyChangeListener (
+ "",
+ static_cast<beans::XPropertyChangeListener*>(this));
+
+ // Register this object as dispose event listener at the controller.
+ if (mxController.is())
+ mxController->addEventListener (
+ static_cast<awt::XWindowListener*>(this));
+
+ // Register at VCL Window to be informed of activated and deactivated
+ // OLE objects.
+ vcl::Window* pWindow = maShapeTreeInfo.GetWindow();
+ if (pWindow != nullptr)
+ {
+ maWindowLink = LINK(
+ this, AccessibleDocumentViewBase, WindowChildEventListener);
+
+ pWindow->AddChildEventListener (maWindowLink);
+
+ sal_uInt16 nCount = pWindow->GetChildCount();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ vcl::Window* pChildWindow = pWindow->GetChild (i);
+ if (pChildWindow &&
+ (AccessibleRole::EMBEDDED_OBJECT
+ ==pChildWindow->GetAccessibleRole()))
+ {
+ SetAccessibleOLEObject (pChildWindow->GetAccessible());
+ }
+ }
+ }
+ SfxObjectShell* pObjShell = mpViewShell->GetViewFrame()->GetObjectShell();
+ if(!pObjShell->IsReadOnly())
+ SetState(AccessibleStateType::EDITABLE);
+}
+
+IMPL_LINK(AccessibleDocumentViewBase, WindowChildEventListener,
+ VclWindowEvent&, rEvent, void)
+{
+ // DBG_ASSERT( pVclEvent->GetWindow(), "Window???" );
+ switch (rEvent.GetId())
+ {
+ case VclEventId::ObjectDying:
+ {
+ // Window is dying. Unregister from VCL Window.
+ // This is also attempted in the disposing() method.
+ vcl::Window* pWindow = maShapeTreeInfo.GetWindow();
+ vcl::Window* pDyingWindow = rEvent.GetWindow();
+ if (pWindow==pDyingWindow && pWindow!=nullptr && maWindowLink.IsSet())
+ {
+ pWindow->RemoveChildEventListener (maWindowLink);
+ maWindowLink = Link<VclWindowEvent&,void>();
+ }
+ }
+ break;
+
+ case VclEventId::WindowShow:
+ {
+ // A new window has been created. Is it an OLE object?
+ vcl::Window* pChildWindow = static_cast<vcl::Window*>(
+ rEvent.GetData());
+ if (pChildWindow!=nullptr
+ && (pChildWindow->GetAccessibleRole()
+ == AccessibleRole::EMBEDDED_OBJECT))
+ {
+ SetAccessibleOLEObject (pChildWindow->GetAccessible());
+ }
+ }
+ break;
+
+ case VclEventId::WindowHide:
+ {
+ // A window has been destroyed. Has that been an OLE
+ // object?
+ vcl::Window* pChildWindow = static_cast<vcl::Window*>(
+ rEvent.GetData());
+ if (pChildWindow!=nullptr
+ && (pChildWindow->GetAccessibleRole()
+ == AccessibleRole::EMBEDDED_OBJECT))
+ {
+ SetAccessibleOLEObject (nullptr);
+ }
+ }
+ break;
+
+ default: break;
+ }
+}
+
+//===== IAccessibleViewForwarderListener ====================================
+
+void AccessibleDocumentViewBase::ViewForwarderChanged()
+{
+ // Empty
+}
+
+//===== XAccessibleContext ==================================================
+
+Reference<XAccessible> SAL_CALL
+ AccessibleDocumentViewBase::getAccessibleParent()
+{
+ ThrowIfDisposed ();
+
+ return AccessibleContextBase::getAccessibleParent();
+}
+
+sal_Int32 SAL_CALL
+ AccessibleDocumentViewBase::getAccessibleChildCount()
+{
+ ThrowIfDisposed ();
+
+ if (mxAccessibleOLEObject.is())
+ return 1;
+ else
+ return 0;
+}
+
+Reference<XAccessible> SAL_CALL
+ AccessibleDocumentViewBase::getAccessibleChild (sal_Int32 nIndex)
+{
+ ThrowIfDisposed ();
+
+ ::osl::MutexGuard aGuard (m_aMutex);
+ if (mxAccessibleOLEObject.is())
+ if (nIndex == 0)
+ return mxAccessibleOLEObject;
+
+ throw lang::IndexOutOfBoundsException ( "no child with index " + OUString::number(nIndex) );
+}
+
+//===== XAccessibleComponent ================================================
+
+/** Iterate over all children and test whether the specified point lies
+ within one of their bounding boxes. Return the first child for which
+ this is true.
+*/
+uno::Reference<XAccessible > SAL_CALL
+ AccessibleDocumentViewBase::getAccessibleAtPoint (
+ const awt::Point& aPoint)
+{
+ ThrowIfDisposed ();
+
+ ::osl::MutexGuard aGuard (m_aMutex);
+ uno::Reference<XAccessible> xChildAtPosition;
+
+ sal_Int32 nChildCount = getAccessibleChildCount ();
+ for (sal_Int32 i=nChildCount-1; i>=0; --i)
+ {
+ Reference<XAccessible> xChild (getAccessibleChild (i));
+ if (xChild.is())
+ {
+ Reference<XAccessibleComponent> xChildComponent (
+ xChild->getAccessibleContext(), uno::UNO_QUERY);
+ if (xChildComponent.is())
+ {
+ awt::Rectangle aBBox (xChildComponent->getBounds());
+ if ( (aPoint.X >= aBBox.X)
+ && (aPoint.Y >= aBBox.Y)
+ && (aPoint.X < aBBox.X+aBBox.Width)
+ && (aPoint.Y < aBBox.Y+aBBox.Height) )
+ {
+ xChildAtPosition = xChild;
+ break;
+ }
+ }
+ }
+ }
+
+ // Have not found a child under the given point. Returning empty
+ // reference to indicate this.
+ return xChildAtPosition;
+}
+
+awt::Rectangle SAL_CALL
+ AccessibleDocumentViewBase::getBounds()
+{
+ ThrowIfDisposed ();
+
+ // Transform visible area into screen coordinates.
+ ::tools::Rectangle aVisibleArea (
+ maShapeTreeInfo.GetViewForwarder()->GetVisibleArea());
+ ::Point aPixelTopLeft (
+ maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
+ aVisibleArea.TopLeft()));
+ ::Point aPixelSize (
+ maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
+ aVisibleArea.BottomRight())
+ - aPixelTopLeft);
+
+ // Prepare to subtract the parent position to transform into relative
+ // coordinates.
+ awt::Point aParentPosition;
+ Reference<XAccessible> xParent = getAccessibleParent ();
+ if (xParent.is())
+ {
+ Reference<XAccessibleComponent> xParentComponent (
+ xParent->getAccessibleContext(), uno::UNO_QUERY);
+ if (xParentComponent.is())
+ aParentPosition = xParentComponent->getLocationOnScreen();
+ }
+
+ return awt::Rectangle (
+ aPixelTopLeft.X() - aParentPosition.X,
+ aPixelTopLeft.Y() - aParentPosition.Y,
+ aPixelSize.X(),
+ aPixelSize.Y());
+}
+
+awt::Point SAL_CALL
+ AccessibleDocumentViewBase::getLocation()
+{
+ ThrowIfDisposed ();
+ awt::Rectangle aBoundingBox (getBounds());
+ return awt::Point (aBoundingBox.X, aBoundingBox.Y);
+}
+
+awt::Point SAL_CALL
+ AccessibleDocumentViewBase::getLocationOnScreen()
+{
+ ThrowIfDisposed ();
+ ::Point aLogicalPoint (maShapeTreeInfo.GetViewForwarder()->GetVisibleArea().TopLeft());
+ ::Point aPixelPoint (maShapeTreeInfo.GetViewForwarder()->LogicToPixel (aLogicalPoint));
+ return awt::Point (aPixelPoint.X(), aPixelPoint.Y());
+}
+
+awt::Size SAL_CALL
+ AccessibleDocumentViewBase::getSize()
+{
+ ThrowIfDisposed ();
+
+ // Transform visible area into screen coordinates.
+ ::tools::Rectangle aVisibleArea (
+ maShapeTreeInfo.GetViewForwarder()->GetVisibleArea());
+ ::Point aPixelTopLeft (
+ maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
+ aVisibleArea.TopLeft()));
+ ::Point aPixelSize (
+ maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
+ aVisibleArea.BottomRight())
+ - aPixelTopLeft);
+
+ return awt::Size (aPixelSize.X(), aPixelSize.Y());
+}
+
+//===== XInterface ==========================================================
+
+uno::Any SAL_CALL
+ AccessibleDocumentViewBase::queryInterface (const uno::Type & rType)
+{
+ uno::Any aReturn = AccessibleContextBase::queryInterface (rType);
+ if ( ! aReturn.hasValue())
+ aReturn = ::cppu::queryInterface (rType,
+ static_cast<XAccessibleComponent*>(this),
+ static_cast<XAccessibleSelection*>(this),
+ static_cast<lang::XEventListener*>(
+ static_cast<awt::XWindowListener*>(this)),
+ static_cast<beans::XPropertyChangeListener*>(this),
+ static_cast<awt::XWindowListener*>(this),
+ static_cast<awt::XFocusListener*>(this)
+ ,static_cast<XAccessibleExtendedAttributes*>(this)
+ );
+ return aReturn;
+}
+
+void SAL_CALL
+ AccessibleDocumentViewBase::acquire()
+ noexcept
+{
+ AccessibleContextBase::acquire ();
+}
+
+void SAL_CALL
+ AccessibleDocumentViewBase::release()
+ noexcept
+{
+ AccessibleContextBase::release ();
+}
+
+// XServiceInfo
+
+OUString SAL_CALL
+ AccessibleDocumentViewBase::getImplementationName()
+{
+ return "AccessibleDocumentViewBase";
+}
+
+css::uno::Sequence< OUString> SAL_CALL
+ AccessibleDocumentViewBase::getSupportedServiceNames()
+{
+ ThrowIfDisposed ();
+ return AccessibleContextBase::getSupportedServiceNames ();
+}
+
+//===== XTypeProvider =======================================================
+
+css::uno::Sequence< css::uno::Type> SAL_CALL
+ AccessibleDocumentViewBase::getTypes()
+{
+ ThrowIfDisposed ();
+
+ return comphelper::concatSequences(
+ // Get list of types from the context base implementation, ...
+ AccessibleContextBase::getTypes(),
+ // ... get list of types from component base implementation, ...
+ AccessibleComponentBase::getTypes(),
+ // ...and add the additional type for the component, ...
+ css::uno::Sequence {
+ cppu::UnoType<lang::XEventListener>::get(),
+ cppu::UnoType<beans::XPropertyChangeListener>::get(),
+ cppu::UnoType<awt::XWindowListener>::get(),
+ cppu::UnoType<awt::XFocusListener>::get(),
+ cppu::UnoType<XAccessibleEventBroadcaster>::get() });
+}
+
+void AccessibleDocumentViewBase::impl_dispose()
+{
+ // Unregister from VCL Window.
+ vcl::Window* pWindow = maShapeTreeInfo.GetWindow();
+ if (maWindowLink.IsSet())
+ {
+ if (pWindow)
+ pWindow->RemoveChildEventListener (maWindowLink);
+ maWindowLink = Link<VclWindowEvent&,void>();
+ }
+ else
+ {
+ DBG_ASSERT (pWindow, "AccessibleDocumentViewBase::disposing");
+ }
+
+ // Unregister from window.
+ if (mxWindow.is())
+ {
+ mxWindow->removeWindowListener (this);
+ mxWindow->removeFocusListener (this);
+ mxWindow = nullptr;
+ }
+
+ // Unregister from the model.
+ if (mxModel.is())
+ mxModel->removeEventListener (
+ static_cast<awt::XWindowListener*>(this));
+
+ // Unregister from the controller.
+ if (mxController.is())
+ {
+ uno::Reference<beans::XPropertySet> xSet (mxController, uno::UNO_QUERY);
+ if (xSet.is())
+ xSet->removePropertyChangeListener ("", static_cast<beans::XPropertyChangeListener*>(this));
+
+ mxController->removeEventListener (
+ static_cast<awt::XWindowListener*>(this));
+ }
+
+ // Propagate change of controller down the shape tree.
+ maShapeTreeInfo.SetModelBroadcaster (nullptr);
+
+ // Reset the model reference.
+ mxModel = nullptr;
+ // Reset the model reference.
+ mxController = nullptr;
+
+ maShapeTreeInfo.SetDocumentWindow (nullptr);
+}
+
+//===== XEventListener ======================================================
+
+void SAL_CALL
+ AccessibleDocumentViewBase::disposing (const lang::EventObject& rEventObject)
+{
+ ThrowIfDisposed ();
+
+ // Register this object as dispose event and document::XEventListener
+ // listener at the model.
+
+ if ( ! rEventObject.Source.is())
+ {
+ // Paranoia. Can this really happen?
+ }
+ else if (rEventObject.Source == mxModel || rEventObject.Source == mxController)
+ {
+ impl_dispose();
+ }
+}
+
+//===== XPropertyChangeListener =============================================
+
+void SAL_CALL AccessibleDocumentViewBase::propertyChange (const beans::PropertyChangeEvent& )
+{
+ // Empty
+}
+
+//===== XWindowListener =====================================================
+
+void SAL_CALL
+ AccessibleDocumentViewBase::windowResized (const css::awt::WindowEvent& )
+{
+ if( IsDisposed() )
+ return;
+
+ ViewForwarderChanged();
+}
+
+void SAL_CALL
+ AccessibleDocumentViewBase::windowMoved (const css::awt::WindowEvent& )
+{
+ if( IsDisposed() )
+ return;
+
+ ViewForwarderChanged();
+}
+
+void SAL_CALL
+ AccessibleDocumentViewBase::windowShown (const css::lang::EventObject& )
+{
+ if( IsDisposed() )
+ return;
+
+ ViewForwarderChanged();
+}
+
+void SAL_CALL
+ AccessibleDocumentViewBase::windowHidden (const css::lang::EventObject& )
+{
+ if( IsDisposed() )
+ return;
+
+ ViewForwarderChanged();
+}
+
+//===== XFocusListener ==================================================
+
+void AccessibleDocumentViewBase::focusGained (const css::awt::FocusEvent& e)
+{
+ ThrowIfDisposed ();
+ if (e.Source == mxWindow)
+ Activated ();
+}
+
+void AccessibleDocumentViewBase::focusLost (const css::awt::FocusEvent& e)
+{
+ ThrowIfDisposed ();
+ if (e.Source == mxWindow)
+ Deactivated ();
+}
+
+//===== protected internal ==================================================
+
+// This method is called from the component helper base class while disposing.
+void SAL_CALL AccessibleDocumentViewBase::disposing()
+{
+ impl_dispose();
+
+ AccessibleContextBase::disposing ();
+}
+
+/// Create a name for this view.
+OUString
+ AccessibleDocumentViewBase::CreateAccessibleName()
+{
+ return "AccessibleDocumentViewBase";
+}
+
+void AccessibleDocumentViewBase::Activated()
+{
+ // Empty. Overwrite to do something useful.
+}
+
+void AccessibleDocumentViewBase::Deactivated()
+{
+ // Empty. Overwrite to do something useful.
+}
+
+void AccessibleDocumentViewBase::SetAccessibleOLEObject (
+ const Reference <XAccessible>& xOLEObject)
+{
+ // Send child event about removed accessible OLE object if necessary.
+ if (mxAccessibleOLEObject != xOLEObject)
+ if (mxAccessibleOLEObject.is())
+ CommitChange (
+ AccessibleEventId::CHILD,
+ uno::Any(),
+ uno::Any (mxAccessibleOLEObject));
+
+ // Assume that the accessible OLE Object disposes itself correctly.
+
+ {
+ ::osl::MutexGuard aGuard (m_aMutex);
+ mxAccessibleOLEObject = xOLEObject;
+ }
+
+ // Send child event about new accessible OLE object if necessary.
+ if (mxAccessibleOLEObject.is())
+ CommitChange (
+ AccessibleEventId::CHILD,
+ uno::Any (mxAccessibleOLEObject),
+ uno::Any());
+}
+
+//===== methods from AccessibleSelectionBase ==================================================
+
+// return the member maMutex;
+::osl::Mutex&
+ AccessibleDocumentViewBase::implGetMutex()
+{
+ return m_aMutex;
+}
+
+// return ourself as context in default case
+uno::Reference< XAccessibleContext >
+ AccessibleDocumentViewBase::implGetAccessibleContext()
+{
+ return this;
+}
+
+// return sal_False in default case
+bool
+ AccessibleDocumentViewBase::implIsSelected( sal_Int32 )
+{
+ return false;
+}
+
+// return nothing in default case
+void
+ AccessibleDocumentViewBase::implSelect( sal_Int32, bool )
+{
+}
+
+uno::Any SAL_CALL AccessibleDocumentViewBase::getExtendedAttributes()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ uno::Any anyAttribute;
+ OUStringBuffer sValue;
+ if (auto pDrViewSh = dynamic_cast<::sd::DrawViewShell* > (mpViewShell))
+ {
+ OUString sDisplay;
+ OUString sName = "page-name:";
+ // MT IA2: Not used...
+ // SdPage* pCurrPge = pDrViewSh->getCurrentPage();
+ SdDrawDocument* pDoc = pDrViewSh->GetDoc();
+ sDisplay = pDrViewSh->getCurrentPage()->GetName();
+ sDisplay = sDisplay.replaceFirst( "\\", "\\\\" );
+ sDisplay = sDisplay.replaceFirst( "=", "\\=" );
+ sDisplay = sDisplay.replaceFirst( ";", "\\;" );
+ sDisplay = sDisplay.replaceFirst( ",", "\\," );
+ sDisplay = sDisplay.replaceFirst( ":", "\\:" );
+ sValue = sName + sDisplay ;
+ sValue.append(";page-number:");
+ sValue.append(static_cast<sal_Int32>(static_cast<sal_uInt16>((pDrViewSh->getCurrentPage()->GetPageNum()-1)>>1) + 1));
+ sValue.append(";total-pages:");
+ sValue.append(static_cast<sal_Int32>(pDrViewSh->GetPageTabControl().GetPageCount()));
+ sValue.append(";");
+ if(pDrViewSh->IsLayerModeActive() && pDrViewSh->GetLayerTabControl()) // #i87182#
+ {
+ sName = "page-name:";
+ sValue = sName;
+ OUString sLayerName(pDrViewSh->GetLayerTabControl()->GetLayerName(pDrViewSh->GetLayerTabControl()->GetCurPageId()) );
+ sDisplay = pDrViewSh->GetLayerTabControl()->GetPageText(pDrViewSh->GetLayerTabControl()->GetCurPageId());
+ if( pDoc )
+ {
+ SdrLayerAdmin& rLayerAdmin = pDoc->GetLayerAdmin();
+ SdrLayer* aSdrLayer = rLayerAdmin.GetLayer(sLayerName);
+ if( aSdrLayer )
+ {
+ const OUString& layerAltText = aSdrLayer->GetTitle();
+ if (!layerAltText.isEmpty())
+ {
+ sName = " ";
+ sDisplay += sName + layerAltText;
+ }
+ }
+ }
+ sDisplay = sDisplay.replaceFirst( "\\", "\\\\" );
+ sDisplay = sDisplay.replaceFirst( "=", "\\=" );
+ sDisplay = sDisplay.replaceFirst( ";", "\\;" );
+ sDisplay = sDisplay.replaceFirst( ",", "\\," );
+ sDisplay = sDisplay.replaceFirst( ":", "\\:" );
+ sValue.append(sDisplay);
+ sValue.append(";page-number:");
+ sValue.append(static_cast<sal_Int32>(pDrViewSh->GetActiveTabLayerIndex()+1));
+ sValue.append(";total-pages:");
+ sValue.append(static_cast<sal_Int32>(pDrViewSh->GetLayerTabControl()->GetPageCount()));
+ sValue.append(";");
+ }
+ }
+ if (auto pPresViewSh = dynamic_cast<::sd::PresentationViewShell* >(mpViewShell))
+ {
+ SdPage* pCurrPge = pPresViewSh->getCurrentPage();
+ SdDrawDocument* pDoc = pPresViewSh->GetDoc();
+ SdPage* pNotesPge = pDoc->GetSdPage((pCurrPge->GetPageNum()-1)>>1, PageKind::Notes);
+ if (pNotesPge)
+ {
+ SdrObject* pNotesObj = pNotesPge->GetPresObj(PresObjKind::Notes);
+ if (pNotesObj)
+ {
+ OutlinerParaObject* pPara = pNotesObj->GetOutlinerParaObject();
+ if (pPara)
+ {
+ sValue.append("note:");
+ const EditTextObject& rEdit = pPara->GetTextObject();
+ for (sal_Int32 i=0;i<rEdit.GetParagraphCount();i++)
+ {
+ OUString strNote = rEdit.GetText(i);
+ strNote = strNote.replaceFirst( "\\", "\\\\" );
+ strNote = strNote.replaceFirst( "=", "\\=" );
+ strNote = strNote.replaceFirst( ";", "\\;" );
+ strNote = strNote.replaceFirst( ",", "\\," );
+ strNote = strNote.replaceFirst( ":", "\\:" );
+ sValue.append(strNote);
+ sValue.append(";");//to divide each paragraph
+ }
+ }
+ }
+ }
+ }
+ if (dynamic_cast<const ::sd::OutlineViewShell* >(mpViewShell ) != nullptr )
+ {
+ SdPage* pCurrPge = mpViewShell->GetActualPage();
+ SdDrawDocument* pDoc = mpViewShell->GetDoc();
+ if(pCurrPge && pDoc)
+ {
+ OUString sDisplay;
+ sDisplay = pCurrPge->GetName();
+ sDisplay = sDisplay.replaceFirst( "=", "\\=" );
+ sDisplay = sDisplay.replaceFirst( ";", "\\;" );
+ sDisplay = sDisplay.replaceFirst( ",", "\\," );
+ sDisplay = sDisplay.replaceFirst( ":", "\\:" );
+ sValue = "page-name:" + sDisplay;
+ sValue.append(";page-number:");
+ sValue.append(static_cast<sal_Int32>(static_cast<sal_uInt16>((pCurrPge->GetPageNum()-1)>>1) + 1));
+ sValue.append(";total-pages:");
+ sValue.append(static_cast<sal_Int32>(pDoc->GetSdPageCount(PageKind::Standard)));
+ sValue.append(";");
+ }
+ }
+ if (sValue.getLength())
+ anyAttribute <<= sValue.makeStringAndClear();
+ return anyAttribute;
+}
+
+sal_Int32 SAL_CALL AccessibleDocumentViewBase::getForeground( )
+{
+ return sal_Int32(COL_BLACK);
+}
+
+sal_Int32 SAL_CALL AccessibleDocumentViewBase::getBackground( )
+{
+ ThrowIfDisposed ();
+ ::osl::MutexGuard aGuard (m_aMutex);
+ return sal_Int32(mpViewShell->GetView()->getColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor);
+}
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessibleDrawDocumentView.cxx b/sd/source/ui/accessibility/AccessibleDrawDocumentView.cxx
new file mode 100644
index 000000000..f6111962a
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessibleDrawDocumentView.cxx
@@ -0,0 +1,777 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleDrawDocumentView.hxx>
+#include <com/sun/star/drawing/ShapeCollection.hpp>
+#include <com/sun/star/drawing/XDrawView.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+
+#include <svx/AccessibleShape.hxx>
+#include <svx/ChildrenManager.hxx>
+#include <svx/svdobj.hxx>
+#include <vcl/svapp.hxx>
+
+#include <ViewShell.hxx>
+#include <View.hxx>
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <algorithm>
+#include <slideshow.hxx>
+#include <anminfo.hxx>
+#include <AccessiblePageShape.hxx>
+
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <osl/mutex.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+
+namespace accessibility {
+
+namespace {
+
+struct XShapePosCompareHelper
+{
+ bool operator() ( const uno::Reference<drawing::XShape>& xshape1,
+ const uno::Reference<drawing::XShape>& xshape2 ) const
+ {
+ // modify the compare method to return the Z-Order, not layout order
+ SdrObject* pObj1 = SdrObject::getSdrObjectFromXShape(xshape1);
+ SdrObject* pObj2 = SdrObject::getSdrObjectFromXShape(xshape2);
+ if(pObj1 && pObj2)
+ return pObj1->GetOrdNum() < pObj2->GetOrdNum();
+ else
+ return false;
+ }
+};
+
+}
+
+//===== internal ============================================================
+
+AccessibleDrawDocumentView::AccessibleDrawDocumentView (
+ ::sd::Window* pSdWindow,
+ ::sd::ViewShell* pViewShell,
+ const uno::Reference<frame::XController>& rxController,
+ const uno::Reference<XAccessible>& rxParent)
+ : AccessibleDocumentViewBase (pSdWindow, pViewShell, rxController, rxParent),
+ mpSdViewSh( pViewShell )
+{
+ UpdateAccessibleName();
+}
+
+AccessibleDrawDocumentView::~AccessibleDrawDocumentView()
+{
+ DBG_ASSERT (rBHelper.bDisposed || rBHelper.bInDispose,
+ "~AccessibleDrawDocumentView: object has not been disposed");
+}
+
+void AccessibleDrawDocumentView::Init()
+{
+ AccessibleDocumentViewBase::Init ();
+
+ // Determine the list of shapes on the current page.
+ uno::Reference<drawing::XShapes> xShapeList;
+ uno::Reference<drawing::XDrawView> xView (mxController, uno::UNO_QUERY);
+ if (xView.is())
+ xShapeList = xView->getCurrentPage();
+
+ // Create the children manager.
+ mpChildrenManager.reset(new ChildrenManager(this, xShapeList, maShapeTreeInfo, *this));
+
+ rtl::Reference<AccessiblePageShape> xPage(CreateDrawPageShape());
+ if (xPage.is())
+ {
+ xPage->Init();
+ mpChildrenManager->AddAccessibleShape (xPage);
+ mpChildrenManager->Update ();
+ }
+
+ mpChildrenManager->UpdateSelection ();
+}
+
+void AccessibleDrawDocumentView::ViewForwarderChanged()
+{
+ AccessibleDocumentViewBase::ViewForwarderChanged();
+ if (mpChildrenManager != nullptr)
+ mpChildrenManager->ViewForwarderChanged();
+}
+
+/** The page shape is created on every call at the moment (provided that
+ everything goes well).
+*/
+rtl::Reference<AccessiblePageShape> AccessibleDrawDocumentView::CreateDrawPageShape()
+{
+ rtl::Reference<AccessiblePageShape> xShape;
+
+ // Create a shape that represents the actual draw page.
+ uno::Reference<drawing::XDrawView> xView (mxController, uno::UNO_QUERY);
+ if (xView.is())
+ {
+ uno::Reference<beans::XPropertySet> xSet (
+ uno::Reference<beans::XPropertySet> (xView->getCurrentPage(), uno::UNO_QUERY));
+ if (xSet.is())
+ {
+ // Create a rectangle shape that will represent the draw page.
+ uno::Reference<lang::XMultiServiceFactory> xFactory (mxModel, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xRectangle;
+ if (xFactory.is())
+ xRectangle.set(xFactory->createInstance ("com.sun.star.drawing.RectangleShape"),
+ uno::UNO_QUERY);
+
+ // Set the shape's size and position.
+ if (xRectangle.is())
+ {
+ uno::Any aValue;
+ awt::Point aPosition;
+ awt::Size aSize;
+
+ // Set size and position of the shape to those of the draw
+ // page.
+ aValue = xSet->getPropertyValue ("BorderLeft");
+ aValue >>= aPosition.X;
+ aValue = xSet->getPropertyValue ("BorderTop");
+ aValue >>= aPosition.Y;
+ xRectangle->setPosition (aPosition);
+
+ aValue = xSet->getPropertyValue ("Width");
+ aValue >>= aSize.Width;
+ aValue = xSet->getPropertyValue ("Height");
+ aValue >>= aSize.Height;
+ xRectangle->setSize (aSize);
+
+ // Create the accessible object for the shape and
+ // initialize it.
+ xShape = new AccessiblePageShape (
+ xView->getCurrentPage(), this, maShapeTreeInfo);
+ }
+ }
+ }
+ return xShape;
+}
+
+//===== XAccessibleContext ==================================================
+
+sal_Int32 SAL_CALL
+ AccessibleDrawDocumentView::getAccessibleChildCount()
+{
+ ThrowIfDisposed ();
+
+ tools::Long nChildCount = AccessibleDocumentViewBase::getAccessibleChildCount();
+
+ // Forward request to children manager.
+ if (mpChildrenManager != nullptr)
+ nChildCount += mpChildrenManager->GetChildCount();
+
+ return nChildCount;
+}
+
+uno::Reference<XAccessible> SAL_CALL
+ AccessibleDrawDocumentView::getAccessibleChild (sal_Int32 nIndex)
+{
+ ThrowIfDisposed ();
+
+ ::osl::ClearableMutexGuard aGuard (m_aMutex);
+
+ // Take care of children of the base class.
+ sal_Int32 nCount = AccessibleDocumentViewBase::getAccessibleChildCount();
+ if (nCount > 0)
+ {
+ if (nIndex < nCount)
+ return AccessibleDocumentViewBase::getAccessibleChild(nIndex);
+ else
+ nIndex -= nCount;
+ }
+
+ // Create a copy of the pointer to the children manager and release the
+ // mutex before calling any of its methods.
+ ChildrenManager* pChildrenManager = mpChildrenManager.get();
+ aGuard.clear();
+
+ // Forward request to children manager.
+ if (pChildrenManager == nullptr)
+ throw lang::IndexOutOfBoundsException (
+ "no accessible child with index " + OUString::number(nIndex),
+ static_cast<uno::XWeak*>(this));
+
+ return pChildrenManager->GetChild (nIndex);
+}
+
+OUString SAL_CALL
+ AccessibleDrawDocumentView::getAccessibleName()
+{
+ SolarMutexGuard g;
+
+ OUString sName = SdResId(SID_SD_A11Y_D_PRESENTATION);
+ ::sd::View* pSdView = static_cast< ::sd::View* >( maShapeTreeInfo.GetSdrView() );
+ if ( pSdView )
+ {
+ SdDrawDocument& rDoc = pSdView->GetDoc();
+ OUString sFileName = rDoc.getDocAccTitle();
+ if ( !sFileName.getLength() )
+ {
+ ::sd::DrawDocShell* pDocSh = pSdView->GetDocSh();
+ if ( pDocSh )
+ {
+ sFileName = pDocSh->GetTitle( SFX_TITLE_APINAME );
+ }
+ }
+
+ OUString sReadOnly;
+ if(rDoc.getDocReadOnly())
+ {
+ sReadOnly = SdResId(SID_SD_A11Y_D_PRESENTATION_READONLY);
+ }
+
+ if ( sFileName.getLength() )
+ {
+ sName = sFileName + sReadOnly + " - " + sName;
+ }
+ }
+
+ return sName;
+}
+
+//===== XEventListener ======================================================
+
+void SAL_CALL
+ AccessibleDrawDocumentView::disposing (const lang::EventObject& rEventObject)
+{
+ ThrowIfDisposed ();
+
+ AccessibleDocumentViewBase::disposing (rEventObject);
+ if (rEventObject.Source == mxModel)
+ {
+ ::osl::Guard< ::osl::Mutex> aGuard (::osl::Mutex::getGlobalMutex());
+ // maShapeTreeInfo has been modified in base class.
+ if (mpChildrenManager != nullptr)
+ mpChildrenManager->SetInfo (maShapeTreeInfo);
+ }
+}
+
+//===== XPropertyChangeListener =============================================
+
+void SAL_CALL
+ AccessibleDrawDocumentView::propertyChange (const beans::PropertyChangeEvent& rEventObject)
+{
+ ThrowIfDisposed ();
+
+ AccessibleDocumentViewBase::propertyChange (rEventObject);
+
+ // add page switch event for slide show mode
+ if (rEventObject.PropertyName == "CurrentPage" ||
+ rEventObject.PropertyName == "PageChange")
+ {
+ // Update the accessible name to reflect the current slide.
+ UpdateAccessibleName();
+
+ // The current page changed. Update the children manager accordingly.
+ uno::Reference<drawing::XDrawView> xView (mxController, uno::UNO_QUERY);
+ if (xView.is() && mpChildrenManager!=nullptr)
+ {
+ // Inform the children manager to forget all children and give
+ // him the new ones.
+ mpChildrenManager->ClearAccessibleShapeList ();
+ mpChildrenManager->SetShapeList (xView->getCurrentPage());
+
+ rtl::Reference<AccessiblePageShape> xPage(CreateDrawPageShape ());
+ if (xPage.is())
+ {
+ xPage->Init();
+ mpChildrenManager->AddAccessibleShape (xPage);
+ mpChildrenManager->Update (false);
+ }
+ }
+ else
+ SAL_WARN("sd", "View invalid");
+ CommitChange(AccessibleEventId::PAGE_CHANGED,rEventObject.NewValue,rEventObject.OldValue);
+ }
+ else if ( rEventObject.PropertyName == "VisibleArea" )
+ {
+ if (mpChildrenManager != nullptr)
+ mpChildrenManager->ViewForwarderChanged();
+ }
+ else if (rEventObject.PropertyName == "ActiveLayer")
+ {
+ CommitChange(AccessibleEventId::PAGE_CHANGED,rEventObject.NewValue,rEventObject.OldValue);
+ }
+ else if (rEventObject.PropertyName == "UpdateAcc")
+ {
+ // The current page changed. Update the children manager accordingly.
+ uno::Reference<drawing::XDrawView> xView (mxController, uno::UNO_QUERY);
+ if (xView.is() && mpChildrenManager!=nullptr)
+ {
+ // Inform the children manager to forget all children and give
+ // him the new ones.
+ mpChildrenManager->ClearAccessibleShapeList ();
+ // update the slide show page's accessible info
+ //mpChildrenManager->SetShapeList (uno::Reference<drawing::XShapes> (
+ // xView->getCurrentPage(), uno::UNO_QUERY));
+ rtl::Reference< sd::SlideShow > xSlideshow( sd::SlideShow::GetSlideShow( mpSdViewSh->GetViewShellBase() ) );
+ if( xSlideshow.is() && xSlideshow->isRunning() && xSlideshow->isFullScreen() )
+ {
+ css::uno::Reference< drawing::XDrawPage > xSlide;
+ // MT IA2: Not used...
+ // sal_Int32 currentPageIndex = xSlideshow->getCurrentPageIndex();
+ css::uno::Reference< css::presentation::XSlideShowController > xSlideController = xSlideshow->getController();
+ if( xSlideController.is() )
+ {
+ xSlide = xSlideController->getCurrentSlide();
+ if (xSlide.is())
+ {
+ mpChildrenManager->SetShapeList (xSlide);
+ }
+ }
+ }
+ rtl::Reference<AccessiblePageShape> xPage(CreateDrawPageShape ());
+ if (xPage.is())
+ {
+ xPage->Init();
+ mpChildrenManager->AddAccessibleShape (xPage);
+ mpChildrenManager->Update (false);
+ }
+ }
+ }
+ else
+ {
+ SAL_INFO("sd", "unhandled");
+ }
+}
+
+// XServiceInfo
+
+OUString SAL_CALL
+ AccessibleDrawDocumentView::getImplementationName()
+{
+ return "AccessibleDrawDocumentView";
+}
+
+css::uno::Sequence< OUString> SAL_CALL
+ AccessibleDrawDocumentView::getSupportedServiceNames()
+{
+ ThrowIfDisposed();
+ const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleDrawDocumentView" };
+ uno::Sequence<OUString> aServiceNames =
+ AccessibleDocumentViewBase::getSupportedServiceNames();
+
+ return comphelper::concatSequences(aServiceNames, vals);
+}
+
+//===== XInterface ==========================================================
+
+uno::Any SAL_CALL
+ AccessibleDrawDocumentView::queryInterface (const uno::Type & rType)
+{
+ uno::Any aReturn = AccessibleDocumentViewBase::queryInterface (rType);
+ if ( ! aReturn.hasValue())
+ aReturn = ::cppu::queryInterface (rType,
+ static_cast<XAccessibleGroupPosition*>(this)
+ );
+ return aReturn;
+}
+
+void SAL_CALL
+ AccessibleDrawDocumentView::acquire()
+ noexcept
+{
+ AccessibleDocumentViewBase::acquire ();
+}
+void SAL_CALL
+ AccessibleDrawDocumentView::release()
+ noexcept
+{
+ AccessibleDocumentViewBase::release ();
+}
+//===== XAccessibleGroupPosition =========================================
+uno::Sequence< sal_Int32 > SAL_CALL
+ AccessibleDrawDocumentView::getGroupPosition( const uno::Any& rAny )
+{
+ SolarMutexGuard g;
+
+ // we will return the:
+ // [0] group level(always be 0 now)
+ // [1] similar items counts in the group
+ // [2] the position of the object in the group
+ uno::Sequence< sal_Int32 > aRet( 3 );
+ //get the xShape of the current selected drawing object
+ uno::Reference<XAccessibleContext> xAccContent;
+ rAny >>= xAccContent;
+ if ( !xAccContent.is() )
+ {
+ return aRet;
+ }
+ AccessibleShape* pAcc = comphelper::getFromUnoTunnel<AccessibleShape>( xAccContent );
+ if ( !pAcc )
+ {
+ return aRet;
+ }
+ uno::Reference< drawing::XShape > xCurShape = pAcc->GetXShape();
+ if ( !xCurShape.is() )
+ {
+ return aRet;
+ }
+ //find all the child in the page, insert them into a vector and sort
+ if ( mpChildrenManager == nullptr )
+ {
+ return aRet;
+ }
+ std::vector< uno::Reference<drawing::XShape> > vXShapes;
+ sal_Int32 nCount = mpChildrenManager->GetChildCount();
+ //get pointer of SdView & SdrPageView for further use.
+ SdrPageView* pPV = nullptr;
+ ::sd::View* pSdView = nullptr;
+ if ( mpSdViewSh )
+ {
+ pSdView = mpSdViewSh->GetView();
+ pPV = pSdView->GetSdrPageView();
+ }
+ for ( sal_Int32 i = 0; i < nCount; i++ )
+ {
+ uno::Reference< drawing::XShape > xShape = mpChildrenManager->GetChildShape(i);
+ if ( xShape.is() )
+ {
+ //if the object is visible in the page, we add it into the group list.
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
+ if ( pObj && pPV && pSdView && pSdView->IsObjMarkable( pObj, pPV ) )
+ {
+ vXShapes.push_back( xShape );
+ }
+ }
+ }
+ std::sort( vXShapes.begin(), vXShapes.end(), XShapePosCompareHelper() );
+ //get the index of the selected object in the group
+ auto aIter = std::find_if(vXShapes.begin(), vXShapes.end(),
+ [&xCurShape](const uno::Reference<drawing::XShape>& rxShape) { return rxShape.get() == xCurShape.get(); });
+ if (aIter != vXShapes.end())
+ {
+ sal_Int32* pArray = aRet.getArray();
+ pArray[0] = 1; //it should be 1 based, not 0 based.
+ pArray[1] = vXShapes.size();
+ pArray[2] = static_cast<sal_Int32>(std::distance(vXShapes.begin(), aIter)) + 1; //we start counting position from 1
+ }
+ return aRet;
+}
+
+OUString AccessibleDrawDocumentView::getObjectLink( const uno::Any& rAny )
+{
+ SolarMutexGuard g;
+
+ OUString aRet;
+ //get the xShape of the current selected drawing object
+ uno::Reference<XAccessibleContext> xAccContent;
+ rAny >>= xAccContent;
+ if ( !xAccContent.is() )
+ {
+ return aRet;
+ }
+ AccessibleShape* pAcc = comphelper::getFromUnoTunnel<AccessibleShape>( xAccContent );
+ if ( !pAcc )
+ {
+ return aRet;
+ }
+ uno::Reference< drawing::XShape > xCurShape = pAcc->GetXShape();
+ if ( !xCurShape.is() )
+ {
+ return aRet;
+ }
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xCurShape);
+ if (pObj)
+ {
+ SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pObj);
+ if( pInfo && (pInfo->meClickAction == presentation::ClickAction_DOCUMENT) )
+ aRet = pInfo->GetBookmark();
+ }
+ return aRet;
+}
+
+/// Create a name for this view.
+OUString AccessibleDrawDocumentView::CreateAccessibleName()
+{
+ OUString sName;
+
+ uno::Reference<lang::XServiceInfo> xInfo (mxController, uno::UNO_QUERY);
+ if (xInfo.is())
+ {
+ uno::Sequence< OUString > aServices( xInfo->getSupportedServiceNames() );
+ OUString sFirstService = aServices[0];
+ if ( sFirstService == "com.sun.star.drawing.DrawingDocumentDrawView" )
+ {
+ if( aServices.getLength() >= 2 && aServices[1] == "com.sun.star.presentation.PresentationView")
+ {
+ SolarMutexGuard aGuard;
+
+ sName = SdResId(SID_SD_A11Y_I_DRAWVIEW_N);
+ }
+ else
+ {
+ SolarMutexGuard aGuard;
+
+ sName = SdResId(SID_SD_A11Y_D_DRAWVIEW_N);
+ }
+ }
+ else if ( sFirstService == "com.sun.star.presentation.NotesView" )
+ {
+ SolarMutexGuard aGuard;
+
+ sName = SdResId(SID_SD_A11Y_I_NOTESVIEW_N);
+ }
+ else if ( sFirstService == "com.sun.star.presentation.HandoutView" )
+ {
+ SolarMutexGuard aGuard;
+
+ sName = SdResId(SID_SD_A11Y_I_HANDOUTVIEW_N);
+ }
+ else
+ {
+ sName = sFirstService;
+ }
+ }
+ else
+ {
+ sName = "AccessibleDrawDocumentView";
+ }
+ return sName;
+}
+
+/** Return selection state of specified child
+*/
+bool
+ AccessibleDrawDocumentView::implIsSelected( sal_Int32 nAccessibleChildIndex )
+{
+ const SolarMutexGuard aSolarGuard;
+ uno::Reference< view::XSelectionSupplier > xSel( mxController, uno::UNO_QUERY );
+ bool bRet = false;
+
+ OSL_ENSURE( 0 <= nAccessibleChildIndex, "AccessibleDrawDocumentView::implIsSelected: invalid index!" );
+
+ if( xSel.is() && ( 0 <= nAccessibleChildIndex ) )
+ {
+ uno::Any aAny( xSel->getSelection() );
+ uno::Reference< drawing::XShapes > xShapes;
+
+ aAny >>= xShapes;
+
+ if( xShapes.is() )
+ {
+ AccessibleShape* pAcc = comphelper::getFromUnoTunnel<AccessibleShape>( getAccessibleChild( nAccessibleChildIndex ) );
+
+ if( pAcc )
+ {
+ uno::Reference< drawing::XShape > xShape( pAcc->GetXShape() );
+
+ if( xShape.is() )
+ {
+ for( sal_Int32 i = 0, nCount = xShapes->getCount(); ( i < nCount ) && !bRet; ++i )
+ if( xShapes->getByIndex( i ) == xShape )
+ bRet = true;
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+/** Select or deselect the specified shapes. The corresponding accessible
+ shapes are notified over the selection change listeners registered with
+ the XSelectionSupplier of the controller.
+*/
+void
+ AccessibleDrawDocumentView::implSelect( sal_Int32 nAccessibleChildIndex, bool bSelect )
+{
+ const SolarMutexGuard aSolarGuard;
+ uno::Reference< view::XSelectionSupplier > xSel( mxController, uno::UNO_QUERY );
+
+ if( !xSel.is() )
+ return;
+
+ uno::Any aAny;
+
+ if( ACCESSIBLE_SELECTION_CHILD_ALL == nAccessibleChildIndex )
+ {
+ // Select or deselect all children.
+
+ if( !bSelect )
+ xSel->select( aAny );
+ else
+ {
+ uno::Reference< drawing::XShapes > xShapes = drawing::ShapeCollection::create(
+ comphelper::getProcessComponentContext());
+
+ for(sal_Int32 i = 0, nCount = getAccessibleChildCount(); i < nCount; ++i )
+ {
+ AccessibleShape* pAcc = comphelper::getFromUnoTunnel<AccessibleShape>( getAccessibleChild( i ) );
+
+ if( pAcc && pAcc->GetXShape().is() )
+ xShapes->add( pAcc->GetXShape() );
+ }
+
+ if( xShapes->getCount() )
+ {
+ xSel->select( Any(xShapes) );
+ }
+ }
+ }
+ else if( nAccessibleChildIndex >= 0 )
+ {
+ // Select or deselect only the child with index
+ // nAccessibleChildIndex.
+
+ AccessibleShape* pAcc = comphelper::getFromUnoTunnel<AccessibleShape>(
+ getAccessibleChild( nAccessibleChildIndex ));
+
+ // Add or remove the shape that is made accessible from the
+ // selection of the controller.
+ if( pAcc )
+ {
+ uno::Reference< drawing::XShape > xShape( pAcc->GetXShape() );
+
+ if( xShape.is() )
+ {
+ uno::Reference< drawing::XShapes > xShapes;
+ bool bFound = false;
+
+ aAny = xSel->getSelection();
+ aAny >>= xShapes;
+
+ // Search shape to be selected in current selection.
+ if (xShapes.is())
+ {
+ sal_Int32 nCount = xShapes->getCount();
+ for (sal_Int32 i=0; ( i < nCount ) && !bFound; ++i )
+ if( xShapes->getByIndex( i ) == xShape )
+ bFound = true;
+ }
+ else
+ // Create an empty selection to add the shape to.
+ xShapes = drawing::ShapeCollection::create(
+ comphelper::getProcessComponentContext());
+
+ // Update the selection.
+ if( !bFound && bSelect )
+ xShapes->add( xShape );
+ else if( bFound && !bSelect )
+ xShapes->remove( xShape );
+
+ xSel->select( Any(xShapes) );
+ }
+ }
+ }
+}
+
+void AccessibleDrawDocumentView::Activated()
+{
+ if (mpChildrenManager == nullptr)
+ return;
+
+ bool bChange = false;
+ // When none of the children has the focus then claim it for the
+ // view.
+ if ( ! mpChildrenManager->HasFocus())
+ {
+ SetState (AccessibleStateType::FOCUSED);
+ bChange = true;
+ }
+ else
+ ResetState (AccessibleStateType::FOCUSED);
+ mpChildrenManager->UpdateSelection();
+ // if the child gets focus in UpdateSelection(), needs to reset the focus on document.
+ if (mpChildrenManager->HasFocus() && bChange)
+ ResetState (AccessibleStateType::FOCUSED);
+}
+
+void AccessibleDrawDocumentView::Deactivated()
+{
+ if (mpChildrenManager != nullptr)
+ mpChildrenManager->RemoveFocus();
+ ResetState (AccessibleStateType::FOCUSED);
+}
+
+void AccessibleDrawDocumentView::impl_dispose()
+{
+ mpChildrenManager.reset();
+ AccessibleDocumentViewBase::impl_dispose();
+}
+
+/** This method is called from the component helper base class while
+ disposing.
+*/
+void SAL_CALL AccessibleDrawDocumentView::disposing()
+{
+ // Release resources.
+ mpChildrenManager.reset();
+
+ // Forward call to base classes.
+ AccessibleDocumentViewBase::disposing ();
+}
+
+void AccessibleDrawDocumentView::UpdateAccessibleName()
+{
+ OUString sNewName (CreateAccessibleName() + ": ");
+
+ // Add the number of the current slide.
+ uno::Reference<drawing::XDrawView> xView (mxController, uno::UNO_QUERY);
+ if (xView.is())
+ {
+ uno::Reference<beans::XPropertySet> xProperties (xView->getCurrentPage(), UNO_QUERY);
+ if (xProperties.is())
+ try
+ {
+ sal_Int16 nPageNumber (0);
+ if (xProperties->getPropertyValue("Number") >>= nPageNumber)
+ {
+ sNewName += OUString::number(nPageNumber);
+ }
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ }
+ }
+
+ // Add the number of pages/slides.
+ Reference<drawing::XDrawPagesSupplier> xPagesSupplier (mxModel, UNO_QUERY);
+ if (xPagesSupplier.is())
+ {
+ Reference<container::XIndexAccess> xPages = xPagesSupplier->getDrawPages();
+ if (xPages.is())
+ {
+ sNewName += " / " + OUString::number(xPages->getCount());
+ }
+ }
+
+ SetAccessibleName (sNewName, AutomaticallyCreated);
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessibleOutlineEditSource.cxx b/sd/source/ui/accessibility/AccessibleOutlineEditSource.cxx
new file mode 100644
index 000000000..a1a79a678
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessibleOutlineEditSource.cxx
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <editeng/unoedhlp.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdview.hxx>
+#include <vcl/window.hxx>
+#include <AccessibleOutlineEditSource.hxx>
+
+namespace accessibility
+{
+
+ AccessibleOutlineEditSource::AccessibleOutlineEditSource(
+ SdrOutliner& rOutliner,
+ SdrView& rView,
+ OutlinerView& rOutlView,
+ const vcl::Window& rViewWindow )
+ : mrView( rView ),
+ mrWindow( rViewWindow ),
+ mpOutliner( &rOutliner ),
+ mpOutlinerView( &rOutlView ),
+ mTextForwarder( rOutliner, false ),
+ mViewForwarder( rOutlView )
+ {
+ // register as listener - need to broadcast state change messages
+ // Moved to ::GetTextForwarder()
+ //rOutliner.SetNotifyHdl( LINK(this, AccessibleOutlineEditSource, NotifyHdl) );
+ StartListening(rOutliner);
+ }
+
+ AccessibleOutlineEditSource::~AccessibleOutlineEditSource()
+ {
+ if( mpOutliner )
+ mpOutliner->SetNotifyHdl( Link<EENotify&,void>() );
+ Broadcast( TextHint( SfxHintId::Dying ) );
+ }
+
+ std::unique_ptr<SvxEditSource> AccessibleOutlineEditSource::Clone() const
+ {
+ return std::unique_ptr<SvxEditSource>(new AccessibleOutlineEditSource(*mpOutliner, mrView, *mpOutlinerView, mrWindow));
+ }
+
+ SvxTextForwarder* AccessibleOutlineEditSource::GetTextForwarder()
+ {
+ // TODO: maybe suboptimal
+ if( IsValid() )
+ {
+ // Moved here to make sure that
+ // the NotifyHandler was set on the current object.
+ mpOutliner->SetNotifyHdl( LINK(this, AccessibleOutlineEditSource, NotifyHdl) );
+ return &mTextForwarder;
+ }
+ else
+ return nullptr;
+ }
+
+ SvxViewForwarder* AccessibleOutlineEditSource::GetViewForwarder()
+ {
+ // TODO: maybe suboptimal
+ if( IsValid() )
+ return this;
+ else
+ return nullptr;
+ }
+
+ SvxEditViewForwarder* AccessibleOutlineEditSource::GetEditViewForwarder( bool )
+ {
+ // TODO: maybe suboptimal
+ if( IsValid() )
+ {
+ // ignore parameter, we're always in edit mode here
+ return &mViewForwarder;
+ }
+ else
+ return nullptr;
+ }
+
+ void AccessibleOutlineEditSource::UpdateData()
+ {
+ // NOOP, since we're always working on the 'real' outliner,
+ // i.e. changes are immediately reflected on the screen
+ }
+
+ SfxBroadcaster& AccessibleOutlineEditSource::GetBroadcaster() const
+ {
+ return * const_cast< AccessibleOutlineEditSource* > (this);
+ }
+
+ bool AccessibleOutlineEditSource::IsValid() const
+ {
+ if( mpOutliner && mpOutlinerView )
+ {
+ // Our view still on outliner?
+ sal_uLong nCurrView, nViews;
+
+ for( nCurrView=0, nViews=mpOutliner->GetViewCount(); nCurrView<nViews; ++nCurrView )
+ {
+ if( mpOutliner->GetView(nCurrView) == mpOutlinerView )
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ Point AccessibleOutlineEditSource::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
+ {
+ if( IsValid() && mrView.GetModel() )
+ {
+ Point aPoint( OutputDevice::LogicToLogic( rPoint, rMapMode,
+ MapMode(mrView.GetModel()->GetScaleUnit()) ) );
+ MapMode aMapMode(mrWindow.GetMapMode());
+ aMapMode.SetOrigin(Point());
+ return mrWindow.LogicToPixel( aPoint, aMapMode );
+ }
+
+ return Point();
+ }
+
+ Point AccessibleOutlineEditSource::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
+ {
+ if( IsValid() && mrView.GetModel() )
+ {
+ MapMode aMapMode(mrWindow.GetMapMode());
+ aMapMode.SetOrigin(Point());
+ Point aPoint( mrWindow.PixelToLogic( rPoint, aMapMode ) );
+ return OutputDevice::LogicToLogic( aPoint,
+ MapMode(mrView.GetModel()->GetScaleUnit()),
+ rMapMode );
+ }
+
+ return Point();
+ }
+
+ void AccessibleOutlineEditSource::Notify( SfxBroadcaster& rBroadcaster, const SfxHint& rHint )
+ {
+ bool bDispose = false;
+
+ if( &rBroadcaster == mpOutliner )
+ {
+ if( rHint.GetId() == SfxHintId::Dying )
+ {
+ bDispose = true;
+ mpOutliner = nullptr;
+ }
+ }
+ else
+ {
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast< const SdrHint* >( &rHint );
+ if( pSdrHint->GetKind() == SdrHintKind::ModelCleared )
+ {
+ // model is dying under us, going defunc
+ bDispose = true;
+ }
+ }
+ }
+
+ if( bDispose )
+ {
+ if( mpOutliner )
+ mpOutliner->SetNotifyHdl( Link<EENotify&,void>() );
+ mpOutliner = nullptr;
+ mpOutlinerView = nullptr;
+ Broadcast( TextHint( SfxHintId::Dying ) );
+ }
+ }
+
+ IMPL_LINK(AccessibleOutlineEditSource, NotifyHdl, EENotify&, rNotify, void)
+ {
+ ::std::unique_ptr< SfxHint > aHint( SvxEditSourceHelper::EENotification2Hint( &rNotify) );
+
+ if (aHint)
+ {
+ Broadcast(*aHint);
+ }
+ }
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessibleOutlineView.cxx b/sd/source/ui/accessibility/AccessibleOutlineView.cxx
new file mode 100644
index 000000000..4e020efef
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessibleOutlineView.cxx
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+#include <Window.hxx>
+#include <OutlineViewShell.hxx>
+#include <DrawDocShell.hxx>
+#include <OutlineView.hxx>
+#include <View.hxx>
+#include <AccessibleOutlineView.hxx>
+#include <AccessibleOutlineEditSource.hxx>
+#include <drawdoc.hxx>
+#include <strings.hrc>
+#include <sdresid.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+namespace accessibility {
+
+//===== internal ============================================================
+
+AccessibleOutlineView::AccessibleOutlineView (
+ ::sd::Window* pSdWindow,
+ ::sd::OutlineViewShell* pViewShell,
+ const uno::Reference<frame::XController>& rxController,
+ const uno::Reference<XAccessible>& rxParent)
+ : AccessibleDocumentViewBase (pSdWindow, pViewShell, rxController, rxParent),
+ maTextHelper( ::std::unique_ptr< SvxEditSource >() )
+{
+ SolarMutexGuard aGuard;
+
+ // 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.
+ if (!pSdWindow)
+ return;
+
+ ::sd::View* pView = pViewShell->GetView();
+
+ auto pShellView = dynamic_cast<::sd::OutlineView* >( pView );
+ if(!pShellView)
+ return;
+
+ OutlinerView* pOutlineView = pShellView->GetViewByWindow( pSdWindow );
+ SdrOutliner& rOutliner = pShellView->GetOutliner();
+
+ if( pOutlineView )
+ {
+ maTextHelper.SetEditSource( ::std::unique_ptr< SvxEditSource >( new AccessibleOutlineEditSource(
+ rOutliner, *pView, *pOutlineView, *pSdWindow ) ) );
+ }
+}
+
+AccessibleOutlineView::~AccessibleOutlineView()
+{
+}
+
+void AccessibleOutlineView::Init()
+{
+ // Set event source _before_ starting to listen
+ maTextHelper.SetEventSource(this);
+
+ AccessibleDocumentViewBase::Init ();
+}
+
+void AccessibleOutlineView::ViewForwarderChanged()
+{
+ AccessibleDocumentViewBase::ViewForwarderChanged();
+
+ UpdateChildren();
+}
+
+//===== XAccessibleContext ==================================================
+
+sal_Int32 SAL_CALL
+ AccessibleOutlineView::getAccessibleChildCount()
+{
+ ThrowIfDisposed ();
+
+ // forward
+ return maTextHelper.GetChildCount();
+}
+
+uno::Reference<XAccessible> SAL_CALL
+ AccessibleOutlineView::getAccessibleChild (sal_Int32 nIndex)
+{
+ ThrowIfDisposed ();
+ // Forward request to children manager.
+ return maTextHelper.GetChild(nIndex);
+}
+
+OUString SAL_CALL
+ AccessibleOutlineView::getAccessibleName()
+{
+ SolarMutexGuard g;
+
+ OUString sName = SdResId(SID_SD_A11Y_D_PRESENTATION);
+ ::sd::View* pSdView = static_cast< ::sd::View* >( maShapeTreeInfo.GetSdrView() );
+ if ( pSdView )
+ {
+ SdDrawDocument& rDoc = pSdView->GetDoc();
+ OUString sFileName = rDoc.getDocAccTitle();
+ if (sFileName.isEmpty())
+ {
+ ::sd::DrawDocShell* pDocSh = pSdView->GetDocSh();
+ if ( pDocSh )
+ {
+ sFileName = pDocSh->GetTitle( SFX_TITLE_APINAME );
+ }
+ }
+ if (!sFileName.isEmpty())
+ {
+ sName = sFileName + " - " + sName;
+ }
+ }
+ return sName;
+}
+
+//===== XAccessibleEventBroadcaster ========================================
+
+void SAL_CALL AccessibleOutlineView::addAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
+{
+ // delegate listener handling to children manager.
+ if ( ! IsDisposed())
+ maTextHelper.AddEventListener(xListener);
+ AccessibleContextBase::addEventListener(xListener);
+}
+
+void SAL_CALL AccessibleOutlineView::removeAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
+{
+ // forward
+ if ( ! IsDisposed())
+ maTextHelper.RemoveEventListener(xListener);
+ AccessibleContextBase::removeEventListener(xListener);
+}
+
+// XServiceInfo
+
+OUString SAL_CALL
+ AccessibleOutlineView::getImplementationName()
+{
+ return "AccessibleOutlineView";
+}
+
+//===== XEventListener ======================================================
+
+//===== protected internal ==================================================
+
+void AccessibleOutlineView::Activated()
+{
+ SolarMutexGuard aGuard;
+
+ // delegate listener handling to children manager.
+ maTextHelper.SetFocus();
+}
+
+void AccessibleOutlineView::Deactivated()
+{
+ SolarMutexGuard aGuard;
+
+ // delegate listener handling to children manager.
+ maTextHelper.SetFocus(false);
+}
+
+void SAL_CALL AccessibleOutlineView::disposing()
+{
+ // dispose children
+ maTextHelper.Dispose();
+
+ AccessibleDocumentViewBase::disposing ();
+}
+
+//===== XPropertyChangeListener =============================================
+
+void SAL_CALL
+ AccessibleOutlineView::propertyChange (const beans::PropertyChangeEvent& rEventObject)
+{
+ ThrowIfDisposed ();
+
+ AccessibleDocumentViewBase::propertyChange (rEventObject);
+
+ //add page switch event for slide show mode
+ if (rEventObject.PropertyName == "CurrentPage" ||
+ rEventObject.PropertyName == "PageChange")
+ {
+ // The current page changed. Update the children accordingly.
+ UpdateChildren();
+ CommitChange(AccessibleEventId::PAGE_CHANGED,rEventObject.NewValue, rEventObject.OldValue);
+ }
+ else if ( rEventObject.PropertyName == "VisibleArea" )
+ {
+ // The visible area changed. Update the children accordingly.
+ UpdateChildren();
+ }
+ else
+ {
+ SAL_INFO("sd", "unhandled");
+ }
+}
+
+/// Create a name for this view.
+OUString AccessibleOutlineView::CreateAccessibleName()
+{
+ return SdResId(SID_SD_A11Y_I_OUTLINEVIEW_N);
+}
+
+void AccessibleOutlineView::UpdateChildren()
+{
+ SolarMutexGuard aGuard;
+
+ // Update visible children
+ maTextHelper.UpdateChildren();
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessiblePageShape.cxx b/sd/source/ui/accessibility/AccessiblePageShape.cxx
new file mode 100644
index 000000000..2900019ae
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessiblePageShape.cxx
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessiblePageShape.hxx>
+#include <svx/AccessibleShapeInfo.hxx>
+#include <svx/IAccessibleViewForwarder.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/gen.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XMasterPageTarget.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+using ::com::sun::star::uno::Reference;
+
+namespace accessibility {
+
+//===== internal ============================================================
+
+AccessiblePageShape::AccessiblePageShape (
+ const uno::Reference<drawing::XDrawPage>& rxPage,
+ const uno::Reference<XAccessible>& rxParent,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo)
+ : AccessibleShape (AccessibleShapeInfo (nullptr, rxParent), rShapeTreeInfo),
+ mxPage (rxPage)
+{
+ // The main part of the initialization is done in the init method which
+ // has to be called from this constructor's caller.
+}
+
+AccessiblePageShape::~AccessiblePageShape()
+{
+}
+
+//===== XAccessibleContext ==================================================
+
+sal_Int32 SAL_CALL
+ AccessiblePageShape::getAccessibleChildCount()
+{
+ return 0;
+}
+
+/** Forward the request to the shape. Return the requested shape or throw
+ an exception for a wrong index.
+*/
+uno::Reference<XAccessible> SAL_CALL
+ AccessiblePageShape::getAccessibleChild( sal_Int32 )
+{
+ throw lang::IndexOutOfBoundsException ("page shape has no children",
+ static_cast<uno::XWeak*>(this));
+}
+
+//===== XAccessibleComponent ================================================
+
+awt::Rectangle SAL_CALL AccessiblePageShape::getBounds()
+{
+ ThrowIfDisposed ();
+
+ awt::Rectangle aBoundingBox;
+
+ if (maShapeTreeInfo.GetViewForwarder() != nullptr)
+ {
+ uno::Reference<beans::XPropertySet> xSet (mxPage, uno::UNO_QUERY);
+ if (xSet.is())
+ {
+ uno::Any aValue;
+
+ aValue = xSet->getPropertyValue ("BorderLeft");
+ aValue >>= aBoundingBox.X;
+ aValue = xSet->getPropertyValue ("BorderTop");
+ aValue >>= aBoundingBox.Y;
+
+ aValue = xSet->getPropertyValue ("Width");
+ aValue >>= aBoundingBox.Width;
+ aValue = xSet->getPropertyValue ("Height");
+ aValue >>= aBoundingBox.Height;
+ }
+
+ // Transform coordinates from internal to pixel.
+ ::Size aPixelSize = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
+ ::Size (aBoundingBox.Width, aBoundingBox.Height));
+ ::Point aPixelPosition = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
+ ::Point (aBoundingBox.X, aBoundingBox.Y));
+
+ // Clip the shape's bounding box with the bounding box of its parent.
+ Reference<XAccessibleComponent> xParentComponent (
+ getAccessibleParent(), uno::UNO_QUERY);
+ if (xParentComponent.is())
+ {
+ // Make the coordinates relative to the parent.
+ awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
+ int x = aPixelPosition.getX() - aParentLocation.X;
+ int y = aPixelPosition.getY() - aParentLocation.Y;
+
+ // Clip with parent (with coordinates relative to itself).
+ ::tools::Rectangle aBBox (
+ x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
+ awt::Size aParentSize (xParentComponent->getSize());
+ ::tools::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
+ aBBox = aBBox.GetIntersection (aParentBBox);
+ aBoundingBox = awt::Rectangle (
+ aBBox.Left(),
+ aBBox.Top(),
+ aBBox.getWidth(),
+ aBBox.getHeight());
+ }
+ else
+ aBoundingBox = awt::Rectangle (
+ aPixelPosition.getX(), aPixelPosition.getY(),
+ aPixelSize.getWidth(), aPixelSize.getHeight());
+ }
+
+ return aBoundingBox;
+}
+
+sal_Int32 SAL_CALL AccessiblePageShape::getForeground()
+{
+ ThrowIfDisposed ();
+ sal_Int32 nColor (0x0ffffffL);
+
+ try
+ {
+ uno::Reference<beans::XPropertySet> aSet (mxPage, uno::UNO_QUERY);
+ if (aSet.is())
+ {
+ uno::Any aColor = aSet->getPropertyValue ("LineColor");
+ aColor >>= nColor;
+ }
+ }
+ catch (const css::beans::UnknownPropertyException&)
+ {
+ // Ignore exception and return default color.
+ }
+ return nColor;
+}
+
+/** Extract the background color from the Background property of the
+ draw page or its master page.
+*/
+sal_Int32 SAL_CALL AccessiblePageShape::getBackground()
+{
+ ThrowIfDisposed ();
+ sal_Int32 nColor (0x01020ffL);
+
+ try
+ {
+ uno::Reference<beans::XPropertySet> xSet (mxPage, uno::UNO_QUERY);
+ if (xSet.is())
+ {
+ uno::Any aBGSet = xSet->getPropertyValue ("Background");
+ Reference<beans::XPropertySet> xBGSet (aBGSet, uno::UNO_QUERY);
+ if ( ! xBGSet.is())
+ {
+ // Draw page has no Background property. Try the master
+ // page instead.
+ Reference<drawing::XMasterPageTarget> xTarget (mxPage, uno::UNO_QUERY);
+ if (xTarget.is())
+ {
+ xSet.set(xTarget->getMasterPage(), uno::UNO_QUERY);
+ aBGSet = xSet->getPropertyValue ("Background");
+ xBGSet.set(aBGSet, uno::UNO_QUERY);
+ }
+ }
+ // Fetch the fill color. Has to be extended to cope with
+ // gradients, hashes, and bitmaps.
+ if (xBGSet.is())
+ {
+ uno::Any aColor = xBGSet->getPropertyValue ("FillColor");
+ aColor >>= nColor;
+ }
+ else
+ SAL_WARN("sd", "no Background property in page");
+ }
+ }
+ catch (const css::beans::UnknownPropertyException&)
+ {
+ TOOLS_WARN_EXCEPTION("sd", "caught exception due to unknown property");
+ // Ignore exception and return default color.
+ }
+ return nColor;
+}
+
+// XServiceInfo
+
+OUString SAL_CALL
+ AccessiblePageShape::getImplementationName()
+{
+ ThrowIfDisposed ();
+ return "AccessiblePageShape";
+}
+
+css::uno::Sequence< OUString> SAL_CALL
+ AccessiblePageShape::getSupportedServiceNames()
+{
+ ThrowIfDisposed ();
+ return AccessibleShape::getSupportedServiceNames();
+}
+
+//===== XComponent ==========================================================
+
+void AccessiblePageShape::dispose()
+{
+ // Cleanup.
+ mxShape = nullptr;
+
+ // Call base classes.
+ AccessibleContextBase::dispose ();
+}
+
+//===== protected internal ==================================================
+
+OUString
+ AccessiblePageShape::CreateAccessibleBaseName()
+{
+ return "PageShape";
+}
+
+OUString
+ AccessiblePageShape::CreateAccessibleName()
+{
+ Reference<beans::XPropertySet> xPageProperties (mxPage, UNO_QUERY);
+
+ // Get name of the current slide.
+ OUString sCurrentSlideName;
+ try
+ {
+ if (xPageProperties.is())
+ {
+ xPageProperties->getPropertyValue( "LinkDisplayName" ) >>= sCurrentSlideName;
+ }
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ }
+
+ return CreateAccessibleBaseName()+": "+sCurrentSlideName;
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessiblePresentationGraphicShape.cxx b/sd/source/ui/accessibility/AccessiblePresentationGraphicShape.cxx
new file mode 100644
index 000000000..a8c37fa89
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessiblePresentationGraphicShape.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 <AccessiblePresentationGraphicShape.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+
+#include <SdShapeTypes.hxx>
+
+#include <svx/ShapeTypeHandler.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+namespace accessibility
+{
+//===== internal ============================================================
+
+AccessiblePresentationGraphicShape::AccessiblePresentationGraphicShape(
+ const AccessibleShapeInfo& rShapeInfo, const AccessibleShapeTreeInfo& rShapeTreeInfo)
+ : AccessibleGraphicShape(rShapeInfo, rShapeTreeInfo)
+{
+}
+
+AccessiblePresentationGraphicShape::~AccessiblePresentationGraphicShape() {}
+
+// XServiceInfo
+
+OUString SAL_CALL AccessiblePresentationGraphicShape::getImplementationName()
+{
+ return "AccessiblePresentationGraphicShape";
+}
+
+/// Set this object's name if is different to the current name.
+OUString AccessiblePresentationGraphicShape::CreateAccessibleBaseName()
+{
+ OUString sName;
+
+ ShapeTypeId nShapeType = ShapeTypeHandler::Instance().GetTypeId(mxShape);
+ switch (nShapeType)
+ {
+ case PRESENTATION_GRAPHIC_OBJECT:
+ sName = "ImpressGraphicObject";
+ break;
+ default:
+ sName = "UnknownAccessibleImpressShape";
+ if (mxShape.is())
+ sName += ": " + mxShape->getShapeType();
+ }
+
+ return sName;
+}
+
+sal_Int16 SAL_CALL AccessiblePresentationGraphicShape::getAccessibleRole()
+{
+ return AccessibleRole::GRAPHIC;
+}
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessiblePresentationOLEShape.cxx b/sd/source/ui/accessibility/AccessiblePresentationOLEShape.cxx
new file mode 100644
index 000000000..411d04af1
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessiblePresentationOLEShape.cxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessiblePresentationOLEShape.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+
+#include <SdShapeTypes.hxx>
+
+#include <svx/ShapeTypeHandler.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+namespace accessibility
+{
+//===== internal ============================================================
+
+AccessiblePresentationOLEShape::AccessiblePresentationOLEShape(
+ const AccessibleShapeInfo& rShapeInfo, const AccessibleShapeTreeInfo& rShapeTreeInfo)
+ : AccessibleOLEShape(rShapeInfo, rShapeTreeInfo)
+{
+}
+
+AccessiblePresentationOLEShape::~AccessiblePresentationOLEShape() {}
+
+// XServiceInfo
+
+OUString SAL_CALL AccessiblePresentationOLEShape::getImplementationName()
+{
+ return "AccessiblePresentationOLEShape";
+}
+
+/// Set this object's name if it is different to the current name.
+OUString AccessiblePresentationOLEShape::CreateAccessibleBaseName()
+{
+ OUString sName;
+
+ ShapeTypeId nShapeType = ShapeTypeHandler::Instance().GetTypeId(mxShape);
+ switch (nShapeType)
+ {
+ case PRESENTATION_OLE:
+ sName = "ImpressOLE";
+ break;
+ case PRESENTATION_CHART:
+ sName = "ImpressChart";
+ break;
+ case PRESENTATION_TABLE:
+ sName = "ImpressTable";
+ break;
+ default:
+ sName = "UnknownAccessibleImpressOLEShape";
+ if (mxShape.is())
+ sName += ": " + mxShape->getShapeType();
+ }
+
+ return sName;
+}
+
+// Return this object's role.
+sal_Int16 SAL_CALL AccessiblePresentationOLEShape::getAccessibleRole()
+{
+ return AccessibleRole::EMBEDDED_OBJECT;
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessiblePresentationShape.cxx b/sd/source/ui/accessibility/AccessiblePresentationShape.cxx
new file mode 100644
index 000000000..e4afe7e9a
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessiblePresentationShape.cxx
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessiblePresentationShape.hxx>
+
+#include <SdShapeTypes.hxx>
+
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <svx/ShapeTypeHandler.hxx>
+
+#include <com/sun/star/drawing/XShape.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+namespace accessibility
+{
+//===== internal ============================================================
+
+AccessiblePresentationShape::AccessiblePresentationShape(
+ const AccessibleShapeInfo& rShapeInfo, const AccessibleShapeTreeInfo& rShapeTreeInfo)
+ : AccessibleShape(rShapeInfo, rShapeTreeInfo)
+{
+}
+
+AccessiblePresentationShape::~AccessiblePresentationShape() {}
+
+// XServiceInfo
+
+OUString SAL_CALL AccessiblePresentationShape::getImplementationName()
+{
+ return "AccessiblePresentationShape";
+}
+
+/// Set this object's name if is different to the current name.
+OUString AccessiblePresentationShape::CreateAccessibleBaseName()
+{
+ OUString sName;
+
+ ShapeTypeId nShapeType = ShapeTypeHandler::Instance().GetTypeId(mxShape);
+ switch (nShapeType)
+ {
+ case PRESENTATION_TITLE:
+ sName = SdResId(SID_SD_A11Y_P_TITLE_N);
+ break;
+ case PRESENTATION_OUTLINER:
+ sName = SdResId(SID_SD_A11Y_P_OUTLINER_N);
+ break;
+ case PRESENTATION_SUBTITLE:
+ sName = SdResId(SID_SD_A11Y_P_SUBTITLE_N);
+ break;
+ case PRESENTATION_PAGE:
+ sName = SdResId(SID_SD_A11Y_P_PAGE_N);
+ break;
+ case PRESENTATION_NOTES:
+ sName = SdResId(SID_SD_A11Y_P_NOTES_N);
+ break;
+ case PRESENTATION_HANDOUT:
+ sName = SdResId(SID_SD_A11Y_P_HANDOUT_N);
+ break;
+ case PRESENTATION_HEADER:
+ sName = SdResId(SID_SD_A11Y_P_HEADER_N);
+ break;
+ case PRESENTATION_FOOTER:
+ sName = SdResId(SID_SD_A11Y_P_FOOTER_N);
+ break;
+ case PRESENTATION_DATETIME:
+ sName = SdResId(SID_SD_A11Y_P_DATE_N);
+ break;
+ case PRESENTATION_PAGENUMBER:
+ sName = SdResId(SID_SD_A11Y_P_NUMBER_N);
+ break;
+ default:
+ sName = SdResId(SID_SD_A11Y_P_UNKNOWN_N);
+ if (mxShape.is())
+ sName += ": " + mxShape->getShapeType();
+ }
+
+ return sName;
+}
+
+OUString AccessiblePresentationShape::GetStyle() const
+{
+ OUString sName;
+
+ ShapeTypeId nShapeType = ShapeTypeHandler::Instance().GetTypeId(mxShape);
+ switch (nShapeType)
+ {
+ case PRESENTATION_TITLE:
+ sName = SdResId(SID_SD_A11Y_P_TITLE_N_STYLE);
+ break;
+ case PRESENTATION_OUTLINER:
+ sName = SdResId(SID_SD_A11Y_P_OUTLINER_N_STYLE);
+ break;
+ case PRESENTATION_SUBTITLE:
+ sName = SdResId(SID_SD_A11Y_P_SUBTITLE_N_STYLE);
+ break;
+ case PRESENTATION_PAGE:
+ sName = SdResId(SID_SD_A11Y_P_PAGE_N_STYLE);
+ break;
+ case PRESENTATION_NOTES:
+ sName = SdResId(SID_SD_A11Y_P_NOTES_N_STYLE);
+ break;
+ case PRESENTATION_HANDOUT:
+ sName = SdResId(SID_SD_A11Y_P_HANDOUT_N_STYLE);
+ break;
+ case PRESENTATION_FOOTER:
+ sName = SdResId(SID_SD_A11Y_P_FOOTER_N_STYLE);
+ break;
+ case PRESENTATION_HEADER:
+ sName = SdResId(SID_SD_A11Y_P_HEADER_N_STYLE);
+ break;
+ case PRESENTATION_DATETIME:
+ sName = SdResId(SID_SD_A11Y_P_DATE_N_STYLE);
+ break;
+ case PRESENTATION_PAGENUMBER:
+ sName = SdResId(SID_SD_A11Y_P_NUMBER_N_STYLE);
+ break;
+ default:
+ sName = SdResId(SID_SD_A11Y_P_UNKNOWN_N_STYLE);
+ if (mxShape.is())
+ sName += ": " + mxShape->getShapeType();
+ }
+
+ return sName;
+}
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessibleSlideSorterObject.cxx b/sd/source/ui/accessibility/AccessibleSlideSorterObject.cxx
new file mode 100644
index 000000000..13fc60db0
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessibleSlideSorterObject.cxx
@@ -0,0 +1,429 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleSlideSorterObject.hxx>
+
+#include <SlideSorter.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsFocusManager.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <view/SlsPageObjectLayouter.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/IllegalAccessibleComponentStateException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/accessibleeventnotifier.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <sal/log.hxx>
+
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <strings.hrc>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+
+namespace accessibility {
+
+AccessibleSlideSorterObject::AccessibleSlideSorterObject(
+ const Reference<XAccessible>& rxParent,
+ ::sd::slidesorter::SlideSorter& rSlideSorter,
+ sal_uInt16 nPageNumber)
+ : mxParent(rxParent),
+ mnPageNumber(nPageNumber),
+ mrSlideSorter(rSlideSorter),
+ mnClientId(0)
+{
+}
+
+AccessibleSlideSorterObject::~AccessibleSlideSorterObject()
+{
+ if ( ! IsDisposed())
+ dispose();
+}
+
+void AccessibleSlideSorterObject::FireAccessibleEvent (
+ short nEventId,
+ const uno::Any& rOldValue,
+ const uno::Any& rNewValue)
+{
+ if (mnClientId != 0)
+ {
+ AccessibleEventObject aEventObject;
+
+ aEventObject.Source = Reference<XWeak>(this);
+ aEventObject.EventId = nEventId;
+ aEventObject.NewValue = rNewValue;
+ aEventObject.OldValue = rOldValue;
+
+ comphelper::AccessibleEventNotifier::addEvent(mnClientId, aEventObject);
+ }
+}
+
+void AccessibleSlideSorterObject::disposing(std::unique_lock<std::mutex>&)
+{
+ // Send a disposing to all listeners.
+ if (mnClientId != 0)
+ {
+ comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(mnClientId, *this);
+ mnClientId = 0;
+ }
+}
+
+//===== XAccessible ===========================================================
+
+Reference<XAccessibleContext> SAL_CALL
+ AccessibleSlideSorterObject::getAccessibleContext()
+{
+ ThrowIfDisposed();
+ return this;
+}
+
+//===== XAccessibleContext ====================================================
+
+sal_Int32 SAL_CALL AccessibleSlideSorterObject::getAccessibleChildCount()
+{
+ ThrowIfDisposed();
+ return 0;
+}
+
+Reference<XAccessible> SAL_CALL AccessibleSlideSorterObject::getAccessibleChild (sal_Int32 )
+{
+ ThrowIfDisposed();
+ throw lang::IndexOutOfBoundsException();
+}
+
+Reference<XAccessible> SAL_CALL AccessibleSlideSorterObject::getAccessibleParent()
+{
+ ThrowIfDisposed();
+ return mxParent;
+}
+
+sal_Int32 SAL_CALL AccessibleSlideSorterObject::getAccessibleIndexInParent()
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+ sal_Int32 nIndexInParent(-1);
+
+ if (mxParent.is())
+ {
+ Reference<XAccessibleContext> xParentContext (mxParent->getAccessibleContext());
+ if (xParentContext.is())
+ {
+ sal_Int32 nChildCount (xParentContext->getAccessibleChildCount());
+ for (sal_Int32 i=0; i<nChildCount; ++i)
+ if (xParentContext->getAccessibleChild(i).get()
+ == static_cast<XAccessible*>(this))
+ {
+ nIndexInParent = i;
+ break;
+ }
+ }
+ }
+
+ return nIndexInParent;
+}
+
+sal_Int16 SAL_CALL AccessibleSlideSorterObject::getAccessibleRole()
+{
+ ThrowIfDisposed();
+ return AccessibleRole::SHAPE;
+}
+
+OUString SAL_CALL AccessibleSlideSorterObject::getAccessibleDescription()
+{
+ ThrowIfDisposed();
+ return SdResId(STR_PAGE);
+}
+
+OUString SAL_CALL AccessibleSlideSorterObject::getAccessibleName()
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+
+ SdPage* pPage = GetPage();
+ if (pPage != nullptr)
+ return pPage->GetName();
+ else
+ return OUString();
+}
+
+Reference<XAccessibleRelationSet> SAL_CALL
+ AccessibleSlideSorterObject::getAccessibleRelationSet()
+{
+ ThrowIfDisposed();
+ return Reference<XAccessibleRelationSet>();
+}
+
+Reference<XAccessibleStateSet> SAL_CALL
+ AccessibleSlideSorterObject::getAccessibleStateSet()
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+ rtl::Reference<::utl::AccessibleStateSetHelper> pStateSet = new ::utl::AccessibleStateSetHelper();
+
+ if (mxParent.is())
+ {
+ // Unconditional states.
+ pStateSet->AddState(AccessibleStateType::SELECTABLE);
+ pStateSet->AddState(AccessibleStateType::FOCUSABLE);
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ pStateSet->AddState(AccessibleStateType::ACTIVE);
+ pStateSet->AddState(AccessibleStateType::SENSITIVE);
+
+ // Conditional states.
+ if (mrSlideSorter.GetController().GetPageSelector().IsPageSelected(mnPageNumber))
+ pStateSet->AddState(AccessibleStateType::SELECTED);
+ if (mrSlideSorter.GetController().GetFocusManager().GetFocusedPageIndex() == mnPageNumber)
+ if (mrSlideSorter.GetController().GetFocusManager().IsFocusShowing())
+ pStateSet->AddState(AccessibleStateType::FOCUSED);
+ }
+
+ return pStateSet;
+}
+
+lang::Locale SAL_CALL AccessibleSlideSorterObject::getLocale()
+{
+ ThrowIfDisposed();
+ // Delegate request to parent.
+ if (mxParent.is())
+ {
+ Reference<XAccessibleContext> xParentContext (mxParent->getAccessibleContext());
+ if (xParentContext.is())
+ return xParentContext->getLocale ();
+ }
+
+ // No locale and no parent. Therefore throw exception to indicate this
+ // cluelessness.
+ throw IllegalAccessibleComponentStateException();
+}
+
+//===== XAccessibleEventBroadcaster ===========================================
+
+void SAL_CALL AccessibleSlideSorterObject::addAccessibleEventListener(
+ const Reference<XAccessibleEventListener>& rxListener)
+{
+ if (!rxListener.is())
+ return;
+
+ const std::unique_lock aGuard(m_aMutex);
+
+ if (IsDisposed())
+ {
+ uno::Reference<uno::XInterface> x (static_cast<lang::XComponent *>(this), uno::UNO_QUERY);
+ rxListener->disposing (lang::EventObject (x));
+ }
+ else
+ {
+ if (mnClientId == 0)
+ mnClientId = comphelper::AccessibleEventNotifier::registerClient();
+ comphelper::AccessibleEventNotifier::addEventListener(mnClientId, rxListener);
+ }
+}
+
+void SAL_CALL AccessibleSlideSorterObject::removeAccessibleEventListener(
+ const Reference<XAccessibleEventListener>& rxListener)
+{
+ ThrowIfDisposed();
+ if (!(rxListener.is() && mnClientId))
+ return;
+
+ const std::unique_lock aGuard(m_aMutex);
+
+ sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, rxListener );
+ 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;
+ }
+}
+
+//===== XAccessibleComponent ==================================================
+
+sal_Bool SAL_CALL AccessibleSlideSorterObject::containsPoint(const awt::Point& aPoint)
+{
+ ThrowIfDisposed();
+ const awt::Size aSize (getSize());
+ return (aPoint.X >= 0)
+ && (aPoint.X < aSize.Width)
+ && (aPoint.Y >= 0)
+ && (aPoint.Y < aSize.Height);
+}
+
+Reference<XAccessible> SAL_CALL
+ AccessibleSlideSorterObject::getAccessibleAtPoint(const awt::Point& )
+{
+ return nullptr;
+}
+
+awt::Rectangle SAL_CALL AccessibleSlideSorterObject::getBounds()
+{
+ ThrowIfDisposed ();
+
+ const SolarMutexGuard aSolarGuard;
+
+ ::tools::Rectangle aBBox (
+ mrSlideSorter.GetView().GetLayouter().GetPageObjectLayouter()->GetBoundingBox(
+ mrSlideSorter.GetModel().GetPageDescriptor(mnPageNumber),
+ ::sd::slidesorter::view::PageObjectLayouter::Part::PageObject,
+ ::sd::slidesorter::view::PageObjectLayouter::WindowCoordinateSystem));
+
+ if (mxParent.is())
+ {
+ Reference<XAccessibleComponent> xParentComponent(mxParent->getAccessibleContext(), UNO_QUERY);
+ if (xParentComponent.is())
+ {
+ awt::Rectangle aParentBBox (xParentComponent->getBounds());
+ aBBox.Intersection(::tools::Rectangle(
+ aParentBBox.X,
+ aParentBBox.Y,
+ aParentBBox.Width,
+ aParentBBox.Height));
+ }
+ }
+
+ return awt::Rectangle(
+ aBBox.Left(),
+ aBBox.Top(),
+ aBBox.GetWidth(),
+ aBBox.GetHeight());
+}
+
+awt::Point SAL_CALL AccessibleSlideSorterObject::getLocation ()
+{
+ ThrowIfDisposed ();
+ const awt::Rectangle aBBox (getBounds());
+ return awt::Point(aBBox.X, aBBox.Y);
+}
+
+awt::Point SAL_CALL AccessibleSlideSorterObject::getLocationOnScreen()
+{
+ ThrowIfDisposed ();
+
+ const SolarMutexGuard aSolarGuard;
+
+ awt::Point aLocation (getLocation());
+
+ if (mxParent.is())
+ {
+ Reference<XAccessibleComponent> xParentComponent(mxParent->getAccessibleContext(),UNO_QUERY);
+ if (xParentComponent.is())
+ {
+ const awt::Point aParentLocationOnScreen(xParentComponent->getLocationOnScreen());
+ aLocation.X += aParentLocationOnScreen.X;
+ aLocation.Y += aParentLocationOnScreen.Y;
+ }
+ }
+
+ return aLocation;
+}
+
+awt::Size SAL_CALL AccessibleSlideSorterObject::getSize()
+{
+ ThrowIfDisposed ();
+ const awt::Rectangle aBBox (getBounds());
+ return awt::Size(aBBox.Width,aBBox.Height);
+}
+
+void SAL_CALL AccessibleSlideSorterObject::grabFocus()
+{
+ // nothing to do
+}
+
+sal_Int32 SAL_CALL AccessibleSlideSorterObject::getForeground()
+{
+ ThrowIfDisposed ();
+ svtools::ColorConfig aColorConfig;
+ Color nColor = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor;
+ return static_cast<sal_Int32>(nColor);
+}
+
+sal_Int32 SAL_CALL AccessibleSlideSorterObject::getBackground()
+{
+ ThrowIfDisposed ();
+ Color nColor = Application::GetSettings().GetStyleSettings().GetWindowColor();
+ return sal_Int32(nColor);
+}
+
+// XServiceInfo
+OUString SAL_CALL
+ AccessibleSlideSorterObject::getImplementationName()
+{
+ return "AccessibleSlideSorterObject";
+}
+
+sal_Bool SAL_CALL AccessibleSlideSorterObject::supportsService (const OUString& sServiceName)
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+uno::Sequence< OUString> SAL_CALL
+ AccessibleSlideSorterObject::getSupportedServiceNames()
+{
+ ThrowIfDisposed ();
+
+ return uno::Sequence<OUString> {
+ OUString("com.sun.star.accessibility.Accessible"),
+ OUString("com.sun.star.accessibility.AccessibleContext")
+ };
+}
+
+void AccessibleSlideSorterObject::ThrowIfDisposed()
+{
+ if (m_bDisposed)
+ {
+ SAL_WARN("sd", "Calling disposed object. Throwing exception:");
+ throw lang::DisposedException ("object has been already disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+bool AccessibleSlideSorterObject::IsDisposed() const
+{
+ return m_bDisposed;
+}
+
+SdPage* AccessibleSlideSorterObject::GetPage() const
+{
+ ::sd::slidesorter::model::SharedPageDescriptor pDescriptor(
+ mrSlideSorter.GetModel().GetPageDescriptor(mnPageNumber));
+ if (pDescriptor)
+ return pDescriptor->GetPage();
+ else
+ return nullptr;
+}
+
+} // end of namespace ::accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessibleSlideSorterView.cxx b/sd/source/ui/accessibility/AccessibleSlideSorterView.cxx
new file mode 100644
index 000000000..87eea89d2
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessibleSlideSorterView.cxx
@@ -0,0 +1,950 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleSlideSorterView.hxx>
+#include <AccessibleSlideSorterObject.hxx>
+
+#include <SlideSorter.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsFocusManager.hxx>
+#include <controller/SlsSelectionManager.hxx>
+#include <view/SlideSorterView.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+
+#include <ViewShell.hxx>
+#include <ViewShellHint.hxx>
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/accessibleeventnotifier.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/safeint.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <rtl/ref.hxx>
+#include <sal/log.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+
+namespace accessibility {
+
+/** Inner implementation class of the AccessibleSlideSorterView.
+
+ Note that some event broadcasting is done asynchronously because
+ otherwise it could lead to deadlocks on (at least) some Solaris
+ machines. Probably (but unverified) this can happen on all GTK based
+ systems. The asynchronous broadcasting is just a workaround for a
+ poorly understood problem.
+*/
+class AccessibleSlideSorterView::Implementation
+ : public SfxListener
+{
+public:
+ Implementation (
+ AccessibleSlideSorterView& rAccessibleSlideSorter,
+ ::sd::slidesorter::SlideSorter& rSlideSorter,
+ vcl::Window* pWindow);
+ virtual ~Implementation() override;
+
+ void RequestUpdateChildren();
+ void Clear();
+ sal_Int32 GetVisibleChildCount() const;
+ AccessibleSlideSorterObject* GetAccessibleChild (sal_Int32 nIndex);
+ AccessibleSlideSorterObject* GetVisibleChild (sal_Int32 nIndex);
+
+ void ConnectListeners();
+ void ReleaseListeners();
+ void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override;
+ DECL_LINK(WindowEventListener, VclWindowEvent&, void);
+ DECL_LINK(SelectionChangeListener, LinkParamNone*, void);
+ DECL_LINK(BroadcastSelectionChange, void*, void);
+ DECL_LINK(FocusChangeListener, LinkParamNone*, void);
+ DECL_LINK(VisibilityChangeListener, LinkParamNone*, void);
+ DECL_LINK(UpdateChildrenCallback, void*, void);
+
+ void Activated();
+private:
+ AccessibleSlideSorterView& mrAccessibleSlideSorter;
+ ::sd::slidesorter::SlideSorter& mrSlideSorter;
+ typedef ::std::vector<rtl::Reference<AccessibleSlideSorterObject> > PageObjectList;
+ PageObjectList maPageObjects;
+ sal_Int32 mnFirstVisibleChild;
+ sal_Int32 mnLastVisibleChild;
+ bool mbListeningToDocument;
+ VclPtr<vcl::Window> mpWindow;
+ sal_Int32 mnFocusedIndex;
+ bool mbModelChangeLocked;
+ ImplSVEvent * mnUpdateChildrenUserEventId;
+ ImplSVEvent * mnSelectionChangeUserEventId;
+
+ void UpdateChildren();
+};
+
+//===== AccessibleSlideSorterView =============================================
+
+AccessibleSlideSorterView::AccessibleSlideSorterView(
+ ::sd::slidesorter::SlideSorter& rSlideSorter,
+ vcl::Window* pContentWindow)
+ : AccessibleSlideSorterViewBase(m_aMutex),
+ mrSlideSorter(rSlideSorter),
+ mnClientId(0),
+ mpContentWindow(pContentWindow)
+{
+}
+
+void AccessibleSlideSorterView::Init()
+{
+ mpImpl.reset(new Implementation(*this,mrSlideSorter,mpContentWindow));
+}
+
+AccessibleSlideSorterView::~AccessibleSlideSorterView()
+{
+ Destroyed ();
+}
+
+void AccessibleSlideSorterView::FireAccessibleEvent (
+ short nEventId,
+ const uno::Any& rOldValue,
+ const uno::Any& rNewValue )
+{
+ if (mnClientId != 0)
+ {
+ AccessibleEventObject aEventObject;
+
+ aEventObject.Source = Reference<XWeak>(this);
+ aEventObject.EventId = nEventId;
+ aEventObject.NewValue = rNewValue;
+ aEventObject.OldValue = rOldValue;
+
+ comphelper::AccessibleEventNotifier::addEvent (mnClientId, aEventObject);
+ }
+}
+
+void SAL_CALL AccessibleSlideSorterView::disposing()
+{
+ if (mnClientId != 0)
+ {
+ comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this );
+ mnClientId = 0;
+ }
+ mpImpl.reset();
+}
+
+AccessibleSlideSorterObject* AccessibleSlideSorterView::GetAccessibleChildImplementation (
+ sal_Int32 nIndex)
+{
+ AccessibleSlideSorterObject* pResult = nullptr;
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ if (nIndex>=0 && nIndex<mpImpl->GetVisibleChildCount())
+ pResult = mpImpl->GetVisibleChild(nIndex);
+
+ return pResult;
+}
+
+void AccessibleSlideSorterView::Destroyed()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ // Send a disposing to all listeners.
+ if (mnClientId != 0)
+ {
+ comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this );
+ mnClientId = 0;
+ }
+}
+
+//===== XAccessible =========================================================
+
+Reference<XAccessibleContext > SAL_CALL
+ AccessibleSlideSorterView::getAccessibleContext()
+{
+ ThrowIfDisposed ();
+ return this;
+}
+
+//===== XAccessibleContext ==================================================
+
+sal_Int32 SAL_CALL AccessibleSlideSorterView::getAccessibleChildCount()
+{
+ ThrowIfDisposed();
+ ::osl::MutexGuard aGuard (m_aMutex);
+ return mpImpl->GetVisibleChildCount();
+}
+
+Reference<XAccessible > SAL_CALL
+ AccessibleSlideSorterView::getAccessibleChild (sal_Int32 nIndex)
+{
+ ThrowIfDisposed();
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ if (nIndex<0 || nIndex>=mpImpl->GetVisibleChildCount())
+ throw lang::IndexOutOfBoundsException();
+
+ return mpImpl->GetVisibleChild(nIndex);
+}
+
+Reference<XAccessible > SAL_CALL AccessibleSlideSorterView::getAccessibleParent()
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+ Reference<XAccessible> xParent;
+
+ if (mpContentWindow != nullptr)
+ {
+ vcl::Window* pParent = mpContentWindow->GetAccessibleParentWindow();
+ if (pParent != nullptr)
+ xParent = pParent->GetAccessible();
+ }
+
+ return xParent;
+}
+
+sal_Int32 SAL_CALL AccessibleSlideSorterView::getAccessibleIndexInParent()
+{
+ OSL_ASSERT(getAccessibleParent().is());
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+ sal_Int32 nIndexInParent(-1);
+
+ Reference<XAccessibleContext> xParentContext (getAccessibleParent()->getAccessibleContext());
+ if (xParentContext.is())
+ {
+ sal_Int32 nChildCount (xParentContext->getAccessibleChildCount());
+ for (sal_Int32 i=0; i<nChildCount; ++i)
+ if (xParentContext->getAccessibleChild(i).get()
+ == static_cast<XAccessible*>(this))
+ {
+ nIndexInParent = i;
+ break;
+ }
+ }
+
+ return nIndexInParent;
+}
+
+sal_Int16 SAL_CALL AccessibleSlideSorterView::getAccessibleRole()
+{
+ ThrowIfDisposed();
+ return AccessibleRole::DOCUMENT;
+}
+
+OUString SAL_CALL AccessibleSlideSorterView::getAccessibleDescription()
+{
+ ThrowIfDisposed();
+ SolarMutexGuard aGuard;
+
+ return SdResId(SID_SD_A11Y_I_SLIDEVIEW_D);
+}
+
+OUString SAL_CALL AccessibleSlideSorterView::getAccessibleName()
+{
+ ThrowIfDisposed();
+ SolarMutexGuard aGuard;
+
+ return SdResId(SID_SD_A11Y_I_SLIDEVIEW_N);
+}
+
+Reference<XAccessibleRelationSet> SAL_CALL
+ AccessibleSlideSorterView::getAccessibleRelationSet()
+{
+ return Reference<XAccessibleRelationSet>();
+}
+
+Reference<XAccessibleStateSet > SAL_CALL
+ AccessibleSlideSorterView::getAccessibleStateSet()
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+ rtl::Reference<::utl::AccessibleStateSetHelper> pStateSet = new ::utl::AccessibleStateSetHelper();
+
+ pStateSet->AddState(AccessibleStateType::FOCUSABLE);
+ pStateSet->AddState(AccessibleStateType::SELECTABLE);
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::ACTIVE);
+ pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
+ pStateSet->AddState(AccessibleStateType::OPAQUE);
+ if (mpContentWindow!=nullptr)
+ {
+ if (mpContentWindow->IsVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ if (mpContentWindow->IsReallyVisible())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ }
+
+ return pStateSet;
+}
+
+lang::Locale SAL_CALL AccessibleSlideSorterView::getLocale()
+{
+ ThrowIfDisposed ();
+ Reference<XAccessibleContext> xParentContext;
+ Reference<XAccessible> xParent (getAccessibleParent());
+ if (xParent.is())
+ xParentContext = xParent->getAccessibleContext();
+
+ if (xParentContext.is())
+ return xParentContext->getLocale();
+ else
+ // Strange, no parent! Anyway, return the default locale.
+ return Application::GetSettings().GetLanguageTag().getLocale();
+}
+
+void SAL_CALL AccessibleSlideSorterView::addAccessibleEventListener(
+ const Reference<XAccessibleEventListener >& rxListener)
+{
+ if (!rxListener.is())
+ return;
+
+ const osl::MutexGuard aGuard(m_aMutex);
+
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ {
+ uno::Reference<uno::XInterface> x (static_cast<lang::XComponent *>(this), uno::UNO_QUERY);
+ rxListener->disposing (lang::EventObject (x));
+ }
+ else
+ {
+ if ( ! mnClientId)
+ mnClientId = comphelper::AccessibleEventNotifier::registerClient();
+ comphelper::AccessibleEventNotifier::addEventListener(mnClientId, rxListener);
+ }
+}
+
+void SAL_CALL AccessibleSlideSorterView::removeAccessibleEventListener(
+ const Reference<XAccessibleEventListener >& rxListener)
+{
+ ThrowIfDisposed();
+ if (!rxListener.is())
+ return;
+
+ const osl::MutexGuard aGuard(m_aMutex);
+
+ if (mnClientId == 0)
+ return;
+
+ sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener(
+ mnClientId, rxListener );
+ 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;
+ }
+}
+
+//===== XAccessibleComponent ==================================================
+
+sal_Bool SAL_CALL AccessibleSlideSorterView::containsPoint (const awt::Point& aPoint)
+{
+ ThrowIfDisposed();
+ const awt::Rectangle aBBox (getBounds());
+ return (aPoint.X >= 0)
+ && (aPoint.X < aBBox.Width)
+ && (aPoint.Y >= 0)
+ && (aPoint.Y < aBBox.Height);
+}
+
+Reference<XAccessible> SAL_CALL
+ AccessibleSlideSorterView::getAccessibleAtPoint (const awt::Point& aPoint)
+{
+ ThrowIfDisposed();
+ Reference<XAccessible> xAccessible;
+ const SolarMutexGuard aSolarGuard;
+
+ const Point aTestPoint (aPoint.X, aPoint.Y);
+ ::sd::slidesorter::model::SharedPageDescriptor pHitDescriptor (
+ mrSlideSorter.GetController().GetPageAt(aTestPoint));
+ if (pHitDescriptor)
+ xAccessible = mpImpl->GetAccessibleChild(
+ (pHitDescriptor->GetPage()->GetPageNum()-1)/2);
+
+ return xAccessible;
+}
+
+awt::Rectangle SAL_CALL AccessibleSlideSorterView::getBounds()
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+ awt::Rectangle aBBox;
+
+ if (mpContentWindow != nullptr)
+ {
+ const Point aPosition (mpContentWindow->GetPosPixel());
+ const Size aSize (mpContentWindow->GetOutputSizePixel());
+
+ aBBox.X = aPosition.X();
+ aBBox.Y = aPosition.Y();
+ aBBox.Width = aSize.Width();
+ aBBox.Height = aSize.Height();
+ }
+
+ return aBBox;
+}
+
+awt::Point SAL_CALL AccessibleSlideSorterView::getLocation()
+{
+ ThrowIfDisposed();
+ awt::Point aLocation;
+
+ if (mpContentWindow != nullptr)
+ {
+ const Point aPosition (mpContentWindow->GetPosPixel());
+ aLocation.X = aPosition.X();
+ aLocation.Y = aPosition.Y();
+ }
+
+ return aLocation;
+}
+
+/** Calculate the location on screen from the parent's location on screen
+ and our own relative location.
+*/
+awt::Point SAL_CALL AccessibleSlideSorterView::getLocationOnScreen()
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+ awt::Point aParentLocationOnScreen;
+
+ Reference<XAccessible> xParent (getAccessibleParent());
+ if (xParent.is())
+ {
+ Reference<XAccessibleComponent> xParentComponent (
+ xParent->getAccessibleContext(), uno::UNO_QUERY);
+ if (xParentComponent.is())
+ aParentLocationOnScreen = xParentComponent->getLocationOnScreen();
+ }
+
+ awt::Point aLocationOnScreen (getLocation());
+ aLocationOnScreen.X += aParentLocationOnScreen.X;
+ aLocationOnScreen.Y += aParentLocationOnScreen.Y;
+
+ return aLocationOnScreen;
+}
+
+awt::Size SAL_CALL AccessibleSlideSorterView::getSize()
+{
+ ThrowIfDisposed();
+ awt::Size aSize;
+
+ if (mpContentWindow != nullptr)
+ {
+ const Size aOutputSize (mpContentWindow->GetOutputSizePixel());
+ aSize.Width = aOutputSize.Width();
+ aSize.Height = aOutputSize.Height();
+ }
+
+ return aSize;
+}
+
+void SAL_CALL AccessibleSlideSorterView::grabFocus()
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+
+ if (mpContentWindow)
+ mpContentWindow->GrabFocus();
+}
+
+sal_Int32 SAL_CALL AccessibleSlideSorterView::getForeground()
+{
+ ThrowIfDisposed();
+ svtools::ColorConfig aColorConfig;
+ Color nColor = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor;
+ return static_cast<sal_Int32>(nColor);
+}
+
+sal_Int32 SAL_CALL AccessibleSlideSorterView::getBackground()
+{
+ ThrowIfDisposed();
+ Color nColor = Application::GetSettings().GetStyleSettings().GetWindowColor();
+ return sal_Int32(nColor);
+}
+
+//===== XAccessibleSelection ==================================================
+
+void SAL_CALL AccessibleSlideSorterView::selectAccessibleChild (sal_Int32 nChildIndex)
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+
+ AccessibleSlideSorterObject* pChild = mpImpl->GetAccessibleChild(nChildIndex);
+ if (pChild == nullptr)
+ throw lang::IndexOutOfBoundsException();
+
+ mrSlideSorter.GetController().GetPageSelector().SelectPage(pChild->GetPageNumber());
+}
+
+sal_Bool SAL_CALL AccessibleSlideSorterView::isAccessibleChildSelected (sal_Int32 nChildIndex)
+{
+ ThrowIfDisposed();
+ bool bIsSelected = false;
+ const SolarMutexGuard aSolarGuard;
+
+ AccessibleSlideSorterObject* pChild = mpImpl->GetAccessibleChild(nChildIndex);
+ if (pChild == nullptr)
+ throw lang::IndexOutOfBoundsException();
+
+ bIsSelected = mrSlideSorter.GetController().GetPageSelector().IsPageSelected(
+ pChild->GetPageNumber());
+
+ return bIsSelected;
+}
+
+void SAL_CALL AccessibleSlideSorterView::clearAccessibleSelection()
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+
+ mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
+}
+
+void SAL_CALL AccessibleSlideSorterView::selectAllAccessibleChildren()
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+
+ mrSlideSorter.GetController().GetPageSelector().SelectAllPages();
+}
+
+sal_Int32 SAL_CALL AccessibleSlideSorterView::getSelectedAccessibleChildCount()
+{
+ ThrowIfDisposed ();
+ const SolarMutexGuard aSolarGuard;
+ return mrSlideSorter.GetController().GetPageSelector().GetSelectedPageCount();
+}
+
+Reference<XAccessible > SAL_CALL
+ AccessibleSlideSorterView::getSelectedAccessibleChild (sal_Int32 nSelectedChildIndex )
+{
+ ThrowIfDisposed ();
+ const SolarMutexGuard aSolarGuard;
+ Reference<XAccessible> xChild;
+
+ ::sd::slidesorter::controller::PageSelector& rSelector (
+ mrSlideSorter.GetController().GetPageSelector());
+ sal_Int32 nPageCount(rSelector.GetPageCount());
+ sal_Int32 nSelectedCount = 0;
+ for (sal_Int32 i=0; i<nPageCount; i++)
+ if (rSelector.IsPageSelected(i))
+ {
+ if (nSelectedCount == nSelectedChildIndex)
+ {
+ xChild = mpImpl->GetAccessibleChild(i);
+ break;
+ }
+ ++nSelectedCount;
+ }
+
+ if ( ! xChild.is() )
+ throw lang::IndexOutOfBoundsException();
+
+ return xChild;
+}
+
+void SAL_CALL AccessibleSlideSorterView::deselectAccessibleChild (sal_Int32 nChildIndex)
+{
+ ThrowIfDisposed();
+ const SolarMutexGuard aSolarGuard;
+
+ AccessibleSlideSorterObject* pChild = mpImpl->GetAccessibleChild(nChildIndex);
+ if (pChild == nullptr)
+ throw lang::IndexOutOfBoundsException();
+
+ mrSlideSorter.GetController().GetPageSelector().DeselectPage(pChild->GetPageNumber());
+}
+
+// XServiceInfo
+OUString SAL_CALL
+ AccessibleSlideSorterView::getImplementationName()
+{
+ return "AccessibleSlideSorterView";
+}
+
+sal_Bool SAL_CALL AccessibleSlideSorterView::supportsService (const OUString& sServiceName)
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+uno::Sequence< OUString> SAL_CALL
+ AccessibleSlideSorterView::getSupportedServiceNames()
+{
+ ThrowIfDisposed ();
+
+ return uno::Sequence<OUString> {
+ OUString("com.sun.star.accessibility.Accessible"),
+ OUString("com.sun.star.accessibility.AccessibleContext"),
+ OUString("com.sun.star.drawing.AccessibleSlideSorterView")
+ };
+}
+
+void AccessibleSlideSorterView::ThrowIfDisposed()
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ {
+ SAL_WARN("sd", "Calling disposed object. Throwing exception:");
+ throw lang::DisposedException ("object has been already disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+//===== AccessibleSlideSorterView::Implementation =============================
+
+AccessibleSlideSorterView::Implementation::Implementation (
+ AccessibleSlideSorterView& rAccessibleSlideSorter,
+ ::sd::slidesorter::SlideSorter& rSlideSorter,
+ vcl::Window* pWindow)
+ : mrAccessibleSlideSorter(rAccessibleSlideSorter),
+ mrSlideSorter(rSlideSorter),
+ mnFirstVisibleChild(0),
+ mnLastVisibleChild(-1),
+ mbListeningToDocument(false),
+ mpWindow(pWindow),
+ mnFocusedIndex(-1),
+ mbModelChangeLocked(false),
+ mnUpdateChildrenUserEventId(nullptr),
+ mnSelectionChangeUserEventId(nullptr)
+{
+ ConnectListeners();
+ UpdateChildren();
+}
+
+AccessibleSlideSorterView::Implementation::~Implementation()
+{
+ if (mnUpdateChildrenUserEventId != nullptr)
+ Application::RemoveUserEvent(mnUpdateChildrenUserEventId);
+ if (mnSelectionChangeUserEventId != nullptr)
+ Application::RemoveUserEvent(mnSelectionChangeUserEventId);
+ ReleaseListeners();
+ Clear();
+}
+
+void AccessibleSlideSorterView::Implementation::RequestUpdateChildren()
+{
+ if (mnUpdateChildrenUserEventId == nullptr)
+ mnUpdateChildrenUserEventId = Application::PostUserEvent(
+ LINK(this, AccessibleSlideSorterView::Implementation,
+ UpdateChildrenCallback));
+}
+
+void AccessibleSlideSorterView::Implementation::UpdateChildren()
+{
+ //By default, all children should be accessible. So here workaround is to make all children visible.
+ // MT: This was in UpdateVisibility, which has some similarity, and hg merge automatically has put it here. Correct?!
+ // In the IA2 CWS, also setting mnFirst/LastVisibleChild was commented out!
+ mnLastVisibleChild = maPageObjects.size();
+
+ if (mbModelChangeLocked)
+ {
+ // Do nothing right now. When the flag is reset, this method is
+ // called again.
+ return;
+ }
+
+ const Range aRange (mrSlideSorter.GetView().GetVisiblePageRange());
+ mnFirstVisibleChild = aRange.Min();
+ mnLastVisibleChild = aRange.Max();
+
+ // Release all children.
+ Clear();
+
+ // Create new children for the modified visible range.
+ maPageObjects.resize(mrSlideSorter.GetModel().GetPageCount());
+
+ // No Visible children
+ if (mnFirstVisibleChild == -1 && mnLastVisibleChild == -1)
+ return;
+
+ for (sal_Int32 nIndex(mnFirstVisibleChild); nIndex<=mnLastVisibleChild; ++nIndex)
+ GetAccessibleChild(nIndex);
+}
+
+void AccessibleSlideSorterView::Implementation::Clear()
+{
+ for (auto& rxPageObject : maPageObjects)
+ if (rxPageObject != nullptr)
+ {
+ mrAccessibleSlideSorter.FireAccessibleEvent(
+ AccessibleEventId::CHILD,
+ Any(Reference<XAccessible>(rxPageObject)),
+ Any());
+
+ Reference<XComponent> xComponent (Reference<XWeak>(rxPageObject), UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+ rxPageObject = nullptr;
+ }
+ maPageObjects.clear();
+}
+
+sal_Int32 AccessibleSlideSorterView::Implementation::GetVisibleChildCount() const
+{
+ if (mnFirstVisibleChild<=mnLastVisibleChild && mnFirstVisibleChild>=0)
+ return mnLastVisibleChild - mnFirstVisibleChild + 1;
+ else
+ return 0;
+}
+
+AccessibleSlideSorterObject* AccessibleSlideSorterView::Implementation::GetVisibleChild (
+ sal_Int32 nIndex)
+{
+ assert(nIndex>=0 && nIndex<GetVisibleChildCount());
+
+ return GetAccessibleChild(nIndex+mnFirstVisibleChild);
+}
+
+AccessibleSlideSorterObject* AccessibleSlideSorterView::Implementation::GetAccessibleChild (
+ sal_Int32 nIndex)
+{
+ AccessibleSlideSorterObject* pChild = nullptr;
+
+ if (nIndex>=0 && o3tl::make_unsigned(nIndex)<maPageObjects.size())
+ {
+ if (maPageObjects[nIndex] == nullptr)
+ {
+ ::sd::slidesorter::model::SharedPageDescriptor pDescriptor(
+ mrSlideSorter.GetModel().GetPageDescriptor(nIndex));
+ if (pDescriptor)
+ {
+ maPageObjects[nIndex] = new AccessibleSlideSorterObject(
+ &mrAccessibleSlideSorter,
+ mrSlideSorter,
+ (pDescriptor->GetPage()->GetPageNum()-1)/2);
+
+ mrAccessibleSlideSorter.FireAccessibleEvent(
+ AccessibleEventId::CHILD,
+ Any(),
+ Any(Reference<XAccessible>(maPageObjects[nIndex])));
+ }
+
+ }
+
+ pChild = maPageObjects[nIndex].get();
+ }
+ else
+ {
+ OSL_ASSERT(nIndex>=0 && o3tl::make_unsigned(nIndex)<maPageObjects.size());
+ }
+
+ return pChild;
+}
+
+void AccessibleSlideSorterView::Implementation::ConnectListeners()
+{
+ StartListening (*mrSlideSorter.GetModel().GetDocument());
+ if (mrSlideSorter.GetViewShell() != nullptr)
+ StartListening (*mrSlideSorter.GetViewShell());
+ mbListeningToDocument = true;
+
+ if (mpWindow != nullptr)
+ mpWindow->AddEventListener(
+ LINK(this,AccessibleSlideSorterView::Implementation,WindowEventListener));
+
+ mrSlideSorter.GetController().GetSelectionManager()->AddSelectionChangeListener(
+ LINK(this,AccessibleSlideSorterView::Implementation,SelectionChangeListener));
+ mrSlideSorter.GetController().GetFocusManager().AddFocusChangeListener(
+ LINK(this,AccessibleSlideSorterView::Implementation,FocusChangeListener));
+ mrSlideSorter.GetView().AddVisibilityChangeListener(
+ LINK(this,AccessibleSlideSorterView::Implementation,VisibilityChangeListener));
+}
+
+void AccessibleSlideSorterView::Implementation::ReleaseListeners()
+{
+ mrSlideSorter.GetController().GetFocusManager().RemoveFocusChangeListener(
+ LINK(this,AccessibleSlideSorterView::Implementation,FocusChangeListener));
+ mrSlideSorter.GetController().GetSelectionManager()->RemoveSelectionChangeListener(
+ LINK(this,AccessibleSlideSorterView::Implementation,SelectionChangeListener));
+ mrSlideSorter.GetView().RemoveVisibilityChangeListener(
+ LINK(this,AccessibleSlideSorterView::Implementation,VisibilityChangeListener));
+
+ if (mpWindow != nullptr)
+ mpWindow->RemoveEventListener(
+ LINK(this,AccessibleSlideSorterView::Implementation,WindowEventListener));
+
+ if (mbListeningToDocument)
+ {
+ if (mrSlideSorter.GetViewShell() != nullptr && !IsListening(*mrSlideSorter.GetViewShell()))
+ { // ??? is it even possible that ConnectListeners is called with no
+ // view shell and this one with a view shell?
+ StartListening(*mrSlideSorter.GetViewShell());
+ }
+ EndListening (*mrSlideSorter.GetModel().GetDocument());
+ mbListeningToDocument = false;
+ }
+}
+
+void AccessibleSlideSorterView::Implementation::Notify (
+ SfxBroadcaster&,
+ const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ switch (pSdrHint->GetKind())
+ {
+ case SdrHintKind::PageOrderChange:
+ RequestUpdateChildren();
+ break;
+ default:
+ break;
+ }
+ }
+ else if (auto pViewShellHint = dynamic_cast<const sd::ViewShellHint*>(&rHint))
+ {
+ switch (pViewShellHint->GetHintId())
+ {
+ case sd::ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START:
+ mbModelChangeLocked = true;
+ break;
+
+ case sd::ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END:
+ mbModelChangeLocked = false;
+ RequestUpdateChildren();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void AccessibleSlideSorterView::SwitchViewActivated()
+{
+ // Firstly, set focus to view
+ FireAccessibleEvent(AccessibleEventId::STATE_CHANGED,
+ Any(),
+ Any(AccessibleStateType::FOCUSED));
+
+ mpImpl->Activated();
+}
+
+void AccessibleSlideSorterView::Implementation::Activated()
+{
+ mrSlideSorter.GetController().GetFocusManager().ShowFocus();
+
+}
+
+IMPL_LINK(AccessibleSlideSorterView::Implementation, WindowEventListener, VclWindowEvent&, rEvent, void)
+{
+ switch (rEvent.GetId())
+ {
+ case VclEventId::WindowMove:
+ case VclEventId::WindowResize:
+ RequestUpdateChildren();
+ break;
+
+ case VclEventId::WindowGetFocus:
+ case VclEventId::WindowLoseFocus:
+ mrAccessibleSlideSorter.FireAccessibleEvent(
+ AccessibleEventId::SELECTION_CHANGED,
+ Any(),
+ Any());
+ break;
+ default:
+ break;
+ }
+}
+
+IMPL_LINK_NOARG(AccessibleSlideSorterView::Implementation, SelectionChangeListener, LinkParamNone*, void)
+{
+ if (mnSelectionChangeUserEventId == nullptr)
+ mnSelectionChangeUserEventId = Application::PostUserEvent(
+ LINK(this, AccessibleSlideSorterView::Implementation, BroadcastSelectionChange));
+}
+
+IMPL_LINK_NOARG(AccessibleSlideSorterView::Implementation, BroadcastSelectionChange, void*, void)
+{
+ mnSelectionChangeUserEventId = nullptr;
+ mrAccessibleSlideSorter.FireAccessibleEvent(
+ AccessibleEventId::SELECTION_CHANGED,
+ Any(),
+ Any());
+}
+
+IMPL_LINK_NOARG(AccessibleSlideSorterView::Implementation, FocusChangeListener, LinkParamNone*, void)
+{
+ sal_Int32 nNewFocusedIndex (
+ mrSlideSorter.GetController().GetFocusManager().GetFocusedPageIndex());
+
+ bool bHasFocus = mrSlideSorter.GetController().GetFocusManager().IsFocusShowing();
+ if (!bHasFocus)
+ nNewFocusedIndex = -1;
+
+ // add a checker whether the focus event is sent out. Only after sent, the mnFocusedIndex should be updated.
+ bool bSentFocus = false;
+ if (nNewFocusedIndex == mnFocusedIndex)
+ return;
+
+ if (mnFocusedIndex >= 0)
+ {
+ AccessibleSlideSorterObject* pObject = GetAccessibleChild(mnFocusedIndex);
+ if (pObject != nullptr)
+ {
+ pObject->FireAccessibleEvent(
+ AccessibleEventId::STATE_CHANGED,
+ Any(AccessibleStateType::FOCUSED),
+ Any());
+ bSentFocus = true;
+ }
+ }
+ if (nNewFocusedIndex >= 0)
+ {
+ AccessibleSlideSorterObject* pObject = GetAccessibleChild(nNewFocusedIndex);
+ if (pObject != nullptr)
+ {
+ pObject->FireAccessibleEvent(
+ AccessibleEventId::STATE_CHANGED,
+ Any(),
+ Any(AccessibleStateType::FOCUSED));
+ bSentFocus = true;
+ }
+ }
+ if (bSentFocus)
+ mnFocusedIndex = nNewFocusedIndex;
+}
+
+IMPL_LINK_NOARG(AccessibleSlideSorterView::Implementation, UpdateChildrenCallback, void*, void)
+{
+ mnUpdateChildrenUserEventId = nullptr;
+ UpdateChildren();
+}
+
+IMPL_LINK_NOARG(AccessibleSlideSorterView::Implementation, VisibilityChangeListener, LinkParamNone*, void)
+{
+ UpdateChildren();
+}
+
+} // end of namespace ::accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/AccessibleViewForwarder.cxx b/sd/source/ui/accessibility/AccessibleViewForwarder.cxx
new file mode 100644
index 000000000..09225e27f
--- /dev/null
+++ b/sd/source/ui/accessibility/AccessibleViewForwarder.cxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleViewForwarder.hxx>
+#include <svx/svdpntv.hxx>
+#include <vcl/window.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <osl/diagnose.h>
+
+namespace accessibility
+{
+/** For the time being, the implementation of this class will not use the
+ member mrDevice. Instead the device is retrieved from the view
+ every time it is used. This is necessary because the device has to stay
+ up-to-date with the current view and the class has to stay compatible.
+ May change in the future.
+*/
+
+AccessibleViewForwarder::AccessibleViewForwarder(SdrPaintView* pView, const OutputDevice& rDevice)
+ : mpView(pView)
+ , mnWindowId(0)
+{
+ // Search the output device to determine its id.
+ for (sal_uInt32 a(0); a < mpView->PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pPaintWindow = mpView->GetPaintWindow(a);
+ OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
+
+ if (&rOutDev == &rDevice)
+ {
+ mnWindowId = static_cast<sal_uInt16>(a);
+ break;
+ }
+ }
+}
+
+AccessibleViewForwarder::~AccessibleViewForwarder()
+{
+ // empty
+}
+
+::tools::Rectangle AccessibleViewForwarder::GetVisibleArea() const
+{
+ ::tools::Rectangle aVisibleArea;
+
+ if (static_cast<sal_uInt32>(mnWindowId) < mpView->PaintWindowCount())
+ {
+ SdrPaintWindow* pPaintWindow = mpView->GetPaintWindow(static_cast<sal_uInt32>(mnWindowId));
+ aVisibleArea = pPaintWindow->GetVisibleArea();
+ }
+
+ return aVisibleArea;
+}
+
+/** Transform the given point into pixel coordinates. After the pixel
+ coordinates of the window origin are added to make the point coordinates
+ absolute.
+*/
+Point AccessibleViewForwarder::LogicToPixel(const Point& rPoint) const
+{
+ OSL_ASSERT(mpView != nullptr);
+ if (static_cast<sal_uInt32>(mnWindowId) < mpView->PaintWindowCount())
+ {
+ SdrPaintWindow* pPaintWindow = mpView->GetPaintWindow(static_cast<sal_uInt32>(mnWindowId));
+ OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
+ ::tools::Rectangle aBBox(rOutDev.GetOwnerWindow()->GetWindowExtentsRelative(nullptr));
+ return rOutDev.LogicToPixel(rPoint) + aBBox.TopLeft();
+ }
+ else
+ return Point();
+}
+
+Size AccessibleViewForwarder::LogicToPixel(const Size& rSize) const
+{
+ OSL_ASSERT(mpView != nullptr);
+ if (static_cast<sal_uInt32>(mnWindowId) < mpView->PaintWindowCount())
+ {
+ SdrPaintWindow* pPaintWindow = mpView->GetPaintWindow(static_cast<sal_uInt32>(mnWindowId));
+ OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
+ return rOutDev.LogicToPixel(rSize);
+ }
+ else
+ return Size();
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/accessibility/SdShapeTypes.cxx b/sd/source/ui/accessibility/SdShapeTypes.cxx
new file mode 100644
index 000000000..7fab0961e
--- /dev/null
+++ b/sd/source/ui/accessibility/SdShapeTypes.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/ShapeTypeHandler.hxx>
+#include <SdShapeTypes.hxx>
+#include <AccessiblePresentationShape.hxx>
+#include <AccessiblePresentationGraphicShape.hxx>
+#include <AccessiblePresentationOLEShape.hxx>
+
+namespace accessibility {
+
+static rtl::Reference<AccessibleShape>
+ CreateSdAccessibleShape (
+ const AccessibleShapeInfo& rShapeInfo,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo,
+ ShapeTypeId nId)
+{
+ switch (nId)
+ {
+ case PRESENTATION_TITLE:
+ case PRESENTATION_OUTLINER:
+ case PRESENTATION_SUBTITLE:
+ case PRESENTATION_PAGE:
+ case PRESENTATION_NOTES:
+ case PRESENTATION_HANDOUT:
+ case PRESENTATION_HEADER:
+ case PRESENTATION_FOOTER:
+ case PRESENTATION_DATETIME:
+ case PRESENTATION_PAGENUMBER:
+ return new AccessiblePresentationShape (rShapeInfo, rShapeTreeInfo);
+
+ case PRESENTATION_GRAPHIC_OBJECT:
+ return new AccessiblePresentationGraphicShape (rShapeInfo, rShapeTreeInfo);
+
+ case PRESENTATION_OLE:
+ case PRESENTATION_CHART:
+ case PRESENTATION_TABLE:
+ return new AccessiblePresentationOLEShape (rShapeInfo, rShapeTreeInfo);
+
+ default:
+ return new AccessibleShape (rShapeInfo, rShapeTreeInfo);
+ }
+}
+
+void RegisterImpressShapeTypes()
+{
+ /** List of shape type descriptors corresponding to the
+ <type>SdShapeTypes</type> enum.
+ */
+ ShapeTypeDescriptor aSdShapeTypeList[] = {
+ ShapeTypeDescriptor (
+ PRESENTATION_OUTLINER,
+ "com.sun.star.presentation.OutlinerShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_SUBTITLE,
+ "com.sun.star.presentation.SubtitleShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_GRAPHIC_OBJECT,
+ "com.sun.star.presentation.GraphicObjectShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_PAGE,
+ "com.sun.star.presentation.PageShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_OLE,
+ "com.sun.star.presentation.OLE2Shape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_CHART,
+ "com.sun.star.presentation.ChartShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_TABLE,
+ "com.sun.star.presentation.TableShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_NOTES,
+ "com.sun.star.presentation.NotesShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_TITLE,
+ "com.sun.star.presentation.TitleTextShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_HANDOUT,
+ "com.sun.star.presentation.HandoutShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_HEADER,
+ "com.sun.star.presentation.HeaderShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_FOOTER,
+ "com.sun.star.presentation.FooterShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_DATETIME,
+ "com.sun.star.presentation.DateTimeShape",
+ CreateSdAccessibleShape ),
+ ShapeTypeDescriptor (
+ PRESENTATION_PAGENUMBER,
+ "com.sun.star.presentation.SlideNumberShape",
+ CreateSdAccessibleShape )
+ };
+
+ ShapeTypeHandler::Instance().AddShapeTypeList (
+ PRESENTATION_PAGENUMBER - PRESENTATION_OUTLINER + 1,
+ aSdShapeTypeList);
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/animations/CustomAnimationDialog.cxx b/sd/source/ui/animations/CustomAnimationDialog.cxx
new file mode 100644
index 000000000..7490a62c5
--- /dev/null
+++ b/sd/source/ui/animations/CustomAnimationDialog.cxx
@@ -0,0 +1,2090 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/animations/Timing.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+#include <com/sun/star/animations/ValuePair.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+
+#include <memory>
+
+#include <comphelper/lok.hxx>
+#include <i18nutil/unicode.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/settings.hxx>
+
+#include <svtools/ctrltool.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewsh.hxx>
+#include <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <editeng/flstitem.hxx>
+
+#include <svx/colorbox.hxx>
+#include <svx/gallery.hxx>
+
+#include <editeng/editids.hrc>
+#include <sdresid.hxx>
+
+#include "CustomAnimationDialog.hxx"
+#include <CustomAnimationPane.hxx>
+#include "STLPropertySet.hxx"
+#include <CustomAnimationPreset.hxx>
+
+#include <avmedia/mediawindow.hxx>
+
+#include <filedlg.hxx>
+#include <strings.hrc>
+#include <helpids.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::presentation;
+
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::drawing::XDrawPage;
+using ::com::sun::star::beans::XPropertySet;
+
+namespace sd {
+
+SdPropertySubControl::SdPropertySubControl(weld::Container* pParent)
+ : mxBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/customanimationfragment.ui",
+ false, reinterpret_cast<sal_uInt64>(SfxViewShell::Current())))
+ , mxContainer(mxBuilder->weld_container("EffectFragment"))
+ , mpParent(pParent)
+{
+}
+
+SdPropertySubControl::~SdPropertySubControl()
+{
+ mpParent->move(mxContainer.get(), nullptr);
+}
+
+namespace {
+
+class SdPresetPropertyBox : public SdPropertySubControl
+{
+public:
+ SdPresetPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const OUString& aPresetId, const Link<LinkParamNone*,void>& rModifyHdl);
+
+ virtual Any getValue() override;
+ virtual void setValue( const Any& rValue, const OUString& rPresetId ) override;
+
+private:
+ std::vector<OUString> maPropertyValues;
+ Link<LinkParamNone*,void> maModifyLink;
+ std::unique_ptr<weld::ComboBox> mxControl;
+
+ DECL_LINK(OnSelect, weld::ComboBox&, void);
+};
+
+}
+
+SdPresetPropertyBox::SdPresetPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const OUString& aPresetId, const Link<LinkParamNone*,void>& rModifyHdl)
+ : SdPropertySubControl(pParent)
+ , maModifyLink(rModifyHdl)
+ , mxControl(mxBuilder->weld_combo_box("combo"))
+{
+ mxControl->connect_changed(LINK(this, SdPresetPropertyBox, OnSelect));
+ mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_PRESETPROPERTYBOX);
+ mxControl->show();
+ pLabel->set_mnemonic_widget(mxControl.get());
+ setValue(rValue, aPresetId);
+}
+
+IMPL_LINK_NOARG(SdPresetPropertyBox, OnSelect, weld::ComboBox&, void)
+{
+ maModifyLink.Call(nullptr);
+}
+
+void SdPresetPropertyBox::setValue( const Any& rValue, const OUString& rPresetId )
+{
+ if (!mxControl)
+ return;
+
+ mxControl->freeze();
+ mxControl->clear();
+ maPropertyValues.clear();
+ int nPos = -1;
+
+ const CustomAnimationPresets& rPresets = CustomAnimationPresets::getCustomAnimationPresets();
+ CustomAnimationPresetPtr pDescriptor = rPresets.getEffectDescriptor( rPresetId );
+ if( pDescriptor )
+ {
+
+ OUString aPropertyValue;
+ rValue >>= aPropertyValue;
+
+ std::vector<OUString> aSubTypes( pDescriptor->getSubTypes() );
+
+ mxControl->set_sensitive(!aSubTypes.empty());
+
+ for( const auto& aSubType : aSubTypes )
+ {
+ mxControl->append_text(rPresets.getUINameForProperty(aSubType));
+ maPropertyValues.push_back(aSubType);
+ if (aSubType == aPropertyValue)
+ nPos = maPropertyValues.size() - 1;
+ }
+ }
+ else
+ {
+ mxControl->set_sensitive(false);
+ }
+ mxControl->thaw();
+ if (nPos != -1)
+ mxControl->set_active(nPos);
+}
+
+Any SdPresetPropertyBox::getValue()
+{
+ const int nIndex = mxControl->get_active();
+ if (nIndex == -1)
+ return Any();
+ return Any(maPropertyValues[nIndex]);
+}
+
+namespace {
+
+class SdColorPropertyBox : public SdPropertySubControl
+{
+public:
+ SdColorPropertyBox(weld::Label* pLabel, weld::Container* pParent, weld::Window* pTopLevel, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
+
+ virtual Any getValue() override;
+ virtual void setValue( const Any& rValue, const OUString& rPresetId ) override;
+
+private:
+ Link<LinkParamNone*,void> maModifyLink;
+ std::unique_ptr<ColorListBox> mxControl;
+
+ DECL_LINK(OnSelect, ColorListBox&, void);
+};
+
+}
+
+SdColorPropertyBox::SdColorPropertyBox(weld::Label* pLabel, weld::Container* pParent, weld::Window* pTopLevel, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
+ : SdPropertySubControl(pParent)
+ , maModifyLink(rModifyHdl)
+ , mxControl(new ColorListBox(mxBuilder->weld_menu_button("color"), [pTopLevel]{ return pTopLevel; }))
+{
+ mxControl->SetSelectHdl(LINK(this, SdColorPropertyBox, OnSelect));
+ mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_COLORPROPERTYBOX);
+ pLabel->set_mnemonic_widget(&mxControl->get_widget());
+ mxControl->show();
+
+ Color nColor;
+ rValue >>= nColor;
+ mxControl->SelectEntry(nColor);
+}
+
+IMPL_LINK_NOARG(SdColorPropertyBox, OnSelect, ColorListBox&, void)
+{
+ maModifyLink.Call(nullptr);
+}
+
+void SdColorPropertyBox::setValue( const Any& rValue, const OUString& )
+{
+ if (mxControl)
+ {
+ Color nColor;
+ rValue >>= nColor;
+
+ mxControl->SetNoSelection();
+ mxControl->SelectEntry(nColor);
+ }
+}
+
+Any SdColorPropertyBox::getValue()
+{
+ return Any(sal_Int32(mxControl->GetSelectEntryColor().GetRGBColor()));
+}
+
+namespace {
+
+class SdFontPropertyBox : public SdPropertySubControl
+{
+public:
+ SdFontPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
+
+ virtual Any getValue() override;
+ virtual void setValue(const Any& rValue, const OUString& rPresetId) override;
+
+private:
+ Link<LinkParamNone*,void> maModifyHdl;
+ std::unique_ptr<weld::ComboBox> mxControl;
+
+ DECL_LINK(ControlSelectHdl, weld::ComboBox&, void);
+};
+
+}
+
+SdFontPropertyBox::SdFontPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
+ : SdPropertySubControl(pParent)
+ , maModifyHdl(rModifyHdl)
+ , mxControl(mxBuilder->weld_combo_box("fontname"))
+{
+ mxControl->connect_changed(LINK(this, SdFontPropertyBox, ControlSelectHdl));
+ mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_FONTPROPERTYBOX);
+ mxControl->show();
+ pLabel->set_mnemonic_widget(mxControl.get());
+
+ const FontList* pFontList = nullptr;
+ bool bMustDelete = false;
+
+ if (SfxObjectShell* pDocSh = SfxObjectShell::Current())
+ {
+ auto pItem = pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST );
+ if (pItem)
+ pFontList = static_cast<const SvxFontListItem*>(pItem)->GetFontList();
+ }
+
+ if (!pFontList)
+ {
+ pFontList = new FontList(Application::GetDefaultDevice(), nullptr);
+ bMustDelete = true;
+ }
+
+ mxControl->freeze();
+
+ sal_uInt16 nFontCount = pFontList->GetFontNameCount();
+ for (sal_uInt16 i = 0; i < nFontCount; ++i)
+ {
+ const FontMetric& rFontMetric = pFontList->GetFontName(i);
+ mxControl->append_text(rFontMetric.GetFamilyName());
+ }
+
+ mxControl->thaw();
+
+ if( bMustDelete )
+ delete pFontList;
+
+ setValue( rValue, OUString() );
+}
+
+IMPL_LINK_NOARG(SdFontPropertyBox, ControlSelectHdl, weld::ComboBox&, void)
+{
+ maModifyHdl.Call(nullptr);
+}
+
+void SdFontPropertyBox::setValue( const Any& rValue, const OUString& )
+{
+ if (mxControl)
+ {
+ OUString aFontName;
+ rValue >>= aFontName;
+ mxControl->set_entry_text(aFontName);
+ }
+}
+
+Any SdFontPropertyBox::getValue()
+{
+ OUString aFontName(mxControl->get_active_text());
+ return Any(aFontName);
+}
+
+namespace {
+
+class SdCharHeightPropertyBox : public SdPropertySubControl
+{
+public:
+ SdCharHeightPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
+
+ virtual Any getValue() override;
+ virtual void setValue( const Any& rValue, const OUString& ) override;
+
+ DECL_LINK(implMenuSelectHdl, const OString& rIdent, void);
+
+private:
+ Link<LinkParamNone*,void> maModifyHdl;
+ std::unique_ptr<weld::MetricSpinButton> mxMetric;
+ std::unique_ptr<weld::MenuButton> mxControl;
+
+ DECL_LINK(EditModifyHdl, weld::MetricSpinButton&, void);
+};
+
+}
+
+SdCharHeightPropertyBox::SdCharHeightPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
+ : SdPropertySubControl(pParent)
+ , maModifyHdl(rModifyHdl)
+ , mxMetric(mxBuilder->weld_metric_spin_button("fontsize", FieldUnit::PERCENT))
+ , mxControl(mxBuilder->weld_menu_button("fontsizemenu"))
+{
+ mxMetric->connect_value_changed(LINK(this, SdCharHeightPropertyBox, EditModifyHdl));
+ mxMetric->set_help_id(HID_SD_CUSTOMANIMATIONPANE_CHARHEIGHTPROPERTYBOX);
+ mxMetric->show();
+ pLabel->set_mnemonic_widget(&mxMetric->get_widget());
+
+ mxControl->connect_selected(LINK(this, SdCharHeightPropertyBox, implMenuSelectHdl));
+ mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_CHARHEIGHTPROPERTYBOX);
+ mxControl->show();
+
+ setValue(rValue, OUString());
+}
+
+IMPL_LINK_NOARG(SdCharHeightPropertyBox, EditModifyHdl, weld::MetricSpinButton&, void)
+{
+ maModifyHdl.Call(nullptr);
+}
+
+IMPL_LINK(SdCharHeightPropertyBox, implMenuSelectHdl, const OString&, rIdent, void)
+{
+ sal_Int32 nValue = rIdent.toInt32();
+ mxMetric->set_value(nValue, FieldUnit::PERCENT);
+ EditModifyHdl(*mxMetric);
+}
+
+void SdCharHeightPropertyBox::setValue( const Any& rValue, const OUString& )
+{
+ if (mxMetric)
+ {
+ double fValue = 0.0;
+ rValue >>= fValue;
+ mxMetric->set_value(static_cast<::tools::Long>(fValue * 100.0), FieldUnit::PERCENT);
+ }
+}
+
+Any SdCharHeightPropertyBox::getValue()
+{
+ return Any(static_cast<double>(mxMetric->get_value(FieldUnit::PERCENT)) / 100.0);
+}
+
+namespace {
+
+class SdTransparencyPropertyBox : public SdPropertySubControl
+{
+public:
+ SdTransparencyPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
+
+ virtual Any getValue() override;
+ virtual void setValue( const Any& rValue, const OUString& rPresetId ) override;
+
+ DECL_LINK(implMenuSelectHdl, const OString&, void);
+ DECL_LINK(implModifyHdl, weld::MetricSpinButton&, void);
+
+ void updateMenu();
+
+private:
+ Link<LinkParamNone*,void> maModifyHdl;
+
+ std::unique_ptr<weld::MetricSpinButton> mxMetric;
+ std::unique_ptr<weld::MenuButton> mxControl;
+};
+
+}
+
+SdTransparencyPropertyBox::SdTransparencyPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
+ : SdPropertySubControl(pParent)
+ , maModifyHdl(rModifyHdl)
+ , mxMetric(mxBuilder->weld_metric_spin_button("transparent", FieldUnit::PERCENT))
+ , mxControl(mxBuilder->weld_menu_button("transparentmenu"))
+{
+ for (sal_Int32 i = 25; i < 101; i += 25)
+ {
+ OUString aStr(unicode::formatPercent(i,
+ Application::GetSettings().GetUILanguageTag()));
+ mxControl->append_item_check(OUString::number(i), aStr);
+ }
+
+ mxControl->connect_selected(LINK(this, SdTransparencyPropertyBox, implMenuSelectHdl));
+ mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_TRANSPARENCYPROPERTYBOX);
+ mxControl->show();
+
+ mxMetric->connect_value_changed(LINK(this, SdTransparencyPropertyBox, implModifyHdl));
+ mxMetric->set_help_id(HID_SD_CUSTOMANIMATIONPANE_TRANSPARENCYPROPERTYBOX);
+ mxMetric->show();
+ pLabel->set_mnemonic_widget(&mxMetric->get_widget());
+
+ setValue(rValue, OUString());
+}
+
+void SdTransparencyPropertyBox::updateMenu()
+{
+ sal_Int64 nValue = mxMetric->get_value(FieldUnit::PERCENT);
+ for (sal_uInt16 i = 25; i < 101; i += 25)
+ mxControl->set_item_active(OString::number(i), nValue == i);
+}
+
+IMPL_LINK_NOARG(SdTransparencyPropertyBox, implModifyHdl, weld::MetricSpinButton&, void)
+{
+ updateMenu();
+ maModifyHdl.Call(nullptr);
+}
+
+IMPL_LINK(SdTransparencyPropertyBox, implMenuSelectHdl, const OString&, rIdent, void)
+{
+ auto nValue = rIdent.toInt32();
+ if (nValue != mxMetric->get_value(FieldUnit::PERCENT))
+ {
+ mxMetric->set_value(nValue, FieldUnit::PERCENT);
+ implModifyHdl(*mxMetric);
+ }
+}
+
+void SdTransparencyPropertyBox::setValue(const Any& rValue, const OUString&)
+{
+ if (mxMetric)
+ {
+ double fValue = 0.0;
+ rValue >>= fValue;
+ ::tools::Long nValue = static_cast<::tools::Long>(fValue * 100);
+ mxMetric->set_value(nValue, FieldUnit::PERCENT);
+ updateMenu();
+ }
+}
+
+Any SdTransparencyPropertyBox::getValue()
+{
+ return Any(static_cast<double>(mxMetric->get_value(FieldUnit::PERCENT)) / 100.0);
+}
+
+namespace {
+
+class SdRotationPropertyBox : public SdPropertySubControl
+{
+public:
+ SdRotationPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
+
+ virtual Any getValue() override;
+ virtual void setValue( const Any& rValue, const OUString& ) override;
+
+ DECL_LINK(implMenuSelectHdl, const OString&, void);
+ DECL_LINK(implModifyHdl, weld::MetricSpinButton&, void);
+
+ void updateMenu();
+
+private:
+ Link<LinkParamNone*,void> maModifyHdl;
+
+ std::unique_ptr<weld::MetricSpinButton> mxMetric;
+ std::unique_ptr<weld::MenuButton> mxControl;
+};
+
+}
+
+SdRotationPropertyBox::SdRotationPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
+ : SdPropertySubControl(pParent)
+ , maModifyHdl(rModifyHdl)
+ , mxMetric(mxBuilder->weld_metric_spin_button("rotate", FieldUnit::DEGREE))
+ , mxControl(mxBuilder->weld_menu_button("rotatemenu"))
+{
+ mxMetric->connect_value_changed(LINK( this, SdRotationPropertyBox, implModifyHdl));
+ mxMetric->set_help_id(HID_SD_CUSTOMANIMATIONPANE_ROTATIONPROPERTYBOX);
+ mxMetric->show();
+ pLabel->set_mnemonic_widget(&mxMetric->get_widget());
+
+ mxControl->connect_selected(LINK(this, SdRotationPropertyBox, implMenuSelectHdl));
+ mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_ROTATIONPROPERTYBOX);
+ mxControl->show();
+
+ setValue(rValue, OUString());
+}
+
+void SdRotationPropertyBox::updateMenu()
+{
+ sal_Int64 nValue = mxMetric->get_value(FieldUnit::DEGREE);
+ bool bDirection = nValue >= 0;
+ nValue = (nValue < 0 ? -nValue : nValue);
+
+ mxControl->set_item_active("90", nValue == 90);
+ mxControl->set_item_active("180", nValue == 180);
+ mxControl->set_item_active("360", nValue == 360);
+ mxControl->set_item_active("720", nValue == 720);
+
+ mxControl->set_item_active("closewise", bDirection);
+ mxControl->set_item_active("counterclock", !bDirection);
+}
+
+IMPL_LINK_NOARG(SdRotationPropertyBox, implModifyHdl, weld::MetricSpinButton&, void)
+{
+ updateMenu();
+ maModifyHdl.Call(nullptr);
+}
+
+IMPL_LINK(SdRotationPropertyBox, implMenuSelectHdl, const OString&, rIdent, void)
+{
+ auto nValue = mxMetric->get_value(FieldUnit::DEGREE);
+ bool bDirection = nValue >= 0;
+ nValue = (nValue < 0 ? -nValue : nValue);
+
+ if (rIdent == "clockwise")
+ bDirection = true;
+ else if (rIdent == "counterclock")
+ bDirection = false;
+ else
+ nValue = rIdent.toInt32();
+
+ if( !bDirection )
+ nValue = -nValue;
+
+ if (nValue != mxMetric->get_value(FieldUnit::DEGREE))
+ {
+ mxMetric->set_value(nValue, FieldUnit::DEGREE);
+ implModifyHdl(*mxMetric);
+ }
+}
+
+void SdRotationPropertyBox::setValue( const Any& rValue, const OUString& )
+{
+ if (mxMetric)
+ {
+ double fValue = 0.0;
+ rValue >>= fValue;
+ ::tools::Long nValue = static_cast<::tools::Long>(fValue);
+ mxMetric->set_value(nValue, FieldUnit::DEGREE);
+ updateMenu();
+ }
+}
+
+Any SdRotationPropertyBox::getValue()
+{
+ return Any(static_cast<double>(mxMetric->get_value(FieldUnit::DEGREE)));
+}
+
+namespace {
+
+class SdScalePropertyBox : public SdPropertySubControl
+{
+public:
+ SdScalePropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
+
+ virtual Any getValue() override;
+ virtual void setValue( const Any& rValue, const OUString& ) override;
+
+ DECL_LINK(implMenuSelectHdl, const OString&, void);
+ DECL_LINK(implModifyHdl, weld::MetricSpinButton&, void);
+
+ void updateMenu();
+
+private:
+ Link<LinkParamNone*,void> maModifyHdl;
+ int mnDirection;
+
+ std::unique_ptr<weld::MetricSpinButton> mxMetric;
+ std::unique_ptr<weld::MenuButton> mxControl;
+};
+
+}
+
+SdScalePropertyBox::SdScalePropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
+ : SdPropertySubControl(pParent)
+ , maModifyHdl( rModifyHdl )
+ , mxMetric(mxBuilder->weld_metric_spin_button("scale", FieldUnit::PERCENT))
+ , mxControl(mxBuilder->weld_menu_button("scalemenu"))
+{
+ mxControl->connect_selected(LINK(this, SdScalePropertyBox, implMenuSelectHdl));
+ mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_SCALEPROPERTYBOX);
+ mxControl->show();
+
+ mxMetric->connect_value_changed(LINK(this, SdScalePropertyBox, implModifyHdl));
+ mxMetric->set_help_id(HID_SD_CUSTOMANIMATIONPANE_SCALEPROPERTYBOX);
+ mxMetric->show();
+ pLabel->set_mnemonic_widget(&mxMetric->get_widget());
+
+ setValue(rValue, OUString());
+}
+
+void SdScalePropertyBox::updateMenu()
+{
+ auto nValue = mxMetric->get_value(FieldUnit::PERCENT);
+
+ mxControl->set_item_active("25scale", nValue == 25);
+ mxControl->set_item_active("50scale", nValue == 50);
+ mxControl->set_item_active("150scale", nValue == 150);
+ mxControl->set_item_active("400scale", nValue == 400);
+
+ mxControl->set_item_active("hori", mnDirection == 1);
+ mxControl->set_item_active("vert", mnDirection == 2);
+ mxControl->set_item_active("both", mnDirection == 3);
+}
+
+IMPL_LINK_NOARG(SdScalePropertyBox, implModifyHdl, weld::MetricSpinButton&, void)
+{
+ updateMenu();
+ maModifyHdl.Call(nullptr);
+}
+
+IMPL_LINK(SdScalePropertyBox, implMenuSelectHdl, const OString&, rIdent, void)
+{
+ auto nValue = mxMetric->get_value(FieldUnit::PERCENT);
+
+ int nDirection = mnDirection;
+
+ if (rIdent == "hori")
+ nDirection = 1;
+ else if (rIdent == "vert")
+ nDirection = 2;
+ else if (rIdent == "both")
+ nDirection = 3;
+ else
+ nValue = rIdent.toInt32(); // Getting here indicates a UI bug and should be handled better
+
+ bool bModified = false;
+
+ if( nDirection != mnDirection )
+ {
+ mnDirection = nDirection;
+ bModified = true;
+ }
+
+ if (nValue != mxMetric->get_value(FieldUnit::PERCENT))
+ {
+ mxMetric->set_value(nValue, FieldUnit::PERCENT);
+ bModified = true;
+ }
+
+ if(bModified)
+ {
+ implModifyHdl(*mxMetric);
+ updateMenu();
+ }
+}
+
+void SdScalePropertyBox::setValue(const Any& rValue, const OUString&)
+{
+ if (!mxMetric)
+ return;
+
+ ValuePair aValues;
+ rValue >>= aValues;
+
+ double fValue1 = 0.0;
+ double fValue2 = 0.0;
+
+ aValues.First >>= fValue1;
+ aValues.Second >>= fValue2;
+
+ // 'Size' drop down menu set by mnDirection when loading Grow and Shrink Animation
+ // Shouldn't compare a float directly to zero... should be fixed with delta epsilon compare
+ // Might be better to just have a flag in the content.xml for this
+ if( (fValue1 == 0.0) && (fValue2 == 0.0) )
+ mnDirection = 3; // assume 'Both' scaling option when both are zero
+ else if( (fValue1 != 0.0) && (fValue2 == 0.0) )
+ mnDirection = 1;
+ else if( (fValue1 == 0.0) && (fValue2 != 0.0) )
+ mnDirection = 2;
+ else
+ mnDirection = 3;
+
+ // Grow and Shrink Animation is a relative change with value stored in content.xml under tag
+ // smil:by=*,*
+ // An offset of 1 must be added to properly translate from content.xml to UI value displayed
+ // e.g. if in content.xml smil:by=0.5,0.5 then 1 + (0.5,0.5) = (1.5,1.5) => grow by 150% of the
+ // size horizontal and vertical
+ // e.g. if in content.xml smil:by=-0.5,-0.5 then 1 + (-0.5,-0.5) = (0.5,0.5) => shrink by 50%
+ // of the size horizontal and vertical
+ fValue1 += 1;
+ fValue2 += 1;
+
+ // Determine value from file for UI 'Size' field based on determined mnDirection
+ ::tools::Long nValue;
+ if( mnDirection == 1 )
+ nValue = static_cast<::tools::Long>(fValue1 * 100.0);
+ else if( mnDirection == 2 )
+ nValue = static_cast<::tools::Long>(fValue2 * 100.0);
+ else if( mnDirection == 3 ){
+ if (fValue1 >= fValue2)
+ nValue = static_cast<::tools::Long>(fValue1 * 100.0);
+ else
+ nValue = static_cast<::tools::Long>(fValue2 * 100.0);
+ }
+ else
+ nValue = static_cast<::tools::Long>(100.0); // default to 100% in UI if something goes wrong
+
+ mxMetric->set_value(nValue, FieldUnit::PERCENT);
+ updateMenu();
+}
+
+Any SdScalePropertyBox::getValue()
+{
+ double fValue1 = static_cast<double>(mxMetric->get_value(FieldUnit::PERCENT)) / 100.0;
+
+ // Grow and Shrink Animation is a relative change with value stored in content.xml under tag
+ // smil:by=*,*
+ // An offset of 1 must be subtracted to properly translate UI value displayed and save to
+ // content.xml
+ // e.g. if UI value is 150% then 1.5 - 1 = 0.5 and is set to smil:by=0.5,0.5 in content.xml
+ // e.g. if UI value is 50% then 0.5 - 1 = -0.5 and is set to smil:by=-0.5,-0.5 in content.xml
+ fValue1 -= 1;
+
+ double fValue2 = fValue1;
+
+ // mnDirection set by 'Size' drop down menu and used to zero out either horizontal or vertical
+ // scaling depending on what option is selected
+ if( mnDirection == 1 )
+ fValue2 = 0.0;
+ else if( mnDirection == 2 )
+ fValue1 = 0.0;
+
+ ValuePair aValues;
+ aValues.First <<= fValue1;
+ aValues.Second <<= fValue2;
+
+ return Any( aValues );
+}
+
+namespace {
+
+class SdFontStylePropertyBox : public SdPropertySubControl
+{
+public:
+ SdFontStylePropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
+
+ virtual Any getValue() override;
+ virtual void setValue( const Any& rValue, const OUString& ) override;
+
+ DECL_LINK(implMenuSelectHdl, const OString&, void);
+
+ void update();
+
+private:
+ float mfFontWeight;
+ awt::FontSlant meFontSlant;
+ sal_Int16 mnFontUnderline;
+ Link<LinkParamNone*,void> maModifyHdl;
+
+ std::unique_ptr<weld::Entry> mxEdit;
+ std::unique_ptr<weld::MenuButton> mxControl;
+};
+
+}
+
+SdFontStylePropertyBox::SdFontStylePropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl )
+ : SdPropertySubControl(pParent)
+ , maModifyHdl( rModifyHdl )
+ , mxEdit(mxBuilder->weld_entry("entry"))
+ , mxControl(mxBuilder->weld_menu_button("entrymenu"))
+{
+ mxEdit->set_text(SdResId(STR_CUSTOMANIMATION_SAMPLE));
+ mxEdit->set_help_id(HID_SD_CUSTOMANIMATIONPANE_FONTSTYLEPROPERTYBOX);
+ pLabel->set_mnemonic_widget(mxEdit.get());
+ mxEdit->show();
+
+ mxControl->connect_selected(LINK(this, SdFontStylePropertyBox, implMenuSelectHdl));
+ mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_FONTSTYLEPROPERTYBOX);
+ mxControl->show();
+
+ setValue(rValue, OUString());
+}
+
+void SdFontStylePropertyBox::update()
+{
+ // update menu
+ mxControl->set_item_active("bold", mfFontWeight == awt::FontWeight::BOLD);
+ mxControl->set_item_active("italic", meFontSlant == awt::FontSlant_ITALIC);
+ mxControl->set_item_active("underline", mnFontUnderline != awt::FontUnderline::NONE );
+
+ // update sample edit
+ vcl::Font aFont(mxEdit->get_font());
+ aFont.SetWeight(mfFontWeight == awt::FontWeight::BOLD ? WEIGHT_BOLD : WEIGHT_NORMAL);
+ aFont.SetItalic(meFontSlant == awt::FontSlant_ITALIC ? ITALIC_NORMAL : ITALIC_NONE);
+ aFont.SetUnderline(mnFontUnderline == awt::FontUnderline::NONE ? LINESTYLE_NONE : LINESTYLE_SINGLE);
+ mxEdit->set_font(aFont);
+}
+
+IMPL_LINK(SdFontStylePropertyBox, implMenuSelectHdl, const OString&, rIdent, void)
+{
+ if (rIdent == "bold")
+ {
+ if( mfFontWeight == awt::FontWeight::BOLD )
+ mfFontWeight = awt::FontWeight::NORMAL;
+ else
+ mfFontWeight = awt::FontWeight::BOLD;
+ }
+ else if (rIdent == "italic")
+ {
+ if( meFontSlant == awt::FontSlant_ITALIC )
+ meFontSlant = awt::FontSlant_NONE;
+ else
+ meFontSlant = awt::FontSlant_ITALIC;
+ }
+ else if (rIdent == "underline")
+ {
+ if( mnFontUnderline == awt::FontUnderline::SINGLE )
+ mnFontUnderline = awt::FontUnderline::NONE;
+ else
+ mnFontUnderline = awt::FontUnderline::SINGLE;
+ }
+
+ update();
+ maModifyHdl.Call(nullptr);
+}
+
+void SdFontStylePropertyBox::setValue( const Any& rValue, const OUString& )
+{
+ Sequence<Any> aValues;
+ rValue >>= aValues;
+
+ aValues[0] >>= mfFontWeight;
+ aValues[1] >>= meFontSlant;
+ aValues[2] >>= mnFontUnderline;
+
+ update();
+}
+
+Any SdFontStylePropertyBox::getValue()
+{
+ Sequence<Any> aValues{ Any(mfFontWeight), Any(meFontSlant), Any(mnFontUnderline) };
+ return Any( aValues );
+}
+
+class CustomAnimationEffectTabPage
+{
+public:
+ CustomAnimationEffectTabPage(weld::Container* pParent, weld::Window* pDialog, const STLPropertySet* pSet);
+
+ void update( STLPropertySet* pSet );
+ DECL_LINK(implSelectHdl, weld::ComboBox&, void);
+ DECL_LINK(implClickHdl, weld::Button&, void);
+ void implHdl(const weld::Widget*);
+
+private:
+ void updateControlStates();
+ void fillSoundListBox();
+ void clearSoundListBox();
+ sal_Int32 getSoundObject( std::u16string_view rStr );
+ void openSoundFileDialog();
+ void onSoundPreview();
+ weld::Window* GetFrameWeld() const { return mpDialog; }
+
+private:
+ ::std::vector< OUString > maSoundList;
+ bool mbHasText;
+ const STLPropertySet* mpSet;
+ css::uno::Reference<css::media::XPlayer> mxPlayer;
+
+ weld::Window* mpDialog;
+ std::unique_ptr<weld::Builder> mxBuilder;
+ std::unique_ptr<weld::Container> mxContainer;
+ std::unique_ptr<weld::Widget> mxSettings;
+ std::unique_ptr<weld::Label> mxFTProperty1;
+ std::unique_ptr<weld::Container> mxPlaceholderBox;
+ std::unique_ptr<weld::CheckButton> mxCBSmoothStart;
+ std::unique_ptr<weld::CheckButton> mxCBSmoothEnd;
+ std::unique_ptr<weld::Label> mxFTSound;
+ std::unique_ptr<weld::ComboBox> mxLBSound;
+ std::unique_ptr<weld::Button> mxPBSoundPreview;
+ std::unique_ptr<weld::Label> mxFTAfterEffect;
+ std::unique_ptr<weld::ComboBox> mxLBAfterEffect;
+ std::unique_ptr<weld::Label> mxFTDimColor;
+ std::unique_ptr<ColorListBox> mxCLBDimColor;
+ std::unique_ptr<weld::Label> mxFTTextAnim;
+ std::unique_ptr<weld::ComboBox> mxLBTextAnim;
+ std::unique_ptr<weld::MetricSpinButton> mxMFTextDelay;
+ std::unique_ptr<weld::Label> mxFTTextDelay;
+ std::unique_ptr<SdPropertySubControl> mxLBSubControl;
+};
+
+CustomAnimationEffectTabPage::CustomAnimationEffectTabPage(weld::Container* pParent, weld::Window* pDialog, const STLPropertySet* pSet)
+ : mbHasText(false)
+ , mpSet(pSet)
+ , mpDialog(pDialog)
+ , mxBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/customanimationeffecttab.ui"))
+ , mxContainer(mxBuilder->weld_container("EffectTab"))
+ , mxSettings(mxBuilder->weld_widget("settings"))
+ , mxFTProperty1(mxBuilder->weld_label("prop_label1"))
+ , mxPlaceholderBox(mxBuilder->weld_container("placeholder"))
+ , mxCBSmoothStart(mxBuilder->weld_check_button("smooth_start"))
+ , mxCBSmoothEnd(mxBuilder->weld_check_button("smooth_end"))
+ , mxFTSound(mxBuilder->weld_label("sound_label"))
+ , mxLBSound(mxBuilder->weld_combo_box("sound_list"))
+ , mxPBSoundPreview(mxBuilder->weld_button("sound_preview"))
+ , mxFTAfterEffect(mxBuilder->weld_label("aeffect_label"))
+ , mxLBAfterEffect(mxBuilder->weld_combo_box("aeffect_list"))
+ , mxFTDimColor(mxBuilder->weld_label("dim_color_label"))
+ , mxCLBDimColor(new ColorListBox(mxBuilder->weld_menu_button("dim_color_list"), [pDialog]{ return pDialog; }))
+ , mxFTTextAnim(mxBuilder->weld_label("text_animation_label"))
+ , mxLBTextAnim(mxBuilder->weld_combo_box("text_animation_list"))
+ , mxMFTextDelay(mxBuilder->weld_metric_spin_button("text_delay", FieldUnit::PERCENT))
+ , mxFTTextDelay(mxBuilder->weld_label("text_delay_label"))
+{
+ mxCLBDimColor->SelectEntry(COL_BLACK);
+
+ // fill the soundbox
+ fillSoundListBox();
+
+ mxLBSound->connect_changed(LINK(this, CustomAnimationEffectTabPage, implSelectHdl));
+ mxPBSoundPreview->connect_clicked(LINK(this, CustomAnimationEffectTabPage, implClickHdl));
+
+ // only show settings if all selected effects have the same preset-id
+ if( pSet->getPropertyState( nHandlePresetId ) != STLPropertyState::Ambiguous )
+ {
+ OUString aPresetId;
+ pSet->getPropertyValue( nHandlePresetId ) >>= aPresetId;
+
+ // property 1
+
+ if( pSet->getPropertyState( nHandleProperty1Type ) != STLPropertyState::Ambiguous )
+ {
+ sal_Int32 nType = 0;
+ pSet->getPropertyValue( nHandleProperty1Type ) >>= nType;
+
+ if( nType != nPropertyTypeNone )
+ {
+ // set ui name for property at fixed text
+ OUString aPropertyName( getPropertyName( nType ) );
+
+ if( !aPropertyName.isEmpty() )
+ {
+ mxSettings->show();
+ mxFTProperty1->set_label(aPropertyName);
+ }
+
+ // get property value
+ const Any aValue( pSet->getPropertyValue( nHandleProperty1Value ) );
+
+ // create property sub control
+ mxLBSubControl = SdPropertySubControl::create(nType, mxFTProperty1.get(), mxPlaceholderBox.get(), mpDialog, aValue, aPresetId, Link<LinkParamNone*,void>());
+ }
+ }
+
+ mxFTProperty1->set_sensitive(mxPlaceholderBox->get_sensitive());
+
+ // accelerate & decelerate
+
+ if( pSet->getPropertyState( nHandleAccelerate ) == STLPropertyState::Direct )
+ {
+ mxCBSmoothStart->show();
+ mxCBSmoothEnd->show();
+
+ double fTemp = 0.0;
+ pSet->getPropertyValue( nHandleAccelerate ) >>= fTemp;
+ mxCBSmoothStart->set_active( fTemp > 0.0 );
+
+ pSet->getPropertyValue( nHandleDecelerate ) >>= fTemp;
+ mxCBSmoothEnd->set_active( fTemp > 0.0 );
+ }
+ }
+
+ // init after effect controls
+
+ mxLBAfterEffect->connect_changed(LINK(this, CustomAnimationEffectTabPage, implSelectHdl));
+ mxLBTextAnim->connect_changed(LINK(this, CustomAnimationEffectTabPage, implSelectHdl));
+
+ if( (pSet->getPropertyState( nHandleHasAfterEffect ) != STLPropertyState::Ambiguous) &&
+ (pSet->getPropertyState( nHandleAfterEffectOnNextEffect ) != STLPropertyState::Ambiguous) &&
+ (pSet->getPropertyState( nHandleDimColor ) != STLPropertyState::Ambiguous))
+ {
+ bool bHasAfterEffect = false;
+ pSet->getPropertyValue( nHandleHasAfterEffect ) >>= bHasAfterEffect;
+
+ sal_Int32 nPos = 0;
+ if( bHasAfterEffect )
+ {
+ nPos++;
+
+ bool bAfterEffectOnNextClick = false;
+ pSet->getPropertyValue( nHandleAfterEffectOnNextEffect ) >>= bAfterEffectOnNextClick;
+ Any aDimColor( pSet->getPropertyValue( nHandleDimColor ) );
+
+ if( aDimColor.hasValue() )
+ {
+ Color aColor;
+ aDimColor >>= aColor;
+ mxCLBDimColor->SelectEntry(aColor);
+ }
+ else
+ {
+ nPos++;
+ if( bAfterEffectOnNextClick )
+ nPos++;
+ }
+ }
+
+ mxLBAfterEffect->set_active(nPos);
+ }
+
+ if( pSet->getPropertyState( nHandleHasText ) != STLPropertyState::Ambiguous )
+ pSet->getPropertyValue( nHandleHasText ) >>= mbHasText;
+
+ if( mbHasText )
+ {
+ if( pSet->getPropertyState( nHandleIterateType ) != STLPropertyState::Ambiguous)
+ {
+ int nPos = -1;
+
+ sal_Int32 nIterateType = 0;
+ pSet->getPropertyValue( nHandleIterateType ) >>= nIterateType;
+ switch( nIterateType )
+ {
+ case TextAnimationType::BY_PARAGRAPH: nPos = 0; break;
+ case TextAnimationType::BY_WORD: nPos = 1; break;
+ case TextAnimationType::BY_LETTER: nPos = 2; break;
+ }
+
+ mxLBTextAnim->set_active(nPos);
+ }
+
+ if( pSet->getPropertyState( nHandleIterateInterval ) != STLPropertyState::Default )
+ {
+ double fIterateInterval = 0.0;
+ pSet->getPropertyValue( nHandleIterateInterval ) >>= fIterateInterval;
+ mxMFTextDelay->set_value(static_cast<::tools::Long>(fIterateInterval*10), FieldUnit::NONE);
+ }
+ }
+ else
+ {
+ mxFTTextAnim->set_sensitive(false);
+ mxLBTextAnim->set_sensitive(false);
+ mxMFTextDelay->set_sensitive(false);
+ mxFTTextDelay->set_sensitive(false);
+
+ }
+
+ if( pSet->getPropertyState( nHandleSoundURL ) != STLPropertyState::Ambiguous )
+ {
+ sal_Int32 nPos = 0;
+
+ const Any aValue( pSet->getPropertyValue( nHandleSoundURL ) );
+
+ if( aValue.getValueType() == ::cppu::UnoType<sal_Bool>::get() )
+ {
+ nPos = 1;
+ }
+ else
+ {
+ OUString aSoundURL;
+ aValue >>= aSoundURL;
+
+ if( !aSoundURL.isEmpty() )
+ {
+ sal_uLong i;
+ for( i = 0; i < maSoundList.size(); i++ )
+ {
+ OUString aString = maSoundList[ i ];
+ if( aString == aSoundURL )
+ {
+ nPos = static_cast<sal_Int32>(i)+2;
+ break;
+ }
+ }
+
+ if( nPos == 0 )
+ {
+ nPos = static_cast<sal_Int32>(maSoundList.size())+2;
+ maSoundList.push_back( aSoundURL );
+ INetURLObject aURL( aSoundURL );
+ mxLBSound->insert_text(nPos, aURL.GetBase());
+ }
+ }
+ }
+
+ if( nPos != -1)
+ mxLBSound->set_active(nPos);
+ }
+
+ updateControlStates();
+
+}
+
+void CustomAnimationEffectTabPage::updateControlStates()
+{
+ auto nPos = mxLBAfterEffect->get_active();
+ mxCLBDimColor->set_sensitive( nPos == 1 );
+ mxFTDimColor->set_sensitive( nPos == 1 );
+
+ if( mbHasText )
+ {
+ nPos = mxLBTextAnim->get_active();
+ mxMFTextDelay->set_sensitive( nPos != 0 );
+ mxFTTextDelay->set_sensitive( nPos != 0 );
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ mxFTSound->hide();
+ mxLBSound->hide();
+ mxPBSoundPreview->hide();
+ }
+ else
+ {
+ nPos = mxLBSound->get_active();
+ mxPBSoundPreview->set_sensitive( nPos >= 2 );
+ }
+
+}
+
+IMPL_LINK(CustomAnimationEffectTabPage, implClickHdl, weld::Button&, rBtn, void)
+{
+ implHdl(&rBtn);
+}
+
+IMPL_LINK(CustomAnimationEffectTabPage, implSelectHdl, weld::ComboBox&, rListBox, void)
+{
+ implHdl(&rListBox);
+}
+
+void CustomAnimationEffectTabPage::implHdl(const weld::Widget* pControl)
+{
+ if (pControl == mxLBTextAnim.get())
+ {
+ if (mxMFTextDelay->get_value(FieldUnit::NONE) == 0)
+ mxMFTextDelay->set_value(100, FieldUnit::NONE);
+ }
+ else if (pControl == mxLBSound.get())
+ {
+ auto nPos = mxLBSound->get_active();
+ if (nPos == (mxLBSound->get_count() - 1))
+ {
+ openSoundFileDialog();
+ }
+ }
+ else if (pControl == mxPBSoundPreview.get())
+ {
+ onSoundPreview();
+ }
+
+ updateControlStates();
+}
+
+void CustomAnimationEffectTabPage::update( STLPropertySet* pSet )
+{
+ if (mxLBSubControl)
+ {
+ Any aNewValue(mxLBSubControl->getValue());
+ Any aOldValue;
+ if( mpSet->getPropertyState( nHandleProperty1Value ) != STLPropertyState::Ambiguous)
+ aOldValue = mpSet->getPropertyValue( nHandleProperty1Value );
+
+ if( aOldValue != aNewValue )
+ pSet->setPropertyValue( nHandleProperty1Value, aNewValue );
+ }
+
+ if (mxCBSmoothStart->get_visible())
+ {
+ // set selected value for accelerate if different than in original set
+
+ double fTemp = mxCBSmoothStart->get_active() ? 0.5 : 0.0;
+
+ double fOldTemp = 0.0;
+ if(mpSet->getPropertyState( nHandleAccelerate ) != STLPropertyState::Ambiguous)
+ mpSet->getPropertyValue( nHandleAccelerate ) >>= fOldTemp;
+ else
+ fOldTemp = -2.0;
+
+ if( fOldTemp != fTemp )
+ pSet->setPropertyValue( nHandleAccelerate, Any( fTemp ) );
+
+ // set selected value for decelerate if different than in original set
+ fTemp = mxCBSmoothEnd->get_active() ? 0.5 : 0.0;
+
+ if(mpSet->getPropertyState( nHandleDecelerate ) != STLPropertyState::Ambiguous)
+ mpSet->getPropertyValue( nHandleDecelerate ) >>= fOldTemp;
+ else
+ fOldTemp = -2.0;
+
+ if( fOldTemp != fTemp )
+ pSet->setPropertyValue( nHandleDecelerate, Any( fTemp ) );
+ }
+
+ auto nPos = mxLBAfterEffect->get_active();
+ if (nPos != -1)
+ {
+ bool bAfterEffect = nPos != 0;
+
+ bool bOldAfterEffect = false;
+
+ if(mpSet->getPropertyState( nHandleHasAfterEffect ) != STLPropertyState::Ambiguous)
+ mpSet->getPropertyValue( nHandleHasAfterEffect ) >>= bOldAfterEffect;
+ else
+ bOldAfterEffect = !bAfterEffect;
+
+ if( bOldAfterEffect != bAfterEffect )
+ pSet->setPropertyValue( nHandleHasAfterEffect, Any( bAfterEffect ) );
+
+ Any aDimColor;
+ if( nPos == 1 )
+ {
+ Color aSelectedColor = mxCLBDimColor->GetSelectEntryColor();
+ aDimColor <<= aSelectedColor.GetRGBColor();
+ }
+
+ if( (mpSet->getPropertyState( nHandleDimColor ) == STLPropertyState::Ambiguous) ||
+ (mpSet->getPropertyValue( nHandleDimColor ) != aDimColor) )
+ pSet->setPropertyValue( nHandleDimColor, aDimColor );
+
+ bool bAfterEffectOnNextEffect = nPos != 2;
+ bool bOldAfterEffectOnNextEffect = !bAfterEffectOnNextEffect;
+
+ if( mpSet->getPropertyState( nHandleAfterEffectOnNextEffect ) != STLPropertyState::Ambiguous)
+ mpSet->getPropertyValue( nHandleAfterEffectOnNextEffect ) >>= bOldAfterEffectOnNextEffect;
+
+ if( bAfterEffectOnNextEffect != bOldAfterEffectOnNextEffect )
+ pSet->setPropertyValue( nHandleAfterEffectOnNextEffect, Any( bAfterEffectOnNextEffect ) );
+ }
+
+ nPos = mxLBTextAnim->get_active();
+ if (nPos != -1)
+ {
+ sal_Int16 nIterateType;
+
+ switch( nPos )
+ {
+ case 1: nIterateType = TextAnimationType::BY_WORD; break;
+ case 2: nIterateType = TextAnimationType::BY_LETTER; break;
+ default:
+ nIterateType = TextAnimationType::BY_PARAGRAPH;
+ }
+
+ sal_Int16 nOldIterateType = nIterateType-1;
+
+ if(mpSet->getPropertyState( nHandleIterateType ) != STLPropertyState::Ambiguous)
+ mpSet->getPropertyValue( nHandleIterateType ) >>= nOldIterateType;
+
+ if( nIterateType != nOldIterateType )
+ pSet->setPropertyValue( nHandleIterateType, Any( nIterateType ) );
+ }
+
+ {
+ double fIterateInterval = static_cast<double>(mxMFTextDelay->get_value(FieldUnit::NONE)) / 10;
+ double fOldIterateInterval = -1.0;
+
+ if( mpSet->getPropertyState( nHandleIterateInterval ) != STLPropertyState::Ambiguous )
+ mpSet->getPropertyValue( nHandleIterateInterval ) >>= fOldIterateInterval;
+
+ if( fIterateInterval != fOldIterateInterval )
+ pSet->setPropertyValue( nHandleIterateInterval, Any( fIterateInterval ) );
+ }
+
+ nPos = mxLBSound->get_active();
+ if (nPos == -1)
+ return;
+
+ Any aNewSoundURL, aOldSoundURL( Any( sal_Int32(0) ) );
+
+ if( nPos == 0 )
+ {
+ // 0 means no sound, so leave any empty
+ }
+ else if( nPos == 1 )
+ {
+ // this means stop sound
+ aNewSoundURL <<= true;
+ }
+ else
+ {
+ OUString aSoundURL( maSoundList[ nPos-2 ] );
+ aNewSoundURL <<= aSoundURL;
+ }
+
+ if( mpSet->getPropertyState( nHandleSoundURL ) != STLPropertyState::Ambiguous )
+ aOldSoundURL = mpSet->getPropertyValue( nHandleSoundURL );
+
+ if( aNewSoundURL != aOldSoundURL )
+ pSet->setPropertyValue( nHandleSoundURL, aNewSoundURL );
+}
+
+void CustomAnimationEffectTabPage::fillSoundListBox()
+{
+ GalleryExplorer::FillObjList( GALLERY_THEME_SOUNDS, maSoundList );
+ GalleryExplorer::FillObjList( GALLERY_THEME_USERSOUNDS, maSoundList );
+
+ mxLBSound->append_text( SdResId(STR_CUSTOMANIMATION_NO_SOUND) );
+ mxLBSound->append_text( SdResId(STR_CUSTOMANIMATION_STOP_PREVIOUS_SOUND) );
+ for(const OUString & rString : maSoundList)
+ {
+ INetURLObject aURL( rString );
+ mxLBSound->append_text( aURL.GetBase() );
+ }
+ mxLBSound->append_text( SdResId(STR_CUSTOMANIMATION_BROWSE_SOUND) );
+}
+
+void CustomAnimationEffectTabPage::clearSoundListBox()
+{
+ maSoundList.clear();
+ mxLBSound->clear();
+}
+
+sal_Int32 CustomAnimationEffectTabPage::getSoundObject( std::u16string_view rStr )
+{
+ size_t i;
+ const size_t nCount = maSoundList.size();
+ for( i = 0; i < nCount; i++ )
+ {
+ if( maSoundList[ i ].equalsIgnoreAsciiCase(rStr) )
+ return i+2;
+ }
+
+ return -1;
+}
+
+void CustomAnimationEffectTabPage::openSoundFileDialog()
+{
+ SdOpenSoundFileDialog aFileDialog(GetFrameWeld());
+
+ bool bValidSoundFile = false;
+ bool bQuitLoop = false;
+ ::tools::Long nPos = 0;
+
+ while( !bQuitLoop && (aFileDialog.Execute() == ERRCODE_NONE) )
+ {
+ OUString aFile = aFileDialog.GetPath();
+ nPos = getSoundObject( aFile );
+
+ if( nPos < 0 ) // not in Soundliste
+ {
+ // try to insert in Gallery
+ if( GalleryExplorer::InsertURL( GALLERY_THEME_USERSOUNDS, aFile ) )
+ {
+ clearSoundListBox();
+ fillSoundListBox();
+
+ nPos = getSoundObject( aFile );
+ DBG_ASSERT( nPos >= 0, "sd::CustomAnimationEffectTabPage::openSoundFileDialog(), Recently inserted sound not in list!" );
+
+ bValidSoundFile=true;
+ bQuitLoop=true;
+ }
+ else
+ {
+ OUString aStrWarning(SdResId(STR_WARNING_NOSOUNDFILE));
+ aStrWarning = aStrWarning.replaceFirst("%", aFile);
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::NONE,
+ aStrWarning));
+ xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
+ xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ bQuitLoop = xWarn->run() != RET_RETRY;
+
+ bValidSoundFile=false;
+ }
+ }
+ else
+ {
+ bValidSoundFile=true;
+ bQuitLoop=true;
+ }
+ }
+
+ if( !bValidSoundFile )
+ nPos = 0;
+
+ mxLBSound->set_active(nPos);
+}
+
+void CustomAnimationEffectTabPage::onSoundPreview()
+{
+#if HAVE_FEATURE_AVMEDIA
+ const auto nPos = mxLBSound->get_active();
+
+ if( nPos >= 2 ) try
+ {
+ const OUString aSoundURL( maSoundList[ nPos-2 ] );
+ mxPlayer.set( avmedia::MediaWindow::createPlayer( aSoundURL, "" ), uno::UNO_SET_THROW );
+ mxPlayer->start();
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "CustomAnimationEffectTabPage::onSoundPreview()" );
+ }
+#endif
+}
+
+class CustomAnimationDurationTabPage
+{
+public:
+ CustomAnimationDurationTabPage(weld::Container* pParent, const STLPropertySet* pSet);
+
+ void update( STLPropertySet* pSet );
+
+ DECL_LINK(implControlHdl, weld::ComboBox&, void);
+ DECL_LINK(DurationModifiedHdl, weld::MetricSpinButton&, void);
+
+private:
+ const STLPropertySet* mpSet;
+
+ std::unique_ptr<weld::Builder> mxBuilder;
+ std::unique_ptr<weld::Container> mxContainer;
+ std::unique_ptr<weld::Label> mxFTStart;
+ std::unique_ptr<weld::ComboBox> mxLBStart;
+ std::unique_ptr<weld::Label> mxFTStartDelay;
+ std::unique_ptr<weld::MetricSpinButton> mxMFStartDelay;
+ std::unique_ptr<weld::Label> mxFTDuration;
+ std::unique_ptr<weld::MetricSpinButton> mxCBXDuration;
+ std::unique_ptr<weld::Label> mxFTRepeat;
+ std::unique_ptr<weld::ComboBox> mxCBRepeat;
+ std::unique_ptr<weld::CheckButton> mxCBXRewind;
+ std::unique_ptr<weld::RadioButton> mxRBClickSequence;
+ std::unique_ptr<weld::RadioButton> mxRBInteractive;
+ std::unique_ptr<weld::ComboBox> mxLBTrigger;
+};
+
+CustomAnimationDurationTabPage::CustomAnimationDurationTabPage(weld::Container* pParent, const STLPropertySet* pSet)
+ : mpSet(pSet)
+ , mxBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/customanimationtimingtab.ui"))
+ , mxContainer(mxBuilder->weld_container("TimingTab"))
+ , mxFTStart(mxBuilder->weld_label("start_label"))
+ , mxLBStart(mxBuilder->weld_combo_box("start_list"))
+ , mxFTStartDelay(mxBuilder->weld_label("delay_label"))
+ , mxMFStartDelay(mxBuilder->weld_metric_spin_button("delay_value", FieldUnit::SECOND))
+ , mxFTDuration(mxBuilder->weld_label("duration_label"))
+ , mxCBXDuration(mxBuilder->weld_metric_spin_button("anim_duration", FieldUnit::SECOND))
+ , mxFTRepeat(mxBuilder->weld_label("repeat_label"))
+ , mxCBRepeat(mxBuilder->weld_combo_box("repeat_list"))
+ , mxCBXRewind(mxBuilder->weld_check_button("rewind"))
+ , mxRBClickSequence(mxBuilder->weld_radio_button("rb_click_sequence"))
+ , mxRBInteractive(mxBuilder->weld_radio_button("rb_interactive"))
+ , mxLBTrigger(mxBuilder->weld_combo_box("trigger_list"))
+{
+ mxLBTrigger->set_size_request(mxLBTrigger->get_approximate_digit_width() * 20, -1);
+
+ fillRepeatComboBox(*mxCBRepeat);
+
+ mxLBTrigger->connect_changed(LINK(this, CustomAnimationDurationTabPage, implControlHdl));
+ mxCBXDuration->connect_value_changed(LINK( this, CustomAnimationDurationTabPage, DurationModifiedHdl));
+
+ if( pSet->getPropertyState( nHandleStart ) != STLPropertyState::Ambiguous )
+ {
+ sal_Int16 nStart = 0;
+ pSet->getPropertyValue( nHandleStart ) >>= nStart;
+ sal_Int32 nPos = 0;
+ switch( nStart )
+ {
+ case EffectNodeType::WITH_PREVIOUS: nPos = 1; break;
+ case EffectNodeType::AFTER_PREVIOUS: nPos = 2; break;
+ }
+ mxLBStart->set_active(nPos);
+ }
+
+ if( pSet->getPropertyState( nHandleBegin ) != STLPropertyState::Ambiguous )
+ {
+ double fBegin = 0.0;
+ pSet->getPropertyValue( nHandleBegin ) >>= fBegin;
+ mxMFStartDelay->set_value(static_cast<::tools::Long>(fBegin*10), FieldUnit::NONE);
+ }
+
+ if( pSet->getPropertyState( nHandleDuration ) != STLPropertyState::Ambiguous )
+ {
+ double fDuration = 0.0;
+ pSet->getPropertyValue( nHandleDuration ) >>= fDuration;
+
+ if( fDuration == 0.001 )
+ {
+ mxFTDuration->set_sensitive(false);
+ mxCBXDuration->set_sensitive(false);
+ mxFTRepeat->set_sensitive(false);
+ mxCBRepeat->set_sensitive(false);
+ mxCBXRewind->set_sensitive(false);
+ }
+ else
+ {
+ mxCBXDuration->set_value(fDuration * 100.0, FieldUnit::NONE);
+ }
+ }
+
+ if( pSet->getPropertyState( nHandleRepeat ) != STLPropertyState::Ambiguous )
+ {
+ Any aRepeatCount( pSet->getPropertyValue( nHandleRepeat ) );
+ if( (aRepeatCount.getValueType() == ::cppu::UnoType<double>::get()) || !aRepeatCount.hasValue() )
+ {
+ double fRepeat = 0.0;
+ if( aRepeatCount.hasValue() )
+ aRepeatCount >>= fRepeat;
+
+ auto nPos = -1;
+
+ if( fRepeat == 0 )
+ nPos = 0;
+ else if( fRepeat == 2.0 )
+ nPos = 1;
+ else if( fRepeat == 3.0 )
+ nPos = 2;
+ else if( fRepeat == 4.0 )
+ nPos = 3;
+ else if( fRepeat == 5.0 )
+ nPos = 4;
+ else if( fRepeat == 10.0 )
+ nPos = 5;
+
+ if (nPos != -1)
+ mxCBRepeat->set_active(nPos);
+ else
+ mxCBRepeat->set_entry_text(OUString::number(fRepeat));
+ }
+ else if( aRepeatCount.getValueType() == ::cppu::UnoType<Timing>::get() )
+ {
+ Any aEnd;
+ if( pSet->getPropertyState( nHandleEnd ) != STLPropertyState::Ambiguous )
+ aEnd = pSet->getPropertyValue( nHandleEnd );
+
+ mxCBRepeat->set_active(aEnd.hasValue() ? 6 : 7);
+ }
+ }
+
+ if( pSet->getPropertyState( nHandleRewind ) != STLPropertyState::Ambiguous )
+ {
+ sal_Int16 nFill = 0;
+ if( pSet->getPropertyValue( nHandleRewind ) >>= nFill )
+ {
+ mxCBXRewind->set_active(nFill == AnimationFill::REMOVE);
+ }
+ else
+ {
+ mxCBXRewind->set_state(TRISTATE_INDET);
+ }
+ }
+
+ Reference< XShape > xTrigger;
+
+ if( pSet->getPropertyState( nHandleTrigger ) != STLPropertyState::Ambiguous )
+ {
+ pSet->getPropertyValue( nHandleTrigger ) >>= xTrigger;
+
+ mxRBInteractive->set_active(xTrigger.is());
+ mxRBClickSequence->set_active(!xTrigger.is());
+ }
+
+ Reference< XDrawPage > xCurrentPage;
+ pSet->getPropertyValue( nHandleCurrentPage ) >>= xCurrentPage;
+ if( !xCurrentPage.is() )
+ return;
+
+ static const OUStringLiteral aStrIsEmptyPresObj( u"IsEmptyPresentationObject" );
+
+ sal_Int32 nShape, nCount = xCurrentPage->getCount();
+ for( nShape = 0; nShape < nCount; nShape++ )
+ {
+ Reference< XShape > xShape( xCurrentPage->getByIndex( nShape ), UNO_QUERY );
+
+ if( !xShape.is() )
+ continue;
+
+ Reference< XPropertySet > xSet( xShape, UNO_QUERY );
+ if( xSet.is() && xSet->getPropertySetInfo()->hasPropertyByName( aStrIsEmptyPresObj ) )
+ {
+ bool bIsEmpty = false;
+ xSet->getPropertyValue( aStrIsEmptyPresObj ) >>= bIsEmpty;
+ if( bIsEmpty )
+ continue;
+ }
+
+ OUString aDescription( getShapeDescription( xShape, true ) );
+ mxLBTrigger->append(OUString::number(nShape), aDescription);
+ auto nPos = mxLBTrigger->get_count() - 1;
+ if (xShape == xTrigger)
+ mxLBTrigger->set_active(nPos);
+ }
+}
+
+IMPL_LINK_NOARG(CustomAnimationDurationTabPage, implControlHdl, weld::ComboBox&, void)
+{
+ mxRBInteractive->set_active(true);
+ assert(!mxRBClickSequence->get_active());
+}
+
+IMPL_LINK_NOARG(CustomAnimationDurationTabPage, DurationModifiedHdl, weld::MetricSpinButton&, void)
+{
+ if (!mxCBXDuration->get_text().isEmpty())
+ {
+ double duration_value = static_cast<double>(mxCBXDuration->get_value(FieldUnit::NONE));
+ if(duration_value <= 0.0)
+ mxCBXDuration->set_value(1, FieldUnit::NONE);
+ else
+ mxCBXDuration->set_value(duration_value, FieldUnit::NONE);
+ }
+}
+
+void CustomAnimationDurationTabPage::update( STLPropertySet* pSet )
+{
+ auto nPos = mxLBStart->get_active();
+ if (nPos != -1)
+ {
+ sal_Int16 nStart;
+ sal_Int16 nOldStart = -1;
+
+ switch( nPos )
+ {
+ case 1: nStart = EffectNodeType::WITH_PREVIOUS; break;
+ case 2: nStart = EffectNodeType::AFTER_PREVIOUS; break;
+ default:
+ nStart = EffectNodeType::ON_CLICK; break;
+ }
+
+ if(mpSet->getPropertyState( nHandleStart ) != STLPropertyState::Ambiguous)
+ mpSet->getPropertyValue( nHandleStart ) >>= nOldStart;
+
+ if( nStart != nOldStart )
+ pSet->setPropertyValue( nHandleStart, Any( nStart ) );
+ }
+
+ {
+ double fBegin = static_cast<double>(mxMFStartDelay->get_value(FieldUnit::NONE)) / 10.0;
+ double fOldBegin = -1.0;
+
+ if( mpSet->getPropertyState( nHandleBegin ) != STLPropertyState::Ambiguous )
+ mpSet->getPropertyValue( nHandleBegin ) >>= fOldBegin;
+
+ if( fBegin != fOldBegin )
+ pSet->setPropertyValue( nHandleBegin, Any( fBegin ) );
+ }
+
+ nPos = mxCBRepeat->get_active();
+ if (nPos != -1 || !mxCBRepeat->get_active_text().isEmpty())
+ {
+ Any aRepeatCount;
+ Any aEnd;
+
+ switch( nPos )
+ {
+ case 0:
+ break;
+
+ case 6:
+ {
+ Event aEvent;
+ aEvent.Trigger = EventTrigger::ON_NEXT;
+ aEvent.Repeat = 0;
+ aEnd <<= aEvent;
+ }
+ [[fallthrough]];
+ case 7:
+ aRepeatCount <<= Timing_INDEFINITE;
+ break;
+ default:
+ {
+ OUString aText(mxCBRepeat->get_text(nPos));
+ if( !aText.isEmpty() )
+ aRepeatCount <<= aText.toDouble();
+ }
+ }
+
+ Any aOldRepeatCount( aRepeatCount );
+ if( mpSet->getPropertyState( nHandleRepeat ) != STLPropertyState::Ambiguous )
+ aOldRepeatCount = mpSet->getPropertyValue( nHandleRepeat );
+
+ if( aRepeatCount != aOldRepeatCount )
+ pSet->setPropertyValue( nHandleRepeat, aRepeatCount );
+
+ Any aOldEnd( aEnd );
+ if( mpSet->getPropertyState( nHandleEnd ) != STLPropertyState::Ambiguous )
+ aOldEnd = mpSet->getPropertyValue( nHandleEnd );
+
+ if( aEnd != aOldEnd )
+ pSet->setPropertyValue( nHandleEnd, aEnd );
+ }
+
+ double fDuration = -1.0;
+
+ if (!mxCBXDuration->get_text().isEmpty())
+ {
+ double duration_value = static_cast<double>(mxCBXDuration->get_value(FieldUnit::NONE));
+
+ if(duration_value > 0)
+ fDuration = duration_value/100.0;
+ }
+
+ if( fDuration != -1.0 )
+ {
+ double fOldDuration = -1;
+
+ if( mpSet->getPropertyState( nHandleDuration ) != STLPropertyState::Ambiguous )
+ mpSet->getPropertyValue( nHandleDuration ) >>= fOldDuration;
+
+ if( fDuration != fOldDuration )
+ pSet->setPropertyValue( nHandleDuration, Any( fDuration ) );
+ }
+
+ if (mxCBXRewind->get_state() != TRISTATE_INDET)
+ {
+ sal_Int16 nFill = mxCBXRewind->get_active() ? AnimationFill::REMOVE : AnimationFill::HOLD;
+
+ bool bSet = true;
+
+ if( mpSet->getPropertyState( nHandleRewind ) != STLPropertyState::Ambiguous )
+ {
+ sal_Int16 nOldFill = 0;
+ mpSet->getPropertyValue( nHandleRewind ) >>= nOldFill;
+ bSet = nFill != nOldFill;
+ }
+
+ if( bSet )
+ pSet->setPropertyValue( nHandleRewind, Any( nFill ) );
+ }
+
+ Reference< XShape > xTrigger;
+
+ if (mxRBInteractive->get_active())
+ {
+ nPos = mxLBTrigger->get_active();
+ if (nPos != -1)
+ {
+ sal_Int32 nShape = mxLBTrigger->get_id(nPos).toInt32();
+
+ Reference< XDrawPage > xCurrentPage;
+ mpSet->getPropertyValue( nHandleCurrentPage ) >>= xCurrentPage;
+
+ if( xCurrentPage.is() && (nShape >= 0) && (nShape < xCurrentPage->getCount()) )
+ xCurrentPage->getByIndex( nShape ) >>= xTrigger;
+ }
+ }
+
+ if (xTrigger.is() || mxRBClickSequence->get_active())
+ {
+ Any aNewValue( xTrigger );
+ Any aOldValue;
+
+ if( mpSet->getPropertyState( nHandleTrigger ) != STLPropertyState::Ambiguous )
+ aOldValue = mpSet->getPropertyValue( nHandleTrigger );
+
+ if( aNewValue != aOldValue )
+ pSet->setPropertyValue( nHandleTrigger, aNewValue );
+ }
+}
+
+class CustomAnimationTextAnimTabPage
+{
+public:
+ CustomAnimationTextAnimTabPage(weld::Container* pParent, const STLPropertySet* pSet);
+
+ void update( STLPropertySet* pSet );
+
+ void updateControlStates();
+ DECL_LINK(implSelectHdl, weld::ComboBox&, void);
+
+private:
+ const STLPropertySet* mpSet;
+ bool mbHasVisibleShapes;
+
+ std::unique_ptr<weld::Builder> mxBuilder;
+ std::unique_ptr<weld::Container> mxContainer;
+ std::unique_ptr<weld::Label> mxFTGroupText;
+ std::unique_ptr<weld::ComboBox> mxLBGroupText;
+ std::unique_ptr<weld::CheckButton> mxCBXGroupAuto;
+ std::unique_ptr<weld::MetricSpinButton> mxMFGroupAuto;
+ std::unique_ptr<weld::CheckButton> mxCBXAnimateForm;
+ std::unique_ptr<weld::CheckButton> mxCBXReverse;
+};
+
+CustomAnimationTextAnimTabPage::CustomAnimationTextAnimTabPage(weld::Container* pParent, const STLPropertySet* pSet)
+ : mpSet(pSet)
+ , mbHasVisibleShapes(true)
+ , mxBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/customanimationtexttab.ui"))
+ , mxContainer(mxBuilder->weld_container("TextAnimationTab"))
+ , mxFTGroupText(mxBuilder->weld_label("group_text_label"))
+ , mxLBGroupText(mxBuilder->weld_combo_box("group_text_list"))
+ , mxCBXGroupAuto(mxBuilder->weld_check_button("auto_after"))
+ , mxMFGroupAuto(mxBuilder->weld_metric_spin_button("auto_after_value",FieldUnit::SECOND))
+ , mxCBXAnimateForm(mxBuilder->weld_check_button("animate_shape"))
+ , mxCBXReverse(mxBuilder->weld_check_button("reverse_order"))
+{
+ mxLBGroupText->connect_changed(LINK(this, CustomAnimationTextAnimTabPage, implSelectHdl));
+
+ if( pSet->getPropertyState( nHandleTextGrouping ) != STLPropertyState::Ambiguous )
+ {
+ sal_Int32 nTextGrouping = 0;
+ if( pSet->getPropertyValue( nHandleTextGrouping ) >>= nTextGrouping )
+ mxLBGroupText->set_active(nTextGrouping + 1);
+ }
+
+ if( pSet->getPropertyState( nHandleHasVisibleShape ) != STLPropertyState::Ambiguous )
+ pSet->getPropertyValue( nHandleHasVisibleShape ) >>= mbHasVisibleShapes;
+
+ if( pSet->getPropertyState( nHandleTextGroupingAuto ) != STLPropertyState::Ambiguous )
+ {
+ double fTextGroupingAuto = 0.0;
+ if( pSet->getPropertyValue( nHandleTextGroupingAuto ) >>= fTextGroupingAuto )
+ {
+ mxCBXGroupAuto->set_active(fTextGroupingAuto >= 0.0);
+ if( fTextGroupingAuto >= 0.0 )
+ mxMFGroupAuto->set_value(static_cast<::tools::Long>(fTextGroupingAuto*10), FieldUnit::NONE);
+ }
+ }
+ else
+ {
+ mxCBXGroupAuto->set_state( TRISTATE_INDET );
+ }
+
+ mxCBXAnimateForm->set_state( TRISTATE_INDET );
+ if( pSet->getPropertyState( nHandleAnimateForm ) != STLPropertyState::Ambiguous )
+ {
+ bool bAnimateForm = false;
+ if( pSet->getPropertyValue( nHandleAnimateForm ) >>= bAnimateForm )
+ {
+ mxCBXAnimateForm->set_active( bAnimateForm );
+ }
+ }
+ else
+ {
+ mxCBXAnimateForm->set_sensitive(false);
+ }
+
+ mxCBXReverse->set_state(TRISTATE_INDET);
+ if( pSet->getPropertyState( nHandleTextReverse ) != STLPropertyState::Ambiguous )
+ {
+ bool bTextReverse = false;
+ if( pSet->getPropertyValue( nHandleTextReverse ) >>= bTextReverse )
+ {
+ mxCBXReverse->set_active( bTextReverse );
+ }
+ }
+
+ if( pSet->getPropertyState( nHandleMaxParaDepth ) == STLPropertyState::Direct )
+ {
+ sal_Int32 nMaxParaDepth = 0;
+ pSet->getPropertyValue( nHandleMaxParaDepth ) >>= nMaxParaDepth;
+ nMaxParaDepth += 1;
+
+ sal_Int32 nPos = 6;
+ while( (nPos > 2) && (nPos > nMaxParaDepth) )
+ {
+ mxLBGroupText->remove(nPos);
+ nPos--;
+ }
+ }
+
+ updateControlStates();
+}
+
+void CustomAnimationTextAnimTabPage::update( STLPropertySet* pSet )
+{
+ auto nPos = mxLBGroupText->get_active();
+ if (nPos != -1)
+ {
+ sal_Int32 nTextGrouping = nPos - 1;
+ sal_Int32 nOldGrouping = -2;
+
+ if(mpSet->getPropertyState( nHandleTextGrouping ) != STLPropertyState::Ambiguous)
+ mpSet->getPropertyValue( nHandleTextGrouping ) >>= nOldGrouping;
+
+ if( nTextGrouping != nOldGrouping )
+ pSet->setPropertyValue( nHandleTextGrouping, Any( nTextGrouping ) );
+ }
+
+ if (nPos != 0)
+ {
+ bool bTextReverse = mxCBXReverse->get_active();
+ bool bOldTextReverse = !bTextReverse;
+
+ if(mpSet->getPropertyState( nHandleTextReverse ) != STLPropertyState::Ambiguous)
+ mpSet->getPropertyValue( nHandleTextReverse ) >>= bOldTextReverse;
+
+ if( bTextReverse != bOldTextReverse )
+ pSet->setPropertyValue( nHandleTextReverse, Any( bTextReverse ) );
+
+ if( nPos > 1 )
+ {
+ double fTextGroupingAuto = mxCBXGroupAuto->get_active() ? mxMFGroupAuto->get_value(FieldUnit::NONE) / 10.0 : -1.0;
+ double fOldTextGroupingAuto = -2.0;
+
+ if(mpSet->getPropertyState( nHandleTextGroupingAuto ) != STLPropertyState::Ambiguous)
+ mpSet->getPropertyValue( nHandleTextGroupingAuto ) >>= fOldTextGroupingAuto;
+
+ if( fTextGroupingAuto != fOldTextGroupingAuto )
+ pSet->setPropertyValue( nHandleTextGroupingAuto, Any( fTextGroupingAuto ) );
+ }
+ }
+ //#i120049# impress crashes when modifying the "Random effects" animation
+ //effect's trigger condition to "Start effect on click of".
+ //If this control is disabled, we should ignore its value
+ if (mxCBXAnimateForm->get_sensitive())
+ {
+ bool bAnimateForm = mxCBXAnimateForm->get_active();
+ bool bOldAnimateForm = !bAnimateForm;
+
+ if(mpSet->getPropertyState( nHandleAnimateForm ) != STLPropertyState::Ambiguous)
+ mpSet->getPropertyValue( nHandleAnimateForm ) >>= bOldAnimateForm;
+
+ if( bAnimateForm != bOldAnimateForm )
+ pSet->setPropertyValue( nHandleAnimateForm, Any( bAnimateForm ) );
+ }
+}
+
+void CustomAnimationTextAnimTabPage::updateControlStates()
+{
+ auto nPos = mxLBGroupText->get_active();
+
+ mxCBXGroupAuto->set_sensitive( nPos > 1 );
+ mxMFGroupAuto->set_sensitive( nPos > 1 );
+ mxCBXReverse->set_sensitive( nPos > 0 );
+
+ if( !mbHasVisibleShapes && nPos > 0 )
+ {
+ mxCBXAnimateForm->set_active(false);
+ mxCBXAnimateForm->set_sensitive(false);
+ }
+ else
+ {
+ mxCBXAnimateForm->set_sensitive(true);
+ }
+}
+
+IMPL_LINK_NOARG(CustomAnimationTextAnimTabPage, implSelectHdl, weld::ComboBox&, void)
+{
+ updateControlStates();
+}
+
+CustomAnimationDialog::CustomAnimationDialog(weld::Window* pParent, std::unique_ptr<STLPropertySet> pSet, const OString& rPage)
+ : GenericDialogController(pParent, "modules/simpress/ui/customanimationproperties.ui", "CustomAnimationProperties")
+ , mxSet(std::move(pSet))
+ , mxTabControl(m_xBuilder->weld_notebook("tabcontrol"))
+ , mxDurationTabPage(new CustomAnimationDurationTabPage(mxTabControl->get_page("timing"), mxSet.get()))
+ , mxEffectTabPage(new CustomAnimationEffectTabPage(mxTabControl->get_page("effect"), m_xDialog.get(), mxSet.get()))
+{
+ bool bHasText = false;
+ if( mxSet->getPropertyState( nHandleHasText ) != STLPropertyState::Ambiguous )
+ mxSet->getPropertyValue( nHandleHasText ) >>= bHasText;
+
+ if( bHasText )
+ {
+ mxTextAnimTabPage.reset(new CustomAnimationTextAnimTabPage(mxTabControl->get_page("textanim"), mxSet.get()));
+ }
+ else
+ {
+ mxTabControl->remove_page("textanim");
+ }
+
+ if (!rPage.isEmpty())
+ mxTabControl->set_current_page(rPage);
+}
+
+CustomAnimationDialog::~CustomAnimationDialog()
+{
+}
+
+STLPropertySet* CustomAnimationDialog::getResultSet()
+{
+ mxResultSet = createDefaultSet();
+
+ mxEffectTabPage->update( mxResultSet.get() );
+ mxDurationTabPage->update( mxResultSet.get() );
+ if (mxTextAnimTabPage)
+ mxTextAnimTabPage->update( mxResultSet.get() );
+
+ return mxResultSet.get();
+}
+
+std::unique_ptr<STLPropertySet> CustomAnimationDialog::createDefaultSet()
+{
+ Any aEmpty;
+
+ std::unique_ptr<STLPropertySet> pSet(new STLPropertySet());
+ pSet->setPropertyDefaultValue( nHandleMaxParaDepth, Any( sal_Int32(-1) ) );
+
+ pSet->setPropertyDefaultValue( nHandleHasAfterEffect, Any( false ) );
+ pSet->setPropertyDefaultValue( nHandleAfterEffectOnNextEffect, Any( false ) );
+ pSet->setPropertyDefaultValue( nHandleDimColor, aEmpty );
+ pSet->setPropertyDefaultValue( nHandleIterateType, Any( sal_Int16(0) ) );
+ pSet->setPropertyDefaultValue( nHandleIterateInterval, Any( 0.0 ) );
+
+ pSet->setPropertyDefaultValue( nHandleStart, Any( sal_Int16(EffectNodeType::ON_CLICK) ) );
+ pSet->setPropertyDefaultValue( nHandleBegin, Any( 0.0 ) );
+ pSet->setPropertyDefaultValue( nHandleDuration, Any( 2.0 ) );
+ pSet->setPropertyDefaultValue( nHandleRepeat, aEmpty );
+ pSet->setPropertyDefaultValue( nHandleRewind, Any( AnimationFill::HOLD ) );
+
+ pSet->setPropertyDefaultValue( nHandleEnd, aEmpty );
+
+ pSet->setPropertyDefaultValue( nHandlePresetId, aEmpty );
+ pSet->setPropertyDefaultValue( nHandleProperty1Type, Any( nPropertyTypeNone ) );
+ pSet->setPropertyDefaultValue( nHandleProperty1Value, aEmpty );
+ pSet->setPropertyDefaultValue( nHandleProperty2Type, Any( nPropertyTypeNone ) );
+ pSet->setPropertyDefaultValue( nHandleProperty2Value, aEmpty );
+ pSet->setPropertyDefaultValue( nHandleAccelerate, aEmpty );
+ pSet->setPropertyDefaultValue( nHandleDecelerate, aEmpty );
+ pSet->setPropertyDefaultValue( nHandleAutoReverse, aEmpty );
+ pSet->setPropertyDefaultValue( nHandleTrigger, aEmpty );
+
+ pSet->setPropertyDefaultValue( nHandleHasText, Any( false ) );
+ pSet->setPropertyDefaultValue( nHandleHasVisibleShape, Any( false ) );
+ pSet->setPropertyDefaultValue( nHandleTextGrouping, Any( sal_Int32(-1) ) );
+ pSet->setPropertyDefaultValue( nHandleAnimateForm, Any( true ) );
+ pSet->setPropertyDefaultValue( nHandleTextGroupingAuto, Any( -1.0 ) );
+ pSet->setPropertyDefaultValue( nHandleTextReverse, Any( false ) );
+
+ pSet->setPropertyDefaultValue( nHandleCurrentPage, aEmpty );
+
+ pSet->setPropertyDefaultValue( nHandleSoundURL, aEmpty );
+ pSet->setPropertyDefaultValue( nHandleSoundVolume, Any( 1.0) );
+ pSet->setPropertyDefaultValue( nHandleSoundEndAfterSlide, Any( sal_Int32(0) ) );
+
+ pSet->setPropertyDefaultValue( nHandleCommand, Any( sal_Int16(0) ) );
+ return pSet;
+}
+
+std::unique_ptr<SdPropertySubControl> SdPropertySubControl::create(sal_Int32 nType, weld::Label* pLabel, weld::Container* pParent, weld::Window* pTopLevel, const Any& rValue, const OUString& rPresetId, const Link<LinkParamNone*,void>& rModifyHdl)
+{
+ std::unique_ptr<SdPropertySubControl> pSubControl;
+ switch( nType )
+ {
+ case nPropertyTypeDirection:
+ case nPropertyTypeSpokes:
+ case nPropertyTypeZoom:
+ pSubControl.reset( new SdPresetPropertyBox( pLabel, pParent, rValue, rPresetId, rModifyHdl ) );
+ break;
+
+ case nPropertyTypeColor:
+ case nPropertyTypeFillColor:
+ case nPropertyTypeFirstColor:
+ case nPropertyTypeCharColor:
+ case nPropertyTypeLineColor:
+ pSubControl.reset( new SdColorPropertyBox( pLabel, pParent, pTopLevel, rValue, rModifyHdl ) );
+ break;
+
+ case nPropertyTypeFont:
+ pSubControl.reset( new SdFontPropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
+ break;
+
+ case nPropertyTypeCharHeight:
+ pSubControl.reset( new SdCharHeightPropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
+ break;
+
+ case nPropertyTypeRotate:
+ pSubControl.reset( new SdRotationPropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
+ break;
+
+ case nPropertyTypeTransparency:
+ pSubControl.reset( new SdTransparencyPropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
+ break;
+
+ case nPropertyTypeScale:
+ pSubControl.reset( new SdScalePropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
+ break;
+
+ case nPropertyTypeCharDecoration:
+ pSubControl.reset( new SdFontStylePropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
+ break;
+ }
+
+ return pSubControl;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/animations/CustomAnimationDialog.hxx b/sd/source/ui/animations/CustomAnimationDialog.hxx
new file mode 100644
index 000000000..b8a8abcff
--- /dev/null
+++ b/sd/source/ui/animations/CustomAnimationDialog.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 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+namespace sd {
+
+// property handles
+const sal_Int32 nHandleSound = 0;
+const sal_Int32 nHandleHasAfterEffect = 1;
+const sal_Int32 nHandleIterateType = 2;
+const sal_Int32 nHandleIterateInterval = 3;
+const sal_Int32 nHandleStart = 4;
+const sal_Int32 nHandleBegin = 5;
+const sal_Int32 nHandleDuration = 6;
+const sal_Int32 nHandleRepeat = 7;
+const sal_Int32 nHandleRewind = 8;
+const sal_Int32 nHandleEnd = 9;
+const sal_Int32 nHandleAfterEffectOnNextEffect = 10;
+const sal_Int32 nHandleDimColor = 11;
+const sal_Int32 nHandleMaxParaDepth = 12;
+const sal_Int32 nHandlePresetId = 13;
+const sal_Int32 nHandleProperty1Type = 14;
+const sal_Int32 nHandleProperty1Value = 15;
+const sal_Int32 nHandleProperty2Type = 16;
+const sal_Int32 nHandleProperty2Value = 17;
+
+const sal_Int32 nHandleAccelerate = 18;
+const sal_Int32 nHandleDecelerate = 19;
+const sal_Int32 nHandleAutoReverse = 20;
+const sal_Int32 nHandleTrigger = 21;
+
+const sal_Int32 nHandleHasText = 22;
+const sal_Int32 nHandleTextGrouping = 23;
+const sal_Int32 nHandleAnimateForm = 24;
+const sal_Int32 nHandleTextGroupingAuto = 25;
+const sal_Int32 nHandleTextReverse = 26;
+
+const sal_Int32 nHandleCurrentPage = 27;
+const sal_Int32 nHandleSoundURL = 28;
+const sal_Int32 nHandleSoundVolume = 29;
+const sal_Int32 nHandleSoundEndAfterSlide = 30;
+
+const sal_Int32 nHandleCommand = 31;
+
+const sal_Int32 nHandleHasVisibleShape = 32;
+
+const sal_Int32 nPropertyTypeNone = 0;
+const sal_Int32 nPropertyTypeDirection = 1;
+const sal_Int32 nPropertyTypeSpokes = 2;
+const sal_Int32 nPropertyTypeFirstColor = 3;
+const sal_Int32 nPropertyTypeSecondColor = 4;
+const sal_Int32 nPropertyTypeZoom = 5;
+const sal_Int32 nPropertyTypeFillColor = 6;
+const sal_Int32 nPropertyTypeColorStyle = 7;
+const sal_Int32 nPropertyTypeFont = 8;
+const sal_Int32 nPropertyTypeCharHeight = 9;
+const sal_Int32 nPropertyTypeCharColor = 10;
+const sal_Int32 nPropertyTypeCharHeightStyle = 11;
+const sal_Int32 nPropertyTypeCharDecoration = 12;
+const sal_Int32 nPropertyTypeLineColor = 13;
+const sal_Int32 nPropertyTypeRotate = 14;
+const sal_Int32 nPropertyTypeColor = 15;
+const sal_Int32 nPropertyTypeAccelerate = 16;
+const sal_Int32 nPropertyTypeDecelerate = 17;
+const sal_Int32 nPropertyTypeAutoReverse = 18;
+const sal_Int32 nPropertyTypeTransparency = 19;
+const sal_Int32 nPropertyTypeFontStyle = 20;
+const sal_Int32 nPropertyTypeScale = 21;
+
+class SdPropertySubControl
+{
+public:
+ explicit SdPropertySubControl(weld::Container* pParent);
+ virtual ~SdPropertySubControl();
+
+ virtual css::uno::Any getValue() = 0;
+ virtual void setValue( const css::uno::Any& rValue, const OUString& rPresetId ) = 0;
+
+ static std::unique_ptr<SdPropertySubControl>
+ create( sal_Int32 nType,
+ weld::Label* pLabel,
+ weld::Container* pParent,
+ weld::Window* pTopLevel,
+ const css::uno::Any& rValue,
+ const OUString& rPresetId,
+ const Link<LinkParamNone*,void>& rModifyHdl );
+
+protected:
+ std::unique_ptr<weld::Builder> mxBuilder;
+ std::unique_ptr<weld::Container> mxContainer;
+ weld::Container* mpParent;
+};
+
+class CustomAnimationDurationTabPage;
+class CustomAnimationEffectTabPage;
+class CustomAnimationTextAnimTabPage;
+class STLPropertySet;
+
+class CustomAnimationDialog : public weld::GenericDialogController
+{
+public:
+ CustomAnimationDialog(weld::Window* pParent, std::unique_ptr<STLPropertySet> pSet, const OString& Page);
+ virtual ~CustomAnimationDialog() override;
+
+ STLPropertySet* getResultSet();
+ STLPropertySet* getPropertySet() const { return mxSet.get(); }
+
+ static std::unique_ptr<STLPropertySet> createDefaultSet();
+
+private:
+ std::unique_ptr<STLPropertySet> mxSet;
+ std::unique_ptr<STLPropertySet> mxResultSet;
+
+ std::unique_ptr<weld::Notebook> mxTabControl;
+ std::unique_ptr<CustomAnimationDurationTabPage> mxDurationTabPage;
+ std::unique_ptr<CustomAnimationEffectTabPage> mxEffectTabPage;
+ std::unique_ptr<CustomAnimationTextAnimTabPage> mxTextAnimTabPage;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/animations/CustomAnimationList.cxx b/sd/source/ui/animations/CustomAnimationList.cxx
new file mode 100644
index 000000000..cc85ed74f
--- /dev/null
+++ b/sd/source/ui/animations/CustomAnimationList.cxx
@@ -0,0 +1,1231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/document/XActionLockable.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/presentation/EffectPresetClass.hpp>
+#include <com/sun/star/presentation/EffectCommands.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/scopeguard.hxx>
+#include <CustomAnimationList.hxx>
+#include <CustomAnimationPreset.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/image.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
+#include <tools/debug.hxx>
+#include <tools/gen.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <sdresid.hxx>
+
+#include <strings.hrc>
+#include <bitmaps.hlst>
+
+#include <algorithm>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::presentation;
+
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::text::XTextRange;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::drawing::XShapes;
+using ::com::sun::star::drawing::XDrawPage;
+using ::com::sun::star::container::XChild;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XEnumerationAccess;
+using ::com::sun::star::container::XEnumeration;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::beans::XPropertySetInfo;
+
+namespace sd {
+
+// go recursively through all shapes in the given XShapes collection and return true as soon as the
+// given shape is found. nIndex is incremented for each shape with the same shape type as the given
+// shape is found until the given shape is found.
+static bool getShapeIndex( const Reference< XShapes >& xShapes, const Reference< XShape >& xShape, sal_Int32& nIndex )
+{
+ const sal_Int32 nCount = xShapes->getCount();
+ sal_Int32 n;
+ for( n = 0; n < nCount; n++ )
+ {
+ Reference< XShape > xChild;
+ xShapes->getByIndex( n ) >>= xChild;
+ if( xChild == xShape )
+ return true;
+
+ if( xChild->getShapeType() == xShape->getShapeType() )
+ nIndex++;
+
+ Reference< XShapes > xChildContainer( xChild, UNO_QUERY );
+ if( xChildContainer.is() )
+ {
+ if( getShapeIndex( xChildContainer, xShape, nIndex ) )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// returns the index of the shape type from the given shape
+static sal_Int32 getShapeIndex( const Reference< XShape >& xShape )
+{
+ Reference< XChild > xChild( xShape, UNO_QUERY );
+ Reference< XShapes > xPage;
+
+ while( xChild.is() && !xPage.is() )
+ {
+ Reference< XInterface > x( xChild->getParent() );
+ xChild.set( x, UNO_QUERY );
+ Reference< XDrawPage > xTestPage( x, UNO_QUERY );
+ if( xTestPage.is() )
+ xPage.set( x, UNO_QUERY );
+ }
+
+ sal_Int32 nIndex = 1;
+
+ if( xPage.is() && getShapeIndex( xPage, xShape, nIndex ) )
+ return nIndex;
+ else
+ return -1;
+}
+
+OUString getShapeDescription( const Reference< XShape >& xShape, bool bWithText )
+{
+ OUString aDescription;
+ Reference< XPropertySet > xSet( xShape, UNO_QUERY );
+ bool bAppendIndex = true;
+
+ if(xSet.is()) try
+ {
+ Reference<XPropertySetInfo> xInfo(xSet->getPropertySetInfo());
+ if (xInfo.is())
+ {
+ static const OUStringLiteral aPropName1(u"Name");
+ if(xInfo->hasPropertyByName(aPropName1))
+ xSet->getPropertyValue(aPropName1) >>= aDescription;
+
+ bAppendIndex = aDescription.isEmpty();
+
+ static const OUStringLiteral aPropName2(u"UINameSingular");
+ if(xInfo->hasPropertyByName(aPropName2))
+ xSet->getPropertyValue(aPropName2) >>= aDescription;
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::getShapeDescription()" );
+ }
+
+ if (bAppendIndex)
+ {
+ aDescription += " " + OUString::number(getShapeIndex(xShape));
+ }
+
+ if( bWithText )
+ {
+ Reference< XTextRange > xText( xShape, UNO_QUERY );
+ if( xText.is() )
+ {
+ OUString aText( xText->getString() );
+ if( !aText.isEmpty() )
+ {
+ aDescription += ": ";
+
+ aText = aText.replace( '\n', ' ' );
+ aText = aText.replace( '\r', ' ' );
+
+ aDescription += aText;
+ }
+ }
+ }
+ return aDescription;
+}
+
+static OUString getDescription( const Any& rTarget, bool bWithText )
+{
+ OUString aDescription;
+
+ if( rTarget.getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ ParagraphTarget aParaTarget;
+ rTarget >>= aParaTarget;
+
+ css::uno::Reference<css::document::XActionLockable> xLockable(aParaTarget.Shape, css::uno::UNO_QUERY);
+ if (xLockable.is())
+ xLockable->addActionLock();
+ comphelper::ScopeGuard aGuard([&xLockable]()
+ {
+ if (xLockable.is())
+ xLockable->removeActionLock();
+ });
+
+ Reference< XEnumerationAccess > xText( aParaTarget.Shape, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xText->createEnumeration(), css::uno::UNO_SET_THROW );
+ sal_Int32 nPara = aParaTarget.Paragraph;
+
+ while( xEnumeration->hasMoreElements() && nPara )
+ {
+ xEnumeration->nextElement();
+ nPara--;
+ }
+
+ DBG_ASSERT( xEnumeration->hasMoreElements(), "sd::CustomAnimationEffect::prepareText(), paragraph out of range!" );
+
+ if( xEnumeration->hasMoreElements() )
+ {
+ Reference< XTextRange > xParagraph;
+ xEnumeration->nextElement() >>= xParagraph;
+
+ if( xParagraph.is() )
+ aDescription = xParagraph->getString();
+ }
+ }
+ else
+ {
+ Reference< XShape > xShape;
+ rTarget >>= xShape;
+ if( xShape.is() )
+ aDescription = getShapeDescription( xShape, bWithText );
+ }
+
+ return aDescription;
+}
+
+class CustomAnimationListEntryItem
+{
+public:
+ CustomAnimationListEntryItem(const OUString& aDescription,
+ const CustomAnimationEffectPtr& pEffect);
+ const CustomAnimationEffectPtr& getEffect() const { return mpEffect; }
+
+ Size GetSize(const vcl::RenderContext& rRenderContext);
+ void Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected);
+ void PaintEffect(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected);
+ void PaintTrigger(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect);
+
+private:
+ OUString msDescription;
+ OUString msEffectName;
+ CustomAnimationEffectPtr mpEffect;
+
+public:
+ static const ::tools::Long nIconWidth = 19;
+ static const ::tools::Long nItemMinHeight = 38;
+};
+
+CustomAnimationListEntryItem::CustomAnimationListEntryItem(const OUString& aDescription, const CustomAnimationEffectPtr& pEffect)
+ : msDescription(aDescription)
+ , mpEffect(pEffect)
+{
+ if (!mpEffect)
+ return;
+ switch (mpEffect->getPresetClass())
+ {
+ case EffectPresetClass::ENTRANCE:
+ msEffectName = SdResId(STR_CUSTOMANIMATION_ENTRANCE); break;
+ case EffectPresetClass::EXIT:
+ msEffectName = SdResId(STR_CUSTOMANIMATION_EXIT); break;
+ case EffectPresetClass::EMPHASIS:
+ msEffectName = SdResId(STR_CUSTOMANIMATION_EMPHASIS); break;
+ case EffectPresetClass::MOTIONPATH:
+ msEffectName = SdResId(STR_CUSTOMANIMATION_MOTION_PATHS); break;
+ default:
+ msEffectName = SdResId(STR_CUSTOMANIMATION_MISC); break;
+ }
+ msEffectName = msEffectName.replaceFirst( "%1" , CustomAnimationPresets::getCustomAnimationPresets().getUINameForPresetId(mpEffect->getPresetId()));
+}
+
+IMPL_STATIC_LINK(CustomAnimationList, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
+{
+ vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
+ const ::tools::Rectangle& rRect = std::get<1>(aPayload);
+ bool bSelected = std::get<2>(aPayload);
+ const OUString& rId = std::get<3>(aPayload);
+
+ CustomAnimationListEntryItem* pItem = weld::fromId<CustomAnimationListEntryItem*>(rId);
+
+ pItem->Paint(rRenderContext, rRect, bSelected);
+}
+
+IMPL_STATIC_LINK(CustomAnimationList, CustomGetSizeHdl, weld::TreeView::get_size_args, aPayload, Size)
+{
+ vcl::RenderContext& rRenderContext = aPayload.first;
+ const OUString& rId = aPayload.second;
+
+ CustomAnimationListEntryItem* pItem = weld::fromId<CustomAnimationListEntryItem*>(rId);
+ if (!pItem)
+ return Size(CustomAnimationListEntryItem::nIconWidth, CustomAnimationListEntryItem::nItemMinHeight);
+ return pItem->GetSize(rRenderContext);
+}
+
+Size CustomAnimationListEntryItem::GetSize(const vcl::RenderContext& rRenderContext)
+{
+ auto width = rRenderContext.GetTextWidth( msDescription ) + nIconWidth;
+ if (width < (rRenderContext.GetTextWidth( msEffectName ) + 2*nIconWidth))
+ width = rRenderContext.GetTextWidth( msEffectName ) + 2*nIconWidth;
+
+ Size aSize(width, rRenderContext.GetTextHeight());
+ if (aSize.Height() < nItemMinHeight)
+ aSize.setHeight(nItemMinHeight);
+ return aSize;
+}
+
+void CustomAnimationListEntryItem::PaintTrigger(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect)
+{
+ Size aSize(rRect.GetSize());
+
+ ::tools::Rectangle aOutRect(rRect);
+
+ // fill the background
+ Color aColor(rRenderContext.GetSettings().GetStyleSettings().GetDialogColor());
+
+ rRenderContext.Push();
+ rRenderContext.SetFillColor(aColor);
+ rRenderContext.SetLineColor();
+ rRenderContext.DrawRect(aOutRect);
+
+ // Erase the four corner pixels to make the rectangle appear rounded.
+ rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetWindowColor());
+ rRenderContext.DrawPixel(aOutRect.TopLeft());
+ rRenderContext.DrawPixel(Point(aOutRect.Right(), aOutRect.Top()));
+ rRenderContext.DrawPixel(Point(aOutRect.Left(), aOutRect.Bottom()));
+ rRenderContext.DrawPixel(Point(aOutRect.Right(), aOutRect.Bottom()));
+
+ // draw the category title
+
+ int nVertBorder = ((aSize.Height() - rRenderContext.GetTextHeight()) >> 1);
+ int nHorzBorder = rRenderContext.LogicToPixel(Size(3, 3), MapMode(MapUnit::MapAppFont)).Width();
+
+ aOutRect.AdjustLeft(nHorzBorder );
+ aOutRect.AdjustRight( -nHorzBorder );
+ aOutRect.AdjustTop( nVertBorder );
+ aOutRect.AdjustBottom( -nVertBorder );
+
+ rRenderContext.DrawText(aOutRect, rRenderContext.GetEllipsisString(msDescription, aOutRect.GetWidth()));
+ rRenderContext.Pop();
+}
+
+void CustomAnimationListEntryItem::PaintEffect(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected)
+{
+ rRenderContext.Push(vcl::PushFlags::TEXTCOLOR);
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ if (bSelected)
+ rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
+ else
+ rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
+
+ Point aPos(rRect.TopLeft());
+ int nItemHeight = rRect.GetHeight();
+
+ sal_Int16 nNodeType = mpEffect->getNodeType();
+ if (nNodeType == EffectNodeType::ON_CLICK )
+ {
+ rRenderContext.DrawImage(aPos, Image(StockImage::Yes, BMP_CUSTOMANIMATION_ON_CLICK));
+ }
+ else if (nNodeType == EffectNodeType::AFTER_PREVIOUS)
+ {
+ rRenderContext.DrawImage(aPos, Image(StockImage::Yes, BMP_CUSTOMANIMATION_AFTER_PREVIOUS));
+ }
+ else if (nNodeType == EffectNodeType::WITH_PREVIOUS)
+ {
+ //FIXME With previous image not defined in CustomAnimation.src
+ }
+
+ aPos.AdjustX(nIconWidth);
+
+ //TODO, full width of widget ?
+ rRenderContext.DrawText(aPos, rRenderContext.GetEllipsisString(msDescription, rRect.GetWidth()));
+
+ aPos.AdjustY(nIconWidth);
+
+ OUString sImage;
+ switch (mpEffect->getPresetClass())
+ {
+ case EffectPresetClass::ENTRANCE:
+ sImage = BMP_CUSTOMANIMATION_ENTRANCE_EFFECT; break;
+ case EffectPresetClass::EXIT:
+ sImage = BMP_CUSTOMANIMATION_EXIT_EFFECT; break;
+ case EffectPresetClass::EMPHASIS:
+ sImage = BMP_CUSTOMANIMATION_EMPHASIS_EFFECT; break;
+ case EffectPresetClass::MOTIONPATH:
+ sImage = BMP_CUSTOMANIMATION_MOTION_PATH; break;
+ case EffectPresetClass::OLEACTION:
+ sImage = BMP_CUSTOMANIMATION_OLE; break;
+ case EffectPresetClass::MEDIACALL:
+ switch (mpEffect->getCommand())
+ {
+ case EffectCommands::TOGGLEPAUSE:
+ sImage = BMP_CUSTOMANIMATION_MEDIA_PAUSE; break;
+ case EffectCommands::STOP:
+ sImage = BMP_CUSTOMANIMATION_MEDIA_STOP; break;
+ case EffectCommands::PLAY:
+ default:
+ sImage = BMP_CUSTOMANIMATION_MEDIA_PLAY; break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!sImage.isEmpty())
+ {
+ Image aImage(StockImage::Yes, sImage);
+ Point aImagePos(aPos);
+ aImagePos.AdjustY((nItemHeight/2 - aImage.GetSizePixel().Height()) >> 1 );
+ rRenderContext.DrawImage(aImagePos, aImage);
+ }
+
+ aPos.AdjustX(nIconWidth );
+ aPos.AdjustY((nItemHeight/2 - rRenderContext.GetTextHeight()) >> 1 );
+
+ rRenderContext.DrawText(aPos, rRenderContext.GetEllipsisString(msEffectName, rRect.GetWidth()));
+ rRenderContext.Pop();
+}
+
+void CustomAnimationListEntryItem::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected)
+{
+ if (mpEffect)
+ PaintEffect(rRenderContext, rRect, bSelected);
+ else
+ PaintTrigger(rRenderContext, rRect);
+}
+
+CustomAnimationList::CustomAnimationList(std::unique_ptr<weld::TreeView> xTreeView,
+ std::unique_ptr<weld::Label> xLabel,
+ std::unique_ptr<weld::Widget> xScrolledWindow)
+ : mxTreeView(std::move(xTreeView))
+ , maDropTargetHelper(*this)
+ , mxEmptyLabel(std::move(xLabel))
+ , mxEmptyLabelParent(std::move(xScrolledWindow))
+ , mbIgnorePaint(false)
+ , mpController(nullptr)
+ , mnLastGroupId(0)
+ , mnPostExpandEvent(nullptr)
+ , mnPostCollapseEvent(nullptr)
+{
+ mxEmptyLabel->set_stack_background();
+
+ mxTreeView->set_selection_mode(SelectionMode::Multiple);
+ mxTreeView->connect_changed(LINK(this, CustomAnimationList, SelectHdl));
+ mxTreeView->connect_key_press(LINK(this, CustomAnimationList, KeyInputHdl));
+ mxTreeView->connect_popup_menu(LINK(this, CustomAnimationList, CommandHdl));
+ mxTreeView->connect_row_activated(LINK(this, CustomAnimationList, DoubleClickHdl));
+ mxTreeView->connect_expanding(LINK(this, CustomAnimationList, ExpandHdl));
+ mxTreeView->connect_collapsing(LINK(this, CustomAnimationList, CollapseHdl));
+ mxTreeView->connect_drag_begin(LINK(this, CustomAnimationList, DragBeginHdl));
+ mxTreeView->connect_custom_get_size(LINK(this, CustomAnimationList, CustomGetSizeHdl));
+ mxTreeView->connect_custom_render(LINK(this, CustomAnimationList, CustomRenderHdl));
+ mxTreeView->set_column_custom_renderer(0, true);
+}
+
+CustomAnimationListDropTarget::CustomAnimationListDropTarget(CustomAnimationList& rTreeView)
+ : DropTargetHelper(rTreeView.get_widget().get_drop_target())
+ , m_rTreeView(rTreeView)
+{
+}
+
+sal_Int8 CustomAnimationListDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt);
+
+ if (nAccept != DND_ACTION_NONE)
+ {
+ // to enable the autoscroll when we're close to the edges
+ weld::TreeView& rWidget = m_rTreeView.get_widget();
+ rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
+ }
+
+ return nAccept;
+}
+
+sal_Int8 CustomAnimationListDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
+{
+ return m_rTreeView.ExecuteDrop(rEvt);
+}
+
+// D'n'D #1: Record selected effects for drag'n'drop.
+IMPL_LINK(CustomAnimationList, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+{
+ rUnsetDragIcon = false;
+
+ // Record which effects are selected:
+ // Since NextSelected(..) iterates through the selected items in the order they
+ // were selected, create a sorted list for simpler drag'n'drop algorithms.
+ mDndEffectsSelected.clear();
+ mxTreeView->selected_foreach([this](weld::TreeIter& rEntry){
+ mDndEffectsSelected.emplace_back(mxTreeView->make_iterator(&rEntry));
+ return false;
+ });
+
+ // Note: pEntry is the effect with focus (if multiple effects are selected)
+ mxDndEffectDragging = mxTreeView->make_iterator();
+ if (!mxTreeView->get_cursor(mxDndEffectDragging.get()))
+ mxDndEffectDragging.reset();
+
+ // Allow normal processing.
+ return false;
+}
+
+// D'n'D #3: Called each time mouse moves during drag
+sal_Int8 CustomAnimationList::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ sal_Int8 ret = DND_ACTION_NONE;
+
+ const bool bIsMove = DND_ACTION_MOVE == rEvt.mnAction;
+ if (mxDndEffectDragging && !rEvt.mbLeaving && bIsMove)
+ ret = DND_ACTION_MOVE;
+ return ret;
+}
+
+// D'n'D #5: Tell model to update effect order.
+sal_Int8 CustomAnimationList::ExecuteDrop(const ExecuteDropEvent& rEvt)
+{
+ std::unique_ptr<weld::TreeIter> xDndEffectInsertBefore(mxTreeView->make_iterator());
+ if (!mxTreeView->get_dest_row_at_pos(rEvt.maPosPixel, xDndEffectInsertBefore.get(), true))
+ xDndEffectInsertBefore.reset();
+
+ const bool bMovingEffect = ( mxDndEffectDragging != nullptr );
+ const bool bMoveNotSelf = !xDndEffectInsertBefore || (mxDndEffectDragging && mxTreeView->iter_compare(*xDndEffectInsertBefore, *mxDndEffectDragging) != 0);
+ const bool bHaveSequence(mpMainSequence);
+
+ if( bMovingEffect && bMoveNotSelf && bHaveSequence )
+ {
+ CustomAnimationListEntryItem* pTarget = xDndEffectInsertBefore ?
+ weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xDndEffectInsertBefore)) :
+ nullptr;
+
+ // Build list of effects
+ std::vector< CustomAnimationEffectPtr > aEffects;
+ for( const auto &pEntry : mDndEffectsSelected )
+ {
+ CustomAnimationListEntryItem* pCustomAnimationEffect = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*pEntry));
+ aEffects.push_back(pCustomAnimationEffect->getEffect());
+ }
+
+ // Callback to observer to have it update the model.
+ // If pTarget is null, pass nullptr to indicate end of list.
+ mpController->onDragNDropComplete(
+ std::move(aEffects),
+ pTarget ? pTarget->getEffect() : nullptr );
+
+ // Reset selection
+ mxTreeView->select(*mxDndEffectDragging);
+ Select();
+ }
+
+ // NOTE: Don't call default handler because all required
+ // move operations have been completed here to update the model.
+ return DND_ACTION_NONE;
+}
+
+CustomAnimationList::~CustomAnimationList()
+{
+ if (mnPostExpandEvent)
+ {
+ Application::RemoveUserEvent(mnPostExpandEvent);
+ mnPostExpandEvent = nullptr;
+ }
+
+ if (mnPostCollapseEvent)
+ {
+ Application::RemoveUserEvent(mnPostCollapseEvent);
+ mnPostCollapseEvent = nullptr;
+ }
+
+ if( mpMainSequence )
+ mpMainSequence->removeListener( this );
+
+ clear();
+}
+
+IMPL_LINK(CustomAnimationList, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ const int nKeyCode = rKEvt.GetKeyCode().GetCode();
+ switch (nKeyCode)
+ {
+ case KEY_DELETE:
+ mpController->onContextMenu("remove");
+ return true;
+ case KEY_INSERT:
+ mpController->onContextMenu("create");
+ return true;
+ case KEY_SPACE:
+ {
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+ if (mxTreeView->get_cursor(xEntry.get()))
+ {
+ auto aRect = mxTreeView->get_row_area(*xEntry);
+ const Point aPos(aRect.getWidth() / 2, aRect.getHeight() / 2);
+ const CommandEvent aCEvt(aPos, CommandEventId::ContextMenu);
+ CommandHdl(aCEvt);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/** selects or deselects the given effect.
+ Selections of other effects are not changed */
+void CustomAnimationList::select( const CustomAnimationEffectPtr& pEffect )
+{
+ CustomAnimationListEntryItem* pEntry = nullptr;
+
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+ if (mxTreeView->get_iter_first(*xEntry))
+ {
+ do
+ {
+ CustomAnimationListEntryItem* pTestEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
+ if (pTestEntry->getEffect() == pEffect)
+ {
+ mxTreeView->select(*xEntry);
+ mxTreeView->scroll_to_row(*xEntry);
+ pEntry = pTestEntry;
+ break;
+ }
+ } while (mxTreeView->iter_next(*xEntry));
+ }
+
+ if( !pEntry )
+ {
+ append( pEffect );
+ select( pEffect );
+ }
+}
+
+void CustomAnimationList::clear()
+{
+ mxEntries.clear();
+ mxTreeView->clear();
+
+ mxEmptyLabelParent->show();
+ mxTreeView->hide();
+
+ mxLastParentEntry.reset();
+ mxLastTargetShape = nullptr;
+}
+
+void CustomAnimationList::update( const MainSequencePtr& pMainSequence )
+{
+ if( mpMainSequence )
+ mpMainSequence->removeListener( this );
+
+ mpMainSequence = pMainSequence;
+ update();
+
+ if( mpMainSequence )
+ mpMainSequence->addListener( this );
+}
+
+struct stl_append_effect_func
+{
+ explicit stl_append_effect_func( CustomAnimationList& rList ) : mrList( rList ) {}
+ void operator()(const CustomAnimationEffectPtr& pEffect);
+ CustomAnimationList& mrList;
+};
+
+void stl_append_effect_func::operator()(const CustomAnimationEffectPtr& pEffect)
+{
+ mrList.append( pEffect );
+}
+
+void CustomAnimationList::update()
+{
+ mbIgnorePaint = true;
+
+ std::vector< CustomAnimationEffectPtr > aVisible;
+ std::vector< CustomAnimationEffectPtr > aSelected;
+ CustomAnimationEffectPtr aCurrent;
+
+ CustomAnimationEffectPtr pFirstSelEffect;
+ CustomAnimationEffectPtr pLastSelEffect;
+ ::tools::Long nFirstVis = -1;
+ ::tools::Long nLastVis = -1;
+ ::tools::Long nFirstSelOld = -1;
+ ::tools::Long nLastSelOld = -1;
+
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+
+ if( mpMainSequence )
+ {
+ std::unique_ptr<weld::TreeIter> xLastSelectedEntry;
+ std::unique_ptr<weld::TreeIter> xLastVisibleEntry;
+
+ // save selection, current, and expand (visible) states
+ mxTreeView->all_foreach([this, &aVisible, &nFirstVis, &xLastVisibleEntry,
+ &aSelected, &nFirstSelOld, &pFirstSelEffect, &xLastSelectedEntry](weld::TreeIter& rEntry){
+ CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(rEntry));
+ CustomAnimationEffectPtr pEffect(pEntry->getEffect());
+ if (pEffect)
+ {
+ if (weld::IsEntryVisible(*mxTreeView, rEntry))
+ {
+ aVisible.push_back(pEffect);
+ // save scroll position
+ if (nFirstVis == -1)
+ nFirstVis = weld::GetAbsPos(*mxTreeView, rEntry);
+ if (!xLastVisibleEntry)
+ xLastVisibleEntry = mxTreeView->make_iterator(&rEntry);
+ else
+ mxTreeView->copy_iterator(rEntry, *xLastVisibleEntry);
+ }
+
+ if (mxTreeView->is_selected(rEntry))
+ {
+ aSelected.push_back(pEffect);
+ if (nFirstSelOld == -1)
+ {
+ pFirstSelEffect = pEffect;
+ nFirstSelOld = weld::GetAbsPos(*mxTreeView, rEntry);
+ }
+ if (!xLastSelectedEntry)
+ xLastSelectedEntry = mxTreeView->make_iterator(&rEntry);
+ else
+ mxTreeView->copy_iterator(rEntry, *xLastSelectedEntry);
+ }
+ }
+
+ return false;
+ });
+
+ if (xLastSelectedEntry)
+ {
+ CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xLastSelectedEntry));
+ pLastSelEffect = pEntry->getEffect();
+ nLastSelOld = weld::GetAbsPos(*mxTreeView, *xLastSelectedEntry);
+ }
+
+ if (xLastVisibleEntry)
+ nLastVis = weld::GetAbsPos(*mxTreeView, *xLastVisibleEntry);
+
+ if (mxTreeView->get_cursor(xEntry.get()))
+ {
+ CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
+ aCurrent = pEntry->getEffect();
+ }
+ }
+
+ // rebuild list
+
+ mxTreeView->freeze();
+
+ clear();
+
+ if (mpMainSequence)
+ {
+ std::for_each( mpMainSequence->getBegin(), mpMainSequence->getEnd(), stl_append_effect_func( *this ) );
+ mxLastParentEntry.reset();
+
+ auto rInteractiveSequenceVector = mpMainSequence->getInteractiveSequenceVector();
+
+ for (InteractiveSequencePtr const& pIS : rInteractiveSequenceVector)
+ {
+ Reference< XShape > xShape( pIS->getTriggerShape() );
+ if( xShape.is() )
+ {
+ OUString aDescription = SdResId(STR_CUSTOMANIMATION_TRIGGER) + ": " +
+ getShapeDescription( xShape, false );
+
+ mxEntries.emplace_back(std::make_unique<CustomAnimationListEntryItem>(aDescription, nullptr));
+
+ OUString sId(weld::toId(mxEntries.back().get()));
+ mxTreeView->insert(nullptr, -1, &aDescription, &sId, nullptr, nullptr, false, nullptr);
+ std::for_each( pIS->getBegin(), pIS->getEnd(), stl_append_effect_func( *this ) );
+ mxLastParentEntry.reset();
+ }
+ }
+ }
+
+ mxTreeView->thaw();
+
+ if (mxTreeView->n_children())
+ {
+ mxEmptyLabelParent->hide();
+ mxTreeView->show();
+ }
+
+ if (mpMainSequence)
+ {
+ ::tools::Long nFirstSelNew = -1;
+ ::tools::Long nLastSelNew = -1;
+
+ std::vector<std::unique_ptr<weld::TreeIter>> aNewSelection;
+
+ // restore selection state, expand state, and current-entry (under cursor)
+ if (mxTreeView->get_iter_first(*xEntry))
+ {
+ do
+ {
+ CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
+
+ CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
+ if (pEffect)
+ {
+ // Any effects that were visible should still be visible, so expand their parents.
+ // (a previously expanded parent may have moved leaving a child to now be the new parent to expand)
+ if( std::find( aVisible.begin(), aVisible.end(), pEffect ) != aVisible.end() )
+ {
+ if (mxTreeView->get_iter_depth(*xEntry))
+ {
+ std::unique_ptr<weld::TreeIter> xParentEntry = mxTreeView->make_iterator(xEntry.get());
+ mxTreeView->iter_parent(*xParentEntry);
+ mxTreeView->expand_row(*xParentEntry);
+ }
+ }
+
+ if( std::find( aSelected.begin(), aSelected.end(), pEffect ) != aSelected.end() )
+ aNewSelection.emplace_back(mxTreeView->make_iterator(xEntry.get()));
+
+ // Restore the cursor, as it may deselect other effects wait until
+ // after the loop to reset the selection
+ if( pEffect == aCurrent )
+ mxTreeView->set_cursor(*xEntry);
+
+ if (pEffect == pFirstSelEffect)
+ nFirstSelNew = weld::GetAbsPos(*mxTreeView, *xEntry);
+
+ if (pEffect == pLastSelEffect)
+ nLastSelNew = weld::GetAbsPos(*mxTreeView, *xEntry);
+ }
+ } while (mxTreeView->iter_next(*xEntry));
+ }
+
+ // tdf#147032 unselect what previous set_cursor may have caused to get selected as a side-effect
+ mxTreeView->unselect_all();
+ for (const auto& rEntry : aNewSelection)
+ mxTreeView->select(*rEntry);
+
+ // Scroll to a selected entry, depending on where the selection moved.
+ const bool bMoved = nFirstSelNew != nFirstSelOld;
+ const bool bMovedUp = nFirstSelNew < nFirstSelOld;
+ const bool bMovedDown = nFirstSelNew > nFirstSelOld;
+
+ if( bMoved && nLastSelOld < nFirstVis && nLastSelNew < nFirstVis )
+ {
+ // The selection is above the visible area.
+ // Scroll up to show the last few selected entries.
+ if( nLastSelNew - (nLastVis - nFirstVis) > nFirstSelNew)
+ {
+ // The entries in the selection range can't fit in view.
+ // Scroll so the last selected entry is last in view.
+ mxTreeView->vadjustment_set_value(nLastSelNew - (nLastVis - nFirstVis));
+ }
+ else
+ mxTreeView->vadjustment_set_value(nFirstSelNew);
+ }
+ else if( bMoved && nFirstSelOld > nLastVis && nFirstSelNew > nLastVis )
+ {
+ // The selection is below the visible area.
+ // Scroll down to the first few selected entries.
+ mxTreeView->vadjustment_set_value(nFirstSelNew);
+ }
+ else if( bMovedUp && nFirstSelOld <= nFirstVis )
+ {
+ // A visible entry has moved up out of view; scroll up one.
+ mxTreeView->vadjustment_set_value(nFirstVis - 1);
+ }
+ else if( bMovedDown && nLastSelOld >= nLastVis )
+ {
+ // An entry has moved down out of view; scroll down one.
+ mxTreeView->vadjustment_set_value(nFirstVis + 1);
+ }
+ else if ( nFirstVis != -1 )
+ {
+ // The selection is still in view, or it hasn't moved.
+ mxTreeView->vadjustment_set_value(nFirstVis);
+ }
+ }
+
+ mbIgnorePaint = false;
+
+ Select();
+}
+
+void CustomAnimationList::append( CustomAnimationEffectPtr pEffect )
+{
+ Any aTarget( pEffect->getTarget() );
+ if( !aTarget.hasValue() )
+ return;
+
+ try
+ {
+ // create a ui description
+ OUString aDescription = getDescription(aTarget, pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_BACKGROUND);
+
+ std::unique_ptr<weld::TreeIter> xParentEntry;
+
+ Reference< XShape > xTargetShape( pEffect->getTargetShape() );
+ sal_Int32 nGroupId = pEffect->getGroupId();
+
+ // if this effect has the same target and group-id as the last root effect,
+ // the last root effect is also this effects parent
+ if (mxLastParentEntry && nGroupId != -1 && mxLastTargetShape == xTargetShape && mnLastGroupId == nGroupId)
+ xParentEntry = mxTreeView->make_iterator(mxLastParentEntry.get());
+
+ // create an entry for the effect
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+
+ mxEntries.emplace_back(std::make_unique<CustomAnimationListEntryItem>(aDescription, pEffect));
+
+ OUString sId(weld::toId(mxEntries.back().get()));
+
+ if (xParentEntry)
+ {
+ // add a subentry
+ mxTreeView->insert(xParentEntry.get(), -1, &aDescription, &sId, nullptr, nullptr, false, xEntry.get());
+ }
+ else
+ {
+ // add a root entry
+ mxTreeView->insert(nullptr, -1, &aDescription, &sId, nullptr, nullptr, false, xEntry.get());
+
+ // and the new root entry becomes the possible next group header
+ mxLastTargetShape = xTargetShape;
+ mnLastGroupId = nGroupId;
+ mxLastParentEntry = std::move(xEntry);
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationList::append()" );
+ }
+}
+
+static void selectShape(weld::TreeView* pTreeList, const Reference< XShape >& xShape )
+{
+ std::unique_ptr<weld::TreeIter> xEntry = pTreeList->make_iterator();
+ if (!pTreeList->get_iter_first(*xEntry))
+ return;
+
+ bool bFirstEntry = true;
+
+ do
+ {
+ CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(pTreeList->get_id(*xEntry));
+ CustomAnimationEffectPtr pEffect(pEntry->getEffect());
+ if (pEffect)
+ {
+ if (pEffect->getTarget() == xShape)
+ {
+ pTreeList->select(*xEntry);
+ if (bFirstEntry)
+ {
+ pTreeList->scroll_to_row(*xEntry);
+ bFirstEntry = false;
+ }
+ }
+ }
+ } while (pTreeList->iter_next(*xEntry));
+}
+
+void CustomAnimationList::onSelectionChanged(const Any& rSelection)
+{
+ try
+ {
+ mxTreeView->unselect_all();
+
+ if (rSelection.hasValue())
+ {
+ Reference< XIndexAccess > xShapes(rSelection, UNO_QUERY);
+ if( xShapes.is() )
+ {
+ sal_Int32 nCount = xShapes->getCount();
+ sal_Int32 nIndex;
+ for( nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ Reference< XShape > xShape( xShapes->getByIndex( nIndex ), UNO_QUERY );
+ if( xShape.is() )
+ selectShape(mxTreeView.get(), xShape);
+ }
+ }
+ else
+ {
+ Reference< XShape > xShape(rSelection, UNO_QUERY);
+ if( xShape.is() )
+ selectShape(mxTreeView.get(), xShape);
+ }
+ }
+
+ Select();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationList::onSelectionChanged()" );
+ }
+}
+
+IMPL_LINK_NOARG(CustomAnimationList, SelectHdl, weld::TreeView&, void)
+{
+ Select();
+}
+
+// Notify controller to refresh UI when we are notified of selection change from base class
+void CustomAnimationList::Select()
+{
+ if( mbIgnorePaint )
+ return;
+ mpController->onSelect();
+}
+
+IMPL_LINK_NOARG(CustomAnimationList, PostExpandHdl, void*, void)
+{
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+ if (mxTreeView->get_selected(xEntry.get()))
+ {
+ for (bool bChild = mxTreeView->iter_children(*xEntry); bChild; bChild = mxTreeView->iter_next_sibling(*xEntry))
+ {
+ if (!mxTreeView->is_selected(*xEntry))
+ mxTreeView->select(*xEntry);
+ }
+ }
+
+ // Notify controller that selection has changed (it should update the UI)
+ mpController->onSelect();
+
+ mnPostExpandEvent = nullptr;
+}
+
+IMPL_LINK(CustomAnimationList, ExpandHdl, const weld::TreeIter&, rParent, bool)
+{
+ // If expanded entry is selected, then select its children too afterwards.
+ if (mxTreeView->is_selected(rParent) && !mnPostExpandEvent) {
+ mnPostExpandEvent = Application::PostUserEvent(LINK(this, CustomAnimationList, PostExpandHdl));
+ }
+
+ return true;
+}
+
+IMPL_LINK_NOARG(CustomAnimationList, PostCollapseHdl, void*, void)
+{
+ // Deselect all entries as SvTreeListBox::Collapse selects the last
+ // entry to have focus (or its parent), which is not desired
+ mxTreeView->unselect_all();
+
+ // Restore selection state for entries which are still visible
+ for (const auto &pEntry : lastSelectedEntries)
+ {
+ if (weld::IsEntryVisible(*mxTreeView, *pEntry))
+ mxTreeView->select(*pEntry);
+ }
+
+ lastSelectedEntries.clear();
+
+ // Notify controller that selection has changed (it should update the UI)
+ mpController->onSelect();
+
+ mnPostCollapseEvent = nullptr;
+}
+
+IMPL_LINK_NOARG(CustomAnimationList, CollapseHdl, const weld::TreeIter&, bool)
+{
+ if (!mnPostCollapseEvent)
+ {
+ // weld::TreeView::collapse() discards multi-selection state
+ // of list entries, so first save current selection state
+ mxTreeView->selected_foreach([this](weld::TreeIter& rEntry){
+ lastSelectedEntries.emplace_back(mxTreeView->make_iterator(&rEntry));
+ return false;
+ });
+
+ mnPostCollapseEvent = Application::PostUserEvent(LINK(this, CustomAnimationList, PostCollapseHdl));
+ }
+
+ // Execute collapse on base class
+ return true;
+}
+
+bool CustomAnimationList::isExpanded( const CustomAnimationEffectPtr& pEffect ) const
+{
+ bool bExpanded = true; // we assume expanded by default
+
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+ if (mxTreeView->get_iter_first(*xEntry))
+ {
+ do
+ {
+ CustomAnimationListEntryItem* pEntry =
+ weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
+ if (pEntry->getEffect() == pEffect)
+ {
+ if (mxTreeView->get_iter_depth(*xEntry)) // no parent, keep expanded default of true
+ {
+ std::unique_ptr<weld::TreeIter> xParentEntry = mxTreeView->make_iterator(xEntry.get());
+ if (mxTreeView->iter_parent(*xParentEntry))
+ bExpanded = mxTreeView->get_row_expanded(*xParentEntry);
+ }
+ break;
+ }
+ } while (mxTreeView->iter_next(*xEntry));
+ }
+
+ return bExpanded;
+}
+
+bool CustomAnimationList::isVisible(const CustomAnimationEffectPtr& pEffect) const
+{
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+ if (mxTreeView->get_iter_first(*xEntry))
+ {
+ do
+ {
+ CustomAnimationListEntryItem* pTestEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
+ if (pTestEntry->getEffect() == pEffect)
+ return weld::IsEntryVisible(*mxTreeView, *xEntry);
+ } while (mxTreeView->iter_next(*xEntry));
+ }
+ return true;
+}
+
+EffectSequence CustomAnimationList::getSelection() const
+{
+ EffectSequence aSelection;
+
+ mxTreeView->selected_foreach([this, &aSelection](weld::TreeIter& rEntry){
+ CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(rEntry));
+ CustomAnimationEffectPtr pEffect(pEntry->getEffect());
+ if (pEffect)
+ aSelection.push_back(pEffect);
+
+ // if the selected effect is not expanded and has children
+ // we say that the children are automatically selected
+ if (!mxTreeView->get_row_expanded(rEntry) && mxTreeView->iter_has_child(rEntry))
+ {
+ std::unique_ptr<weld::TreeIter> xChild = mxTreeView->make_iterator(&rEntry);
+ (void)mxTreeView->iter_children(*xChild);
+
+ do
+ {
+ if (!mxTreeView->is_selected(*xChild))
+ {
+ CustomAnimationListEntryItem* pChild = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xChild));
+ const CustomAnimationEffectPtr& pChildEffect( pChild->getEffect() );
+ if( pChildEffect )
+ aSelection.push_back( pChildEffect );
+ }
+ } while (mxTreeView->iter_next_sibling(*xChild));
+ }
+
+ return false;
+ });
+
+ return aSelection;
+}
+
+IMPL_LINK_NOARG(CustomAnimationList, DoubleClickHdl, weld::TreeView&, bool)
+{
+ mpController->onDoubleClick();
+ return false;
+}
+
+IMPL_LINK(CustomAnimationList, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ if (rCEvt.IsMouseEvent())
+ {
+ ::Point aPos = rCEvt.GetMousePosPixel();
+ std::unique_ptr<weld::TreeIter> xIter(mxTreeView->make_iterator());
+ if (mxTreeView->get_dest_row_at_pos(aPos, xIter.get(), false) && !mxTreeView->is_selected(*xIter))
+ {
+ mxTreeView->unselect_all();
+ mxTreeView->set_cursor(*xIter);
+ mxTreeView->select(*xIter);
+ SelectHdl(*mxTreeView);
+ }
+ }
+
+ if (!mxTreeView->get_selected(nullptr))
+ return false;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxTreeView.get(), "modules/simpress/ui/effectmenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu = xBuilder->weld_menu("menu");
+
+ sal_Int16 nNodeType = -1;
+ sal_Int16 nEntries = 0;
+
+ mxTreeView->selected_foreach([this, &nNodeType, &nEntries](weld::TreeIter& rEntry){
+ CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(rEntry));
+ CustomAnimationEffectPtr pEffect(pEntry->getEffect());
+
+ nEntries++;
+ if (pEffect)
+ {
+ if( nNodeType == -1 )
+ {
+ nNodeType = pEffect->getNodeType();
+ }
+ else
+ {
+ if( nNodeType != pEffect->getNodeType() )
+ {
+ nNodeType = -1;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ });
+
+ xMenu->set_active("onclick", nNodeType == EffectNodeType::ON_CLICK);
+ xMenu->set_active("withprev", nNodeType == EffectNodeType::WITH_PREVIOUS);
+ xMenu->set_active("afterprev", nNodeType == EffectNodeType::AFTER_PREVIOUS);
+ xMenu->set_sensitive("options", nEntries == 1);
+ xMenu->set_sensitive("timing", nEntries == 1);
+
+ OString sCommand = xMenu->popup_at_rect(mxTreeView.get(), ::tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
+ if (!sCommand.isEmpty())
+ ExecuteContextMenuAction(sCommand);
+
+ return true;
+}
+
+void CustomAnimationList::ExecuteContextMenuAction(const OString& rIdent)
+{
+ mpController->onContextMenu(rIdent);
+}
+
+void CustomAnimationList::notify_change()
+{
+ update();
+ mpController->onSelect();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/animations/CustomAnimationPane.cxx b/sd/source/ui/animations/CustomAnimationPane.cxx
new file mode 100644
index 000000000..0910ba96e
--- /dev/null
+++ b/sd/source/ui/animations/CustomAnimationPane.cxx
@@ -0,0 +1,2578 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/presentation/EffectPresetClass.hpp>
+#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/ParallelTimeContainer.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/document/XActionLockable.hpp>
+#include <com/sun/star/drawing/XDrawView.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/EffectCommands.hpp>
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+#include <com/sun/star/text/XTextRangeCompare.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <tools/debug.hxx>
+#include "STLPropertySet.hxx"
+#include <CustomAnimationPane.hxx>
+#include "CustomAnimationDialog.hxx"
+#include <CustomAnimationList.hxx>
+#include "motionpathtag.hxx"
+#include <CustomAnimationPreset.hxx>
+
+#include <comphelper/lok.hxx>
+#include <comphelper/sequence.hxx>
+#include <sfx2/frame.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <svx/svxids.hrc>
+#include <DrawDocShell.hxx>
+#include <ViewShellBase.hxx>
+#include <DrawViewShell.hxx>
+#include <DrawController.hxx>
+#include <sdresid.hxx>
+#include <drawview.hxx>
+#include <slideshow.hxx>
+#include <undoanim.hxx>
+#include <optsitem.hxx>
+#include <sdmod.hxx>
+#include <framework/FrameworkHelper.hxx>
+
+#include <EventMultiplexer.hxx>
+
+#include <strings.hrc>
+#include <sdpage.hxx>
+#include <app.hrc>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+#include <algorithm>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::text;
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using ::com::sun::star::view::XSelectionSupplier;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XEnumerationAccess;
+using ::com::sun::star::container::XEnumeration;
+using ::com::sun::star::text::XText;
+using ::sd::framework::FrameworkHelper;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+
+namespace sd {
+
+void fillRepeatComboBox(weld::ComboBox& rBox)
+{
+ OUString aNone( SdResId( STR_CUSTOMANIMATION_REPEAT_NONE ) );
+ rBox.append_text(aNone);
+ rBox.append_text(OUString::number(2));
+ rBox.append_text(OUString::number(3));
+ rBox.append_text(OUString::number(4));
+ rBox.append_text(OUString::number(5));
+ rBox.append_text(OUString::number(10));
+
+ OUString aUntilClick( SdResId( STR_CUSTOMANIMATION_REPEAT_UNTIL_NEXT_CLICK ) );
+ rBox.append_text(aUntilClick);
+
+ OUString aEndOfSlide( SdResId( STR_CUSTOMANIMATION_REPEAT_UNTIL_END_OF_SLIDE ) );
+ rBox.append_text(aEndOfSlide);
+}
+
+CustomAnimationPane::CustomAnimationPane( weld::Widget* pParent, ViewShellBase& rBase )
+ : PanelLayout(pParent, "CustomAnimationsPanel", "modules/simpress/ui/customanimationspanel.ui")
+ , mrBase(rBase)
+ // load resources
+ , mxFTAnimation(m_xBuilder->weld_label("effectlabel"))
+ , mxCustomAnimationList(new CustomAnimationList(m_xBuilder->weld_tree_view("custom_animation_list"),
+ m_xBuilder->weld_label("custom_animation_label"),
+ m_xBuilder->weld_widget("custom_animation_label_parent")))
+ , mxPBAddEffect(m_xBuilder->weld_button("add_effect"))
+ , mxPBRemoveEffect(m_xBuilder->weld_button("remove_effect"))
+ , mxPBMoveUp(m_xBuilder->weld_button("move_up"))
+ , mxPBMoveDown(m_xBuilder->weld_button("move_down"))
+ , mxFTCategory(m_xBuilder->weld_label("categorylabel"))
+ , mxLBCategory(m_xBuilder->weld_combo_box("categorylb"))
+ , mxFTEffect(m_xBuilder->weld_label("effect_label"))
+ , mxLBAnimation(m_xBuilder->weld_tree_view("effect_list"))
+ , mxFTStart(m_xBuilder->weld_label("start_effect"))
+ , mxLBStart(m_xBuilder->weld_combo_box("start_effect_list"))
+ , mxFTProperty(m_xBuilder->weld_label("effect_property"))
+ , mxPlaceholderBox(m_xBuilder->weld_container("placeholder"))
+ , mxPBPropertyMore(m_xBuilder->weld_button("more_properties"))
+ , mxFTDuration(m_xBuilder->weld_label("effect_duration"))
+ , mxCBXDuration(m_xBuilder->weld_metric_spin_button("anim_duration", FieldUnit::SECOND))
+ , mxFTStartDelay(m_xBuilder->weld_label("delay_label"))
+ , mxMFStartDelay(m_xBuilder->weld_metric_spin_button("delay_value", FieldUnit::SECOND))
+ , mxCBAutoPreview(m_xBuilder->weld_check_button("auto_preview"))
+ , mxPBPlay(m_xBuilder->weld_button("play"))
+ , maIdle("sd idle treeview select")
+ , mnLastSelectedAnimation(-1)
+ , mnPropertyType(nPropertyTypeNone)
+ , mnCurvePathPos(-1)
+ , mnPolygonPathPos(-1)
+ , mnFreeformPathPos(-1)
+ , maLateInitTimer("sd CustomAnimationPane maLateInitTimer")
+{
+ initialize();
+}
+
+css::ui::LayoutSize CustomAnimationPane::GetHeightForWidth(const sal_Int32 /*nWidth*/)
+{
+ sal_Int32 nMinimumHeight = get_preferred_size().Height();
+ return css::ui::LayoutSize(nMinimumHeight, -1, nMinimumHeight);
+}
+
+void CustomAnimationPane::initialize()
+{
+ mxLBAnimation->connect_changed(LINK(this, CustomAnimationPane, AnimationSelectHdl));
+ mxCustomAnimationList->setController( static_cast<ICustomAnimationListController*> ( this ) );
+ mxCustomAnimationList->set_size_request(mxCustomAnimationList->get_approximate_digit_width() * 15,
+ mxCustomAnimationList->get_height_rows(4));
+
+ mxLBAnimation->set_size_request(mxLBAnimation->get_approximate_digit_width() * 15,
+ mxLBAnimation->get_height_rows(4));
+
+ maStrProperty = mxFTProperty->get_label();
+
+ mxPBAddEffect->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl ) );
+ mxPBRemoveEffect->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl ) );
+ mxLBStart->connect_changed( LINK( this, CustomAnimationPane, implControlListBoxHdl ) );
+ mxCBXDuration->connect_value_changed(LINK( this, CustomAnimationPane, DurationModifiedHdl));
+ mxPBPropertyMore->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl ) );
+ mxPBMoveUp->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl ) );
+ mxPBMoveDown->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl ) );
+ mxPBPlay->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl ) );
+ mxCBAutoPreview->connect_toggled( LINK( this, CustomAnimationPane, implToggleHdl ) );
+ mxLBCategory->connect_changed( LINK(this, CustomAnimationPane, UpdateAnimationLB) );
+ mxMFStartDelay->connect_value_changed( LINK(this, CustomAnimationPane, DelayModifiedHdl) );
+ mxMFStartDelay->connect_focus_out(LINK( this, CustomAnimationPane, DelayLoseFocusHdl));
+
+ maIdle.SetPriority(TaskPriority::DEFAULT);
+ maIdle.SetInvokeHandler(LINK(this, CustomAnimationPane, SelectionHandler));
+
+ maStrModify = mxFTEffect->get_label();
+
+ // get current controller and initialize listeners
+ try
+ {
+ mxView.set(mrBase.GetController(), UNO_QUERY);
+ addListener();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::CustomAnimationPane()" );
+ }
+
+ // tdf#137637 keep user selection during initialization
+ ScopeLockGuard aGuard(maSelectionLock);
+ // get current page and update custom animation list
+ onChangeCurrentPage();
+
+ // Wait a short time before the presets list is created. This gives the
+ // system time to paint the control.
+ maLateInitTimer.SetTimeout(100);
+ maLateInitTimer.SetInvokeHandler(LINK(this, CustomAnimationPane, lateInitCallback));
+ maLateInitTimer.Start();
+}
+
+CustomAnimationPane::~CustomAnimationPane()
+{
+ maLateInitTimer.Stop();
+
+ removeListener();
+
+ MotionPathTagVector aTags;
+ aTags.swap( maMotionPathTags );
+ for (auto const& tag : aTags)
+ tag->Dispose();
+
+ mxPBAddEffect.reset();
+ mxPBRemoveEffect.reset();
+ mxFTEffect.reset();
+ mxFTStart.reset();
+ mxLBStart.reset();
+ mxLBSubControl.reset();
+ mxFTProperty.reset();
+ mxPlaceholderBox.reset();
+ mxPBPropertyMore.reset();
+ mxFTDuration.reset();
+ mxCBXDuration.reset();
+ mxFTStartDelay.reset();
+ mxMFStartDelay.reset();
+ mxCustomAnimationList.reset();
+ mxPBMoveUp.reset();
+ mxPBMoveDown.reset();
+ mxPBPlay.reset();
+ mxCBAutoPreview.reset();
+ mxFTCategory.reset();
+ mxLBCategory.reset();
+ mxFTAnimation.reset();
+ mxLBAnimation.reset();
+}
+
+void CustomAnimationPane::addUndo()
+{
+ SfxUndoManager* pManager = mrBase.GetDocShell()->GetUndoManager();
+ if( pManager )
+ {
+ SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
+ if( pPage )
+ pManager->AddUndoAction( std::make_unique<UndoAnimation>( mrBase.GetDocShell()->GetDoc(), pPage ) );
+ }
+}
+
+void CustomAnimationPane::addListener()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,CustomAnimationPane,EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->AddEventListener(aLink);
+}
+
+void CustomAnimationPane::removeListener()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,CustomAnimationPane,EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
+}
+
+IMPL_LINK(CustomAnimationPane,EventMultiplexerListener,
+ tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ case EventMultiplexerEventId::EditViewSelection:
+ onSelectionChanged();
+ break;
+
+ case EventMultiplexerEventId::CurrentPageChanged:
+ onChangeCurrentPage();
+ break;
+
+ case EventMultiplexerEventId::MainViewAdded:
+ // At this moment the controller may not yet been set at model
+ // or ViewShellBase. Take it from the view shell passed with
+ // the event.
+ if (mrBase.GetMainViewShell() != nullptr)
+ {
+ if( mrBase.GetMainViewShell()->GetShellType() == ViewShell::ST_IMPRESS )
+ {
+ mxView.set(mrBase.GetDrawController(), UNO_QUERY);
+ onSelectionChanged();
+ onChangeCurrentPage();
+ break;
+ }
+ }
+ [[fallthrough]];
+ case EventMultiplexerEventId::MainViewRemoved:
+ mxView = nullptr;
+ mxCurrentPage = nullptr;
+ updateControls();
+ break;
+
+ case EventMultiplexerEventId::Disposing:
+ mxView.clear();
+ onSelectionChanged();
+ onChangeCurrentPage();
+ break;
+ case EventMultiplexerEventId::EndTextEdit:
+ if (mpMainSequence && rEvent.mpUserData)
+ mxCustomAnimationList->update( mpMainSequence );
+ break;
+ default: break;
+ }
+}
+
+static sal_Int32 getPropertyType( std::u16string_view rProperty )
+{
+ if ( rProperty == u"Direction" )
+ return nPropertyTypeDirection;
+
+ if ( rProperty == u"Spokes" )
+ return nPropertyTypeSpokes;
+
+ if ( rProperty == u"Zoom" )
+ return nPropertyTypeZoom;
+
+ if ( rProperty == u"Accelerate" )
+ return nPropertyTypeAccelerate;
+
+ if ( rProperty == u"Decelerate" )
+ return nPropertyTypeDecelerate;
+
+ if ( rProperty == u"Color1" )
+ return nPropertyTypeFirstColor;
+
+ if ( rProperty == u"Color2" )
+ return nPropertyTypeSecondColor;
+
+ if ( rProperty == u"FillColor" )
+ return nPropertyTypeFillColor;
+
+ if ( rProperty == u"ColorStyle" )
+ return nPropertyTypeColorStyle;
+
+ if ( rProperty == u"AutoReverse" )
+ return nPropertyTypeAutoReverse;
+
+ if ( rProperty == u"FontStyle" )
+ return nPropertyTypeFont;
+
+ if ( rProperty == u"CharColor" )
+ return nPropertyTypeCharColor;
+
+ if ( rProperty == u"CharHeight" )
+ return nPropertyTypeCharHeight;
+
+ if ( rProperty == u"CharDecoration" )
+ return nPropertyTypeCharDecoration;
+
+ if ( rProperty == u"LineColor" )
+ return nPropertyTypeLineColor;
+
+ if ( rProperty == u"Rotate" )
+ return nPropertyTypeRotate;
+
+ if ( rProperty == u"Transparency" )
+ return nPropertyTypeTransparency;
+
+ if ( rProperty == u"Color" )
+ return nPropertyTypeColor;
+
+ if ( rProperty == u"Scale" )
+ return nPropertyTypeScale;
+
+ return nPropertyTypeNone;
+}
+
+OUString getPropertyName( sal_Int32 nPropertyType )
+{
+ switch( nPropertyType )
+ {
+ case nPropertyTypeDirection:
+ return SdResId(STR_CUSTOMANIMATION_DIRECTION_PROPERTY);
+
+ case nPropertyTypeSpokes:
+ return SdResId(STR_CUSTOMANIMATION_SPOKES_PROPERTY);
+
+ case nPropertyTypeFirstColor:
+ return SdResId(STR_CUSTOMANIMATION_FIRST_COLOR_PROPERTY);
+
+ case nPropertyTypeSecondColor:
+ return SdResId(STR_CUSTOMANIMATION_SECOND_COLOR_PROPERTY);
+
+ case nPropertyTypeZoom:
+ return SdResId(STR_CUSTOMANIMATION_ZOOM_PROPERTY);
+
+ case nPropertyTypeFillColor:
+ return SdResId(STR_CUSTOMANIMATION_FILL_COLOR_PROPERTY);
+
+ case nPropertyTypeColorStyle:
+ return SdResId(STR_CUSTOMANIMATION_STYLE_PROPERTY);
+
+ case nPropertyTypeFont:
+ return SdResId(STR_CUSTOMANIMATION_FONT_PROPERTY);
+
+ case nPropertyTypeCharHeight:
+ return SdResId(STR_CUSTOMANIMATION_SIZE_PROPERTY);
+
+ case nPropertyTypeCharColor:
+ return SdResId(STR_CUSTOMANIMATION_FONT_COLOR_PROPERTY);
+
+ case nPropertyTypeCharHeightStyle:
+ return SdResId(STR_CUSTOMANIMATION_FONT_SIZE_STYLE_PROPERTY);
+
+ case nPropertyTypeCharDecoration:
+ return SdResId(STR_CUSTOMANIMATION_FONT_STYLE_PROPERTY);
+
+ case nPropertyTypeLineColor:
+ return SdResId(STR_CUSTOMANIMATION_LINE_COLOR_PROPERTY);
+
+ case nPropertyTypeRotate:
+ return SdResId(STR_CUSTOMANIMATION_AMOUNT_PROPERTY);
+
+ case nPropertyTypeColor:
+ return SdResId(STR_CUSTOMANIMATION_COLOR_PROPERTY);
+
+ case nPropertyTypeTransparency:
+ return SdResId(STR_CUSTOMANIMATION_AMOUNT_PROPERTY);
+
+ case nPropertyTypeScale:
+ return SdResId(STR_CUSTOMANIMATION_SCALE_PROPERTY);
+ }
+
+ return OUString();
+}
+
+void CustomAnimationPane::updateControls()
+{
+ mxFTDuration->set_sensitive(mxView.is());
+ mxCBXDuration->set_sensitive(mxView.is());
+ mxCustomAnimationList->set_sensitive(mxView.is());
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ mxPBPlay->hide();
+ mxCBAutoPreview->set_active(false);
+ mxCBAutoPreview->hide();
+ }
+ else
+ {
+ mxPBPlay->set_sensitive(mxView.is());
+ mxCBAutoPreview->set_sensitive(mxView.is());
+ }
+
+ if (!mxView.is())
+ {
+ mxPBAddEffect->set_sensitive(false);
+ mxPBRemoveEffect->set_sensitive(false);
+ mxFTStart->set_sensitive(false);
+ mxLBStart->set_sensitive(false);
+ mxPBPropertyMore->set_sensitive(false);
+ mxPlaceholderBox->set_sensitive(false);
+ mxFTProperty->set_sensitive(false);
+ mxFTCategory->set_sensitive(false);
+ mxLBCategory->set_sensitive(false);
+ mxFTAnimation->set_sensitive(false);
+ mxLBAnimation->set_sensitive(false);
+ mxFTStartDelay->set_sensitive(false);
+ mxMFStartDelay->set_sensitive(false);
+ mxLBAnimation->clear();
+ mnLastSelectedAnimation = -1;
+ mxCustomAnimationList->clear();
+ return;
+ }
+
+ const int nSelectionCount = maListSelection.size();
+
+ mxPBAddEffect->set_sensitive( maViewSelection.hasValue() );
+ mxPBRemoveEffect->set_sensitive(nSelectionCount != 0);
+ bool bIsSelected = (nSelectionCount > 0);
+
+ if(bIsSelected)
+ {
+ mxFTAnimation->set_sensitive(true);
+ mxLBAnimation->set_sensitive(true);
+ }
+ else
+ {
+ mxFTAnimation->set_sensitive(false);
+ mxLBAnimation->set_sensitive(false);
+ mxLBAnimation->clear();
+ mnLastSelectedAnimation = -1;
+ }
+
+ mxLBCategory->set_sensitive(bIsSelected);
+ mxFTCategory->set_sensitive(bIsSelected);
+
+ mxFTStart->set_sensitive(nSelectionCount > 0);
+ mxLBStart->set_sensitive(nSelectionCount > 0);
+ mxPlaceholderBox->set_sensitive(nSelectionCount > 0);
+ mxPBPropertyMore->set_sensitive(nSelectionCount > 0);
+ mxFTStartDelay->set_sensitive(nSelectionCount > 0);
+ mxMFStartDelay->set_sensitive(nSelectionCount > 0);
+
+ mxFTProperty->set_label(maStrProperty);
+
+ sal_Int32 nOldPropertyType = mnPropertyType;
+
+ mnPropertyType = nPropertyTypeNone;
+
+ if(bIsSelected)
+ {
+ CustomAnimationEffectPtr pEffect = maListSelection.front();
+
+ OUString aUIName( CustomAnimationPresets::getCustomAnimationPresets().getUINameForPresetId( pEffect->getPresetId() ) );
+
+ OUString aTemp( maStrModify );
+
+ if( !aUIName.isEmpty() )
+ {
+ aTemp += " " + aUIName;
+ mxFTEffect->set_label( aTemp );
+ }
+
+ Any aValue;
+ CustomAnimationPresetPtr pDescriptor = CustomAnimationPresets::getCustomAnimationPresets().getEffectDescriptor( pEffect->getPresetId() );
+ if (pDescriptor)
+ {
+ std::vector<OUString> aProperties( pDescriptor->getProperties() );
+ if( !aProperties.empty() )
+ {
+ mnPropertyType = getPropertyType( aProperties.front() );
+
+ mxFTProperty->set_label( getPropertyName( mnPropertyType ) );
+
+ aValue = getProperty1Value( mnPropertyType, pEffect );
+ }
+ }
+
+ sal_Int32 nNewPropertyType = mnPropertyType;
+ // if there is no value, then the control will be disabled, just show a disabled Direction box in that
+ // case to have something to fill the space
+ if (!aValue.hasValue())
+ nNewPropertyType = nPropertyTypeDirection;
+
+ if (!mxLBSubControl || nOldPropertyType != nNewPropertyType)
+ {
+ // for LOK destroy old widgets first
+ mxLBSubControl.reset(nullptr);
+ // then create new control, to keep correct pointers for actions
+ mxLBSubControl = SdPropertySubControl::create(nNewPropertyType, mxFTProperty.get(), mxPlaceholderBox.get(), GetFrameWeld(), aValue, pEffect->getPresetId(), LINK(this, CustomAnimationPane, implPropertyHdl));
+ }
+ else
+ {
+ mxLBSubControl->setValue(aValue, pEffect->getPresetId());
+ }
+
+ bool bEnable = aValue.hasValue();
+ mxPlaceholderBox->set_sensitive( bEnable );
+ mxFTProperty->set_sensitive( bEnable );
+
+ if (!pDescriptor)
+ {
+ mxPBPropertyMore->set_sensitive( false );
+ mxFTStartDelay->set_sensitive( false );
+ mxMFStartDelay->set_sensitive( false );
+ }
+ sal_Int32 nCategoryPos = -1;
+ switch(pEffect->getPresetClass())
+ {
+ case EffectPresetClass::ENTRANCE: nCategoryPos = 0; break;
+ case EffectPresetClass::EMPHASIS: nCategoryPos = 1; break;
+ case EffectPresetClass::EXIT: nCategoryPos = 2; break;
+ case EffectPresetClass::MOTIONPATH: nCategoryPos = 3; break;
+ default:
+ break;
+ }
+ switch(pEffect->getCommand())
+ {
+ case EffectCommands::TOGGLEPAUSE:
+ case EffectCommands::STOP:
+ case EffectCommands::PLAY:
+ nCategoryPos = 4; break;
+ default:
+ break;
+ }
+ mxLBCategory->set_active(nCategoryPos);
+
+ fillAnimationLB( pEffect->hasText() );
+
+ OUString rsPresetId = pEffect->getPresetId();
+ sal_Int32 nAnimationPos = mxLBAnimation->n_children();
+ while( nAnimationPos-- )
+ {
+ auto pEntryData = weld::fromId<CustomAnimationPresetPtr*>(mxLBAnimation->get_id(nAnimationPos));
+ if (pEntryData)
+ {
+ CustomAnimationPresetPtr& pPtr = *pEntryData;
+ if( pPtr && pPtr->getPresetId() == rsPresetId )
+ {
+ mxLBAnimation->select( nAnimationPos );
+ mnLastSelectedAnimation = nAnimationPos;
+ break;
+ }
+ }
+ }
+
+ // If preset id is missing and category is motion path.
+ if (nAnimationPos < 0 && nCategoryPos == 3)
+ {
+ if (rsPresetId == "libo-motionpath-curve")
+ {
+ mxLBAnimation->select(mnCurvePathPos);
+ mnLastSelectedAnimation = mnCurvePathPos;
+ }
+ else if (rsPresetId == "libo-motionpath-polygon")
+ {
+ mxLBAnimation->select(mnPolygonPathPos);
+ mnLastSelectedAnimation = mnPolygonPathPos;
+ }
+ else if (rsPresetId == "libo-motionpath-freeform-line")
+ {
+ mxLBAnimation->select(mnFreeformPathPos);
+ mnLastSelectedAnimation = mnFreeformPathPos;
+ }
+ }
+
+ sal_uInt16 nPos = 0xffff;
+
+ sal_Int16 nNodeType = pEffect->getNodeType();
+ switch( nNodeType )
+ {
+ case EffectNodeType::ON_CLICK: nPos = 0; break;
+ case EffectNodeType::WITH_PREVIOUS: nPos = 1; break;
+ case EffectNodeType::AFTER_PREVIOUS: nPos = 2; break;
+ }
+
+ mxLBStart->set_active( nPos );
+
+ double fDuration = pEffect->getDuration();
+ const bool bHasSpeed = fDuration > 0.001;
+
+ mxFTDuration->set_sensitive(bHasSpeed);
+ mxCBXDuration->set_sensitive(bHasSpeed);
+
+ if( bHasSpeed )
+ {
+ mxCBXDuration->set_value(fDuration*100.0, FieldUnit::NONE);
+ }
+
+ mxPBPropertyMore->set_sensitive(true);
+
+ mxFTStartDelay->set_sensitive(true);
+ mxMFStartDelay->set_sensitive(true);
+ double fBegin = pEffect->getBegin();
+ mxMFStartDelay->set_value(fBegin*10.0, FieldUnit::NONE);
+ }
+ else
+ {
+ // use an empty direction box to fill the space
+ if (!mxLBSubControl || (nOldPropertyType != nPropertyTypeDirection && nOldPropertyType != nPropertyTypeNone))
+ {
+ // for LOK destroy old widgets first
+ mxLBSubControl.reset(nullptr);
+ // then create new control, to keep correct pointers for actions
+ mxLBSubControl = SdPropertySubControl::create(nPropertyTypeDirection, mxFTProperty.get(), mxPlaceholderBox.get(), GetFrameWeld(), uno::Any(), OUString(), LINK(this, CustomAnimationPane, implPropertyHdl));
+ }
+ else
+ mxLBSubControl->setValue(uno::Any(), OUString());
+
+ mxPlaceholderBox->set_sensitive(false);
+ mxFTProperty->set_sensitive(false);
+ mxFTStartDelay->set_sensitive(false);
+ mxMFStartDelay->set_sensitive(false);
+ mxPBPropertyMore->set_sensitive(false);
+ mxFTDuration->set_sensitive(false);
+ mxCBXDuration->set_sensitive(false);
+ mxCBXDuration->set_text(OUString());
+ mxFTEffect->set_label(maStrModify);
+ }
+
+ bool bEnableUp = true;
+ bool bEnableDown = true;
+ if( nSelectionCount == 0 )
+ {
+ bEnableUp = false;
+ bEnableDown = false;
+ }
+ else
+ {
+ if( mpMainSequence->find( maListSelection.front() ) == mpMainSequence->getBegin() )
+ bEnableUp = false;
+
+ EffectSequence::iterator aIter( mpMainSequence->find( maListSelection.back() ) );
+ if( aIter == mpMainSequence->getEnd() )
+ {
+ bEnableDown = false;
+ }
+ else
+ {
+ do
+ {
+ ++aIter;
+ }
+ while( (aIter != mpMainSequence->getEnd()) && !(mxCustomAnimationList->isExpanded(*aIter) ) );
+
+ if( aIter == mpMainSequence->getEnd() )
+ bEnableDown = false;
+ }
+
+ if( bEnableUp || bEnableDown )
+ {
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+
+ EffectSequenceHelper* pSequence = nullptr;
+ for( const CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ if( pEffect )
+ {
+ if( pSequence == nullptr )
+ {
+ pSequence = pEffect->getEffectSequence();
+ }
+ else
+ {
+ if( pSequence != pEffect->getEffectSequence() )
+ {
+ bEnableUp = false;
+ bEnableDown = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ mxPBMoveUp->set_sensitive(mxView.is() && bEnableUp);
+ mxPBMoveDown->set_sensitive(mxView.is() && bEnableDown);
+
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ mxCBAutoPreview->set_active(pOptions->IsPreviewChangedEffects());
+
+ updateMotionPathTags();
+}
+
+static bool updateMotionPathImpl( CustomAnimationPane& rPane, ::sd::View& rView, EffectSequence::iterator aIter, const EffectSequence::iterator& aEnd, MotionPathTagVector& rOldTags, MotionPathTagVector& rNewTags )
+{
+ bool bChanges = false;
+ while( aIter != aEnd )
+ {
+ CustomAnimationEffectPtr pEffect( *aIter++ );
+ if( pEffect && pEffect->getPresetClass() == css::presentation::EffectPresetClass::MOTIONPATH )
+ {
+ rtl::Reference< MotionPathTag > xMotionPathTag;
+ // first try to find if there is already a tag for this
+ auto aMIter = std::find_if(rOldTags.begin(), rOldTags.end(),
+ [&pEffect](const rtl::Reference<MotionPathTag>& xTag) { return xTag->getEffect() == pEffect; });
+ if (aMIter != rOldTags.end())
+ {
+ rtl::Reference< MotionPathTag > xTag( *aMIter );
+ if( !xTag->isDisposed() )
+ {
+ xMotionPathTag = xTag;
+ rOldTags.erase( aMIter );
+ }
+ }
+
+ // if not found, create new one
+ if( !xMotionPathTag.is() )
+ {
+ xMotionPathTag.set( new MotionPathTag( rPane, rView, pEffect ) );
+ bChanges = true;
+ }
+
+ if( xMotionPathTag.is() )
+ rNewTags.push_back( xMotionPathTag );
+ }
+ }
+
+ return bChanges;
+}
+
+void CustomAnimationPane::updateMotionPathTags()
+{
+ bool bChanges = false;
+
+ MotionPathTagVector aTags;
+ aTags.swap( maMotionPathTags );
+
+ ::sd::View* pView = nullptr;
+
+ if( mxView.is() )
+ {
+ std::shared_ptr<ViewShell> xViewShell( mrBase.GetMainViewShell() );
+ if( xViewShell )
+ pView = xViewShell->GetView();
+ }
+
+ if (mpMainSequence && pView)
+ {
+ bChanges = updateMotionPathImpl( *this, *pView, mpMainSequence->getBegin(), mpMainSequence->getEnd(), aTags, maMotionPathTags );
+
+ auto rInteractiveSequenceVector = mpMainSequence->getInteractiveSequenceVector();
+ for (InteractiveSequencePtr const& pIS : rInteractiveSequenceVector)
+ {
+ bChanges |= updateMotionPathImpl( *this, *pView, pIS->getBegin(), pIS->getEnd(), aTags, maMotionPathTags );
+ }
+ }
+
+ if( !aTags.empty() )
+ {
+ bChanges = true;
+ for( rtl::Reference< MotionPathTag >& xTag : aTags )
+ {
+ xTag->Dispose();
+ }
+ }
+
+ if( bChanges && pView )
+ pView->updateHandles();
+}
+
+void CustomAnimationPane::onSelectionChanged()
+{
+ if( maSelectionLock.isLocked() )
+ return;
+
+ ScopeLockGuard aGuard( maSelectionLock );
+
+ if( mxView.is() ) try
+ {
+ Reference< XSelectionSupplier > xSel( mxView, UNO_QUERY_THROW );
+ maViewSelection = xSel->getSelection();
+ mxCustomAnimationList->onSelectionChanged( maViewSelection );
+ updateControls();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::onSelectionChanged()" );
+ }
+}
+
+void CustomAnimationPane::onDoubleClick()
+{
+ showOptions();
+}
+
+void CustomAnimationPane::onContextMenu(const OString &rIdent)
+{
+ if (rIdent == "onclick")
+ onChangeStart( EffectNodeType::ON_CLICK );
+ else if (rIdent == "withprev")
+ onChangeStart( EffectNodeType::WITH_PREVIOUS );
+ else if (rIdent == "afterprev")
+ onChangeStart( EffectNodeType::AFTER_PREVIOUS );
+ else if (rIdent == "options")
+ showOptions();
+ else if (rIdent == "timing")
+ showOptions("timing");
+ else if (rIdent == "remove")
+ onRemove();
+ else if (rIdent == "create" && maViewSelection.hasValue())
+ onAdd();
+ updateControls();
+}
+
+static void addValue( const std::unique_ptr<STLPropertySet>& pSet, sal_Int32 nHandle, const Any& rValue )
+{
+ switch( pSet->getPropertyState( nHandle ) )
+ {
+ case STLPropertyState::Ambiguous:
+ // value is already ambiguous, do nothing
+ break;
+ case STLPropertyState::Direct:
+ // set to ambiguous if existing value is different
+ if( rValue != pSet->getPropertyValue( nHandle ) )
+ pSet->setPropertyState( nHandle, STLPropertyState::Ambiguous );
+ break;
+ case STLPropertyState::Default:
+ // just set new value
+ pSet->setPropertyValue( nHandle, rValue );
+ break;
+ }
+}
+
+static sal_Int32 calcMaxParaDepth( const Reference< XShape >& xTargetShape )
+{
+ sal_Int32 nMaxParaDepth = -1;
+
+ if( xTargetShape.is() )
+ {
+ Reference< XEnumerationAccess > xText( xTargetShape, UNO_QUERY );
+ if( xText.is() )
+ {
+ Reference< XPropertySet > xParaSet;
+
+ Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ xEnumeration->nextElement() >>= xParaSet;
+ if( xParaSet.is() )
+ {
+ sal_Int32 nParaDepth = 0;
+ xParaSet->getPropertyValue( "NumberingLevel" ) >>= nParaDepth;
+
+ if( nParaDepth > nMaxParaDepth )
+ nMaxParaDepth = nParaDepth;
+ }
+ }
+ }
+ }
+
+ return nMaxParaDepth + 1;
+}
+
+Any CustomAnimationPane::getProperty1Value( sal_Int32 nType, const CustomAnimationEffectPtr& pEffect )
+{
+ switch( nType )
+ {
+ case nPropertyTypeDirection:
+ case nPropertyTypeSpokes:
+ case nPropertyTypeZoom:
+ return Any( pEffect->getPresetSubType() );
+
+ case nPropertyTypeColor:
+ case nPropertyTypeFillColor:
+ case nPropertyTypeFirstColor:
+ case nPropertyTypeSecondColor:
+ case nPropertyTypeCharColor:
+ case nPropertyTypeLineColor:
+ {
+ const sal_Int32 nIndex = (nPropertyTypeFirstColor == nType) ? 0 : 1;
+ return pEffect->getColor( nIndex );
+ }
+
+ case nPropertyTypeFont:
+ return pEffect->getProperty( AnimationNodeType::SET, u"CharFontName" , EValue::To );
+
+ case nPropertyTypeCharHeight:
+ {
+ static const OUStringLiteral aAttributeName( u"CharHeight" );
+ Any aValue( pEffect->getProperty( AnimationNodeType::SET, aAttributeName, EValue::To ) );
+ if( !aValue.hasValue() )
+ aValue = pEffect->getProperty( AnimationNodeType::ANIMATE, aAttributeName, EValue::To );
+ return aValue;
+ }
+
+ case nPropertyTypeRotate:
+ return pEffect->getTransformationProperty( AnimationTransformType::ROTATE, EValue::By);
+
+ case nPropertyTypeTransparency:
+ return pEffect->getProperty( AnimationNodeType::SET, u"Opacity" , EValue::To );
+
+ case nPropertyTypeScale:
+ return pEffect->getTransformationProperty( AnimationTransformType::SCALE, EValue::By );
+
+ case nPropertyTypeCharDecoration:
+ {
+ Sequence< Any > aValues{
+ pEffect->getProperty( AnimationNodeType::SET, u"CharWeight" , EValue::To ),
+ pEffect->getProperty( AnimationNodeType::SET, u"CharPosture" , EValue::To ),
+ pEffect->getProperty( AnimationNodeType::SET, u"CharUnderline" , EValue::To )
+ };
+ return Any( aValues );
+ }
+ }
+
+ Any aAny;
+ return aAny;
+}
+
+bool CustomAnimationPane::setProperty1Value( sal_Int32 nType, const CustomAnimationEffectPtr& pEffect, const Any& rValue )
+{
+ bool bEffectChanged = false;
+ switch( nType )
+ {
+ case nPropertyTypeDirection:
+ case nPropertyTypeSpokes:
+ case nPropertyTypeZoom:
+ {
+ OUString aPresetSubType;
+ rValue >>= aPresetSubType;
+ if( aPresetSubType != pEffect->getPresetSubType() )
+ {
+ CustomAnimationPresets::getCustomAnimationPresets().changePresetSubType( pEffect, aPresetSubType );
+ bEffectChanged = true;
+ }
+ }
+ break;
+
+ case nPropertyTypeFillColor:
+ case nPropertyTypeColor:
+ case nPropertyTypeFirstColor:
+ case nPropertyTypeSecondColor:
+ case nPropertyTypeCharColor:
+ case nPropertyTypeLineColor:
+ {
+ const sal_Int32 nIndex = (nPropertyTypeFirstColor == nType) ? 0 : 1;
+ Any aOldColor( pEffect->getColor( nIndex ) );
+ if( aOldColor != rValue )
+ {
+ pEffect->setColor( nIndex, rValue );
+ bEffectChanged = true;
+ }
+ }
+ break;
+
+ case nPropertyTypeFont:
+ bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, u"CharFontName" , EValue::To, rValue );
+ break;
+
+ case nPropertyTypeCharHeight:
+ {
+ static const OUStringLiteral aAttributeName( u"CharHeight" );
+ bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, aAttributeName, EValue::To, rValue );
+ if( !bEffectChanged )
+ bEffectChanged = pEffect->setProperty( AnimationNodeType::ANIMATE, aAttributeName, EValue::To, rValue );
+ }
+ break;
+ case nPropertyTypeRotate:
+ bEffectChanged = pEffect->setTransformationProperty( AnimationTransformType::ROTATE, EValue::By , rValue );
+ break;
+
+ case nPropertyTypeTransparency:
+ bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, u"Opacity" , EValue::To, rValue );
+ break;
+
+ case nPropertyTypeScale:
+ bEffectChanged = pEffect->setTransformationProperty( AnimationTransformType::SCALE, EValue::By, rValue );
+ break;
+
+ case nPropertyTypeCharDecoration:
+ {
+ Sequence< Any > aValues(3);
+ rValue >>= aValues;
+ bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, u"CharWeight" , EValue::To, aValues[0] );
+ bEffectChanged |= pEffect->setProperty( AnimationNodeType::SET, u"CharPosture" , EValue::To, aValues[1] );
+ bEffectChanged |= pEffect->setProperty( AnimationNodeType::SET, u"CharUnderline" , EValue::To, aValues[2] );
+ }
+ break;
+
+ }
+
+ return bEffectChanged;
+}
+
+static bool hasVisibleShape( const Reference< XShape >& xShape )
+{
+ try
+ {
+ const OUString sShapeType( xShape->getShapeType() );
+
+ if( sShapeType == "com.sun.star.presentation.TitleTextShape" || sShapeType == "com.sun.star.presentation.OutlinerShape" ||
+ sShapeType == "com.sun.star.presentation.SubtitleShape" || sShapeType == "com.sun.star.drawing.TextShape" )
+ {
+ Reference< XPropertySet > xSet( xShape, UNO_QUERY_THROW );
+
+ FillStyle eFillStyle;
+ xSet->getPropertyValue( "FillStyle" ) >>= eFillStyle;
+
+ css::drawing::LineStyle eLineStyle;
+ xSet->getPropertyValue( "LineStyle" ) >>= eLineStyle;
+
+ return eFillStyle != FillStyle_NONE || eLineStyle != css::drawing::LineStyle_NONE;
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ return true;
+}
+
+std::unique_ptr<STLPropertySet> CustomAnimationPane::createSelectionSet()
+{
+ std::unique_ptr<STLPropertySet> pSet = CustomAnimationDialog::createDefaultSet();
+
+ pSet->setPropertyValue( nHandleCurrentPage, Any( mxCurrentPage ) );
+
+ sal_Int32 nMaxParaDepth = 0;
+
+ // get options from selected effects
+ const CustomAnimationPresets& rPresets (CustomAnimationPresets::getCustomAnimationPresets());
+ for( CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
+ if( !pEffectSequence )
+ pEffectSequence = mpMainSequence.get();
+
+ if( pEffect->hasText() )
+ {
+ sal_Int32 n = calcMaxParaDepth(pEffect->getTargetShape());
+ if( n > nMaxParaDepth )
+ nMaxParaDepth = n;
+ }
+
+ addValue( pSet, nHandleHasAfterEffect, Any( pEffect->hasAfterEffect() ) );
+ addValue( pSet, nHandleAfterEffectOnNextEffect, Any( pEffect->IsAfterEffectOnNext() ) );
+ addValue( pSet, nHandleDimColor, pEffect->getDimColor() );
+ addValue( pSet, nHandleIterateType, Any( pEffect->getIterateType() ) );
+
+ // convert absolute time to percentage value
+ // This calculation is done in float to avoid some rounding artifacts.
+ float fIterateInterval = static_cast<float>(pEffect->getIterateInterval());
+ if( pEffect->getDuration() )
+ fIterateInterval = static_cast<float>(fIterateInterval / pEffect->getDuration() );
+ fIterateInterval *= 100.0;
+ addValue( pSet, nHandleIterateInterval, Any( static_cast<double>(fIterateInterval) ) );
+
+ addValue( pSet, nHandleBegin, Any( pEffect->getBegin() ) );
+ addValue( pSet, nHandleDuration, Any( pEffect->getDuration() ) );
+ addValue( pSet, nHandleStart, Any( pEffect->getNodeType() ) );
+ addValue( pSet, nHandleRepeat, pEffect->getRepeatCount() );
+ addValue( pSet, nHandleEnd, pEffect->getEnd() );
+ addValue( pSet, nHandleRewind, Any( pEffect->getFill() ) );
+
+ addValue( pSet, nHandlePresetId, Any( pEffect->getPresetId() ) );
+
+ addValue( pSet, nHandleHasText, Any( pEffect->hasText() ) );
+
+ addValue( pSet, nHandleHasVisibleShape, Any( hasVisibleShape( pEffect->getTargetShape() ) ) );
+
+ Any aSoundSource;
+ if( pEffect->getAudio().is() )
+ {
+ aSoundSource = pEffect->getAudio()->getSource();
+ addValue( pSet, nHandleSoundVolume, Any( pEffect->getAudio()->getVolume() ) );
+// todo addValue( pSet, nHandleSoundEndAfterSlide, makeAny( pEffect->getAudio()->getEndAfterSlide() ) );
+// this is now stored at the XCommand parameter sequence
+ }
+ else if( pEffect->getCommand() == EffectCommands::STOPAUDIO )
+ {
+ aSoundSource <<= true;
+ }
+ addValue( pSet, nHandleSoundURL, aSoundSource );
+
+ sal_Int32 nGroupId = pEffect->getGroupId();
+ CustomAnimationTextGroupPtr pTextGroup;
+ if( nGroupId != -1 )
+ pTextGroup = pEffectSequence->findGroup( nGroupId );
+
+ addValue( pSet, nHandleTextGrouping, Any( pTextGroup ? pTextGroup->getTextGrouping() : sal_Int32(-1) ) );
+ addValue( pSet, nHandleAnimateForm, Any( !pTextGroup || pTextGroup->getAnimateForm() ) );
+ addValue( pSet, nHandleTextGroupingAuto, Any( pTextGroup ? pTextGroup->getTextGroupingAuto() : -1.0 ) );
+ addValue( pSet, nHandleTextReverse, Any( pTextGroup && pTextGroup->getTextReverse() ) );
+
+ if( pEffectSequence->getSequenceType() == EffectNodeType::INTERACTIVE_SEQUENCE )
+ {
+ InteractiveSequence* pIS = static_cast< InteractiveSequence* >( pEffectSequence );
+ addValue( pSet, nHandleTrigger, Any( pIS->getTriggerShape() ) );
+ }
+
+ CustomAnimationPresetPtr pDescriptor = rPresets.getEffectDescriptor( pEffect->getPresetId() );
+ if( pDescriptor )
+ {
+ sal_Int32 nType = nPropertyTypeNone;
+
+ std::vector<OUString> aProperties( pDescriptor->getProperties() );
+ if( !aProperties.empty() )
+ nType = getPropertyType( aProperties.front() );
+
+ if( nType != nPropertyTypeNone )
+ {
+ addValue( pSet, nHandleProperty1Type, Any( nType ) );
+ addValue( pSet, nHandleProperty1Value, getProperty1Value( nType, pEffect ) );
+ }
+
+ if( pDescriptor->hasProperty( u"Accelerate" ) )
+ {
+ addValue( pSet, nHandleAccelerate, Any( pEffect->getAcceleration() ) );
+ }
+
+ if( pDescriptor->hasProperty( u"Decelerate" ) )
+ {
+ addValue( pSet, nHandleDecelerate, Any( pEffect->getDecelerate() ) );
+ }
+
+ if( pDescriptor->hasProperty( u"AutoReverse" ) )
+ {
+ addValue( pSet, nHandleAutoReverse, Any( pEffect->getAutoReverse() ) );
+ }
+ }
+ }
+
+ addValue( pSet, nHandleMaxParaDepth, Any( nMaxParaDepth ) );
+
+ return pSet;
+}
+
+void CustomAnimationPane::changeSelection( STLPropertySet const * pResultSet, STLPropertySet const * pOldSet )
+{
+ // change selected effect
+ bool bChanged = false;
+
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+
+ for( CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ DBG_ASSERT( pEffect->getEffectSequence(), "sd::CustomAnimationPane::changeSelection(), dead effect in selection!" );
+ if( !pEffect->getEffectSequence() )
+ continue;
+
+ double fDuration = 0.0; // we might need this for iterate-interval
+ if( pResultSet->getPropertyState( nHandleDuration ) == STLPropertyState::Direct )
+ {
+ pResultSet->getPropertyValue( nHandleDuration ) >>= fDuration;
+ }
+ else
+ {
+ fDuration = pEffect->getDuration();
+ }
+
+ if( pResultSet->getPropertyState( nHandleIterateType ) == STLPropertyState::Direct )
+ {
+ sal_Int16 nIterateType = 0;
+ pResultSet->getPropertyValue( nHandleIterateType ) >>= nIterateType;
+ if( pEffect->getIterateType() != nIterateType )
+ {
+ pEffect->setIterateType( nIterateType );
+ bChanged = true;
+ }
+ }
+
+ if( pEffect->getIterateType() )
+ {
+ if( pResultSet->getPropertyState( nHandleIterateInterval ) == STLPropertyState::Direct )
+ {
+ double fIterateInterval = 0.0;
+ pResultSet->getPropertyValue( nHandleIterateInterval ) >>= fIterateInterval;
+ if( pEffect->getIterateInterval() != fIterateInterval )
+ {
+ const double f = fIterateInterval * pEffect->getDuration() / 100;
+ pEffect->setIterateInterval( f );
+ bChanged = true;
+ }
+ }
+ }
+
+ double fBegin = 0.0;
+
+ if( pResultSet->getPropertyState( nHandleBegin ) == STLPropertyState::Direct )
+ pResultSet->getPropertyValue( nHandleBegin ) >>= fBegin;
+ else
+ fBegin = pEffect->getBegin();
+
+ if( pEffect->getBegin() != fBegin && pResultSet->getPropertyState( nHandleBegin ) == STLPropertyState::Direct)
+ {
+ pEffect->setBegin( fBegin );
+ bChanged = true;
+ }
+
+ if( pResultSet->getPropertyState( nHandleDuration ) == STLPropertyState::Direct )
+ {
+ if( pEffect->getDuration() != fDuration )
+ {
+ pEffect->setDuration( fDuration );
+ bChanged = true;
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleStart ) == STLPropertyState::Direct )
+ {
+ sal_Int16 nNodeType = 0;
+ pResultSet->getPropertyValue( nHandleStart ) >>= nNodeType;
+ if( pEffect->getNodeType() != nNodeType )
+ {
+ pEffect->setNodeType( nNodeType );
+ bChanged = true;
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleRepeat ) == STLPropertyState::Direct )
+ {
+ Any aRepeatCount( pResultSet->getPropertyValue( nHandleRepeat ) );
+ if( aRepeatCount != pEffect->getRepeatCount() )
+ {
+ pEffect->setRepeatCount( aRepeatCount );
+ bChanged = true;
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleEnd ) == STLPropertyState::Direct )
+ {
+ Any aEndValue( pResultSet->getPropertyValue( nHandleEnd ) );
+ if( pEffect->getEnd() != aEndValue )
+ {
+ pEffect->setEnd( aEndValue );
+ bChanged = true;
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleRewind ) == STLPropertyState::Direct )
+ {
+ sal_Int16 nFill = 0;
+ pResultSet->getPropertyValue( nHandleRewind ) >>= nFill;
+ if( pEffect->getFill() != nFill )
+ {
+ pEffect->setFill( nFill );
+ bChanged = true;
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleHasAfterEffect ) == STLPropertyState::Direct )
+ {
+ bool bHasAfterEffect = false;
+ if( pResultSet->getPropertyValue( nHandleHasAfterEffect ) >>= bHasAfterEffect )
+ {
+ if( pEffect->hasAfterEffect() != bHasAfterEffect )
+ {
+ pEffect->setHasAfterEffect( bHasAfterEffect );
+ bChanged = true;
+ }
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleAfterEffectOnNextEffect ) == STLPropertyState::Direct )
+ {
+ bool bAfterEffectOnNextEffect = false;
+ if( (pResultSet->getPropertyValue( nHandleAfterEffectOnNextEffect ) >>= bAfterEffectOnNextEffect)
+ && (pEffect->IsAfterEffectOnNext() != bAfterEffectOnNextEffect) )
+ {
+ pEffect->setAfterEffectOnNext( bAfterEffectOnNextEffect );
+ bChanged = true;
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleDimColor ) == STLPropertyState::Direct )
+ {
+ Any aDimColor( pResultSet->getPropertyValue( nHandleDimColor ) );
+ if( pEffect->getDimColor() != aDimColor )
+ {
+ pEffect->setDimColor( aDimColor );
+ bChanged = true;
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleAccelerate ) == STLPropertyState::Direct )
+ {
+ double fAccelerate = 0.0;
+ pResultSet->getPropertyValue( nHandleAccelerate ) >>= fAccelerate;
+ if( pEffect->getAcceleration() != fAccelerate )
+ {
+ pEffect->setAcceleration( fAccelerate );
+ bChanged = true;
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleDecelerate ) == STLPropertyState::Direct )
+ {
+ double fDecelerate = 0.0;
+ pResultSet->getPropertyValue( nHandleDecelerate ) >>= fDecelerate;
+ if( pEffect->getDecelerate() != fDecelerate )
+ {
+ pEffect->setDecelerate( fDecelerate );
+ bChanged = true;
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleAutoReverse ) == STLPropertyState::Direct )
+ {
+ bool bAutoReverse = false;
+ pResultSet->getPropertyValue( nHandleAutoReverse ) >>= bAutoReverse;
+ if( pEffect->getAutoReverse() != bAutoReverse )
+ {
+ pEffect->setAutoReverse( bAutoReverse );
+ bChanged = true;
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleProperty1Value ) == STLPropertyState::Direct )
+ {
+ sal_Int32 nType = 0;
+ pOldSet->getPropertyValue( nHandleProperty1Type ) >>= nType;
+
+ bChanged |= setProperty1Value( nType, pEffect, pResultSet->getPropertyValue( nHandleProperty1Value ) );
+ }
+
+ if( pResultSet->getPropertyState( nHandleSoundURL ) == STLPropertyState::Direct )
+ {
+ const Any aSoundSource( pResultSet->getPropertyValue( nHandleSoundURL ) );
+
+ if( aSoundSource.getValueType() == ::cppu::UnoType<sal_Bool>::get() )
+ {
+ pEffect->setStopAudio();
+ bChanged = true;
+ }
+ else
+ {
+ OUString aSoundURL;
+ aSoundSource >>= aSoundURL;
+
+ if( !aSoundURL.isEmpty() )
+ {
+ if( !pEffect->getAudio().is() )
+ {
+ pEffect->createAudio( aSoundSource );
+ bChanged = true;
+ }
+ else
+ {
+ if( pEffect->getAudio()->getSource() != aSoundSource )
+ {
+ pEffect->getAudio()->setSource( aSoundSource );
+ bChanged = true;
+ }
+ }
+ }
+ else
+ {
+ if( pEffect->getAudio().is() || pEffect->getStopAudio() )
+ {
+ pEffect->removeAudio();
+ bChanged = true;
+ }
+ }
+ }
+ }
+
+ if( pResultSet->getPropertyState( nHandleTrigger ) == STLPropertyState::Direct )
+ {
+ Reference< XShape > xTriggerShape;
+ pResultSet->getPropertyValue( nHandleTrigger ) >>= xTriggerShape;
+ bChanged |= mpMainSequence->setTrigger( pEffect, xTriggerShape );
+ }
+ }
+
+ const bool bHasTextGrouping = pResultSet->getPropertyState( nHandleTextGrouping ) == STLPropertyState::Direct;
+ const bool bHasAnimateForm = pResultSet->getPropertyState( nHandleAnimateForm ) == STLPropertyState::Direct;
+ const bool bHasTextGroupingAuto = pResultSet->getPropertyState( nHandleTextGroupingAuto ) == STLPropertyState::Direct;
+ const bool bHasTextReverse = pResultSet->getPropertyState( nHandleTextReverse ) == STLPropertyState::Direct;
+
+ if( bHasTextGrouping || bHasAnimateForm || bHasTextGroupingAuto || bHasTextReverse )
+ {
+ // we need to do a second pass for text grouping options
+ // since changing them can cause effects to be removed
+ // or replaced, we do this after we applied all other options
+ // above
+
+ sal_Int32 nTextGrouping = 0;
+ bool bAnimateForm = true, bTextReverse = false;
+ double fTextGroupingAuto = -1.0;
+
+ if( bHasTextGrouping )
+ pResultSet->getPropertyValue(nHandleTextGrouping) >>= nTextGrouping;
+ else
+ pOldSet->getPropertyValue(nHandleTextGrouping) >>= nTextGrouping;
+
+ if( bHasAnimateForm )
+ pResultSet->getPropertyValue(nHandleAnimateForm) >>= bAnimateForm;
+ else
+ pOldSet->getPropertyValue(nHandleAnimateForm) >>= bAnimateForm;
+
+ if( bHasTextGroupingAuto )
+ pResultSet->getPropertyValue(nHandleTextGroupingAuto) >>= fTextGroupingAuto;
+ else
+ pOldSet->getPropertyValue(nHandleTextGroupingAuto) >>= fTextGroupingAuto;
+
+ if( bHasTextReverse )
+ pResultSet->getPropertyValue(nHandleTextReverse) >>= bTextReverse;
+ else
+ pOldSet->getPropertyValue(nHandleTextReverse) >>= bTextReverse;
+
+ EffectSequence const aSelectedEffects( maListSelection );
+ for( CustomAnimationEffectPtr const& pEffect : aSelectedEffects )
+ {
+ EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
+ if( !pEffectSequence )
+ pEffectSequence = mpMainSequence.get();
+
+ sal_Int32 nGroupId = pEffect->getGroupId();
+ CustomAnimationTextGroupPtr pTextGroup;
+ if( nGroupId != -1 )
+ {
+ // use existing group
+ pTextGroup = pEffectSequence->findGroup( nGroupId );
+ }
+ else
+ {
+ // somethings changed so we need a group now
+ pTextGroup = pEffectSequence->createTextGroup( pEffect, nTextGrouping, fTextGroupingAuto, bAnimateForm, bTextReverse );
+ bChanged = true;
+ }
+
+ //#i119988#
+ /************************************************************************/
+ /*
+ Note, the setAnimateForm means set the animation from TextGroup to Object's Shape
+ And on the UI in means "Animate attached shape" in "Effect Option" dialog
+ The setTextGrouping means set animation to Object's Text,
+ the nTextGrouping is Text Animation Type
+ nTextGrouping = -1 is "As one Object", means no text animation.
+
+ The previous call order first do the setTextGrouping and then do the setAnimateForm,
+ that will cause such defect: in the setTextGrouping, the effect has been removed,
+ but in setAnimateForm still need this effect, then a NULL pointer of that effect will
+ be gotten, and cause crash.
+
+ []bHasAnimateForm means the UI has changed, bAnimateForm is it value
+
+ So if create a new textgroup animation, the following animation will never be run!
+ Since the \A1\B0Animate attached shape\A1\B1 is default checked.
+ And the bHasAnimateForm default is false, and if user uncheck it the value bAnimateForm will be false,
+ it same as the TextGroup\A1\AFs default value, also could not be run setAnimateForm.
+ if( bHasAnimateForm )
+ {
+ if( pTextGroup->getAnimateForm() != bAnimateForm )
+ {
+ pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
+ bChanged = true;
+ }
+ }
+
+ In setTextGrouping, there are three case:
+ 1. Create new text effects for empty TextGroup
+ 2. Remove all text effects of TextGroup (nTextGrouping == -1)
+ 3. Change all the text effects\A1\AF start type
+
+ So here is the right logic:
+ If set the animation from text to shape and remove text animation,
+ should do setAnimateForm first, then do setTextGrouping.
+ Other case,do setTextGrouping first, then do setAnimateForm.
+
+ */
+ /************************************************************************/
+
+ bool bDoSetAnimateFormFirst = false;
+ bool bNeedDoSetAnimateForm = false;
+
+ if( bHasAnimateForm )
+ {
+ if( pTextGroup && pTextGroup->getAnimateForm() != bAnimateForm )
+ {
+ if( (pTextGroup->getTextGrouping() >= 0) && (nTextGrouping == -1 ) )
+ {
+ bDoSetAnimateFormFirst = true;
+ }
+ bNeedDoSetAnimateForm = true;
+ }
+ }
+
+ if (bDoSetAnimateFormFirst)
+ {
+ pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
+ bChanged = true;
+ }
+
+ if( bHasTextGrouping )
+ {
+ if( pTextGroup && pTextGroup->getTextGrouping() != nTextGrouping )
+ {
+ pEffectSequence->setTextGrouping( pTextGroup, nTextGrouping );
+
+ // All the effects of the outline object is removed so we need to
+ // put it back. OTOH, the shape object that still has effects
+ // in the text group is fine.
+ if (nTextGrouping == -1 && pTextGroup->getEffects().empty())
+ {
+ pEffect->setTarget(Any(pEffect->getTargetShape()));
+ pEffect->setGroupId(-1);
+ mpMainSequence->append(pEffect);
+ }
+
+ bChanged = true;
+ }
+ }
+
+ if (!bDoSetAnimateFormFirst && bNeedDoSetAnimateForm)
+ {
+ if( pTextGroup )
+ {
+ pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
+ bChanged = true;
+ }
+ }
+
+ if( bHasTextGroupingAuto )
+ {
+ if( pTextGroup && pTextGroup->getTextGroupingAuto() != fTextGroupingAuto )
+ {
+ pEffectSequence->setTextGroupingAuto( pTextGroup, fTextGroupingAuto );
+ bChanged = true;
+ }
+ }
+
+ if( bHasTextReverse )
+ {
+ if( pTextGroup && pTextGroup->getTextReverse() != bTextReverse )
+ {
+ pEffectSequence->setTextReverse( pTextGroup, bTextReverse );
+ bChanged = true;
+ }
+ }
+ }
+ }
+
+ if( bChanged )
+ {
+ mpMainSequence->rebuild();
+ updateControls();
+ mrBase.GetDocShell()->SetModified();
+ }
+}
+
+void CustomAnimationPane::showOptions(const OString& rPage)
+{
+ std::unique_ptr<STLPropertySet> xSet = createSelectionSet();
+
+ auto xDlg = std::make_shared<CustomAnimationDialog>(GetFrameWeld(), std::move(xSet), rPage);
+
+ weld::DialogController::runAsync(xDlg, [xDlg, this](sal_Int32 nResult){
+ if (nResult )
+ {
+ addUndo();
+ changeSelection(xDlg->getResultSet(), xDlg->getPropertySet());
+ updateControls();
+ }
+ });
+}
+
+void CustomAnimationPane::onChangeCurrentPage()
+{
+ if( !mxView.is() )
+ return;
+
+ try
+ {
+ Reference< XDrawPage > xNewPage( mxView->getCurrentPage() );
+ if( xNewPage != mxCurrentPage )
+ {
+ mxCurrentPage = xNewPage;
+ SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
+ if( pPage )
+ {
+ mpMainSequence = pPage->getMainSequence();
+ mxCustomAnimationList->update( mpMainSequence );
+ }
+ updateControls();
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::onChangeCurrentPage()" );
+ }
+}
+
+static bool getTextSelection( const Any& rSelection, Reference< XShape >& xShape, std::vector< sal_Int16 >& rParaList )
+{
+ Reference< XTextRange > xSelectedText;
+ rSelection >>= xSelectedText;
+ if( xSelectedText.is() ) try
+ {
+ xShape.set( xSelectedText->getText(), UNO_QUERY_THROW );
+
+ css::uno::Reference<css::document::XActionLockable> xLockable(xShape, css::uno::UNO_QUERY);
+ if (xLockable.is())
+ xLockable->addActionLock();
+ comphelper::ScopeGuard aGuard([&xLockable]()
+ {
+ if (xLockable.is())
+ xLockable->removeActionLock();
+ });
+
+ Reference< XTextRangeCompare > xTextRangeCompare( xShape, UNO_QUERY_THROW );
+ Reference< XEnumerationAccess > xParaEnumAccess( xShape, UNO_QUERY_THROW );
+ Reference< XEnumeration > xParaEnum( xParaEnumAccess->createEnumeration(), UNO_SET_THROW );
+ Reference< XTextRange > xRange;
+ Reference< XTextRange > xStart( xSelectedText->getStart() );
+ Reference< XTextRange > xEnd( xSelectedText->getEnd() );
+
+ if( xTextRangeCompare->compareRegionEnds( xStart, xEnd ) < 0 )
+ {
+ Reference< XTextRange > xTemp( xStart );
+ xStart = xEnd;
+ xEnd = xTemp;
+ }
+
+ sal_Int16 nPara = 0;
+ while( xParaEnum->hasMoreElements() )
+ {
+ xParaEnum->nextElement() >>= xRange;
+
+ // break if start of selection is prior to end of current paragraph
+ if( xRange.is() && (xTextRangeCompare->compareRegionEnds( xStart, xRange ) >= 0 ) )
+ break;
+
+ nPara++;
+ }
+
+ while( xRange.is() )
+ {
+ if( xRange.is() && !xRange->getString().isEmpty() )
+ rParaList.push_back( nPara );
+
+ // break if end of selection is before or at end of current paragraph
+ if( xRange.is() && xTextRangeCompare->compareRegionEnds( xEnd, xRange ) >= 0 )
+ break;
+
+ nPara++;
+
+ if( xParaEnum->hasMoreElements() )
+ xParaEnum->nextElement() >>= xRange;
+ else
+ xRange.clear();
+ }
+
+ return true;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::getTextSelection()" );
+ }
+
+ return false;
+}
+
+namespace
+{
+ Reference<XShape> getTargetShape(const Any& rTarget)
+ {
+ Reference<XShape> xShape;
+ rTarget >>= xShape;
+ if( !xShape.is() )
+ {
+ ParagraphTarget aParaTarget;
+ if (rTarget >>= aParaTarget)
+ xShape = aParaTarget.Shape;
+ }
+ return xShape;
+ }
+}
+
+void CustomAnimationPane::onAdd()
+{
+ bool bHasText = true;
+
+ // first create vector of targets for dialog preview
+ std::vector< Any > aTargets;
+
+ // gather shapes from the selection
+ Reference< XSelectionSupplier > xSel( mxView, UNO_QUERY_THROW );
+ maViewSelection = xSel->getSelection();
+
+ if( maViewSelection.getValueType() == cppu::UnoType<XShapes>::get())
+ {
+ Reference< XIndexAccess > xShapes;
+ maViewSelection >>= xShapes;
+
+ sal_Int32 nCount = xShapes->getCount();
+ aTargets.reserve( nCount );
+ for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ Any aTarget( xShapes->getByIndex( nIndex ) );
+ aTargets.push_back( aTarget );
+ if( bHasText )
+ {
+ Reference< XText > xText;
+ aTarget >>= xText;
+ if( !xText.is() || xText->getString().isEmpty() )
+ bHasText = false;
+ }
+ }
+ }
+ else if ( maViewSelection.getValueType() == cppu::UnoType<XShape>::get())
+ {
+ aTargets.push_back( maViewSelection );
+ Reference< XText > xText;
+ maViewSelection >>= xText;
+ if( !xText.is() || xText->getString().isEmpty() )
+ bHasText = false;
+ }
+ else if ( maViewSelection.getValueType() == cppu::UnoType<XTextCursor>::get())
+ {
+ Reference< XShape > xShape;
+ std::vector< sal_Int16 > aParaList;
+ if( getTextSelection( maViewSelection, xShape, aParaList ) )
+ {
+ ParagraphTarget aParaTarget;
+ aParaTarget.Shape = xShape;
+
+ for( const auto& rPara : aParaList )
+ {
+ aParaTarget.Paragraph = rPara;
+ aTargets.push_back( Any( aParaTarget ) );
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("sd::CustomAnimationPane::onAdd(), unknown view selection!" );
+ return;
+ }
+
+ CustomAnimationPresetPtr pDescriptor;
+ mxFTCategory->set_sensitive(true);
+ mxFTAnimation->set_sensitive(true);
+
+ bool bCategoryReset = false;
+
+ if (!mxLBCategory->get_sensitive() || mxLBCategory->get_active() == -1)
+ {
+ mxLBCategory->set_sensitive(true);
+ mxLBCategory->set_active(0);
+ bCategoryReset = true;
+ }
+
+ if (bCategoryReset || !mxLBAnimation->get_sensitive() ||
+ mxLBAnimation->get_selected_index() == -1)
+ {
+ mxLBAnimation->set_sensitive(true);
+
+ sal_Int32 nFirstEffect = fillAnimationLB(bHasText);
+ if (nFirstEffect == -1)
+ return;
+
+ mxLBAnimation->select(nFirstEffect);
+ mnLastSelectedAnimation = nFirstEffect;
+ }
+
+ auto pEntryData = weld::fromId<CustomAnimationPresetPtr*>(mxLBAnimation->get_selected_id());
+ if (pEntryData)
+ pDescriptor = *pEntryData;
+
+ if( pDescriptor )
+ {
+ const double fDuration = pDescriptor->getDuration();
+ mxCBXDuration->set_value(fDuration*100.0, FieldUnit::NONE);
+ bool bHasSpeed = pDescriptor->getDuration() > 0.001;
+ mxCBXDuration->set_sensitive( bHasSpeed );
+ mxFTDuration->set_sensitive( bHasSpeed );
+
+ mxCustomAnimationList->unselect_all();
+
+ // gather shapes from the selection
+ bool bFirst = true;
+ for( const auto& rTarget : aTargets )
+ {
+ css::uno::Reference<css::document::XActionLockable> xLockable(getTargetShape(rTarget), css::uno::UNO_QUERY);
+ if (xLockable.is())
+ xLockable->addActionLock();
+ comphelper::ScopeGuard aGuard([&xLockable]()
+ {
+ if (xLockable.is())
+ xLockable->removeActionLock();
+ });
+
+ CustomAnimationEffectPtr pCreated = mpMainSequence->append( pDescriptor, rTarget, fDuration );
+
+ // if only one shape with text and no fill or outline is selected, animate only by first level paragraphs
+ if( bHasText && (aTargets.size() == 1) )
+ {
+ Reference< XShape > xShape( rTarget, UNO_QUERY );
+ if( xShape.is() && !hasVisibleShape( xShape ) )
+ {
+ mpMainSequence->createTextGroup( pCreated, 1, -1.0, false, false );
+ }
+ }
+
+ if( bFirst )
+ bFirst = false;
+ else
+ pCreated->setNodeType( EffectNodeType::WITH_PREVIOUS );
+
+ if( pCreated )
+ mxCustomAnimationList->select( pCreated );
+ }
+ }
+
+ PathKind ePathKind = getCreatePathKind();
+
+ if (ePathKind != PathKind::NONE)
+ {
+ createPath( ePathKind, aTargets, 0.0 );
+ updateMotionPathTags();
+ }
+
+ addUndo();
+ mrBase.GetDocShell()->SetModified();
+
+ updateControls();
+
+ SlideShow::Stop( mrBase );
+}
+
+void CustomAnimationPane::onRemove()
+{
+ if( maListSelection.empty() )
+ return;
+
+ addUndo();
+
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+
+ EffectSequence aList( maListSelection );
+
+ for( CustomAnimationEffectPtr& pEffect : aList )
+ {
+ if( pEffect->getEffectSequence() )
+ pEffect->getEffectSequence()->remove( pEffect );
+ }
+
+ maListSelection.clear();
+ mrBase.GetDocShell()->SetModified();
+}
+
+void CustomAnimationPane::remove( CustomAnimationEffectPtr const & pEffect )
+{
+ if( pEffect->getEffectSequence() )
+ {
+ addUndo();
+ pEffect->getEffectSequence()->remove( pEffect );
+ mrBase.GetDocShell()->SetModified();
+ }
+}
+
+void CustomAnimationPane::onChangeStart()
+{
+ sal_Int16 nNodeType;
+ switch( mxLBStart->get_active() )
+ {
+ case 0: nNodeType = EffectNodeType::ON_CLICK; break;
+ case 1: nNodeType = EffectNodeType::WITH_PREVIOUS; break;
+ case 2: nNodeType = EffectNodeType::AFTER_PREVIOUS; break;
+ default:
+ return;
+ }
+
+ onChangeStart( nNodeType );
+}
+
+void CustomAnimationPane::onChangeStart( sal_Int16 nNodeType )
+{
+ addUndo();
+
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+
+ bool bNeedRebuild = false;
+
+ for( CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ if( pEffect->getNodeType() != nNodeType )
+ {
+ pEffect->setNodeType( nNodeType );
+ bNeedRebuild = true;
+ }
+ }
+
+ if( bNeedRebuild )
+ {
+ mpMainSequence->rebuild();
+ updateControls();
+ mrBase.GetDocShell()->SetModified();
+ }
+}
+
+void CustomAnimationPane::onChangeSpeed()
+{
+ double fDuration = getDuration();
+
+ if(fDuration < 0)
+ return;
+ else
+ {
+ addUndo();
+
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+
+ // change selected effect
+ for( CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ pEffect->setDuration( fDuration );
+ }
+
+ mpMainSequence->rebuild();
+ updateControls();
+ mrBase.GetDocShell()->SetModified();
+ }
+}
+
+double CustomAnimationPane::getDuration() const
+{
+ double fDuration = 0;
+
+ if (!mxCBXDuration->get_text().isEmpty())
+ fDuration = mxCBXDuration->get_value(FieldUnit::NONE) / 100.0;
+
+ return fDuration;
+}
+
+PathKind CustomAnimationPane::getCreatePathKind() const
+{
+ PathKind eKind = PathKind::NONE;
+
+ if (mxLBAnimation->count_selected_rows() == 1 &&
+ mxLBCategory->get_active() == gnMotionPathPos)
+ {
+ const sal_Int32 nPos = mxLBAnimation->get_selected_index();
+ if( nPos == mnCurvePathPos )
+ {
+ eKind = PathKind::CURVE;
+ }
+ else if( nPos == mnPolygonPathPos )
+ {
+ eKind = PathKind::POLYGON;
+ }
+ else if( nPos == mnFreeformPathPos )
+ {
+ eKind = PathKind::FREEFORM;
+ }
+ }
+
+ return eKind;
+}
+
+void CustomAnimationPane::createPath( PathKind eKind, std::vector< Any >& rTargets, double fDuration)
+{
+ sal_uInt16 nSID = 0;
+
+ switch( eKind )
+ {
+ case PathKind::CURVE: nSID = SID_DRAW_BEZIER_NOFILL; break;
+ case PathKind::POLYGON: nSID = SID_DRAW_POLYGON_NOFILL; break;
+ case PathKind::FREEFORM: nSID = SID_DRAW_FREELINE_NOFILL; break;
+ default: break;
+ }
+
+ if( !nSID )
+ return;
+
+ DrawViewShell* pViewShell = dynamic_cast< DrawViewShell* >(
+ FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
+
+ if( pViewShell )
+ {
+ DrawView* pView = pViewShell->GetDrawView();
+ if( pView )
+ pView->UnmarkAllObj();
+
+ std::vector< Any > aTargets( 1, Any( fDuration ) );
+ aTargets.insert( aTargets.end(), rTargets.begin(), rTargets.end() );
+ Sequence< Any > aTargetSequence( comphelper::containerToSequence( aTargets ) );
+ const SfxUnoAnyItem aItem( SID_ADD_MOTION_PATH, Any( aTargetSequence ) );
+ pViewShell->GetViewFrame()->GetDispatcher()->ExecuteList( nSID, SfxCallMode::ASYNCHRON, {&aItem} );
+ }
+}
+
+
+/// this link is called when the property box is modified by the user
+IMPL_LINK_NOARG(CustomAnimationPane, implPropertyHdl, LinkParamNone*, void)
+{
+ if (!mxLBSubControl)
+ return;
+
+ addUndo();
+
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+
+ const Any aValue(mxLBSubControl->getValue());
+
+ bool bNeedUpdate = false;
+
+ // change selected effect
+ for( const CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ if( setProperty1Value( mnPropertyType, pEffect, aValue ) )
+ bNeedUpdate = true;
+ }
+
+ if( bNeedUpdate )
+ {
+ mpMainSequence->rebuild();
+ updateControls();
+ mrBase.GetDocShell()->SetModified();
+ }
+
+ onPreview( false );
+}
+
+IMPL_LINK_NOARG(CustomAnimationPane, DelayModifiedHdl, weld::MetricSpinButton&, void)
+{
+ addUndo();
+}
+
+IMPL_LINK_NOARG(CustomAnimationPane, DelayLoseFocusHdl, weld::Widget&, void)
+{
+ double fBegin = mxMFStartDelay->get_value(FieldUnit::NONE);
+
+ //sequence rebuild only when the control loses focus
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+
+ // change selected effect
+ for( CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ pEffect->setBegin( fBegin/10.0 );
+ }
+
+ mpMainSequence->rebuild();
+ updateControls();
+ mrBase.GetDocShell()->SetModified();
+}
+
+IMPL_LINK_NOARG(CustomAnimationPane, AnimationSelectHdl, weld::TreeView&, void)
+{
+ maIdle.Start();
+}
+
+IMPL_LINK_NOARG(CustomAnimationPane, SelectionHandler, Timer*, void)
+{
+ if (mxLBAnimation->has_grab()) // tdf#136474 try again later
+ {
+ maIdle.Start();
+ return;
+ }
+
+ int nSelected = mxLBAnimation->get_selected_index();
+ if (nSelected == -1)
+ return;
+
+ // tdf#99137, the selected entry may also be a subcategory title, so not an effect
+ // just skip it and move to the next one in this case
+ if (mxLBAnimation->get_text_emphasis(nSelected, 0))
+ {
+ if (nSelected == 0 || nSelected > mnLastSelectedAnimation)
+ mxLBAnimation->select(++nSelected);
+ else
+ mxLBAnimation->select(--nSelected);
+ }
+
+ mnLastSelectedAnimation = nSelected;
+
+ CustomAnimationPresetPtr* pPreset = weld::fromId<CustomAnimationPresetPtr*>(mxLBAnimation->get_id(nSelected));
+ PathKind ePathKind = getCreatePathKind();
+
+ if ( ePathKind != PathKind::NONE )
+ {
+ std::vector< Any > aTargets;
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+
+ for( const CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ aTargets.push_back( pEffect->getTarget() );
+
+ EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
+ if( !pEffectSequence )
+ pEffectSequence = mpMainSequence.get();
+
+ // delete the old animation, new one will be appended
+ // by createPath and SID_ADD_MOTION_PATH therein
+ pEffectSequence->remove( pEffect );
+ }
+
+ createPath( ePathKind, aTargets, 0.0 );
+ updateMotionPathTags();
+ return;
+ }
+
+ CustomAnimationPresetPtr pDescriptor(*pPreset);
+ const double fDuration = (*pPreset)->getDuration();
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+
+ // get selected effect
+ for( const CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ // Dispose the deprecated motion path tag. It will be rebuilt later.
+ if (pEffect->getPresetClass() == css::presentation::EffectPresetClass::MOTIONPATH)
+ {
+ for (auto const& xTag: maMotionPathTags)
+ {
+ if(xTag->getEffect() == pEffect && !xTag->isDisposed())
+ xTag->Dispose();
+ }
+ }
+
+ EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
+ if( !pEffectSequence )
+ pEffectSequence = mpMainSequence.get();
+
+ pEffectSequence->replace( pEffect, pDescriptor, fDuration );
+ }
+
+ addUndo();
+ onPreview(false);
+}
+
+IMPL_LINK_NOARG(CustomAnimationPane, UpdateAnimationLB, weld::ComboBox&, void)
+{
+ //FIXME: first effect only? what if there is more?
+ CustomAnimationEffectPtr pEffect = maListSelection.front();
+ fillAnimationLB( pEffect->hasText() );
+}
+
+IMPL_LINK_NOARG(CustomAnimationPane, DurationModifiedHdl, weld::MetricSpinButton&, void)
+{
+ if (!mxCBXDuration->get_text().isEmpty())
+ {
+ double duration_value = static_cast<double>(mxCBXDuration->get_value(FieldUnit::NONE));
+ if(duration_value <= 0.0)
+ {
+ mxCBXDuration->set_value(1, FieldUnit::NONE);
+ }
+ onChangeSpeed();
+ }
+}
+
+namespace
+{
+ void InsertCategory(weld::TreeView& rLBAnimation, const OUString& rMotionPathLabel)
+ {
+ int nRow = rLBAnimation.n_children();
+ rLBAnimation.append_text(rMotionPathLabel);
+ rLBAnimation.set_text_emphasis(nRow, true, 0);
+ rLBAnimation.set_text_align(nRow, 0.5, 0);
+ }
+}
+
+sal_Int32 CustomAnimationPane::fillAnimationLB( bool bHasText )
+{
+ PresetCategoryList rCategoryList;
+ sal_uInt16 nPosition = mxLBCategory->get_active();
+ const CustomAnimationPresets& rPresets (CustomAnimationPresets::getCustomAnimationPresets());
+ switch(nPosition)
+ {
+ case 0:rCategoryList = rPresets.getEntrancePresets();break;
+ case 1:rCategoryList = rPresets.getEmphasisPresets();break;
+ case 2:rCategoryList = rPresets.getExitPresets();break;
+ case 3:rCategoryList = rPresets.getMotionPathsPresets();break;
+ case 4:rCategoryList = rPresets.getMiscPresets();break;
+ }
+
+ sal_Int32 nFirstEffect = -1;
+
+ int nOldEntryCount = mxLBAnimation->n_children();
+ int nOldScrollPos = mxLBAnimation->vadjustment_get_value();
+
+ mxLBAnimation->freeze();
+ mxLBAnimation->clear();
+ mnLastSelectedAnimation = -1;
+
+ if (nPosition == gnMotionPathPos)
+ {
+ OUString sMotionPathLabel( SdResId( STR_CUSTOMANIMATION_USERPATH ) );
+ InsertCategory(*mxLBAnimation, sMotionPathLabel);
+ mnCurvePathPos = mxLBAnimation->n_children();
+ mxLBAnimation->append_text( SvxResId(STR_ObjNameSingulCOMBLINE) );
+ mxLBAnimation->set_text_emphasis(mnCurvePathPos, false, 0);
+ mnPolygonPathPos = mnCurvePathPos + 1;
+ mxLBAnimation->append_text( SvxResId(STR_ObjNameSingulPOLY) );
+ mxLBAnimation->set_text_emphasis(mnPolygonPathPos, false, 0);
+ mnFreeformPathPos = mnPolygonPathPos + 1;
+ mxLBAnimation->append_text( SvxResId(STR_ObjNameSingulFREELINE) );
+ mxLBAnimation->set_text_emphasis(mnFreeformPathPos, false, 0);
+ }
+
+ for (const PresetCategoryPtr& pCategory : rCategoryList)
+ {
+ if( pCategory )
+ {
+ InsertCategory(*mxLBAnimation, pCategory->maLabel);
+
+ int nPos = mxLBAnimation->n_children();
+
+ std::vector< CustomAnimationPresetPtr > aSortedVector =
+ pCategory->maEffects;
+
+ for( const CustomAnimationPresetPtr& pDescriptor : aSortedVector )
+ {
+ // ( !isTextOnly || ( isTextOnly && bHasText ) ) <=> !isTextOnly || bHasText
+ if( pDescriptor && ( !pDescriptor->isTextOnly() || bHasText ) )
+ {
+ auto pCustomPtr = new CustomAnimationPresetPtr(pDescriptor);
+ OUString sId = weld::toId(pCustomPtr);
+ mxLBAnimation->append(sId, pDescriptor->getLabel());
+ mxLBAnimation->set_text_emphasis(nPos, false, 0);
+
+ if (nFirstEffect == -1)
+ nFirstEffect = nPos;
+
+ ++nPos;
+ }
+ }
+ }
+ }
+
+ mxLBAnimation->thaw();
+
+ if (mxLBAnimation->n_children() == nOldEntryCount)
+ mxLBAnimation->vadjustment_set_value(nOldScrollPos);
+
+ return nFirstEffect;
+}
+
+IMPL_LINK(CustomAnimationPane, implToggleHdl, weld::Toggleable&, rBtn, void)
+{
+ implControlHdl(&rBtn);
+}
+
+IMPL_LINK(CustomAnimationPane, implClickHdl, weld::Button&, rBtn, void)
+{
+ implControlHdl(&rBtn);
+}
+
+IMPL_LINK( CustomAnimationPane, implControlListBoxHdl, weld::ComboBox&, rListBox, void )
+{
+ implControlHdl(&rListBox);
+}
+
+/// this link is called when one of the controls is modified
+void CustomAnimationPane::implControlHdl(const weld::Widget* pControl)
+{
+ if (pControl == mxPBAddEffect.get())
+ onAdd();
+ else if (pControl == mxPBRemoveEffect.get())
+ onRemove();
+ else if (pControl == mxLBStart.get())
+ onChangeStart();
+ else if (pControl == mxPBPropertyMore.get())
+ showOptions();
+ else if (pControl == mxPBMoveUp.get())
+ moveSelection( true );
+ else if (pControl == mxPBMoveDown.get())
+ moveSelection( false );
+ else if (pControl == mxPBPlay.get())
+ onPreview( true );
+ else if (pControl == mxCBAutoPreview.get())
+ {
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ pOptions->SetPreviewChangedEffects(mxCBAutoPreview->get_active());
+ }
+}
+
+IMPL_LINK_NOARG(CustomAnimationPane, lateInitCallback, Timer *, void)
+{
+ // Call getPresets() to initiate the (expensive) construction of the
+ // presets list.
+ CustomAnimationPresets::getCustomAnimationPresets();
+
+ // update selection and control states
+ onSelectionChanged();
+}
+
+void CustomAnimationPane::moveSelection( bool bUp )
+{
+ if( maListSelection.empty() )
+ return;
+
+ EffectSequenceHelper* pSequence = maListSelection.front()->getEffectSequence();
+ if( pSequence == nullptr )
+ return;
+
+ addUndo();
+
+ bool bChanged = false;
+
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+ EffectSequence& rEffectSequence = pSequence->getSequence();
+
+ if( bUp )
+ {
+ for( const CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ EffectSequence::iterator aUpEffectPos( pSequence->find( pEffect ) );
+ // coverity[copy_paste_error : FALSE] - this is correct, checking if it exists
+ if( aUpEffectPos != rEffectSequence.end() )
+ {
+ EffectSequence::iterator aInsertPos( rEffectSequence.erase( aUpEffectPos ) );
+
+ if( aInsertPos != rEffectSequence.begin() )
+ {
+ --aInsertPos;
+ while( (aInsertPos != rEffectSequence.begin()) && !mxCustomAnimationList->isExpanded(*aInsertPos))
+ --aInsertPos;
+ rEffectSequence.insert( aInsertPos, pEffect );
+ }
+ else
+ {
+ rEffectSequence.push_front( pEffect );
+ }
+ bChanged = true;
+ }
+ }
+ }
+ else
+ {
+ EffectSequence::reverse_iterator aIter( maListSelection.rbegin() );
+ const EffectSequence::reverse_iterator aEnd( maListSelection.rend() );
+
+ while( aIter != aEnd )
+ {
+ CustomAnimationEffectPtr pEffect = *aIter++;
+
+ EffectSequence::iterator aDownEffectPos( pSequence->find( pEffect ) );
+ // coverity[copy_paste_error : FALSE] - this is correct, checking if it exists
+ if( aDownEffectPos != rEffectSequence.end() )
+ {
+ EffectSequence::iterator aInsertPos( rEffectSequence.erase( aDownEffectPos ) );
+
+ if( aInsertPos != rEffectSequence.end() )
+ {
+ ++aInsertPos;
+ // Advance over rolled-up (un-expanded) items, unless we just moved it there.
+ while( (aInsertPos != rEffectSequence.end())
+ && !mxCustomAnimationList->isExpanded(*aInsertPos)
+ && (std::find(maListSelection.begin(), maListSelection.end(), *aInsertPos)
+ == maListSelection.end())
+ )
+ ++aInsertPos;
+ rEffectSequence.insert( aInsertPos, pEffect );
+ }
+ else
+ {
+ rEffectSequence.push_back( pEffect );
+ }
+ bChanged = true;
+ }
+ }
+ }
+
+ if( bChanged )
+ {
+ mpMainSequence->rebuild();
+ updateControls();
+ mrBase.GetDocShell()->SetModified();
+ }
+}
+
+void CustomAnimationPane::onPreview( bool bForcePreview )
+{
+ if (!bForcePreview && !mxCBAutoPreview->get_active())
+ return;
+
+ // No preview in LOK.
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+
+ if( maListSelection.empty() )
+ {
+ rtl::Reference< MotionPathTag > xMotionPathTag;
+ auto aIter = std::find_if(maMotionPathTags.begin(), maMotionPathTags.end(),
+ [](const MotionPathTagVector::value_type& rxMotionPathTag) { return rxMotionPathTag->isSelected(); });
+ if (aIter != maMotionPathTags.end())
+ xMotionPathTag = *aIter;
+
+ if( xMotionPathTag.is() )
+ {
+ MainSequencePtr pSequence = std::make_shared<MainSequence>();
+ pSequence->append( xMotionPathTag->getEffect()->clone() );
+ preview( pSequence->getRootNode() );
+ }
+ else
+ {
+ Reference< XAnimationNodeSupplier > xNodeSupplier( mxCurrentPage, UNO_QUERY );
+ if( !xNodeSupplier.is() )
+ return;
+
+ preview( xNodeSupplier->getAnimationNode() );
+ }
+ }
+ else
+ {
+ MainSequencePtr pSequence = std::make_shared<MainSequence>();
+
+ for( const CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ pSequence->append( pEffect->clone() );
+ }
+
+ preview( pSequence->getRootNode() );
+ }
+}
+
+void CustomAnimationPane::preview( const Reference< XAnimationNode >& xAnimationNode )
+{
+ Reference< XParallelTimeContainer > xRoot = ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() );
+ Sequence< css::beans::NamedValue > aUserData
+ { { "node-type", css::uno::Any(css::presentation::EffectNodeType::TIMING_ROOT) } };
+ xRoot->setUserData( aUserData );
+ xRoot->appendChild( xAnimationNode );
+
+ SlideShow::StartPreview( mrBase, mxCurrentPage, xRoot );
+}
+
+// ICustomAnimationListController
+void CustomAnimationPane::onSelect()
+{
+ maListSelection = mxCustomAnimationList->getSelection();
+ updateControls();
+
+ // mark shapes from selected effects
+ if( maSelectionLock.isLocked() )
+ return;
+
+ // tdf#145030 if nothing is selected in the effects list, leave the selection of
+ // objects in the slide untouched
+ if (maListSelection.empty())
+ return;
+
+ ScopeLockGuard aGuard( maSelectionLock );
+ DrawViewShell* pViewShell = dynamic_cast< DrawViewShell* >(
+ FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
+ DrawView* pView = pViewShell ? pViewShell->GetDrawView() : nullptr;
+
+ if( pView )
+ {
+ pView->UnmarkAllObj();
+ for( const CustomAnimationEffectPtr& pEffect : maListSelection )
+ {
+ Reference< XShape > xShape( pEffect->getTargetShape() );
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
+ if( pObj )
+ pView->MarkObj(pObj, pView->GetSdrPageView());
+ }
+ }
+}
+
+// ICustomAnimationListController
+// pEffectInsertBefore may be null if moving to end of list.
+void CustomAnimationPane::onDragNDropComplete(std::vector< CustomAnimationEffectPtr > pEffectsDragged, CustomAnimationEffectPtr pEffectInsertBefore)
+{
+ if ( !mpMainSequence )
+ return;
+
+ addUndo();
+
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+
+ // Move all selected effects
+ for( auto const& pEffectDragged : pEffectsDragged )
+ {
+ // Move this dragged effect and any hidden sub-effects
+ EffectSequence::iterator aIter = mpMainSequence->find( pEffectDragged );
+ const EffectSequence::iterator aEnd( mpMainSequence->getEnd() );
+
+ while( aIter != aEnd )
+ {
+ CustomAnimationEffectPtr pEffect = *aIter++;
+
+ // Update model with new location (function triggers a rebuild)
+ // target may be null, which will insert at the end.
+ mpMainSequence->moveToBeforeEffect( pEffect, pEffectInsertBefore );
+ // Done moving effect and its hidden sub-effects when *next* effect is visible.
+ if (aIter != aEnd && mxCustomAnimationList->isVisible(*aIter))
+ break;
+ }
+ }
+
+ updateControls();
+ mrBase.GetDocShell()->SetModified();
+}
+
+void CustomAnimationPane::updatePathFromMotionPathTag( const rtl::Reference< MotionPathTag >& xTag )
+{
+ MainSequenceRebuildGuard aGuard( mpMainSequence );
+ if( !xTag.is() )
+ return;
+
+ SdrPathObj* pPathObj = xTag->getPathObj();
+ CustomAnimationEffectPtr pEffect = xTag->getEffect();
+ if( (pPathObj != nullptr) && pEffect )
+ {
+ SfxUndoManager* pManager = mrBase.GetDocShell()->GetUndoManager();
+ if( pManager )
+ {
+ SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
+ if( pPage )
+ pManager->AddUndoAction( std::make_unique<UndoAnimationPath>( mrBase.GetDocShell()->GetDoc(), pPage, pEffect->getNode() ) );
+ }
+
+ pEffect->updatePathFromSdrPathObj( *pPathObj );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/animations/STLPropertySet.cxx b/sd/source/ui/animations/STLPropertySet.cxx
new file mode 100644
index 000000000..592d7639c
--- /dev/null
+++ b/sd/source/ui/animations/STLPropertySet.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "STLPropertySet.hxx"
+#include <sal/log.hxx>
+
+using com::sun::star::uno::Any;
+
+namespace sd
+{
+
+STLPropertySet::STLPropertySet()
+{
+}
+
+STLPropertySet::~STLPropertySet()
+{
+}
+
+void STLPropertySet::setPropertyDefaultValue( sal_Int32 nHandle, const Any& rValue )
+{
+ STLPropertyMapEntry aEntry( rValue );
+ maPropertyMap[ nHandle ] = aEntry;
+}
+
+void STLPropertySet::setPropertyValue( sal_Int32 nHandle, const Any& rValue )
+{
+ PropertyMapIter aIter;
+ if( findProperty( nHandle, aIter ) )
+ {
+ (*aIter).second.mnState = STLPropertyState::Direct;
+ (*aIter).second.maValue = rValue;
+ }
+ else
+ {
+ SAL_WARN("sd", "sd::STLPropertySet::setPropertyValue(), unknown property!");
+ }
+}
+
+Any STLPropertySet::getPropertyValue( sal_Int32 nHandle ) const
+{
+ PropertyMapConstIter aIter;
+ if( findProperty( nHandle, aIter ) )
+ {
+ return (*aIter).second.maValue;
+ }
+ else
+ {
+ SAL_WARN("sd", "sd::STLPropertySet::getPropertyValue(), unknown property!");
+
+ Any aAny;
+ return aAny;
+ }
+}
+
+STLPropertyState STLPropertySet::getPropertyState( sal_Int32 nHandle ) const
+{
+ PropertyMapConstIter aIter;
+ if( findProperty( nHandle, aIter ) )
+ {
+ return (*aIter).second.mnState;
+ }
+ else
+ {
+ SAL_WARN("sd", "sd::STLPropertySet::getPropertyState(), unknown property!");
+ return STLPropertyState::Ambiguous;
+ }
+}
+
+void STLPropertySet::setPropertyState( sal_Int32 nHandle, STLPropertyState nState )
+{
+ PropertyMapIter aIter;
+ if( findProperty( nHandle, aIter ) )
+ {
+ (*aIter).second.mnState = nState;
+ }
+ else
+ {
+ SAL_WARN("sd","sd::STLPropertySet::setPropertyState(), unknown property!");
+ }
+}
+
+bool STLPropertySet::findProperty( sal_Int32 nHandle, PropertyMapIter& rIter )
+{
+ rIter = maPropertyMap.find(nHandle);
+ return( rIter != maPropertyMap.end() );
+}
+
+bool STLPropertySet::findProperty( sal_Int32 nHandle, PropertyMapConstIter& rIter ) const
+{
+ rIter = maPropertyMap.find(nHandle);
+ return( rIter != maPropertyMap.end() );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/animations/STLPropertySet.hxx b/sd/source/ui/animations/STLPropertySet.hxx
new file mode 100644
index 000000000..3096e7c78
--- /dev/null
+++ b/sd/source/ui/animations/STLPropertySet.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <map>
+#include <com/sun/star/uno/Any.hxx>
+
+namespace sd
+{
+
+enum class STLPropertyState {
+ Default = 0,
+ Direct = 1,
+ Ambiguous = 3
+};
+
+struct STLPropertyMapEntry
+{
+ css::uno::Any maValue;
+ STLPropertyState mnState;
+
+ STLPropertyMapEntry()
+ : mnState( STLPropertyState::Ambiguous ) {}
+ explicit STLPropertyMapEntry(css::uno::Any aValue)
+ : maValue( aValue ), mnState( STLPropertyState::Default ) {}
+
+};
+
+typedef std::map<sal_Int32, STLPropertyMapEntry > PropertyMap;
+typedef PropertyMap::iterator PropertyMapIter;
+typedef PropertyMap::const_iterator PropertyMapConstIter;
+
+class STLPropertySet
+{
+public:
+ STLPropertySet();
+ ~STLPropertySet();
+
+ void setPropertyDefaultValue( sal_Int32 nHandle, const css::uno::Any& rValue );
+ void setPropertyValue( sal_Int32 nHandle, const css::uno::Any& rValue );
+ css::uno::Any getPropertyValue( sal_Int32 nHandle ) const;
+
+ STLPropertyState getPropertyState( sal_Int32 nHandle ) const;
+ void setPropertyState( sal_Int32 nHandle, STLPropertyState nState );
+
+private:
+ bool findProperty( sal_Int32 nHandle, PropertyMapIter& rIter );
+ bool findProperty( sal_Int32 nHandle, PropertyMapConstIter& rIter ) const;
+
+private:
+ PropertyMap maPropertyMap;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/animations/SlideTransitionPane.cxx b/sd/source/ui/animations/SlideTransitionPane.cxx
new file mode 100644
index 000000000..846f21c34
--- /dev/null
+++ b/sd/source/ui/animations/SlideTransitionPane.cxx
@@ -0,0 +1,1155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/XDrawView.hpp>
+#include <SlideTransitionPane.hxx>
+
+#include <TransitionPreset.hxx>
+#include <sdresid.hxx>
+#include <ViewShellBase.hxx>
+#include <DrawDocShell.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <drawdoc.hxx>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+#include <filedlg.hxx>
+#include <strings.hrc>
+#include <EventMultiplexer.hxx>
+
+#include <comphelper/lok.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <svx/gallery.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <tools/urlobj.hxx>
+#include <slideshow.hxx>
+#include <sdundogr.hxx>
+#include <undoanim.hxx>
+#include <optsitem.hxx>
+
+#include <o3tl/safeint.hxx>
+
+#include <algorithm>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+
+
+namespace sd::impl
+{
+struct TransitionEffect
+{
+ TransitionEffect() :
+ mnType( 0 ),
+ mnSubType( 0 ),
+ mbDirection( true ),
+ mnFadeColor( 0 )
+ {
+ init();
+ }
+ explicit TransitionEffect( const ::sd::TransitionPreset & rPreset ) :
+ mnType( rPreset.getTransition()),
+ mnSubType( rPreset.getSubtype()),
+ mbDirection( rPreset.getDirection()),
+ mnFadeColor( rPreset.getFadeColor())
+ {
+ init();
+ }
+ explicit TransitionEffect( const SdPage & rPage ) :
+ mnType( rPage.getTransitionType() ),
+ mnSubType( rPage.getTransitionSubtype() ),
+ mbDirection( rPage.getTransitionDirection() ),
+ mnFadeColor( rPage.getTransitionFadeColor() )
+ {
+ init();
+
+ mfDuration = rPage.getTransitionDuration();
+ mfTime = rPage.GetTime();
+ mePresChange = rPage.GetPresChange();
+ mbSoundOn = rPage.IsSoundOn();
+ maSound = rPage.GetSoundFile();
+ mbLoopSound = rPage.IsLoopSound();
+ mbStopSound = rPage.IsStopSound();
+ }
+
+ void init()
+ {
+ mfDuration = 2.0;
+ mfTime = 0.0;
+ mePresChange = PresChange::Manual;
+ mbSoundOn = false;
+ mbLoopSound = false;
+ mbStopSound = false;
+
+ mbEffectAmbiguous = false;
+ mbDurationAmbiguous = false;
+ mbTimeAmbiguous = false;
+ mbPresChangeAmbiguous = false;
+ mbSoundAmbiguous = false;
+ mbLoopSoundAmbiguous = false;
+ }
+
+ void setAllAmbiguous()
+ {
+ mbEffectAmbiguous = true;
+ mbDurationAmbiguous = true;
+ mbTimeAmbiguous = true;
+ mbPresChangeAmbiguous = true;
+ mbSoundAmbiguous = true;
+ mbLoopSoundAmbiguous = true;
+ }
+
+ bool operator == ( const ::sd::TransitionPreset & rPreset ) const
+ {
+ return
+ (mnType == rPreset.getTransition()) &&
+ (mnSubType == rPreset.getSubtype()) &&
+ (mbDirection == rPreset.getDirection()) &&
+ (mnFadeColor == rPreset.getFadeColor());
+ }
+
+ void applyTo( SdPage & rOutPage ) const
+ {
+ if( ! mbEffectAmbiguous )
+ {
+ rOutPage.setTransitionType( mnType );
+ rOutPage.setTransitionSubtype( mnSubType );
+ rOutPage.setTransitionDirection( mbDirection );
+ rOutPage.setTransitionFadeColor( mnFadeColor );
+ }
+
+ if( ! mbDurationAmbiguous )
+ rOutPage.setTransitionDuration( mfDuration );
+ if( ! mbTimeAmbiguous )
+ rOutPage.SetTime( mfTime );
+ if( ! mbPresChangeAmbiguous )
+ rOutPage.SetPresChange( mePresChange );
+ if( ! mbSoundAmbiguous )
+ {
+ if( mbStopSound )
+ {
+ rOutPage.SetStopSound( true );
+ rOutPage.SetSound( false );
+ }
+ else
+ {
+ rOutPage.SetStopSound( false );
+ rOutPage.SetSound( mbSoundOn );
+ rOutPage.SetSoundFile( maSound );
+ }
+ }
+ if( ! mbLoopSoundAmbiguous )
+ rOutPage.SetLoopSound( mbLoopSound );
+ }
+
+ void compareWith( const SdPage & rPage )
+ {
+ TransitionEffect aOtherEffect( rPage );
+ mbEffectAmbiguous = mbEffectAmbiguous || aOtherEffect.mbEffectAmbiguous
+ || (mnType != aOtherEffect.mnType)
+ || (mnSubType != aOtherEffect.mnSubType)
+ || (mbDirection != aOtherEffect.mbDirection)
+ || (mnFadeColor != aOtherEffect.mnFadeColor);
+
+ mbDurationAmbiguous = mbDurationAmbiguous || aOtherEffect.mbDurationAmbiguous || mfDuration != aOtherEffect.mfDuration;
+ mbTimeAmbiguous = mbTimeAmbiguous || aOtherEffect.mbTimeAmbiguous || mfTime != aOtherEffect.mfTime;
+ mbPresChangeAmbiguous = mbPresChangeAmbiguous || aOtherEffect.mbPresChangeAmbiguous || mePresChange != aOtherEffect.mePresChange;
+ mbSoundAmbiguous = mbSoundAmbiguous || aOtherEffect.mbSoundAmbiguous || mbSoundOn != aOtherEffect.mbSoundOn;
+#if 0
+ // Weird leftover isolated expression with no effect, introduced in 2007 in
+ // CWS impress122. Ifdeffed out to avoid compiler warning, kept here in case
+ // somebody who understands this code notices and understands what the
+ // "right" thing to do might be.
+ (!mbStopSound && !aOtherEffect.mbStopSound && maSound != aOtherEffect.maSound) || (mbStopSound != aOtherEffect.mbStopSound);
+#endif
+ mbLoopSoundAmbiguous = mbLoopSoundAmbiguous || aOtherEffect.mbLoopSoundAmbiguous || mbLoopSound != aOtherEffect.mbLoopSound;
+ }
+
+ // effect
+ sal_Int16 mnType;
+ sal_Int16 mnSubType;
+ bool mbDirection;
+ sal_Int32 mnFadeColor;
+
+ // other settings
+ double mfDuration;
+ double mfTime;
+ PresChange mePresChange;
+ bool mbSoundOn;
+ OUString maSound;
+ bool mbLoopSound;
+ bool mbStopSound;
+
+ bool mbEffectAmbiguous;
+ bool mbDurationAmbiguous;
+ bool mbTimeAmbiguous;
+ bool mbPresChangeAmbiguous;
+ bool mbSoundAmbiguous;
+ bool mbLoopSoundAmbiguous;
+};
+
+} // namespace sd::impl
+
+// Local Helper Functions
+namespace
+{
+
+void lcl_ApplyToPages(
+ const ::sd::slidesorter::SharedPageSelection& rpPages,
+ const ::sd::impl::TransitionEffect & rEffect )
+{
+ for( const auto& rpPage : *rpPages )
+ {
+ rEffect.applyTo( *rpPage );
+ }
+}
+
+void lcl_CreateUndoForPages(
+ const ::sd::slidesorter::SharedPageSelection& rpPages,
+ ::sd::ViewShellBase const & rBase )
+{
+ ::sd::DrawDocShell* pDocSh = rBase.GetDocShell();
+ if (!pDocSh)
+ return;
+ SfxUndoManager* pManager = pDocSh->GetUndoManager();
+ if (!pManager)
+ return;
+ SdDrawDocument* pDoc = pDocSh->GetDoc();
+ if (!pDoc)
+ return;
+
+ OUString aComment( SdResId(STR_UNDO_SLIDE_PARAMS) );
+ pManager->EnterListAction(aComment, aComment, 0, rBase.GetViewShellId());
+ std::unique_ptr<SdUndoGroup> pUndoGroup(new SdUndoGroup( pDoc ));
+ pUndoGroup->SetComment( aComment );
+
+ for( const auto& rpPage : *rpPages )
+ {
+ pUndoGroup->AddAction( new sd::UndoTransition( pDoc, rpPage ) );
+ }
+
+ pManager->AddUndoAction( std::move(pUndoGroup) );
+ pManager->LeaveListAction();
+}
+
+struct lcl_EqualsSoundFileName
+{
+ explicit lcl_EqualsSoundFileName( const OUString & rStr ) :
+ maStr( rStr )
+ {}
+
+ bool operator() ( const OUString & rStr ) const
+ {
+ // note: formerly this was a case insensitive search for all
+ // platforms. It seems more sensible to do this platform-dependent
+ INetURLObject aURL(rStr);
+#if defined(_WIN32)
+ return maStr.equalsIgnoreAsciiCase( aURL.GetBase() );
+#else
+ return maStr == aURL.GetBase();
+#endif
+ }
+
+private:
+ OUString maStr;
+};
+
+// returns -1 if no object was found
+bool lcl_findSoundInList( const ::std::vector< OUString > & rSoundList,
+ std::u16string_view rFileName,
+ ::std::vector< OUString >::size_type & rOutPosition )
+{
+ INetURLObject aURL(rFileName);
+ ::std::vector< OUString >::const_iterator aIt =
+ ::std::find_if( rSoundList.begin(), rSoundList.end(),
+ lcl_EqualsSoundFileName( aURL.GetBase()));
+ if( aIt != rSoundList.end())
+ {
+ rOutPosition = ::std::distance( rSoundList.begin(), aIt );
+ return true;
+ }
+
+ return false;
+}
+
+OUString lcl_getSoundFileURL(
+ const ::std::vector< OUString > & rSoundList,
+ const weld::ComboBox& rListBox )
+{
+ sal_Int32 nPos = rListBox.get_active();
+ // the first three entries are no actual sounds
+ if( nPos >= 3 )
+ {
+ DBG_ASSERT( static_cast<sal_uInt32>(rListBox.get_count() - 3) == rSoundList.size(),
+ "Sound list-box is not synchronized to sound list" );
+ nPos -= 3;
+ if( rSoundList.size() > o3tl::make_unsigned(nPos) )
+ return rSoundList[ nPos ];
+ }
+
+ return OUString();
+}
+
+struct lcl_AppendSoundToListBox
+{
+ explicit lcl_AppendSoundToListBox(weld::ComboBox& rListBox)
+ : mrListBox( rListBox )
+ {}
+
+ void operator() ( std::u16string_view rString ) const
+ {
+ INetURLObject aURL( rString );
+ mrListBox.append_text( aURL.GetBase() );
+ }
+
+private:
+ weld::ComboBox& mrListBox;
+};
+
+void lcl_FillSoundListBox(
+ const ::std::vector< OUString > & rSoundList,
+ weld::ComboBox& rOutListBox )
+{
+ sal_Int32 nCount = rOutListBox.get_count();
+
+ // keep first three entries
+ for( sal_Int32 i=nCount - 1; i>=3; --i )
+ rOutListBox.remove( i );
+
+ ::std::for_each( rSoundList.begin(), rSoundList.end(),
+ lcl_AppendSoundToListBox( rOutListBox ));
+}
+
+/// Returns an offset into the list of transition presets
+size_t getPresetOffset( const sd::impl::TransitionEffect &rEffect )
+{
+ const sd::TransitionPresetList& rPresetList =
+ sd::TransitionPreset::getTransitionPresetList();
+
+ size_t nIdx = 0;
+ for( const auto& aIt: rPresetList )
+ {
+ if( rEffect.operator==( *aIt ))
+ break;
+ nIdx++;
+ }
+ return nIdx;
+}
+
+} // anonymous namespace
+
+namespace sd
+{
+
+class TransitionPane : public ValueSet
+{
+public:
+ explicit TransitionPane(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
+ : ValueSet(std::move(pScrolledWindow))
+ {
+ }
+
+ void Recalculate()
+ {
+ GetScrollBar()->set_vpolicy(VclPolicyType::AUTOMATIC);
+ RecalculateItemSizes();
+ }
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
+ {
+ Size aSize = pDrawingArea->get_ref_device().LogicToPixel(Size(70, 88), MapMode(MapUnit::MapAppFont));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ ValueSet::SetDrawingArea(pDrawingArea);
+ SetOutputSizePixel(aSize);
+
+ SetStyle(GetStyle() | WB_ITEMBORDER | WB_FLATVALUESET | WB_VSCROLL);
+ EnableFullItemMode( false );
+ SetColCount(3);
+ }
+};
+
+// SlideTransitionPane
+SlideTransitionPane::SlideTransitionPane(
+ weld::Widget* pParent,
+ ViewShellBase & rBase) :
+ PanelLayout( pParent, "SlideTransitionsPanel", "modules/simpress/ui/slidetransitionspanel.ui" ),
+ mrBase( rBase ),
+ mpDrawDoc( rBase.GetDocShell() ? rBase.GetDocShell()->GetDoc() : nullptr ),
+ mbHasSelection( false ),
+ mbUpdatingControls( false ),
+ mbIsMainViewChangePending( false ),
+ maLateInitTimer("sd SlideTransitionPane maLateInitTimer")
+{
+ Initialize(mpDrawDoc);
+}
+
+css::ui::LayoutSize SlideTransitionPane::GetHeightForWidth(const sal_Int32 /*nWidth*/)
+{
+ sal_Int32 nMinimumHeight = get_preferred_size().Height();
+ return css::ui::LayoutSize(nMinimumHeight, -1, nMinimumHeight);
+}
+
+constexpr sal_uInt16 nNoneId = std::numeric_limits<sal_uInt16>::max();
+
+void SlideTransitionPane::Initialize(SdDrawDocument* pDoc)
+{
+ mxFT_VARIANT = m_xBuilder->weld_label("variant_label");
+ mxLB_VARIANT = m_xBuilder->weld_combo_box("variant_list");
+ mxFT_duration = m_xBuilder->weld_label("duration_label");
+ mxCBX_duration = m_xBuilder->weld_metric_spin_button("transition_duration", FieldUnit::SECOND);
+ mxFT_SOUND = m_xBuilder->weld_label("sound_label");
+ mxLB_SOUND = m_xBuilder->weld_combo_box("sound_list");
+ mxCB_LOOP_SOUND = m_xBuilder->weld_check_button("loop_sound");
+ mxRB_ADVANCE_ON_MOUSE = m_xBuilder->weld_radio_button("rb_mouse_click");
+ mxRB_ADVANCE_AUTO = m_xBuilder->weld_radio_button("rb_auto_after");
+ mxMF_ADVANCE_AUTO_AFTER = m_xBuilder->weld_metric_spin_button("auto_after_value", FieldUnit::SECOND);
+ mxPB_APPLY_TO_ALL = m_xBuilder->weld_button("apply_to_all");
+ mxPB_PLAY = m_xBuilder->weld_button("play");
+ mxCB_AUTO_PREVIEW = m_xBuilder->weld_check_button("auto_preview");
+
+ auto nMax = mxMF_ADVANCE_AUTO_AFTER->get_max(FieldUnit::SECOND);
+ mxMF_ADVANCE_AUTO_AFTER->set_max(99, FieldUnit::SECOND);
+ int nWidthChars = mxMF_ADVANCE_AUTO_AFTER->get_width_chars();
+ mxMF_ADVANCE_AUTO_AFTER->set_max(nMax, FieldUnit::SECOND);
+ mxMF_ADVANCE_AUTO_AFTER->set_width_chars(nWidthChars);
+ mxCBX_duration->set_width_chars(nWidthChars);
+
+ mxVS_TRANSITION_ICONS.reset(new TransitionPane(m_xBuilder->weld_scrolled_window("transitions_iconswin", true)));
+ mxVS_TRANSITION_ICONSWin.reset(new weld::CustomWeld(*m_xBuilder, "transitions_icons", *mxVS_TRANSITION_ICONS));
+
+ if( pDoc )
+ mxModel.set( pDoc->getUnoModel(), uno::UNO_QUERY );
+ // TODO: get correct view
+ if( mxModel.is())
+ mxView.set( mxModel->getCurrentController(), uno::UNO_QUERY );
+
+ // dummy list box of slide transitions for startup.
+ mxVS_TRANSITION_ICONS->InsertItem(
+ nNoneId, Image( StockImage::Yes, "sd/cmd/transition-none.png" ),
+ SdResId( STR_SLIDETRANSITION_NONE ),
+ VALUESET_APPEND, /* show legend */ true );
+ mxVS_TRANSITION_ICONS->Recalculate();
+
+ // set defaults
+ mxCB_AUTO_PREVIEW->set_active(true); // automatic preview on
+
+ // update control states before adding handlers
+ updateControls();
+
+ // set handlers
+ mxPB_APPLY_TO_ALL->connect_clicked( LINK( this, SlideTransitionPane, ApplyToAllButtonClicked ));
+ mxPB_PLAY->connect_clicked( LINK( this, SlideTransitionPane, PlayButtonClicked ));
+
+ mxVS_TRANSITION_ICONS->SetSelectHdl( LINK( this, SlideTransitionPane, TransitionSelected ));
+
+ mxLB_VARIANT->connect_changed( LINK( this, SlideTransitionPane, VariantListBoxSelected ));
+ mxCBX_duration->connect_value_changed(LINK( this, SlideTransitionPane, DurationModifiedHdl));
+ mxCBX_duration->connect_focus_out(LINK( this, SlideTransitionPane, DurationLoseFocusHdl));
+ mxLB_SOUND->connect_changed( LINK( this, SlideTransitionPane, SoundListBoxSelected ));
+ mxCB_LOOP_SOUND->connect_toggled( LINK( this, SlideTransitionPane, LoopSoundBoxChecked ));
+
+ mxRB_ADVANCE_ON_MOUSE->connect_toggled( LINK( this, SlideTransitionPane, AdvanceSlideRadioButtonToggled ));
+ mxRB_ADVANCE_AUTO->connect_toggled( LINK( this, SlideTransitionPane, AdvanceSlideRadioButtonToggled ));
+ mxMF_ADVANCE_AUTO_AFTER->connect_value_changed( LINK( this, SlideTransitionPane, AdvanceTimeModified ));
+ mxCB_AUTO_PREVIEW->connect_toggled( LINK( this, SlideTransitionPane, AutoPreviewClicked ));
+ addListener();
+
+ maLateInitTimer.SetTimeout(200);
+ maLateInitTimer.SetInvokeHandler(LINK(this, SlideTransitionPane, LateInitCallback));
+ maLateInitTimer.Start();
+}
+
+SlideTransitionPane::~SlideTransitionPane()
+{
+ maLateInitTimer.Stop();
+ removeListener();
+ mxVS_TRANSITION_ICONSWin.reset();
+ mxVS_TRANSITION_ICONS.reset();
+ mxFT_VARIANT.reset();
+ mxLB_VARIANT.reset();
+ mxFT_duration.reset();
+ mxCBX_duration.reset();
+ mxFT_SOUND.reset();
+ mxLB_SOUND.reset();
+ mxCB_LOOP_SOUND.reset();
+ mxRB_ADVANCE_ON_MOUSE.reset();
+ mxRB_ADVANCE_AUTO.reset();
+ mxMF_ADVANCE_AUTO_AFTER.reset();
+ mxPB_APPLY_TO_ALL.reset();
+ mxPB_PLAY.reset();
+ mxCB_AUTO_PREVIEW.reset();
+}
+
+void SlideTransitionPane::onSelectionChanged()
+{
+ updateControls();
+}
+
+void SlideTransitionPane::onChangeCurrentPage()
+{
+ updateControls();
+}
+
+::sd::slidesorter::SharedPageSelection SlideTransitionPane::getSelectedPages() const
+{
+ ::sd::slidesorter::SlideSorterViewShell * pSlideSorterViewShell
+ = ::sd::slidesorter::SlideSorterViewShell::GetSlideSorter(mrBase);
+ std::shared_ptr<sd::slidesorter::SlideSorterViewShell::PageSelection> pSelection;
+
+ if( pSlideSorterViewShell )
+ {
+ pSelection = pSlideSorterViewShell->GetPageSelection();
+ }
+ else
+ {
+ pSelection = std::make_shared<sd::slidesorter::SlideSorterViewShell::PageSelection>();
+ if( mxView.is() )
+ {
+ SdPage* pPage = SdPage::getImplementation( mxView->getCurrentPage() );
+ if( pPage )
+ pSelection->push_back(pPage);
+ }
+ }
+
+ return pSelection;
+}
+
+void SlideTransitionPane::updateControls()
+{
+ ::sd::slidesorter::SharedPageSelection pSelectedPages(getSelectedPages());
+ if( pSelectedPages->empty())
+ {
+ mbHasSelection = false;
+ return;
+ }
+ mbHasSelection = true;
+
+ DBG_ASSERT( ! mbUpdatingControls, "Multiple Control Updates" );
+ mbUpdatingControls = true;
+
+ // get model data for first page
+ SdPage * pFirstPage = pSelectedPages->front();
+ DBG_ASSERT( pFirstPage, "Invalid Page" );
+
+ impl::TransitionEffect aEffect( *pFirstPage );
+
+ // merge with other pages
+
+ // start with second page (note aIt != aEndIt, because ! aSelectedPages.empty())
+ for( const auto& rpPage : *pSelectedPages )
+ {
+ if( rpPage )
+ aEffect.compareWith( *rpPage );
+ }
+
+ // detect current slide effect
+ if( aEffect.mbEffectAmbiguous )
+ {
+ SAL_WARN( "sd.transitions", "Unusual, ambiguous transition effect" );
+ mxVS_TRANSITION_ICONS->SelectItem(nNoneId);
+ }
+ else
+ {
+ // ToDo: That 0 is "no transition" is documented nowhere except in the
+ // CTOR of sdpage
+ if( aEffect.mnType == 0 )
+ mxVS_TRANSITION_ICONS->SelectItem(nNoneId);
+ else
+ updateVariants( getPresetOffset( aEffect ) );
+ }
+
+ if( aEffect.mbDurationAmbiguous )
+ {
+ mxCBX_duration->set_text("");
+//TODO mxCBX_duration->SetNoSelection();
+ }
+ else
+ {
+ mxCBX_duration->set_value( (aEffect.mfDuration)*100.0, FieldUnit::SECOND );
+ }
+
+ if( aEffect.mbSoundAmbiguous )
+ {
+ mxLB_SOUND->set_active(-1);
+ maCurrentSoundFile.clear();
+ }
+ else
+ {
+ maCurrentSoundFile.clear();
+ if( aEffect.mbStopSound )
+ {
+ mxLB_SOUND->set_active( 1 );
+ }
+ else if( aEffect.mbSoundOn && !aEffect.maSound.isEmpty() )
+ {
+ std::vector<OUString>::size_type nPos = 0;
+ if( lcl_findSoundInList( maSoundList, aEffect.maSound, nPos ))
+ {
+ mxLB_SOUND->set_active( nPos + 3 );
+ maCurrentSoundFile = aEffect.maSound;
+ }
+ }
+ else
+ {
+ mxLB_SOUND->set_active( 0 );
+ }
+ }
+
+ if( aEffect.mbLoopSoundAmbiguous )
+ {
+ mxCB_LOOP_SOUND->set_state(TRISTATE_INDET);
+ }
+ else
+ {
+ mxCB_LOOP_SOUND->set_active(aEffect.mbLoopSound);
+ }
+
+ if( aEffect.mbPresChangeAmbiguous )
+ {
+ mxRB_ADVANCE_ON_MOUSE->set_active( false );
+ mxRB_ADVANCE_AUTO->set_active( false );
+ }
+ else
+ {
+ mxRB_ADVANCE_ON_MOUSE->set_active( aEffect.mePresChange == PresChange::Manual );
+ mxRB_ADVANCE_AUTO->set_active( aEffect.mePresChange == PresChange::Auto );
+ mxMF_ADVANCE_AUTO_AFTER->set_value(aEffect.mfTime * 100.0, FieldUnit::SECOND);
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ mxPB_PLAY->hide();
+ mxCB_AUTO_PREVIEW->set_active(false);
+ mxCB_AUTO_PREVIEW->hide();
+ mxFT_SOUND->hide();
+ mxLB_SOUND->hide();
+ mxCB_LOOP_SOUND->hide();
+ }
+ else
+ {
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ mxCB_AUTO_PREVIEW->set_active( pOptions->IsPreviewTransitions() );
+ }
+
+ mbUpdatingControls = false;
+
+ updateControlState();
+}
+
+void SlideTransitionPane::updateControlState()
+{
+ mxVS_TRANSITION_ICONSWin->set_sensitive( mbHasSelection );
+ mxLB_VARIANT->set_sensitive( mbHasSelection && mxLB_VARIANT->get_count() > 0 );
+ mxCBX_duration->set_sensitive( mbHasSelection );
+ mxLB_SOUND->set_sensitive( mbHasSelection );
+ mxCB_LOOP_SOUND->set_sensitive( mbHasSelection && (mxLB_SOUND->get_active() > 2));
+ mxRB_ADVANCE_ON_MOUSE->set_sensitive( mbHasSelection );
+ mxRB_ADVANCE_AUTO->set_sensitive( mbHasSelection );
+ mxMF_ADVANCE_AUTO_AFTER->set_sensitive( mbHasSelection && mxRB_ADVANCE_AUTO->get_active());
+
+ mxPB_APPLY_TO_ALL->set_sensitive( mbHasSelection );
+ mxPB_PLAY->set_sensitive( mbHasSelection );
+ mxCB_AUTO_PREVIEW->set_sensitive( mbHasSelection );
+}
+
+void SlideTransitionPane::updateSoundList()
+{
+ maSoundList.clear();
+
+ GalleryExplorer::FillObjList( GALLERY_THEME_SOUNDS, maSoundList );
+ GalleryExplorer::FillObjList( GALLERY_THEME_USERSOUNDS, maSoundList );
+
+ lcl_FillSoundListBox( maSoundList, *mxLB_SOUND );
+}
+
+void SlideTransitionPane::openSoundFileDialog()
+{
+ if( ! mxLB_SOUND->get_sensitive())
+ return;
+
+ SdOpenSoundFileDialog aFileDialog(GetFrameWeld());
+
+ DBG_ASSERT( mxLB_SOUND->get_active() == 2,
+ "Dialog should only open when \"Other sound\" is selected" );
+
+ bool bValidSoundFile( false );
+ bool bQuitLoop( false );
+
+ while( ! bQuitLoop &&
+ aFileDialog.Execute() == ERRCODE_NONE )
+ {
+ OUString aFile = aFileDialog.GetPath();
+ std::vector<OUString>::size_type nPos = 0;
+ bValidSoundFile = lcl_findSoundInList( maSoundList, aFile, nPos );
+
+ if( bValidSoundFile )
+ {
+ bQuitLoop = true;
+ }
+ else // not in sound list
+ {
+ // try to insert into gallery
+ if( GalleryExplorer::InsertURL( GALLERY_THEME_USERSOUNDS, aFile ) )
+ {
+ updateSoundList();
+ bValidSoundFile = lcl_findSoundInList( maSoundList, aFile, nPos );
+ DBG_ASSERT( bValidSoundFile, "Adding sound to gallery failed" );
+
+ bQuitLoop = true;
+ }
+ else
+ {
+ OUString aStrWarning(SdResId(STR_WARNING_NOSOUNDFILE));
+ aStrWarning = aStrWarning.replaceFirst("%", aFile);
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::NONE,
+ aStrWarning));
+ xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
+ xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ bQuitLoop = (xWarn->run() != RET_RETRY);
+
+ bValidSoundFile = false;
+ }
+ }
+
+ if( bValidSoundFile )
+ // skip first three entries in list
+ mxLB_SOUND->set_active( nPos + 3 );
+ }
+
+ if( bValidSoundFile )
+ return;
+
+ if( !maCurrentSoundFile.isEmpty() )
+ {
+ std::vector<OUString>::size_type nPos = 0;
+ if( lcl_findSoundInList( maSoundList, maCurrentSoundFile, nPos ))
+ mxLB_SOUND->set_active( nPos + 3 );
+ else
+ mxLB_SOUND->set_active( 0 ); // NONE
+ }
+ else
+ mxLB_SOUND->set_active( 0 ); // NONE
+}
+
+impl::TransitionEffect SlideTransitionPane::getTransitionEffectFromControls() const
+{
+ impl::TransitionEffect aResult;
+ aResult.setAllAmbiguous();
+
+ bool bNoneSelected = mxVS_TRANSITION_ICONS->IsNoSelection() || mxVS_TRANSITION_ICONS->GetSelectedItemId() == nNoneId;
+
+ // check first (aResult might be overwritten)
+ if( mxVS_TRANSITION_ICONSWin->get_sensitive() &&
+ !bNoneSelected &&
+ mxVS_TRANSITION_ICONS->GetSelectedItemId() > 0 )
+ {
+ const sd::TransitionPresetList& rPresetList = sd::TransitionPreset::getTransitionPresetList();
+ auto aSelected = rPresetList.begin();
+ std::advance( aSelected, mxVS_TRANSITION_ICONS->GetSelectedItemId() - 1);
+
+ if (mxLB_VARIANT->get_active() == -1)
+ {
+ // Transition with just one effect.
+ aResult = impl::TransitionEffect( **aSelected );
+ aResult.setAllAmbiguous();
+ }
+ else
+ {
+ int nVariant = 0;
+ bool bFound = false;
+ for( const auto& aIter: rPresetList )
+ {
+ if( aIter->getSetId() == (*aSelected)->getSetId() )
+ {
+ if( mxLB_VARIANT->get_active() == nVariant)
+ {
+ aResult = impl::TransitionEffect( *aIter );
+ aResult.setAllAmbiguous();
+ bFound = true;
+ break;
+ }
+ else
+ {
+ nVariant++;
+ }
+ }
+ }
+ if( !bFound )
+ {
+ aResult.mnType = 0;
+ }
+ }
+ aResult.mbEffectAmbiguous = false;
+ }
+ else if (bNoneSelected)
+ {
+ aResult.mbEffectAmbiguous = false;
+ }
+
+ //duration
+
+ if( mxCBX_duration->get_sensitive() && (!(mxCBX_duration->get_text()).isEmpty()) )
+ {
+ aResult.mfDuration = static_cast<double>(mxCBX_duration->get_value(FieldUnit::SECOND))/100.0;
+ aResult.mbDurationAmbiguous = false;
+ }
+
+ // slide-advance mode
+ if( mxRB_ADVANCE_ON_MOUSE->get_sensitive() && mxRB_ADVANCE_AUTO->get_sensitive() &&
+ (mxRB_ADVANCE_ON_MOUSE->get_active() || mxRB_ADVANCE_AUTO->get_active()))
+ {
+ if( mxRB_ADVANCE_ON_MOUSE->get_active())
+ aResult.mePresChange = PresChange::Manual;
+ else
+ {
+ aResult.mePresChange = PresChange::Auto;
+ if( mxMF_ADVANCE_AUTO_AFTER->get_sensitive())
+ {
+ aResult.mfTime = static_cast<double>(mxMF_ADVANCE_AUTO_AFTER->get_value(FieldUnit::SECOND) ) / 100.0 ;
+ aResult.mbTimeAmbiguous = false;
+ }
+ }
+
+ aResult.mbPresChangeAmbiguous = false;
+ }
+
+ // sound
+ if( mxLB_SOUND->get_sensitive())
+ {
+ maCurrentSoundFile.clear();
+ sal_Int32 nPos = mxLB_SOUND->get_active();
+ if (nPos != -1)
+ {
+ aResult.mbStopSound = nPos == 1;
+ aResult.mbSoundOn = nPos > 1;
+ if( aResult.mbStopSound )
+ {
+ aResult.maSound.clear();
+ aResult.mbSoundAmbiguous = false;
+ }
+ else
+ {
+ aResult.maSound = lcl_getSoundFileURL(maSoundList, *mxLB_SOUND);
+ aResult.mbSoundAmbiguous = false;
+ maCurrentSoundFile = aResult.maSound;
+ }
+ }
+ }
+
+ // sound loop
+ if( mxCB_LOOP_SOUND->get_sensitive() )
+ {
+ aResult.mbLoopSound = mxCB_LOOP_SOUND->get_active();
+ aResult.mbLoopSoundAmbiguous = false;
+ }
+
+ return aResult;
+}
+
+void SlideTransitionPane::applyToSelectedPages(bool bPreview = true)
+{
+ if( mbUpdatingControls )
+ return;
+
+ vcl::Window *pFocusWindow = Application::GetFocusWindow();
+
+ ::sd::slidesorter::SharedPageSelection pSelectedPages( getSelectedPages());
+ impl::TransitionEffect aEffect = getTransitionEffectFromControls();
+ if( ! pSelectedPages->empty())
+ {
+ lcl_CreateUndoForPages( pSelectedPages, mrBase );
+ lcl_ApplyToPages( pSelectedPages, aEffect );
+ mrBase.GetDocShell()->SetModified();
+ }
+ if( mxCB_AUTO_PREVIEW->get_sensitive() &&
+ mxCB_AUTO_PREVIEW->get_active() && bPreview)
+ {
+ if (aEffect.mnType) // mnType = 0 denotes no transition
+ playCurrentEffect();
+ else if( mxView.is() )
+ SlideShow::Stop( mrBase );
+ }
+
+ if (pFocusWindow)
+ pFocusWindow->GrabFocus();
+}
+
+void SlideTransitionPane::playCurrentEffect()
+{
+ if( mxView.is() )
+ {
+
+ Reference< css::animations::XAnimationNode > xNode;
+ SlideShow::StartPreview( mrBase, mxView->getCurrentPage(), xNode );
+ }
+}
+
+void SlideTransitionPane::addListener()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,SlideTransitionPane,EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->AddEventListener( aLink );
+}
+
+void SlideTransitionPane::removeListener()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,SlideTransitionPane,EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
+}
+
+IMPL_LINK(SlideTransitionPane,EventMultiplexerListener,
+ tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ case EventMultiplexerEventId::EditViewSelection:
+ onSelectionChanged();
+ break;
+
+ case EventMultiplexerEventId::CurrentPageChanged:
+ case EventMultiplexerEventId::SlideSortedSelection:
+ onChangeCurrentPage();
+ break;
+
+ case EventMultiplexerEventId::MainViewRemoved:
+ mxView.clear();
+ onSelectionChanged();
+ onChangeCurrentPage();
+ break;
+
+ case EventMultiplexerEventId::MainViewAdded:
+ mbIsMainViewChangePending = true;
+ break;
+
+ case EventMultiplexerEventId::ConfigurationUpdated:
+ if (mbIsMainViewChangePending)
+ {
+ mbIsMainViewChangePending = false;
+
+ // At this moment the controller may not yet been set at
+ // model or ViewShellBase. Take it from the view shell
+ // passed with the event.
+ if (mrBase.GetMainViewShell() != nullptr)
+ {
+ mxView.set(mrBase.GetController(), css::uno::UNO_QUERY);
+ onSelectionChanged();
+ onChangeCurrentPage();
+ }
+ }
+ break;
+
+ default:
+ if (rEvent.meEventId != EventMultiplexerEventId::Disposing)
+ {
+ onSelectionChanged();
+ onChangeCurrentPage();
+ }
+ break;
+ }
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, ApplyToAllButtonClicked, weld::Button&, void)
+{
+ DBG_ASSERT( mpDrawDoc, "Invalid Draw Document!" );
+ if( !mpDrawDoc )
+ return;
+
+ ::sd::slidesorter::SharedPageSelection pPages =
+ std::make_shared<::sd::slidesorter::SlideSorterViewShell::PageSelection>();
+
+ sal_uInt16 nPageCount = mpDrawDoc->GetSdPageCount( PageKind::Standard );
+ pPages->reserve( nPageCount );
+ for( sal_uInt16 i=0; i<nPageCount; ++i )
+ {
+ SdPage * pPage = mpDrawDoc->GetSdPage( i, PageKind::Standard );
+ if( pPage )
+ pPages->push_back( pPage );
+ }
+
+ if( ! pPages->empty())
+ {
+ lcl_CreateUndoForPages( pPages, mrBase );
+ lcl_ApplyToPages( pPages, getTransitionEffectFromControls() );
+ }
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, PlayButtonClicked, weld::Button&, void)
+{
+ playCurrentEffect();
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, TransitionSelected, ValueSet*, void)
+{
+ updateVariants( mxVS_TRANSITION_ICONS->GetSelectedItemId() - 1 );
+ applyToSelectedPages();
+}
+
+/// we use an integer offset into the list of transition presets
+void SlideTransitionPane::updateVariants( size_t nPresetOffset )
+{
+ const sd::TransitionPresetList& rPresetList = sd::TransitionPreset::getTransitionPresetList();
+ mxLB_VARIANT->clear();
+ mxVS_TRANSITION_ICONS->SelectItem(nNoneId);
+
+ if( nPresetOffset >= rPresetList.size() )
+ {
+ mxLB_VARIANT->set_sensitive( false );
+ }
+ else
+ {
+ auto pFound = rPresetList.begin();
+ std::advance( pFound, nPresetOffset );
+
+ // Fill in the variant listbox
+ size_t nFirstItem = 0, nItem = 1;
+ for( const auto& aIt: rPresetList )
+ {
+ if( aIt->getSetId() == (*pFound)->getSetId() )
+ {
+ if (!nFirstItem)
+ nFirstItem = nItem;
+ if( !aIt->getVariantLabel().isEmpty() )
+ {
+ mxLB_VARIANT->append_text( aIt->getVariantLabel() );
+ if( *pFound == aIt )
+ mxLB_VARIANT->set_active( mxLB_VARIANT->get_count()-1 );
+ }
+ }
+ nItem++;
+ }
+
+ if( mxLB_VARIANT->get_count() == 0 )
+ mxLB_VARIANT->set_sensitive( false );
+ else
+ mxLB_VARIANT->set_sensitive(true);
+
+ // item has the id of the first transition from this set.
+ mxVS_TRANSITION_ICONS->SelectItem( nFirstItem );
+ }
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, AdvanceSlideRadioButtonToggled, weld::Toggleable&, void)
+{
+ updateControlState();
+ applyToSelectedPages(false);
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, AdvanceTimeModified, weld::MetricSpinButton&, void)
+{
+ applyToSelectedPages(false);
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, VariantListBoxSelected, weld::ComboBox&, void)
+{
+ applyToSelectedPages();
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, DurationModifiedHdl, weld::MetricSpinButton&, void)
+{
+ double duration_value = static_cast<double>(mxCBX_duration->get_value(FieldUnit::SECOND));
+ if (duration_value <= 0.0)
+ mxCBX_duration->set_value(0, FieldUnit::SECOND);
+ else
+ mxCBX_duration->set_value(duration_value, FieldUnit::SECOND);
+
+ applyToSelectedPages();
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, DurationLoseFocusHdl, weld::Widget&, void)
+{
+ applyToSelectedPages();
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, SoundListBoxSelected, weld::ComboBox&, void)
+{
+ sal_Int32 nPos = mxLB_SOUND->get_active();
+ if( nPos == 2 )
+ {
+ // other sound...
+ openSoundFileDialog();
+ }
+ updateControlState();
+ applyToSelectedPages();
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, LoopSoundBoxChecked, weld::Toggleable&, void)
+{
+ applyToSelectedPages();
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, AutoPreviewClicked, weld::Toggleable&, void)
+{
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ pOptions->SetPreviewTransitions( mxCB_AUTO_PREVIEW->get_active() );
+}
+
+IMPL_LINK_NOARG(SlideTransitionPane, LateInitCallback, Timer *, void)
+{
+ const TransitionPresetList& rPresetList = TransitionPreset::getTransitionPresetList();
+
+ size_t nPresetOffset = 0;
+ for( const TransitionPresetPtr& pPreset: rPresetList )
+ {
+ const OUString sLabel( pPreset->getSetLabel() );
+ if( !sLabel.isEmpty() )
+ {
+ if( m_aNumVariants.find( pPreset->getSetId() ) == m_aNumVariants.end() )
+ {
+ OUString sImageName("sd/cmd/transition-" + pPreset->getSetId() + ".png");
+ BitmapEx aIcon( sImageName );
+ if ( aIcon.IsEmpty() ) // need a fallback
+ sImageName = "sd/cmd/transition-none.png";
+
+ mxVS_TRANSITION_ICONS->InsertItem(
+ nPresetOffset + 1, Image(StockImage::Yes, sImageName), sLabel,
+ VALUESET_APPEND, /* show legend */ true );
+
+ m_aNumVariants[ pPreset->getSetId() ] = 1;
+ }
+ else
+ {
+ m_aNumVariants[ pPreset->getSetId() ]++;
+ }
+ }
+ nPresetOffset++;
+ }
+ mxVS_TRANSITION_ICONS->Recalculate();
+
+ SAL_INFO( "sd.transitions", "Item transition offsets in ValueSet:");
+ for( size_t i = 0; i < mxVS_TRANSITION_ICONS->GetItemCount(); ++i )
+ SAL_INFO( "sd.transitions", i << ":" << mxVS_TRANSITION_ICONS->GetItemId( i ) );
+
+ nPresetOffset = 0;
+ SAL_INFO( "sd.transitions", "Transition presets by offsets:");
+ for( const auto& aIter: rPresetList )
+ {
+ SAL_INFO( "sd.transitions", nPresetOffset++ << " " <<
+ aIter->getPresetId() << ": " << aIter->getSetId() );
+ }
+
+ updateSoundList();
+ updateControls();
+}
+
+} // namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/animations/motionpathtag.cxx b/sd/source/ui/animations/motionpathtag.cxx
new file mode 100644
index 000000000..ced685395
--- /dev/null
+++ b/sd/source/ui/animations/motionpathtag.cxx
@@ -0,0 +1,1200 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/util/XChangesNotifier.hpp>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+
+#include <svx/svdpagv.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnedcit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/svxids.hrc>
+#include <svx/polypolygoneditor.hxx>
+#include <svx/svddrgmt.hxx>
+
+#include <CustomAnimationPane.hxx>
+#include <View.hxx>
+#include "motionpathtag.hxx"
+#include <ViewShell.hxx>
+#include <Window.hxx>
+
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
+
+using sdr::PolyPolygonEditor;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::drawing;
+
+namespace sd
+{
+
+const sal_uInt32 SMART_TAG_HDL_NUM = SAL_MAX_UINT32;
+const int DRGPIX = 2; // Drag MinMove in Pixel
+
+namespace {
+
+class PathDragMove : public SdrDragMove
+{
+private:
+ basegfx::B2DPolyPolygon maPathPolyPolygon;
+
+protected:
+ virtual void createSdrDragEntries() override;
+
+public:
+ PathDragMove(SdrDragView& rNewView,
+ const rtl::Reference <MotionPathTag >& xTag,
+ const basegfx::B2DPolyPolygon& rPathPolyPolygon)
+ : SdrDragMove(rNewView),
+ maPathPolyPolygon(rPathPolyPolygon),
+ mxTag( xTag )
+ {}
+
+ PathDragMove(SdrDragView& rNewView,
+ const rtl::Reference <MotionPathTag >& xTag)
+ : SdrDragMove(rNewView),
+ mxTag( xTag )
+ {}
+
+ virtual bool BeginSdrDrag() override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+
+ rtl::Reference <MotionPathTag > mxTag;
+};
+
+}
+
+void PathDragMove::createSdrDragEntries()
+{
+ // call parent
+ SdrDragMove::createSdrDragEntries();
+
+ if(maPathPolyPolygon.count())
+ {
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(maPathPolyPolygon)));
+ }
+}
+
+bool PathDragMove::BeginSdrDrag()
+{
+ if( mxTag.is() )
+ {
+ SdrPathObj* pPathObj = mxTag->getPathObj();
+ if( pPathObj )
+ {
+ DragStat().SetActionRect(pPathObj->GetCurrentBoundRect());
+ }
+ }
+ Show();
+ return true;
+}
+
+bool PathDragMove::EndSdrDrag(bool /*bCopy*/)
+{
+ Hide();
+ if( mxTag.is() )
+ mxTag->MovePath( DragStat().GetDX(), DragStat().GetDY() );
+ return true;
+}
+
+namespace {
+
+class PathDragResize : public SdrDragResize
+{
+private:
+ basegfx::B2DPolyPolygon maPathPolyPolygon;
+
+protected:
+ virtual void createSdrDragEntries() override;
+
+public:
+ PathDragResize(SdrDragView& rNewView,
+ const rtl::Reference <MotionPathTag >& xTag,
+ const basegfx::B2DPolyPolygon& rPathPolyPolygon)
+ : SdrDragResize(rNewView),
+ maPathPolyPolygon(rPathPolyPolygon),
+ mxTag( xTag )
+ {}
+
+ PathDragResize(SdrDragView& rNewView,
+ const rtl::Reference <MotionPathTag >& xTag)
+ : SdrDragResize(rNewView),
+ mxTag( xTag )
+ {}
+
+ virtual bool EndSdrDrag(bool bCopy) override;
+ rtl::Reference <MotionPathTag > mxTag;
+};
+
+}
+
+void PathDragResize::createSdrDragEntries()
+{
+ // call parent
+ SdrDragResize::createSdrDragEntries();
+
+ if(maPathPolyPolygon.count())
+ {
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(maPathPolyPolygon)));
+ }
+}
+
+bool PathDragResize::EndSdrDrag(bool /*bCopy*/)
+{
+ Hide();
+ if( mxTag.is() )
+ {
+ SdrPathObj* pPathObj = mxTag->getPathObj();
+ if( pPathObj )
+ {
+ const Point aRef( DragStat().GetRef1() );
+ basegfx::B2DHomMatrix aTrans(basegfx::utils::createTranslateB2DHomMatrix(-aRef.X(), -aRef.Y()));
+ aTrans.scale(double(aXFact), double(aYFact));
+ aTrans.translate(aRef.X(), aRef.Y());
+ basegfx::B2DPolyPolygon aDragPoly(pPathObj->GetPathPoly());
+ aDragPoly.transform(aTrans);
+ pPathObj->SetPathPoly( aDragPoly );
+ }
+ }
+ return true;
+}
+
+namespace {
+
+class PathDragObjOwn : public SdrDragObjOwn
+{
+private:
+ basegfx::B2DPolyPolygon maPathPolyPolygon;
+
+protected:
+ virtual void createSdrDragEntries() override;
+
+public:
+ PathDragObjOwn(SdrDragView& rNewView,
+ const basegfx::B2DPolyPolygon& rPathPolyPolygon)
+ : SdrDragObjOwn(rNewView),
+ maPathPolyPolygon(rPathPolyPolygon)
+ {}
+
+ explicit PathDragObjOwn(SdrDragView& rNewView)
+ : SdrDragObjOwn(rNewView)
+ {}
+
+ virtual bool EndSdrDrag(bool bCopy) override;
+};
+
+}
+
+void PathDragObjOwn::createSdrDragEntries()
+{
+ // call parent
+ SdrDragObjOwn::createSdrDragEntries();
+
+ if(maPathPolyPolygon.count())
+ {
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(maPathPolyPolygon)));
+ }
+}
+
+bool PathDragObjOwn::EndSdrDrag(bool /*bCopy*/)
+{
+ Hide();
+
+ SdrObject* pObj = GetDragObj();
+
+ if(pObj && pObj->applySpecialDrag(DragStat()))
+ {
+ pObj->SetChanged();
+ pObj->BroadcastObjectChange();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+namespace {
+
+class SdPathHdl : public SmartHdl
+{
+public:
+ SdPathHdl( const SmartTagReference& xTag, SdrPathObj* mpPathObj );
+
+ virtual void CreateB2dIAObject() override;
+ virtual bool IsFocusHdl() const override;
+
+private:
+ SdrPathObj* mpPathObj;
+};
+
+}
+
+SdPathHdl::SdPathHdl( const SmartTagReference& xTag, SdrPathObj* pPathObj )
+: SmartHdl( xTag, pPathObj->GetCurrentBoundRect().TopLeft(), SdrHdlKind::SmartTag )
+, mpPathObj( pPathObj )
+{
+}
+
+void SdPathHdl::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ if(!pHdlList)
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!pView || pView->areMarkHandlesHidden())
+ return;
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is() && mpPathObj)
+ {
+ const sdr::contact::ViewContact& rVC = mpPathObj->GetViewContact();
+ drawinglayer::primitive2d::Primitive2DContainer aSequence;
+ rVC.getViewIndependentPrimitive2DContainer(aSequence);
+ std::unique_ptr<sdr::overlay::OverlayObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(std::move(aSequence)));
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNew),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+bool SdPathHdl::IsFocusHdl() const
+{
+ return false;
+}
+
+MotionPathTag::MotionPathTag( CustomAnimationPane& rPane, ::sd::View& rView, const CustomAnimationEffectPtr& pEffect )
+: SmartTag( rView )
+, mrPane( rPane )
+, mpEffect( pEffect )
+, mxOrigin( pEffect->getTargetShape() )
+, msLastPath( pEffect->getPath() )
+, mbInUpdatePath( false )
+{
+ mpPathObj = mpEffect->createSdrPathObjFromPath(rView.getSdrModelFromSdrView());
+ mxPolyPoly = mpPathObj->GetPathPoly();
+ if (mxOrigin.is())
+ maOriginPos = mxOrigin->getPosition();
+
+ XDash aDash( css::drawing::DashStyle_RECT, 1, 80, 1, 80, 80);
+ OUString aEmpty( "?" );
+ mpPathObj->SetMergedItem( XLineDashItem( aEmpty, aDash ) );
+ mpPathObj->SetMergedItem( XLineStyleItem( drawing::LineStyle_DASH ) );
+ mpPathObj->SetMergedItem( XLineColorItem(aEmpty, COL_GRAY) );
+ mpPathObj->SetMergedItem( XFillStyleItem( drawing::FillStyle_NONE ) );
+
+ ::basegfx::B2DPolygon aStartArrow;
+ aStartArrow.append(::basegfx::B2DPoint(20.0, 0.0));
+ aStartArrow.append(::basegfx::B2DPoint(0.0, 0.0));
+ aStartArrow.append(::basegfx::B2DPoint(10.0, 30.0));
+ aStartArrow.setClosed(true);
+ mpPathObj->SetMergedItem(XLineStartItem(aEmpty,::basegfx::B2DPolyPolygon(aStartArrow)));
+ mpPathObj->SetMergedItem(XLineStartWidthItem(400));
+ mpPathObj->SetMergedItem(XLineStartCenterItem(true));
+
+ updatePathAttributes();
+
+ mpPathObj->SetMergedItem(XLineTransparenceItem(50));
+
+ mpMark.reset(new SdrMark( mpPathObj, mrView.GetSdrPageView() ));
+
+ mpPathObj->AddListener( *this );
+
+ Reference< XChangesNotifier > xNotifier( mpEffect->getNode(), UNO_QUERY );
+ if( xNotifier.is() )
+ {
+ xNotifier->addChangesListener( this );
+ }
+}
+
+MotionPathTag::~MotionPathTag()
+{
+ DBG_ASSERT( mpPathObj == nullptr, "sd::MotionPathTag::~MotionPathTag(), dispose me first!" );
+ Dispose();
+}
+
+void MotionPathTag::updatePathAttributes()
+{
+ ::basegfx::B2DPolygon aCandidate;
+ if( mxPolyPoly.count() )
+ {
+ aCandidate = mxPolyPoly.getB2DPolygon(0);
+ ::basegfx::utils::checkClosed( aCandidate );
+ }
+
+ if( !aCandidate.isClosed() )
+ {
+ ::basegfx::B2DPolygon aEndArrow;
+ aEndArrow.append(::basegfx::B2DPoint(10.0, 0.0));
+ aEndArrow.append(::basegfx::B2DPoint(0.0, 30.0));
+ aEndArrow.append(::basegfx::B2DPoint(20.0, 30.0));
+ aEndArrow.setClosed(true);
+ mpPathObj->SetMergedItem(XLineEndItem("?",::basegfx::B2DPolyPolygon(aEndArrow)));
+ mpPathObj->SetMergedItem(XLineEndWidthItem(400));
+ mpPathObj->SetMergedItem(XLineEndCenterItem(true));
+ }
+ else
+ {
+ mpPathObj->SetMergedItem(XLineEndItem());
+ }
+}
+
+void MotionPathTag::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+{
+ if( !(mpPathObj && !mbInUpdatePath && rHint.GetId() == SfxHintId::ThisIsAnSdrHint && mpEffect) )
+ return;
+
+ if( mxPolyPoly != mpPathObj->GetPathPoly() )
+ {
+ mbInUpdatePath = true;
+ mxPolyPoly = mpPathObj->GetPathPoly();
+ rtl::Reference< MotionPathTag > xTag( this );
+ mrPane.updatePathFromMotionPathTag( xTag );
+ msLastPath = mpEffect->getPath();
+ updatePathAttributes();
+ mbInUpdatePath = false;
+ }
+}
+
+void MotionPathTag::MovePath( int nDX, int nDY )
+{
+ if( mpPathObj )
+ {
+ mpPathObj->Move( Size( nDX, nDY ) );
+ mrView.updateHandles();
+ }
+}
+
+/** returns true if the MotionPathTag handled the event. */
+bool MotionPathTag::MouseButtonDown( const MouseEvent& rMEvt, SmartHdl& rHdl )
+{
+ if( !mpPathObj )
+ return false;
+
+ if( !isSelected() )
+ {
+ SmartTagReference xTag( this );
+ mrView.getSmartTags().select( xTag );
+ selectionChanged();
+ return true;
+ }
+ else
+ {
+ if( rMEvt.IsLeft() && (rMEvt.GetClicks() == 2) )
+ {
+ mrView.GetViewShell()->GetViewFrame()->GetDispatcher()->Execute(SID_BEZIER_EDIT, SfxCallMode::ASYNCHRON);
+ return true;
+ }
+ else if( rMEvt.IsLeft() )
+ {
+ OutputDevice* pOut = mrView.GetViewShell()->GetActiveWindow()->GetOutDev();
+ Point aMDPos( pOut->PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ if( !mrView.IsFrameDragSingles() && mrView.IsInsObjPointMode() && (rHdl.GetObjHdlNum() == SMART_TAG_HDL_NUM) )
+ {
+ // insert a point in edit mode
+ const bool bNewObj = rMEvt.IsMod1();
+
+ mrView.BrkAction();
+
+ Point aPt(aMDPos); // - pMarkedPV->GetOffset());
+
+ if(bNewObj)
+ aPt = mrView.GetSnapPos(aPt,mrView.GetSdrPageView());
+
+ bool bClosed0(mpPathObj->IsClosedObj());
+
+ sal_uInt32 nInsPointNum = mpPathObj->NbcInsPointOld(aPt, bNewObj);
+
+ if(bClosed0 != mpPathObj->IsClosedObj())
+ {
+ // Obj was closed implicit
+ // object changed
+ mpPathObj->SetChanged();
+ mpPathObj->BroadcastObjectChange();
+ }
+
+ if(0xffffffff != nInsPointNum)
+ {
+ mrView.UnmarkAllPoints();
+ mrView.updateHandles();
+
+ bool bRet = mrView.BegDragObj(aMDPos, pOut, mrView.GetHdl(nInsPointNum+1), 0, new PathDragObjOwn( mrView ) );
+
+ if (bRet)
+ {
+ const_cast< SdrDragStat* >( &mrView.GetDragStat() )->SetMinMoved();
+ mrView.MovDragObj(aMDPos);
+ }
+ }
+ return true;
+ }
+ else
+ {
+ SmartHdl* pHdl = &rHdl;
+ if (!mrView.IsPointMarked(*pHdl) || rMEvt.IsShift())
+ {
+ if (!rMEvt.IsShift())
+ {
+ mrView.UnmarkAllPoints();
+ pHdl = dynamic_cast< SmartHdl* >( mrView.PickHandle(aMDPos) );
+ }
+ else
+ {
+ if (mrView.IsPointMarked(*pHdl) )
+ {
+ mrView.UnmarkPoint(*pHdl);
+ pHdl = nullptr;
+ }
+ else
+ {
+ pHdl = dynamic_cast< SmartHdl* >( mrView.PickHandle(aMDPos) );
+ }
+ }
+
+ if (pHdl)
+ mrView.MarkPoint(*pHdl);
+ }
+
+ if( pHdl && !rMEvt.IsRight() )
+ {
+ mrView.BrkAction();
+ const sal_uInt16 nDrgLog = static_cast<sal_uInt16>(pOut->PixelToLogic(Size(DRGPIX,0)).Width());
+
+ rtl::Reference< MotionPathTag > xTag( this );
+ SdrDragMethod* pDragMethod;
+
+ // #i95646# add DragPoly as geometry to each local SdrDragMethod to be able
+ // to create the needed local SdrDragEntry for it in createSdrDragEntries()
+ const basegfx::B2DPolyPolygon aDragPoly(mpPathObj->GetPathPoly());
+
+ if( (pHdl->GetKind() == SdrHdlKind::Move) || (pHdl->GetKind() == SdrHdlKind::SmartTag) )
+ {
+ pDragMethod = new PathDragMove( mrView, xTag, aDragPoly );
+ pHdl->SetPos( aMDPos );
+ }
+ else if( pHdl->GetKind() == SdrHdlKind::Poly )
+ {
+ pDragMethod = new PathDragObjOwn( mrView, aDragPoly );
+ }
+ else
+ {
+ pDragMethod = new PathDragResize( mrView, xTag, aDragPoly );
+ }
+
+ mrView.BegDragObj(aMDPos, nullptr, pHdl, nDrgLog, pDragMethod );
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/** returns true if the SmartTag consumes this event. */
+bool MotionPathTag::KeyInput( const KeyEvent& rKEvt )
+{
+ if( !mpPathObj )
+ return false;
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+ switch( nCode )
+ {
+ case KEY_DELETE:
+ return OnDelete();
+
+ case KEY_DOWN:
+ case KEY_UP:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ return OnMove( rKEvt );
+
+ case KEY_ESCAPE:
+ {
+ SmartTagReference xThis( this );
+ mrView.getSmartTags().deselect();
+ return true;
+ }
+
+ case KEY_TAB:
+ return OnTabHandles( rKEvt );
+
+ case KEY_SPACE:
+ return OnMarkHandle( rKEvt );
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool MotionPathTag::OnDelete()
+{
+ mrPane.remove( mpEffect );
+ return true;
+}
+
+bool MotionPathTag::OnTabHandles( const KeyEvent& rKEvt )
+{
+ if(rKEvt.GetKeyCode().IsMod1() || rKEvt.GetKeyCode().IsMod2())
+ {
+ const SdrHdlList& rHdlList = mrView.GetHdlList();
+ bool bForward(!rKEvt.GetKeyCode().IsShift());
+
+ const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward);
+
+ // guarantee visibility of focused handle
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(pHdl)
+ {
+ Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
+ if( pWindow )
+ {
+ Point aHdlPosition(pHdl->GetPos());
+ ::tools::Rectangle aVisRect(aHdlPosition - Point(100, 100), Size(200, 200));
+ mrView.MakeVisible(aVisRect, *pWindow);
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool MotionPathTag::OnMarkHandle( const KeyEvent& rKEvt )
+{
+ const SdrHdlList& rHdlList = mrView.GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(pHdl && pHdl->GetKind() == SdrHdlKind::Poly )
+ {
+ // rescue ID of point with focus
+ sal_uInt32 nPol(pHdl->GetPolyNum());
+ sal_uInt32 nPnt(pHdl->GetPointNum());
+
+ if(mrView.IsPointMarked(*pHdl))
+ {
+ if(rKEvt.GetKeyCode().IsShift())
+ {
+ mrView.UnmarkPoint(*pHdl);
+ }
+ }
+ else
+ {
+ if(!rKEvt.GetKeyCode().IsShift())
+ {
+ mrView.UnmarkAllPoints();
+ }
+ mrView.MarkPoint(*pHdl);
+ }
+
+ if(nullptr == rHdlList.GetFocusHdl())
+ {
+ // restore point with focus
+ SdrHdl* pNewOne = nullptr;
+
+ for(size_t a = 0; !pNewOne && a < rHdlList.GetHdlCount(); ++a)
+ {
+ SdrHdl* pAct = rHdlList.GetHdl(a);
+
+ if(pAct && pAct->GetKind() == SdrHdlKind::Poly && pAct->GetPolyNum() == nPol && pAct->GetPointNum() == nPnt)
+ pNewOne = pAct;
+ }
+
+ if(pNewOne)
+ const_cast<SdrHdlList&>(rHdlList).SetFocusHdl(pNewOne);
+ }
+ }
+
+ return true;
+}
+
+bool MotionPathTag::OnMove( const KeyEvent& rKEvt )
+{
+ ::tools::Long nX = 0;
+ ::tools::Long nY = 0;
+
+ switch( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_UP: nY = -1; break;
+ case KEY_DOWN: nY = 1; break;
+ case KEY_LEFT: nX = -1; break;
+ case KEY_RIGHT: nX = 1; break;
+ default: break;
+ }
+
+ if(rKEvt.GetKeyCode().IsMod2())
+ {
+ OutputDevice* pOut = mrView.GetViewShell()->GetActiveWindow()->GetOutDev();
+ Size aLogicSizeOnePixel = pOut ? pOut->PixelToLogic(Size(1,1)) : Size(100, 100);
+ nX *= aLogicSizeOnePixel.Width();
+ nY *= aLogicSizeOnePixel.Height();
+ }
+ else
+ {
+ // old, fixed move distance
+ nX *= 100;
+ nY *= 100;
+ }
+
+ if( nX || nY )
+ {
+ // in point edit mode move the handle with the focus
+ const SdrHdlList& rHdlList = mrView.GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(pHdl)
+ {
+ // now move the Handle (nX, nY)
+ Point aStartPoint(pHdl->GetPos());
+ Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
+
+ // start dragging
+ rtl::Reference< MotionPathTag > xTag( this );
+ SdrDragMethod* pDragMethod = nullptr;
+ if( (pHdl->GetKind() == SdrHdlKind::Move) || (pHdl->GetKind() == SdrHdlKind::SmartTag) )
+ {
+ pDragMethod = new PathDragMove( mrView, xTag );
+ }
+ else if( pHdl->GetKind() == SdrHdlKind::Poly )
+ {
+ pDragMethod = new PathDragObjOwn( mrView );
+ }
+ else if( pHdl->GetKind() != SdrHdlKind::BezierWeight )
+ {
+ pDragMethod = new PathDragResize( mrView, xTag );
+ }
+ mrView.BegDragObj(aStartPoint, nullptr, pHdl, 0, pDragMethod);
+
+ if(mrView.IsDragObj())
+ {
+ bool bWasNoSnap = mrView.GetDragStat().IsNoSnap();
+ bool bWasSnapEnabled = mrView.IsSnapEnabled();
+
+ // switch snapping off
+ if(!bWasNoSnap)
+ const_cast<SdrDragStat&>(mrView.GetDragStat()).SetNoSnap();
+ if(bWasSnapEnabled)
+ mrView.SetSnapEnabled(false);
+
+ mrView.MovAction(aEndPoint);
+ mrView.EndDragObj();
+
+ // restore snap
+ if(!bWasNoSnap)
+ const_cast<SdrDragStat&>(mrView.GetDragStat()).SetNoSnap(bWasNoSnap);
+ if(bWasSnapEnabled)
+ mrView.SetSnapEnabled(bWasSnapEnabled);
+ }
+ }
+ else
+ {
+ // move the path
+ MovePath( nX, nY );
+ }
+ }
+
+ return true;
+}
+
+sal_Int32 MotionPathTag::GetMarkablePointCount() const
+{
+ if( mpPathObj && isSelected() )
+ {
+ return mpPathObj->GetPointCount();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+sal_Int32 MotionPathTag::GetMarkedPointCount() const
+{
+ if( mpMark )
+ {
+ const SdrUShortCont& rPts = mpMark->GetMarkedPoints();
+ return rPts.size();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+bool MotionPathTag::MarkPoint(SdrHdl& rHdl, bool bUnmark )
+{
+ bool bRet=false;
+ if( mpPathObj && mrView.IsPointMarkable( rHdl ) && (rHdl.GetKind() != SdrHdlKind::SmartTag) )
+ {
+ SmartHdl* pSmartHdl = dynamic_cast< SmartHdl* >( &rHdl );
+ if( pSmartHdl && pSmartHdl->getTag().get() == this )
+ {
+ if (mrView.MarkPointHelper(&rHdl,mpMark.get(),bUnmark))
+ {
+ mrView.MarkListHasChanged();
+ bRet=true;
+ }
+ }
+ }
+ return bRet;
+}
+
+bool MotionPathTag::MarkPoints(const ::tools::Rectangle* pRect, bool bUnmark )
+{
+ bool bChgd=false;
+
+ if( mpPathObj && isSelected() )
+ {
+ size_t nHdlNum = mrView.GetHdlList().GetHdlCount();
+ if ( nHdlNum <= 1 )
+ return false;
+
+ while( --nHdlNum > 0 )
+ {
+ SmartHdl* pHdl = dynamic_cast< SmartHdl* >( mrView.GetHdl( nHdlNum ) );
+
+ if( pHdl && (pHdl->getTag().get() == this) && mrView.IsPointMarkable(*pHdl) && pHdl->IsSelected() == bUnmark)
+ {
+ Point aPos(pHdl->GetPos());
+ if( pRect==nullptr || pRect->Contains(aPos))
+ {
+ if( mrView.MarkPointHelper(pHdl,mpMark.get(),bUnmark) )
+ bChgd=true;
+ }
+ }
+ }
+
+ if(bChgd)
+ mrView.MarkListHasChanged();
+ }
+
+ return bChgd;
+}
+
+bool MotionPathTag::getContext( SdrViewContext& rContext )
+{
+ if( mpPathObj && isSelected() && !mrView.IsFrameDragSingles() )
+ {
+ rContext = SdrViewContext::PointEdit;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void MotionPathTag::CheckPossibilities()
+{
+ if( !(mpPathObj && isSelected()) )
+ return;
+
+ mrView.SetMoveAllowed( true );
+ mrView.SetMoveProtected( false );
+ mrView.SetResizeFreeAllowed( true );
+ mrView.SetResizePropAllowed( true );
+ mrView.SetResizeProtected( false );
+
+ if( !mrView.IsFrameDragSingles() )
+ {
+ bool b1stSmooth(true);
+ bool b1stSegm(true);
+ bool bCurve(false);
+ bool bSmoothFuz(false);
+ bool bSegmFuz(false);
+ basegfx::B2VectorContinuity eSmooth = basegfx::B2VectorContinuity::NONE;
+
+ mrView.CheckPolyPossibilitiesHelper( mpMark.get(), b1stSmooth, b1stSegm, bCurve, bSmoothFuz, bSegmFuz, eSmooth );
+ }
+}
+
+void MotionPathTag::addCustomHandles( SdrHdlList& rHandlerList )
+{
+ if( !mpPathObj )
+ return;
+
+ css::awt::Point aPos;
+ if (mxOrigin.is())
+ aPos = mxOrigin->getPosition();
+ if( (aPos.X != maOriginPos.X) || (aPos.Y != maOriginPos.Y) )
+ {
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createTranslateB2DHomMatrix(
+ aPos.X - maOriginPos.X, aPos.Y - maOriginPos.Y));
+ mxPolyPoly.transform( aTransform );
+ mpPathObj->SetPathPoly( mxPolyPoly );
+ maOriginPos = aPos;
+ }
+
+ SmartTagReference xThis( this );
+ std::unique_ptr<SdPathHdl> pHdl(new SdPathHdl( xThis, mpPathObj ));
+ pHdl->SetObjHdlNum( SMART_TAG_HDL_NUM );
+ pHdl->SetPageView( mrView.GetSdrPageView() );
+ pHdl->SetObj(mpPathObj);
+ rHandlerList.AddHdl( std::move(pHdl) );
+
+ if( !isSelected() )
+ return;
+
+ mrView.GetSdrPageView()->SetHasMarkedObj(true);
+
+ if( !mrView.IsFrameDragSingles() )
+ {
+ SdrHdlList aTemp( rHandlerList.GetView() );
+ mpPathObj->AddToHdlList( aTemp );
+ const SdrUShortCont& rMrkPnts = mpMark->GetMarkedPoints();
+
+ for( size_t nHandle = 0; nHandle < aTemp.GetHdlCount(); ++nHandle )
+ {
+ SdrHdl* pTempHdl = aTemp.GetHdl( nHandle );
+
+ SmartHdl* pSmartHdl = new SmartHdl( xThis, mpPathObj, pTempHdl->GetPos(), pTempHdl->GetKind() );
+ pSmartHdl->SetObjHdlNum( static_cast<sal_uInt32>(nHandle) );
+ pSmartHdl->SetPolyNum( pTempHdl->GetPolyNum() );
+ pSmartHdl->SetPointNum( pTempHdl->GetPointNum() );
+ pSmartHdl->SetPlusHdl( pTempHdl->IsPlusHdl() );
+ pSmartHdl->SetSourceHdlNum( pTempHdl->GetSourceHdlNum() );
+ pSmartHdl->SetPageView( mrView.GetSdrPageView() );
+
+ rHandlerList.AddHdl( std::unique_ptr<SmartHdl>(pSmartHdl) );
+
+ const bool bSelected = rMrkPnts.find( sal_uInt16(nHandle) ) != rMrkPnts.end();
+ pSmartHdl->SetSelected(bSelected);
+
+ if( mrView.IsPlusHandlesAlwaysVisible() || bSelected )
+ {
+ SdrHdlList plusList(nullptr);
+ mpPathObj->AddToPlusHdlList(plusList, *pSmartHdl);
+ sal_uInt32 nPlusHdlCnt=plusList.GetHdlCount();
+ for (sal_uInt32 nPlusNum=0; nPlusNum<nPlusHdlCnt; nPlusNum++)
+ {
+ SdrHdl* pPlusHdl = plusList.GetHdl(nPlusNum);
+ pPlusHdl->SetObj(mpPathObj);
+ pPlusHdl->SetPageView(mrView.GetSdrPageView());
+ pPlusHdl->SetPlusHdl(true);
+ }
+ plusList.MoveTo(rHandlerList);
+ }
+ }
+ }
+ else
+ {
+ ::tools::Rectangle aRect(mpPathObj->GetCurrentBoundRect());
+
+ if(!aRect.IsEmpty())
+ {
+ size_t nCount = rHandlerList.GetHdlCount();
+
+ bool bWdt0=aRect.Left()==aRect.Right();
+ bool bHgt0=aRect.Top()==aRect.Bottom();
+ if (bWdt0 && bHgt0)
+ {
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.TopLeft(),SdrHdlKind::UpperLeft));
+ }
+ else if (bWdt0 || bHgt0)
+ {
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.TopLeft() ,SdrHdlKind::UpperLeft));
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.BottomRight(),SdrHdlKind::LowerRight));
+ }
+ else // !bWdt0 && !bHgt0
+ {
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.TopLeft() ,SdrHdlKind::UpperLeft));
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.TopCenter() ,SdrHdlKind::Upper));
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.TopRight() ,SdrHdlKind::UpperRight));
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.LeftCenter() ,SdrHdlKind::Left ));
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.RightCenter() ,SdrHdlKind::Right));
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.BottomLeft() ,SdrHdlKind::LowerLeft));
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.BottomCenter(),SdrHdlKind::Lower));
+ rHandlerList.AddHdl(std::make_unique<SmartHdl>( xThis, mpPathObj, aRect.BottomRight() ,SdrHdlKind::LowerRight));
+ }
+
+ while( nCount < rHandlerList.GetHdlCount() )
+ {
+ rHandlerList.GetHdl(nCount++)->SetPageView( mrView.GetSdrPageView() );
+ }
+ }
+ }
+}
+
+void MotionPathTag::disposing()
+{
+ Reference< XChangesNotifier > xNotifier( mpEffect->getNode(), UNO_QUERY );
+ if( xNotifier.is() )
+ {
+ xNotifier->removeChangesListener( this );
+ }
+
+ if( mpPathObj )
+ {
+ SdrObject* pTemp(mpPathObj);
+ mpPathObj = nullptr;
+ mrView.updateHandles();
+
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject::Free(pTemp);
+ }
+
+ mpMark.reset();
+
+ SmartTag::disposing();
+}
+
+void MotionPathTag::deselect()
+{
+ SmartTag::deselect();
+
+ if( mpMark )
+ {
+ SdrUShortCont& rPts = mpMark->GetMarkedPoints();
+ rPts.clear();
+ }
+
+ selectionChanged();
+}
+
+void MotionPathTag::selectionChanged()
+{
+ if( mrView.GetViewShell() && mrView.GetViewShell()->GetViewFrame() )
+ {
+ SfxBindings& rBindings = mrView.GetViewShell()->GetViewFrame()->GetBindings();
+ rBindings.InvalidateAll(true);
+ }
+}
+
+// IPolyPolygonEditorController
+
+void MotionPathTag::DeleteMarkedPoints()
+{
+ if( !(mpPathObj && IsDeleteMarkedPointsPossible()) )
+ return;
+
+ mrView.BrkAction();
+
+ SdrUShortCont& rPts = mpMark->GetMarkedPoints();
+ PolyPolygonEditor aEditor( mpPathObj->GetPathPoly());
+ if (aEditor.DeletePoints(rPts))
+ {
+ if( aEditor.GetPolyPolygon().count() )
+ {
+ mpPathObj->SetPathPoly( aEditor.GetPolyPolygon() );
+ }
+
+ mrView.UnmarkAllPoints();
+ mrView.MarkListHasChanged();
+ mrView.updateHandles();
+ }
+}
+
+bool MotionPathTag::IsDeleteMarkedPointsPossible() const
+{
+ return mpPathObj && isSelected() && (GetMarkedPointCount() != 0);
+}
+
+void MotionPathTag::RipUpAtMarkedPoints()
+{
+ // not supported for motion path
+}
+
+bool MotionPathTag::IsRipUpAtMarkedPointsPossible() const
+{
+ // not supported for motion path
+ return false;
+}
+
+bool MotionPathTag::IsSetMarkedSegmentsKindPossible() const
+{
+ if( mpPathObj )
+ return mrView.IsSetMarkedSegmentsKindPossible();
+ else
+ return false;
+}
+
+SdrPathSegmentKind MotionPathTag::GetMarkedSegmentsKind() const
+{
+ if( mpPathObj )
+ return mrView.GetMarkedSegmentsKind();
+ else
+ return SdrPathSegmentKind::Line;
+}
+
+void MotionPathTag::SetMarkedSegmentsKind(SdrPathSegmentKind eKind)
+{
+ if(mpPathObj && isSelected() && (GetMarkedPointCount() != 0))
+ {
+ SdrUShortCont& rPts = mpMark->GetMarkedPoints();
+ PolyPolygonEditor aEditor( mpPathObj->GetPathPoly() );
+ if (aEditor.SetSegmentsKind(eKind, rPts))
+ {
+ mpPathObj->SetPathPoly(aEditor.GetPolyPolygon());
+ mrView.MarkListHasChanged();
+ mrView.updateHandles();
+ }
+ }
+}
+
+bool MotionPathTag::IsSetMarkedPointsSmoothPossible() const
+{
+ if( mpPathObj )
+ return mrView.IsSetMarkedPointsSmoothPossible();
+ else
+ return false;
+}
+
+SdrPathSmoothKind MotionPathTag::GetMarkedPointsSmooth() const
+{
+ if( mpPathObj )
+ return mrView.GetMarkedPointsSmooth();
+ else
+ return SdrPathSmoothKind::Angular;
+}
+
+void MotionPathTag::SetMarkedPointsSmooth(SdrPathSmoothKind eKind)
+{
+ basegfx::B2VectorContinuity eFlags;
+
+ if(SdrPathSmoothKind::Angular == eKind)
+ {
+ eFlags = basegfx::B2VectorContinuity::NONE;
+ }
+ else if(SdrPathSmoothKind::Asymmetric == eKind)
+ {
+ eFlags = basegfx::B2VectorContinuity::C1;
+ }
+ else if(SdrPathSmoothKind::Symmetric == eKind)
+ {
+ eFlags = basegfx::B2VectorContinuity::C2;
+ }
+ else
+ {
+ return;
+ }
+
+ if(mpPathObj && mpMark && isSelected() && (GetMarkedPointCount() != 0))
+ {
+ SdrUShortCont& rPts = mpMark->GetMarkedPoints();
+ PolyPolygonEditor aEditor( mpPathObj->GetPathPoly());
+ if (aEditor.SetPointsSmooth(eFlags, rPts))
+ {
+ mpPathObj->SetPathPoly(aEditor.GetPolyPolygon());
+ mrView.MarkListHasChanged();
+ mrView.updateHandles();
+ }
+ }
+}
+
+bool MotionPathTag::IsOpenCloseMarkedObjectsPossible() const
+{
+ // not supported for motion path
+ return false;
+}
+
+SdrObjClosedKind MotionPathTag::GetMarkedObjectsClosedState() const
+{
+ // not supported for motion path
+ return SdrObjClosedKind::Open;
+}
+
+// XChangesListener
+void SAL_CALL MotionPathTag::changesOccurred( const ChangesEvent& /*Event*/ )
+{
+ if( mpPathObj && !mbInUpdatePath && (mpEffect->getPath() != msLastPath) )
+ {
+ mbInUpdatePath =true;
+ msLastPath = mpEffect->getPath();
+ mpEffect->updateSdrPathObjFromPath( *mpPathObj );
+ mbInUpdatePath = false;
+ updatePathAttributes();
+ mrView.updateHandles();
+ }
+}
+
+void SAL_CALL MotionPathTag::disposing( const EventObject& /*Source*/ )
+{
+ if( mpPathObj )
+ Dispose();
+}
+
+Any SAL_CALL MotionPathTag::queryInterface( const css::uno::Type& aType )
+{
+ if( aType == cppu::UnoType<XChangesListener>::get() )
+ return Any( Reference< XChangesListener >( this ) );
+ if( aType == cppu::UnoType<XEventListener>::get() )
+ return Any( Reference< XEventListener >( this ) );
+ if( aType == cppu::UnoType<XInterface>::get() )
+ return Any( Reference< XInterface >( this ) );
+
+ return Any();
+}
+
+void SAL_CALL MotionPathTag::acquire() noexcept
+{
+ SimpleReferenceComponent::acquire();
+}
+
+void SAL_CALL MotionPathTag::release( ) noexcept
+{
+ SimpleReferenceComponent::release();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/animations/motionpathtag.hxx b/sd/source/ui/animations/motionpathtag.hxx
new file mode 100644
index 000000000..715ce4268
--- /dev/null
+++ b/sd/source/ui/animations/motionpathtag.hxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/util/XChangesListener.hpp>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <smarttag.hxx>
+#include <CustomAnimationList.hxx>
+
+namespace com::sun::star::drawing { class XShape; }
+class SdrPathObj;
+
+namespace sd {
+
+class View;
+class CustomAnimationPane;
+
+/// Base class for all functions.
+class MotionPathTag final : public SmartTag, public IPolyPolygonEditorController, public SfxListener, public css::util::XChangesListener
+{
+public:
+ MotionPathTag( CustomAnimationPane& rPane, ::sd::View& rView, const CustomAnimationEffectPtr& pEffect );
+ virtual ~MotionPathTag() override;
+
+ SdrPathObj* getPathObj() const { return mpPathObj; }
+
+ /// @return true if the SmartTag handled the event.
+ virtual bool MouseButtonDown( const MouseEvent&, SmartHdl& ) override;
+
+ /// @return true if the SmartTag consumes this event.
+ virtual bool KeyInput( const KeyEvent& rKEvt ) override;
+
+ // callbacks from sdr view
+ virtual sal_Int32 GetMarkablePointCount() const override;
+ virtual sal_Int32 GetMarkedPointCount() const override;
+ virtual bool MarkPoint(SdrHdl& rHdl, bool bUnmark) override;
+ virtual void CheckPossibilities() override;
+ virtual bool MarkPoints(const ::tools::Rectangle* pRect, bool bUnmark) override;
+
+ const CustomAnimationEffectPtr& getEffect() const { return mpEffect; }
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ // IPolyPolygonEditorController
+ virtual void DeleteMarkedPoints() override;
+ virtual bool IsDeleteMarkedPointsPossible() const override;
+
+ virtual void RipUpAtMarkedPoints() override;
+ virtual bool IsRipUpAtMarkedPointsPossible() const override;
+
+ virtual bool IsSetMarkedSegmentsKindPossible() const override;
+ virtual SdrPathSegmentKind GetMarkedSegmentsKind() const override;
+ virtual void SetMarkedSegmentsKind(SdrPathSegmentKind eKind) override;
+
+ virtual bool IsSetMarkedPointsSmoothPossible() const override;
+ virtual SdrPathSmoothKind GetMarkedPointsSmooth() const override;
+ virtual void SetMarkedPointsSmooth(SdrPathSmoothKind eKind) override;
+
+ virtual bool IsOpenCloseMarkedObjectsPossible() const override;
+ virtual SdrObjClosedKind GetMarkedObjectsClosedState() const override;
+
+ void MovePath( int nDX, int nDY );
+ bool OnDelete();
+ bool OnTabHandles( const KeyEvent& rKEvt );
+ bool OnMarkHandle( const KeyEvent& rKEvt );
+ bool OnMove( const KeyEvent& rKEvt );
+
+ // XChangesListener
+ virtual void SAL_CALL changesOccurred( const css::util::ChangesEvent& Event ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire( ) noexcept override;
+ virtual void SAL_CALL release( ) noexcept override;
+
+private:
+ virtual void addCustomHandles( SdrHdlList& rHandlerList ) override;
+ virtual bool getContext( SdrViewContext& rContext ) override;
+ virtual void disposing() override;
+ virtual void deselect() override;
+
+ void updatePathAttributes();
+ void selectionChanged();
+
+ CustomAnimationPane& mrPane;
+ CustomAnimationEffectPtr mpEffect;
+ ::basegfx::B2DPolyPolygon mxPolyPoly;
+ css::uno::Reference< css::drawing::XShape > mxOrigin;
+ SdrPathObj* mpPathObj;
+ css::awt::Point maOriginPos;
+ std::unique_ptr<SdrMark> mpMark;
+ OUString msLastPath;
+ bool mbInUpdatePath;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/annotations/annotationmanager.cxx b/sd/source/ui/annotations/annotationmanager.cxx
new file mode 100644
index 000000000..ab9fe0c1a
--- /dev/null
+++ b/sd/source/ui/annotations/annotationmanager.cxx
@@ -0,0 +1,1220 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/XDrawView.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/geometry/RealPoint2D.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/document/XEventBroadcaster.hpp>
+#include <com/sun/star/office/XAnnotationAccess.hpp>
+#include <comphelper/lok.hxx>
+#include <svx/svxids.hrc>
+
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <sal/macros.h>
+#include <svl/itempool.hxx>
+#include <svl/intitem.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/useroptions.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/saveopt.hxx>
+
+#include <tools/datetime.hxx>
+#include <tools/UnitConversion.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/dispatch.hxx>
+
+#include <editeng/editeng.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/postitem.hxx>
+
+#include <svx/postattr.hxx>
+
+#include <annotationmanager.hxx>
+#include "annotationmanagerimpl.hxx"
+#include "annotationwindow.hxx"
+#include <strings.hrc>
+
+#include <Annotation.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <sdresid.hxx>
+#include <EventMultiplexer.hxx>
+#include <ViewShellBase.hxx>
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <textapi.hxx>
+#include <optsitem.hxx>
+#include <sdmod.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::geometry;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::office;
+
+namespace sd {
+
+SfxItemPool* GetAnnotationPool()
+{
+ static rtl::Reference<SfxItemPool> s_pAnnotationPool;
+ if( !s_pAnnotationPool )
+ {
+ s_pAnnotationPool = EditEngine::CreatePool();
+ s_pAnnotationPool->SetPoolDefaultItem(SvxFontHeightItem(423,100,EE_CHAR_FONTHEIGHT));
+
+ vcl::Font aAppFont( Application::GetSettings().GetStyleSettings().GetAppFont() );
+ s_pAnnotationPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(),aAppFont.GetFamilyName(),"",PITCH_DONTKNOW,RTL_TEXTENCODING_DONTKNOW,EE_CHAR_FONTINFO));
+ }
+
+ return s_pAnnotationPool.get();
+}
+
+static SfxBindings* getBindings( ViewShellBase const & rBase )
+{
+ if( rBase.GetMainViewShell() && rBase.GetMainViewShell()->GetViewFrame() )
+ return &rBase.GetMainViewShell()->GetViewFrame()->GetBindings();
+
+ return nullptr;
+}
+
+static SfxDispatcher* getDispatcher( ViewShellBase const & rBase )
+{
+ if( rBase.GetMainViewShell() && rBase.GetMainViewShell()->GetViewFrame() )
+ return rBase.GetMainViewShell()->GetViewFrame()->GetDispatcher();
+
+ return nullptr;
+}
+
+css::util::DateTime getCurrentDateTime()
+{
+ DateTime aCurrentDate( DateTime::SYSTEM );
+ return css::util::DateTime( 0, aCurrentDate.GetSec(),
+ aCurrentDate.GetMin(), aCurrentDate.GetHour(),
+ aCurrentDate.GetDay(), aCurrentDate.GetMonth(),
+ aCurrentDate.GetYear(), false );
+}
+
+OUString getAnnotationDateTimeString( const Reference< XAnnotation >& xAnnotation )
+{
+ OUString sRet;
+ if( xAnnotation.is() )
+ {
+ const SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData();
+
+ css::util::DateTime aDateTime( xAnnotation->getDateTime() );
+
+ Date aSysDate( Date::SYSTEM );
+ Date aDate( aDateTime.Day, aDateTime.Month, aDateTime.Year );
+ if (aDate==aSysDate)
+ sRet = SdResId(STR_ANNOTATION_TODAY);
+ else if (aDate == (aSysDate-1))
+ sRet = SdResId(STR_ANNOTATION_YESTERDAY);
+ else if (aDate.IsValidAndGregorian() )
+ sRet = rLocalData.getDate(aDate);
+
+ ::tools::Time aTime( aDateTime );
+ if(aTime.GetTime() != 0)
+ sRet += " " + rLocalData.getTime( aTime,false );
+ }
+ return sRet;
+}
+
+AnnotationManagerImpl::AnnotationManagerImpl( ViewShellBase& rViewShellBase )
+: mrBase( rViewShellBase )
+, mpDoc( rViewShellBase.GetDocument() )
+, mbShowAnnotations( true )
+, mnUpdateTagsEvent( nullptr )
+{
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(mpDoc->GetDocumentType());
+ if( pOptions )
+ mbShowAnnotations = pOptions->IsShowComments();
+}
+
+void AnnotationManagerImpl::init()
+{
+ // get current controller and initialize listeners
+ try
+ {
+ addListener();
+ mxView.set(mrBase.GetController(), UNO_QUERY);
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::AnnotationManagerImpl::AnnotationManagerImpl()" );
+ }
+
+ try
+ {
+ Reference<XEventBroadcaster> xModel (mrBase.GetDocShell()->GetModel(), UNO_QUERY_THROW );
+ Reference<XEventListener> xListener( this );
+ xModel->addEventListener( xListener );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// WeakComponentImplHelper
+void AnnotationManagerImpl::disposing (std::unique_lock<std::mutex>&)
+{
+ try
+ {
+ Reference<XEventBroadcaster> xModel (mrBase.GetDocShell()->GetModel(), UNO_QUERY_THROW );
+ Reference<XEventListener> xListener( this );
+ xModel->removeEventListener( xListener );
+ }
+ catch( Exception& )
+ {
+ }
+
+ removeListener();
+ DisposeTags();
+
+ if( mnUpdateTagsEvent )
+ {
+ Application::RemoveUserEvent( mnUpdateTagsEvent );
+ mnUpdateTagsEvent = nullptr;
+ }
+
+ mxView.clear();
+ mxCurrentPage.clear();
+}
+
+// XEventListener
+void SAL_CALL AnnotationManagerImpl::notifyEvent( const css::document::EventObject& aEvent )
+{
+ if( !(aEvent.EventName == "OnAnnotationInserted" || aEvent.EventName == "OnAnnotationRemoved" || aEvent.EventName == "OnAnnotationChanged") )
+ return;
+
+ // AnnotationInsertion and modification is not handled here because when
+ // a new annotation is inserted, it consists of OnAnnotationInserted
+ // followed by a chain of OnAnnotationChanged (called for setting each
+ // of the annotation attributes - author, text etc.). This is not what a
+ // LOK client wants. So only handle removal here as annotation removal
+ // consists of only one event - 'OnAnnotationRemoved'
+ if ( aEvent.EventName == "OnAnnotationRemoved" )
+ {
+ Reference< XAnnotation > xAnnotation( aEvent.Source, uno::UNO_QUERY );
+ if ( xAnnotation.is() )
+ {
+ LOKCommentNotify(CommentNotificationType::Remove, &mrBase, xAnnotation);
+ }
+ }
+
+ UpdateTags();
+}
+
+void SAL_CALL AnnotationManagerImpl::disposing( const css::lang::EventObject& /*Source*/ )
+{
+}
+
+Reference<XAnnotation> AnnotationManagerImpl::GetAnnotationById(sal_uInt32 nAnnotationId)
+{
+ SdPage* pPage = nullptr;
+ do
+ {
+ pPage = GetNextPage(pPage, true);
+ if( pPage && !pPage->getAnnotations().empty() )
+ {
+ AnnotationVector aAnnotations(pPage->getAnnotations());
+ auto iter = std::find_if(aAnnotations.begin(), aAnnotations.end(),
+ [nAnnotationId](const Reference<XAnnotation>& xAnnotation) {
+ return sd::getAnnotationId(xAnnotation) == nAnnotationId;
+ });
+ if (iter != aAnnotations.end())
+ return *iter;
+ }
+ } while( pPage );
+
+ Reference<XAnnotation> xAnnotationEmpty;
+ return xAnnotationEmpty;
+}
+
+void AnnotationManagerImpl::ShowAnnotations( bool bShow )
+{
+ // enforce show annotations if a new annotation is inserted
+ if( mbShowAnnotations != bShow )
+ {
+ mbShowAnnotations = bShow;
+
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(mpDoc->GetDocumentType());
+ if( pOptions )
+ pOptions->SetShowComments( mbShowAnnotations );
+
+ UpdateTags();
+ }
+}
+
+void AnnotationManagerImpl::ExecuteAnnotation(SfxRequest const & rReq )
+{
+ switch( rReq.GetSlot() )
+ {
+ case SID_INSERT_POSTIT:
+ ExecuteInsertAnnotation( rReq );
+ break;
+ case SID_DELETE_POSTIT:
+ case SID_DELETEALL_POSTIT:
+ case SID_DELETEALLBYAUTHOR_POSTIT:
+ ExecuteDeleteAnnotation( rReq );
+ break;
+ case SID_EDIT_POSTIT:
+ ExecuteEditAnnotation( rReq );
+ break;
+ case SID_PREVIOUS_POSTIT:
+ case SID_NEXT_POSTIT:
+ SelectNextAnnotation( rReq.GetSlot() == SID_NEXT_POSTIT );
+ break;
+ case SID_REPLYTO_POSTIT:
+ ExecuteReplyToAnnotation( rReq );
+ break;
+ case SID_TOGGLE_NOTES:
+ ShowAnnotations( !mbShowAnnotations );
+ break;
+ }
+}
+
+void AnnotationManagerImpl::ExecuteInsertAnnotation(SfxRequest const & rReq)
+{
+ if (!comphelper::LibreOfficeKit::isActive() || comphelper::LibreOfficeKit::isTiledAnnotations())
+ ShowAnnotations(true);
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ OUString sText;
+ if (pArgs)
+ {
+ if (const SfxStringItem* pPoolItem = pArgs->GetItemIfSet(SID_ATTR_POSTIT_TEXT))
+ {
+ sText = pPoolItem->GetValue();
+ }
+ }
+
+ InsertAnnotation(sText);
+}
+
+void AnnotationManagerImpl::ExecuteDeleteAnnotation(SfxRequest const & rReq)
+{
+ ShowAnnotations( true );
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ switch( rReq.GetSlot() )
+ {
+ case SID_DELETEALL_POSTIT:
+ DeleteAllAnnotations();
+ break;
+ case SID_DELETEALLBYAUTHOR_POSTIT:
+ if( pArgs )
+ {
+ const SfxPoolItem* pPoolItem = nullptr;
+ if( SfxItemState::SET == pArgs->GetItemState( SID_DELETEALLBYAUTHOR_POSTIT, true, &pPoolItem ) )
+ {
+ OUString sAuthor( static_cast<const SfxStringItem*>( pPoolItem )->GetValue() );
+ DeleteAnnotationsByAuthor( sAuthor );
+ }
+ }
+ break;
+ case SID_DELETE_POSTIT:
+ {
+ Reference< XAnnotation > xAnnotation;
+ sal_uInt32 nId = 0;
+ if( pArgs )
+ {
+ const SfxPoolItem* pPoolItem = nullptr;
+ if( SfxItemState::SET == pArgs->GetItemState( SID_DELETE_POSTIT, true, &pPoolItem ) )
+ static_cast<const SfxUnoAnyItem*>(pPoolItem)->GetValue() >>= xAnnotation;
+ if( SfxItemState::SET == pArgs->GetItemState( SID_ATTR_POSTIT_ID, true, &pPoolItem ) )
+ nId = static_cast<const SvxPostItIdItem*>(pPoolItem)->GetValue().toUInt32();
+ }
+
+ if (nId != 0)
+ xAnnotation = GetAnnotationById(nId);
+ else if( !xAnnotation.is() )
+ GetSelectedAnnotation( xAnnotation );
+
+ DeleteAnnotation( xAnnotation );
+ }
+ break;
+ }
+
+ UpdateTags();
+}
+
+void AnnotationManagerImpl::ExecuteEditAnnotation(SfxRequest const & rReq)
+{
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ Reference< XAnnotation > xAnnotation;
+ OUString sText;
+ sal_Int32 nPositionX = -1;
+ sal_Int32 nPositionY = -1;
+
+ if (!pArgs)
+ return;
+
+ if (mpDoc->IsUndoEnabled())
+ mpDoc->BegUndo(SdResId(STR_ANNOTATION_UNDO_EDIT));
+
+ if (const SvxPostItIdItem* pPoolItem = pArgs->GetItemIfSet(SID_ATTR_POSTIT_ID))
+ {
+ sal_uInt32 nId = pPoolItem->GetValue().toUInt32();
+ xAnnotation = GetAnnotationById(nId);
+ }
+ if (const SfxStringItem* pPoolItem = pArgs->GetItemIfSet(SID_ATTR_POSTIT_TEXT))
+ sText = pPoolItem->GetValue();
+
+ if (const SfxInt32Item* pPoolItem = pArgs->GetItemIfSet(SID_ATTR_POSTIT_POSITION_X))
+ nPositionX = pPoolItem->GetValue();
+
+ if (const SfxInt32Item* pPoolItem = pArgs->GetItemIfSet(SID_ATTR_POSTIT_POSITION_Y))
+ nPositionY = pPoolItem->GetValue();
+
+ if (xAnnotation.is())
+ {
+ CreateChangeUndo(xAnnotation);
+
+ if (nPositionX >= 0 && nPositionY >= 0)
+ {
+ double fX = convertTwipToMm100(nPositionX) / 100.0;
+ double fY = convertTwipToMm100(nPositionY) / 100.0;
+ xAnnotation->setPosition({fX, fY});
+ }
+
+ if (!sText.isEmpty())
+ {
+ // TODO: Not allow other authors to change others' comments ?
+ Reference<XText> xText(xAnnotation->getTextRange());
+ xText->setString(sText);
+ }
+
+ LOKCommentNotifyAll(CommentNotificationType::Modify, xAnnotation);
+ }
+
+ if (mpDoc->IsUndoEnabled())
+ mpDoc->EndUndo();
+
+ UpdateTags(true);
+}
+
+void AnnotationManagerImpl::InsertAnnotation(const OUString& rText)
+{
+ SdPage* pPage = GetCurrentPage();
+ if( !pPage )
+ return;
+
+ if( mpDoc->IsUndoEnabled() )
+ mpDoc->BegUndo( SdResId( STR_ANNOTATION_UNDO_INSERT ) );
+
+ // find free space for new annotation
+ int y = 0, x = 0;
+
+ AnnotationVector aAnnotations( pPage->getAnnotations() );
+ if( !aAnnotations.empty() )
+ {
+ const int page_width = pPage->GetSize().Width();
+ const int width = 1000;
+ const int height = 800;
+ ::tools::Rectangle aTagRect;
+
+ while( true )
+ {
+ ::tools::Rectangle aNewRect( x, y, x + width - 1, y + height - 1 );
+ bool bFree = true;
+
+ for( const auto& rxAnnotation : aAnnotations )
+ {
+ RealPoint2D aPoint( rxAnnotation->getPosition() );
+ aTagRect.SetLeft( sal::static_int_cast< ::tools::Long >( aPoint.X * 100.0 ) );
+ aTagRect.SetTop( sal::static_int_cast< ::tools::Long >( aPoint.Y * 100.0 ) );
+ aTagRect.SetRight( aTagRect.Left() + width - 1 );
+ aTagRect.SetBottom( aTagRect.Top() + height - 1 );
+
+ if( aNewRect.Overlaps( aTagRect ) )
+ {
+ bFree = false;
+ break;
+ }
+ }
+
+ if( !bFree )
+ {
+ x += width;
+ if( x > page_width )
+ {
+ x = 0;
+ y += height;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ Reference< XAnnotation > xAnnotation;
+ pPage->createAnnotation( xAnnotation );
+
+ OUString sAuthor;
+ if (comphelper::LibreOfficeKit::isActive())
+ sAuthor = mrBase.GetMainViewShell()->GetView()->GetAuthor();
+ else
+ {
+ SvtUserOptions aUserOptions;
+ sAuthor = aUserOptions.GetFullName();
+ xAnnotation->setInitials( aUserOptions.GetID() );
+ }
+
+ if (!rText.isEmpty())
+ {
+ Reference<XText> xText(xAnnotation->getTextRange());
+ xText->setString(rText);
+ }
+
+ // set current author to new annotation
+ xAnnotation->setAuthor( sAuthor );
+ // set current time to new annotation
+ xAnnotation->setDateTime( getCurrentDateTime() );
+
+ // set position
+ RealPoint2D aPos( static_cast<double>(x) / 100.0, static_cast<double>(y) / 100.0 );
+ xAnnotation->setPosition( aPos );
+
+ if( mpDoc->IsUndoEnabled() )
+ mpDoc->EndUndo();
+
+ // Tell our LOK clients about new comment added
+ LOKCommentNotifyAll(CommentNotificationType::Add, xAnnotation);
+
+ UpdateTags(true);
+ SelectAnnotation( xAnnotation, true );
+}
+
+void AnnotationManagerImpl::ExecuteReplyToAnnotation( SfxRequest const & rReq )
+{
+ Reference< XAnnotation > xAnnotation;
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ OUString sReplyText;
+ if( pArgs )
+ {
+ const SfxPoolItem* pPoolItem = nullptr;
+ if( SfxItemState::SET == pArgs->GetItemState( SID_ATTR_POSTIT_ID, true, &pPoolItem ) )
+ {
+ sal_uInt32 nReplyId = 0; // Id of the comment to reply to
+ nReplyId = static_cast<const SvxPostItIdItem*>(pPoolItem)->GetValue().toUInt32();
+ xAnnotation = GetAnnotationById(nReplyId);
+ }
+ else if( SfxItemState::SET == pArgs->GetItemState( rReq.GetSlot(), true, &pPoolItem ) )
+ static_cast<const SfxUnoAnyItem*>( pPoolItem )->GetValue() >>= xAnnotation;
+
+ if( SfxItemState::SET == pArgs->GetItemState( SID_ATTR_POSTIT_TEXT, true, &pPoolItem ) )
+ sReplyText = static_cast<const SvxPostItTextItem*>( pPoolItem )->GetValue();
+ }
+
+ TextApiObject* pTextApi = getTextApiObject( xAnnotation );
+ if( !pTextApi )
+ return;
+
+ ::Outliner aOutliner( GetAnnotationPool(),OutlinerMode::TextObject );
+
+ SdDrawDocument::SetCalcFieldValueHdl( &aOutliner );
+ aOutliner.SetUpdateLayout( true );
+
+ OUString aStr(SdResId(STR_ANNOTATION_REPLY));
+ OUString sAuthor( xAnnotation->getAuthor() );
+ if( sAuthor.isEmpty() )
+ sAuthor = SdResId( STR_ANNOTATION_NOAUTHOR );
+
+ aStr = aStr.replaceFirst("%1", sAuthor) +
+ " (" + getAnnotationDateTimeString( xAnnotation ) + "): \"";
+
+ OUString sQuote( pTextApi->GetText() );
+
+ if( sQuote.isEmpty() )
+ sQuote = "...";
+ aStr += sQuote + "\"\n";
+
+ for( sal_Int32 nIdx = 0; nIdx >= 0; )
+ aOutliner.Insert( aStr.getToken( 0, '\n', nIdx ), EE_PARA_APPEND, -1 );
+
+ if( aOutliner.GetParagraphCount() > 1 )
+ {
+ SfxItemSet aAnswerSet( aOutliner.GetEmptyItemSet() );
+ aAnswerSet.Put(SvxPostureItem(ITALIC_NORMAL,EE_CHAR_ITALIC));
+
+ ESelection aSel;
+ aSel.nEndPara = aOutliner.GetParagraphCount()-2;
+ aSel.nEndPos = aOutliner.GetText( aOutliner.GetParagraph( aSel.nEndPara ) ).getLength();
+
+ aOutliner.QuickSetAttribs( aAnswerSet, aSel );
+ }
+
+ if (!sReplyText.isEmpty())
+ aOutliner.Insert(sReplyText);
+
+ std::optional< OutlinerParaObject > pOPO( aOutliner.CreateParaObject() );
+ pTextApi->SetText(*pOPO);
+
+ OUString sReplyAuthor;
+ if (comphelper::LibreOfficeKit::isActive())
+ sReplyAuthor = mrBase.GetMainViewShell()->GetView()->GetAuthor();
+ else
+ {
+ SvtUserOptions aUserOptions;
+ sReplyAuthor = aUserOptions.GetFullName();
+ xAnnotation->setInitials( aUserOptions.GetID() );
+ }
+
+ xAnnotation->setAuthor( sReplyAuthor );
+ // set current time to reply
+ xAnnotation->setDateTime( getCurrentDateTime() );
+
+ // Tell our LOK clients about this (comment modification)
+ LOKCommentNotifyAll(CommentNotificationType::Modify, xAnnotation);
+
+ UpdateTags(true);
+ SelectAnnotation( xAnnotation, true );
+}
+
+void AnnotationManagerImpl::DeleteAnnotation( const Reference< XAnnotation >& xAnnotation )
+{
+ SdPage* pPage = GetCurrentPage();
+
+ if( xAnnotation.is() && pPage )
+ {
+ if( mpDoc->IsUndoEnabled() )
+ mpDoc->BegUndo( SdResId( STR_ANNOTATION_UNDO_DELETE ) );
+
+ pPage->removeAnnotation( xAnnotation );
+
+ if( mpDoc->IsUndoEnabled() )
+ mpDoc->EndUndo();
+
+ UpdateTags();
+ }
+}
+
+void AnnotationManagerImpl::DeleteAnnotationsByAuthor( std::u16string_view sAuthor )
+{
+ if( mpDoc->IsUndoEnabled() )
+ mpDoc->BegUndo( SdResId( STR_ANNOTATION_UNDO_DELETE ) );
+
+ SdPage* pPage = nullptr;
+ do
+ {
+ pPage = GetNextPage( pPage, true );
+
+ if( pPage && !pPage->getAnnotations().empty() )
+ {
+ AnnotationVector aAnnotations( pPage->getAnnotations() );
+ for( Reference< XAnnotation >& xAnnotation : aAnnotations )
+ {
+ if( xAnnotation->getAuthor() == sAuthor )
+ {
+ if( mxSelectedAnnotation == xAnnotation )
+ mxSelectedAnnotation.clear();
+ pPage->removeAnnotation( xAnnotation );
+ }
+ }
+ }
+ } while( pPage );
+
+ if( mpDoc->IsUndoEnabled() )
+ mpDoc->EndUndo();
+}
+
+void AnnotationManagerImpl::DeleteAllAnnotations()
+{
+ if( mpDoc->IsUndoEnabled() )
+ mpDoc->BegUndo( SdResId( STR_ANNOTATION_UNDO_DELETE ) );
+
+ SdPage* pPage = nullptr;
+ do
+ {
+ pPage = GetNextPage( pPage, true );
+
+ if( pPage && !pPage->getAnnotations().empty() )
+ {
+
+ AnnotationVector aAnnotations( pPage->getAnnotations() );
+ for( const auto& rxAnnotation : aAnnotations )
+ {
+ pPage->removeAnnotation( rxAnnotation );
+ }
+ }
+ }
+ while( pPage );
+
+ mxSelectedAnnotation.clear();
+
+ if( mpDoc->IsUndoEnabled() )
+ mpDoc->EndUndo();
+}
+
+void AnnotationManagerImpl::GetAnnotationState(SfxItemSet& rSet)
+{
+ SdPage* pCurrentPage = GetCurrentPage();
+
+ const bool bReadOnly = mrBase.GetDocShell()->IsReadOnly();
+ const bool bWrongPageKind = (pCurrentPage == nullptr) || (pCurrentPage->GetPageKind() != PageKind::Standard);
+
+ const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( GetODFSaneDefaultVersion() );
+
+ if (bReadOnly || bWrongPageKind || (nCurrentODFVersion <= SvtSaveOptions::ODFSVER_012))
+ rSet.DisableItem( SID_INSERT_POSTIT );
+
+ rSet.Put(SfxBoolItem(SID_TOGGLE_NOTES, mbShowAnnotations));
+
+ Reference< XAnnotation > xAnnotation;
+ GetSelectedAnnotation( xAnnotation );
+
+ // Don't disable these slot in case of LOK, as postit doesn't need to
+ // selected before doing an operation on it in LOK
+ if( (!xAnnotation.is() && !comphelper::LibreOfficeKit::isActive()) || bReadOnly )
+ {
+ rSet.DisableItem( SID_DELETE_POSTIT );
+ rSet.DisableItem( SID_EDIT_POSTIT );
+ }
+
+ SdPage* pPage = nullptr;
+
+ bool bHasAnnotations = false;
+ do
+ {
+ pPage = GetNextPage( pPage, true );
+
+ if( pPage && !pPage->getAnnotations().empty() )
+ bHasAnnotations = true;
+ }
+ while( pPage && !bHasAnnotations );
+
+ if( !bHasAnnotations || bReadOnly )
+ {
+ rSet.DisableItem( SID_DELETEALL_POSTIT );
+ }
+
+ if( bWrongPageKind || !bHasAnnotations )
+ {
+ rSet.DisableItem( SID_PREVIOUS_POSTIT );
+ rSet.DisableItem( SID_NEXT_POSTIT );
+ }
+}
+
+void AnnotationManagerImpl::SelectNextAnnotation(bool bForward)
+{
+ ShowAnnotations( true );
+
+ Reference< XAnnotation > xCurrent;
+ GetSelectedAnnotation( xCurrent );
+ SdPage* pPage = GetCurrentPage();
+ if( !pPage )
+ return;
+
+ AnnotationVector aAnnotations( pPage->getAnnotations() );
+
+ if( bForward )
+ {
+ if( xCurrent.is() )
+ {
+ auto iter = std::find(aAnnotations.begin(), aAnnotations.end(), xCurrent);
+ if (iter != aAnnotations.end())
+ {
+ ++iter;
+ if( iter != aAnnotations.end() )
+ {
+ SelectAnnotation( *iter );
+ return;
+ }
+ }
+ }
+ else if( !aAnnotations.empty() )
+ {
+ SelectAnnotation( *(aAnnotations.begin()) );
+ return;
+ }
+ }
+ else
+ {
+ if( xCurrent.is() )
+ {
+ auto iter = std::find(aAnnotations.begin(), aAnnotations.end(), xCurrent);
+ if (iter != aAnnotations.end() && iter != aAnnotations.begin())
+ {
+ --iter;
+ SelectAnnotation( *iter );
+ return;
+ }
+ }
+ else if( !aAnnotations.empty() )
+ {
+ AnnotationVector::iterator iter( aAnnotations.end() );
+ SelectAnnotation( *(--iter) );
+ return;
+ }
+ }
+
+ mxSelectedAnnotation.clear();
+ do
+ {
+ do
+ {
+ pPage = GetNextPage( pPage, bForward );
+
+ if( pPage && !pPage->getAnnotations().empty() )
+ {
+ // switch to next/previous slide with annotations
+ std::shared_ptr<DrawViewShell> pDrawViewShell(std::dynamic_pointer_cast<DrawViewShell>(mrBase.GetMainViewShell()));
+ if (pDrawViewShell != nullptr)
+ {
+ pDrawViewShell->ChangeEditMode(pPage->IsMasterPage() ? EditMode::MasterPage : EditMode::Page, false);
+ pDrawViewShell->SwitchPage((pPage->GetPageNum() - 1) >> 1);
+
+ SfxDispatcher* pDispatcher = getDispatcher( mrBase );
+ if( pDispatcher )
+ pDispatcher->Execute( bForward ? SID_NEXT_POSTIT : SID_PREVIOUS_POSTIT );
+
+ return;
+ }
+ }
+ }
+ while( pPage );
+
+ // The question text depends on the search direction.
+ bool bImpress = mpDoc->GetDocumentType() == DocumentType::Impress;
+ TranslateId pStringId;
+ if(bForward)
+ pStringId = bImpress ? STR_ANNOTATION_WRAP_FORWARD : STR_ANNOTATION_WRAP_FORWARD_DRAW;
+ else
+ pStringId = bImpress ? STR_ANNOTATION_WRAP_BACKWARD : STR_ANNOTATION_WRAP_BACKWARD_DRAW;
+
+ // Pop up question box that asks the user whether to wrap around.
+ // The dialog is made modal with respect to the whole application.
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Question, VclButtonsType::YesNo,
+ SdResId(pStringId)));
+ xQueryBox->set_default_response(RET_YES);
+ if (xQueryBox->run() != RET_YES)
+ break;
+ }
+ while( true );
+}
+
+void AnnotationManagerImpl::onTagSelected( AnnotationTag const & rTag )
+{
+ mxSelectedAnnotation = rTag.GetAnnotation();
+ invalidateSlots();
+}
+
+void AnnotationManagerImpl::onTagDeselected( AnnotationTag const & rTag )
+{
+ if( rTag.GetAnnotation() == mxSelectedAnnotation )
+ {
+ mxSelectedAnnotation.clear();
+ invalidateSlots();
+ }
+}
+
+void AnnotationManagerImpl::SelectAnnotation( const css::uno::Reference< css::office::XAnnotation >& xAnnotation, bool bEdit /* = sal_False */ )
+{
+ mxSelectedAnnotation = xAnnotation;
+
+ auto iter = std::find_if(maTagVector.begin(), maTagVector.end(),
+ [&xAnnotation](const rtl::Reference<AnnotationTag>& rxTag) { return rxTag->GetAnnotation() == xAnnotation; });
+ if (iter != maTagVector.end())
+ {
+ SmartTagReference xTag( *iter );
+ mrBase.GetMainViewShell()->GetView()->getSmartTags().select( xTag );
+ (*iter)->OpenPopup( bEdit );
+ }
+}
+
+void AnnotationManagerImpl::GetSelectedAnnotation( css::uno::Reference< css::office::XAnnotation >& xAnnotation )
+{
+ xAnnotation = mxSelectedAnnotation;
+}
+
+void AnnotationManagerImpl::invalidateSlots()
+{
+ SfxBindings* pBindings = getBindings( mrBase );
+ if( pBindings )
+ {
+ pBindings->Invalidate( SID_INSERT_POSTIT );
+ pBindings->Invalidate( SID_DELETE_POSTIT );
+ pBindings->Invalidate( SID_DELETEALL_POSTIT );
+ pBindings->Invalidate( SID_PREVIOUS_POSTIT );
+ pBindings->Invalidate( SID_NEXT_POSTIT );
+ pBindings->Invalidate( SID_UNDO );
+ pBindings->Invalidate( SID_REDO );
+ }
+}
+
+void AnnotationManagerImpl::onSelectionChanged()
+{
+ if( !(mxView.is() && mrBase.GetDrawView()) )
+ return;
+
+ try
+ {
+ Reference< XAnnotationAccess > xPage( mxView->getCurrentPage(), UNO_QUERY );
+
+ if( xPage != mxCurrentPage )
+ {
+ mxCurrentPage = xPage;
+
+ UpdateTags(true);
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::AnnotationManagerImpl::onSelectionChanged()" );
+ }
+}
+
+void AnnotationManagerImpl::UpdateTags( bool bSynchron )
+{
+ if( bSynchron )
+ {
+ if( mnUpdateTagsEvent )
+ Application::RemoveUserEvent( mnUpdateTagsEvent );
+
+ UpdateTagsHdl(nullptr);
+ }
+ else
+ {
+ if( !mnUpdateTagsEvent && mxView.is() )
+ mnUpdateTagsEvent = Application::PostUserEvent( LINK( this, AnnotationManagerImpl, UpdateTagsHdl ) );
+ }
+}
+
+IMPL_LINK_NOARG(AnnotationManagerImpl, UpdateTagsHdl, void*, void)
+{
+ mnUpdateTagsEvent = nullptr;
+ DisposeTags();
+
+ if( mbShowAnnotations )
+ CreateTags();
+
+ if( mrBase.GetDrawView() )
+ static_cast< ::sd::View* >( mrBase.GetDrawView() )->updateHandles();
+
+ invalidateSlots();
+}
+
+void AnnotationManagerImpl::CreateTags()
+{
+ if( !(mxCurrentPage.is() && mpDoc) )
+ return;
+
+ auto xViewShell = mrBase.GetMainViewShell();
+ if (!xViewShell)
+ return;
+
+ try
+ {
+ int nIndex = 1;
+ maFont = Application::GetSettings().GetStyleSettings().GetAppFont();
+
+ rtl::Reference< AnnotationTag > xSelectedTag;
+
+ Reference< XAnnotationEnumeration > xEnum( mxCurrentPage->createAnnotationEnumeration() );
+ while( xEnum->hasMoreElements() )
+ {
+ Reference< XAnnotation > xAnnotation( xEnum->nextElement() );
+ Color aColor( GetColorLight( mpDoc->GetAnnotationAuthorIndex( xAnnotation->getAuthor() ) ) );
+ rtl::Reference< AnnotationTag > xTag( new AnnotationTag( *this, *xViewShell->GetView(), xAnnotation, aColor, nIndex++, maFont ) );
+ maTagVector.push_back(xTag);
+
+ if( xAnnotation == mxSelectedAnnotation )
+ {
+ xSelectedTag = xTag;
+ }
+ }
+
+ if( xSelectedTag.is() )
+ {
+ SmartTagReference xTag( xSelectedTag );
+ mrBase.GetMainViewShell()->GetView()->getSmartTags().select( xTag );
+ }
+ else
+ {
+ // no tag, no selection!
+ mxSelectedAnnotation.clear();
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::AnnotationManagerImpl::onSelectionChanged()" );
+ }
+}
+
+void AnnotationManagerImpl::DisposeTags()
+{
+ for (auto& rxTag : maTagVector)
+ {
+ rxTag->Dispose();
+ }
+
+ maTagVector.clear();
+}
+
+void AnnotationManagerImpl::addListener()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,AnnotationManagerImpl,EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->AddEventListener(aLink);
+}
+
+void AnnotationManagerImpl::removeListener()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,AnnotationManagerImpl,EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
+}
+
+IMPL_LINK(AnnotationManagerImpl,EventMultiplexerListener,
+ tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ case EventMultiplexerEventId::CurrentPageChanged:
+ case EventMultiplexerEventId::EditViewSelection:
+ onSelectionChanged();
+ break;
+
+ case EventMultiplexerEventId::MainViewRemoved:
+ mxView.clear();
+ onSelectionChanged();
+ break;
+
+ case EventMultiplexerEventId::MainViewAdded:
+ mxView.set( mrBase.GetController(), UNO_QUERY );
+ onSelectionChanged();
+ break;
+
+ default: break;
+ }
+}
+
+void AnnotationManagerImpl::ExecuteAnnotationTagContextMenu(const Reference<XAnnotation>& xAnnotation, weld::Widget* pParent, const ::tools::Rectangle& rContextRect)
+{
+ SfxDispatcher* pDispatcher( getDispatcher( mrBase ) );
+ if( !pDispatcher )
+ return;
+
+ const bool bReadOnly = mrBase.GetDocShell()->IsReadOnly();
+
+ if (bReadOnly)
+ return;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/annotationtagmenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+
+ SvtUserOptions aUserOptions;
+ OUString sCurrentAuthor( aUserOptions.GetFullName() );
+ OUString sAuthor( xAnnotation->getAuthor() );
+
+ OUString aStr(xMenu->get_label(".uno:DeleteAllAnnotationByAuthor"));
+ OUString aReplace( sAuthor );
+ if( aReplace.isEmpty() )
+ aReplace = SdResId( STR_ANNOTATION_NOAUTHOR );
+ aStr = aStr.replaceFirst("%1", aReplace);
+ xMenu->set_label(".uno:DeleteAllAnnotationByAuthor", aStr);
+
+ bool bShowReply = sAuthor != sCurrentAuthor;
+ xMenu->set_visible(".uno:ReplyToAnnotation", bShowReply);
+ xMenu->set_visible("separator", bShowReply);
+ xMenu->set_visible(".uno:DeleteAnnotation", xAnnotation.is());
+
+ auto sId = xMenu->popup_at_rect(pParent, rContextRect);
+
+ if (sId == ".uno:ReplyToAnnotation")
+ {
+ const SfxUnoAnyItem aItem( SID_REPLYTO_POSTIT, Any( xAnnotation ) );
+ pDispatcher->ExecuteList(SID_REPLYTO_POSTIT,
+ SfxCallMode::ASYNCHRON, { &aItem });
+ }
+ else if (sId == ".uno:DeleteAnnotation")
+ {
+ const SfxUnoAnyItem aItem( SID_DELETE_POSTIT, Any( xAnnotation ) );
+ pDispatcher->ExecuteList(SID_DELETE_POSTIT, SfxCallMode::ASYNCHRON,
+ { &aItem });
+ }
+ else if (sId == ".uno:DeleteAllAnnotationByAuthor")
+ {
+ const SfxStringItem aItem( SID_DELETEALLBYAUTHOR_POSTIT, sAuthor );
+ pDispatcher->ExecuteList( SID_DELETEALLBYAUTHOR_POSTIT,
+ SfxCallMode::ASYNCHRON, { &aItem });
+ }
+ else if (sId == ".uno:DeleteAllAnnotation")
+ pDispatcher->Execute( SID_DELETEALL_POSTIT );
+}
+
+Color AnnotationManagerImpl::GetColor(sal_uInt16 aAuthorIndex)
+{
+ if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ static const Color aArrayNormal[] = {
+ COL_AUTHOR1_NORMAL, COL_AUTHOR2_NORMAL, COL_AUTHOR3_NORMAL,
+ COL_AUTHOR4_NORMAL, COL_AUTHOR5_NORMAL, COL_AUTHOR6_NORMAL,
+ COL_AUTHOR7_NORMAL, COL_AUTHOR8_NORMAL, COL_AUTHOR9_NORMAL };
+
+ return aArrayNormal[ aAuthorIndex % SAL_N_ELEMENTS( aArrayNormal ) ];
+ }
+
+ return COL_WHITE;
+}
+
+Color AnnotationManagerImpl::GetColorLight(sal_uInt16 aAuthorIndex)
+{
+ if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ static const Color aArrayLight[] = {
+ COL_AUTHOR1_LIGHT, COL_AUTHOR2_LIGHT, COL_AUTHOR3_LIGHT,
+ COL_AUTHOR4_LIGHT, COL_AUTHOR5_LIGHT, COL_AUTHOR6_LIGHT,
+ COL_AUTHOR7_LIGHT, COL_AUTHOR8_LIGHT, COL_AUTHOR9_LIGHT };
+
+ return aArrayLight[ aAuthorIndex % SAL_N_ELEMENTS( aArrayLight ) ];
+ }
+
+ return COL_WHITE;
+}
+
+Color AnnotationManagerImpl::GetColorDark(sal_uInt16 aAuthorIndex)
+{
+ if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ static const Color aArrayAnkor[] = {
+ COL_AUTHOR1_DARK, COL_AUTHOR2_DARK, COL_AUTHOR3_DARK,
+ COL_AUTHOR4_DARK, COL_AUTHOR5_DARK, COL_AUTHOR6_DARK,
+ COL_AUTHOR7_DARK, COL_AUTHOR8_DARK, COL_AUTHOR9_DARK };
+
+ return aArrayAnkor[ aAuthorIndex % SAL_N_ELEMENTS( aArrayAnkor ) ];
+ }
+
+ return COL_WHITE;
+}
+
+SdPage* AnnotationManagerImpl::GetNextPage( SdPage const * pPage, bool bForward )
+{
+ if( pPage == nullptr )
+ {
+ if (bForward)
+ return mpDoc->GetSdPage(0, PageKind::Standard ); // first page
+ else
+ return mpDoc->GetMasterSdPage( mpDoc->GetMasterSdPageCount(PageKind::Standard) - 1, PageKind::Standard ); // last page
+ }
+
+ sal_uInt16 nPageNum = (pPage->GetPageNum() - 1) >> 1;
+
+ // first all non master pages
+ if( !pPage->IsMasterPage() )
+ {
+ if( bForward )
+ {
+ if( nPageNum >= mpDoc->GetSdPageCount(PageKind::Standard)-1 )
+ {
+ // we reached end of draw pages, start with master pages (skip handout master for draw)
+ return mpDoc->GetMasterSdPage( (mpDoc->GetDocumentType() == DocumentType::Impress) ? 0 : 1, PageKind::Standard );
+ }
+ nPageNum++;
+ }
+ else
+ {
+ if( nPageNum == 0 )
+ return nullptr; // we are already on the first draw page, finished
+
+ nPageNum--;
+ }
+ return mpDoc->GetSdPage(nPageNum, PageKind::Standard);
+ }
+ else
+ {
+ if( bForward )
+ {
+ if( nPageNum >= mpDoc->GetMasterSdPageCount(PageKind::Standard)-1 )
+ {
+ return nullptr; // we reached the end, there is nothing more to see here
+ }
+ nPageNum++;
+ }
+ else
+ {
+ if( nPageNum == (mpDoc->GetDocumentType() == DocumentType::Impress ? 0 : 1) )
+ {
+ // we reached beginning of master pages, start with end if pages
+ return mpDoc->GetSdPage( mpDoc->GetSdPageCount(PageKind::Standard)-1, PageKind::Standard );
+ }
+
+ nPageNum--;
+ }
+ return mpDoc->GetMasterSdPage(nPageNum,PageKind::Standard);
+ }
+}
+
+SdPage* AnnotationManagerImpl::GetCurrentPage()
+{
+ if (mrBase.GetMainViewShell())
+ return mrBase.GetMainViewShell()->getCurrentPage();
+ return nullptr;
+}
+
+AnnotationManager::AnnotationManager( ViewShellBase& rViewShellBase )
+: mxImpl( new AnnotationManagerImpl( rViewShellBase ) )
+{
+ mxImpl->init();
+}
+
+AnnotationManager::~AnnotationManager()
+{
+ mxImpl->dispose();
+}
+
+void AnnotationManager::ExecuteAnnotation(SfxRequest const & rRequest)
+{
+ mxImpl->ExecuteAnnotation( rRequest );
+}
+
+void AnnotationManager::GetAnnotationState(SfxItemSet& rItemSet)
+{
+ mxImpl->GetAnnotationState(rItemSet);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/annotations/annotationmanagerimpl.hxx b/sd/source/ui/annotations/annotationmanagerimpl.hxx
new file mode 100644
index 000000000..c5871d90c
--- /dev/null
+++ b/sd/source/ui/annotations/annotationmanagerimpl.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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/document/XEventListener.hpp>
+
+#include <rtl/ustring.hxx>
+
+#include <comphelper/compbase.hxx>
+
+#include "annotationtag.hxx"
+
+namespace com::sun::star::drawing { class XDrawView; }
+namespace com::sun::star::office { class XAnnotationAccess; }
+namespace com::sun::star::office { class XAnnotation; }
+
+class SfxRequest;
+class SdPage;
+class SdDrawDocument;
+struct ImplSVEvent;
+
+namespace sd
+{
+
+class ViewShellBase;
+
+namespace tools {
+class EventMultiplexerEvent;
+}
+
+typedef comphelper::WeakComponentImplHelper <
+ css::document::XEventListener
+ > AnnotationManagerImplBase;
+
+class AnnotationManagerImpl : public AnnotationManagerImplBase
+{
+public:
+ explicit AnnotationManagerImpl( ViewShellBase& rViewShellBase );
+
+ void init();
+
+ // WeakComponentImplHelper
+ virtual void disposing (std::unique_lock<std::mutex>&) override;
+
+ // XEventListener
+ virtual void SAL_CALL notifyEvent( const css::document::EventObject& Event ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ void ExecuteAnnotation (SfxRequest const & rRequest);
+ void GetAnnotationState (SfxItemSet& rItemSet);
+
+ void ExecuteInsertAnnotation(SfxRequest const & rReq);
+ void ExecuteDeleteAnnotation(SfxRequest const & rReq);
+ void ExecuteEditAnnotation(SfxRequest const & rReq);
+ void ExecuteReplyToAnnotation(SfxRequest const & rReq);
+
+ void SelectNextAnnotation(bool bForward);
+
+ void SelectAnnotation( const css::uno::Reference< css::office::XAnnotation >& xAnnotation, bool bEdit = false );
+ void GetSelectedAnnotation( css::uno::Reference< css::office::XAnnotation >& xAnnotation );
+
+ void InsertAnnotation(const OUString& rText);
+ void DeleteAnnotation( const css::uno::Reference< css::office::XAnnotation >& xAnnotation );
+ void DeleteAnnotationsByAuthor( std::u16string_view sAuthor );
+ void DeleteAllAnnotations();
+
+ void ExecuteAnnotationTagContextMenu(const css::uno::Reference<css::office::XAnnotation>& xAnnotation, weld::Widget* pParent, const ::tools::Rectangle& rContextRect);
+
+ static Color GetColorDark(sal_uInt16 aAuthorIndex);
+ static Color GetColorLight(sal_uInt16 aAuthorIndex);
+ static Color GetColor(sal_uInt16 aAuthorIndex);
+
+ // callbacks
+ void onTagSelected( AnnotationTag const & rTag );
+ void onTagDeselected( AnnotationTag const & rTag );
+
+ void onSelectionChanged();
+
+ void addListener();
+ void removeListener();
+
+ void invalidateSlots();
+
+ DECL_LINK(EventMultiplexerListener, tools::EventMultiplexerEvent&, void);
+ DECL_LINK(UpdateTagsHdl, void *, void);
+
+ void UpdateTags(bool bSynchron = false);
+ void CreateTags();
+ void DisposeTags();
+
+ SdPage* GetNextPage( SdPage const * pPage, bool bForward );
+
+ SdPage* GetCurrentPage();
+
+ SdDrawDocument* GetDoc() { return mpDoc; }
+
+ void ShowAnnotations(bool bShow);
+
+private:
+ ViewShellBase& mrBase;
+ SdDrawDocument* mpDoc;
+
+ std::vector< rtl::Reference< AnnotationTag > > maTagVector;
+
+ css::uno::Reference< css::drawing::XDrawView > mxView;
+ css::uno::Reference< css::office::XAnnotationAccess > mxCurrentPage;
+ css::uno::Reference< css::office::XAnnotation > mxSelectedAnnotation;
+
+ bool mbShowAnnotations;
+ ImplSVEvent * mnUpdateTagsEvent;
+ vcl::Font maFont;
+
+ css::uno::Reference<css::office::XAnnotation> GetAnnotationById(sal_uInt32 nAnnotationId);
+};
+
+OUString getAnnotationDateTimeString( const css::uno::Reference< css::office::XAnnotation >& xAnnotation );
+
+SfxItemPool* GetAnnotationPool();
+
+css::util::DateTime getCurrentDateTime();
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/annotations/annotationtag.cxx b/sd/source/ui/annotations/annotationtag.cxx
new file mode 100644
index 000000000..cfd632dcc
--- /dev/null
+++ b/sd/source/ui/annotations/annotationtag.cxx
@@ -0,0 +1,662 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/geometry/RealPoint2D.hpp>
+#include <com/sun/star/office/XAnnotation.hpp>
+
+#include <rtl/ustrbuf.hxx>
+
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/weldutils.hxx>
+
+#include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
+#include <svx/sdr/overlay/overlaybitmapex.hxx>
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svddrgmt.hxx>
+#include <tools/debug.hxx>
+
+#include <View.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include "annotationmanagerimpl.hxx"
+#include "annotationwindow.hxx"
+#include "annotationtag.hxx"
+#include <Annotation.hxx>
+#include <ViewShell.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::office;
+using namespace ::com::sun::star::geometry;
+
+namespace sd
+{
+
+const sal_uInt32 SMART_TAG_HDL_NUM = SAL_MAX_UINT32;
+const int DRGPIX = 2; // Drag MinMove in Pixel
+
+static OUString getInitials( const OUString& rName )
+{
+ OUStringBuffer sInitials;
+
+ const sal_Unicode * pStr = rName.getStr();
+ sal_Int32 nLength = rName.getLength();
+
+ while( nLength )
+ {
+ // skip whitespace
+ while( nLength && (*pStr <= ' ') )
+ {
+ nLength--; pStr++;
+ }
+
+ // take letter
+ if( nLength )
+ {
+ sInitials.append(*pStr);
+ nLength--; pStr++;
+ }
+
+ // skip letters until whitespace
+ while( nLength && (*pStr > ' ') )
+ {
+ nLength--; pStr++;
+ }
+ }
+
+ return sInitials.makeStringAndClear();
+}
+
+namespace {
+
+class AnnotationDragMove : public SdrDragMove
+{
+public:
+ AnnotationDragMove(SdrDragView& rNewView, const rtl::Reference <AnnotationTag >& xTag);
+ virtual bool BeginSdrDrag() override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+ virtual void MoveSdrDrag(const Point& rNoSnapPnt) override;
+ virtual void CancelSdrDrag() override;
+
+private:
+ rtl::Reference <AnnotationTag > mxTag;
+ Point maOrigin;
+};
+
+}
+
+AnnotationDragMove::AnnotationDragMove(SdrDragView& rNewView, const rtl::Reference <AnnotationTag >& xTag)
+: SdrDragMove(rNewView)
+, mxTag( xTag )
+{
+}
+
+bool AnnotationDragMove::BeginSdrDrag()
+{
+ DragStat().SetRef1(GetDragHdl()->GetPos());
+ DragStat().SetShown(!DragStat().IsShown());
+
+ maOrigin = GetDragHdl()->GetPos();
+ DragStat().SetActionRect(::tools::Rectangle(maOrigin,maOrigin));
+
+ return true;
+}
+
+void AnnotationDragMove::MoveSdrDrag(const Point& rNoSnapPnt)
+{
+ Point aPnt(rNoSnapPnt);
+
+ if (DragStat().CheckMinMoved(rNoSnapPnt))
+ {
+ if (aPnt!=DragStat().GetNow())
+ {
+ Hide();
+ DragStat().NextMove(aPnt);
+ GetDragHdl()->SetPos( maOrigin + Point( DragStat().GetDX(), DragStat().GetDY() ) );
+ Show();
+ DragStat().SetActionRect(::tools::Rectangle(aPnt,aPnt));
+ }
+ }
+}
+
+bool AnnotationDragMove::EndSdrDrag(bool /*bCopy*/)
+{
+ Hide();
+ if( mxTag.is() )
+ mxTag->Move( DragStat().GetDX(), DragStat().GetDY() );
+ return true;
+}
+
+void AnnotationDragMove::CancelSdrDrag()
+{
+ Hide();
+}
+
+namespace {
+
+class AnnotationHdl : public SmartHdl
+{
+public:
+ AnnotationHdl( const SmartTagReference& xTag, const Reference< XAnnotation >& xAnnotation, const Point& rPnt );
+
+ virtual void CreateB2dIAObject() override;
+ virtual bool IsFocusHdl() const override;
+
+private:
+ Reference< XAnnotation > mxAnnotation;
+ rtl::Reference< AnnotationTag > mxTag;
+};
+
+}
+
+AnnotationHdl::AnnotationHdl( const SmartTagReference& xTag, const Reference< XAnnotation >& xAnnotation, const Point& rPnt )
+: SmartHdl( xTag, rPnt, SdrHdlKind::SmartTag )
+, mxAnnotation( xAnnotation )
+, mxTag( dynamic_cast< AnnotationTag* >( xTag.get() ) )
+{
+}
+
+void AnnotationHdl::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ if (!mxAnnotation.is())
+ return;
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ const Point aTagPos( GetPos() );
+ basegfx::B2DPoint aPosition( aTagPos.X(), aTagPos.Y() );
+
+ const bool bFocused = IsFocusHdl() && pHdlList && (pHdlList->GetFocusHdl() == this);
+
+ BitmapEx aBitmapEx( mxTag->CreateAnnotationBitmap(mxTag->isSelected()) );
+ BitmapEx aBitmapEx2;
+ if( bFocused )
+ aBitmapEx2 = mxTag->CreateAnnotationBitmap(!mxTag->isSelected() );
+
+ if(!pHdlList)
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!pView || pView->areMarkHandlesHidden())
+ return;
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b = 0; b < pPageView->PageWindowCount(); b++)
+ {
+ // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ SdrPaintWindow& rPaintWindow = rPageWindow.GetPaintWindow();
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if(rPaintWindow.OutputToWindow() && xManager.is() )
+ {
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject;
+
+ auto* pAnnotation = dynamic_cast<sd::Annotation*>(mxAnnotation.get());
+
+ if (pAnnotation && pAnnotation->hasCustomAnnotationMarker())
+ {
+ CustomAnnotationMarker& rCustomAnnotationMarker = pAnnotation->getCustomAnnotationMarker();
+
+ auto& rPolygons = rCustomAnnotationMarker.maPolygons;
+ if (!rPolygons.empty())
+ {
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ for (auto const & rPolygon : rPolygons)
+ aPolyPolygon.append(rPolygon);
+
+ pOverlayObject.reset(new sdr::overlay::OverlayPolyPolygon(
+ aPolyPolygon,
+ rCustomAnnotationMarker.maLineColor,
+ rCustomAnnotationMarker.mnLineWidth,
+ rCustomAnnotationMarker.maFillColor));
+ }
+ }
+ else
+ {
+ // animate focused handles
+ if(bFocused)
+ {
+ const sal_uInt64 nBlinkTime = rStyleSettings.GetCursorBlinkTime();
+
+ pOverlayObject.reset(new sdr::overlay::OverlayAnimatedBitmapEx(aPosition, aBitmapEx, aBitmapEx2, nBlinkTime, 0, 0, 0, 0 ));
+ }
+ else
+ {
+ pOverlayObject.reset(new sdr::overlay::OverlayBitmapEx( aPosition, aBitmapEx, 0, 0 ));
+ }
+ }
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+}
+
+bool AnnotationHdl::IsFocusHdl() const
+{
+ return true;
+}
+
+AnnotationTag::AnnotationTag( AnnotationManagerImpl& rManager, ::sd::View& rView, const Reference< XAnnotation >& xAnnotation, Color const & rColor, int nIndex, const vcl::Font& rFont )
+: SmartTag( rView )
+, mrManager( rManager )
+, mxAnnotation( xAnnotation )
+, maColor( rColor )
+, mnIndex( nIndex )
+, mrFont( rFont )
+, mpListenWindow( nullptr )
+{
+}
+
+AnnotationTag::~AnnotationTag()
+{
+ DBG_ASSERT( !mxAnnotation.is(), "sd::AnnotationTag::~AnnotationTag(), dispose me first!" );
+ Dispose();
+}
+
+/** returns true if the AnnotationTag handled the event. */
+bool AnnotationTag::MouseButtonDown( const MouseEvent& rMEvt, SmartHdl& /*rHdl*/ )
+{
+ if( !mxAnnotation.is() )
+ return false;
+
+ bool bRet = false;
+ if( !isSelected() )
+ {
+ SmartTagReference xTag( this );
+ mrView.getSmartTags().select( xTag );
+ bRet = true;
+ }
+
+ if( rMEvt.IsLeft() && !rMEvt.IsRight() )
+ {
+ vcl::Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
+ if( pWindow )
+ {
+ maMouseDownPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() );
+
+ if( mpListenWindow )
+ mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
+
+ mpListenWindow = pWindow;
+ mpListenWindow->AddEventListener( LINK(this, AnnotationTag, WindowEventHandler));
+ }
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+/** returns true if the SmartTag consumes this event. */
+bool AnnotationTag::KeyInput( const KeyEvent& rKEvt )
+{
+ if( !mxAnnotation.is() )
+ return false;
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+ switch( nCode )
+ {
+ case KEY_DELETE:
+ mrManager.DeleteAnnotation( mxAnnotation );
+ return true;
+
+ case KEY_DOWN:
+ case KEY_UP:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ return OnMove( rKEvt );
+
+ case KEY_ESCAPE:
+ {
+ SmartTagReference xThis( this );
+ mrView.getSmartTags().deselect();
+ return true;
+ }
+
+ case KEY_TAB:
+ mrManager.SelectNextAnnotation(!rKEvt.GetKeyCode().IsShift());
+ return true;
+
+ case KEY_RETURN:
+ case KEY_SPACE:
+ OpenPopup( true );
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/** returns true if the SmartTag consumes this event. */
+bool AnnotationTag::Command( const CommandEvent& rCEvt )
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+ if (vcl::Window* pWindow = mrView.GetViewShell()->GetActiveWindow())
+ {
+ ::tools::Rectangle aContextRect(rCEvt.GetMousePosPixel(),Size(1,1));
+ weld::Window* pParent = weld::GetPopupParent(*pWindow, aContextRect);
+ mrManager.ExecuteAnnotationTagContextMenu(mxAnnotation, pParent, aContextRect);
+ return true;
+ }
+ return false;
+}
+
+void AnnotationTag::Move( int nDX, int nDY )
+{
+ if( !mxAnnotation.is() )
+ return;
+
+ if( mrManager.GetDoc()->IsUndoEnabled() )
+ mrManager.GetDoc()->BegUndo( SdResId( STR_ANNOTATION_UNDO_MOVE ) );
+
+ RealPoint2D aPosition( mxAnnotation->getPosition() );
+ aPosition.X += static_cast<double>(nDX) / 100.0;
+ aPosition.Y += static_cast<double>(nDY) / 100.0;
+ mxAnnotation->setPosition( aPosition );
+
+ if( mrManager.GetDoc()->IsUndoEnabled() )
+ mrManager.GetDoc()->EndUndo();
+
+ mrView.updateHandles();
+}
+
+bool AnnotationTag::OnMove( const KeyEvent& rKEvt )
+{
+ ::tools::Long nX = 0;
+ ::tools::Long nY = 0;
+
+ switch( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_UP: nY = -1; break;
+ case KEY_DOWN: nY = 1; break;
+ case KEY_LEFT: nX = -1; break;
+ case KEY_RIGHT: nX = 1; break;
+ default: break;
+ }
+
+ if(rKEvt.GetKeyCode().IsMod2())
+ {
+ OutputDevice* pOut = mrView.GetViewShell()->GetActiveWindow()->GetOutDev();
+ Size aLogicSizeOnePixel = pOut ? pOut->PixelToLogic(Size(1,1)) : Size(100, 100);
+ nX *= aLogicSizeOnePixel.Width();
+ nY *= aLogicSizeOnePixel.Height();
+ }
+ else
+ {
+ // old, fixed move distance
+ nX *= 100;
+ nY *= 100;
+ }
+
+ if( nX || nY )
+ {
+ // move the annotation
+ Move( nX, nY );
+ }
+
+ return true;
+}
+
+void AnnotationTag::CheckPossibilities()
+{
+}
+
+sal_Int32 AnnotationTag::GetMarkablePointCount() const
+{
+ return 0;
+}
+
+sal_Int32 AnnotationTag::GetMarkedPointCount() const
+{
+ return 0;
+}
+
+bool AnnotationTag::MarkPoint(SdrHdl& /*rHdl*/, bool /*bUnmark*/ )
+{
+ return false;
+}
+
+bool AnnotationTag::MarkPoints(const ::tools::Rectangle* /*pRect*/, bool /*bUnmark*/ )
+{
+ return false;
+}
+
+bool AnnotationTag::getContext( SdrViewContext& /*rContext*/ )
+{
+ return false;
+}
+
+void AnnotationTag::addCustomHandles( SdrHdlList& rHandlerList )
+{
+ if( !mxAnnotation.is() )
+ return;
+
+ SmartTagReference xThis( this );
+ std::unique_ptr<AnnotationHdl> pHdl(new AnnotationHdl( xThis, mxAnnotation, Point() ));
+ pHdl->SetObjHdlNum( SMART_TAG_HDL_NUM );
+ pHdl->SetPageView( mrView.GetSdrPageView() );
+
+ RealPoint2D aPosition( mxAnnotation->getPosition() );
+ Point aBasePos( static_cast<::tools::Long>(aPosition.X * 100.0), static_cast<::tools::Long>(aPosition.Y * 100.0) );
+ pHdl->SetPos( aBasePos );
+
+ rHandlerList.AddHdl( std::move(pHdl) );
+}
+
+void AnnotationTag::disposing()
+{
+ if( mpListenWindow )
+ {
+ mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
+ }
+
+ mxAnnotation.clear();
+ ClosePopup();
+ SmartTag::disposing();
+}
+
+void AnnotationTag::select()
+{
+ SmartTag::select();
+
+ mrManager.onTagSelected( *this );
+
+ vcl::Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
+ if( pWindow )
+ {
+ RealPoint2D aPosition( mxAnnotation->getPosition() );
+ Point aPos( static_cast<::tools::Long>(aPosition.X * 100.0), static_cast<::tools::Long>(aPosition.Y * 100.0) );
+
+ ::tools::Rectangle aVisRect( aPos, pWindow->PixelToLogic(maSize) );
+ mrView.MakeVisible(aVisRect, *pWindow);
+ }
+}
+
+void AnnotationTag::deselect()
+{
+ SmartTag::deselect();
+
+ ClosePopup();
+
+ mrManager.onTagDeselected( *this );
+}
+
+BitmapEx AnnotationTag::CreateAnnotationBitmap( bool bSelected )
+{
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+
+ OUString sInitials(mxAnnotation->getInitials());
+ if (sInitials.isEmpty())
+ sInitials = getInitials(mxAnnotation->getAuthor());
+
+ OUString sAuthor(sInitials + " " + OUString::number(mnIndex));
+
+ pVDev->SetFont( mrFont );
+
+ const int BORDER_X = 4; // pixels
+ const int BORDER_Y = 4; // pixels
+
+ maSize = Size( pVDev->GetTextWidth( sAuthor ) + 2*BORDER_X, pVDev->GetTextHeight() + 2*BORDER_Y );
+ pVDev->SetOutputSizePixel( maSize, false );
+
+ Color aBorderColor( maColor );
+
+ if( bSelected )
+ {
+ aBorderColor.Invert();
+ }
+ else
+ {
+ if( maColor.IsDark() )
+ {
+ aBorderColor.IncreaseLuminance( 32 );
+ }
+ else
+ {
+ aBorderColor.DecreaseLuminance( 32 );
+ }
+ }
+
+ Point aPos;
+ ::tools::Rectangle aBorderRect( aPos, maSize );
+ pVDev->SetLineColor(aBorderColor);
+ pVDev->SetFillColor(maColor);
+ pVDev->DrawRect( aBorderRect );
+
+ pVDev->SetTextColor( maColor.IsDark() ? COL_WHITE : COL_BLACK );
+ pVDev->DrawText( Point( BORDER_X, BORDER_Y ), sAuthor );
+
+ return pVDev->GetBitmapEx( aPos, maSize );
+}
+
+void AnnotationTag::OpenPopup( bool bEdit )
+{
+ if( !mxAnnotation.is() )
+ return;
+
+ if( !mpAnnotationWindow )
+ {
+ OutputDevice* pOut = getView().GetFirstOutputDevice();
+ vcl::Window* pWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
+ if( pWindow )
+ {
+ RealPoint2D aPosition( mxAnnotation->getPosition() );
+ Point aPos(pWindow->LogicToPixel( Point( static_cast<::tools::Long>(aPosition.X * 100.0), static_cast<::tools::Long>(aPosition.Y * 100.0) ) ) );
+
+ aPos.AdjustX(4 ); // magic!
+ aPos.AdjustY(1 );
+
+ ::tools::Rectangle aRect( aPos, maSize );
+
+ weld::Window* pParent = weld::GetPopupParent(*pWindow, aRect);
+ mpAnnotationWindow.reset(new AnnotationWindow(pParent, aRect, mrView.GetDocSh(), mxAnnotation));
+ mpAnnotationWindow->connect_closed(LINK(this, AnnotationTag, PopupModeEndHdl));
+ }
+ }
+
+ if (bEdit && mpAnnotationWindow)
+ mpAnnotationWindow->StartEdit();
+}
+
+IMPL_LINK_NOARG(AnnotationTag, PopupModeEndHdl, weld::Popover&, void)
+{
+ ClosePopup();
+}
+
+void AnnotationTag::ClosePopup()
+{
+ if (mpAnnotationWindow)
+ {
+ mpAnnotationWindow->SaveToDocument();
+ mpAnnotationWindow.reset();
+ }
+}
+
+IMPL_LINK(AnnotationTag, WindowEventHandler, VclWindowEvent&, rEvent, void)
+{
+ vcl::Window* pWindow = rEvent.GetWindow();
+
+ if( !pWindow )
+ return;
+
+ if( pWindow != mpListenWindow )
+ return;
+
+ switch( rEvent.GetId() )
+ {
+ case VclEventId::WindowMouseButtonUp:
+ {
+ // if we stop pressing the button without a mouse move we open the popup
+ mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
+ mpListenWindow = nullptr;
+ if( !mpAnnotationWindow )
+ OpenPopup(false);
+ }
+ break;
+ case VclEventId::WindowMouseMove:
+ {
+ // if we move the mouse after a button down we want to start dragging
+ mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
+ mpListenWindow = nullptr;
+
+ SdrHdl* pHdl = mrView.PickHandle(maMouseDownPos);
+ if( pHdl )
+ {
+ mrView.BrkAction();
+ const sal_uInt16 nDrgLog = static_cast<sal_uInt16>(pWindow->PixelToLogic(Size(DRGPIX,0)).Width());
+
+ rtl::Reference< AnnotationTag > xTag( this );
+
+ SdrDragMethod* pDragMethod = new AnnotationDragMove( mrView, xTag );
+ mrView.BegDragObj(maMouseDownPos, nullptr, pHdl, nDrgLog, pDragMethod );
+ }
+ }
+ break;
+ case VclEventId::ObjectDying:
+ mpListenWindow = nullptr;
+ break;
+ default: break;
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/annotations/annotationtag.hxx b/sd/source/ui/annotations/annotationtag.hxx
new file mode 100644
index 000000000..23dcde13a
--- /dev/null
+++ b/sd/source/ui/annotations/annotationtag.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/vclevent.hxx>
+
+#include <smarttag.hxx>
+#include "annotationwindow.hxx"
+
+namespace com::sun::star::office { class XAnnotation; }
+
+namespace sd {
+
+class View;
+class AnnotationManagerImpl;
+
+class AnnotationTag final : public SmartTag
+{
+public:
+ AnnotationTag( AnnotationManagerImpl& rManager, ::sd::View& rView, const css::uno::Reference< css::office::XAnnotation >& xAnnotation, Color const & rColor, int nIndex, const vcl::Font& rFont );
+ virtual ~AnnotationTag() override;
+
+ /// @return true if the SmartTag handled the event.
+ virtual bool MouseButtonDown( const MouseEvent&, SmartHdl& ) override;
+
+ /// @return true if the SmartTag consumes this event.
+ virtual bool KeyInput( const KeyEvent& rKEvt ) override;
+
+ /// @return true if the SmartTag consumes this event.
+ virtual bool Command( const CommandEvent& rCEvt ) override;
+
+ // callbacks from sdr view
+ virtual sal_Int32 GetMarkablePointCount() const override;
+ virtual sal_Int32 GetMarkedPointCount() const override;
+ virtual bool MarkPoint(SdrHdl& rHdl, bool bUnmark) override;
+ virtual void CheckPossibilities() override;
+ virtual bool MarkPoints(const ::tools::Rectangle* pRect, bool bUnmark) override;
+
+ void Move( int nDX, int nDY );
+ bool OnMove( const KeyEvent& rKEvt );
+
+ BitmapEx CreateAnnotationBitmap(bool);
+
+ const css::uno::Reference< css::office::XAnnotation >& GetAnnotation() const { return mxAnnotation; }
+
+ void OpenPopup( bool bEdit );
+ void ClosePopup();
+
+private:
+ virtual void addCustomHandles( SdrHdlList& rHandlerList ) override;
+ virtual bool getContext( SdrViewContext& rContext ) override;
+ virtual void disposing() override;
+ virtual void select() override;
+ virtual void deselect() override;
+
+ DECL_LINK( WindowEventHandler, VclWindowEvent&, void );
+ DECL_LINK(PopupModeEndHdl, weld::Popover&, void);
+
+ AnnotationManagerImpl& mrManager;
+ css::uno::Reference< css::office::XAnnotation > mxAnnotation;
+ std::unique_ptr<AnnotationWindow> mpAnnotationWindow;
+ Color maColor;
+ int mnIndex;
+ const vcl::Font& mrFont;
+ Size maSize;
+ VclPtr<vcl::Window> mpListenWindow;
+ Point maMouseDownPos;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/annotations/annotationwindow.cxx b/sd/source/ui/annotations/annotationwindow.cxx
new file mode 100644
index 000000000..6c1210575
--- /dev/null
+++ b/sd/source/ui/annotations/annotationwindow.cxx
@@ -0,0 +1,802 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/eeitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <svx/svxids.hrc>
+#include <unotools/useroptions.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/stritem.hxx>
+
+#include <vcl/commandevent.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/vclenum.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/gradient.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/ptrstyle.hxx>
+
+#include <strings.hrc>
+#include "annotationwindow.hxx"
+#include "annotationmanagerimpl.hxx"
+
+#include <com/sun/star/office/XAnnotation.hpp>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <drawdoc.hxx>
+#include <textapi.hxx>
+#include <sdresid.hxx>
+
+#include <memory>
+
+using namespace ::sd;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::office;
+using namespace ::com::sun::star::text;
+
+#define METABUTTON_WIDTH 16
+#define METABUTTON_HEIGHT 18
+#define POSTIT_META_HEIGHT sal_Int32(30)
+
+namespace sd {
+
+void AnnotationTextWindow::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect)
+{
+ Size aSize = GetOutputSizePixel();
+
+ const bool bHighContrast = Application::GetSettings().GetStyleSettings().GetHighContrastMode();
+ if (!bHighContrast)
+ {
+ rRenderContext.DrawGradient(::tools::Rectangle(Point(0,0), rRenderContext.PixelToLogic(aSize)),
+ Gradient(GradientStyle::Linear, mrContents.maColorLight, mrContents.maColor));
+ }
+
+ DoPaint(rRenderContext, rRect);
+}
+
+void AnnotationTextWindow::EditViewScrollStateChange()
+{
+ mrContents.SetScrollbar();
+}
+
+bool AnnotationTextWindow::KeyInput(const KeyEvent& rKeyEvt)
+{
+ const vcl::KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
+ sal_uInt16 nKey = rKeyCode.GetCode();
+
+ bool bDone = false;
+
+ if ((rKeyCode.IsMod1() && rKeyCode.IsMod2()) && ((nKey == KEY_PAGEUP) || (nKey == KEY_PAGEDOWN)))
+ {
+ SfxDispatcher* pDispatcher = mrContents.DocShell()->GetViewShell()->GetViewFrame()->GetDispatcher();
+ if( pDispatcher )
+ pDispatcher->Execute( nKey == KEY_PAGEDOWN ? SID_NEXT_POSTIT : SID_PREVIOUS_POSTIT );
+ bDone = true;
+ }
+ else if (nKey == KEY_INSERT)
+ {
+ if (!rKeyCode.IsMod1() && !rKeyCode.IsMod2())
+ mrContents.ToggleInsMode();
+ bDone = true;
+ }
+ else
+ {
+ ::tools::Long aOldHeight = mrContents.GetPostItTextHeight();
+
+ /// HACK: need to switch off processing of Undo/Redo in Outliner
+ if ( !( (nKey == KEY_Z || nKey == KEY_Y) && rKeyCode.IsMod1()) )
+ {
+ bool bIsProtected = mrContents.IsProtected();
+ if (!bIsProtected || !EditEngine::DoesKeyChangeText(rKeyEvt) )
+ {
+ if (EditView* pEditView = GetEditView())
+ {
+ bDone = pEditView->PostKeyEvent(rKeyEvt);
+ if (!bDone && rKeyEvt.GetKeyCode().IsMod1() && !rKeyEvt.GetKeyCode().IsMod2())
+ {
+ if (nKey == KEY_A)
+ {
+ EditEngine* pEditEngine = GetEditEngine();
+ sal_Int32 nPar = pEditEngine->GetParagraphCount();
+ if (nPar)
+ {
+ sal_Int32 nLen = pEditEngine->GetTextLen(nPar - 1);
+ pEditView->SetSelection(ESelection(0, 0, nPar - 1, nLen));
+ }
+ bDone = true;
+ }
+ }
+ }
+ }
+ }
+ if (bDone)
+ {
+ mrContents.ResizeIfNecessary(aOldHeight, mrContents.GetPostItTextHeight());
+ }
+ }
+
+ return bDone;
+}
+
+AnnotationTextWindow::AnnotationTextWindow(AnnotationWindow& rContents)
+ : mrContents(rContents)
+{
+}
+
+EditView* AnnotationTextWindow::GetEditView() const
+{
+ OutlinerView* pOutlinerView = mrContents.GetOutlinerView();
+ if (!pOutlinerView)
+ return nullptr;
+ return &pOutlinerView->GetEditView();
+}
+
+EditEngine* AnnotationTextWindow::GetEditEngine() const
+{
+ OutlinerView* pOutlinerView = mrContents.GetOutlinerView();
+ if (!pOutlinerView)
+ return nullptr;
+ return pOutlinerView->GetEditView().GetEditEngine();
+}
+
+void AnnotationTextWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Size aSize(0, 0);
+ 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::Map100thMM));
+ rDevice.SetBackground(aBgColor);
+
+ Size aOutputSize(rDevice.PixelToLogic(aSize));
+
+ EditView* pEditView = GetEditView();
+ pEditView->setEditViewCallbacks(this);
+
+ EditEngine* pEditEngine = GetEditEngine();
+ pEditEngine->SetPaperSize(aOutputSize);
+ pEditEngine->SetRefDevice(&rDevice);
+
+ pEditView->SetOutputArea(::tools::Rectangle(Point(0, 0), aOutputSize));
+ pEditView->SetBackgroundColor(aBgColor);
+
+ pDrawingArea->set_cursor(PointerStyle::Text);
+
+ InitAccessible();
+}
+
+// see SwAnnotationWin in sw for something similar
+AnnotationWindow::AnnotationWindow(weld::Window* pParent, const ::tools::Rectangle& rRect,
+ DrawDocShell* pDocShell,
+ const Reference<XAnnotation>& xAnnotation)
+ : mxBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/annotation.ui"))
+ , mxPopover(mxBuilder->weld_popover("Annotation"))
+ , mxContainer(mxBuilder->weld_widget("container"))
+ , mpDocShell(pDocShell)
+ , mpDoc(pDocShell->GetDoc())
+ , mbReadonly(pDocShell->IsReadOnly())
+ , mbProtected(false)
+{
+ mxContainer->set_size_request(320, 240);
+ mxPopover->popup_at_rect(pParent, rRect);
+
+ InitControls();
+ setAnnotation(xAnnotation);
+ FillMenuButton();
+
+ DoResize();
+
+ mxTextControl->GrabFocus();
+}
+
+AnnotationWindow::~AnnotationWindow()
+{
+}
+
+void AnnotationWindow::InitControls()
+{
+ // window control for author and date
+ mxMeta = mxBuilder->weld_label("meta");
+ mxMeta->set_direction(AllSettings::GetLayoutRTL());
+
+ maLabelFont = Application::GetSettings().GetStyleSettings().GetLabelFont();
+ maLabelFont.SetFontHeight(8);
+
+ // we should leave this setting alone, but for this we need a better layout algo
+ // with variable meta size height
+ mxMeta->set_font(maLabelFont);
+
+ mpOutliner.reset( new ::Outliner(GetAnnotationPool(),OutlinerMode::TextObject) );
+ SdDrawDocument::SetCalcFieldValueHdl( mpOutliner.get() );
+ mpOutliner->SetUpdateLayout( true );
+
+ if (OutputDevice* pDev = mpDoc->GetRefDevice())
+ mpOutliner->SetRefDevice( pDev );
+
+ mpOutlinerView.reset( new OutlinerView ( mpOutliner.get(), nullptr) );
+ mpOutliner->InsertView(mpOutlinerView.get() );
+
+ //create Scrollbars
+ mxVScrollbar = mxBuilder->weld_scrolled_window("scrolledwindow", true);
+
+ // actual window which holds the user text
+ mxTextControl.reset(new AnnotationTextWindow(*this));
+ mxTextControlWin.reset(new weld::CustomWeld(*mxBuilder, "editview", *mxTextControl));
+ mxTextControl->SetPointer(PointerStyle::Text);
+
+ Rescale();
+ OutputDevice& rDevice = mxTextControl->GetDrawingArea()->get_ref_device();
+
+ mxVScrollbar->set_direction(false);
+ mxVScrollbar->connect_vadjustment_changed(LINK(this, AnnotationWindow, ScrollHdl));
+
+ mpOutlinerView->SetBackgroundColor(COL_TRANSPARENT);
+ mpOutlinerView->SetOutputArea(rDevice.PixelToLogic(::tools::Rectangle(0, 0, 1, 1)));
+
+ mxMenuButton = mxBuilder->weld_menu_button("menubutton");
+ if (mbReadonly)
+ mxMenuButton->hide();
+ else
+ {
+ mxMenuButton->set_size_request(METABUTTON_WIDTH, METABUTTON_HEIGHT);
+ mxMenuButton->connect_selected(LINK(this, AnnotationWindow, MenuItemSelectedHdl));
+ }
+
+ EEControlBits nCntrl = mpOutliner->GetControlWord();
+ nCntrl |= EEControlBits::PASTESPECIAL | EEControlBits::AUTOCORRECT | EEControlBits::USECHARATTRIBS | EEControlBits::NOCOLORS;
+ mpOutliner->SetControlWord(nCntrl);
+
+ mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
+ mpOutliner->EnableUndo( false );
+
+ mpOutliner->ClearModifyFlag();
+ mpOutliner->GetUndoManager().Clear();
+ mpOutliner->EnableUndo( true );
+
+ SetLanguage(SvxLanguageItem(mpDoc->GetLanguage(EE_CHAR_LANGUAGE), SID_ATTR_LANGUAGE));
+
+ mxTextControl->GrabFocus();
+}
+
+IMPL_LINK(AnnotationWindow, MenuItemSelectedHdl, const OString&, rIdent, void)
+{
+ SfxDispatcher* pDispatcher = mpDocShell->GetViewShell()->GetViewFrame()->GetDispatcher();
+ if (!pDispatcher)
+ return;
+
+ if (rIdent == ".uno:ReplyToAnnotation")
+ {
+ const SfxUnoAnyItem aItem( SID_REPLYTO_POSTIT, Any( mxAnnotation ) );
+ pDispatcher->ExecuteList(SID_REPLYTO_POSTIT,
+ SfxCallMode::ASYNCHRON, { &aItem });
+ }
+ else if (rIdent == ".uno:DeleteAnnotation")
+ {
+ const SfxUnoAnyItem aItem( SID_DELETE_POSTIT, Any( mxAnnotation ) );
+ pDispatcher->ExecuteList(SID_DELETE_POSTIT, SfxCallMode::ASYNCHRON,
+ { &aItem });
+ }
+ else if (rIdent == ".uno:DeleteAllAnnotationByAuthor")
+ {
+ const SfxStringItem aItem( SID_DELETEALLBYAUTHOR_POSTIT, mxAnnotation->getAuthor() );
+ pDispatcher->ExecuteList( SID_DELETEALLBYAUTHOR_POSTIT,
+ SfxCallMode::ASYNCHRON, { &aItem });
+ }
+ else if (rIdent == ".uno:DeleteAllAnnotation")
+ pDispatcher->Execute( SID_DELETEALL_POSTIT );
+}
+
+void AnnotationWindow::FillMenuButton()
+{
+ SvtUserOptions aUserOptions;
+ OUString sCurrentAuthor( aUserOptions.GetFullName() );
+ OUString sAuthor( mxAnnotation->getAuthor() );
+
+ OUString aStr(mxMenuButton->get_item_label(".uno:DeleteAllAnnotationByAuthor"));
+ OUString aReplace( sAuthor );
+ if( aReplace.isEmpty() )
+ aReplace = SdResId( STR_ANNOTATION_NOAUTHOR );
+ aStr = aStr.replaceFirst("%1", aReplace);
+ mxMenuButton->set_item_label(".uno:DeleteAllAnnotationByAuthor", aStr);
+
+ bool bShowReply = sAuthor != sCurrentAuthor && !mbReadonly;
+ mxMenuButton->set_item_visible(".uno:ReplyToAnnotation", bShowReply);
+ mxMenuButton->set_item_visible("separator", bShowReply);
+ mxMenuButton->set_item_visible(".uno:DeleteAnnotation", mxAnnotation.is() && !mbReadonly);
+ mxMenuButton->set_item_visible(".uno:DeleteAllAnnotationByAuthor", !mbReadonly);
+ mxMenuButton->set_item_visible(".uno:DeleteAllAnnotation", !mbReadonly);
+}
+
+void AnnotationWindow::StartEdit()
+{
+ GetOutlinerView()->SetSelection(ESelection(EE_PARA_MAX_COUNT,EE_TEXTPOS_MAX_COUNT,EE_PARA_MAX_COUNT,EE_TEXTPOS_MAX_COUNT));
+ GetOutlinerView()->ShowCursor();
+}
+
+void AnnotationWindow::SetMapMode(const MapMode& rNewMapMode)
+{
+ OutputDevice& rDevice = mxTextControl->GetDrawingArea()->get_ref_device();
+ rDevice.SetMapMode(rNewMapMode);
+}
+
+void AnnotationWindow::Rescale()
+{
+ MapMode aMode(MapUnit::Map100thMM);
+ aMode.SetOrigin( Point() );
+ mpOutliner->SetRefMapMode( aMode );
+ SetMapMode( aMode );
+
+ if (mxMeta)
+ {
+ vcl::Font aFont = maLabelFont;
+ sal_Int32 nHeight = ::tools::Long(aFont.GetFontHeight() * aMode.GetScaleY());
+ aFont.SetFontHeight( nHeight );
+ mxMeta->set_font(aFont);
+ }
+}
+
+void AnnotationWindow::DoResize()
+{
+ OutputDevice& rDevice = mxTextControl->GetDrawingArea()->get_ref_device();
+
+ ::tools::Long aHeight = mxContainer->get_preferred_size().Height();
+ ::tools::ULong aWidth = mxContainer->get_preferred_size().Width();
+
+ aHeight -= POSTIT_META_HEIGHT;
+
+ mpOutliner->SetPaperSize( rDevice.PixelToLogic( Size(aWidth, aHeight) ) ) ;
+ ::tools::Long aTextHeight = rDevice.LogicToPixel(mpOutliner->CalcTextSize()).Height();
+
+ if( aTextHeight > aHeight )
+ {
+ const int nThickness = mxVScrollbar->get_scroll_thickness();
+ if (nThickness)
+ {
+ // we need vertical scrollbars and have to reduce the width
+ aWidth -= nThickness;
+ mpOutliner->SetPaperSize(rDevice.PixelToLogic(Size(aWidth, aHeight)));
+ }
+ mxVScrollbar->set_vpolicy(VclPolicyType::ALWAYS);
+ }
+ else
+ {
+ mxVScrollbar->set_vpolicy(VclPolicyType::NEVER);
+ }
+
+ ::tools::Rectangle aOutputArea = rDevice.PixelToLogic(::tools::Rectangle(0, 0, aWidth, aHeight));
+ if (mxVScrollbar->get_vpolicy() == VclPolicyType::NEVER)
+ {
+ // if we do not have a scrollbar anymore, we want to see the complete text
+ mpOutlinerView->SetVisArea(aOutputArea);
+ }
+ mpOutlinerView->SetOutputArea(aOutputArea);
+ mpOutlinerView->ShowCursor(true, true);
+
+ int nUpper = mpOutliner->GetTextHeight();
+ int nCurrentDocPos = mpOutlinerView->GetVisArea().Top();
+ int nStepIncrement = mpOutliner->GetTextHeight() / 10;
+ int nPageIncrement = rDevice.PixelToLogic(Size(0,aHeight)).Height() * 8 / 10;
+ int nPageSize = rDevice.PixelToLogic(Size(0,aHeight)).Height();
+
+ /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has
+ effectively...
+
+ lower = gtk_adjustment_get_lower
+ upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size
+
+ and requires that upper > lower or the deceleration animation never ends
+ */
+ nPageSize = std::min(nPageSize, nUpper);
+
+ mxVScrollbar->vadjustment_configure(nCurrentDocPos, 0, nUpper,
+ nStepIncrement, nPageIncrement, nPageSize);
+}
+
+void AnnotationWindow::SetScrollbar()
+{
+ mxVScrollbar->vadjustment_set_value(mpOutlinerView->GetVisArea().Top());
+}
+
+void AnnotationWindow::ResizeIfNecessary(::tools::Long aOldHeight, ::tools::Long aNewHeight)
+{
+ if (aOldHeight != aNewHeight)
+ DoResize();
+ else
+ SetScrollbar();
+}
+
+void AnnotationWindow::SetLanguage(const SvxLanguageItem &aNewItem)
+{
+ mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
+ ESelection aOld = GetOutlinerView()->GetSelection();
+
+ ESelection aNewSelection( 0, 0, mpOutliner->GetParagraphCount()-1, EE_TEXTPOS_ALL );
+ GetOutlinerView()->SetSelection( aNewSelection );
+ SfxItemSet aEditAttr(GetOutlinerView()->GetAttribs());
+ aEditAttr.Put(aNewItem);
+ GetOutlinerView()->SetAttribs( aEditAttr );
+
+ GetOutlinerView()->SetSelection(aOld);
+
+ mxTextControl->Invalidate();
+}
+
+void AnnotationWindow::ToggleInsMode()
+{
+ if( mpOutlinerView )
+ {
+ SfxBindings &rBnd = mpDocShell->GetViewShell()->GetViewFrame()->GetBindings();
+ rBnd.Invalidate(SID_ATTR_INSERT);
+ rBnd.Update(SID_ATTR_INSERT);
+ }
+}
+
+::tools::Long AnnotationWindow::GetPostItTextHeight()
+{
+ OutputDevice& rDevice = mxTextControl->GetDrawingArea()->get_ref_device();
+ return mpOutliner ? rDevice.LogicToPixel(mpOutliner->CalcTextSize()).Height() : 0;
+}
+
+IMPL_LINK(AnnotationWindow, ScrollHdl, weld::ScrolledWindow&, rScrolledWindow, void)
+{
+ ::tools::Long nDiff = GetOutlinerView()->GetEditView().GetVisArea().Top() - rScrolledWindow.vadjustment_get_value();
+ GetOutlinerView()->Scroll( 0, nDiff );
+}
+
+TextApiObject* getTextApiObject( const Reference< XAnnotation >& xAnnotation )
+{
+ if( xAnnotation.is() )
+ {
+ Reference< XText > xText( xAnnotation->getTextRange() );
+ return TextApiObject::getImplementation( xText );
+ }
+ return nullptr;
+}
+
+void AnnotationWindow::setAnnotation( const Reference< XAnnotation >& xAnnotation )
+{
+ if( (xAnnotation == mxAnnotation) || !xAnnotation.is() )
+ return;
+
+ mxAnnotation = xAnnotation;
+
+ SetColor();
+
+ SvtUserOptions aUserOptions;
+ mbProtected = aUserOptions.GetFullName() != xAnnotation->getAuthor();
+
+ mpOutliner->Clear();
+ TextApiObject* pTextApi = getTextApiObject( mxAnnotation );
+
+ if( pTextApi )
+ {
+ std::optional< OutlinerParaObject > pOPO( pTextApi->CreateText() );
+ mpOutliner->SetText(*pOPO);
+ }
+
+ mpOutliner->ClearModifyFlag();
+ mpOutliner->GetUndoManager().Clear();
+
+//TODO Invalidate();
+
+ OUString sMeta( xAnnotation->getAuthor() );
+ OUString sDateTime( getAnnotationDateTimeString(xAnnotation) );
+
+ if( !sDateTime.isEmpty() )
+ {
+ if( !sMeta.isEmpty() )
+ sMeta += "\n";
+
+ sMeta += sDateTime;
+ }
+ mxMeta->set_label(sMeta);
+}
+
+void AnnotationWindow::SetColor()
+{
+ sal_uInt16 nAuthorIdx = mpDoc->GetAnnotationAuthorIndex( mxAnnotation->getAuthor() );
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const bool bHighContrast = rStyleSettings.GetHighContrastMode();
+ if( bHighContrast )
+ {
+ maColor = rStyleSettings.GetWindowColor();
+ maColorDark = maColor;
+ maColorLight = rStyleSettings.GetWindowTextColor();
+ }
+ else
+ {
+ maColor = AnnotationManagerImpl::GetColor( nAuthorIdx );
+ maColorDark = AnnotationManagerImpl::GetColorDark( nAuthorIdx );
+ maColorLight = AnnotationManagerImpl::GetColorLight( nAuthorIdx );
+ }
+
+ {
+ SvtAccessibilityOptions aOptions;
+ mpOutliner->ForceAutoColor( bHighContrast || aOptions.GetIsAutomaticFontColor() );
+ }
+
+ mxPopover->set_background(maColor);
+ mxMenuButton->set_background(maColor);
+
+ mxMeta->set_font_color(bHighContrast ? maColorLight : maColorDark);
+
+ mxVScrollbar->customize_scrollbars(maColorLight,
+ maColorDark,
+ maColor);
+ mxVScrollbar->set_scroll_thickness(GetPrefScrollbarWidth());
+}
+
+void AnnotationWindow::SaveToDocument()
+{
+ Reference< XAnnotation > xAnnotation( mxAnnotation );
+
+ // write changed text back to annotation
+ if (mpOutliner->IsModified())
+ {
+ TextApiObject* pTextApi = getTextApiObject( xAnnotation );
+
+ if( pTextApi )
+ {
+ std::optional<OutlinerParaObject> pOPO = mpOutliner->CreateParaObject();
+ if( pOPO )
+ {
+ if( mpDoc->IsUndoEnabled() )
+ mpDoc->BegUndo( SdResId( STR_ANNOTATION_UNDO_EDIT ) );
+
+ pTextApi->SetText( *pOPO );
+ pOPO.reset();
+
+ // set current time to changed annotation
+ xAnnotation->setDateTime( getCurrentDateTime() );
+
+ if( mpDoc->IsUndoEnabled() )
+ mpDoc->EndUndo();
+
+ mpDocShell->SetModified();
+ }
+
+ }
+ }
+ mpOutliner->ClearModifyFlag();
+
+ mpOutliner->GetUndoManager().Clear();
+}
+
+bool AnnotationTextWindow::Command(const CommandEvent& rCEvt)
+{
+ if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
+ {
+ const bool bReadOnly = mrContents.DocShell()->IsReadOnly();
+ if (bReadOnly)
+ return true;
+
+ SfxDispatcher* pDispatcher = mrContents.DocShell()->GetViewShell()->GetViewFrame()->GetDispatcher();
+ if( !pDispatcher )
+ return true;
+
+ if (IsMouseCaptured())
+ {
+ // so the menu can capture it and the EditView doesn't get the button release and change its
+ // selection on a successful button click
+ ReleaseMouse();
+ }
+
+ ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1));
+ weld::Widget* pPopupParent = GetDrawingArea();
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "modules/simpress/ui/annotationtagmenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+
+ auto xAnnotation = mrContents.getAnnotation();
+
+ SvtUserOptions aUserOptions;
+ OUString sCurrentAuthor( aUserOptions.GetFullName() );
+ OUString sAuthor( xAnnotation->getAuthor() );
+
+ OUString aStr(xMenu->get_label(".uno:DeleteAllAnnotationByAuthor"));
+ OUString aReplace( sAuthor );
+ if( aReplace.isEmpty() )
+ aReplace = SdResId( STR_ANNOTATION_NOAUTHOR );
+ aStr = aStr.replaceFirst("%1", aReplace);
+ xMenu->set_label(".uno:DeleteAllAnnotationByAuthor", aStr);
+
+ bool bShowReply = sAuthor != sCurrentAuthor && !bReadOnly;
+ xMenu->set_visible(".uno:ReplyToAnnotation", bShowReply);
+ xMenu->set_visible("separator", bShowReply);
+ xMenu->set_visible(".uno:DeleteAnnotation", xAnnotation.is() && !bReadOnly);
+ xMenu->set_visible(".uno:DeleteAllAnnotationByAuthor", !bReadOnly);
+ xMenu->set_visible(".uno:DeleteAllAnnotation", !bReadOnly);
+
+ int nInsertPos = 2;
+
+ auto xFrame = mrContents.DocShell()->GetViewShell()->GetViewFrame()->GetFrame().GetFrameInterface();
+ OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame));
+
+ bool bEditable = !mrContents.IsProtected() && !bReadOnly;
+ if (bEditable)
+ {
+ SfxItemSet aSet(mrContents.GetOutlinerView()->GetAttribs());
+
+ xMenu->insert(nInsertPos++, ".uno:Bold",
+ vcl::CommandInfoProvider::GetMenuLabelForCommand(
+ vcl::CommandInfoProvider::GetCommandProperties(".uno:Bold", aModuleName)),
+ nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Bold", xFrame),
+ TRISTATE_TRUE);
+
+ if ( aSet.GetItemState( EE_CHAR_WEIGHT ) == SfxItemState::SET )
+ {
+ if( aSet.Get( EE_CHAR_WEIGHT ).GetWeight() == WEIGHT_BOLD )
+ xMenu->set_active(".uno:Bold", true);
+ }
+
+ xMenu->insert(nInsertPos++, ".uno:Italic",
+ vcl::CommandInfoProvider::GetMenuLabelForCommand(
+ vcl::CommandInfoProvider::GetCommandProperties(".uno:Italic", aModuleName)),
+ nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Italic", xFrame),
+ TRISTATE_TRUE);
+
+ if ( aSet.GetItemState( EE_CHAR_ITALIC ) == SfxItemState::SET )
+ {
+ if( aSet.Get( EE_CHAR_ITALIC ).GetPosture() != ITALIC_NONE )
+ xMenu->set_active(".uno:Italic", true);
+
+ }
+
+ xMenu->insert(nInsertPos++, ".uno:Underline",
+ vcl::CommandInfoProvider::GetMenuLabelForCommand(
+ vcl::CommandInfoProvider::GetCommandProperties(".uno:Underline", aModuleName)),
+ nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Underline", xFrame),
+ TRISTATE_TRUE);
+
+ if ( aSet.GetItemState( EE_CHAR_UNDERLINE ) == SfxItemState::SET )
+ {
+ if( aSet.Get( EE_CHAR_UNDERLINE ).GetLineStyle() != LINESTYLE_NONE )
+ xMenu->set_active(".uno:Underline", true);
+ }
+
+ xMenu->insert(nInsertPos++, ".uno:Strikeout",
+ vcl::CommandInfoProvider::GetMenuLabelForCommand(
+ vcl::CommandInfoProvider::GetCommandProperties(".uno:Strikeout", aModuleName)),
+ nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Strikeout", xFrame),
+ TRISTATE_TRUE);
+
+ if ( aSet.GetItemState( EE_CHAR_STRIKEOUT ) == SfxItemState::SET )
+ {
+ if( aSet.Get( EE_CHAR_STRIKEOUT ).GetStrikeout() != STRIKEOUT_NONE )
+ xMenu->set_active(".uno:Strikeout", true);
+ }
+
+ xMenu->insert_separator(nInsertPos++, "separator2");
+ }
+
+ xMenu->insert(nInsertPos++, ".uno:Copy",
+ vcl::CommandInfoProvider::GetMenuLabelForCommand(
+ vcl::CommandInfoProvider::GetCommandProperties(".uno:Copy", aModuleName)),
+ nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Copy", xFrame),
+ TRISTATE_INDET);
+
+ xMenu->insert(nInsertPos++, ".uno:Paste",
+ vcl::CommandInfoProvider::GetMenuLabelForCommand(
+ vcl::CommandInfoProvider::GetCommandProperties(".uno:Paste", aModuleName)),
+ nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Paste", xFrame),
+ TRISTATE_INDET);
+
+ bool bCanPaste = false;
+ if (bEditable)
+ {
+ TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromClipboard(GetClipboard()));
+ bCanPaste = aDataHelper.GetFormatCount() != 0;
+ }
+
+ xMenu->insert_separator(nInsertPos++, "separator3");
+
+ xMenu->set_sensitive(".uno:Copy", mrContents.GetOutlinerView()->HasSelection());
+ xMenu->set_sensitive(".uno:Paste", bCanPaste);
+
+ auto sId = xMenu->popup_at_rect(pPopupParent, aRect);
+
+ if (sId == ".uno:ReplyToAnnotation")
+ {
+ const SfxUnoAnyItem aItem( SID_REPLYTO_POSTIT, Any( xAnnotation ) );
+ pDispatcher->ExecuteList(SID_REPLYTO_POSTIT,
+ SfxCallMode::ASYNCHRON, { &aItem });
+ }
+ else if (sId == ".uno:DeleteAnnotation")
+ {
+ const SfxUnoAnyItem aItem( SID_DELETE_POSTIT, Any( xAnnotation ) );
+ pDispatcher->ExecuteList(SID_DELETE_POSTIT, SfxCallMode::ASYNCHRON,
+ { &aItem });
+ }
+ else if (sId == ".uno:DeleteAllAnnotationByAuthor")
+ {
+ const SfxStringItem aItem( SID_DELETEALLBYAUTHOR_POSTIT, sAuthor );
+ pDispatcher->ExecuteList( SID_DELETEALLBYAUTHOR_POSTIT,
+ SfxCallMode::ASYNCHRON, { &aItem });
+ }
+ else if (sId == ".uno:DeleteAllAnnotation")
+ pDispatcher->Execute( SID_DELETEALL_POSTIT );
+ else if (sId == ".uno:Copy")
+ {
+ mrContents.GetOutlinerView()->Copy();
+ }
+ else if (sId == ".uno:Paste")
+ {
+ mrContents.GetOutlinerView()->PasteSpecial();
+ mrContents.DoResize();
+ }
+ else if (!sId.isEmpty())
+ {
+ SfxItemSet aEditAttr(mrContents.GetOutlinerView()->GetAttribs());
+ SfxItemSet aNewAttr(mrContents.GetOutliner()->GetEmptyItemSet());
+
+ if (sId == ".uno:Bold")
+ {
+ FontWeight eFW = aEditAttr.Get( EE_CHAR_WEIGHT ).GetWeight();
+ aNewAttr.Put( SvxWeightItem( eFW == WEIGHT_NORMAL ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
+ }
+ else if (sId == ".uno:Italic")
+ {
+ FontItalic eFI = aEditAttr.Get( EE_CHAR_ITALIC ).GetPosture();
+ aNewAttr.Put( SvxPostureItem( eFI == ITALIC_NORMAL ? ITALIC_NONE : ITALIC_NORMAL, EE_CHAR_ITALIC ) );
+ }
+ else if (sId == ".uno:Underline")
+ {
+ FontLineStyle eFU = aEditAttr. Get( EE_CHAR_UNDERLINE ).GetLineStyle();
+ aNewAttr.Put( SvxUnderlineItem( eFU == LINESTYLE_SINGLE ? LINESTYLE_NONE : LINESTYLE_SINGLE, EE_CHAR_UNDERLINE ) );
+ }
+ else if (sId == ".uno:Strikeout")
+ {
+ FontStrikeout eFSO = aEditAttr.Get( EE_CHAR_STRIKEOUT ).GetStrikeout();
+ aNewAttr.Put( SvxCrossedOutItem( eFSO == STRIKEOUT_SINGLE ? STRIKEOUT_NONE : STRIKEOUT_SINGLE, EE_CHAR_STRIKEOUT ) );
+ }
+
+ mrContents.GetOutlinerView()->SetAttribs( aNewAttr );
+ }
+
+ return true;
+ }
+ return WeldEditView::Command(rCEvt);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/annotations/annotationwindow.hxx b/sd/source/ui/annotations/annotationwindow.hxx
new file mode 100644
index 000000000..558cc6165
--- /dev/null
+++ b/sd/source/ui/annotations/annotationwindow.hxx
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <tools/long.hxx>
+#include <svx/weldeditview.hxx>
+
+namespace com::sun::star::office { class XAnnotation; }
+
+class OutlinerView;
+class Outliner;
+class SvxLanguageItem;
+class SdDrawDocument;
+
+namespace sd {
+
+class AnnotationManagerImpl;
+class DrawDocShell;
+class TextApiObject;
+
+class AnnotationWindow;
+
+class AnnotationTextWindow : public WeldEditView
+{
+private:
+ AnnotationWindow& mrContents;
+
+public:
+ AnnotationTextWindow(AnnotationWindow& rContents);
+
+ virtual EditView* GetEditView() const override;
+
+ virtual EditEngine* GetEditEngine() const override;
+
+ virtual void EditViewScrollStateChange() override;
+
+ void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+ virtual void Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect) override;
+ virtual bool KeyInput(const KeyEvent& rKeyEvt) override;
+ virtual bool Command(const CommandEvent& rCEvt) override;
+};
+
+class AnnotationWindow final
+{
+private:
+ std::unique_ptr<weld::Builder> mxBuilder;
+ std::unique_ptr<weld::Popover> mxPopover;
+ std::unique_ptr<weld::Widget> mxContainer;
+
+ DrawDocShell* mpDocShell;
+ SdDrawDocument* mpDoc;
+
+ bool mbReadonly;
+ bool mbProtected;
+
+ css::uno::Reference< css::office::XAnnotation > mxAnnotation;
+
+public:
+ Color maColor;
+ Color maColorDark;
+ Color maColorLight;
+
+private:
+ vcl::Font maLabelFont;
+
+ std::unique_ptr<OutlinerView> mpOutlinerView;
+ std::unique_ptr<::Outliner> mpOutliner;
+
+ std::unique_ptr<weld::ScrolledWindow> mxVScrollbar;
+ std::unique_ptr<WeldEditView> mxTextControl;
+ std::unique_ptr<weld::CustomWeld> mxTextControlWin;
+ std::unique_ptr<weld::Label> mxMeta;
+ std::unique_ptr<weld::MenuButton> mxMenuButton;
+
+ DECL_LINK(ScrollHdl, weld::ScrolledWindow&, void);
+ DECL_LINK(MenuItemSelectedHdl, const OString&, void);
+
+ void FillMenuButton();
+ void InitControls();
+
+ void SetMapMode(const MapMode& rNewMapMode);
+ void setAnnotation(const css::uno::Reference<css::office::XAnnotation>& xAnnotation);
+
+ static sal_Int32 GetPrefScrollbarWidth() { return 16; }
+public:
+ AnnotationWindow(weld::Window* pParent, const ::tools::Rectangle& rRect, DrawDocShell* pDocShell,
+ const css::uno::Reference<css::office::XAnnotation>& xAnnotation);
+
+ void connect_closed(const Link<weld::Popover&, void>& rLink) { mxPopover->connect_closed(rLink); }
+
+ void DoResize();
+ void ResizeIfNecessary(::tools::Long aOldHeight, ::tools::Long aNewHeight);
+ void SetScrollbar();
+ void StartEdit();
+
+ const css::uno::Reference<css::office::XAnnotation>& getAnnotation() const { return mxAnnotation; }
+
+ void SaveToDocument();
+
+ ::tools::Long GetPostItTextHeight();
+
+ DrawDocShell* DocShell() { return mpDocShell; }
+
+ void SetLanguage(const SvxLanguageItem &aNewItem);
+
+ void Rescale();
+
+ void ToggleInsMode();
+
+ bool IsProtected() const { return mbProtected; }
+
+ OutlinerView* GetOutlinerView() { return mpOutlinerView.get();}
+ ::Outliner* GetOutliner() { return mpOutliner.get();}
+ ~AnnotationWindow();
+
+ void SetColor();
+};
+
+TextApiObject* getTextApiObject( const css::uno::Reference< css::office::XAnnotation >& xAnnotation );
+
+
+} // namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/app/optsitem.cxx b/sd/source/ui/app/optsitem.cxx
new file mode 100644
index 000000000..5baff32e2
--- /dev/null
+++ b/sd/source/ui/app/optsitem.cxx
@@ -0,0 +1,1407 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svxids.hrc>
+#include <tools/debug.hxx>
+#include <tools/helpers.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <osl/diagnose.h>
+
+#include <optsitem.hxx>
+#include <FrameView.hxx>
+#include <sdattr.hrc>
+
+using namespace ::utl;
+using namespace ::com::sun::star::uno;
+
+template< class T > static T getSafeValue( const Any& rAny )
+{
+ T value = T();
+ bool bOk = (rAny >>= value);
+
+ DBG_ASSERT( bOk, "SdOptionsItem, wrong type from configuration!" );
+
+ return value;
+}
+
+
+SdOptionsItem::SdOptionsItem( const SdOptionsGeneric& rParent, const OUString& rSubTree ) :
+ ConfigItem ( rSubTree ),
+ mrParent ( rParent )
+{
+}
+
+SdOptionsItem::~SdOptionsItem()
+{
+}
+
+void SdOptionsItem::ImplCommit()
+{
+ if( IsModified() )
+ mrParent.Commit( *this );
+};
+
+void SdOptionsItem::Notify( const css::uno::Sequence<OUString>& )
+{}
+
+Sequence< Any > SdOptionsItem::GetProperties( const Sequence< OUString >& rNames )
+{
+ return ConfigItem::GetProperties( rNames );
+}
+
+bool SdOptionsItem::PutProperties( const Sequence< OUString >& rNames, const Sequence< Any>& rValues )
+{
+ return ConfigItem::PutProperties( rNames, rValues );
+}
+
+SdOptionsGeneric::SdOptionsGeneric(bool bImpress, const OUString& rSubTree)
+ : maSubTree(rSubTree)
+ , mbImpress(bImpress)
+ , mbInit(rSubTree.isEmpty())
+ , mbEnableModify(false)
+{
+}
+
+SdOptionsGeneric::SdOptionsGeneric(SdOptionsGeneric const & rSource)
+{
+ operator=(rSource);
+}
+
+SdOptionsGeneric& SdOptionsGeneric::operator=(SdOptionsGeneric const & rSource)
+{
+ if (this != &rSource)
+ {
+ maSubTree = rSource.maSubTree;
+ mpCfgItem.reset(rSource.mpCfgItem ? new SdOptionsItem(*rSource.mpCfgItem) : nullptr );
+ mbImpress = rSource.mbImpress;
+ mbInit = rSource.mbInit;
+ mbEnableModify = rSource.mbEnableModify;
+ }
+ return *this;
+}
+
+void SdOptionsGeneric::Init() const
+{
+ if( mbInit )
+ return;
+
+ SdOptionsGeneric* pThis = const_cast<SdOptionsGeneric*>(this);
+
+ if( !mpCfgItem )
+ pThis->mpCfgItem.reset( new SdOptionsItem( *this, maSubTree ) );
+ assert(mpCfgItem && "mpCfgItem is set by now");
+
+ const Sequence< OUString > aNames( GetPropertyNames() );
+ const Sequence< Any > aValues = mpCfgItem->GetProperties( aNames );
+
+ if( aNames.hasElements() && ( aValues.getLength() == aNames.getLength() ) )
+ {
+ const Any* pValues = aValues.getConstArray();
+
+ pThis->EnableModify( false );
+ pThis->mbInit = pThis->ReadData( pValues );
+ pThis->EnableModify( true );
+ }
+ else
+ pThis->mbInit = true;
+}
+
+SdOptionsGeneric::~SdOptionsGeneric()
+{
+}
+
+void SdOptionsGeneric::Commit( SdOptionsItem& rCfgItem ) const
+{
+ const Sequence< OUString > aNames( GetPropertyNames() );
+ Sequence< Any > aValues( aNames.getLength() );
+
+ if( aNames.hasElements() )
+ {
+ if( WriteData( aValues.getArray() ) )
+ rCfgItem.PutProperties( aNames, aValues );
+ else
+ {
+ OSL_FAIL( "PutProperties failed" );
+ }
+ }
+}
+
+Sequence< OUString > SdOptionsGeneric::GetPropertyNames() const
+{
+ sal_uLong nCount;
+ const char** ppPropNames;
+
+ GetPropNameArray( ppPropNames, nCount );
+
+ Sequence< OUString > aNames( nCount );
+ OUString* pNames = aNames.getArray();
+
+ for( sal_uLong i = 0; i < nCount; i++ )
+ pNames[ i ] = OUString::createFromAscii( ppPropNames[ i ] );
+
+ return aNames;
+}
+
+void SdOptionsGeneric::Store()
+{
+ if( mpCfgItem )
+ mpCfgItem->Commit();
+}
+
+bool SdOptionsGeneric::isMetricSystem()
+{
+ SvtSysLocale aSysLocale;
+ MeasurementSystem eSys = aSysLocale.GetLocaleData().getMeasurementSystemEnum();
+
+ return ( eSys == MeasurementSystem::Metric );
+}
+
+/*************************************************************************
+|*
+|* SdOptionsLayout
+|*
+\************************************************************************/
+
+SdOptionsLayout::SdOptionsLayout(bool bImpress, bool bUseConfig) :
+ SdOptionsGeneric( bImpress, bUseConfig ?
+ ( bImpress ?
+ OUString( "Office.Impress/Layout" ) :
+ OUString( "Office.Draw/Layout" ) ) :
+ OUString() ),
+ bRuler( true ),
+ bMoveOutline( true ),
+ bDragStripes( false ),
+ bHandlesBezier( false ),
+ bHelplines( true ),
+ nMetric(static_cast<sal_uInt16>(isMetricSystem() ? FieldUnit::CM : FieldUnit::INCH)),
+ nDefTab( 1250 )
+{
+ EnableModify( true );
+}
+
+bool SdOptionsLayout::operator==( const SdOptionsLayout& rOpt ) const
+{
+ return( IsRulerVisible() == rOpt.IsRulerVisible() &&
+ IsMoveOutline() == rOpt.IsMoveOutline() &&
+ IsDragStripes() == rOpt.IsDragStripes() &&
+ IsHandlesBezier() == rOpt.IsHandlesBezier() &&
+ IsHelplines() == rOpt.IsHelplines() &&
+ GetMetric() == rOpt.GetMetric() &&
+ GetDefTab() == rOpt.GetDefTab() );
+}
+
+void SdOptionsLayout::GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const
+{
+ if( isMetricSystem() )
+ {
+ static const char* aPropNamesMetric[] =
+ {
+ "Display/Ruler",
+ "Display/Bezier",
+ "Display/Contour",
+ "Display/Guide",
+ "Display/Helpline",
+ "Other/MeasureUnit/Metric",
+ "Other/TabStop/Metric"
+ };
+ ppNames = aPropNamesMetric;
+ rCount = SAL_N_ELEMENTS(aPropNamesMetric);
+ }
+ else
+ {
+ static const char* aPropNamesNonMetric[] =
+ {
+ "Display/Ruler",
+ "Display/Bezier",
+ "Display/Contour",
+ "Display/Guide",
+ "Display/Helpline",
+ "Other/MeasureUnit/NonMetric",
+ "Other/TabStop/NonMetric"
+ };
+ ppNames = aPropNamesNonMetric;
+ rCount = SAL_N_ELEMENTS(aPropNamesNonMetric);
+ }
+}
+
+bool SdOptionsLayout::ReadData( const Any* pValues )
+{
+ if( pValues[0].hasValue() ) SetRulerVisible( *o3tl::doAccess<bool>(pValues[ 0 ]) );
+ if( pValues[1].hasValue() ) SetHandlesBezier( *o3tl::doAccess<bool>(pValues[ 1 ]) );
+ if( pValues[2].hasValue() ) SetMoveOutline( *o3tl::doAccess<bool>(pValues[ 2 ]) );
+ if( pValues[3].hasValue() ) SetDragStripes( *o3tl::doAccess<bool>(pValues[ 3 ]) );
+ if( pValues[4].hasValue() ) SetHelplines( *o3tl::doAccess<bool>(pValues[ 4 ]) );
+ if( pValues[5].hasValue() ) SetMetric( static_cast<sal_uInt16>(*o3tl::doAccess<sal_Int32>(pValues[ 5 ])) );
+ if( pValues[6].hasValue() ) SetDefTab( static_cast<sal_uInt16>(*o3tl::doAccess<sal_Int32>(pValues[ 6 ])) );
+
+ return true;
+}
+
+bool SdOptionsLayout::WriteData( Any* pValues ) const
+{
+ pValues[ 0 ] <<= IsRulerVisible();
+ pValues[ 1 ] <<= IsHandlesBezier();
+ pValues[ 2 ] <<= IsMoveOutline();
+ pValues[ 3 ] <<= IsDragStripes();
+ pValues[ 4 ] <<= IsHelplines();
+ pValues[ 5 ] <<= static_cast<sal_Int32>(GetMetric());
+ pValues[ 6 ] <<= static_cast<sal_Int32>(GetDefTab());
+
+ return true;
+}
+
+/*************************************************************************
+|*
+|* SdOptionsLayoutItem
+|*
+\************************************************************************/
+
+SdOptionsLayoutItem::SdOptionsLayoutItem()
+: SfxPoolItem ( ATTR_OPTIONS_LAYOUT )
+, maOptionsLayout ( false, false )
+{
+}
+
+SdOptionsLayoutItem::SdOptionsLayoutItem( SdOptions const * pOpts, ::sd::FrameView const * pView )
+: SfxPoolItem ( ATTR_OPTIONS_LAYOUT )
+, maOptionsLayout ( false, false )
+{
+ if( pOpts )
+ {
+ maOptionsLayout.SetMetric( pOpts->GetMetric() );
+ maOptionsLayout.SetDefTab( pOpts->GetDefTab() );
+ }
+
+ if( pView )
+ {
+ maOptionsLayout.SetRulerVisible( pView->HasRuler() );
+ maOptionsLayout.SetMoveOutline( !pView->IsNoDragXorPolys() );
+ maOptionsLayout.SetDragStripes( pView->IsDragStripes() );
+ maOptionsLayout.SetHandlesBezier( pView->IsPlusHandlesAlwaysVisible() );
+ maOptionsLayout.SetHelplines( pView->IsHlplVisible() );
+ }
+ else if( pOpts )
+ {
+ maOptionsLayout.SetRulerVisible( pOpts->IsRulerVisible() );
+ maOptionsLayout.SetMoveOutline( pOpts->IsMoveOutline() );
+ maOptionsLayout.SetDragStripes( pOpts->IsDragStripes() );
+ maOptionsLayout.SetHandlesBezier( pOpts->IsHandlesBezier() );
+ maOptionsLayout.SetHelplines( pOpts->IsHelplines() );
+ }
+}
+
+SdOptionsLayoutItem* SdOptionsLayoutItem::Clone( SfxItemPool* ) const
+{
+ return new SdOptionsLayoutItem( *this );
+}
+
+bool SdOptionsLayoutItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+ return maOptionsLayout == static_cast<const SdOptionsLayoutItem&>(rAttr).maOptionsLayout;
+}
+
+void SdOptionsLayoutItem::SetOptions( SdOptions* pOpts ) const
+{
+ if( pOpts )
+ {
+ pOpts->SetRulerVisible( maOptionsLayout.IsRulerVisible() );
+ pOpts->SetMoveOutline( maOptionsLayout.IsMoveOutline() );
+ pOpts->SetDragStripes( maOptionsLayout.IsDragStripes() );
+ pOpts->SetHandlesBezier( maOptionsLayout.IsHandlesBezier() );
+ pOpts->SetHelplines( maOptionsLayout.IsHelplines() );
+ pOpts->SetMetric( maOptionsLayout.GetMetric() );
+ pOpts->SetDefTab( maOptionsLayout.GetDefTab() );
+ }
+}
+
+/*************************************************************************
+|*
+|* SdOptionsContents
+|*
+\************************************************************************/
+
+SdOptionsContents::SdOptionsContents(bool bImpress) :
+ SdOptionsGeneric( bImpress, bImpress ?
+ OUString( "Office.Impress/Content" ) :
+ OUString( "Office.Draw/Content" ) )
+{
+ EnableModify( true );
+}
+
+bool SdOptionsContents::operator==(const SdOptionsContents&) const
+{
+ return true;
+}
+
+void SdOptionsContents::GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const
+{
+ static const char* aPropNames[] =
+ {
+ "Display/PicturePlaceholder",
+ "Display/ContourMode",
+ "Display/LineContour",
+ "Display/TextPlaceholder"
+ };
+
+ rCount = SAL_N_ELEMENTS(aPropNames);
+ ppNames = aPropNames;
+}
+
+bool SdOptionsContents::ReadData(const Any*)
+{
+ return true;
+}
+
+bool SdOptionsContents::WriteData( Any* pValues ) const
+{
+ //#i80528# no draft anymore
+ pValues[ 0 ] <<= false;
+ pValues[ 1 ] <<= false;
+ pValues[ 2 ] <<= false;
+ pValues[ 3 ] <<= false;
+
+ return true;
+}
+/*************************************************************************
+|*
+|* SdOptionsMisc
+|*
+\************************************************************************/
+
+SdOptionsMisc::SdOptionsMisc( bool bImpress, bool bUseConfig ) :
+ SdOptionsGeneric( bImpress, bUseConfig ?
+ ( bImpress ?
+ OUString( "Office.Impress/Misc" ) :
+ OUString( "Office.Draw/Misc" ) ) :
+ OUString() ),
+ nDefaultObjectSizeWidth(8000),
+ nDefaultObjectSizeHeight(5000),
+ bStartWithTemplate( false ),
+ bMarkedHitMovesAlways( true ),
+ bMoveOnlyDragging( false ),
+ bCrookNoContortion( false ),
+ bQuickEdit( IsImpress() ),
+ bMasterPageCache( true ),
+ bDragWithCopy( false ),
+ bPickThrough( true ),
+ bDoubleClickTextEdit( true ),
+ bClickChangeRotation( false ),
+ bEnableSdremote( false ),
+ bEnablePresenterScreen( true),
+ bSolidDragging( true ),
+ bSummationOfParagraphs( false ),
+ bTabBarVisible( true ),
+ bShowUndoDeleteWarning( true ),
+ bSlideshowRespectZOrder( true ),
+ bShowComments( true ),
+ bPreviewNewEffects( true ),
+ bPreviewChangedEffects( false ),
+ bPreviewTransitions( true ),
+ mnDisplay( 0 ),
+ mnPenColor( 0xff0000 ),
+ mnPenWidth( 150.0 ),
+
+ // The default for 6.1-and-above documents is to use printer-independent
+ // formatting.
+ mnPrinterIndependentLayout (1)
+{
+ EnableModify( true );
+}
+
+bool SdOptionsMisc::operator==( const SdOptionsMisc& rOpt ) const
+{
+ return( IsStartWithTemplate() == rOpt.IsStartWithTemplate() &&
+ IsMarkedHitMovesAlways() == rOpt.IsMarkedHitMovesAlways() &&
+ IsMoveOnlyDragging() == rOpt.IsMoveOnlyDragging() &&
+ IsCrookNoContortion() == rOpt.IsCrookNoContortion() &&
+ IsQuickEdit() == rOpt.IsQuickEdit() &&
+ IsMasterPagePaintCaching() == rOpt.IsMasterPagePaintCaching() &&
+ IsDragWithCopy() == rOpt.IsDragWithCopy() &&
+ IsPickThrough() == rOpt.IsPickThrough() &&
+ IsDoubleClickTextEdit() == rOpt.IsDoubleClickTextEdit() &&
+ IsClickChangeRotation() == rOpt.IsClickChangeRotation() &&
+ IsEnableSdremote() == rOpt.IsEnableSdremote() &&
+ IsEnablePresenterScreen() == rOpt.IsEnablePresenterScreen()&&
+ IsSummationOfParagraphs() == rOpt.IsSummationOfParagraphs() &&
+ IsTabBarVisible() == rOpt.IsTabBarVisible() &&
+ IsSolidDragging() == rOpt.IsSolidDragging() &&
+ IsShowUndoDeleteWarning() == rOpt.IsShowUndoDeleteWarning() &&
+ IsSlideshowRespectZOrder() == rOpt.IsSlideshowRespectZOrder() &&
+ GetPrinterIndependentLayout() == rOpt.GetPrinterIndependentLayout() &&
+ GetDefaultObjectSizeWidth() == rOpt.GetDefaultObjectSizeWidth() &&
+ GetDefaultObjectSizeHeight() == rOpt.GetDefaultObjectSizeHeight() &&
+
+ IsPreviewNewEffects() == rOpt.IsPreviewNewEffects() &&
+ IsPreviewChangedEffects() == rOpt.IsPreviewChangedEffects() &&
+ IsPreviewTransitions() == rOpt.IsPreviewTransitions() &&
+ GetDisplay() == rOpt.GetDisplay() &&
+ IsShowComments() == rOpt.IsShowComments() &&
+ GetPresentationPenColor() == rOpt.GetPresentationPenColor() &&
+ GetPresentationPenWidth() == rOpt.GetPresentationPenWidth()
+ );
+}
+
+void SdOptionsMisc::GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const
+{
+ static const char* aPropNames[] =
+ {
+ "ObjectMoveable",
+ "NoDistort",
+ "TextObject/QuickEditing",
+ "BackgroundCache",
+ "CopyWhileMoving",
+ "TextObject/Selectable",
+ "DclickTextedit",
+ "RotateClick",
+ "Preview",
+ "ModifyWithAttributes",
+ "DefaultObjectSize/Width",
+ "DefaultObjectSize/Height",
+
+ "Compatibility/PrinterIndependentLayout",
+
+ "ShowComments",
+
+ // just for impress
+ "NewDoc/AutoPilot",
+ "Compatibility/AddBetween",
+ "ShowUndoDeleteWarning",
+ "SlideshowRespectZOrder",
+
+ "PreviewNewEffects",
+ "PreviewChangedEffects",
+ "PreviewTransitions",
+
+ "Display",
+
+ "PenColor",
+ "PenWidth",
+ "Start/EnableSdremote",
+ "Start/EnablePresenterScreen",
+ "TabBarVisible"
+ };
+
+ rCount = ( IsImpress() ? SAL_N_ELEMENTS(aPropNames) : 14 );
+ ppNames = aPropNames;
+}
+
+bool SdOptionsMisc::ReadData( const Any* pValues )
+{
+ if( pValues[0].hasValue() ) SetMarkedHitMovesAlways( *o3tl::doAccess<bool>(pValues[ 0 ]) );
+ if( pValues[1].hasValue() ) SetCrookNoContortion( *o3tl::doAccess<bool>(pValues[ 1 ]) );
+ if( pValues[2].hasValue() ) SetQuickEdit( *o3tl::doAccess<bool>(pValues[ 2 ]) );
+ if( pValues[3].hasValue() ) SetMasterPagePaintCaching( *o3tl::doAccess<bool>(pValues[ 3 ]) );
+ if( pValues[4].hasValue() ) SetDragWithCopy( *o3tl::doAccess<bool>(pValues[ 4 ]) );
+ if( pValues[5].hasValue() ) SetPickThrough( *o3tl::doAccess<bool>(pValues[ 5 ]) );
+ if( pValues[6].hasValue() ) SetDoubleClickTextEdit( *o3tl::doAccess<bool>(pValues[ 6 ]) );
+ if( pValues[7].hasValue() ) SetClickChangeRotation( *o3tl::doAccess<bool>(pValues[ 7 ]) );
+ if( pValues[9].hasValue() ) SetSolidDragging( *o3tl::doAccess<bool>(pValues[ 9 ]) );
+ if( pValues[10].hasValue() ) SetDefaultObjectSizeWidth( *o3tl::doAccess<sal_Int32>(pValues[ 10 ]) );
+ if( pValues[11].hasValue() ) SetDefaultObjectSizeHeight( *o3tl::doAccess<sal_Int32>(pValues[ 11 ]) );
+ if( pValues[12].hasValue() ) SetPrinterIndependentLayout( *o3tl::doAccess<sal_uInt16>(pValues[ 12 ]) );
+
+ if( pValues[13].hasValue() )
+ SetShowComments( *o3tl::doAccess<bool>(pValues[ 13 ]) );
+
+ // just for Impress
+ if (IsImpress())
+ {
+ if( pValues[14].hasValue() )
+ SetStartWithTemplate( *o3tl::doAccess<bool>(pValues[ 14 ]) );
+ if( pValues[15].hasValue() )
+ SetSummationOfParagraphs( *o3tl::doAccess<bool>(pValues[ 15 ]) );
+ if( pValues[16].hasValue() )
+ SetShowUndoDeleteWarning( *o3tl::doAccess<bool>(pValues[ 16 ]) );
+
+ if( pValues[17].hasValue() )
+ SetSlideshowRespectZOrder(*o3tl::doAccess<bool>(pValues[ 17 ]));
+
+ if( pValues[18].hasValue() )
+ SetPreviewNewEffects(*o3tl::doAccess<bool>(pValues[ 18 ]));
+
+ if( pValues[19].hasValue() )
+ SetPreviewChangedEffects(*o3tl::doAccess<bool>(pValues[ 19 ]));
+
+ if( pValues[20].hasValue() )
+ SetPreviewTransitions(*o3tl::doAccess<bool>(pValues[ 20 ]));
+
+ if( pValues[21].hasValue() )
+ SetDisplay(*o3tl::doAccess<sal_Int32>(pValues[ 21 ]));
+
+ if( pValues[22].hasValue() )
+ SetPresentationPenColor( getSafeValue< sal_Int32 >( pValues[ 22 ] ) );
+
+ if( pValues[23].hasValue() )
+ SetPresentationPenWidth( getSafeValue< double >( pValues[ 23 ] ) );
+
+ if( pValues[24].hasValue() )
+ SetEnableSdremote( *o3tl::doAccess<bool>(pValues[ 24 ]) );
+
+ if( pValues[25].hasValue() )
+ SetEnablePresenterScreen( *o3tl::doAccess<bool>(pValues[ 25 ]) );
+
+ if( pValues[26].hasValue() ) {
+ SetTabBarVisible( *o3tl::doAccess<bool>(pValues[ 26 ]) );
+ }
+ }
+
+ return true;
+}
+
+bool SdOptionsMisc::WriteData( Any* pValues ) const
+{
+ pValues[ 0 ] <<= IsMarkedHitMovesAlways();
+ pValues[ 1 ] <<= IsCrookNoContortion();
+ pValues[ 2 ] <<= IsQuickEdit();
+ pValues[ 3 ] <<= IsMasterPagePaintCaching();
+ pValues[ 4 ] <<= IsDragWithCopy();
+ pValues[ 5 ] <<= IsPickThrough();
+ pValues[ 6 ] <<= IsDoubleClickTextEdit();
+ pValues[ 7 ] <<= IsClickChangeRotation();
+ // The preview is not supported anymore. Use a dummy value.
+ pValues[ 8 ] <<= double(0);// GetPreviewQuality();
+ pValues[ 9 ] <<= IsSolidDragging();
+ pValues[ 10 ] <<= GetDefaultObjectSizeWidth();
+ pValues[ 11 ] <<= GetDefaultObjectSizeHeight();
+ pValues[ 12 ] <<= GetPrinterIndependentLayout();
+ pValues[ 13 ] <<= IsShowComments();
+
+ // just for Impress
+ if (IsImpress())
+ {
+ pValues[ 14 ] <<= IsStartWithTemplate();
+ pValues[ 15 ] <<= IsSummationOfParagraphs();
+ pValues[ 16 ] <<= IsShowUndoDeleteWarning();
+ pValues[ 17 ] <<= IsSlideshowRespectZOrder();
+
+ pValues[ 18 ] <<= IsPreviewNewEffects();
+ pValues[ 19 ] <<= IsPreviewChangedEffects();
+ pValues[ 20 ] <<= IsPreviewTransitions();
+
+ pValues[ 21 ] <<= GetDisplay();
+
+ pValues[ 22 ] <<= GetPresentationPenColor();
+ pValues[ 23 ] <<= GetPresentationPenWidth();
+ pValues[ 24 ] <<= IsEnableSdremote();
+ pValues[ 25 ] <<= IsEnablePresenterScreen();
+ pValues[ 26 ] <<= IsTabBarVisible();
+ }
+
+ return true;
+}
+
+/*************************************************************************
+|*
+|* SdOptionsMiscItem
+|*
+\************************************************************************/
+
+SdOptionsMiscItem::SdOptionsMiscItem()
+: SfxPoolItem ( ATTR_OPTIONS_MISC )
+, maOptionsMisc ( false, false )
+{
+}
+
+SdOptionsMiscItem::SdOptionsMiscItem( SdOptions const * pOpts, ::sd::FrameView const * pView )
+: SfxPoolItem ( ATTR_OPTIONS_MISC )
+, maOptionsMisc ( false, false )
+{
+ if( pOpts )
+ {
+ maOptionsMisc.SetStartWithTemplate( pOpts->IsStartWithTemplate() );
+ maOptionsMisc.SetEnableSdremote( pOpts->IsEnableSdremote() );
+ maOptionsMisc.SetEnablePresenterScreen( pOpts->IsEnablePresenterScreen() );
+ maOptionsMisc.SetSummationOfParagraphs( pOpts->IsSummationOfParagraphs() );
+ maOptionsMisc.SetTabBarVisible( pOpts->IsTabBarVisible() );
+ maOptionsMisc.SetShowUndoDeleteWarning( pOpts->IsShowUndoDeleteWarning() );
+ maOptionsMisc.SetPrinterIndependentLayout( pOpts->GetPrinterIndependentLayout() );
+ maOptionsMisc.SetDefaultObjectSizeWidth( pOpts->GetDefaultObjectSizeWidth() );
+ maOptionsMisc.SetDefaultObjectSizeHeight( pOpts->GetDefaultObjectSizeHeight() );
+
+ maOptionsMisc.SetPreviewNewEffects(pOpts->IsPreviewNewEffects());
+ maOptionsMisc.SetPreviewChangedEffects(pOpts->IsPreviewChangedEffects());
+ maOptionsMisc.SetPreviewTransitions(pOpts->IsPreviewTransitions());
+
+ maOptionsMisc.SetDisplay(pOpts->GetDisplay());
+ maOptionsMisc.SetShowComments( pOpts->IsShowComments() );
+
+ maOptionsMisc.SetPresentationPenColor(pOpts->GetPresentationPenColor() );
+ maOptionsMisc.SetPresentationPenWidth(pOpts->GetPresentationPenWidth() );
+ }
+
+ if( pView )
+ {
+ maOptionsMisc.SetMarkedHitMovesAlways( pView->IsMarkedHitMovesAlways() );
+ maOptionsMisc.SetMoveOnlyDragging( pView->IsMoveOnlyDragging() );
+ maOptionsMisc.SetCrookNoContortion( pView->IsCrookNoContortion() );
+ maOptionsMisc.SetQuickEdit( pView->IsQuickEdit() );
+
+ // #i26631#
+ maOptionsMisc.SetMasterPagePaintCaching( pView->IsMasterPagePaintCaching() );
+
+ maOptionsMisc.SetDragWithCopy( pView->IsDragWithCopy() );
+ maOptionsMisc.SetPickThrough( pView->GetModel()->IsPickThroughTransparentTextFrames() );
+ maOptionsMisc.SetDoubleClickTextEdit( pView->IsDoubleClickTextEdit() );
+ maOptionsMisc.SetClickChangeRotation( pView->IsClickChangeRotation() );
+ maOptionsMisc.SetSolidDragging( pView->IsSolidDragging() );
+ }
+ else if( pOpts )
+ {
+ maOptionsMisc.SetMarkedHitMovesAlways( pOpts->IsMarkedHitMovesAlways() );
+ maOptionsMisc.SetMoveOnlyDragging( pOpts->IsMoveOnlyDragging() );
+ maOptionsMisc.SetCrookNoContortion( pOpts->IsCrookNoContortion() );
+ maOptionsMisc.SetQuickEdit( pOpts->IsQuickEdit() );
+ maOptionsMisc.SetMasterPagePaintCaching( pOpts->IsMasterPagePaintCaching() );
+ maOptionsMisc.SetDragWithCopy( pOpts->IsDragWithCopy() );
+ maOptionsMisc.SetPickThrough( pOpts->IsPickThrough() );
+ maOptionsMisc.SetDoubleClickTextEdit( pOpts->IsDoubleClickTextEdit() );
+ maOptionsMisc.SetClickChangeRotation( pOpts->IsClickChangeRotation() );
+ maOptionsMisc.SetSolidDragging( pOpts->IsSolidDragging() );
+ }
+}
+
+SdOptionsMiscItem* SdOptionsMiscItem::Clone( SfxItemPool* ) const
+{
+ return new SdOptionsMiscItem( *this );
+}
+
+bool SdOptionsMiscItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+ return maOptionsMisc == static_cast<const SdOptionsMiscItem&>(rAttr).maOptionsMisc;
+}
+
+void SdOptionsMiscItem::SetOptions( SdOptions* pOpts ) const
+{
+ if( !pOpts )
+ return;
+
+ pOpts->SetStartWithTemplate( maOptionsMisc.IsStartWithTemplate() );
+ pOpts->SetMarkedHitMovesAlways( maOptionsMisc.IsMarkedHitMovesAlways() );
+ pOpts->SetMoveOnlyDragging( maOptionsMisc.IsMoveOnlyDragging() );
+ pOpts->SetCrookNoContortion( maOptionsMisc.IsCrookNoContortion() );
+ pOpts->SetQuickEdit( maOptionsMisc.IsQuickEdit() );
+ pOpts->SetMasterPagePaintCaching( maOptionsMisc.IsMasterPagePaintCaching() );
+ pOpts->SetDragWithCopy( maOptionsMisc.IsDragWithCopy() );
+ pOpts->SetPickThrough( maOptionsMisc.IsPickThrough() );
+ pOpts->SetDoubleClickTextEdit( maOptionsMisc.IsDoubleClickTextEdit() );
+ pOpts->SetClickChangeRotation( maOptionsMisc.IsClickChangeRotation() );
+ pOpts->SetEnableSdremote( maOptionsMisc.IsEnableSdremote() );
+ pOpts->SetEnablePresenterScreen( maOptionsMisc.IsEnablePresenterScreen() );
+ pOpts->SetSummationOfParagraphs( maOptionsMisc.IsSummationOfParagraphs() );
+ pOpts->SetTabBarVisible( maOptionsMisc.IsTabBarVisible() );
+
+ pOpts->SetSolidDragging( maOptionsMisc.IsSolidDragging() );
+ pOpts->SetShowUndoDeleteWarning( maOptionsMisc.IsShowUndoDeleteWarning() );
+ pOpts->SetPrinterIndependentLayout( maOptionsMisc.GetPrinterIndependentLayout() );
+ pOpts->SetShowComments( maOptionsMisc.IsShowComments() );
+ pOpts->SetDefaultObjectSizeWidth( maOptionsMisc.GetDefaultObjectSizeWidth() );
+ pOpts->SetDefaultObjectSizeHeight( maOptionsMisc.GetDefaultObjectSizeHeight() );
+
+ pOpts->SetPreviewNewEffects( maOptionsMisc.IsPreviewNewEffects() );
+ pOpts->SetPreviewChangedEffects( maOptionsMisc.IsPreviewChangedEffects() );
+ pOpts->SetPreviewTransitions( maOptionsMisc.IsPreviewTransitions() );
+
+ pOpts->SetDisplay( maOptionsMisc.GetDisplay() );
+
+ pOpts->SetPresentationPenColor( maOptionsMisc.GetPresentationPenColor() );
+ pOpts->SetPresentationPenWidth( maOptionsMisc.GetPresentationPenWidth() );
+}
+
+/*************************************************************************
+|*
+|* SdOptionsSnap
+|*
+\************************************************************************/
+
+SdOptionsSnap::SdOptionsSnap( bool bImpress, bool bUseConfig ) :
+ SdOptionsGeneric( bImpress, bUseConfig ?
+ ( bImpress ?
+ OUString( "Office.Impress/Snap" ) :
+ OUString( "Office.Draw/Snap" ) ) :
+ OUString() ),
+ bSnapHelplines( true ),
+ bSnapBorder( true ),
+ bSnapFrame( false ),
+ bSnapPoints( false ),
+ bOrtho( false ),
+ bBigOrtho( true ),
+ bRotate( false ),
+ nSnapArea( 5 ),
+ nAngle( 1500 ),
+ nBezAngle( 1500 )
+
+{
+ EnableModify( true );
+}
+
+bool SdOptionsSnap::operator==( const SdOptionsSnap& rOpt ) const
+{
+ return( IsSnapHelplines() == rOpt.IsSnapHelplines() &&
+ IsSnapBorder() == rOpt.IsSnapBorder() &&
+ IsSnapFrame() == rOpt.IsSnapFrame() &&
+ IsSnapPoints() == rOpt.IsSnapPoints() &&
+ IsOrtho() == rOpt.IsOrtho() &&
+ IsBigOrtho() == rOpt.IsBigOrtho() &&
+ IsRotate() == rOpt.IsRotate() &&
+ GetSnapArea() == rOpt.GetSnapArea() &&
+ GetAngle() == rOpt.GetAngle() &&
+ GetEliminatePolyPointLimitAngle() == rOpt.GetEliminatePolyPointLimitAngle() );
+}
+
+void SdOptionsSnap::GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const
+{
+ static const char* aPropNames[] =
+ {
+ "Object/SnapLine",
+ "Object/PageMargin",
+ "Object/ObjectFrame",
+ "Object/ObjectPoint",
+ "Position/CreatingMoving",
+ "Position/ExtendEdges",
+ "Position/Rotating",
+ "Object/Range",
+ "Position/RotatingValue",
+ "Position/PointReduction"
+ };
+
+ rCount = SAL_N_ELEMENTS(aPropNames);
+ ppNames = aPropNames;
+}
+
+bool SdOptionsSnap::ReadData( const Any* pValues )
+{
+ if( pValues[0].hasValue() ) SetSnapHelplines( *o3tl::doAccess<bool>(pValues[ 0 ]) );
+ if( pValues[1].hasValue() ) SetSnapBorder( *o3tl::doAccess<bool>(pValues[ 1 ]) );
+ if( pValues[2].hasValue() ) SetSnapFrame( *o3tl::doAccess<bool>(pValues[ 2 ]) );
+ if( pValues[3].hasValue() ) SetSnapPoints( *o3tl::doAccess<bool>(pValues[ 3 ]) );
+ if( pValues[4].hasValue() ) SetOrtho( *o3tl::doAccess<bool>(pValues[ 4 ]) );
+ if( pValues[5].hasValue() ) SetBigOrtho( *o3tl::doAccess<bool>(pValues[ 5 ]) );
+ if( pValues[6].hasValue() ) SetRotate( *o3tl::doAccess<bool>(pValues[ 6 ]) );
+ if( pValues[7].hasValue() ) SetSnapArea( static_cast<sal_Int16>(*o3tl::doAccess<sal_Int32>(pValues[ 7 ])) );
+ if( pValues[8].hasValue() ) SetAngle( Degree100(*o3tl::doAccess<sal_Int32>(pValues[ 8 ])) );
+ if( pValues[9].hasValue() ) SetEliminatePolyPointLimitAngle( Degree100(*o3tl::doAccess<sal_Int32>(pValues[ 9 ])) );
+
+ return true;
+}
+
+bool SdOptionsSnap::WriteData( Any* pValues ) const
+{
+ pValues[ 0 ] <<= IsSnapHelplines();
+ pValues[ 1 ] <<= IsSnapBorder();
+ pValues[ 2 ] <<= IsSnapFrame();
+ pValues[ 3 ] <<= IsSnapPoints();
+ pValues[ 4 ] <<= IsOrtho();
+ pValues[ 5 ] <<= IsBigOrtho();
+ pValues[ 6 ] <<= IsRotate();
+ pValues[ 7 ] <<= static_cast<sal_Int32>(GetSnapArea());
+ pValues[ 8 ] <<= static_cast<sal_Int32>(GetAngle().get());
+ pValues[ 9 ] <<= static_cast<sal_Int32>(GetEliminatePolyPointLimitAngle().get());
+
+ return true;
+}
+
+/*************************************************************************
+|*
+|* SdOptionsSnapItem
+|*
+\************************************************************************/
+
+SdOptionsSnapItem::SdOptionsSnapItem()
+: SfxPoolItem ( ATTR_OPTIONS_SNAP )
+, maOptionsSnap ( false, false )
+{
+}
+
+SdOptionsSnapItem::SdOptionsSnapItem( SdOptions const * pOpts, ::sd::FrameView const * pView )
+: SfxPoolItem ( ATTR_OPTIONS_SNAP )
+, maOptionsSnap ( false, false )
+{
+ if( pView )
+ {
+ maOptionsSnap.SetSnapHelplines( pView->IsHlplSnap() );
+ maOptionsSnap.SetSnapBorder( pView->IsBordSnap() );
+ maOptionsSnap.SetSnapFrame( pView->IsOFrmSnap() );
+ maOptionsSnap.SetSnapPoints( pView->IsOPntSnap() );
+ maOptionsSnap.SetOrtho( pView->IsOrtho() );
+ maOptionsSnap.SetBigOrtho( pView->IsBigOrtho() );
+ maOptionsSnap.SetRotate( pView->IsAngleSnapEnabled() );
+ maOptionsSnap.SetSnapArea( pView->GetSnapMagneticPixel() );
+ maOptionsSnap.SetAngle( pView->GetSnapAngle() );
+ maOptionsSnap.SetEliminatePolyPointLimitAngle( pView->GetEliminatePolyPointLimitAngle() );
+ }
+ else if( pOpts )
+ {
+ maOptionsSnap.SetSnapHelplines( pOpts->IsSnapHelplines() );
+ maOptionsSnap.SetSnapBorder( pOpts->IsSnapBorder() );
+ maOptionsSnap.SetSnapFrame( pOpts->IsSnapFrame() );
+ maOptionsSnap.SetSnapPoints( pOpts->IsSnapPoints() );
+ maOptionsSnap.SetOrtho( pOpts->IsOrtho() );
+ maOptionsSnap.SetBigOrtho( pOpts->IsBigOrtho() );
+ maOptionsSnap.SetRotate( pOpts->IsRotate() );
+ maOptionsSnap.SetSnapArea( pOpts->GetSnapArea() );
+ maOptionsSnap.SetAngle( pOpts->GetAngle() );
+ maOptionsSnap.SetEliminatePolyPointLimitAngle( pOpts->GetEliminatePolyPointLimitAngle() );
+ }
+}
+
+SdOptionsSnapItem* SdOptionsSnapItem::Clone( SfxItemPool* ) const
+{
+ return new SdOptionsSnapItem( *this );
+}
+
+bool SdOptionsSnapItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+ return maOptionsSnap == static_cast<const SdOptionsSnapItem&>(rAttr).maOptionsSnap;
+}
+
+void SdOptionsSnapItem::SetOptions( SdOptions* pOpts ) const
+{
+ if( !pOpts )
+ return;
+
+ pOpts->SetSnapHelplines( maOptionsSnap.IsSnapHelplines() );
+ pOpts->SetSnapBorder( maOptionsSnap.IsSnapBorder() );
+ pOpts->SetSnapFrame( maOptionsSnap.IsSnapFrame() );
+ pOpts->SetSnapPoints( maOptionsSnap.IsSnapPoints() );
+ pOpts->SetOrtho( maOptionsSnap.IsOrtho() );
+ pOpts->SetBigOrtho( maOptionsSnap.IsBigOrtho() );
+ pOpts->SetRotate( maOptionsSnap.IsRotate() );
+ pOpts->SetSnapArea( maOptionsSnap.GetSnapArea() );
+ pOpts->SetAngle( maOptionsSnap.GetAngle() );
+ pOpts->SetEliminatePolyPointLimitAngle( maOptionsSnap.GetEliminatePolyPointLimitAngle() );
+}
+
+/*************************************************************************
+|*
+|* SdOptionsZoom
+|*
+\************************************************************************/
+
+SdOptionsZoom::SdOptionsZoom( bool bImpress ) :
+ SdOptionsGeneric( bImpress, bImpress ?
+ OUString() :
+ OUString("Office.Draw/Zoom") ),
+ nX( 1 ),
+ nY( 1 )
+
+{
+ EnableModify( true );
+}
+
+void SdOptionsZoom::GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const
+{
+ static const char* aPropNames[] =
+ {
+ "ScaleX",
+ "ScaleY"
+ };
+
+ rCount = !IsImpress() ? SAL_N_ELEMENTS(aPropNames) : 0;
+ ppNames = aPropNames;
+}
+
+bool SdOptionsZoom::ReadData( const Any* pValues )
+{
+ sal_Int32 x = 1, y = 1;
+
+ if( pValues[0].hasValue() ) x = *o3tl::doAccess<sal_Int32>(pValues[ 0 ]);
+ if( pValues[1].hasValue() ) y = *o3tl::doAccess<sal_Int32>(pValues[ 1 ]);
+
+ SetScale( x, y );
+
+ return true;
+}
+
+bool SdOptionsZoom::WriteData( Any* pValues ) const
+{
+ sal_Int32 x, y;
+
+ GetScale( x, y );
+
+ pValues[ 0 ] <<= x;
+ pValues[ 1 ] <<= y;
+
+ return true;
+}
+
+/*************************************************************************
+|*
+|* SdOptionsGrid
+|*
+\************************************************************************/
+
+SdOptionsGrid::SdOptionsGrid(bool bImpress) :
+ SdOptionsGeneric( bImpress,
+ bImpress ?
+ OUString( "Office.Impress/Grid" ) :
+ OUString( "Office.Draw/Grid" )
+ )
+{
+ EnableModify( false );
+ SetDefaults();
+ EnableModify( true );
+}
+
+SdOptionsGrid::~SdOptionsGrid()
+{
+}
+
+void SdOptionsGrid::SetDefaults()
+{
+ const sal_uInt32 nVal = 1000;
+
+ SetFieldDivisionX( nVal );
+ SetFieldDivisionY( nVal );
+ SetFieldDrawX( nVal );
+ SetFieldDrawY( nVal );
+ SetFieldSnapX( nVal );
+ SetFieldSnapY( nVal );
+ SetUseGridSnap( false );
+ SetSynchronize( true );
+ SetGridVisible( false );
+ SetEqualGrid( true );
+}
+
+void SdOptionsGrid::GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const
+{
+ if( isMetricSystem() )
+ {
+ static const char* aPropNamesMetric[] =
+ {
+ "Resolution/XAxis/Metric",
+ "Resolution/YAxis/Metric",
+ "Subdivision/XAxis",
+ "Subdivision/YAxis",
+ "SnapGrid/XAxis/Metric",
+ "SnapGrid/YAxis/Metric",
+ "Option/SnapToGrid",
+ "Option/Synchronize",
+ "Option/VisibleGrid",
+ "SnapGrid/Size"
+ };
+ ppNames = aPropNamesMetric;
+ rCount = SAL_N_ELEMENTS(aPropNamesMetric);
+ }
+ else
+ {
+ static const char* aPropNamesNonMetric[] =
+ {
+ "Resolution/XAxis/NonMetric",
+ "Resolution/YAxis/NonMetric",
+ "Subdivision/XAxis",
+ "Subdivision/YAxis",
+ "SnapGrid/XAxis/NonMetric",
+ "SnapGrid/YAxis/NonMetric",
+ "Option/SnapToGrid",
+ "Option/Synchronize",
+ "Option/VisibleGrid",
+ "SnapGrid/Size"
+ };
+ ppNames = aPropNamesNonMetric;
+ rCount = SAL_N_ELEMENTS(aPropNamesNonMetric);
+ }
+}
+
+bool SdOptionsGrid::ReadData( const Any* pValues )
+{
+ if( pValues[0].hasValue() ) SetFieldDrawX( *o3tl::doAccess<sal_Int32>(pValues[ 0 ]) );
+ if( pValues[1].hasValue() ) SetFieldDrawY( *o3tl::doAccess<sal_Int32>(pValues[ 1 ]) );
+
+ if( pValues[2].hasValue() )
+ {
+ const sal_uInt32 nDivX = FRound( *o3tl::doAccess<double>(pValues[ 2 ]) );
+ SetFieldDivisionX( SvxOptionsGrid::GetFieldDrawX() / ( nDivX + 1 ) );
+ }
+
+ if( pValues[3].hasValue() )
+ {
+ const sal_uInt32 nDivY = FRound( *o3tl::doAccess<double>(pValues[ 3 ]) );
+ SetFieldDivisionY( SvxOptionsGrid::GetFieldDrawY() / ( nDivY + 1 ) );
+ }
+
+ if( pValues[4].hasValue() ) SetFieldSnapX( *o3tl::doAccess<sal_Int32>(pValues[ 4 ]) );
+ if( pValues[5].hasValue() ) SetFieldSnapY( *o3tl::doAccess<sal_Int32>(pValues[ 5 ]) );
+ if( pValues[6].hasValue() ) SetUseGridSnap( *o3tl::doAccess<bool>(pValues[ 6 ]) );
+ if( pValues[7].hasValue() ) SetSynchronize( *o3tl::doAccess<bool>(pValues[ 7 ]) );
+ if( pValues[8].hasValue() ) SetGridVisible( *o3tl::doAccess<bool>(pValues[ 8 ]) );
+ if( pValues[9].hasValue() ) SetEqualGrid( *o3tl::doAccess<bool>(pValues[ 9 ]) );
+
+ return true;
+}
+
+bool SdOptionsGrid::WriteData( Any* pValues ) const
+{
+ pValues[ 0 ] <<= static_cast<sal_Int32>(GetFieldDrawX());
+ pValues[ 1 ] <<= static_cast<sal_Int32>(GetFieldDrawY());
+ pValues[ 2 ] <<= ( GetFieldDivisionX() ? ( static_cast<double>(GetFieldDrawX()) / GetFieldDivisionX() - 1.0 ) : double(0) );
+ pValues[ 3 ] <<= ( GetFieldDivisionY() ? ( static_cast<double>(GetFieldDrawY()) / GetFieldDivisionY() - 1.0 ) : double(0) );
+ pValues[ 4 ] <<= static_cast<sal_Int32>(GetFieldSnapX());
+ pValues[ 5 ] <<= static_cast<sal_Int32>(GetFieldSnapY());
+ pValues[ 6 ] <<= IsUseGridSnap();
+ pValues[ 7 ] <<= IsSynchronize();
+ pValues[ 8 ] <<= IsGridVisible();
+ pValues[ 9 ] <<= IsEqualGrid();
+
+ return true;
+}
+
+/*************************************************************************
+|*
+|* SdOptionsGridItem
+|*
+\************************************************************************/
+
+SdOptionsGridItem::SdOptionsGridItem( SdOptions const * pOpts ) :
+ SvxGridItem( SID_ATTR_GRID_OPTIONS )
+{
+ SetSynchronize( pOpts->IsSynchronize() );
+ SetEqualGrid( pOpts->IsEqualGrid() );
+
+ SetFieldDrawX( pOpts->GetFieldDrawX() );
+ SetFieldDrawY( pOpts->GetFieldDrawY() );
+ SetFieldDivisionX( pOpts->GetFieldDivisionX() ? ( pOpts->GetFieldDrawX() / pOpts->GetFieldDivisionX() - 1 ) : 0 );
+ SetFieldDivisionY( pOpts->GetFieldDivisionY() ? ( pOpts->GetFieldDrawY() / pOpts->GetFieldDivisionY() - 1 ) : 0 );
+ SetFieldSnapX( pOpts->GetFieldSnapX() );
+ SetFieldSnapY( pOpts->GetFieldSnapY() );
+ SetUseGridSnap( pOpts->IsUseGridSnap() );
+ SetGridVisible( pOpts->IsGridVisible() );
+}
+
+void SdOptionsGridItem::SetOptions( SdOptions* pOpts ) const
+{
+ pOpts->SetFieldDrawX( GetFieldDrawX() );
+ pOpts->SetFieldDivisionX( GetFieldDrawX() / ( GetFieldDivisionX() + 1 ) );
+ pOpts->SetFieldDrawY( GetFieldDrawY() );
+ pOpts->SetFieldDivisionY( GetFieldDrawY() / ( GetFieldDivisionY() + 1 ) );
+ pOpts->SetFieldSnapX( GetFieldSnapX() );
+ pOpts->SetFieldSnapY( GetFieldSnapY() );
+ pOpts->SetUseGridSnap( GetUseGridSnap() );
+ pOpts->SetSynchronize( GetSynchronize() );
+ pOpts->SetGridVisible( GetGridVisible() );
+ pOpts->SetEqualGrid( GetEqualGrid() );
+}
+
+/*************************************************************************
+|*
+|* SdOptionsPrint
+|*
+\************************************************************************/
+
+SdOptionsPrint::SdOptionsPrint( bool bImpress, bool bUseConfig ) :
+ SdOptionsGeneric( bImpress, bUseConfig ?
+ ( bImpress ?
+ OUString( "Office.Impress/Print" ) :
+ OUString( "Office.Draw/Print" ) ) :
+ OUString() ),
+ bDraw( true ),
+ bNotes( false ),
+ bHandout( false ),
+ bOutline( false ),
+ bDate( false ),
+ bTime( false ),
+ bPagename( false ),
+ bHiddenPages( true ),
+ bPagesize( false ),
+ bPagetile( false ),
+ bWarningPrinter( true ),
+ bWarningSize( false ),
+ bWarningOrientation( false ),
+ bBooklet( false ),
+ bFront( true ),
+ bBack( true ),
+ bCutPage( false ),
+ bPaperbin( false ),
+ mbHandoutHorizontal( true ),
+ mnHandoutPages( 6 ),
+ nQuality( 0 )
+{
+ EnableModify( true );
+}
+
+bool SdOptionsPrint::operator==( const SdOptionsPrint& rOpt ) const
+{
+ return( IsDraw() == rOpt.IsDraw() &&
+ IsNotes() == rOpt.IsNotes() &&
+ IsHandout() == rOpt.IsHandout() &&
+ IsOutline() == rOpt.IsOutline() &&
+ IsDate() == rOpt.IsDate() &&
+ IsTime() == rOpt.IsTime() &&
+ IsPagename() == rOpt.IsPagename() &&
+ IsHiddenPages() == rOpt.IsHiddenPages() &&
+ IsPagesize() == rOpt.IsPagesize() &&
+ IsPagetile() == rOpt.IsPagetile() &&
+ IsWarningPrinter() == rOpt.IsWarningPrinter() &&
+ IsWarningSize() == rOpt.IsWarningSize() &&
+ IsWarningOrientation() == rOpt.IsWarningOrientation() &&
+ IsBooklet() == rOpt.IsBooklet() &&
+ IsFrontPage() == rOpt.IsFrontPage() &&
+ IsBackPage() == rOpt.IsBackPage() &&
+ IsCutPage() == rOpt.IsCutPage() &&
+ IsPaperbin() == rOpt.IsPaperbin() &&
+ GetOutputQuality() == rOpt.GetOutputQuality() &&
+ IsHandoutHorizontal() == rOpt.IsHandoutHorizontal() &&
+ GetHandoutPages() == rOpt.GetHandoutPages() );
+}
+
+void SdOptionsPrint::GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const
+{
+ if (IsImpress())
+ {
+ static const char* aImpressPropNames[] =
+ {
+ "Other/Date",
+ "Other/Time",
+ "Other/PageName",
+ "Other/HiddenPage",
+ "Page/PageSize",
+ "Page/PageTile",
+ // bWarningPrinter
+ // bWarningSize
+ // bWarningOrientation
+ "Page/Booklet",
+ "Page/BookletFront",
+ "Page/BookletBack",
+ // bCutPage
+ "Other/FromPrinterSetup",
+ "Other/Quality",
+ "Content/Presentation",
+ "Content/Note",
+ "Content/Handout",
+ "Content/Outline",
+ "Other/HandoutHorizontal",
+ "Other/PagesPerHandout"
+ };
+ rCount = SAL_N_ELEMENTS(aImpressPropNames);
+ ppNames = aImpressPropNames;
+ }
+ else
+ {
+ static const char* aDrawPropNames[] =
+ {
+ "Other/Date",
+ "Other/Time",
+ "Other/PageName",
+ "Other/HiddenPage",
+ "Page/PageSize",
+ "Page/PageTile",
+ // bWarningPrinter
+ // bWarningSize
+ // bWarningOrientation
+ "Page/Booklet",
+ "Page/BookletFront",
+ "Page/BookletBack",
+ // bCutPage
+ "Other/FromPrinterSetup",
+ "Other/Quality",
+ "Content/Drawing",
+ };
+ rCount = SAL_N_ELEMENTS(aDrawPropNames);
+ ppNames = aDrawPropNames;
+ }
+}
+
+bool SdOptionsPrint::ReadData( const Any* pValues )
+{
+ if( pValues[0].hasValue() ) SetDate( *o3tl::doAccess<bool>(pValues[ 0 ]) );
+ if( pValues[1].hasValue() ) SetTime( *o3tl::doAccess<bool>(pValues[ 1 ]) );
+ if( pValues[2].hasValue() ) SetPagename( *o3tl::doAccess<bool>(pValues[ 2 ]) );
+ if( pValues[3].hasValue() ) SetHiddenPages( *o3tl::doAccess<bool>(pValues[ 3 ]) );
+ if( pValues[4].hasValue() ) SetPagesize( *o3tl::doAccess<bool>(pValues[ 4 ]) );
+ if( pValues[5].hasValue() ) SetPagetile( *o3tl::doAccess<bool>(pValues[ 5 ]) );
+ if( pValues[6].hasValue() ) SetBooklet( *o3tl::doAccess<bool>(pValues[ 6 ]) );
+ if( pValues[7].hasValue() ) SetFrontPage( *o3tl::doAccess<bool>(pValues[ 7 ]) );
+ if( pValues[8].hasValue() ) SetBackPage( *o3tl::doAccess<bool>(pValues[ 8 ]) );
+ if( pValues[9].hasValue() ) SetPaperbin( *o3tl::doAccess<bool>(pValues[ 9 ]) );
+ if( pValues[10].hasValue() ) SetOutputQuality( static_cast<sal_uInt16>(*o3tl::doAccess<sal_Int32>(pValues[ 10 ])) );
+ if( pValues[11].hasValue() ) SetDraw( *o3tl::doAccess<bool>(pValues[ 11 ]) );
+
+ // just for impress
+ if (IsImpress())
+ {
+ if( pValues[12].hasValue() ) SetNotes( *o3tl::doAccess<bool>(pValues[ 12 ]) );
+ if( pValues[13].hasValue() ) SetHandout( *o3tl::doAccess<bool>(pValues[ 13 ]) );
+ if( pValues[14].hasValue() ) SetOutline( *o3tl::doAccess<bool>(pValues[ 14 ]) );
+ if( pValues[15].hasValue() ) SetHandoutHorizontal( *o3tl::doAccess<bool>(pValues[15]) );
+ if( pValues[16].hasValue() ) SetHandoutPages( static_cast<sal_uInt16>(*o3tl::doAccess<sal_Int32>(pValues[16])) );
+ }
+
+ return true;
+}
+
+bool SdOptionsPrint::WriteData( Any* pValues ) const
+{
+ pValues[ 0 ] <<= IsDate();
+ pValues[ 1 ] <<= IsTime();
+ pValues[ 2 ] <<= IsPagename();
+ pValues[ 3 ] <<= IsHiddenPages();
+ pValues[ 4 ] <<= IsPagesize();
+ pValues[ 5 ] <<= IsPagetile();
+ pValues[ 6 ] <<= IsBooklet();
+ pValues[ 7 ] <<= IsFrontPage();
+ pValues[ 8 ] <<= IsBackPage();
+ pValues[ 9 ] <<= IsPaperbin();
+ pValues[ 10 ] <<= static_cast<sal_Int32>(GetOutputQuality());
+ pValues[ 11 ] <<= IsDraw();
+
+ // just for impress
+ if (IsImpress())
+ {
+ pValues[ 12 ] <<= IsNotes();
+ pValues[ 13 ] <<= IsHandout();
+ pValues[ 14 ] <<= IsOutline();
+ pValues[ 15 ] <<= IsHandoutHorizontal();
+ pValues[ 16 ] <<= GetHandoutPages();
+ }
+
+ return true;
+}
+
+/*************************************************************************
+|*
+|* SdOptionsPrintItem
+|*
+\************************************************************************/
+
+SdOptionsPrintItem::SdOptionsPrintItem()
+: SfxPoolItem ( ATTR_OPTIONS_PRINT )
+, maOptionsPrint ( false, false )
+{
+}
+
+SdOptionsPrintItem::SdOptionsPrintItem( SdOptions const * pOpts )
+: SfxPoolItem ( ATTR_OPTIONS_PRINT )
+, maOptionsPrint ( false, false )
+{
+ if( !pOpts )
+ return;
+
+ maOptionsPrint.SetDraw( pOpts->IsDraw() );
+ maOptionsPrint.SetNotes( pOpts->IsNotes() );
+ maOptionsPrint.SetHandout( pOpts->IsHandout() );
+ maOptionsPrint.SetOutline( pOpts->IsOutline() );
+ maOptionsPrint.SetDate( pOpts->IsDate() );
+ maOptionsPrint.SetTime( pOpts->IsTime() );
+ maOptionsPrint.SetPagename( pOpts->IsPagename() );
+ maOptionsPrint.SetHiddenPages( pOpts->IsHiddenPages() );
+ maOptionsPrint.SetPagesize( pOpts->IsPagesize() );
+ maOptionsPrint.SetPagetile( pOpts->IsPagetile() );
+ maOptionsPrint.SetWarningPrinter( pOpts->IsWarningPrinter() );
+ maOptionsPrint.SetWarningSize( pOpts->IsWarningSize() );
+ maOptionsPrint.SetWarningOrientation( pOpts->IsWarningOrientation() );
+ maOptionsPrint.SetBooklet( pOpts->IsBooklet() );
+ maOptionsPrint.SetFrontPage( pOpts->IsFrontPage() );
+ maOptionsPrint.SetBackPage( pOpts->IsBackPage() );
+ maOptionsPrint.SetCutPage( pOpts->IsCutPage() );
+ maOptionsPrint.SetPaperbin( pOpts->IsPaperbin() );
+ maOptionsPrint.SetOutputQuality( pOpts->GetOutputQuality() );
+}
+
+SdOptionsPrintItem* SdOptionsPrintItem::Clone( SfxItemPool* ) const
+{
+ return new SdOptionsPrintItem( *this );
+}
+
+bool SdOptionsPrintItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+ return maOptionsPrint == static_cast<const SdOptionsPrintItem&>(rAttr).maOptionsPrint;
+}
+
+void SdOptionsPrintItem::SetOptions( SdOptions* pOpts ) const
+{
+ if( !pOpts )
+ return;
+
+ pOpts->SetDraw( maOptionsPrint.IsDraw() );
+ pOpts->SetNotes( maOptionsPrint.IsNotes() );
+ pOpts->SetHandout( maOptionsPrint.IsHandout() );
+ pOpts->SetOutline( maOptionsPrint.IsOutline() );
+ pOpts->SetDate( maOptionsPrint.IsDate() );
+ pOpts->SetTime( maOptionsPrint.IsTime() );
+ pOpts->SetPagename( maOptionsPrint.IsPagename() );
+ pOpts->SetHiddenPages( maOptionsPrint.IsHiddenPages() );
+ pOpts->SetPagesize( maOptionsPrint.IsPagesize() );
+ pOpts->SetPagetile( maOptionsPrint.IsPagetile() );
+ pOpts->SetWarningPrinter( maOptionsPrint.IsWarningPrinter() );
+ pOpts->SetWarningSize( maOptionsPrint.IsWarningSize() );
+ pOpts->SetWarningOrientation( maOptionsPrint.IsWarningOrientation() );
+ pOpts->SetBooklet( maOptionsPrint.IsBooklet() );
+ pOpts->SetFrontPage( maOptionsPrint.IsFrontPage() );
+ pOpts->SetBackPage( maOptionsPrint.IsBackPage() );
+ pOpts->SetCutPage( maOptionsPrint.IsCutPage() );
+ pOpts->SetPaperbin( maOptionsPrint.IsPaperbin() );
+ pOpts->SetOutputQuality( maOptionsPrint.GetOutputQuality() );
+}
+
+/*************************************************************************
+|*
+|* SdOptions
+|*
+\************************************************************************/
+
+SdOptions::SdOptions(bool bImpress) :
+ SdOptionsLayout( bImpress, true ),
+ SdOptionsContents( bImpress ),
+ SdOptionsMisc( bImpress, true ),
+ SdOptionsSnap( bImpress, true ),
+ SdOptionsZoom( bImpress ),
+ SdOptionsGrid( bImpress ),
+ SdOptionsPrint( bImpress, true )
+{
+}
+
+SdOptions::~SdOptions()
+{
+}
+
+void SdOptions::StoreConfig()
+{
+ SdOptionsLayout::Store();
+ SdOptionsContents::Store();
+ SdOptionsMisc::Store();
+ SdOptionsSnap::Store();
+ SdOptionsZoom::Store();
+ SdOptionsGrid::Store();
+ SdOptionsPrint::Store();
+}
+
+sal_Int32 SdOptionsMisc::GetDisplay() const
+{
+ Init();
+ return mnDisplay;
+}
+
+void SdOptionsMisc::SetDisplay( sal_Int32 nDisplay )
+{
+ if( mnDisplay != nDisplay )
+ {
+ OptionsChanged();
+ mnDisplay = nDisplay;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/app/scalectrl.cxx b/sd/source/ui/app/scalectrl.cxx
new file mode 100644
index 000000000..0444163b5
--- /dev/null
+++ b/sd/source/ui/app/scalectrl.cxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scalectrl.hxx>
+
+#include <vcl/commandevent.hxx>
+#include <vcl/status.hxx>
+#include <vcl/weldutils.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/sfxsids.hrc>
+
+#include <ViewShellBase.hxx>
+#include <drawdoc.hxx>
+#include <app.hrc>
+#include <sdresid.hxx>
+#include <strings.hrc>
+
+SFX_IMPL_STATUSBAR_CONTROL(SdScaleControl, SfxStringItem);
+
+// class SdScaleControl ------------------------------------------
+SdScaleControl::SdScaleControl(sal_uInt16 _nSlotId, sal_uInt16 _nId, StatusBar& rStb)
+ : SfxStatusBarControl(_nSlotId, _nId, rStb)
+{
+ GetStatusBar().SetQuickHelpText(GetId(), SdResId(STR_SCALE_TOOLTIP));
+}
+
+SdScaleControl::~SdScaleControl() {}
+
+void SdScaleControl::StateChangedAtStatusBarControl(sal_uInt16 /*nSID*/, SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ if (eState != SfxItemState::DEFAULT || pState->IsVoidItem())
+ return;
+ auto pStringItem = dynamic_cast<const SfxStringItem*>(pState);
+ GetStatusBar().SetItemText(GetId(), pStringItem->GetValue());
+}
+
+void SdScaleControl::Command(const CommandEvent& rCEvt)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu
+ || GetStatusBar().GetItemText(GetId()).isEmpty())
+ return;
+
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+
+ sd::ViewShellBase* pViewShellBase = sd::ViewShellBase::GetViewShellBase(pViewFrame);
+ if (!pViewShellBase)
+ return;
+
+ SdDrawDocument* pDoc = pViewShellBase->GetDocument();
+ if (!pDoc)
+ return;
+
+ std::unique_ptr<weld::Builder> xBuilder(
+ Application::CreateBuilder(nullptr, "modules/simpress/ui/masterpagemenu.ui"));
+ std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("menu"));
+
+ sal_uInt16 aTable[12] = { 1, 2, 4, 5, 8, 10, 16, 20, 30, 40, 50, 100 };
+
+ for (sal_uInt16 i = 11; i > 0; i--)
+ xPopup->append(OUString::number(12 - i), OUString::number(aTable[i]) + ":1");
+ for (sal_uInt16 i = 0; i < 12; i++)
+ xPopup->append(OUString::number(12 + i), "1:" + OUString::number(aTable[i]));
+
+ ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pParent = weld::GetPopupParent(GetStatusBar(), aRect);
+ OString sResult = xPopup->popup_at_rect(pParent, aRect);
+ if (sResult.isEmpty())
+ return;
+
+ sal_Int32 i = sResult.toUInt32();
+ sal_Int32 nX;
+ sal_Int32 nY;
+ if (i > 11)
+ nX = 1;
+ else
+ nX = aTable[(12 - i) % 12];
+ if (i > 11)
+ nY = aTable[i % 12];
+ else
+ nY = 1;
+ pDoc->SetUIScale(Fraction(nX, nY));
+
+ SfxBindings& pBindings = pViewFrame->GetBindings();
+ pBindings.Invalidate(SID_SCALE); //update statusbar
+ pBindings.Invalidate(SID_ATTR_METRIC); //update sidebar
+ pViewShellBase->UpdateBorder(true); // update ruler
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/app/sddll.cxx b/sd/source/ui/app/sddll.cxx
new file mode 100644
index 000000000..4e20d0997
--- /dev/null
+++ b/sd/source/ui/app/sddll.cxx
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <avmedia/mediaplayer.hxx>
+#include <avmedia/mediatoolbox.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <svx/fmobjfac.hxx>
+#include <svx/objfac3d.hxx>
+#include <vcl/svapp.hxx>
+
+#include <registerinterfaces.hxx>
+#include <sddll.hxx>
+#include <app.hrc>
+#include <AnimationChildWindow.hxx>
+#include <BezierObjectBar.hxx>
+#include <diactrl.hxx>
+#include <DrawDocShell.hxx>
+#include <FactoryIds.hxx>
+#include <gluectrl.hxx>
+#include <GraphicDocShell.hxx>
+#include <GraphicObjectBar.hxx>
+#include <GraphicViewShell.hxx>
+#include <GraphicViewShellBase.hxx>
+#include <ImpressViewShellBase.hxx>
+#include <PresentationViewShell.hxx>
+#include <PresentationViewShellBase.hxx>
+#include <MediaObjectBar.hxx>
+#include <NavigatorChildWindow.hxx>
+#include <OutlineViewShell.hxx>
+#include <OutlineViewShellBase.hxx>
+#include <PaneChildWindows.hxx>
+#include <SpellDialogChildWindow.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <SlideSorterViewShellBase.hxx>
+#include <SdShapeTypes.hxx>
+#include <TextObjectBar.hxx>
+#include <tmplctrl.hxx>
+#include <scalectrl.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/bmpmask.hxx>
+#include <svx/clipboardctl.hxx>
+#include <svx/f3dchild.hxx>
+#include <svx/fillctrl.hxx>
+#include <svx/fontwork.hxx>
+#include <svx/formatpaintbrushctrl.hxx>
+#include <svx/grafctrl.hxx>
+#include <svx/hyperdlg.hxx>
+#include <svx/imapdlg.hxx>
+#include <svx/linectrl.hxx>
+#include <svx/modctrl.hxx>
+#include <svx/pszctrl.hxx>
+#include <svx/srchdlg.hxx>
+#include <svx/SvxColorChildWindow.hxx>
+#include <svx/xmlsecctrl.hxx>
+#include <svx/zoomctrl.hxx>
+#include <svx/zoomsliderctrl.hxx>
+#include <svx/tbxctl.hxx>
+#include <sfx2/sidebar/SidebarChildWindow.hxx>
+#include <sfx2/devtools/DevelopmentToolChildWindow.hxx>
+#include <comphelper/lok.hxx>
+#include <sdabstdlg.hxx>
+#include <sdfilter.hxx>
+#include <sdmod.hxx>
+
+using namespace ::com::sun::star;
+
+// Register all Factories
+void SdDLL::RegisterFactorys()
+{
+ if (utl::ConfigManager::IsFuzzing() || SvtModuleOptions().IsImpress())
+ {
+ ::sd::ImpressViewShellBase::RegisterFactory (
+ ::sd::IMPRESS_FACTORY_ID);
+ ::sd::SlideSorterViewShellBase::RegisterFactory (
+ ::sd::SLIDE_SORTER_FACTORY_ID);
+ ::sd::OutlineViewShellBase::RegisterFactory (
+ ::sd::OUTLINE_FACTORY_ID);
+ ::sd::PresentationViewShellBase::RegisterFactory (
+ ::sd::PRESENTATION_FACTORY_ID);
+ }
+ if (!utl::ConfigManager::IsFuzzing() && SvtModuleOptions().IsDraw())
+ {
+ ::sd::GraphicViewShellBase::RegisterFactory (::sd::DRAW_FACTORY_ID);
+ }
+}
+
+// Register all Interfaces
+
+void SdDLL::RegisterInterfaces(const SdModule* pMod)
+{
+ // Module
+ SdModule::RegisterInterface(pMod);
+
+ // View shell base.
+ ::sd::ViewShellBase::RegisterInterface(pMod);
+
+ // DocShells
+ ::sd::DrawDocShell::RegisterInterface(pMod);
+ ::sd::GraphicDocShell::RegisterInterface(pMod);
+
+ // Impress ViewShells
+ ::sd::DrawViewShell::RegisterInterface(pMod);
+ ::sd::OutlineViewShell::RegisterInterface(pMod);
+ ::sd::PresentationViewShell::RegisterInterface(pMod);
+
+ // Draw ViewShell
+ ::sd::GraphicViewShell::RegisterInterface(pMod);
+
+ // Impress ObjectShells
+ ::sd::BezierObjectBar::RegisterInterface(pMod);
+ ::sd::TextObjectBar::RegisterInterface(pMod);
+ ::sd::GraphicObjectBar::RegisterInterface(pMod);
+
+ // Media ObjectShell
+ ::sd::MediaObjectBar::RegisterInterface(pMod);
+
+ // Table ObjectShell
+ ::sd::ui::table::RegisterInterfaces(pMod);
+
+ // View shells for the side panes.
+ ::sd::slidesorter::SlideSorterViewShell::RegisterInterface (pMod);
+}
+
+// Register all Controllers
+
+void SdDLL::RegisterControllers(SdModule* pMod)
+{
+ SdTbxCtlDiaPages::RegisterControl( SID_PAGES_PER_ROW, pMod );
+ SdTbxCtlGlueEscDir::RegisterControl( SID_GLUE_ESCDIR, pMod );
+
+ ::sd::AnimationChildWindow::RegisterChildWindow(false, pMod);
+
+ Svx3DChildWindow::RegisterChildWindow(false, pMod);
+ SvxFontWorkChildWindow::RegisterChildWindow(false, pMod);
+ SvxColorChildWindow::RegisterChildWindow(false, pMod, SfxChildWindowFlags::TASK);
+ SvxSearchDialogWrapper::RegisterChildWindow(false, pMod);
+ SvxBmpMaskChildWindow::RegisterChildWindow(false, pMod);
+ SvxIMapDlgChildWindow::RegisterChildWindow(false, pMod);
+ SvxHlinkDlgWrapper::RegisterChildWindow(false, pMod);
+ ::sd::SpellDialogChildWindow::RegisterChildWindow(
+ false, pMod, comphelper::LibreOfficeKit::isActive() ? SfxChildWindowFlags::NEVERCLONE
+ : SfxChildWindowFlags::NONE);
+#if HAVE_FEATURE_AVMEDIA
+ ::avmedia::MediaPlayer::RegisterChildWindow(false, pMod);
+#endif
+ ::sd::LeftPaneImpressChildWindow::RegisterChildWindow(false, pMod);
+ ::sd::LeftPaneDrawChildWindow::RegisterChildWindow(false, pMod);
+ ::sfx2::sidebar::SidebarChildWindow::RegisterChildWindow(false, pMod);
+ DevelopmentToolChildWindow::RegisterChildWindow(false, pMod);
+
+ ::sd::SdNavigatorWrapper::RegisterChildWindow(false, pMod, SfxChildWindowFlags::NEVERHIDE);
+
+ SvxFillToolBoxControl::RegisterControl(0, pMod);
+ SvxLineWidthToolBoxControl::RegisterControl(0, pMod);
+
+ SvxGrafModeToolBoxControl::RegisterControl( SID_ATTR_GRAF_MODE, pMod );
+ SvxGrafRedToolBoxControl::RegisterControl( SID_ATTR_GRAF_RED, pMod );
+ SvxGrafGreenToolBoxControl::RegisterControl( SID_ATTR_GRAF_GREEN, pMod );
+ SvxGrafBlueToolBoxControl::RegisterControl( SID_ATTR_GRAF_BLUE, pMod );
+ SvxGrafLuminanceToolBoxControl::RegisterControl( SID_ATTR_GRAF_LUMINANCE, pMod );
+ SvxGrafContrastToolBoxControl::RegisterControl( SID_ATTR_GRAF_CONTRAST, pMod );
+ SvxGrafGammaToolBoxControl::RegisterControl( SID_ATTR_GRAF_GAMMA, pMod );
+ SvxGrafTransparenceToolBoxControl::RegisterControl( SID_ATTR_GRAF_TRANSPARENCE, pMod );
+
+ // register StatusBarControls
+ SvxZoomPageStatusBarControl::RegisterControl( SID_ZOOM_ENTIRE_PAGE, pMod );
+ SvxZoomStatusBarControl::RegisterControl( SID_ATTR_ZOOM, pMod );
+ SvxPosSizeStatusBarControl::RegisterControl( SID_ATTR_SIZE, pMod );
+ SvxModifyControl::RegisterControl( SID_DOC_MODIFIED, pMod );
+ SvxZoomSliderControl::RegisterControl( SID_ATTR_ZOOMSLIDER, pMod );
+
+ svx::FormatPaintBrushToolBoxControl::RegisterControl(SID_FORMATPAINTBRUSH, pMod );
+
+ SvxClipBoardControl::RegisterControl( SID_PASTE, pMod );
+ SvxClipBoardControl::RegisterControl( SID_PASTE_UNFORMATTED, pMod );
+
+#if HAVE_FEATURE_AVMEDIA
+ ::avmedia::MediaToolBoxControl::RegisterControl( SID_AVMEDIA_TOOLBOX, pMod );
+#endif
+ XmlSecStatusBarControl::RegisterControl( SID_SIGNATURE, pMod );
+ SdTemplateControl::RegisterControl( SID_STATUS_LAYOUT, pMod );
+ SdScaleControl::RegisterControl( SID_SCALE, pMod );
+ SvxTbxCtlDraw::RegisterControl(SID_INSERT_DRAW, pMod );
+}
+
+void SdDLL::Init()
+{
+ if ( SfxApplication::GetModule(SfxToolsModule::Draw) ) // Module already active
+ return;
+
+ SfxObjectFactory* pDrawFact = nullptr;
+ SfxObjectFactory* pImpressFact = nullptr;
+
+ if (utl::ConfigManager::IsFuzzing() || SvtModuleOptions().IsImpress())
+ pImpressFact = &::sd::DrawDocShell::Factory();
+
+ if (!utl::ConfigManager::IsFuzzing() && SvtModuleOptions().IsDraw())
+ pDrawFact = &::sd::GraphicDocShell::Factory();
+
+ auto pUniqueModule = std::make_unique<SdModule>(pImpressFact, pDrawFact);
+ SdModule* pModule = pUniqueModule.get();
+ SfxApplication::SetModule(SfxToolsModule::Draw, std::move(pUniqueModule));
+
+ if (!utl::ConfigManager::IsFuzzing() && SvtModuleOptions().IsImpress())
+ {
+ // Register the Impress shape types in order to make the shapes accessible.
+ ::accessibility::RegisterImpressShapeTypes ();
+ ::sd::DrawDocShell::Factory().SetDocumentServiceName( "com.sun.star.presentation.PresentationDocument" );
+ }
+
+ if (!utl::ConfigManager::IsFuzzing() && SvtModuleOptions().IsDraw())
+ {
+ ::sd::GraphicDocShell::Factory().SetDocumentServiceName( "com.sun.star.drawing.DrawingDocument" );
+ }
+
+ // register your view-factories here
+ RegisterFactorys();
+
+ // register your shell-interfaces here
+ RegisterInterfaces(pModule);
+
+ // register your controllers here
+ RegisterControllers(pModule);
+
+ // register 3D-object-factory
+ E3dObjFactory();
+
+ // register css::form::component::Form-Object-Factory
+ FmFormObjFactory();
+
+ // register your exotic remote controls here
+#ifdef ENABLE_SDREMOTE
+ if (!utl::ConfigManager::IsFuzzing() && !Application::IsHeadlessModeEnabled())
+ RegisterRemotes();
+#endif
+}
+
+#ifndef DISABLE_DYNLOADING
+
+extern "C" SAL_DLLPUBLIC_EXPORT
+void lok_preload_hook()
+{
+ SdFilter::Preload();
+ SdAbstractDialogFactory::Create();
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/app/sdmod.cxx b/sd/source/ui/app/sdmod.cxx
new file mode 100644
index 000000000..c7d56831d
--- /dev/null
+++ b/sd/source/ui/app/sdmod.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unotools/pathoptions.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/resmgr.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/numformat.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/objface.hxx>
+#include <comphelper/processfactory.hxx>
+#include <svtools/ehdl.hxx>
+
+#include <svx/svxids.hrc>
+#include <svl/srchitem.hxx>
+#include <svx/svxerr.hxx>
+
+#include <svtools/colorcfg.hxx>
+
+#include <sdmod.hxx>
+#include <sdresid.hxx>
+#include <optsitem.hxx>
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <errhdl.hrc>
+
+#define ShellClass_SdModule
+#include <sdslots.hxx>
+
+SFX_IMPL_INTERFACE(SdModule, SfxModule)
+
+void SdModule::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterStatusBar(StatusBarId::DrawStatusBar);
+}
+
+// Ctor
+SdModule::SdModule(SfxObjectFactory* pFact1, SfxObjectFactory* pFact2 )
+: SfxModule("sd", {pFact1, pFact2}),
+ pTransferClip(nullptr),
+ pTransferDrag(nullptr),
+ pTransferSelection(nullptr),
+ pImpressOptions(nullptr),
+ pDrawOptions(nullptr),
+ bWaterCan(false),
+ mbEventListenerAdded(false),
+ mpColorConfig(new svtools::ColorConfig)
+{
+ SetName( "StarDraw" ); // Do not translate!
+ pSearchItem.reset( new SvxSearchItem(SID_SEARCH_ITEM) );
+ pSearchItem->SetAppFlag(SvxSearchApp::DRAW);
+ StartListening( *SfxGetpApp() );
+ SvxErrorHandler::ensure();
+ mpErrorHdl.reset( new SfxErrorHandler(RID_SD_ERRHDL, ErrCodeArea::Sd, ErrCodeArea::Sd, GetResLocale()) );
+
+ // Create a new ref device and (by calling SetReferenceDevice())
+ // set its resolution to 600 DPI. This leads to a visually better
+ // formatting of text in small sizes (6 point and below.)
+ mpVirtualRefDevice.reset(VclPtr<VirtualDevice>::Create());
+ mpVirtualRefDevice->SetMapMode(MapMode(MapUnit::Map100thMM));
+ mpVirtualRefDevice->SetReferenceDevice ( VirtualDevice::RefDevMode::Dpi600 );
+}
+
+OUString SdResId(TranslateId aId)
+{
+ return Translate::get(aId, SD_MOD()->GetResLocale());
+}
+
+OUString SdResId(TranslateNId aContextSingularPlural, int nCardinality)
+{
+ return Translate::nget(aContextSingularPlural, nCardinality, SD_MOD()->GetResLocale());
+}
+
+// Dtor
+SdModule::~SdModule()
+{
+ pSearchItem.reset();
+ pNumberFormatter.reset();
+
+ if (mbEventListenerAdded)
+ {
+ Application::RemoveEventListener( LINK( this, SdModule, EventListenerHdl ) );
+ }
+
+ mpErrorHdl.reset();
+ mpVirtualRefDevice.disposeAndClear();
+}
+
+void SdModule::SetSearchItem(std::unique_ptr<SvxSearchItem> pItem)
+{
+ pSearchItem = std::move(pItem);
+}
+
+/// get notifications
+void SdModule::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if( rHint.GetId() == SfxHintId::Deinitializing )
+ {
+ delete pImpressOptions;
+ pImpressOptions = nullptr;
+ delete pDrawOptions;
+ pDrawOptions = nullptr;
+ }
+}
+
+/// Return options
+SdOptions* SdModule::GetSdOptions(DocumentType eDocType)
+{
+ SdOptions* pOptions = nullptr;
+
+ if (eDocType == DocumentType::Draw)
+ {
+ if (!pDrawOptions)
+ pDrawOptions = new SdOptions(false);
+
+ pOptions = pDrawOptions;
+ }
+ else if (eDocType == DocumentType::Impress)
+ {
+ if (!pImpressOptions)
+ pImpressOptions = new SdOptions(true);
+
+ pOptions = pImpressOptions;
+ }
+ if( pOptions )
+ {
+ sal_uInt16 nMetric = pOptions->GetMetric();
+
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ SdDrawDocument* pDoc = nullptr;
+ if (pDocSh)
+ pDoc = pDocSh->GetDoc();
+
+ if( nMetric != 0xffff && pDoc && eDocType == pDoc->GetDocumentType() )
+ PutItem( SfxUInt16Item( SID_ATTR_METRIC, nMetric ) );
+ }
+
+ return pOptions;
+}
+
+/**
+ * Open and return option stream for internal options;
+ * if the stream is opened for reading but does not exist, an 'empty'
+ * RefObject is returned
+ */
+tools::SvRef<SotStorageStream> SdModule::GetOptionStream( std::u16string_view rOptionName,
+ SdOptionStreamMode eMode )
+{
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ tools::SvRef<SotStorageStream> xStm;
+
+ if( pDocSh )
+ {
+ DocumentType eType = pDocSh->GetDoc()->GetDocumentType();
+
+ if( !xOptionStorage.is() )
+ {
+ INetURLObject aURL( SvtPathOptions().GetUserConfigPath() );
+
+ aURL.Append( u"drawing.cfg" );
+
+ std::unique_ptr<SvStream> pStm = ::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READWRITE );
+
+ if( pStm )
+ xOptionStorage = new SotStorage( pStm.release(), true );
+ }
+
+ OUString aStmName;
+
+ if( DocumentType::Draw == eType )
+ aStmName = "Draw_";
+ else
+ aStmName = "Impress_";
+
+ aStmName += rOptionName;
+
+ if( SdOptionStreamMode::Store == eMode || xOptionStorage->IsContained( aStmName ) )
+ xStm = xOptionStorage->OpenSotStream( aStmName );
+ }
+
+ return xStm;
+}
+
+SvNumberFormatter* SdModule::GetNumberFormatter()
+{
+ if( !pNumberFormatter )
+ pNumberFormatter.reset( new SvNumberFormatter( ::comphelper::getProcessComponentContext(), LANGUAGE_SYSTEM ) );
+
+ return pNumberFormatter.get();
+}
+
+svtools::ColorConfig& SdModule::GetColorConfig()
+{
+ return *mpColorConfig;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/app/sdmod1.cxx b/sd/source/ui/app/sdmod1.cxx
new file mode 100644
index 000000000..573ee8530
--- /dev/null
+++ b/sd/source/ui/app/sdmod1.cxx
@@ -0,0 +1,638 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/lckbitem.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <osl/diagnose.h>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/errinf.hxx>
+#include <editeng/langitem.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/templatedlg.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <svx/svxids.hrc>
+#include <strings.hrc>
+
+#include <sdmod.hxx>
+#include <pres.hxx>
+#include <optsitem.hxx>
+#include <ViewShell.hxx>
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <sdresid.hxx>
+#include <OutlineView.hxx>
+#include <OutlineViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <FactoryIds.hxx>
+#include <memory>
+#include <slideshow.hxx>
+
+using ::sd::framework::FrameworkHelper;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::frame::XFrame;
+
+namespace {
+
+class OutlineToImpressFinalizer final
+{
+public:
+ OutlineToImpressFinalizer (
+ ::sd::ViewShellBase& rBase,
+ SdDrawDocument& rDocument,
+ SvLockBytes const & rBytes);
+ void operator() (bool bEventSeen);
+private:
+ ::sd::ViewShellBase& mrBase;
+ SdDrawDocument& mrDocument;
+ std::shared_ptr<SvMemoryStream> mpStream;
+};
+
+} //end of anonymous namespace
+
+void SdModule::Execute(SfxRequest& rReq)
+{
+ const SfxItemSet* pSet = rReq.GetArgs();
+ sal_uLong nSlotId = rReq.GetSlot();
+
+ switch ( nSlotId )
+ {
+ case SID_NEWDOC:
+ {
+ SfxGetpApp()->ExecuteSlot(rReq, SfxGetpApp()->GetInterface());
+ }
+ break;
+
+ case SID_AUTOSPELL_CHECK:
+ {
+ // automatic spell checker
+ const SfxBoolItem* pItem;
+ if( pSet && (pItem = pSet->GetItemIfSet( SID_AUTOSPELL_CHECK, false ) ) )
+ {
+ bool bOnlineSpelling = pItem->GetValue();
+ // save at document:
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if( pDocSh )
+ {
+ SdDrawDocument* pDoc = pDocSh->GetDoc();
+ pDoc->SetOnlineSpell( bOnlineSpelling );
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_METRIC:
+ {
+ const SfxUInt16Item* pItem;
+ if ( pSet && (pItem = pSet->GetItemIfSet( SID_ATTR_METRIC ) ) )
+ {
+ FieldUnit eUnit = static_cast<FieldUnit>(pItem->GetValue());
+ switch( eUnit )
+ {
+ case FieldUnit::MM: // only the units which are also in the dialog
+ case FieldUnit::CM:
+ case FieldUnit::INCH:
+ case FieldUnit::PICA:
+ case FieldUnit::POINT:
+ {
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if(pDocSh)
+ {
+ DocumentType eDocType = pDocSh->GetDoc()->GetDocumentType();
+
+ PutItem( *pItem );
+ SdOptions* pOptions = GetSdOptions( eDocType );
+ if(pOptions)
+ pOptions->SetMetric( static_cast<sal_uInt16>(eUnit) );
+ rReq.Done();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+ break;
+
+ case SID_ATTR_LANGUAGE:
+ case SID_ATTR_CHAR_CJK_LANGUAGE:
+ case SID_ATTR_CHAR_CTL_LANGUAGE:
+ {
+ const SfxPoolItem* pItem;
+ if( pSet &&
+ (
+ SfxItemState::SET == pSet->GetItemState(SID_ATTR_LANGUAGE, false, &pItem ) ||
+ SfxItemState::SET == pSet->GetItemState(SID_ATTR_CHAR_CJK_LANGUAGE, false, &pItem ) ||
+ SfxItemState::SET == pSet->GetItemState(SID_ATTR_CHAR_CTL_LANGUAGE, false, &pItem )
+ )
+ )
+ {
+ // save at the document:
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if ( pDocSh )
+ {
+ LanguageType eLanguage = static_cast<const SvxLanguageItem*>(pItem)->GetValue();
+ SdDrawDocument* pDoc = pDocSh->GetDoc();
+
+ if( nSlotId == sal_uInt16(SID_ATTR_CHAR_CJK_LANGUAGE) )
+ pDoc->SetLanguage( eLanguage, EE_CHAR_LANGUAGE_CJK );
+ else if( nSlotId == sal_uInt16(SID_ATTR_CHAR_CTL_LANGUAGE) )
+ pDoc->SetLanguage( eLanguage, EE_CHAR_LANGUAGE_CTL );
+ else
+ pDoc->SetLanguage( eLanguage, EE_CHAR_LANGUAGE );
+
+ if( pDoc->GetOnlineSpell() )
+ {
+ pDoc->StopOnlineSpelling();
+ pDoc->StartOnlineSpelling();
+ }
+ }
+ }
+ }
+ break;
+
+ case SID_NEWSD:
+ {
+ SfxFrame* pFrame = ExecuteNewDocument( rReq );
+ // if a frame was created, set it as return value
+ if(pFrame)
+ rReq.SetReturnValue(SfxFrameItem(0, pFrame));
+ }
+
+ break;
+
+ case SID_OPENHYPERLINK:
+ case SID_OPENDOC:
+ {
+ bool bIntercept = false;
+ ::sd::DrawDocShell* pDocShell = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if (pDocShell)
+ {
+ ::sd::ViewShell* pViewShell = pDocShell->GetViewShell();
+ if (pViewShell)
+ {
+ if( sd::SlideShow::IsRunning( pViewShell->GetViewShellBase() ) )
+ {
+ // Prevent documents from opening while the slide
+ // show is running, except when this request comes
+ // from a shape interaction.
+ if (rReq.GetArgs() == nullptr)
+ {
+ bIntercept = true;
+ }
+ }
+ }
+ }
+
+ if (!bIntercept)
+ {
+ SfxGetpApp()->ExecuteSlot(rReq, SfxGetpApp()->GetInterface());
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::Ok, SdResId(STR_CANT_PERFORM_IN_LIVEMODE)));
+
+ xErrorBox->run();
+
+ const SfxLinkItem* pLinkItem = rReq.GetArg<SfxLinkItem>(SID_DONELINK);
+ if( pLinkItem )
+ pLinkItem->GetValue().Call( nullptr );
+ }
+ }
+ break;
+
+ case SID_OUTLINE_TO_IMPRESS:
+ OutlineToImpress (rReq);
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool SdModule::OutlineToImpress(SfxRequest const & rRequest)
+{
+ const SfxItemSet* pSet = rRequest.GetArgs();
+
+ if (pSet)
+ {
+ SvLockBytes* pBytes = static_cast<const SfxLockBytesItem&>(pSet->Get(SID_OUTLINE_TO_IMPRESS)).GetValue();
+
+ if (pBytes)
+ {
+ SfxObjectShellLock xDocShell;
+ ::sd::DrawDocShell* pDocSh;
+ xDocShell = pDocSh = new ::sd::DrawDocShell(
+ SfxObjectCreateMode::STANDARD, false, DocumentType::Impress);
+
+ pDocSh->DoInitNew();
+ SdDrawDocument* pDoc = pDocSh->GetDoc();
+ if(pDoc)
+ {
+ pDoc->CreateFirstPages();
+ pDoc->StopWorkStartupDelay();
+ }
+
+ const SfxFrameItem* pFrmItem = rRequest.GetArg<SfxFrameItem>(SID_DOCFRAME);
+ SfxViewFrame::LoadDocumentIntoFrame( *pDocSh, pFrmItem, ::sd::OUTLINE_FACTORY_ID );
+
+ ::sd::ViewShell* pViewSh = pDocSh->GetViewShell();
+
+ if (pViewSh && pDoc)
+ {
+ // AutoLayouts have to be finished
+ pDoc->StopWorkStartupDelay();
+
+ SfxViewFrame* pViewFrame = pViewSh->GetViewFrame();
+
+ // When the view frame has not been just created we have
+ // to switch synchronously to the outline view.
+ // (Otherwise the request will be ignored anyway.)
+ ::sd::ViewShellBase* pBase
+ = dynamic_cast< ::sd::ViewShellBase*>(pViewFrame->GetViewShell());
+ if (pBase != nullptr)
+ {
+ std::shared_ptr<FrameworkHelper> pHelper (
+ FrameworkHelper::Instance(*pBase));
+ pHelper->RequestView(
+ FrameworkHelper::msOutlineViewURL,
+ FrameworkHelper::msCenterPaneURL);
+
+ pHelper->RunOnResourceActivation(
+ FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msOutlineViewURL,
+ FrameworkHelper::msCenterPaneURL),
+ OutlineToImpressFinalizer(*pBase, *pDoc, *pBytes));
+ }
+ }
+ }
+ }
+
+ return rRequest.IsDone();
+}
+
+void SdModule::GetState(SfxItemSet& rItemSet)
+{
+ if( SfxItemState::DEFAULT == rItemSet.GetItemState( SID_ATTR_METRIC ) )
+ {
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if(pDocSh)
+ {
+ DocumentType eDocType = pDocSh->GetDoc()->GetDocumentType();
+
+ SdOptions* pOptions = GetSdOptions(eDocType);
+ rItemSet.Put( SfxUInt16Item( SID_ATTR_METRIC, pOptions->GetMetric() ) );
+ }
+ }
+
+ // state of SID_OPENDOC is determined by the base class
+ if (rItemSet.GetItemState(SID_OPENDOC) != SfxItemState::UNKNOWN)
+ {
+ const SfxPoolItem* pItem = SfxGetpApp()->GetSlotState(SID_OPENDOC, SfxGetpApp()->GetInterface());
+ if (pItem)
+ rItemSet.Put(*pItem);
+ }
+
+ // state of SID_OPENHYPERLINK is determined by the base class
+ if (rItemSet.GetItemState(SID_OPENHYPERLINK) != SfxItemState::UNKNOWN)
+ {
+ const SfxPoolItem* pItem = SfxGetpApp()->GetSlotState(SID_OPENHYPERLINK, SfxGetpApp()->GetInterface());
+ if (pItem)
+ rItemSet.Put(*pItem);
+ }
+
+ if( SfxItemState::DEFAULT == rItemSet.GetItemState( SID_AUTOSPELL_CHECK ) )
+ {
+ ::sd::DrawDocShell* pDocSh =
+ dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if( pDocSh )
+ {
+ SdDrawDocument* pDoc = pDocSh->GetDoc();
+ rItemSet.Put( SfxBoolItem( SID_AUTOSPELL_CHECK, pDoc->GetOnlineSpell() ) );
+ }
+ }
+
+ if( SfxItemState::DEFAULT == rItemSet.GetItemState( SID_ATTR_LANGUAGE ) )
+ {
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if( pDocSh )
+ rItemSet.Put( SvxLanguageItem( pDocSh->GetDoc()->GetLanguage( EE_CHAR_LANGUAGE ), SID_ATTR_LANGUAGE ) );
+ }
+
+ if( SfxItemState::DEFAULT == rItemSet.GetItemState( SID_ATTR_CHAR_CJK_LANGUAGE ) )
+ {
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if( pDocSh )
+ rItemSet.Put( SvxLanguageItem( pDocSh->GetDoc()->GetLanguage( EE_CHAR_LANGUAGE_CJK ), SID_ATTR_CHAR_CJK_LANGUAGE ) );
+ }
+
+ if( SfxItemState::DEFAULT == rItemSet.GetItemState( SID_ATTR_CHAR_CTL_LANGUAGE ) )
+ {
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if( pDocSh )
+ rItemSet.Put( SvxLanguageItem( pDocSh->GetDoc()->GetLanguage( EE_CHAR_LANGUAGE_CTL ), SID_ATTR_CHAR_CTL_LANGUAGE ) );
+ }
+
+ if ( mbEventListenerAdded )
+ return;
+
+ ::sd::DrawDocShell* pDocShell = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if( pDocShell ) // Impress or Draw ?
+ {
+ ::sd::ViewShell* pViewShell = pDocShell->GetViewShell();
+
+ if( pViewShell && (pDocShell->GetDocumentType() == DocumentType::Impress) )
+ {
+ // add our event listener as soon as possible
+ Application::AddEventListener( LINK( this, SdModule, EventListenerHdl ) );
+ mbEventListenerAdded = true;
+ }
+ }
+}
+
+IMPL_STATIC_LINK( SdModule, EventListenerHdl, VclSimpleEvent&, rSimpleEvent, void )
+{
+ if( !((rSimpleEvent.GetId() == VclEventId::WindowCommand) && static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData()) )
+ return;
+
+ const CommandEvent& rEvent = *static_cast<const CommandEvent*>(static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData());
+
+ if( rEvent.GetCommand() != CommandEventId::Media )
+ return;
+
+ CommandMediaData* pMediaData = rEvent.GetMediaData();
+ pMediaData->SetPassThroughToOS(false);
+ switch (pMediaData->GetMediaId())
+ {
+ case MediaCommand::Play:
+ {
+ ::sd::DrawDocShell* pDocShell = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ if( pDocShell ) // Impress or Draw ?
+ {
+ ::sd::ViewShell* pViewShell = pDocShell->GetViewShell();
+
+ // #i97925# start the presentation if and only if an Impress document is focused
+ if( pViewShell && (pDocShell->GetDocumentType() == DocumentType::Impress) )
+ pViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_PRESENTATION );
+ }
+ break;
+ }
+ default:
+ pMediaData->SetPassThroughToOS(true);
+ break;
+ }
+}
+
+
+SfxFrame* SdModule::CreateFromTemplate(const OUString& rTemplatePath, const Reference<XFrame>& i_rFrame,
+ const bool bReplaceable)
+{
+ SfxFrame* pFrame = nullptr;
+
+ SfxObjectShellLock xDocShell;
+
+ std::unique_ptr<SfxItemSet> pSet(new SfxAllItemSet( SfxGetpApp()->GetPool() ));
+ pSet->Put( SfxBoolItem( SID_TEMPLATE, true ) );
+
+ ErrCode lErr = SfxGetpApp()->LoadTemplate( xDocShell, rTemplatePath, std::move(pSet) );
+
+ SfxObjectShell* pDocShell = xDocShell;
+
+ if( lErr )
+ {
+ ErrorHandler::HandleError(lErr);
+ }
+ else if( pDocShell )
+ {
+ if (pDocShell->GetMedium() && pDocShell->GetMedium()->GetItemSet())
+ pDocShell->GetMedium()->GetItemSet()->Put(SfxBoolItem(SID_REPLACEABLE, bReplaceable));
+ SfxViewFrame* pViewFrame = SfxViewFrame::LoadDocumentIntoFrame( *pDocShell, i_rFrame );
+ OSL_ENSURE( pViewFrame, "SdModule::CreateFromTemplate: no view frame - was the document really loaded?" );
+ pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr;
+ }
+
+ return pFrame;
+
+}
+
+SfxFrame* SdModule::ExecuteNewDocument( SfxRequest const & rReq )
+{
+ SfxFrame* pFrame = nullptr;
+ if ( SvtModuleOptions().IsImpress() )
+ {
+ Reference< XFrame > xTargetFrame;
+ const SfxUnoFrameItem* pFrmItem = rReq.GetArg<SfxUnoFrameItem>(SID_FILLFRAME);
+ if ( pFrmItem )
+ xTargetFrame = pFrmItem->GetFrame();
+
+ SdOptions* pOpt = GetSdOptions(DocumentType::Impress);
+ bool bStartWithTemplate = pOpt->IsStartWithTemplate();
+
+ bool bNewDocDirect = rReq.GetSlot() == SID_NEWSD;
+
+ if( bNewDocDirect )
+ {
+ //we start without wizard
+
+ //check whether we should load a template document
+ OUString aStandardTemplate( SfxObjectFactory::GetStandardTemplate( u"com.sun.star.presentation.PresentationDocument" ) );
+
+ if( !aStandardTemplate.isEmpty() )
+ {
+ //load a template document
+ pFrame = CreateFromTemplate(aStandardTemplate, xTargetFrame, true);
+ }
+ else
+ {
+ //create an empty document
+ pFrame = CreateEmptyDocument( xTargetFrame );
+ }
+ }
+
+ if (bStartWithTemplate)
+ {
+ //Launch TemplateSelectionDialog
+ SfxTemplateSelectionDlg aTemplDlg(SfxGetpApp()->GetTopWindow());
+ aTemplDlg.run();
+
+ //check to disable the dialog
+ pOpt->SetStartWithTemplate( aTemplDlg.IsStartWithTemplate() );
+
+ //pFrame is loaded with the desired template
+ if (!aTemplDlg.getTemplatePath().isEmpty())
+ pFrame = CreateFromTemplate(aTemplDlg.getTemplatePath(), xTargetFrame, false);
+
+ // show tip-of-the-day dialog if it was deferred because SfxTemplateSelectionDlg
+ // was open
+ if (pFrame && SfxApplication::IsTipOfTheDayDue() && !SfxApplication::IsHeadlessOrUITest())
+ {
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ {
+ // tdf#127946 pass in argument for dialog parent
+ SfxUnoFrameItem aDocFrame(SID_FILLFRAME, pFrame->GetFrameInterface());
+ pDispatcher->ExecuteList(SID_TIPOFTHEDAY, SfxCallMode::SLOT, {}, { &aDocFrame });
+ }
+ }
+ }
+ }
+
+ return pFrame;
+}
+
+SfxFrame* SdModule::CreateEmptyDocument( const Reference< XFrame >& i_rFrame )
+{
+ SfxFrame* pFrame = nullptr;
+
+ SfxObjectShellLock xDocShell;
+ ::sd::DrawDocShell* pNewDocSh;
+ xDocShell = pNewDocSh = new ::sd::DrawDocShell(SfxObjectCreateMode::STANDARD,false,DocumentType::Impress);
+ pNewDocSh->DoInitNew();
+ SdDrawDocument* pDoc = pNewDocSh->GetDoc();
+ if (pDoc)
+ {
+ pDoc->CreateFirstPages();
+ pDoc->StopWorkStartupDelay();
+ }
+ if (pNewDocSh->GetMedium() && pNewDocSh->GetMedium()->GetItemSet())
+ pNewDocSh->GetMedium()->GetItemSet()->Put(SfxBoolItem(SID_REPLACEABLE, true));
+
+ SfxViewFrame* pViewFrame = SfxViewFrame::LoadDocumentIntoFrame( *pNewDocSh, i_rFrame );
+ OSL_ENSURE( pViewFrame, "SdModule::CreateEmptyDocument: no view frame - was the document really loaded?" );
+ pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr;
+
+ return pFrame;
+}
+
+//===== OutlineToImpressFinalize ==============================================
+
+namespace {
+
+OutlineToImpressFinalizer::OutlineToImpressFinalizer (
+ ::sd::ViewShellBase& rBase,
+ SdDrawDocument& rDocument,
+ SvLockBytes const & rBytes)
+ : mrBase(rBase),
+ mrDocument(rDocument)
+{
+ // The given stream has a lifetime shorter than this new
+ // OutlineToImpressFinalizer object. Therefore a local copy of the
+ // stream is created.
+ const SvStream* pStream (rBytes.GetStream());
+ if (pStream == nullptr)
+ return;
+
+ // Create a memory stream and prepare to fill it with the content of
+ // the original stream.
+ mpStream = std::make_shared<SvMemoryStream>();
+ static const std::size_t nBufferSize = 4096;
+ ::std::unique_ptr<sal_Int8[]> pBuffer (new sal_Int8[nBufferSize]);
+
+ sal_uInt64 nReadPosition(0);
+ bool bLoop (true);
+ while (bLoop)
+ {
+ // Read the next part of the original stream.
+ std::size_t nReadByteCount (0);
+ const ErrCode nErrorCode (
+ rBytes.ReadAt(
+ nReadPosition,
+ pBuffer.get(),
+ nBufferSize,
+ &nReadByteCount));
+
+ // Check the error code and stop copying the stream data when an
+ // error has occurred.
+ if (nErrorCode == ERRCODE_NONE)
+ {
+ if (nReadByteCount == 0)
+ bLoop = false;
+ }
+ else if (nErrorCode == ERRCODE_IO_PENDING)
+ ;
+ else
+ {
+ bLoop = false;
+ nReadByteCount = 0;
+ }
+
+ // Append the read bytes to the end of the memory stream.
+ if (nReadByteCount > 0)
+ {
+ mpStream->WriteBytes(pBuffer.get(), nReadByteCount);
+ nReadPosition += nReadByteCount;
+ }
+ }
+
+ // Rewind the memory stream so that in the operator() method its
+ // content is properly read.
+ mpStream->Seek(STREAM_SEEK_TO_BEGIN);
+}
+
+void OutlineToImpressFinalizer::operator() (bool)
+{
+ // Fetch the new outline view shell.
+ ::sd::OutlineViewShell* pOutlineShell
+ = dynamic_cast<sd::OutlineViewShell*>(FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
+
+ if (pOutlineShell != nullptr && mpStream != nullptr)
+ {
+ sd::OutlineView* pView = static_cast<sd::OutlineView*>(pOutlineShell->GetView());
+ // mba: the stream can't contain any relative URLs, because we don't
+ // have any information about a BaseURL!
+ pOutlineShell->ReadRtf(*mpStream);
+
+ // Call UpdatePreview once for every slide to resync the
+ // document with the outliner of the OutlineViewShell.
+ sal_uInt16 nPageCount (mrDocument.GetSdPageCount(PageKind::Standard));
+ for (sal_uInt16 nIndex=0; nIndex<nPageCount; nIndex++)
+ {
+ SdPage* pPage = mrDocument.GetSdPage(nIndex, PageKind::Standard);
+ // Make the page the actual page so that the
+ // following UpdatePreview() call accesses the
+ // correct paragraphs.
+ pView->SetActualPage(pPage);
+ pOutlineShell->UpdatePreview(pPage);
+ }
+ // Select the first slide.
+ SdPage* pPage = mrDocument.GetSdPage(0, PageKind::Standard);
+ pView->SetActualPage(pPage);
+ pOutlineShell->UpdatePreview(pPage);
+ }
+
+ // Undo-Stack needs to be cleared, else the user may remove the
+ // only drawpage and this is a state we cannot handle ATM.
+ ::sd::DrawDocShell* pDocShell = mrDocument.GetDocSh();
+ if( pDocShell )
+ pDocShell->ClearUndoBuffer();
+}
+
+} // end of anonymous namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/app/sdmod2.cxx b/sd/source/ui/app/sdmod2.cxx
new file mode 100644
index 000000000..cccf42517
--- /dev/null
+++ b/sd/source/ui/app/sdmod2.cxx
@@ -0,0 +1,809 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/flditem.hxx>
+#include <editeng/CustomPropertyField.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/styfitem.hxx>
+#include <svl/inethist.hxx>
+#include <svl/poolitem.hxx>
+#include <svl/flagitem.hxx>
+#include <unotools/useroptions.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/docfile.hxx>
+#include <osl/diagnose.h>
+
+#include <editeng/measfld.hxx>
+#include <editeng/editstat.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/dialogs.hrc>
+#include <svx/svdotext.hxx>
+
+#include <sfx2/sfxdlg.hxx>
+
+#include <sdmod.hxx>
+#include <app.hrc>
+#include <family.hrc>
+#include <strings.hrc>
+#include <sdattr.hrc>
+
+#include <bitmaps.hlst>
+#include <ViewShell.hxx>
+#include <FrameView.hxx>
+#include <optsitem.hxx>
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <Outliner.hxx>
+#include <sdresid.hxx>
+#include <pres.hxx>
+#include <OutlineViewShell.hxx>
+#include <OutlineView.hxx>
+#include <ViewShellBase.hxx>
+#include <sdpage.hxx>
+#include <sdabstdlg.hxx>
+#include <svl/intitem.hxx>
+
+/** retrieves the page that is currently painted. This will only be the master page
+ if the current drawn view only shows the master page*/
+static SdPage* GetCurrentPage( sd::ViewShell const * pViewSh, EditFieldInfo const * pInfo, bool& bMasterView )
+{
+ if( !pInfo )
+ return nullptr;
+
+ bMasterView = false;
+ SdPage* pPage = dynamic_cast< SdPage* >( pInfo->GetSdrPage() );
+ SdrOutliner* pOutliner = dynamic_cast< SdrOutliner* >( pInfo->GetOutliner() );
+
+ // special case, someone already set the current page on the EditFieldInfo
+ // This is used from the svx::UnoGraphicsExporter f.e.
+ if( pPage )
+ {
+ bMasterView = false;
+ return pPage;
+ }
+
+ // first try to check if we are inside the outline view
+ sd::OutlineView* pSdView = nullptr;
+ if( auto pOutlineViewShell = dynamic_cast<const sd::OutlineViewShell* >(pViewSh) )
+ pSdView = static_cast<sd::OutlineView*>(pOutlineViewShell->GetView());
+
+ if (pSdView != nullptr && (pOutliner == &pSdView->GetOutliner()))
+ {
+ // outline mode
+ int nPgNum = 0;
+ Outliner& rOutl = pSdView->GetOutliner();
+ tools::Long nPos = pInfo->GetPara();
+ sal_Int32 nParaPos = 0;
+
+ for( Paragraph* pPara = rOutl.GetParagraph( 0 ); pPara && nPos >= 0; pPara = rOutl.GetParagraph( ++nParaPos ), nPos-- )
+ {
+ if( Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) )
+ nPgNum++;
+ }
+
+ pPage = pViewSh->GetDoc()->GetSdPage( static_cast<sal_uInt16>(nPgNum), PageKind::Standard );
+ }
+ else
+ {
+ // draw mode, slide mode and preview. Get the processed page from the outliner
+ if(pOutliner)
+ {
+ pPage = dynamic_cast< SdPage* >(const_cast< SdrPage* >(pOutliner->getVisualizedPage()));
+ }
+
+ // The path using GetPaintingPageView() and GetCurrentPaintingDisplayInfo()
+ // is no longer needed. I debugged and checked all usages of PageNumber decompositions
+ // which all use the new possibility of setting the visualized page at the SdrOutliner.
+
+ // if all else failed, geht the current page from the object that is
+ // currently formatted from the document
+ if(!pPage)
+ {
+ const SdrTextObj* pTextObj = (pViewSh && pViewSh->GetDoc()) ? pViewSh->GetDoc()->GetFormattingTextObj() : nullptr;
+
+ if( pTextObj )
+ {
+ pPage = dynamic_cast< SdPage* >( pTextObj->getSdrPageFromSdrObject() );
+ }
+ }
+
+ if(pPage)
+ {
+ bMasterView = pPage->IsMasterPage();
+ }
+ }
+
+ return pPage;
+}
+
+/**
+ * Link for CalcFieldValue of Outliners
+ */
+IMPL_LINK(SdModule, CalcFieldValueHdl, EditFieldInfo*, pInfo, void)
+{
+ if (!pInfo)
+ return;
+
+ const SvxFieldData* pField = pInfo->GetField().GetField();
+ ::sd::DrawDocShell* pDocShell = nullptr;
+ SdDrawDocument* pDoc = nullptr;
+
+ SdrOutliner* pSdrOutliner = dynamic_cast< SdrOutliner* >( pInfo->GetOutliner() );
+ if( pSdrOutliner )
+ {
+ const SdrTextObj* pTextObj = pSdrOutliner->GetTextObj();
+
+ if( pTextObj )
+ pDoc = dynamic_cast< SdDrawDocument* >( &pTextObj->getSdrModelFromSdrObject() );
+
+ if( pDoc )
+ pDocShell = pDoc->GetDocSh();
+ }
+
+ if( !pDocShell )
+ pDocShell = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+
+ const SvxDateField* pDateField = nullptr;
+ const SvxExtTimeField* pExtTimeField = nullptr;
+ const SvxExtFileField* pExtFileField = nullptr;
+ const SvxAuthorField* pAuthorField = nullptr;
+ const SvxURLField* pURLField = nullptr;
+
+ const editeng::CustomPropertyField* pCustomPropertyField = nullptr;
+
+ if( (pDateField = dynamic_cast< const SvxDateField* >(pField)) != nullptr )
+ {
+ LanguageType eLang = pInfo->GetOutliner()->GetLanguage( pInfo->GetPara(), pInfo->GetPos() );
+ pInfo->SetRepresentation( pDateField->GetFormatted( *GetNumberFormatter(), eLang ) );
+ }
+ else if( (pExtTimeField = dynamic_cast< const SvxExtTimeField *>(pField)) != nullptr )
+ {
+ LanguageType eLang = pInfo->GetOutliner()->GetLanguage( pInfo->GetPara(), pInfo->GetPos() );
+ pInfo->SetRepresentation( pExtTimeField->GetFormatted( *GetNumberFormatter(), eLang ) );
+ }
+ else if( (pExtFileField = dynamic_cast< const SvxExtFileField * >(pField)) != nullptr )
+ {
+ if( pDocShell && (pExtFileField->GetType() != SvxFileType::Fix) )
+ {
+ OUString aName;
+ if( pDocShell->HasName() )
+ aName = pDocShell->GetMedium()->GetName();
+ else
+ aName = pDocShell->GetName();
+
+ const_cast< SvxExtFileField* >(pExtFileField)->SetFile( aName );
+ }
+ pInfo->SetRepresentation( pExtFileField->GetFormatted() );
+
+ }
+ else if( (pAuthorField = dynamic_cast< const SvxAuthorField* >( pField )) != nullptr )
+ {
+ if( pAuthorField->GetType() != SvxAuthorType::Fix )
+ {
+ SvtUserOptions aUserOptions;
+ SvxAuthorField aAuthorField(
+ aUserOptions.GetFirstName(), aUserOptions.GetLastName(), aUserOptions.GetID(),
+ pAuthorField->GetType(), pAuthorField->GetFormat() );
+
+ *const_cast< SvxAuthorField* >(pAuthorField) = aAuthorField;
+ }
+ pInfo->SetRepresentation( pAuthorField->GetFormatted() );
+
+ }
+ else if( dynamic_cast< const SvxPageField* >(pField) )
+ {
+ OUString aRepresentation(" ");
+
+ ::sd::ViewShell* pViewSh = pDocShell ? pDocShell->GetViewShell() : nullptr;
+ if(pViewSh == nullptr)
+ {
+ ::sd::ViewShellBase* pBase = dynamic_cast< ::sd::ViewShellBase *>( SfxViewShell::Current() );
+ if(pBase)
+ pViewSh = pBase->GetMainViewShell().get();
+ }
+ if( !pDoc && pViewSh )
+ pDoc = pViewSh->GetDoc();
+
+ bool bMasterView;
+ SdPage* pPage = GetCurrentPage( pViewSh, pInfo, bMasterView );
+
+ if( pPage && pDoc && !bMasterView )
+ {
+ int nPgNum;
+
+ if( (pPage->GetPageKind() == PageKind::Handout) && pViewSh )
+ {
+ nPgNum = pViewSh->GetPrintedHandoutPageNum();
+ }
+ else
+ {
+ nPgNum = (pPage->GetPageNum() - 1) / 2 + 1;
+ }
+ aRepresentation = pDoc->CreatePageNumValue(static_cast<sal_uInt16>(nPgNum));
+ }
+ else
+ aRepresentation = SdResId(STR_FIELD_PLACEHOLDER_NUMBER);
+
+ pInfo->SetRepresentation( aRepresentation );
+ }
+ else if( dynamic_cast< const SvxPageTitleField* >(pField) )
+ {
+ OUString aRepresentation(" ");
+
+ ::sd::ViewShell* pViewSh = pDocShell ? pDocShell->GetViewShell() : nullptr;
+ if(pViewSh == nullptr)
+ {
+ ::sd::ViewShellBase* pBase = dynamic_cast< ::sd::ViewShellBase *>( SfxViewShell::Current() );
+ if(pBase)
+ pViewSh = pBase->GetMainViewShell().get();
+ }
+ if( !pDoc && pViewSh )
+ pDoc = pViewSh->GetDoc();
+
+ bool bMasterView;
+ SdPage* pPage = GetCurrentPage( pViewSh, pInfo, bMasterView );
+
+ if( pPage && pDoc && !bMasterView )
+ {
+ aRepresentation = pPage->GetName();
+ }
+ else
+ {
+ DocumentType eDocType = pDoc ? pDoc->GetDocumentType() : DocumentType::Impress;
+ aRepresentation = ( ( eDocType == DocumentType::Impress )
+ ? SdResId(STR_FIELD_PLACEHOLDER_SLIDENAME)
+ : SdResId(STR_FIELD_PLACEHOLDER_PAGENAME) );
+ }
+
+ pInfo->SetRepresentation( aRepresentation );
+ }
+ else if( dynamic_cast< const SvxPagesField* >(pField) )
+ {
+ OUString aRepresentation(" ");
+
+ ::sd::ViewShell* pViewSh = pDocShell ? pDocShell->GetViewShell() : nullptr;
+ if(pViewSh == nullptr)
+ {
+ ::sd::ViewShellBase* pBase = dynamic_cast< ::sd::ViewShellBase *>( SfxViewShell::Current() );
+ if(pBase)
+ pViewSh = pBase->GetMainViewShell().get();
+ }
+ if( !pDoc && pViewSh )
+ pDoc = pViewSh->GetDoc();
+
+ bool bMasterView;
+ SdPage* pPage = GetCurrentPage( pViewSh, pInfo, bMasterView );
+
+ sal_uInt16 nPageCount = 0;
+
+ if( !bMasterView )
+ {
+ if( pPage && (pPage->GetPageKind() == PageKind::Handout) && pViewSh )
+ {
+ nPageCount = pViewSh->GetPrintedHandoutPageCount();
+ }
+ else if( pDoc )
+ {
+ nPageCount = pDoc->GetActiveSdPageCount();
+ }
+ }
+
+ if( nPageCount > 0 )
+ aRepresentation = pDoc->CreatePageNumValue(nPageCount);
+ else
+ aRepresentation = SdResId(STR_FIELD_PLACEHOLDER_COUNT);
+
+ pInfo->SetRepresentation( aRepresentation );
+ }
+ else if( (pURLField = dynamic_cast< const SvxURLField* >(pField)) != nullptr )
+ {
+ switch ( pURLField->GetFormat() )
+ {
+ case SvxURLFormat::AppDefault: //!!! adjustable at App???
+ case SvxURLFormat::Repr:
+ pInfo->SetRepresentation( pURLField->GetRepresentation() );
+ break;
+
+ case SvxURLFormat::Url:
+ pInfo->SetRepresentation( pURLField->GetURL() );
+ break;
+ }
+
+ const OUString& aURL = pURLField->GetURL();
+
+ svtools::ColorConfig aConfig;
+ svtools::ColorConfigEntry eEntry =
+ INetURLHistory::GetOrCreate()->QueryUrl( aURL ) ? svtools::LINKSVISITED : svtools::LINKS;
+ pInfo->SetTextColor( aConfig.GetColorValue(eEntry).nColor );
+ }
+ else if ( dynamic_cast< const SdrMeasureField* >(pField))
+ {
+ pInfo->SetFieldColor(std::optional<Color>()); // clear the field color
+ }
+ else if ((pCustomPropertyField = dynamic_cast<const editeng::CustomPropertyField*>(pField)) != nullptr)
+ {
+ try
+ {
+ SfxObjectShell* pObjSh = SfxObjectShell::Current();
+ if (pObjSh && pObjSh->IsLoadingFinished())
+ {
+ auto pNonConstCustomPropertyField = const_cast<editeng::CustomPropertyField*>(pCustomPropertyField);
+ OUString sCurrent = pNonConstCustomPropertyField->GetFormatted(pObjSh->getDocProperties());
+ pInfo->SetRepresentation(sCurrent);
+ }
+ else
+ pInfo->SetRepresentation(pCustomPropertyField->GetCurrentPresentation());
+ }
+ catch (...)
+ {
+ pInfo->SetRepresentation(pCustomPropertyField->GetCurrentPresentation());
+ }
+ }
+ else
+ {
+ OUString aRepresentation;
+
+ bool bHeaderField = dynamic_cast< const SvxHeaderField* >( pField ) != nullptr;
+ bool bFooterField = !bHeaderField && (dynamic_cast< const SvxFooterField* >( pField ) != nullptr );
+ bool bDateTimeField = !bHeaderField && !bFooterField && (dynamic_cast< const SvxDateTimeField* >( pField ) != nullptr);
+
+ if( bHeaderField || bFooterField || bDateTimeField )
+ {
+ sd::ViewShell* pViewSh = pDocShell ? pDocShell->GetViewShell() : nullptr;
+ bool bMasterView = false;
+ SdPage* pPage = GetCurrentPage( pViewSh, pInfo, bMasterView );
+
+ if( (pPage == nullptr) || bMasterView )
+ {
+ if( bHeaderField )
+ aRepresentation = SdResId(STR_FIELD_PLACEHOLDER_HEADER);
+ else if (bFooterField )
+ aRepresentation = SdResId(STR_FIELD_PLACEHOLDER_FOOTER);
+ else if (bDateTimeField )
+ aRepresentation = SdResId(STR_FIELD_PLACEHOLDER_DATETIME);
+ }
+ else
+ {
+ const sd::HeaderFooterSettings &rSettings = pPage->getHeaderFooterSettings();
+
+ if( bHeaderField )
+ {
+ aRepresentation = rSettings.maHeaderText;
+ }
+ else if( bFooterField )
+ {
+ aRepresentation = rSettings.maFooterText;
+ }
+ else if( bDateTimeField )
+ {
+ if( rSettings.mbDateTimeIsFixed )
+ {
+ aRepresentation = rSettings.maDateTimeText;
+ }
+ else
+ {
+ DateTime aDateTime( DateTime::SYSTEM );
+ LanguageType eLang = pInfo->GetOutliner()->GetLanguage( pInfo->GetPara(), pInfo->GetPos() );
+ aRepresentation = SvxDateTimeField::GetFormatted( aDateTime, aDateTime,
+ rSettings.meDateFormat, rSettings.meTimeFormat, *GetNumberFormatter(), eLang );
+ }
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("sd::SdModule::CalcFieldValueHdl(), unknown field type!");
+ }
+
+ if( aRepresentation.isEmpty() ) // TODO: Edit engine doesn't handle empty fields?
+ aRepresentation = " ";
+ pInfo->SetRepresentation( aRepresentation );
+ }
+}
+
+/**
+ * virtual methods for option dialog
+ */
+std::optional<SfxItemSet> SdModule::CreateItemSet( sal_uInt16 nSlot )
+{
+ ::sd::FrameView* pFrameView = nullptr;
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ SdDrawDocument* pDoc = nullptr;
+
+ // Here we set the DocType of the option dialog (not document!)
+ DocumentType eDocType = DocumentType::Impress;
+ if( nSlot == SID_SD_GRAPHIC_OPTIONS )
+ eDocType = DocumentType::Draw;
+
+ if (pDocSh)
+ {
+ pDoc = pDocSh->GetDoc();
+
+ // If the option dialog is identical to the document type,
+ // we can pass the FrameView too:
+ if( pDoc && eDocType == pDoc->GetDocumentType() )
+ pFrameView = pDocSh->GetFrameView();
+
+ ::sd::ViewShell* pViewShell = pDocSh->GetViewShell();
+ if (pViewShell != nullptr)
+ pViewShell->WriteFrameViewData();
+ }
+
+ SdOptions* pOptions = GetSdOptions(eDocType);
+
+ // Pool has by default MapUnit Twips (Awgh!)
+ SfxItemPool& rPool = GetPool();
+ rPool.SetDefaultMetric( MapUnit::Map100thMM );
+
+ SfxItemSetFixed<
+ SID_ATTR_GRID_OPTIONS, SID_ATTR_GRID_OPTIONS,
+ SID_ATTR_METRIC, SID_ATTR_METRIC,
+ SID_ATTR_DEFTABSTOP, SID_ATTR_DEFTABSTOP,
+ ATTR_OPTIONS_LAYOUT, ATTR_OPTIONS_SCALE_END> aRet(rPool);
+
+ // TP_OPTIONS_LAYOUT:
+ aRet.Put( SdOptionsLayoutItem( pOptions, pFrameView ) );
+
+ sal_uInt16 nDefTab = 0;
+ if( pFrameView)
+ nDefTab = pDoc->GetDefaultTabulator();
+ else
+ nDefTab = pOptions->GetDefTab();
+ aRet.Put( SfxUInt16Item( SID_ATTR_DEFTABSTOP, nDefTab ) );
+
+ FieldUnit nMetric = FieldUnit(0xffff);
+ if( pFrameView)
+ nMetric = pDoc->GetUIUnit();
+ else
+ nMetric = static_cast<FieldUnit>(pOptions->GetMetric());
+
+ if( nMetric == FieldUnit(0xffff) )
+ nMetric = GetFieldUnit();
+
+ aRet.Put( SfxUInt16Item( SID_ATTR_METRIC, static_cast<sal_uInt16>(nMetric) ) );
+
+ // TP_OPTIONS_MISC:
+ SdOptionsMiscItem aSdOptionsMiscItem( pOptions, pFrameView );
+ if ( pFrameView )
+ {
+ aSdOptionsMiscItem.GetOptionsMisc().SetSummationOfParagraphs( pDoc->IsSummationOfParagraphs() );
+ aSdOptionsMiscItem.GetOptionsMisc().SetPrinterIndependentLayout (
+ static_cast<sal_uInt16>(pDoc->GetPrinterIndependentLayout()));
+ }
+ aRet.Put( aSdOptionsMiscItem );
+
+ // TP_OPTIONS_SNAP:
+ aRet.Put( SdOptionsSnapItem( pOptions, pFrameView ) );
+
+ // TP_SCALE:
+ sal_uInt32 nW = 10;
+ sal_uInt32 nH = 10;
+ sal_Int32 nX;
+ sal_Int32 nY;
+ if( pDocSh )
+ {
+ SdrPage* pPage = pDoc->GetSdPage(0, PageKind::Standard);
+ Size aSize(pPage->GetSize());
+ nW = aSize.Width();
+ nH = aSize.Height();
+ }
+
+ if(pFrameView)
+ {
+ const Fraction& rFraction = pDoc->GetUIScale();
+ nX=rFraction.GetNumerator();
+ nY=rFraction.GetDenominator();
+ }
+ else
+ {
+ // Get options from configuration file
+ pOptions->GetScale( nX, nY );
+ }
+
+ aRet.Put( SfxInt32Item( ATTR_OPTIONS_SCALE_X, nX ) );
+ aRet.Put( SfxInt32Item( ATTR_OPTIONS_SCALE_Y, nY ) );
+ aRet.Put( SfxUInt32Item( ATTR_OPTIONS_SCALE_WIDTH, nW ) );
+ aRet.Put( SfxUInt32Item( ATTR_OPTIONS_SCALE_HEIGHT, nH ) );
+
+ // TP_OPTIONS_PRINT:
+ aRet.Put( SdOptionsPrintItem( pOptions ) );
+
+ // RID_SVXPAGE_GRID:
+ aRet.Put( SdOptionsGridItem( pOptions ) );
+
+ return aRet;
+}
+
+void SdModule::ApplyItemSet( sal_uInt16 nSlot, const SfxItemSet& rSet )
+{
+ bool bNewDefTab = false;
+ bool bNewPrintOptions = false;
+ bool bMiscOptions = false;
+
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ SdDrawDocument* pDoc = nullptr;
+ // Here we set the DocType of the option dialog (not document!)
+ DocumentType eDocType = DocumentType::Impress;
+ if( nSlot == SID_SD_GRAPHIC_OPTIONS )
+ eDocType = DocumentType::Draw;
+
+ ::sd::ViewShell* pViewShell = nullptr;
+
+ if (pDocSh)
+ {
+ pDoc = pDocSh->GetDoc();
+
+ pViewShell = pDocSh->GetViewShell();
+ if (pViewShell != nullptr)
+ pViewShell->WriteFrameViewData();
+ }
+ SdOptions* pOptions = GetSdOptions(eDocType);
+ // Grid
+ if( const SdOptionsGridItem* pGridItem = static_cast<const SdOptionsGridItem*>(rSet.GetItemIfSet( SID_ATTR_GRID_OPTIONS, false )) )
+ {
+ pGridItem->SetOptions( pOptions );
+ }
+
+ // Layout
+ if( const SdOptionsLayoutItem* pLayoutItem = rSet.GetItemIfSet( ATTR_OPTIONS_LAYOUT, false ))
+ {
+ pLayoutItem->SetOptions( pOptions );
+ }
+
+ // Metric
+ if( const SfxUInt16Item* pItem = rSet.GetItemIfSet( SID_ATTR_METRIC, false ) )
+ {
+ if( pDoc && eDocType == pDoc->GetDocumentType() )
+ PutItem( *pItem );
+ pOptions->SetMetric( pItem->GetValue() );
+ }
+ sal_uInt16 nDefTab = pOptions->GetDefTab();
+ // Default-Tabulator
+ if( const SfxUInt16Item* pItem = rSet.GetItemIfSet( SID_ATTR_DEFTABSTOP, false ) )
+ {
+ nDefTab = pItem->GetValue();
+ pOptions->SetDefTab( nDefTab );
+
+ bNewDefTab = true;
+ }
+
+ // Scale
+ if( const SfxInt32Item* pItem = rSet.GetItemIfSet( ATTR_OPTIONS_SCALE_X, false ) )
+ {
+ sal_Int32 nX = pItem->GetValue();
+ pItem = rSet.GetItemIfSet( ATTR_OPTIONS_SCALE_Y, false );
+ if( pItem )
+ {
+ sal_Int32 nY = pItem->GetValue();
+ pOptions->SetScale( nX, nY );
+
+ // Apply to document only if doc type match
+ if( pDocSh && pDoc && eDocType == pDoc->GetDocumentType() )
+ {
+ pDoc->SetUIScale( Fraction( nX, nY ) );
+ if( pViewShell )
+ pViewShell->SetRuler( pViewShell->HasRuler() );
+ }
+ }
+ }
+
+ // Misc
+ const SdOptionsMiscItem* pMiscItem = rSet.GetItemIfSet( ATTR_OPTIONS_MISC, false);
+ if( pMiscItem )
+ {
+ pMiscItem->SetOptions( pOptions );
+ bMiscOptions = true;
+ }
+
+ // Snap
+ const SdOptionsSnapItem* pSnapItem = rSet.GetItemIfSet( ATTR_OPTIONS_SNAP, false );
+ if( pSnapItem )
+ {
+ pSnapItem->SetOptions( pOptions );
+ }
+
+ SfxItemSetFixed<SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
+ SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC,
+ ATTR_OPTIONS_PRINT, ATTR_OPTIONS_PRINT> aPrintSet( GetPool() );
+
+ // Print
+ const SdOptionsPrintItem* pPrintItem = rSet.GetItemIfSet( ATTR_OPTIONS_PRINT, false);
+ if( pPrintItem )
+ {
+ pPrintItem->SetOptions( pOptions );
+
+ // set PrintOptionsSet
+ SdOptionsPrintItem aPrintItem( pOptions );
+ SfxFlagItem aFlagItem( SID_PRINTER_CHANGESTODOC );
+ SfxPrinterChangeFlags nFlags =
+ (aPrintItem.GetOptionsPrint().IsWarningSize() ? SfxPrinterChangeFlags::CHG_SIZE : SfxPrinterChangeFlags::NONE) |
+ (aPrintItem.GetOptionsPrint().IsWarningOrientation() ? SfxPrinterChangeFlags::CHG_ORIENTATION : SfxPrinterChangeFlags::NONE);
+ aFlagItem.SetValue( static_cast<int>(nFlags) );
+
+ aPrintSet.Put( aPrintItem );
+ aPrintSet.Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aPrintItem.GetOptionsPrint().IsWarningPrinter() ) );
+ aPrintSet.Put( aFlagItem );
+
+ bNewPrintOptions = true;
+ }
+
+ // Only if also the document type matches...
+ if( pDocSh && pDoc && eDocType == pDoc->GetDocumentType() )
+ {
+ if( bNewPrintOptions )
+ {
+ pDocSh->GetPrinter(true)->SetOptions( aPrintSet );
+ }
+
+ // set DefTab at Model
+ if( bNewDefTab )
+ {
+ SdDrawDocument* pDocument = pDocSh->GetDoc();
+ pDocument->SetDefaultTabulator( nDefTab );
+
+ SdOutliner* pOutl = pDocument->GetOutliner( false );
+ if( pOutl )
+ pOutl->SetDefTab( nDefTab );
+
+ SdOutliner* pInternalOutl = pDocument->GetInternalOutliner( false );
+ if( pInternalOutl )
+ pInternalOutl->SetDefTab( nDefTab );
+ }
+ if ( bMiscOptions )
+ {
+ pDoc->SetSummationOfParagraphs( pMiscItem->GetOptionsMisc().IsSummationOfParagraphs() );
+ EEControlBits nSum = pMiscItem->GetOptionsMisc().IsSummationOfParagraphs() ? EEControlBits::ULSPACESUMMATION : EEControlBits::NONE;
+ EEControlBits nCntrl;
+
+ SdDrawDocument* pDocument = pDocSh->GetDoc();
+ SdrOutliner& rOutl = pDocument->GetDrawOutliner();
+ nCntrl = rOutl.GetControlWord() &~ EEControlBits::ULSPACESUMMATION;
+ rOutl.SetControlWord( nCntrl | nSum );
+ SdOutliner* pOutl = pDocument->GetOutliner( false );
+ if( pOutl )
+ {
+ nCntrl = pOutl->GetControlWord() &~ EEControlBits::ULSPACESUMMATION;
+ pOutl->SetControlWord( nCntrl | nSum );
+ }
+ pOutl = pDocument->GetInternalOutliner( false );
+ if( pOutl )
+ {
+ nCntrl = pOutl->GetControlWord() &~ EEControlBits::ULSPACESUMMATION;
+ pOutl->SetControlWord( nCntrl | nSum );
+ }
+
+ // Set printer independent layout mode.
+ if( pDoc->GetPrinterIndependentLayout() != pMiscItem->GetOptionsMisc().GetPrinterIndependentLayout() )
+ pDoc->SetPrinterIndependentLayout (pMiscItem->GetOptionsMisc().GetPrinterIndependentLayout());
+ }
+ }
+
+ pOptions->StoreConfig();
+
+ // Only if also the document type matches...
+ if( pDocSh && pDoc && eDocType == pDoc->GetDocumentType() )
+ {
+ FieldUnit eUIUnit = static_cast<FieldUnit>(pOptions->GetMetric());
+ pDoc->SetUIUnit(eUIUnit);
+
+ if (pViewShell)
+ {
+ // make sure no one is in text edit mode, cause there
+ // are some pointers remembered else (!)
+ if(pViewShell->GetView())
+ pViewShell->GetView()->SdrEndTextEdit();
+
+ ::sd::FrameView* pFrame = pViewShell->GetFrameView();
+ pFrame->Update(pOptions);
+ pViewShell->ReadFrameViewData(pFrame);
+ pViewShell->SetUIUnit(eUIUnit);
+ pViewShell->SetDefTabHRuler( nDefTab );
+ }
+ }
+
+ if( pViewShell && pViewShell->GetViewFrame() )
+ pViewShell->GetViewFrame()->GetBindings().InvalidateAll( true );
+}
+
+std::unique_ptr<SfxTabPage> SdModule::CreateTabPage( sal_uInt16 nId, weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet )
+{
+ std::unique_ptr<SfxTabPage> xRet;
+ SfxAllItemSet aSet(*(rSet.GetPool()));
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+
+ switch(nId)
+ {
+ case SID_SD_TP_CONTENTS:
+ case SID_SI_TP_CONTENTS:
+ {
+ ::CreateTabPage fnCreatePage = pFact->GetSdOptionsContentsTabPageCreatorFunc();
+ if( fnCreatePage )
+ xRet = (*fnCreatePage)( pPage, pController, &rSet );
+ }
+ break;
+ case SID_SD_TP_SNAP:
+ case SID_SI_TP_SNAP:
+ {
+ ::CreateTabPage fnCreatePage = pFact->GetSdOptionsSnapTabPageCreatorFunc();
+ if( fnCreatePage )
+ xRet = (*fnCreatePage)( pPage, pController, &rSet );
+ }
+ break;
+ case SID_SD_TP_PRINT:
+ case SID_SI_TP_PRINT:
+ {
+ ::CreateTabPage fnCreatePage = pFact->GetSdPrintOptionsTabPageCreatorFunc();
+ if( fnCreatePage )
+ {
+ xRet = (*fnCreatePage)( pPage, pController, &rSet );
+ if(SID_SD_TP_PRINT == nId)
+ aSet.Put (SfxUInt32Item(SID_SDMODE_FLAG,SD_DRAW_MODE));
+ xRet->PageCreated(aSet);
+ }
+ }
+ break;
+ case SID_SI_TP_MISC:
+ case SID_SD_TP_MISC:
+ {
+ ::CreateTabPage fnCreatePage = pFact->GetSdOptionsMiscTabPageCreatorFunc();
+ if( fnCreatePage )
+ {
+ xRet = (*fnCreatePage)( pPage, pController, &rSet );
+ if(SID_SD_TP_MISC == nId)
+ aSet.Put (SfxUInt32Item(SID_SDMODE_FLAG,SD_DRAW_MODE));
+ else
+ aSet.Put (SfxUInt32Item(SID_SDMODE_FLAG,SD_IMPRESS_MODE));
+ xRet->PageCreated(aSet);
+ }
+ }
+ break;
+ case RID_SVXPAGE_TEXTANIMATION :
+ {
+ SfxAbstractDialogFactory* pSfxFact = SfxAbstractDialogFactory::Create();
+ ::CreateTabPage fnCreatePage = pSfxFact->GetTabPageCreatorFunc( nId );
+ if ( fnCreatePage )
+ xRet = (*fnCreatePage)( pPage, pController, &rSet );
+ }
+ break;
+ }
+ DBG_ASSERT( xRet, "SdModule::CreateTabPage(): no valid ID for TabPage!" );
+
+ return xRet;
+}
+
+std::optional<SfxStyleFamilies> SdModule::CreateStyleFamilies()
+{
+ SfxStyleFamilies aStyleFamilies;
+
+ aStyleFamilies.emplace_back(SfxStyleFamily::Para,
+ SdResId(STR_GRAPHICS_STYLE_FAMILY),
+ BMP_STYLES_FAMILY_GRAPHICS,
+ RID_GRAPHICSTYLEFAMILY, SD_MOD()->GetResLocale());
+
+ aStyleFamilies.emplace_back(SfxStyleFamily::Pseudo,
+ SdResId(STR_PRESENTATIONS_STYLE_FAMILY),
+ BMP_STYLES_FAMILY_PRESENTATIONS,
+ RID_PRESENTATIONSTYLEFAMILY, SD_MOD()->GetResLocale());
+
+ return aStyleFamilies;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/app/sdpopup.cxx b/sd/source/ui/app/sdpopup.cxx
new file mode 100644
index 000000000..4aafd2848
--- /dev/null
+++ b/sd/source/ui/app/sdpopup.cxx
@@ -0,0 +1,318 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <editeng/flditem.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <unotools/useroptions.hxx>
+#include <vcl/svapp.hxx>
+
+#include <strings.hrc>
+#include <sdpopup.hxx>
+#include <sdresid.hxx>
+#include <sdmod.hxx>
+#include <DrawDocShell.hxx>
+
+/*
+ * Popup menu for editing of field command
+ */
+SdFieldPopup::SdFieldPopup(const SvxFieldData* pInField, LanguageType eLanguage)
+ : m_xBuilder(Application::CreateBuilder(nullptr, "modules/simpress/ui/fieldmenu.ui"))
+ , m_xPopup(m_xBuilder->weld_menu("menu"))
+ , m_pField(pInField)
+{
+ Fill(eLanguage);
+}
+
+SdFieldPopup::~SdFieldPopup()
+{
+}
+
+void SdFieldPopup::Fill( LanguageType eLanguage )
+{
+ sal_uInt16 nID = 1;
+ m_xPopup->append_radio(OUString::number(nID++), SdResId(STR_FIX));
+ m_xPopup->append_radio(OUString::number(nID++), SdResId(STR_VAR));
+ m_xPopup->append_separator("separator1");
+
+ if( auto pDateField = dynamic_cast< const SvxDateField *>( m_pField ) )
+ {
+ SvxDateField aDateField( *pDateField );
+
+ if (pDateField->GetType() == SvxDateType::Fix)
+ m_xPopup->set_active("1", true);
+ else
+ m_xPopup->set_active("2", true);
+
+ //SvxDateFormat::AppDefault, // is not used
+ //SvxDateFormat::System, // is not used
+ m_xPopup->append_radio(OUString::number(nID++), SdResId(STR_STANDARD_SMALL));
+ m_xPopup->append_radio(OUString::number(nID++), SdResId(STR_STANDARD_BIG));
+
+ SvNumberFormatter* pNumberFormatter = SD_MOD()->GetNumberFormatter();
+ aDateField.SetFormat( SvxDateFormat::A ); // 13.02.96
+ m_xPopup->append_radio(OUString::number(nID++), aDateField.GetFormatted(*pNumberFormatter, eLanguage));
+ aDateField.SetFormat( SvxDateFormat::B ); // 13.02.1996
+ m_xPopup->append_radio(OUString::number(nID++), aDateField.GetFormatted(*pNumberFormatter, eLanguage));
+ aDateField.SetFormat( SvxDateFormat::C ); // 13.Feb 1996
+ m_xPopup->append_radio(OUString::number(nID++), aDateField.GetFormatted(*pNumberFormatter, eLanguage));
+
+ aDateField.SetFormat( SvxDateFormat::D ); // 13.Februar 1996
+ m_xPopup->append_radio(OUString::number(nID++), aDateField.GetFormatted(*pNumberFormatter, eLanguage));
+ aDateField.SetFormat( SvxDateFormat::E ); // Die, 13.Februar 1996
+ m_xPopup->append_radio(OUString::number(nID++), aDateField.GetFormatted(*pNumberFormatter, eLanguage));
+ aDateField.SetFormat( SvxDateFormat::F ); // Dienstag, 13.Februar 1996
+ m_xPopup->append_radio(OUString::number(nID++), aDateField.GetFormatted(*pNumberFormatter, eLanguage));
+
+ m_xPopup->set_active(OString::number(static_cast<sal_uInt16>( pDateField->GetFormat() ) + 1), true); // - 2 + 3 !
+ }
+ else if( auto pTimeField = dynamic_cast< const SvxExtTimeField *>( m_pField ) )
+ {
+ SvxExtTimeField aTimeField( *pTimeField );
+
+ if( pTimeField->GetType() == SvxTimeType::Fix )
+ m_xPopup->set_active("1", true);
+ else
+ m_xPopup->set_active("2", true);
+
+ //SvxTimeFormat::AppDefault, // is not used
+ //SvxTimeFormat::System, // is not used
+ m_xPopup->append_radio(OUString::number(nID++), SdResId(STR_STANDARD_NORMAL));
+
+ SvNumberFormatter* pNumberFormatter = SD_MOD()->GetNumberFormatter();
+ aTimeField.SetFormat( SvxTimeFormat::HH24_MM ); // 13:49
+ m_xPopup->append_radio(OUString::number(nID++), aTimeField.GetFormatted(*pNumberFormatter, eLanguage));
+ aTimeField.SetFormat( SvxTimeFormat::HH24_MM_SS ); // 13:49:38
+ m_xPopup->append_radio(OUString::number(nID++), aTimeField.GetFormatted(*pNumberFormatter, eLanguage));
+ aTimeField.SetFormat( SvxTimeFormat::HH24_MM_SS_00 ); // 13:49:38.78
+ m_xPopup->append_radio(OUString::number(nID++), aTimeField.GetFormatted(*pNumberFormatter, eLanguage));
+
+ aTimeField.SetFormat( SvxTimeFormat::HH12_MM ); // 01:49
+ m_xPopup->append_radio(OUString::number(nID++), aTimeField.GetFormatted(*pNumberFormatter, eLanguage));
+ aTimeField.SetFormat( SvxTimeFormat::HH12_MM_SS ); // 01:49:38
+ m_xPopup->append_radio(OUString::number(nID++), aTimeField.GetFormatted(*pNumberFormatter, eLanguage));
+ aTimeField.SetFormat( SvxTimeFormat::HH12_MM_SS_00 ); // 01:49:38.78
+ m_xPopup->append_radio(OUString::number(nID++), aTimeField.GetFormatted(*pNumberFormatter, eLanguage));
+ //SvxTimeFormat::HH12_MM_AMPM, // 01:49 PM
+ //SvxTimeFormat::HH12_MM_SS_AMPM, // 01:49:38 PM
+ //SvxTimeFormat::HH12_MM_SS_00_AMPM // 01:49:38.78 PM
+
+ m_xPopup->set_active(OString::number(static_cast<sal_uInt16>( pTimeField->GetFormat() ) + 1), true); // - 2 + 3 !
+ }
+ else if( auto pFileField = dynamic_cast< const SvxExtFileField *>( m_pField ) )
+ {
+ //SvxExtFileField aFileField( *pFileField );
+
+ if( pFileField->GetType() == SvxFileType::Fix )
+ m_xPopup->set_active("1", true);
+ else
+ m_xPopup->set_active("2", true);
+
+ m_xPopup->append_radio(OUString::number(nID++), SdResId(STR_FILEFORMAT_NAME_EXT));
+ m_xPopup->append_radio(OUString::number(nID++), SdResId(STR_FILEFORMAT_FULLPATH));
+ m_xPopup->append_radio(OUString::number(nID++), SdResId(STR_FILEFORMAT_PATH));
+ m_xPopup->append_radio(OUString::number(nID++), SdResId(STR_FILEFORMAT_NAME));
+
+ m_xPopup->set_active(OString::number(static_cast<sal_uInt16>( pFileField->GetFormat() ) + 3), true);
+ }
+ else if( auto pAuthorField = dynamic_cast< const SvxAuthorField *>( m_pField ) )
+ {
+ SvxAuthorField aAuthorField( *pAuthorField );
+
+ if( pAuthorField->GetType() == SvxAuthorType::Fix )
+ m_xPopup->set_active("1", true);
+ else
+ m_xPopup->set_active("2", true);
+
+ for( sal_uInt16 i = 0; i < 4; i++ )
+ {
+ aAuthorField.SetFormat( static_cast<SvxAuthorFormat>(i) );
+ m_xPopup->append_radio(OUString::number(nID++), aAuthorField.GetFormatted());
+ }
+ m_xPopup->set_active(OString::number(static_cast<sal_uInt16>( pAuthorField->GetFormat() ) + 3), true);
+ }
+}
+
+void SdFieldPopup::Execute(weld::Window* pParent, const tools::Rectangle& rRect)
+{
+ OString sIdent = m_xPopup->popup_at_rect(pParent, rRect);
+ if (sIdent.isEmpty())
+ return;
+
+ if (sIdent == "1" || sIdent == "2")
+ {
+ m_xPopup->set_active("1", sIdent == "1");
+ m_xPopup->set_active("2", sIdent == "2");
+ }
+ else
+ {
+ int nCount = m_xPopup->n_children();
+ for (int i = 3; i < nCount; i++)
+ m_xPopup->set_active(
+ OString::number(i), sIdent == std::string_view(OString::number(i)));
+ }
+}
+
+/**
+ * Returns a new field, owned by caller.
+ * Returns NULL if nothing changed.
+ */
+SvxFieldData* SdFieldPopup::GetField()
+{
+ SvxFieldData* pNewField = nullptr;
+
+ sal_uInt16 nCount = m_xPopup->n_children();
+
+ if( auto pDateField = dynamic_cast< const SvxDateField *>( m_pField ) )
+ {
+ SvxDateType eType;
+ SvxDateFormat eFormat;
+ sal_uInt16 i;
+
+ if (m_xPopup->get_active("1"))
+ eType = SvxDateType::Fix;
+ else
+ eType = SvxDateType::Var;
+
+ for( i = 3; i < nCount; i++ )
+ {
+ if (m_xPopup->get_active(OString::number(i)))
+ break;
+ }
+ eFormat = static_cast<SvxDateFormat>( i - 1 );
+
+ if( pDateField->GetFormat() != eFormat ||
+ pDateField->GetType() != eType )
+ {
+ pNewField = new SvxDateField( *pDateField );
+ static_cast<SvxDateField*>( pNewField )->SetType( eType );
+ static_cast<SvxDateField*>( pNewField )->SetFormat( eFormat );
+
+ if( (pDateField->GetType() == SvxDateType::Var) && (eType == SvxDateType::Fix) )
+ {
+ Date aDate( Date::SYSTEM );
+ static_cast<SvxDateField*>( pNewField )->SetFixDate( aDate );
+ }
+ }
+ }
+ else if( auto pTimeField = dynamic_cast< const SvxExtTimeField *>( m_pField ) )
+ {
+ SvxTimeType eType;
+ SvxTimeFormat eFormat;
+ sal_uInt16 i;
+
+ if (m_xPopup->get_active("1"))
+ eType = SvxTimeType::Fix;
+ else
+ eType = SvxTimeType::Var;
+
+ for( i = 3; i < nCount; i++ )
+ {
+ if (m_xPopup->get_active(OString::number(i)))
+ break;
+ }
+ eFormat = static_cast<SvxTimeFormat>( i - 1 );
+
+ if( pTimeField->GetFormat() != eFormat ||
+ pTimeField->GetType() != eType )
+ {
+ pNewField = new SvxExtTimeField( *pTimeField );
+ static_cast<SvxExtTimeField*>( pNewField )->SetType( eType );
+ static_cast<SvxExtTimeField*>( pNewField )->SetFormat( eFormat );
+
+ if( (pTimeField->GetType() == SvxTimeType::Var) && (eType == SvxTimeType::Fix) )
+ {
+ tools::Time aTime( tools::Time::SYSTEM );
+ static_cast<SvxExtTimeField*>( pNewField )->SetFixTime( aTime );
+ }
+
+ }
+ }
+ else if( auto pFileField = dynamic_cast< const SvxExtFileField *>( m_pField ) )
+ {
+ SvxFileType eType;
+ SvxFileFormat eFormat;
+ sal_uInt16 i;
+
+ if (m_xPopup->get_active("1"))
+ eType = SvxFileType::Fix;
+ else
+ eType = SvxFileType::Var;
+
+ for( i = 3; i < nCount; i++ )
+ {
+ if (m_xPopup->get_active(OString::number(i)))
+ break;
+ }
+ eFormat = static_cast<SvxFileFormat>( i - 3 );
+
+ if( pFileField->GetFormat() != eFormat ||
+ pFileField->GetType() != eType )
+ {
+ ::sd::DrawDocShell* pDocSh = dynamic_cast<::sd::DrawDocShell* >( SfxObjectShell::Current() );
+
+ if( pDocSh )
+ {
+ OUString aName;
+ if( pDocSh->HasName() )
+ aName = pDocSh->GetMedium()->GetName();
+
+ // Get current filename, not the one stored in the old field
+ pNewField = new SvxExtFileField( aName );
+ static_cast<SvxExtFileField*>( pNewField )->SetType( eType );
+ static_cast<SvxExtFileField*>( pNewField )->SetFormat( eFormat );
+ }
+ }
+ }
+ else if( auto pAuthorField = dynamic_cast< const SvxAuthorField *>( m_pField ) )
+ {
+ SvxAuthorType eType;
+ SvxAuthorFormat eFormat;
+ sal_uInt16 i;
+
+ if (m_xPopup->get_active("1"))
+ eType = SvxAuthorType::Fix;
+ else
+ eType = SvxAuthorType::Var;
+
+ for( i = 3; i < nCount; i++ )
+ {
+ if (m_xPopup->get_active(OString::number(i)))
+ break;
+ }
+ eFormat = static_cast<SvxAuthorFormat>( i - 3 );
+
+ if( pAuthorField->GetFormat() != eFormat ||
+ pAuthorField->GetType() != eType )
+ {
+ // Get current state of address, not the old one
+ SvtUserOptions aUserOptions;
+ pNewField = new SvxAuthorField( aUserOptions.GetFirstName(), aUserOptions.GetLastName(), aUserOptions.GetID() );
+ static_cast<SvxAuthorField*>( pNewField )->SetType( eType );
+ static_cast<SvxAuthorField*>( pNewField )->SetFormat( eFormat );
+ }
+ }
+ return pNewField;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/app/sdxfer.cxx b/sd/source/ui/app/sdxfer.cxx
new file mode 100644
index 000000000..67016fd19
--- /dev/null
+++ b/sd/source/ui/app/sdxfer.cxx
@@ -0,0 +1,807 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <comphelper/fileformat.h>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/tempfile.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdotext.hxx>
+#include <editeng/outlobj.hxx>
+#include <sot/storage.hxx>
+#include <editeng/editobj.hxx>
+#include <o3tl/safeint.hxx>
+#include <svx/svdobjkind.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <sot/formats.hxx>
+#include <svl/urlbmk.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <unotools/streamwrap.hxx>
+
+#include <svx/svdotable.hxx>
+#include <svx/unomodel.hxx>
+#include <svx/svditer.hxx>
+#include <sfx2/docfile.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <svtools/embedtransfer.hxx>
+#include <DrawDocShell.hxx>
+#include <View.hxx>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <stlpool.hxx>
+#include <sdxfer.hxx>
+#include <unomodel.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::clipboard;
+
+constexpr sal_uInt32 SDTRANSFER_OBJECTTYPE_DRAWMODEL = 1;
+constexpr sal_uInt32 SDTRANSFER_OBJECTTYPE_DRAWOLE = 2;
+
+SdTransferable::SdTransferable( SdDrawDocument* pSrcDoc, ::sd::View* pWorkView, bool bInitOnGetData )
+: mpPageDocShell( nullptr )
+, mpSdView( pWorkView )
+, mpSdViewIntern( pWorkView )
+, mpSdDrawDocument( nullptr )
+, mpSdDrawDocumentIntern( nullptr )
+, mpSourceDoc( pSrcDoc )
+, mpVDev( nullptr )
+, mbInternalMove( false )
+, mbOwnDocument( false )
+, mbOwnView( false )
+, mbLateInit( bInitOnGetData )
+, mbPageTransferable( false )
+, mbPageTransferablePersistent( false )
+{
+ if( mpSourceDoc )
+ StartListening( *mpSourceDoc );
+
+ if( pWorkView )
+ StartListening( *pWorkView );
+
+ if( !mbLateInit )
+ CreateData();
+}
+
+SdTransferable::~SdTransferable()
+{
+ SolarMutexGuard g;
+
+ if( mpSourceDoc )
+ EndListening( *mpSourceDoc );
+
+ if( mpSdView )
+ EndListening( *const_cast< sd::View *>( mpSdView) );
+
+ ObjectReleased();
+
+ if( mbOwnView )
+ delete mpSdViewIntern;
+
+ mpOLEDataHelper.reset();
+
+ if( maDocShellRef.is() )
+ {
+ SfxObjectShell* pObj = maDocShellRef.get();
+ ::sd::DrawDocShell* pDocSh = static_cast< ::sd::DrawDocShell*>(pObj);
+ pDocSh->DoClose();
+ }
+
+ maDocShellRef.clear();
+
+ if( mbOwnDocument )
+ delete mpSdDrawDocumentIntern;
+
+ mpGraphic.reset();
+ mpBookmark.reset();
+ mpImageMap.reset();
+
+ mpVDev.disposeAndClear();
+ mpObjDesc.reset();
+
+ //call explicitly at end of dtor to be covered by above SolarMutex
+ maUserData.clear();
+}
+
+void SdTransferable::CreateObjectReplacement( SdrObject* pObj )
+{
+ if( !pObj )
+ return;
+
+ mpOLEDataHelper.reset();
+ mpGraphic.reset();
+ mpBookmark.reset();
+ mpImageMap.reset();
+
+ if( auto pOleObj = dynamic_cast< SdrOle2Obj* >( pObj ) )
+ {
+ try
+ {
+ uno::Reference < embed::XEmbeddedObject > xObj = pOleObj->GetObjRef();
+ uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
+ if( xObj.is() && xPersist.is() && xPersist->hasEntry() )
+ {
+ mpOLEDataHelper.reset( new TransferableDataHelper( new SvEmbedTransferHelper( xObj, pOleObj->GetGraphic(), pOleObj->GetAspect() ) ) );
+
+ // TODO/LATER: the standalone handling of the graphic should not be used any more in future
+ // The EmbedDataHelper should bring the graphic in future
+ const Graphic* pObjGr = pOleObj->GetGraphic();
+ if ( pObjGr )
+ mpGraphic.reset( new Graphic( *pObjGr ) );
+ }
+ }
+ catch( uno::Exception& )
+ {}
+ }
+ else if( dynamic_cast< const SdrGrafObj *>( pObj ) != nullptr && (mpSourceDoc && !SdDrawDocument::GetAnimationInfo( pObj )) )
+ {
+ mpGraphic.reset( new Graphic( static_cast< SdrGrafObj* >( pObj )->GetTransformedGraphic() ) );
+ }
+ else if( pObj->IsUnoObj() && SdrInventor::FmForm == pObj->GetObjInventor() && ( pObj->GetObjIdentifier() == SdrObjKind::FormButton ) )
+ {
+ SdrUnoObj* pUnoCtrl = static_cast< SdrUnoObj* >( pObj );
+
+ if (SdrInventor::FmForm == pUnoCtrl->GetObjInventor())
+ {
+ const Reference< css::awt::XControlModel >& xControlModel( pUnoCtrl->GetUnoControlModel() );
+
+ if( !xControlModel.is() )
+ return;
+
+ Reference< css::beans::XPropertySet > xPropSet( xControlModel, UNO_QUERY );
+
+ if( !xPropSet.is() )
+ return;
+
+ css::form::FormButtonType eButtonType;
+ Any aTmp( xPropSet->getPropertyValue( "ButtonType" ) );
+
+ if( aTmp >>= eButtonType )
+ {
+ OUString aLabel, aURL;
+
+ xPropSet->getPropertyValue( "Label" ) >>= aLabel;
+ xPropSet->getPropertyValue( "TargetURL" ) >>= aURL;
+
+ mpBookmark.reset( new INetBookmark( aURL, aLabel ) );
+ }
+ }
+ }
+ else if( auto pTextObj = dynamic_cast< SdrTextObj *>( pObj ) )
+ {
+ const OutlinerParaObject* pPara;
+
+ if( (pPara = pTextObj->GetOutlinerParaObject()) != nullptr )
+ {
+ const SvxFieldItem* pField;
+
+ if( (pField = pPara->GetTextObject().GetField()) != nullptr )
+ {
+ const SvxFieldData* pData = pField->GetField();
+
+ if( auto pURL = dynamic_cast< const SvxURLField *>( pData ) )
+ {
+ // #i63399# This special code identifies TextFrames which have just a URL
+ // as content and directly add this to the clipboard, probably to avoid adding
+ // an unnecessary DrawObject to the target where paste may take place. This is
+ // wanted only for SdrObjects with no fill and no line, else it is necessary to
+ // use the whole SdrObject. Test here for Line/FillStyle and take shortcut only
+ // when both are unused
+ if(!pObj->HasFillStyle() && !pObj->HasLineStyle())
+ {
+ mpBookmark.reset( new INetBookmark( pURL->GetURL(), pURL->GetRepresentation() ) );
+ }
+ }
+ }
+ }
+ }
+
+ SvxIMapInfo* pInfo = SvxIMapInfo::GetIMapInfo( pObj );
+
+ if( pInfo )
+ mpImageMap.reset( new ImageMap( pInfo->GetImageMap() ) );
+}
+
+void SdTransferable::CreateData()
+{
+ if( mpSdDrawDocument && !mpSdViewIntern )
+ {
+ mbOwnView = true;
+
+ SdPage* pPage = mpSdDrawDocument->GetSdPage(0, PageKind::Standard);
+
+ if( pPage && 1 == pPage->GetObjCount() )
+ CreateObjectReplacement( pPage->GetObj( 0 ) );
+
+ mpVDev = VclPtr<VirtualDevice>::Create( *Application::GetDefaultDevice() );
+ mpVDev->SetMapMode( MapMode( mpSdDrawDocumentIntern->GetScaleUnit(), Point(), mpSdDrawDocumentIntern->GetScaleFraction(), mpSdDrawDocumentIntern->GetScaleFraction() ) );
+ mpSdViewIntern = new ::sd::View( *mpSdDrawDocumentIntern, mpVDev );
+ mpSdViewIntern->EndListening(*mpSdDrawDocumentIntern );
+ mpSdViewIntern->hideMarkHandles();
+ SdrPageView* pPageView = mpSdViewIntern->ShowSdrPage(pPage);
+ mpSdViewIntern->MarkAllObj(pPageView);
+ }
+ else if( mpSdView && !mpSdDrawDocumentIntern )
+ {
+ const SdrMarkList& rMarkList = mpSdView->GetMarkedObjectList();
+
+ if( rMarkList.GetMarkCount() == 1 )
+ CreateObjectReplacement( rMarkList.GetMark( 0 )->GetMarkedSdrObj() );
+
+ if( mpSourceDoc )
+ mpSourceDoc->CreatingDataObj(this);
+ mpSdDrawDocumentIntern = static_cast<SdDrawDocument*>( mpSdView->CreateMarkedObjModel().release() );
+ if( mpSourceDoc )
+ mpSourceDoc->CreatingDataObj(nullptr);
+
+ if( !maDocShellRef.is() && mpSdDrawDocumentIntern->GetDocSh() )
+ maDocShellRef = mpSdDrawDocumentIntern->GetDocSh();
+
+ if( !maDocShellRef.is() )
+ {
+ OSL_FAIL( "SdTransferable::CreateData(), failed to create a model with persist, clipboard operation will fail for OLE objects!" );
+ mbOwnDocument = true;
+ }
+
+ // Use dimension of source page
+ SdrPageView* pPgView = mpSdView->GetSdrPageView();
+ SdPage* pOldPage = static_cast<SdPage*>( pPgView->GetPage() );
+ SdrModel* pOldModel = mpSdView->GetModel();
+ SdStyleSheetPool* pOldStylePool = static_cast<SdStyleSheetPool*>( pOldModel->GetStyleSheetPool() );
+ SdStyleSheetPool* pNewStylePool = static_cast<SdStyleSheetPool*>( mpSdDrawDocumentIntern->GetStyleSheetPool() );
+ SdPage* pPage = mpSdDrawDocumentIntern->GetSdPage( 0, PageKind::Standard );
+ OUString aOldLayoutName( pOldPage->GetLayoutName() );
+
+ pPage->SetSize( pOldPage->GetSize() );
+ pPage->SetLayoutName( aOldLayoutName );
+ pNewStylePool->CopyGraphicSheets( *pOldStylePool );
+ pNewStylePool->CopyCellSheets( *pOldStylePool );
+ pNewStylePool->CopyTableStyles( *pOldStylePool );
+ sal_Int32 nPos = aOldLayoutName.indexOf( SD_LT_SEPARATOR );
+ if( nPos != -1 )
+ aOldLayoutName = aOldLayoutName.copy( 0, nPos );
+ StyleSheetCopyResultVector aCreatedSheets;
+ pNewStylePool->CopyLayoutSheets( aOldLayoutName, *pOldStylePool, aCreatedSheets );
+ }
+
+ // set VisArea and adjust objects if necessary
+ if( !(maVisArea.IsEmpty() &&
+ mpSdDrawDocumentIntern && mpSdViewIntern &&
+ mpSdDrawDocumentIntern->GetPageCount()) )
+ return;
+
+ SdPage* pPage = mpSdDrawDocumentIntern->GetSdPage( 0, PageKind::Standard );
+
+ if( 1 == mpSdDrawDocumentIntern->GetPageCount() )
+ {
+ // #112978# need to use GetAllMarkedBoundRect instead of GetAllMarkedRect to get
+ // fat lines correctly
+ maVisArea = mpSdViewIntern->GetAllMarkedBoundRect();
+ Point aOrigin( maVisArea.TopLeft() );
+ Size aVector( -aOrigin.X(), -aOrigin.Y() );
+
+ for( size_t nObj = 0, nObjCount = pPage->GetObjCount(); nObj < nObjCount; ++nObj )
+ {
+ SdrObject* pObj = pPage->GetObj( nObj );
+ pObj->NbcMove( aVector );
+ }
+ }
+ else
+ maVisArea.SetSize( pPage->GetSize() );
+
+ // output is at the zero point
+ maVisArea.SetPos( Point() );
+}
+
+static bool lcl_HasOnlyControls( SdrModel* pModel )
+{
+ bool bOnlyControls = false; // default if there are no objects
+
+ if ( pModel )
+ {
+ SdrPage* pPage = pModel->GetPage(0);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObj = aIter.Next();
+ if ( pObj )
+ {
+ bOnlyControls = true; // only set if there are any objects at all
+ while ( pObj )
+ {
+ if (dynamic_cast< const SdrUnoObj *>( pObj ) == nullptr)
+ {
+ bOnlyControls = false;
+ break;
+ }
+ pObj = aIter.Next();
+ }
+ }
+ }
+ }
+
+ return bOnlyControls;
+}
+
+static bool lcl_HasOnlyOneTable( SdrModel* pModel )
+{
+ if ( pModel )
+ {
+ SdrPage* pPage = pModel->GetPage(0);
+ if (pPage && pPage->GetObjCount() == 1 )
+ {
+ if( dynamic_cast< sdr::table::SdrTableObj* >( pPage->GetObj(0) ) != nullptr )
+ return true;
+ }
+ }
+ return false;
+}
+
+void SdTransferable::AddSupportedFormats()
+{
+ if( mbPageTransferable && !mbPageTransferablePersistent )
+ return;
+
+ if( !mbLateInit )
+ CreateData();
+
+ if( mpObjDesc )
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+
+ if( mpOLEDataHelper )
+ {
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+
+ DataFlavorExVector aVector( mpOLEDataHelper->GetDataFlavorExVector() );
+
+ for( const auto& rItem : aVector )
+ AddFormat( rItem );
+ }
+ else if( mpGraphic )
+ {
+ // #i25616#
+ AddFormat( SotClipboardFormatId::DRAWING );
+
+ AddFormat( SotClipboardFormatId::SVXB );
+
+ if( mpGraphic->GetType() == GraphicType::Bitmap )
+ {
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ }
+ else
+ {
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ }
+ }
+ else if( mpBookmark )
+ {
+ AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ AddFormat( SotClipboardFormatId::STRING );
+ }
+ else
+ {
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::DRAWING );
+ if( !mpSdDrawDocument || !lcl_HasOnlyControls( mpSdDrawDocument ) )
+ {
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ }
+
+ if( lcl_HasOnlyOneTable( mpSdDrawDocument ) ) {
+ AddFormat( SotClipboardFormatId::RTF );
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ }
+ }
+
+ if( mpImageMap )
+ AddFormat( SotClipboardFormatId::SVIM );
+}
+
+bool SdTransferable::GetData( const DataFlavor& rFlavor, const OUString& rDestDoc )
+{
+ if (SD_MOD()==nullptr)
+ return false;
+
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ bool bOK = false;
+
+ CreateData();
+
+ if( nFormat == SotClipboardFormatId::RTF && lcl_HasOnlyOneTable( mpSdDrawDocument ) )
+ {
+ bOK = SetTableRTF( mpSdDrawDocument );
+ }
+ else if( mpOLEDataHelper && mpOLEDataHelper->HasFormat( rFlavor ) )
+ {
+ // TODO/LATER: support all the graphical formats, the embedded object scenario should not have separated handling
+ if( nFormat == SotClipboardFormatId::GDIMETAFILE && mpGraphic )
+ bOK = SetGDIMetaFile( mpGraphic->GetGDIMetaFile() );
+ else
+ bOK = SetAny( mpOLEDataHelper->GetAny(rFlavor, rDestDoc) );
+ }
+ else if( HasFormat( nFormat ) )
+ {
+ if( ( nFormat == SotClipboardFormatId::LINKSRCDESCRIPTOR || nFormat == SotClipboardFormatId::OBJECTDESCRIPTOR ) && mpObjDesc )
+ {
+ bOK = SetTransferableObjectDescriptor( *mpObjDesc );
+ }
+ else if( nFormat == SotClipboardFormatId::DRAWING )
+ {
+ SfxObjectShellRef aOldRef( maDocShellRef );
+
+ maDocShellRef.clear();
+
+ if( mpSdViewIntern )
+ {
+ SdDrawDocument& rInternDoc = mpSdViewIntern->GetDoc();
+ rInternDoc.CreatingDataObj(this);
+ SdDrawDocument* pDoc = dynamic_cast< SdDrawDocument* >( mpSdViewIntern->CreateMarkedObjModel().release() );
+ rInternDoc.CreatingDataObj(nullptr);
+
+ bOK = SetObject( pDoc, SDTRANSFER_OBJECTTYPE_DRAWMODEL, rFlavor );
+
+ if( maDocShellRef.is() )
+ {
+ maDocShellRef->DoClose();
+ }
+ else
+ {
+ delete pDoc;
+ }
+ }
+
+ maDocShellRef = aOldRef;
+ }
+ else if( nFormat == SotClipboardFormatId::GDIMETAFILE )
+ {
+ if (mpSdViewIntern)
+ {
+ const bool bToggleOnlineSpell = mpSdDrawDocumentIntern && mpSdDrawDocumentIntern->GetOnlineSpell();
+ if (bToggleOnlineSpell)
+ mpSdDrawDocumentIntern->SetOnlineSpell(false);
+ bOK = SetGDIMetaFile( mpSdViewIntern->GetMarkedObjMetaFile( true ) );
+ if (bToggleOnlineSpell)
+ mpSdDrawDocumentIntern->SetOnlineSpell(true);
+ }
+ }
+ else if( SotClipboardFormatId::BITMAP == nFormat || SotClipboardFormatId::PNG == nFormat )
+ {
+ if (mpSdViewIntern)
+ {
+ const bool bToggleOnlineSpell = mpSdDrawDocumentIntern && mpSdDrawDocumentIntern->GetOnlineSpell();
+ if (bToggleOnlineSpell)
+ mpSdDrawDocumentIntern->SetOnlineSpell(false);
+ bOK = SetBitmapEx( mpSdViewIntern->GetMarkedObjBitmapEx(true), rFlavor );
+ if (bToggleOnlineSpell)
+ mpSdDrawDocumentIntern->SetOnlineSpell(true);
+ }
+ }
+ else if( ( nFormat == SotClipboardFormatId::STRING ) && mpBookmark )
+ {
+ bOK = SetString( mpBookmark->GetURL() );
+ }
+ else if( ( nFormat == SotClipboardFormatId::SVXB ) && mpGraphic )
+ {
+ bOK = SetGraphic( *mpGraphic );
+ }
+ else if( ( nFormat == SotClipboardFormatId::SVIM ) && mpImageMap )
+ {
+ bOK = SetImageMap( *mpImageMap );
+ }
+ else if( mpBookmark )
+ {
+ bOK = SetINetBookmark( *mpBookmark, rFlavor );
+ }
+ else if( nFormat == SotClipboardFormatId::EMBED_SOURCE )
+ {
+ if( mpSdDrawDocumentIntern )
+ {
+ if( !maDocShellRef.is() )
+ {
+ maDocShellRef = new ::sd::DrawDocShell(
+ mpSdDrawDocumentIntern,
+ SfxObjectCreateMode::EMBEDDED,
+ true,
+ mpSdDrawDocumentIntern->GetDocumentType());
+ mbOwnDocument = false;
+ maDocShellRef->DoInitNew();
+ }
+
+ maDocShellRef->SetVisArea( maVisArea );
+ bOK = SetObject( maDocShellRef.get(), SDTRANSFER_OBJECTTYPE_DRAWOLE, rFlavor );
+ }
+ }
+ }
+
+ return bOK;
+}
+
+bool SdTransferable::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pObject, sal_uInt32 nObjectType, const DataFlavor& )
+{
+ bool bRet = false;
+
+ switch( nObjectType )
+ {
+ case SDTRANSFER_OBJECTTYPE_DRAWMODEL:
+ {
+ try
+ {
+ static const bool bDontBurnInStyleSheet = ( getenv( "AVOID_BURN_IN_FOR_GALLERY_THEME" ) != nullptr );
+ SdDrawDocument* pDoc = static_cast<SdDrawDocument*>(pObject);
+ if ( !bDontBurnInStyleSheet )
+ pDoc->BurnInStyleSheetAttributes();
+ rxOStm->SetBufferSize( 16348 );
+
+ Reference< XComponent > xComponent( new SdXImpressDocument( pDoc, true ) );
+ pDoc->setUnoModel( Reference< XInterface >::query( xComponent ) );
+
+ {
+ css::uno::Reference<css::io::XOutputStream> xDocOut( new utl::OOutputStreamWrapper( *rxOStm ) );
+ SvxDrawingLayerExport( pDoc, xDocOut, xComponent, (pDoc->GetDocumentType() == DocumentType::Impress) ? "com.sun.star.comp.Impress.XMLClipboardExporter" : "com.sun.star.comp.DrawingLayer.XMLExporter" );
+ }
+
+ xComponent->dispose();
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SdTransferable::WriteObject()" );
+ bRet = false;
+ }
+ }
+ break;
+
+ case SDTRANSFER_OBJECTTYPE_DRAWOLE:
+ {
+ SfxObjectShell* pEmbObj = static_cast<SfxObjectShell*>(pObject);
+ ::utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+
+ try
+ {
+ uno::Reference< embed::XStorage > xWorkStore =
+ ::comphelper::OStorageHelper::GetStorageFromURL( aTempFile.GetURL(), embed::ElementModes::READWRITE );
+
+ // write document storage
+ pEmbObj->SetupStorage( xWorkStore, SOFFICE_FILEFORMAT_CURRENT, false );
+ // mba: no relative URLs for clipboard!
+ SfxMedium aMedium( xWorkStore, OUString() );
+ pEmbObj->DoSaveObjectAs( aMedium, false );
+ pEmbObj->DoSaveCompleted();
+
+ uno::Reference< embed::XTransactedObject > xTransact( xWorkStore, uno::UNO_QUERY );
+ if ( xTransact.is() )
+ xTransact->commit();
+
+ std::unique_ptr<SvStream> pSrcStm = ::utl::UcbStreamHelper::CreateStream( aTempFile.GetURL(), StreamMode::READ );
+ if( pSrcStm )
+ {
+ rxOStm->SetBufferSize( 0xff00 );
+ rxOStm->WriteStream( *pSrcStm );
+ pSrcStm.reset();
+ }
+
+ bRet = true;
+ }
+ catch ( Exception& )
+ {}
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return bRet;
+}
+
+void SdTransferable::DragFinished( sal_Int8 nDropAction )
+{
+ if( mpSdView )
+ const_cast< ::sd::View* >(mpSdView)->DragFinished( nDropAction );
+}
+
+void SdTransferable::ObjectReleased()
+{
+ SdModule *pModule = SD_MOD();
+ if (!pModule)
+ return;
+
+ if( this == pModule->pTransferClip )
+ pModule->pTransferClip = nullptr;
+
+ if( this == pModule->pTransferDrag )
+ pModule->pTransferDrag = nullptr;
+
+ if( this == pModule->pTransferSelection )
+ pModule->pTransferSelection = nullptr;
+}
+
+void SdTransferable::SetObjectDescriptor( std::unique_ptr<TransferableObjectDescriptor> pObjDesc )
+{
+ mpObjDesc = std::move(pObjDesc);
+ PrepareOLE( *mpObjDesc );
+}
+
+void SdTransferable::SetPageBookmarks( std::vector<OUString> && rPageBookmarks, bool bPersistent )
+{
+ if( !mpSourceDoc )
+ return;
+
+ if( mpSdViewIntern )
+ mpSdViewIntern->HideSdrPage();
+
+ mpSdDrawDocument->ClearModel(false);
+
+ mpPageDocShell = nullptr;
+
+ maPageBookmarks.clear();
+
+ if( bPersistent )
+ {
+ mpSdDrawDocument->CreateFirstPages(mpSourceDoc);
+ mpSdDrawDocument->InsertBookmarkAsPage( rPageBookmarks, nullptr, false, true, 1, true,
+ mpSourceDoc->GetDocSh(), true, true, false );
+ }
+ else
+ {
+ mpPageDocShell = mpSourceDoc->GetDocSh();
+ maPageBookmarks = std::move(rPageBookmarks);
+ }
+
+ if( mpSdViewIntern )
+ {
+ SdPage* pPage = mpSdDrawDocument->GetSdPage( 0, PageKind::Standard );
+
+ if( pPage )
+ {
+ mpSdViewIntern->MarkAllObj( mpSdViewIntern->ShowSdrPage( pPage ) );
+ }
+ }
+
+ // set flags for page transferable; if ( mbPageTransferablePersistent == sal_False ),
+ // don't offer any formats => it's just for internal purposes
+ mbPageTransferable = true;
+ mbPageTransferablePersistent = bPersistent;
+}
+
+sal_Int64 SAL_CALL SdTransferable::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+void SdTransferable::AddUserData (const std::shared_ptr<UserData>& rpData)
+{
+ maUserData.push_back(rpData);
+}
+
+sal_Int32 SdTransferable::GetUserDataCount() const
+{
+ return maUserData.size();
+}
+
+std::shared_ptr<SdTransferable::UserData> SdTransferable::GetUserData (const sal_Int32 nIndex) const
+{
+ if (nIndex>=0 && o3tl::make_unsigned(nIndex)<maUserData.size())
+ return maUserData[nIndex];
+ else
+ return std::shared_ptr<UserData>();
+}
+
+const css::uno::Sequence< sal_Int8 >& SdTransferable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theSdTransferableUnoTunnelId;
+ return theSdTransferableUnoTunnelId.getSeq();
+}
+
+SdTransferable* SdTransferable::getImplementation( const Reference< XInterface >& rxData ) noexcept
+{
+ try
+ {
+ return comphelper::getFromUnoTunnel<SdTransferable>(rxData);
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+ return nullptr;
+}
+
+void SdTransferable::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast< const SdrHint* >( &rHint );
+ if( SdrHintKind::ModelCleared == pSdrHint->GetKind() )
+ {
+ EndListening(*mpSourceDoc);
+ mpSourceDoc = nullptr;
+ }
+ }
+ else
+ {
+ if( rHint.GetId() == SfxHintId::Dying )
+ {
+ if( &rBC == mpSourceDoc )
+ mpSourceDoc = nullptr;
+ if( &rBC == mpSdViewIntern )
+ mpSdViewIntern = nullptr;
+ if( &rBC == mpSdView )
+ mpSdView = nullptr;
+ }
+ }
+}
+
+void SdTransferable::SetView(const ::sd::View* pView)
+{
+ if (mpSdView)
+ EndListening(*const_cast<sd::View*>(mpSdView));
+ mpSdView = pView;
+ if (mpSdView)
+ StartListening(*const_cast<sd::View*>(mpSdView));
+}
+
+bool SdTransferable::SetTableRTF( SdDrawDocument* pModel )
+{
+ if ( pModel )
+ {
+ SdrPage* pPage = pModel->GetPage(0);
+ if (pPage && pPage->GetObjCount() == 1 )
+ {
+ sdr::table::SdrTableObj* pTableObj = dynamic_cast< sdr::table::SdrTableObj* >( pPage->GetObj(0) );
+ if( pTableObj )
+ {
+ SvMemoryStream aMemStm( 65535, 65535 );
+ sdr::table::ExportAsRTF( aMemStm, *pTableObj );
+ return SetAny( Any( Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() ) ) );
+ }
+ }
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/app/tmplctrl.cxx b/sd/source/ui/app/tmplctrl.cxx
new file mode 100644
index 000000000..1f645bf66
--- /dev/null
+++ b/sd/source/ui/app/tmplctrl.cxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/commandevent.hxx>
+#include <vcl/status.hxx>
+#include <vcl/weldutils.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <tmplctrl.hxx>
+#include <ViewShellBase.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <sdattr.hrc>
+#include <app.hrc>
+#include <sdresid.hxx>
+#include <strings.hrc>
+
+SFX_IMPL_STATUSBAR_CONTROL( SdTemplateControl, SfxStringItem );
+
+// class SdTemplateControl ------------------------------------------
+SdTemplateControl::SdTemplateControl( sal_uInt16 _nSlotId,
+ sal_uInt16 _nId,
+ StatusBar& rStb ) :
+ SfxStatusBarControl( _nSlotId, _nId, rStb )
+{
+ GetStatusBar().SetQuickHelpText(GetId(), SdResId(STR_STATUSBAR_MASTERPAGE));
+}
+
+SdTemplateControl::~SdTemplateControl()
+{
+}
+
+void SdTemplateControl::StateChangedAtStatusBarControl(
+ sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState )
+{
+ if( eState != SfxItemState::DEFAULT || pState->IsVoidItem() )
+ GetStatusBar().SetItemText( GetId(), OUString() );
+ else if ( auto pStringItem = dynamic_cast< const SfxStringItem *>( pState ) )
+ {
+ msTemplate = pStringItem->GetValue();
+ GetStatusBar().SetItemText( GetId(), msTemplate );
+ }
+}
+
+void SdTemplateControl::Paint( const UserDrawEvent& )
+{
+}
+
+void SdTemplateControl::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() != CommandEventId::ContextMenu || GetStatusBar().GetItemText( GetId() ).isEmpty() )
+ return;
+
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+
+ sd::ViewShellBase* pViewShellBase = sd::ViewShellBase::GetViewShellBase( pViewFrame );
+ if( !pViewShellBase )
+ return;
+
+ SdDrawDocument* pDoc = pViewShellBase->GetDocument();
+ if( !pDoc )
+ return;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/simpress/ui/masterpagemenu.ui"));
+ std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("menu"));
+
+ const sal_uInt16 nMasterCount = pDoc->GetMasterSdPageCount(PageKind::Standard);
+
+ for (sal_uInt16 nPage = 0; nPage < nMasterCount; ++nPage)
+ {
+ SdPage* pMaster = pDoc->GetMasterSdPage(nPage, PageKind::Standard);
+ if (!pMaster)
+ continue;
+ xPopup->append(OUString::number(nPage), pMaster->GetName());
+ }
+
+ ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pParent = weld::GetPopupParent(GetStatusBar(), aRect);
+ OString sResult = xPopup->popup_at_rect(pParent, aRect);
+ if (!sResult.isEmpty())
+ {
+ sal_uInt16 nCurrId = sResult.toUInt32();
+ SdPage* pMaster = pDoc->GetMasterSdPage(nCurrId, PageKind::Standard);
+ SfxStringItem aStyle( ATTR_PRESLAYOUT_NAME, pMaster->GetName() );
+ pViewFrame->GetDispatcher()->ExecuteList(
+ SID_PRESENTATION_LAYOUT, SfxCallMode::SLOT, { &aStyle });
+ pViewFrame->GetBindings().Invalidate(SID_PRESENTATION_LAYOUT);
+ pViewFrame->GetBindings().Invalidate(SID_STATUS_LAYOUT);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/controller/displaymodecontroller.cxx b/sd/source/ui/controller/displaymodecontroller.cxx
new file mode 100644
index 000000000..81ad2d19e
--- /dev/null
+++ b/sd/source/ui/controller/displaymodecontroller.cxx
@@ -0,0 +1,264 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <svtools/popupwindowcontroller.hxx>
+#include <svtools/toolbarmenu.hxx>
+#include <svtools/valueset.hxx>
+#include <vcl/toolbox.hxx>
+
+#include <strings.hrc>
+
+#include <bitmaps.hlst>
+#include <sdresid.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+
+namespace sd
+{
+
+// Component to select which display mode has to be used.
+// Composed of a dropdown button in the toolbar and a
+// popup menu to select the value
+
+namespace {
+
+class DisplayModeController : public svt::PopupWindowController
+{
+public:
+ explicit DisplayModeController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ void setToolboxItemImage(const OUString& rImage);
+};
+
+class DisplayModeToolbarMenu final : public WeldToolbarPopup
+{
+public:
+ DisplayModeToolbarMenu(DisplayModeController* pControl, weld::Widget* pParent);
+ virtual void GrabFocus() override
+ {
+ mxDisplayModeSet1->GrabFocus();
+ }
+
+private:
+ rtl::Reference<DisplayModeController> mxControl;
+ std::unique_ptr<weld::Frame> mxFrame1;
+ std::unique_ptr<ValueSet> mxDisplayModeSet1;
+ std::unique_ptr<weld::CustomWeld> mxDisplayModeSetWin1;
+ std::unique_ptr<weld::Frame> mxFrame2;
+ std::unique_ptr<ValueSet> mxDisplayModeSet2;
+ std::unique_ptr<weld::CustomWeld> mxDisplayModeSetWin2;
+
+ DECL_LINK(SelectValueSetHdl, ValueSet*, void);
+};
+
+struct snew_slide_value_info
+{
+ sal_uInt16 mnId;
+ OUString msBmpResId;
+ TranslateId mpStrResId;
+ const char* msUnoCommand;
+};
+
+}
+
+const snew_slide_value_info editmodes[] =
+{
+ {1,
+ BMP_DISPLAYMODE_SLIDE,
+ STR_NORMAL_MODE,
+ ".uno:NormalMultiPaneGUI" },
+ {2,
+ BMP_DISPLAYMODE_OUTLINE,
+ STR_OUTLINE_MODE,
+ ".uno:OutlineMode" },
+ {3,
+ BMP_DISPLAYMODE_NOTES,
+ STR_NOTES_MODE,
+ ".uno:NotesMode" },
+ {4,
+ BMP_DISPLAYMODE_SLIDE_SORTER,
+ STR_SLIDE_SORTER_MODE,
+ ".uno:DiaMode" },
+ {0, "", {}, "" }
+};
+
+const snew_slide_value_info mastermodes[] =
+{
+ {5,
+ BMP_DISPLAYMODE_SLIDE_MASTER,
+ STR_SLIDE_MASTER_MODE,
+ ".uno:SlideMasterPage" },
+ {6,
+ BMP_DISPLAYMODE_NOTES_MASTER,
+ STR_NOTES_MASTER_MODE,
+ ".uno:NotesMasterPage" },
+ {7,
+ BMP_DISPLAYMODE_HANDOUT_MASTER,
+ STR_HANDOUT_MASTER_MODE,
+ ".uno:HandoutMode" },
+ {0, "", {}, "" }
+};
+
+
+static void fillLayoutValueSet(ValueSet* pValue, const snew_slide_value_info* pInfo)
+{
+ Size aLayoutItemSize;
+ for( ; pInfo->mnId; pInfo++ )
+ {
+ OUString aText(SdResId(pInfo->mpStrResId));
+ BitmapEx aBmp(pInfo->msBmpResId);
+
+ pValue->InsertItem(pInfo->mnId, Image(aBmp), aText);
+
+ aLayoutItemSize.setWidth( std::max( aLayoutItemSize.Width(), aBmp.GetSizePixel().Width() ) );
+ aLayoutItemSize.setHeight( std::max( aLayoutItemSize.Height(), aBmp.GetSizePixel().Height() ) );
+ }
+
+ aLayoutItemSize = pValue->CalcItemSizePixel( aLayoutItemSize );
+ Size aSize(pValue->CalcWindowSizePixel(aLayoutItemSize));
+
+ const sal_Int32 LAYOUT_BORDER_PIX = 7;
+ aSize.AdjustWidth((pValue->GetColCount() + 1) * LAYOUT_BORDER_PIX );
+ aSize.AdjustHeight((pValue->GetLineCount() +1) * LAYOUT_BORDER_PIX );
+
+ pValue->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height());
+ pValue->SetOutputSizePixel(aSize);
+}
+
+DisplayModeToolbarMenu::DisplayModeToolbarMenu(DisplayModeController* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "modules/simpress/ui/displaywindow.ui", "DisplayWindow")
+ , mxControl(pControl)
+ , mxFrame1(m_xBuilder->weld_frame("editframe"))
+ , mxDisplayModeSet1(new ValueSet(nullptr))
+ , mxDisplayModeSetWin1(new weld::CustomWeld(*m_xBuilder, "valueset1", *mxDisplayModeSet1))
+ , mxFrame2(m_xBuilder->weld_frame("masterframe"))
+ , mxDisplayModeSet2(new ValueSet(nullptr))
+ , mxDisplayModeSetWin2(new weld::CustomWeld(*m_xBuilder, "valueset2", *mxDisplayModeSet2))
+{
+ mxDisplayModeSet1->SetStyle(WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT);
+ mxDisplayModeSet1->SetStyle(WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT);
+
+ mxDisplayModeSet1->SetSelectHdl( LINK( this, DisplayModeToolbarMenu, SelectValueSetHdl ) );
+ mxDisplayModeSet2->SetSelectHdl( LINK( this, DisplayModeToolbarMenu, SelectValueSetHdl ) );
+
+ sal_Int16 nColCount = 2;
+
+ mxDisplayModeSet1->SetColCount( nColCount );
+ fillLayoutValueSet( mxDisplayModeSet1.get(), &editmodes[0] );
+
+ mxDisplayModeSet2->SetColCount( nColCount );
+ fillLayoutValueSet( mxDisplayModeSet2.get(), &mastermodes[0] );
+}
+
+IMPL_LINK( DisplayModeToolbarMenu, SelectValueSetHdl, ValueSet*, pControl, void )
+{
+ OUString sCommandURL;
+ OUString sImage;
+
+ if( pControl == mxDisplayModeSet1.get() ) {
+ sCommandURL = OUString::createFromAscii(editmodes[mxDisplayModeSet1->GetSelectedItemId() - 1 ].msUnoCommand);
+ sImage = editmodes[mxDisplayModeSet1->GetSelectedItemId() - 1 ].msBmpResId;
+ }
+ else if( pControl == mxDisplayModeSet2.get() ) {
+ sCommandURL = OUString::createFromAscii(mastermodes[mxDisplayModeSet2->GetSelectedItemId() - 5 ].msUnoCommand);
+ sImage = mastermodes[mxDisplayModeSet2->GetSelectedItemId() - 5 ].msBmpResId;
+ }
+
+ if (!sCommandURL.isEmpty())
+ mxControl->dispatchCommand( sCommandURL, Sequence< PropertyValue >() );
+
+ mxControl->setToolboxItemImage(sImage);
+ mxControl->EndPopupMode();
+}
+
+DisplayModeController::DisplayModeController( const css::uno::Reference< css::uno::XComponentContext >& rxContext )
+: svt::PopupWindowController( rxContext, Reference< frame::XFrame >(), OUString() )
+{
+}
+
+void SAL_CALL DisplayModeController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::PopupWindowController::initialize( aArguments );
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if ( getToolboxId( nId, &pToolBox ) )
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+ setToolboxItemImage(BMP_DISPLAYMODE_SLIDE);
+}
+
+std::unique_ptr<WeldToolbarPopup> DisplayModeController::weldPopupWindow()
+{
+ return std::make_unique<sd::DisplayModeToolbarMenu>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> DisplayModeController::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<sd::DisplayModeToolbarMenu>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+void DisplayModeController::setToolboxItemImage(const OUString& rImage)
+{
+ ToolBoxItemId nId;
+ ToolBox* pToolBox = nullptr;
+ if (!getToolboxId( nId, &pToolBox ))
+ return;
+
+ BitmapEx aBmp(rImage);
+ int targetSize = (pToolBox->GetToolboxButtonSize() == ToolBoxButtonSize::Large) ? 32 : 16;
+ double scale = 1.0f;
+ Size size = aBmp.GetSizePixel();
+ if (size.Width() > targetSize)
+ scale = static_cast<double>(targetSize) / static_cast<double>(size.Width());
+ if (size.Height() > targetSize)
+ scale = ::std::min( scale, static_cast<double>(targetSize) / static_cast<double>(size.Height()) );
+ aBmp.Scale( scale, scale );
+ pToolBox->SetItemImage( nId, Image( aBmp ) );
+}
+
+// XServiceInfo
+
+OUString SAL_CALL DisplayModeController::getImplementationName()
+{
+ return "com.sun.star.comp.sd.DisplayModeController";
+}
+
+Sequence< OUString > SAL_CALL DisplayModeController::getSupportedServiceNames( )
+{
+ css::uno::Sequence<OUString> aRet { "com.sun.star.frame.ToolbarController" };
+ return aRet;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface*
+com_sun_star_comp_sd_DisplayModeController_get_implementation( css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::DisplayModeController(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/controller/slidelayoutcontroller.cxx b/sd/source/ui/controller/slidelayoutcontroller.cxx
new file mode 100644
index 000000000..251548a22
--- /dev/null
+++ b/sd/source/ui/controller/slidelayoutcontroller.cxx
@@ -0,0 +1,380 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/DrawViewMode.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/toolbox.hxx>
+
+#include <svl/cjkoptions.hxx>
+
+#include <svtools/toolbarmenu.hxx>
+#include <svtools/valueset.hxx>
+
+#include <xmloff/autolayout.hxx>
+
+#include <strings.hrc>
+
+#include <bitmaps.hlst>
+#include <sdresid.hxx>
+#include "slidelayoutcontroller.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::beans;
+
+namespace sd
+{
+
+namespace {
+
+class LayoutToolbarMenu : public WeldToolbarPopup
+{
+public:
+ LayoutToolbarMenu(SlideLayoutController* pController, weld::Widget* pParent, const bool bInsertPage, const OUString& rCommand);
+ virtual void GrabFocus() override
+ {
+ mxLayoutSet1->GrabFocus();
+ }
+
+protected:
+ DECL_LINK(SelectToolbarMenuHdl, weld::Button&, void);
+ DECL_LINK(SelectValueSetHdl, ValueSet*, void);
+ void SelectHdl(AutoLayout eLayout);
+private:
+ rtl::Reference<SlideLayoutController> mxControl;
+ bool const mbInsertPage;
+ std::unique_ptr<weld::Frame> mxFrame1;
+ std::unique_ptr<ValueSet> mxLayoutSet1;
+ std::unique_ptr<weld::CustomWeld> mxLayoutSetWin1;
+ std::unique_ptr<weld::Frame> mxFrame2;
+ std::unique_ptr<ValueSet> mxLayoutSet2;
+ std::unique_ptr<weld::CustomWeld> mxLayoutSetWin2;
+ std::unique_ptr<weld::Button> mxMoreButton;
+};
+
+struct snew_slide_value_info_layout
+{
+ rtl::OUStringConstExpr msBmpResId;
+ TranslateId mpStrResId;
+ AutoLayout maAutoLayout;
+};
+
+}
+
+constexpr OUStringLiteral EMPTY = u"";
+
+const snew_slide_value_info_layout notes[] =
+{
+ {BMP_SLIDEN_01, STR_AUTOLAYOUT_NOTES, AUTOLAYOUT_NOTES},
+ {EMPTY, {}, AUTOLAYOUT_NONE},
+};
+
+const snew_slide_value_info_layout handout[] =
+{
+ {BMP_SLIDEH_01, STR_AUTOLAYOUT_HANDOUT1, AUTOLAYOUT_HANDOUT1},
+ {BMP_SLIDEH_02, STR_AUTOLAYOUT_HANDOUT2, AUTOLAYOUT_HANDOUT2},
+ {BMP_SLIDEH_03, STR_AUTOLAYOUT_HANDOUT3, AUTOLAYOUT_HANDOUT3},
+ {BMP_SLIDEH_04, STR_AUTOLAYOUT_HANDOUT4, AUTOLAYOUT_HANDOUT4},
+ {BMP_SLIDEH_06, STR_AUTOLAYOUT_HANDOUT6, AUTOLAYOUT_HANDOUT6},
+ {BMP_SLIDEH_09, STR_AUTOLAYOUT_HANDOUT9, AUTOLAYOUT_HANDOUT9},
+ {EMPTY, {}, AUTOLAYOUT_NONE},
+};
+
+const snew_slide_value_info_layout standard[] =
+{
+ {BMP_LAYOUT_EMPTY, STR_AUTOLAYOUT_NONE, AUTOLAYOUT_NONE },
+ {BMP_LAYOUT_HEAD03, STR_AUTOLAYOUT_TITLE, AUTOLAYOUT_TITLE },
+ {BMP_LAYOUT_HEAD02, STR_AUTOLAYOUT_CONTENT, AUTOLAYOUT_TITLE_CONTENT },
+ {BMP_LAYOUT_HEAD02A, STR_AUTOLAYOUT_2CONTENT, AUTOLAYOUT_TITLE_2CONTENT },
+ {BMP_LAYOUT_HEAD01, STR_AUTOLAYOUT_ONLY_TITLE, AUTOLAYOUT_TITLE_ONLY },
+ {BMP_LAYOUT_TEXTONLY, STR_AUTOLAYOUT_ONLY_TEXT, AUTOLAYOUT_ONLY_TEXT },
+ {BMP_LAYOUT_HEAD03B, STR_AUTOLAYOUT_2CONTENT_CONTENT, AUTOLAYOUT_TITLE_2CONTENT_CONTENT },
+ {BMP_LAYOUT_HEAD03C, STR_AUTOLAYOUT_CONTENT_2CONTENT, AUTOLAYOUT_TITLE_CONTENT_2CONTENT },
+ {BMP_LAYOUT_HEAD03A, STR_AUTOLAYOUT_2CONTENT_OVER_CONTENT,AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT },
+ {BMP_LAYOUT_HEAD02B, STR_AUTOLAYOUT_CONTENT_OVER_CONTENT, AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT },
+ {BMP_LAYOUT_HEAD04, STR_AUTOLAYOUT_4CONTENT, AUTOLAYOUT_TITLE_4CONTENT },
+ {BMP_LAYOUT_HEAD06, STR_AUTOLAYOUT_6CONTENT, AUTOLAYOUT_TITLE_6CONTENT },
+ {EMPTY, {}, AUTOLAYOUT_NONE}
+};
+
+const snew_slide_value_info_layout v_standard[] =
+{
+ // vertical
+ {BMP_LAYOUT_VERTICAL02, STR_AL_VERT_TITLE_TEXT_CHART, AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT },
+ {BMP_LAYOUT_VERTICAL01, STR_AL_VERT_TITLE_VERT_OUTLINE, AUTOLAYOUT_VTITLE_VCONTENT },
+ {BMP_LAYOUT_HEAD02, STR_AL_TITLE_VERT_OUTLINE, AUTOLAYOUT_TITLE_VCONTENT },
+ {BMP_LAYOUT_HEAD02A, STR_AL_TITLE_VERT_OUTLINE_CLIPART, AUTOLAYOUT_TITLE_2VTEXT },
+ {EMPTY, {}, AUTOLAYOUT_NONE}
+};
+
+static void fillLayoutValueSet( ValueSet* pValue, const snew_slide_value_info_layout* pInfo )
+{
+ Size aLayoutItemSize;
+ for( ; pInfo->mpStrResId; pInfo++ )
+ {
+ OUString aText(SdResId(pInfo->mpStrResId));
+ Image aImg(StockImage::Yes, pInfo->msBmpResId);
+ pValue->InsertItem(static_cast<sal_uInt16>(pInfo->maAutoLayout)+1, aImg, aText);
+ aLayoutItemSize.setWidth( std::max( aLayoutItemSize.Width(), aImg.GetSizePixel().Width() ) );
+ aLayoutItemSize.setHeight( std::max( aLayoutItemSize.Height(), aImg.GetSizePixel().Height() ) );
+ }
+
+ aLayoutItemSize = pValue->CalcItemSizePixel( aLayoutItemSize );
+ Size aSize(pValue->CalcWindowSizePixel(aLayoutItemSize));
+
+ const sal_Int32 LAYOUT_BORDER_PIX = 7;
+
+ aSize.AdjustWidth((pValue->GetColCount() + 1) * LAYOUT_BORDER_PIX);
+ aSize.AdjustHeight((pValue->GetLineCount() +1) * LAYOUT_BORDER_PIX);
+
+ pValue->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height());
+ pValue->SetOutputSizePixel(aSize);
+}
+
+LayoutToolbarMenu::LayoutToolbarMenu(SlideLayoutController* pControl, weld::Widget* pParent, const bool bInsertPage, const OUString& rCommand)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "modules/simpress/ui/layoutwindow.ui", "LayoutWindow")
+ , mxControl(pControl)
+ , mbInsertPage(bInsertPage)
+ , mxFrame1(m_xBuilder->weld_frame("horiframe"))
+ , mxLayoutSet1(new ValueSet(nullptr))
+ , mxLayoutSetWin1(new weld::CustomWeld(*m_xBuilder, "valueset1", *mxLayoutSet1))
+ , mxFrame2(m_xBuilder->weld_frame("vertframe"))
+ , mxLayoutSet2(new ValueSet(nullptr))
+ , mxLayoutSetWin2(new weld::CustomWeld(*m_xBuilder, "valueset2", *mxLayoutSet2))
+ , mxMoreButton(m_xBuilder->weld_button("more"))
+{
+ mxLayoutSet1->SetStyle(WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT);
+ mxLayoutSet2->SetStyle(WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT);
+
+ DrawViewMode eMode = DrawViewMode_DRAW;
+
+ // find out which view is running
+ if( m_xFrame.is() ) try
+ {
+ Reference< XPropertySet > xControllerSet( m_xFrame->getController(), UNO_QUERY_THROW );
+ xControllerSet->getPropertyValue( "DrawViewMode" ) >>= eMode;
+ }
+ catch( Exception& )
+ {
+ OSL_ASSERT(false);
+ }
+
+ const bool bVerticalEnabled = SvtCJKOptions::IsVerticalTextEnabled();
+
+ mxLayoutSet1->SetSelectHdl( LINK( this, LayoutToolbarMenu, SelectValueSetHdl ) );
+
+ const snew_slide_value_info_layout* pInfo = nullptr;
+ sal_Int16 nColCount = 4;
+ switch( eMode )
+ {
+ case DrawViewMode_DRAW: pInfo = &standard[0]; break;
+ case DrawViewMode_HANDOUT: pInfo = &handout[0]; nColCount = 2; break;
+ case DrawViewMode_NOTES: pInfo = &notes[0]; nColCount = 1; break;
+ default: assert(false); // can't happen, will crash later otherwise
+ }
+
+ mxLayoutSet1->SetColCount( nColCount );
+
+ fillLayoutValueSet( mxLayoutSet1.get(), pInfo );
+
+ bool bUseUILabel = (bVerticalEnabled && eMode == DrawViewMode_DRAW);
+ if (!bUseUILabel)
+ {
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rCommand, mxControl->getModuleName());
+ mxFrame1->set_label(vcl::CommandInfoProvider::GetLabelForCommand(aProperties));
+ }
+
+ if (bVerticalEnabled && eMode == DrawViewMode_DRAW)
+ {
+ mxLayoutSet2->SetSelectHdl( LINK( this, LayoutToolbarMenu, SelectValueSetHdl ) );
+ mxLayoutSet2->SetColCount( 4 );
+ mxLayoutSet2->EnableFullItemMode( false );
+
+ fillLayoutValueSet( mxLayoutSet2.get(), &v_standard[0] );
+
+ mxFrame2->show();
+ }
+
+ if( eMode != DrawViewMode_DRAW )
+ return;
+
+ if( !m_xFrame.is() )
+ return;
+
+ OUString sSlotStr;
+
+ if( bInsertPage )
+ sSlotStr = ".uno:DuplicatePage";
+ else
+ sSlotStr = ".uno:Undo";
+
+ css::uno::Reference<css::graphic::XGraphic> xSlotImage = vcl::CommandInfoProvider::GetXGraphicForCommand(sSlotStr, m_xFrame);
+
+ OUString sSlotTitle;
+ if( bInsertPage )
+ {
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(sSlotStr, mxControl->getModuleName());
+ sSlotTitle = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
+ }
+ else
+ sSlotTitle = SdResId( STR_RESET_LAYOUT );
+
+ mxMoreButton->set_label(sSlotTitle);
+ mxMoreButton->set_image(xSlotImage);
+ mxMoreButton->connect_clicked(LINK(this, LayoutToolbarMenu, SelectToolbarMenuHdl));
+ mxMoreButton->show();
+}
+
+IMPL_LINK(LayoutToolbarMenu, SelectValueSetHdl, ValueSet*, pLayoutSet, void)
+{
+ SelectHdl(static_cast<AutoLayout>(pLayoutSet->GetSelectedItemId()-1));
+}
+
+IMPL_LINK_NOARG(LayoutToolbarMenu, SelectToolbarMenuHdl, weld::Button&, void)
+{
+ SelectHdl(AUTOLAYOUT_END);
+}
+
+void LayoutToolbarMenu::SelectHdl(AutoLayout eLayout)
+{
+ Sequence< PropertyValue > aArgs;
+
+ OUString sCommandURL( mxControl->getCommandURL() );
+
+ if( eLayout != AUTOLAYOUT_END )
+ {
+ aArgs = { comphelper::makePropertyValue("WhatLayout", static_cast<sal_Int32>(eLayout)) };
+ }
+ else if( mbInsertPage )
+ {
+ sCommandURL = ".uno:DuplicatePage";
+ }
+
+ mxControl->dispatchCommand( sCommandURL, aArgs );
+
+ mxControl->EndPopupMode();
+}
+
+
+/// @throws css::uno::RuntimeException
+static OUString SlideLayoutController_getImplementationName()
+{
+ return "com.sun.star.comp.sd.SlideLayoutController";
+}
+
+/// @throws RuntimeException
+static Sequence< OUString > SlideLayoutController_getSupportedServiceNames()
+{
+ Sequence<OUString> aSNS { "com.sun.star.frame.ToolbarController" };
+ return aSNS;
+}
+
+/// @throws css::uno::RuntimeException
+static OUString InsertSlideController_getImplementationName()
+{
+ return "com.sun.star.comp.sd.InsertSlideController";
+}
+
+/// @throws RuntimeException
+static Sequence< OUString > InsertSlideController_getSupportedServiceNames()
+{
+ Sequence<OUString> aSNS { "com.sun.star.frame.ToolbarController" };
+ return aSNS;
+}
+
+SlideLayoutController::SlideLayoutController(const Reference< uno::XComponentContext >& rxContext, bool bInsertPage)
+ : svt::PopupWindowController(rxContext, nullptr, OUString())
+ , mbInsertPage(bInsertPage)
+{
+}
+
+void SAL_CALL SlideLayoutController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::PopupWindowController::initialize( aArguments );
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if ( getToolboxId( nId, &pToolBox ) )
+ {
+ if ( mbInsertPage )
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWN );
+ else
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+ }
+}
+
+std::unique_ptr<WeldToolbarPopup> SlideLayoutController::weldPopupWindow()
+{
+ return std::make_unique<sd::LayoutToolbarMenu>(this, m_pToolbar, mbInsertPage, m_aCommandURL);
+}
+
+VclPtr<vcl::Window> SlideLayoutController::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<sd::LayoutToolbarMenu>(this, pParent->GetFrameWeld(), mbInsertPage, m_aCommandURL));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+// XServiceInfo
+
+OUString SAL_CALL SlideLayoutController::getImplementationName()
+{
+ if( mbInsertPage )
+ return InsertSlideController_getImplementationName();
+ else
+ return SlideLayoutController_getImplementationName();
+}
+
+Sequence< OUString > SAL_CALL SlideLayoutController::getSupportedServiceNames( )
+{
+ if( mbInsertPage )
+ return InsertSlideController_getSupportedServiceNames();
+ else
+ return SlideLayoutController_getSupportedServiceNames();
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_sd_SlideLayoutController_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::SlideLayoutController(context, false));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_sd_InsertSlideController_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::SlideLayoutController(context, true));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/controller/slidelayoutcontroller.hxx b/sd/source/ui/controller/slidelayoutcontroller.hxx
new file mode 100644
index 000000000..ae4a3a09f
--- /dev/null
+++ b/sd/source/ui/controller/slidelayoutcontroller.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svtools/popupwindowcontroller.hxx>
+
+namespace sd
+{
+class SlideLayoutController : public svt::PopupWindowController
+{
+public:
+ SlideLayoutController(const css::uno::Reference<css::uno::XComponentContext>& rxContext,
+ bool bInsertPage);
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow(vcl::Window* pParent) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& aArguments) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+private:
+ bool mbInsertPage;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/AnimationChildWindow.cxx b/sd/source/ui/dlg/AnimationChildWindow.cxx
new file mode 100644
index 000000000..2f221fc9e
--- /dev/null
+++ b/sd/source/ui/dlg/AnimationChildWindow.cxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AnimationChildWindow.hxx>
+
+#include <app.hrc>
+#include <animobjs.hxx>
+#include <sfx2/childwin.hxx>
+
+namespace sd {
+
+SFX_IMPL_DOCKINGWINDOW_WITHID(AnimationChildWindow, SID_ANIMATION_OBJECTS)
+
+/**
+ * Derivative from SfxChildWindow as "container" for animator
+ */
+AnimationChildWindow::AnimationChildWindow(
+ vcl::Window* _pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo )
+ : SfxChildWindow( _pParent, nId )
+{
+ VclPtr<AnimationWindow> pAnimWin = VclPtr<AnimationWindow>::Create(pBindings, this, _pParent);
+ SetWindow(pAnimWin);
+
+ pAnimWin->Initialize( pInfo );
+
+ SetHideNotDelete( true );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/BulletAndPositionDlg.cxx b/sd/source/ui/dlg/BulletAndPositionDlg.cxx
new file mode 100644
index 000000000..384b477e4
--- /dev/null
+++ b/sd/source/ui/dlg/BulletAndPositionDlg.cxx
@@ -0,0 +1,1293 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/mapunit.hxx>
+#include <tools/urlobj.hxx>
+#include <editeng/numitem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/itempool.hxx>
+#include <svx/colorbox.hxx>
+#include <svx/strarray.hxx>
+#include <svx/gallery.hxx>
+#include <editeng/brushitem.hxx>
+#include <svl/intitem.hxx>
+#include <vcl/graph.hxx>
+#include <svtools/unitconv.hxx>
+#include <svx/svxids.hrc>
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+#include <sfx2/opengrf.hxx>
+
+#include <strings.hrc>
+#include <svl/stritem.hxx>
+#include <sal/log.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/SvxNumOptionsTabPageHelper.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <cui/cuicharmap.hxx>
+#include <BulletAndPositionDlg.hxx>
+#include <sdresid.hxx>
+#include <DrawViewShell.hxx>
+
+#define SHOW_NUMBERING 0
+#define SHOW_BULLET 1
+#define SHOW_BITMAP 2
+
+#define MAX_BMP_WIDTH 16
+#define MAX_BMP_HEIGHT 16
+
+static bool bLastRelative = false;
+
+static const vcl::Font& lcl_GetDefaultBulletFont()
+{
+ static vcl::Font aDefBulletFont = []() {
+ 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;
+}
+
+class SdDrawDocument;
+
+SvxBulletAndPositionDlg::SvxBulletAndPositionDlg(weld::Window* pWindow, const SfxItemSet& rSet,
+ const ::sd::View* pView)
+ : GenericDialogController(pWindow, "cui/ui/bulletandposition.ui", "BulletAndPosition")
+ , aInvalidateTimer("sd SvxBulletAndPositionDlg aInvalidateTimer")
+ , rFirstStateSet(rSet)
+ , bLastWidthModified(false)
+ , bModified(false)
+ , bInInitControl(false)
+ , bLabelAlignmentPosAndSpaceModeActive(false)
+ , bApplyToMaster(false)
+ , nBullet(0xff)
+ , nActNumLvl(1)
+ , p_Window(pWindow)
+ , nNumItemId(SID_ATTR_NUMBERING_RULE)
+ , m_xGrid(m_xBuilder->weld_widget("grid2"))
+ , m_xLevelLB(m_xBuilder->weld_tree_view("levellb"))
+ , m_xFmtLB(m_xBuilder->weld_combo_box("numfmtlb"))
+ , m_xPrefixFT(m_xBuilder->weld_label("prefixft"))
+ , m_xPrefixED(m_xBuilder->weld_entry("prefix"))
+ , m_xSuffixFT(m_xBuilder->weld_label("suffixft"))
+ , m_xSuffixED(m_xBuilder->weld_entry("suffix"))
+ , m_xBeforeAfter(m_xBuilder->weld_frame("beforeafter"))
+ , m_xBulColorFT(m_xBuilder->weld_label("colorft"))
+ , m_xBulColLB(new ColorListBox(m_xBuilder->weld_menu_button("color"),
+ [this] { return m_xDialog.get(); }))
+ , m_xBulRelSizeFT(m_xBuilder->weld_label("relsizeft"))
+ , m_xBulRelSizeMF(m_xBuilder->weld_metric_spin_button("relsize", FieldUnit::PERCENT))
+ , m_xStartFT(m_xBuilder->weld_label("startatft"))
+ , m_xStartED(m_xBuilder->weld_spin_button("startat"))
+ , m_xBulletFT(m_xBuilder->weld_label("bulletft"))
+ , m_xBulletPB(m_xBuilder->weld_button("bullet"))
+ , m_xBitmapMB(m_xBuilder->weld_menu_button("bitmap"))
+ , m_xWidthFT(m_xBuilder->weld_label("widthft"))
+ , m_xWidthMF(m_xBuilder->weld_metric_spin_button("widthmf", FieldUnit::CM))
+ , m_xHeightFT(m_xBuilder->weld_label("heightft"))
+ , m_xHeightMF(m_xBuilder->weld_metric_spin_button("heightmf", FieldUnit::CM))
+ , m_xRatioCB(m_xBuilder->weld_check_button("keepratio"))
+ , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreviewWIN))
+ , m_xDistBorderFT(m_xBuilder->weld_label("indent"))
+ , m_xDistBorderMF(m_xBuilder->weld_metric_spin_button("indentmf", FieldUnit::CM))
+ , m_xRelativeCB(m_xBuilder->weld_check_button("relative"))
+ , m_xIndentFT(m_xBuilder->weld_label("numberingwidth"))
+ , m_xIndentMF(m_xBuilder->weld_metric_spin_button("numberingwidthmf", FieldUnit::CM))
+ , m_xLeftTB(m_xBuilder->weld_toggle_button("left"))
+ , m_xCenterTB(m_xBuilder->weld_toggle_button("center"))
+ , m_xRightTB(m_xBuilder->weld_toggle_button("right"))
+ , m_xSlideRB(m_xBuilder->weld_radio_button("sliderb"))
+ , m_xSelectionRB(m_xBuilder->weld_radio_button("selectionrb"))
+ , m_xApplyToMaster(m_xBuilder->weld_toggle_button("applytomaster"))
+ , m_xReset(m_xBuilder->weld_button("reset"))
+{
+ m_xBulColLB->SetSlotId(SID_ATTR_CHAR_COLOR);
+ m_xBulRelSizeMF->set_min(SVX_NUM_REL_SIZE_MIN, FieldUnit::PERCENT);
+ m_xBulRelSizeMF->set_increments(5, 50, FieldUnit::PERCENT);
+ aActBulletFont = lcl_GetDefaultBulletFont();
+
+ m_xBulletPB->connect_clicked(LINK(this, SvxBulletAndPositionDlg, BulletHdl_Impl));
+ m_xFmtLB->connect_changed(LINK(this, SvxBulletAndPositionDlg, NumberTypeSelectHdl_Impl));
+ m_xBitmapMB->connect_selected(LINK(this, SvxBulletAndPositionDlg, GraphicHdl_Impl));
+ m_xBitmapMB->connect_toggled(LINK(this, SvxBulletAndPositionDlg, PopupActivateHdl_Impl));
+ m_xLevelLB->set_selection_mode(SelectionMode::Multiple);
+ m_xLevelLB->connect_changed(LINK(this, SvxBulletAndPositionDlg, LevelHdl_Impl));
+ m_xWidthMF->connect_value_changed(LINK(this, SvxBulletAndPositionDlg, SizeHdl_Impl));
+ m_xHeightMF->connect_value_changed(LINK(this, SvxBulletAndPositionDlg, SizeHdl_Impl));
+ m_xRatioCB->connect_toggled(LINK(this, SvxBulletAndPositionDlg, RatioHdl_Impl));
+ m_xStartED->connect_value_changed(LINK(this, SvxBulletAndPositionDlg, SpinModifyHdl_Impl));
+ m_xPrefixED->connect_changed(LINK(this, SvxBulletAndPositionDlg, EditModifyHdl_Impl));
+ m_xSuffixED->connect_changed(LINK(this, SvxBulletAndPositionDlg, EditModifyHdl_Impl));
+ m_xBulRelSizeMF->connect_value_changed(LINK(this, SvxBulletAndPositionDlg, BulRelSizeHdl_Impl));
+ m_xBulColLB->SetSelectHdl(LINK(this, SvxBulletAndPositionDlg, BulColorHdl_Impl));
+ m_xLeftTB->connect_toggled(LINK(this, SvxBulletAndPositionDlg, SelectLeftAlignmentHdl_Impl));
+ m_xCenterTB->connect_toggled(
+ LINK(this, SvxBulletAndPositionDlg, SelectCenterAlignmentHdl_Impl));
+ m_xRightTB->connect_toggled(LINK(this, SvxBulletAndPositionDlg, SelectRightAlignmentHdl_Impl));
+ m_xApplyToMaster->connect_toggled(LINK(this, SvxBulletAndPositionDlg, ApplyToMasterHdl_Impl));
+ m_xReset->connect_clicked(LINK(this, SvxBulletAndPositionDlg, ResetHdl_Impl));
+
+ aInvalidateTimer.SetInvokeHandler(
+ LINK(this, SvxBulletAndPositionDlg, PreviewInvalidateHdl_Impl));
+ aInvalidateTimer.SetTimeout(50);
+
+ eCoreUnit = rSet.GetPool()->GetMetric(rSet.GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE));
+
+ // Fill ListBox with predefined / translated numbering types.
+ sal_uInt32 nCount = SvxNumberingTypeTable::Count();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ m_xFmtLB->append(OUString::number(SvxNumberingTypeTable::GetValue(i)),
+ SvxNumberingTypeTable::GetString(i));
+ }
+
+ // Get advanced numbering types from the component.
+ // Watch out for the ugly
+ // 136 == 0x88 == SVX_NUM_BITMAP|0x80 == SVX_NUM_BITMAP|LINK_TOKEN
+ // to not remove that.
+ SvxNumOptionsTabPageHelper::GetI18nNumbering(*m_xFmtLB, (SVX_NUM_BITMAP | LINK_TOKEN));
+
+ m_xFmtLB->set_active(0);
+ m_xRelativeCB->set_active(true);
+
+ Link<weld::MetricSpinButton&, void> aLk3
+ = LINK(this, SvxBulletAndPositionDlg, DistanceHdl_Impl);
+ m_xDistBorderMF->connect_value_changed(aLk3);
+ m_xIndentMF->connect_value_changed(aLk3);
+
+ m_xRelativeCB->connect_toggled(LINK(this, SvxBulletAndPositionDlg, RelativeHdl_Impl));
+ m_xRelativeCB->set_active(bLastRelative);
+
+ Size aSize(m_xGrid->get_preferred_size());
+ m_xGrid->set_size_request(aSize.Width(), -1);
+
+ // PageCreated
+ FieldUnit eMetric = pView->GetDoc().GetUIUnit();
+ SfxAllItemSet aSet(*(rSet.GetPool()));
+ aSet.Put(SfxUInt16Item(SID_METRIC_ITEM, static_cast<sal_uInt16>(eMetric)));
+
+ const SfxStringItem* pNumCharFmt = aSet.GetItem<SfxStringItem>(SID_NUM_CHAR_FMT, false);
+ const SfxUInt16Item* pMetricItem = aSet.GetItem<SfxUInt16Item>(SID_METRIC_ITEM, false);
+
+ if (pNumCharFmt)
+ SetCharFmt(pNumCharFmt->GetValue());
+
+ if (pMetricItem)
+ SetMetric(static_cast<FieldUnit>(pMetricItem->GetValue()));
+
+ // tdf#130526: Hide "Apply To Master"-button in Draw and rename "Slide" to "Page"
+ DocumentType aDocumentType = pView->GetDoc().GetDocumentType();
+ if (aDocumentType == DocumentType::Draw)
+ {
+ m_xApplyToMaster->hide();
+ m_xSlideRB->set_label(SdResId(STR_PAGE_NAME));
+ }
+ // tdf#137406: Crash when clicking "Apply to Master" in Slide Master mode on Bullets and Numbering dialog
+ EditMode aEditmode = static_cast<::sd::DrawViewShell*>(pView->GetViewShell())->GetEditMode();
+ if (aDocumentType == DocumentType::Impress && aEditmode == EditMode::MasterPage)
+ m_xApplyToMaster->hide();
+
+ // End PageCreated
+
+ Reset(&rSet);
+
+ // ActivatePage part
+
+ const SfxItemSet* pExampleSet = &rSet;
+ sal_uInt16 nTmpNumLvl = 1;
+ bool bPreset = false;
+ if (pExampleSet)
+ {
+ if (const SfxBoolItem* pItem = pExampleSet->GetItemIfSet(SID_PARAM_NUM_PRESET, false))
+ bPreset = pItem->GetValue();
+ if (const SfxUInt16Item* pItem = pExampleSet->GetItemIfSet(SID_PARAM_CUR_NUM_LEVEL, false))
+ nTmpNumLvl = pItem->GetValue();
+ }
+ if (const SvxNumBulletItem* pItem = rSet.GetItemIfSet(nNumItemId, false))
+ {
+ pSaveNum.reset(new SvxNumRule(pItem->GetNumRule()));
+ }
+
+ bModified = (!pActNum->Get(0) || bPreset);
+ if (*pActNum != *pSaveNum || nActNumLvl != nTmpNumLvl)
+ {
+ nActNumLvl = nTmpNumLvl;
+ sal_uInt16 nMask = 1;
+ if (nActNumLvl == SAL_MAX_UINT16)
+ m_xLevelLB->select(pActNum->GetLevelCount());
+ if (nActNumLvl != SAL_MAX_UINT16)
+ {
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ m_xLevelLB->select(i);
+ nMask <<= 1;
+ }
+ }
+ *pActNum = *pSaveNum;
+
+ m_xRelativeCB->set_sensitive(nActNumLvl != 1);
+
+ InitPosAndSpaceMode();
+ InitControls();
+ }
+
+ m_aPreviewWIN.SetLevel(nActNumLvl);
+ m_aPreviewWIN.Invalidate();
+
+ // End of the ActivatePage part
+}
+
+SvxBulletAndPositionDlg::~SvxBulletAndPositionDlg() {}
+
+void SvxBulletAndPositionDlg::SetMetric(FieldUnit eMetric)
+{
+ if (eMetric == FieldUnit::MM)
+ {
+ m_xWidthMF->set_digits(1);
+ m_xHeightMF->set_digits(1);
+ m_xDistBorderMF->set_digits(1);
+ m_xIndentMF->set_digits(1);
+ }
+ m_xWidthMF->set_unit(eMetric);
+ m_xHeightMF->set_unit(eMetric);
+ m_xDistBorderMF->set_unit(eMetric);
+ m_xIndentMF->set_unit(eMetric);
+}
+
+SfxItemSet* SvxBulletAndPositionDlg::GetOutputItemSet(SfxItemSet* pSet)
+{
+ pSet->Put(SfxUInt16Item(SID_PARAM_CUR_NUM_LEVEL, nActNumLvl));
+ if (bModified && pActNum)
+ {
+ *pSaveNum = *pActNum;
+ pSet->Put(SvxNumBulletItem(*pSaveNum, nNumItemId));
+ pSet->Put(SfxBoolItem(SID_PARAM_NUM_PRESET, false));
+ }
+ return pSet;
+};
+
+bool SvxBulletAndPositionDlg::IsApplyToMaster() const { return bApplyToMaster; }
+bool SvxBulletAndPositionDlg::IsSlideScope() const { return m_xSlideRB->get_active(); }
+
+void SvxBulletAndPositionDlg::Reset(const SfxItemSet* rSet)
+{
+ const SvxNumBulletItem* pItem = rSet->GetItemIfSet(SID_ATTR_NUMBERING_RULE, false);
+ // in Draw the item exists as WhichId, in Writer only as SlotId
+ if (!pItem)
+ {
+ nNumItemId = rSet->GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE);
+ pItem = rSet->GetItemIfSet(nNumItemId, false);
+
+ if (!pItem)
+ {
+ pItem = &rSet->Get(nNumItemId);
+ }
+ }
+ DBG_ASSERT(pItem, "no item found!");
+ pSaveNum.reset(new SvxNumRule(pItem->GetNumRule()));
+
+ // insert levels
+ if (!m_xLevelLB->n_children())
+ {
+ for (sal_uInt16 i = 1; i <= pSaveNum->GetLevelCount(); i++)
+ m_xLevelLB->append_text(OUString::number(i));
+ if (pSaveNum->GetLevelCount() > 1)
+ {
+ OUString sEntry = "1 - " + OUString::number(pSaveNum->GetLevelCount());
+ m_xLevelLB->append_text(sEntry);
+ m_xLevelLB->select_text(sEntry);
+ }
+ else
+ m_xLevelLB->select(0);
+ }
+ else
+ m_xLevelLB->select(m_xLevelLB->n_children() - 1);
+
+ sal_uInt16 nMask = 1;
+ m_xLevelLB->unselect_all();
+ if (nActNumLvl == SAL_MAX_UINT16)
+ {
+ m_xLevelLB->select(pSaveNum->GetLevelCount());
+ }
+ else
+ {
+ for (sal_uInt16 i = 0; i < pSaveNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ m_xLevelLB->select(i);
+ nMask <<= 1;
+ }
+ }
+
+ if (!pActNum)
+ pActNum.reset(new SvxNumRule(*pSaveNum));
+ else if (*pSaveNum != *pActNum)
+ *pActNum = *pSaveNum;
+ m_aPreviewWIN.SetNumRule(pActNum.get());
+
+ bool bContinuous = pActNum->IsFeatureSupported(SvxNumRuleFlags::CONTINUOUS);
+
+ // again misusage: in Draw there is numeration only until the bitmap
+ // without SVX_NUM_NUMBER_NONE
+ //remove types that are unsupported by Draw/Impress
+ if (!bContinuous)
+ {
+ sal_Int32 nFmtCount = m_xFmtLB->get_count();
+ for (sal_Int32 i = nFmtCount; i; i--)
+ {
+ sal_uInt16 nEntryData = m_xFmtLB->get_id(i - 1).toUInt32();
+ if (/*SVX_NUM_NUMBER_NONE == nEntryData ||*/
+ (SVX_NUM_BITMAP | LINK_TOKEN) == nEntryData)
+ m_xFmtLB->remove(i - 1);
+ }
+ }
+ //one must be enabled
+ if (!pActNum->IsFeatureSupported(SvxNumRuleFlags::ENABLE_LINKED_BMP))
+ {
+ auto nPos = m_xFmtLB->find_id(OUString::number(SVX_NUM_BITMAP | LINK_TOKEN));
+ if (nPos != -1)
+ m_xFmtLB->remove(nPos);
+ }
+ else if (!pActNum->IsFeatureSupported(SvxNumRuleFlags::ENABLE_EMBEDDED_BMP))
+ {
+ auto nPos = m_xFmtLB->find_id(OUString::number(SVX_NUM_BITMAP));
+ if (nPos != -1)
+ m_xFmtLB->remove(nPos);
+ }
+
+ // MegaHack: because of a not-fixable 'design mistake/error' in Impress
+ // delete all kinds of numeric enumerations
+ if (pActNum->IsFeatureSupported(SvxNumRuleFlags::NO_NUMBERS))
+ {
+ sal_Int32 nFmtCount = m_xFmtLB->get_count();
+ for (sal_Int32 i = nFmtCount; i; i--)
+ {
+ sal_uInt16 nEntryData = m_xFmtLB->get_id(i - 1).toUInt32();
+ if (/*nEntryData >= SVX_NUM_CHARS_UPPER_LETTER &&*/ nEntryData <= SVX_NUM_NUMBER_NONE)
+ m_xFmtLB->remove(i - 1);
+ }
+ }
+
+ InitPosAndSpaceMode();
+
+ InitControls();
+ bModified = false;
+}
+
+void SvxBulletAndPositionDlg::InitControls()
+{
+ bInInitControl = true;
+
+ const bool bRelative = !bLabelAlignmentPosAndSpaceModeActive && m_xRelativeCB->get_sensitive()
+ && m_xRelativeCB->get_active();
+ const bool bSingleSelection
+ = m_xLevelLB->count_selected_rows() == 1 && SAL_MAX_UINT16 != nActNumLvl;
+
+ m_xDistBorderMF->set_sensitive(!bLabelAlignmentPosAndSpaceModeActive
+ && (bSingleSelection || bRelative));
+ m_xDistBorderFT->set_sensitive(!bLabelAlignmentPosAndSpaceModeActive
+ && (bSingleSelection || bRelative));
+
+ bool bShowBullet = true;
+ bool bShowBitmap = true;
+ bool bSameType = true;
+ bool bSameStart = true;
+ bool bSamePrefix = true;
+ bool bSameSuffix = true;
+ bool bSameSize = true;
+ bool bSameBulColor = true;
+ bool bSameBulRelSize = true;
+ bool bSameDistBorderNum = !bLabelAlignmentPosAndSpaceModeActive;
+ bool bSetDistEmpty = false;
+ bool bSameIndent = !bLabelAlignmentPosAndSpaceModeActive;
+
+ const SvxNumberFormat* aNumFmtArr[SVX_MAX_NUM];
+ SvxAdjust eFirstAdjust = SvxAdjust::Left;
+ Size aFirstSize(0, 0);
+ sal_uInt16 nMask = 1;
+ sal_uInt16 nLvl = SAL_MAX_UINT16;
+
+ bool bBullColor = pActNum->IsFeatureSupported(SvxNumRuleFlags::BULLET_COLOR);
+ bool bBullRelSize = pActNum->IsFeatureSupported(SvxNumRuleFlags::BULLET_REL_SIZE);
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ aNumFmtArr[i] = &pActNum->GetLevel(i);
+
+ if (nActNumLvl & nMask)
+ {
+ bShowBullet &= aNumFmtArr[i]->GetNumberingType() == SVX_NUM_CHAR_SPECIAL;
+ bShowBitmap &= (aNumFmtArr[i]->GetNumberingType() & (~LINK_TOKEN)) == SVX_NUM_BITMAP;
+ eFirstAdjust = aNumFmtArr[i]->GetNumAdjust();
+ if (SAL_MAX_UINT16 == nLvl)
+ {
+ nLvl = i;
+ if (bShowBitmap)
+ aFirstSize = aNumFmtArr[i]->GetGraphicSize();
+ }
+ if (i > nLvl)
+ {
+ bSameType
+ &= aNumFmtArr[i]->GetNumberingType() == aNumFmtArr[nLvl]->GetNumberingType();
+ bSameStart = aNumFmtArr[i]->GetStart() == aNumFmtArr[nLvl]->GetStart();
+
+ bSamePrefix = aNumFmtArr[i]->GetPrefix() == aNumFmtArr[nLvl]->GetPrefix();
+ bSameSuffix = aNumFmtArr[i]->GetSuffix() == aNumFmtArr[nLvl]->GetSuffix();
+ //bSameAdjust &= eFirstAdjust == aNumFmtArr[i]->GetNumAdjust();
+ if (bShowBitmap && bSameSize)
+ bSameSize &= aNumFmtArr[i]->GetGraphicSize() == aFirstSize;
+ bSameBulColor
+ &= aNumFmtArr[i]->GetBulletColor() == aNumFmtArr[nLvl]->GetBulletColor();
+ bSameBulRelSize
+ &= aNumFmtArr[i]->GetBulletRelSize() == aNumFmtArr[nLvl]->GetBulletRelSize();
+ bSameIndent //?
+ &= aNumFmtArr[i]->GetFirstLineOffset()
+ == aNumFmtArr[nLvl]->GetFirstLineOffset();
+ }
+ }
+
+ nMask <<= 1;
+ }
+ SwitchNumberType(bShowBullet ? 1 : bShowBitmap ? 2 : 0);
+
+ sal_uInt16 nNumberingType;
+ if (nLvl != SAL_MAX_UINT16)
+ nNumberingType = aNumFmtArr[nLvl]->GetNumberingType();
+ else
+ {
+ nNumberingType = SVX_NUM_NUMBER_NONE;
+ bSameDistBorderNum = false;
+ bSameIndent = false;
+ bSameBulRelSize = false;
+ bSameBulColor = false;
+ bSameStart = false;
+ bSamePrefix = false;
+ bSameSuffix = false;
+ }
+
+ CheckForStartValue_Impl(nNumberingType);
+
+ if (bShowBitmap)
+ {
+ if (bSameSize)
+ {
+ SetMetricValue(*m_xHeightMF, aFirstSize.Height(), eCoreUnit);
+ SetMetricValue(*m_xWidthMF, aFirstSize.Width(), eCoreUnit);
+ }
+ else
+ {
+ m_xHeightMF->set_text("");
+ m_xWidthMF->set_text("");
+ }
+ }
+
+ if (bSameType)
+ {
+ sal_uInt16 nLBData = nNumberingType;
+ m_xFmtLB->set_active_id(OUString::number(nLBData));
+ }
+ else
+ m_xFmtLB->set_active(-1);
+
+ if (bBullRelSize)
+ {
+ if (bSameBulRelSize)
+ m_xBulRelSizeMF->set_value(aNumFmtArr[nLvl]->GetBulletRelSize(), FieldUnit::PERCENT);
+ else
+ m_xBulRelSizeMF->set_text("");
+ }
+ if (bBullColor)
+ {
+ if (bSameBulColor)
+ m_xBulColLB->SelectEntry(aNumFmtArr[nLvl]->GetBulletColor());
+ else
+ m_xBulColLB->SetNoSelection();
+ }
+ switch (nBullet)
+ {
+ case SHOW_NUMBERING:
+ if (bSameStart)
+ {
+ m_xStartED->set_value(aNumFmtArr[nLvl]->GetStart());
+ }
+ else
+ m_xStartED->set_text("");
+ break;
+ case SHOW_BULLET:
+ break;
+ case SHOW_BITMAP:
+ break;
+ }
+
+ switch (eFirstAdjust)
+ {
+ case SvxAdjust::Left:
+ m_xLeftTB->set_active(true);
+ m_xCenterTB->set_active(false);
+ m_xRightTB->set_active(false);
+ break;
+ case SvxAdjust::Center:
+ m_xLeftTB->set_active(false);
+ m_xCenterTB->set_active(true);
+ m_xRightTB->set_active(false);
+ break;
+ case SvxAdjust::Right:
+ m_xLeftTB->set_active(false);
+ m_xCenterTB->set_active(false);
+ m_xRightTB->set_active(true);
+ break;
+ default:
+ break;
+ }
+
+ if (bSamePrefix)
+ m_xPrefixED->set_text(aNumFmtArr[nLvl]->GetPrefix());
+ else
+ m_xPrefixED->set_text("");
+ if (bSameSuffix)
+ m_xSuffixED->set_text(aNumFmtArr[nLvl]->GetSuffix());
+ else
+ m_xSuffixED->set_text("");
+
+ if (bSameDistBorderNum)
+ {
+ tools::Long nDistBorderNum;
+ if (bRelative)
+ {
+ nDistBorderNum = static_cast<tools::Long>(aNumFmtArr[nLvl]->GetAbsLSpace())
+ + aNumFmtArr[nLvl]->GetFirstLineOffset();
+ if (nLvl)
+ nDistBorderNum -= static_cast<tools::Long>(aNumFmtArr[nLvl - 1]->GetAbsLSpace())
+ + aNumFmtArr[nLvl - 1]->GetFirstLineOffset();
+ }
+ else
+ {
+ nDistBorderNum = static_cast<tools::Long>(aNumFmtArr[nLvl]->GetAbsLSpace())
+ + aNumFmtArr[nLvl]->GetFirstLineOffset();
+ }
+ SetMetricValue(*m_xDistBorderMF, nDistBorderNum, eCoreUnit);
+ }
+ else
+ bSetDistEmpty = true;
+
+ if (bSetDistEmpty)
+ m_xDistBorderMF->set_text("");
+
+ if (bSameIndent)
+ SetMetricValue(*m_xIndentMF, -aNumFmtArr[nLvl]->GetFirstLineOffset(), eCoreUnit);
+ else
+ m_xIndentMF->set_text("");
+
+ m_xSelectionRB->set_active(true);
+
+ m_aPreviewWIN.SetLevel(nActNumLvl);
+ m_aPreviewWIN.Invalidate();
+ bInInitControl = false;
+}
+
+// 0 - Number; 1 - Bullet; 2 - Bitmap
+void SvxBulletAndPositionDlg::SwitchNumberType(sal_uInt8 nType)
+{
+ if (nBullet == nType)
+ return;
+ nBullet = nType;
+ bool bBullet = (nType == SHOW_BULLET);
+ bool bBitmap = (nType == SHOW_BITMAP);
+ bool bEnableBitmap = (nType == SHOW_BITMAP);
+ bool bNumeric = !(bBitmap || bBullet);
+ m_xPrefixFT->set_visible(bNumeric);
+ m_xPrefixED->set_visible(bNumeric);
+ m_xSuffixFT->set_visible(bNumeric);
+ m_xSuffixED->set_visible(bNumeric);
+ m_xBeforeAfter->set_visible(bNumeric);
+
+ m_xStartFT->set_visible(!(bBullet || bBitmap));
+ m_xStartED->set_visible(!(bBullet || bBitmap));
+
+ m_xBulletFT->set_visible(bBullet);
+ m_xBulletPB->set_visible(bBullet);
+ bool bBullColor = pActNum->IsFeatureSupported(SvxNumRuleFlags::BULLET_COLOR);
+ m_xBulColorFT->set_visible(!bBitmap && bBullColor);
+ m_xBulColLB->set_visible(!bBitmap && bBullColor);
+ bool bBullResSize = pActNum->IsFeatureSupported(SvxNumRuleFlags::BULLET_REL_SIZE);
+ m_xBulRelSizeFT->set_visible(!bBitmap && bBullResSize);
+ m_xBulRelSizeMF->set_visible(!bBitmap && bBullResSize);
+
+ m_xBitmapMB->set_visible(bBitmap);
+
+ m_xWidthFT->set_visible(bBitmap);
+ m_xWidthMF->set_visible(bBitmap);
+ m_xHeightFT->set_visible(bBitmap);
+ m_xHeightMF->set_visible(bBitmap);
+ m_xRatioCB->set_visible(bBitmap);
+
+ m_xWidthFT->set_sensitive(bEnableBitmap);
+ m_xWidthMF->set_sensitive(bEnableBitmap);
+ m_xHeightFT->set_sensitive(bEnableBitmap);
+ m_xHeightMF->set_sensitive(bEnableBitmap);
+ m_xRatioCB->set_sensitive(bEnableBitmap);
+}
+
+void SvxBulletAndPositionDlg::CheckForStartValue_Impl(sal_uInt16 nNumberingType)
+{
+ bool bIsNull = m_xStartED->get_value() == 0;
+ bool bNoZeroAllowed = nNumberingType < SVX_NUM_ARABIC
+ || SVX_NUM_CHARS_UPPER_LETTER_N == nNumberingType
+ || SVX_NUM_CHARS_LOWER_LETTER_N == nNumberingType;
+ m_xStartED->set_min(bNoZeroAllowed ? 1 : 0);
+ if (bIsNull && bNoZeroAllowed)
+ SpinModifyHdl_Impl(*m_xStartED);
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, LevelHdl_Impl, weld::TreeView&, rBox, void)
+{
+ sal_uInt16 nSaveNumLvl = nActNumLvl;
+ nActNumLvl = 0;
+ auto aSelectedRows = rBox.get_selected_rows();
+ if (std::find(aSelectedRows.begin(), aSelectedRows.end(), pActNum->GetLevelCount())
+ != aSelectedRows.end()
+ && (aSelectedRows.size() == 1 || nSaveNumLvl != 0xffff))
+ {
+ nActNumLvl = 0xFFFF;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ rBox.unselect(i);
+ }
+ else if (!aSelectedRows.empty())
+ {
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (std::find(aSelectedRows.begin(), aSelectedRows.end(), i) != aSelectedRows.end())
+ nActNumLvl |= nMask;
+ nMask <<= 1;
+ }
+ rBox.unselect(pActNum->GetLevelCount());
+ }
+ else
+ nActNumLvl = nSaveNumLvl;
+
+ InitControls();
+}
+
+IMPL_LINK_NOARG(SvxBulletAndPositionDlg, PreviewInvalidateHdl_Impl, Timer*, void)
+{
+ m_aPreviewWIN.Invalidate();
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, NumberTypeSelectHdl_Impl, weld::ComboBox&, rBox, void)
+{
+ bool bBmp = false;
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ {
+ SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+ // PAGEDESC does not exist
+ SvxNumType nNumType = static_cast<SvxNumType>(rBox.get_active_id().toUInt32());
+ aNumFmt.SetNumberingType(nNumType);
+ sal_uInt16 nNumberingType = aNumFmt.GetNumberingType();
+ if (SVX_NUM_BITMAP == (nNumberingType & (~LINK_TOKEN)))
+ {
+ bBmp |= nullptr != aNumFmt.GetBrush();
+ aNumFmt.SetIncludeUpperLevels(0);
+ aNumFmt.SetListFormat("", "", i);
+ if (!bBmp)
+ aNumFmt.SetGraphic("");
+ pActNum->SetLevel(i, aNumFmt);
+ SwitchNumberType(SHOW_BITMAP);
+ }
+ else if (SVX_NUM_CHAR_SPECIAL == nNumberingType)
+ {
+ aNumFmt.SetIncludeUpperLevels(0);
+ aNumFmt.SetListFormat("", "", i);
+ if (!aNumFmt.GetBulletFont())
+ aNumFmt.SetBulletFont(&aActBulletFont);
+ if (!aNumFmt.GetBulletChar())
+ aNumFmt.SetBulletChar(SVX_DEF_BULLET);
+ pActNum->SetLevel(i, aNumFmt);
+ SwitchNumberType(SHOW_BULLET);
+ // allocation of the drawing pattern is automatic
+ }
+ else
+ {
+ aNumFmt.SetListFormat(m_xPrefixED->get_text(), m_xSuffixED->get_text(), i);
+ SwitchNumberType(SHOW_NUMBERING);
+ pActNum->SetLevel(i, aNumFmt);
+ CheckForStartValue_Impl(nNumberingType);
+
+ // allocation of the drawing pattern is automatic
+ }
+ }
+ nMask <<= 1;
+ }
+
+ SetModified();
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, BulColorHdl_Impl, ColorListBox&, rColorBox, void)
+{
+ Color nSetColor = rColorBox.GetSelectEntryColor();
+
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ {
+ SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+ aNumFmt.SetBulletColor(nSetColor);
+ pActNum->SetLevel(i, aNumFmt);
+ }
+ nMask <<= 1;
+ }
+ SetModified();
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, BulRelSizeHdl_Impl, weld::MetricSpinButton&, rField, void)
+{
+ sal_uInt16 nRelSize = rField.get_value(FieldUnit::PERCENT);
+
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ {
+ SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+ aNumFmt.SetBulletRelSize(nRelSize);
+ pActNum->SetLevel(i, aNumFmt);
+ }
+ nMask <<= 1;
+ }
+ SetModified();
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, GraphicHdl_Impl, const OString&, rIdent, void)
+{
+ OUString aGrfName;
+ Size aSize;
+ bool bSucc(false);
+ SvxOpenGraphicDialog aGrfDlg(SdResId(RID_SVXSTR_EDIT_GRAPHIC), p_Window);
+
+ OString sNumber;
+ if (rIdent.startsWith("gallery", &sNumber))
+ {
+ auto idx = sNumber.toUInt32();
+ if (idx < aGrfNames.size())
+ {
+ aGrfName = aGrfNames[idx];
+ Graphic aGraphic;
+ if (GalleryExplorer::GetGraphicObj(GALLERY_THEME_BULLETS, idx, &aGraphic))
+ {
+ aSize = SvxNumberFormat::GetGraphicSizeMM100(&aGraphic);
+ bSucc = true;
+ }
+ }
+ }
+ else if (rIdent == "fromfile")
+ {
+ aGrfDlg.EnableLink(false);
+ aGrfDlg.AsLink(false);
+ if (!aGrfDlg.Execute())
+ {
+ // memorize selected filter
+ aGrfName = aGrfDlg.GetPath();
+
+ Graphic aGraphic;
+ if (!aGrfDlg.GetGraphic(aGraphic))
+ {
+ aSize = SvxNumberFormat::GetGraphicSizeMM100(&aGraphic);
+ bSucc = true;
+ }
+ }
+ }
+ if (!bSucc)
+ return;
+
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(eCoreUnit));
+
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ {
+ SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+ aNumFmt.SetCharFormatName(m_sNumCharFmtName);
+ aNumFmt.SetGraphic(aGrfName);
+
+ // set size for a later comparison
+ const SvxBrushItem* pBrushItem = aNumFmt.GetBrush();
+ // initiate asynchronous loading
+ sal_Int16 eOrient = aNumFmt.GetVertOrient();
+ aNumFmt.SetGraphicBrush(pBrushItem, &aSize, &eOrient);
+ aInitSize[i] = aNumFmt.GetGraphicSize();
+
+ pActNum->SetLevel(i, aNumFmt);
+ }
+ nMask <<= 1;
+ }
+ m_xRatioCB->set_sensitive(true);
+ m_xWidthFT->set_sensitive(true);
+ m_xHeightFT->set_sensitive(true);
+ m_xWidthMF->set_sensitive(true);
+ m_xHeightMF->set_sensitive(true);
+ SetMetricValue(*m_xWidthMF, aSize.Width(), eCoreUnit);
+ SetMetricValue(*m_xHeightMF, aSize.Height(), eCoreUnit);
+
+ SetModified();
+ //needed due to asynchronous loading of graphics in the SvxBrushItem
+ aInvalidateTimer.Start();
+}
+
+IMPL_LINK_NOARG(SvxBulletAndPositionDlg, PopupActivateHdl_Impl, weld::Toggleable&, void)
+{
+ if (m_xGalleryMenu)
+ return;
+
+ m_xGalleryMenu = m_xBuilder->weld_menu("gallerysubmenu");
+ weld::WaitObject aWait(p_Window);
+
+ if (!GalleryExplorer::FillObjList(GALLERY_THEME_BULLETS, aGrfNames))
+ return;
+
+ GalleryExplorer::BeginLocking(GALLERY_THEME_BULLETS);
+
+ Graphic aGraphic;
+ OUString sGrfName;
+ ScopedVclPtrInstance<VirtualDevice> pVD;
+ size_t i = 0;
+ for (const auto& grfName : aGrfNames)
+ {
+ sGrfName = grfName;
+ OUString sItemId = "gallery" + OUString::number(i);
+ INetURLObject aObj(sGrfName);
+ if (aObj.GetProtocol() == INetProtocol::File)
+ sGrfName = aObj.PathToFileName();
+ if (GalleryExplorer::GetGraphicObj(GALLERY_THEME_BULLETS, i, &aGraphic))
+ {
+ BitmapEx aBitmap(aGraphic.GetBitmapEx());
+ Size aSize(aBitmap.GetSizePixel());
+ if (aSize.Width() > MAX_BMP_WIDTH || aSize.Height() > MAX_BMP_HEIGHT)
+ {
+ bool bWidth = aSize.Width() > aSize.Height();
+ double nScale = bWidth
+ ? double(MAX_BMP_WIDTH) / static_cast<double>(aSize.Width())
+ : double(MAX_BMP_HEIGHT) / static_cast<double>(aSize.Height());
+ aBitmap.Scale(nScale, nScale);
+ }
+ pVD->SetOutputSizePixel(aBitmap.GetSizePixel(), false);
+ pVD->DrawBitmapEx(Point(), aBitmap);
+
+ // We want to show only icon names not full path.
+ aObj.removeExtension();
+ OUString sIconName = aObj.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
+
+ m_xGalleryMenu->append(sItemId, sIconName, *pVD);
+ }
+ else
+ {
+ m_xGalleryMenu->append(sItemId, sGrfName);
+ }
+ ++i;
+ }
+ GalleryExplorer::EndLocking(GALLERY_THEME_BULLETS);
+}
+
+IMPL_LINK_NOARG(SvxBulletAndPositionDlg, BulletHdl_Impl, weld::Button&, void)
+{
+ SvxCharacterMap aMap(p_Window, nullptr, nullptr);
+
+ sal_uInt16 nMask = 1;
+ std::optional<vcl::Font> pFmtFont;
+ bool bSameBullet = true;
+ sal_UCS4 cBullet = 0;
+ bool bFirst = true;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ {
+ const SvxNumberFormat& rCurFmt = pActNum->GetLevel(i);
+ if (bFirst)
+ {
+ cBullet = rCurFmt.GetBulletChar();
+ }
+ else if (rCurFmt.GetBulletChar() != cBullet)
+ {
+ bSameBullet = false;
+ break;
+ }
+ if (!pFmtFont)
+ pFmtFont = rCurFmt.GetBulletFont();
+ bFirst = false;
+ }
+ nMask <<= 1;
+ }
+
+ if (pFmtFont)
+ aMap.SetCharFont(*pFmtFont);
+ else
+ aMap.SetCharFont(aActBulletFont);
+ if (bSameBullet)
+ aMap.SetChar(cBullet);
+ if (aMap.run() != RET_OK)
+ return;
+
+ // change Font Numrules
+ aActBulletFont = aMap.GetCharFont();
+
+ sal_uInt16 _nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & _nMask)
+ {
+ SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+ aNumFmt.SetBulletFont(&aActBulletFont);
+ aNumFmt.SetBulletChar(aMap.GetChar());
+ pActNum->SetLevel(i, aNumFmt);
+ }
+ _nMask <<= 1;
+ }
+
+ SetModified();
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, SizeHdl_Impl, weld::MetricSpinButton&, rField, void)
+{
+ bool bWidth = &rField == m_xWidthMF.get();
+ bLastWidthModified = bWidth;
+ bool bRatio = m_xRatioCB->get_active();
+ tools::Long nWidthVal = static_cast<tools::Long>(
+ m_xWidthMF->denormalize(m_xWidthMF->get_value(FieldUnit::MM_100TH)));
+ tools::Long nHeightVal = static_cast<tools::Long>(
+ m_xHeightMF->denormalize(m_xHeightMF->get_value(FieldUnit::MM_100TH)));
+ nWidthVal = OutputDevice::LogicToLogic(nWidthVal, MapUnit::Map100thMM, eCoreUnit);
+ nHeightVal = OutputDevice::LogicToLogic(nHeightVal, MapUnit::Map100thMM, eCoreUnit);
+ double fSizeRatio;
+
+ bool bRepaint = false;
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ {
+ SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+ if (SVX_NUM_BITMAP == (aNumFmt.GetNumberingType() & (~LINK_TOKEN)))
+ {
+ Size aSize(aNumFmt.GetGraphicSize());
+ Size aSaveSize(aSize);
+
+ if (aInitSize[i].Height())
+ fSizeRatio = static_cast<double>(aInitSize[i].Width())
+ / static_cast<double>(aInitSize[i].Height());
+ else
+ fSizeRatio = double(1);
+
+ if (bWidth)
+ {
+ tools::Long nDelta = nWidthVal - aInitSize[i].Width();
+ aSize.setWidth(nWidthVal);
+ if (bRatio)
+ {
+ aSize.setHeight(
+ aInitSize[i].Height()
+ + static_cast<tools::Long>(static_cast<double>(nDelta) / fSizeRatio));
+ m_xHeightMF->set_value(m_xHeightMF->normalize(OutputDevice::LogicToLogic(
+ aSize.Height(), eCoreUnit, MapUnit::Map100thMM)),
+ FieldUnit::MM_100TH);
+ }
+ }
+ else
+ {
+ tools::Long nDelta = nHeightVal - aInitSize[i].Height();
+ aSize.setHeight(nHeightVal);
+ if (bRatio)
+ {
+ aSize.setWidth(
+ aInitSize[i].Width()
+ + static_cast<tools::Long>(static_cast<double>(nDelta) * fSizeRatio));
+ m_xWidthMF->set_value(m_xWidthMF->normalize(OutputDevice::LogicToLogic(
+ aSize.Width(), eCoreUnit, MapUnit::Map100thMM)),
+ FieldUnit::MM_100TH);
+ }
+ }
+ const SvxBrushItem* pBrushItem = aNumFmt.GetBrush();
+ sal_Int16 eOrient = aNumFmt.GetVertOrient();
+ if (aSize != aSaveSize)
+ bRepaint = true;
+ aNumFmt.SetGraphicBrush(pBrushItem, &aSize, &eOrient);
+ pActNum->SetLevel(i, aNumFmt);
+ }
+ }
+ nMask <<= 1;
+ }
+ SetModified(bRepaint);
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, RatioHdl_Impl, weld::Toggleable&, rBox, void)
+{
+ if (rBox.get_active())
+ {
+ if (bLastWidthModified)
+ SizeHdl_Impl(*m_xWidthMF);
+ else
+ SizeHdl_Impl(*m_xHeightMF);
+ }
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, SelectLeftAlignmentHdl_Impl, weld::Toggleable&, rButton, void)
+{
+ if (rButton.get_active())
+ {
+ SetAlignmentHdl_Impl(SvxAdjust::Left);
+
+ m_xCenterTB->set_active(false);
+ m_xRightTB->set_active(false);
+
+ SetModified();
+ }
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, SelectCenterAlignmentHdl_Impl, weld::Toggleable&, rButton, void)
+{
+ if (rButton.get_active())
+ {
+ SetAlignmentHdl_Impl(SvxAdjust::Center);
+
+ m_xLeftTB->set_active(false);
+ m_xRightTB->set_active(false);
+
+ SetModified();
+ }
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, SelectRightAlignmentHdl_Impl, weld::Toggleable&, rButton, void)
+{
+ if (rButton.get_active())
+ {
+ SetAlignmentHdl_Impl(SvxAdjust::Right);
+
+ m_xLeftTB->set_active(false);
+ m_xCenterTB->set_active(false);
+
+ SetModified();
+ }
+}
+
+void SvxBulletAndPositionDlg::SetAlignmentHdl_Impl(SvxAdjust eAdjust)
+{
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ {
+ SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+ aNumFmt.SetNumAdjust(eAdjust);
+ pActNum->SetLevel(i, aNumFmt);
+ }
+ nMask <<= 1;
+ }
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, ApplyToMasterHdl_Impl, weld::Toggleable&, rButton, void)
+{
+ bApplyToMaster = rButton.get_active();
+}
+
+IMPL_LINK_NOARG(SvxBulletAndPositionDlg, ResetHdl_Impl, weld::Button&, void)
+{
+ Reset(&rFirstStateSet);
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, EditModifyHdl_Impl, weld::Entry&, rEdit, void)
+{
+ EditModifyHdl_Impl(&rEdit);
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, SpinModifyHdl_Impl, weld::SpinButton&, rSpinButton, void)
+{
+ EditModifyHdl_Impl(&rSpinButton);
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, DistanceHdl_Impl, weld::MetricSpinButton&, rFld, void)
+{
+ if (bInInitControl)
+ return;
+ tools::Long nValue = GetCoreValue(rFld, eCoreUnit);
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ {
+ SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+ if (&rFld == m_xDistBorderMF.get())
+ {
+ if (m_xRelativeCB->get_active())
+ {
+ if (0 == i)
+ {
+ auto const nTmp = aNumFmt.GetFirstLineOffset();
+ aNumFmt.SetAbsLSpace(nValue - nTmp);
+ }
+ else
+ {
+ tools::Long nTmp = pActNum->GetLevel(i - 1).GetAbsLSpace()
+ + pActNum->GetLevel(i - 1).GetFirstLineOffset()
+ - pActNum->GetLevel(i).GetFirstLineOffset();
+
+ aNumFmt.SetAbsLSpace(nValue + nTmp);
+ }
+ }
+ else
+ {
+ aNumFmt.SetAbsLSpace(nValue - aNumFmt.GetFirstLineOffset());
+ }
+ }
+ else if (&rFld == m_xIndentMF.get())
+ {
+ // together with the FirstLineOffset the AbsLSpace must be changed, too
+ tools::Long nDiff = nValue + aNumFmt.GetFirstLineOffset();
+ auto const nAbsLSpace = aNumFmt.GetAbsLSpace();
+ aNumFmt.SetAbsLSpace(nAbsLSpace + nDiff);
+ aNumFmt.SetFirstLineOffset(-nValue);
+ }
+
+ pActNum->SetLevel(i, aNumFmt);
+ }
+ nMask <<= 1;
+ }
+
+ SetModified();
+ if (!m_xDistBorderMF->get_sensitive())
+ {
+ m_xDistBorderMF->set_text("");
+ }
+
+ sal_Int32 aLastLevelLSpace
+ = pActNum->GetLevel(pActNum->GetLevelCount() - 1).GetAbsLSpace() / 40;
+ m_aPreviewWIN.set_size_request(aLastLevelLSpace, 300);
+}
+
+IMPL_LINK(SvxBulletAndPositionDlg, RelativeHdl_Impl, weld::Toggleable&, rBox, void)
+{
+ bool bOn = rBox.get_active();
+ bool bSingleSelection = m_xLevelLB->count_selected_rows() == 1 && SAL_MAX_UINT16 != nActNumLvl;
+ bool bSetValue = false;
+ tools::Long nValue = 0;
+ if (bOn || bSingleSelection)
+ {
+ sal_uInt16 nMask = 1;
+ bool bFirst = true;
+ bSetValue = true;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ {
+ const SvxNumberFormat& rNumFmt = pActNum->GetLevel(i);
+ if (bFirst)
+ {
+ nValue = rNumFmt.GetAbsLSpace() + rNumFmt.GetFirstLineOffset();
+ if (bOn && i)
+ nValue -= (pActNum->GetLevel(i - 1).GetAbsLSpace()
+ + pActNum->GetLevel(i - 1).GetFirstLineOffset());
+ }
+ else
+ bSetValue = nValue
+ == (rNumFmt.GetAbsLSpace() + rNumFmt.GetFirstLineOffset())
+ - (pActNum->GetLevel(i - 1).GetAbsLSpace()
+ + pActNum->GetLevel(i - 1).GetFirstLineOffset());
+ bFirst = false;
+ }
+ nMask <<= 1;
+ }
+ }
+ if (bSetValue)
+ SetMetricValue(*m_xDistBorderMF, nValue, eCoreUnit);
+ else
+ m_xDistBorderMF->set_text("");
+ m_xDistBorderMF->set_sensitive(bOn || bSingleSelection);
+ m_xDistBorderFT->set_sensitive(bOn || bSingleSelection);
+ bLastRelative = bOn;
+}
+
+void SvxBulletAndPositionDlg::EditModifyHdl_Impl(const weld::Entry* pEdit)
+{
+ bool bPrefixOrSuffix = (pEdit == m_xPrefixED.get()) || (pEdit == m_xSuffixED.get());
+ bool bStart = pEdit == m_xStartED.get();
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+ {
+ if (nActNumLvl & nMask)
+ {
+ SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+ if (bPrefixOrSuffix)
+ aNumFmt.SetListFormat(m_xPrefixED->get_text(), m_xSuffixED->get_text(), i);
+ else if (bStart)
+ aNumFmt.SetStart(m_xStartED->get_value());
+ pActNum->SetLevel(i, aNumFmt);
+ }
+ nMask <<= 1;
+ }
+ SetModified();
+}
+
+void SvxBulletAndPositionDlg::SetModified(bool bRepaint)
+{
+ bModified = true;
+ if (bRepaint)
+ {
+ m_aPreviewWIN.SetLevel(nActNumLvl);
+ m_aPreviewWIN.Invalidate();
+ }
+}
+
+void SvxBulletAndPositionDlg::InitPosAndSpaceMode()
+{
+ if (pActNum == nullptr)
+ {
+ SAL_WARN("cui.tabpages", "<SvxNumPositionTabPage::InitPosAndSpaceMode()> - misusage of "
+ "method -> <pAktNum> has to be already set!");
+ return;
+ }
+
+ SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode = SvxNumberFormat::LABEL_ALIGNMENT;
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); ++i)
+ {
+ if (nActNumLvl & nMask)
+ {
+ SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+ ePosAndSpaceMode = aNumFmt.GetPositionAndSpaceMode();
+ if (ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT)
+ {
+ break;
+ }
+ }
+ nMask <<= 1;
+ }
+
+ bLabelAlignmentPosAndSpaceModeActive = ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/LayerTabBar.cxx b/sd/source/ui/dlg/LayerTabBar.cxx
new file mode 100644
index 000000000..41cc90ac7
--- /dev/null
+++ b/sd/source/ui/dlg/LayerTabBar.cxx
@@ -0,0 +1,437 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <LayerTabBar.hxx>
+#include <svx/svdlayer.hxx>
+#include <svx/svdpagv.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <helpids.h>
+#include <app.hrc>
+#include <strings.hrc>
+
+#include <DrawViewShell.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <sdresid.hxx>
+#include <unokywds.hxx>
+#include <DrawDocShell.hxx>
+#include <drawview.hxx>
+#include <undolayer.hxx>
+
+namespace sd {
+
+/**
+ * default constructor
+ */
+LayerTabBar::LayerTabBar(DrawViewShell* pViewSh, vcl::Window* pParent)
+ : TabBar( pParent, WinBits( WB_BORDER | WB_3DLOOK | WB_SCROLL ) ),
+ DropTargetHelper( this ),
+ pDrViewSh(pViewSh)
+{
+ EnableEditMode();
+ SetSizePixel(Size(0, 0));
+ SetMaxPageWidth( 150 );
+ SetHelpId( HID_SD_TABBAR_LAYERS );
+}
+
+LayerTabBar::~LayerTabBar()
+{
+ disposeOnce();
+}
+
+void LayerTabBar::dispose()
+{
+ DropTargetHelper::dispose();
+ TabBar::dispose();
+}
+
+OUString LayerTabBar::convertToLocalizedName(const OUString& rName)
+{
+ if ( rName == sUNO_LayerName_background )
+ return SdResId( STR_LAYER_BCKGRND );
+
+ if ( rName == sUNO_LayerName_background_objects )
+ return SdResId( STR_LAYER_BCKGRNDOBJ );
+
+ if ( rName == sUNO_LayerName_layout )
+ return SdResId( STR_LAYER_LAYOUT );
+
+ if ( rName == sUNO_LayerName_controls )
+ return SdResId( STR_LAYER_CONTROLS );
+
+ if ( rName == sUNO_LayerName_measurelines )
+ return SdResId( STR_LAYER_MEASURELINES );
+
+ return rName;
+}
+
+// Use a method name, that is specific to LayerTabBar to make code better readable
+OUString LayerTabBar::GetLayerName(sal_uInt16 nPageId) const
+{
+ return GetAuxiliaryText(nPageId);
+}
+
+void LayerTabBar::SetLayerName( sal_uInt16 nPageId, const OUString& rText )
+{
+ SetAuxiliaryText(nPageId, rText);
+}
+
+// Here "Page" is a tab in the LayerTabBar.
+void LayerTabBar::InsertPage( sal_uInt16 nPageId, const OUString& rText,
+ TabBarPageBits nBits, sal_uInt16 nPos)
+{
+ OUString sLocalizedName(convertToLocalizedName(rText));
+ TabBar::InsertPage(nPageId, sLocalizedName, nBits, nPos );
+ SetLayerName(nPageId, rText);
+}
+
+void LayerTabBar::SetPageText( sal_uInt16 nPageId, const OUString& rText )
+{
+ OUString sLocalizedName(convertToLocalizedName(rText));
+ SetLayerName(nPageId, rText);
+ TabBar::SetPageText(nPageId, sLocalizedName);
+}
+
+bool LayerTabBar::IsLocalizedNameOfStandardLayer(std::u16string_view rName)
+{
+ return ( rName == SdResId(STR_LAYER_LAYOUT)
+ || rName == SdResId(STR_LAYER_CONTROLS)
+ || rName == SdResId(STR_LAYER_MEASURELINES)
+ || rName == SdResId(STR_LAYER_BCKGRND)
+ || rName == SdResId(STR_LAYER_BCKGRNDOBJ) );
+}
+
+bool LayerTabBar::IsRealNameOfStandardLayer(std::u16string_view rName)
+{
+ return ( rName == sUNO_LayerName_layout
+ || rName == sUNO_LayerName_controls
+ || rName == sUNO_LayerName_measurelines
+ || rName == sUNO_LayerName_background
+ || rName == sUNO_LayerName_background_objects );
+}
+
+void LayerTabBar::Select()
+{
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute(SID_SWITCHLAYER, SfxCallMode::ASYNCHRON);
+}
+
+void LayerTabBar::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bSetPageID=false;
+
+ if (rMEvt.IsLeft())
+ {
+ Point aPosPixel = rMEvt.GetPosPixel();
+ sal_uInt16 aTabId = GetPageId( PixelToLogic(aPosPixel) );
+ if (aTabId == 0)
+ {
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute(SID_INSERTLAYER, SfxCallMode::SYNCHRON);
+
+ bSetPageID=true;
+ }
+ else if (rMEvt.IsMod2())
+ {
+ // direct editing of tab text
+ // make sure the clicked tab is the current tab otherwise Edit() acts on the wrong tab
+ if ( aTabId != GetCurPageId())
+ {
+ MouseEvent aSyntheticEvent (rMEvt.GetPosPixel(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0);
+ TabBar::MouseButtonDown(aSyntheticEvent);
+ }
+ }
+ else if (rMEvt.IsMod1() || rMEvt.IsShift())
+ {
+ // keyboard Shortcuts to change layer attributes
+
+ OUString aName(GetLayerName(aTabId));
+ SdrPageView* pPV = pDrViewSh->GetView()->GetSdrPageView();
+
+ // Save old state
+
+ bool bOldPrintable = pPV->IsLayerPrintable(aName);
+ bool bOldVisible = pPV->IsLayerVisible(aName);
+ bool bOldLocked = pPV->IsLayerLocked(aName);
+
+ bool bNewPrintable = bOldPrintable;
+ bool bNewVisible = bOldVisible;
+ bool bNewLocked = bOldLocked;
+
+ if (rMEvt.IsMod1() && rMEvt.IsShift())
+ {
+ // Shift+Ctrl: Toggle between layer printable / not printable
+ bNewPrintable = !bOldPrintable;
+ pPV->SetLayerPrintable(aName, bNewPrintable);
+ }
+ else if (rMEvt.IsShift())
+ {
+ // Shift: Toggle between layer visible / hidden
+ bNewVisible = !bOldVisible;
+ pPV->SetLayerVisible(aName, bNewVisible);
+ }
+ else // if (rMEvt.IsMod1())
+ {
+ // Ctrl: Toggle between layer locked / unlocked
+ bNewLocked = !bOldLocked;
+ pPV->SetLayerLocked(aName, bNewLocked);
+ }
+
+ pDrViewSh->ResetActualLayer();
+
+ // Add Undo action
+
+ ::sd::View* pView = pDrViewSh->GetView();
+ DrawView* pDrView = dynamic_cast<DrawView*>(pView);
+
+ SdDrawDocument& rDoc = pView->GetDoc();
+ SdrLayer* pLayer = rDoc.GetLayerAdmin().GetLayer(aName);
+
+ if (pLayer)
+ {
+ assert (pDrView && "Change layer attribute undo action is only working with a SdDrawView");
+ if(pDrView)
+ {
+ SfxUndoManager* pManager = rDoc.GetDocSh()->GetUndoManager();
+ std::unique_ptr<SdLayerModifyUndoAction> pAction(new SdLayerModifyUndoAction(
+ &rDoc,
+ pLayer,
+ aName,
+ pLayer->GetTitle(),
+ pLayer->GetDescription(),
+ bOldVisible,
+ bOldLocked,
+ bOldPrintable,
+ aName,
+ pLayer->GetTitle(),
+ pLayer->GetDescription(),
+ bNewVisible,
+ bNewLocked,
+ bNewPrintable
+ ));
+ pManager->AddUndoAction(std::move(pAction));
+ }
+ }
+
+ // Mark document changed
+
+ pView->GetDoc().SetChanged();
+ }
+ }
+
+ // If you insert a new layer you must not call TabBar::MouseButtonDown(rMEvt);
+ // because you want to activate the new layer
+ if( !bSetPageID )
+ TabBar::MouseButtonDown(rMEvt);
+}
+
+void LayerTabBar::DoubleClick()
+{
+ if (GetCurPageId() != 0)
+ {
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute( SID_MODIFYLAYER, SfxCallMode::SYNCHRON );
+ }
+}
+
+/**
+ * AcceptDrop-Event
+ */
+
+sal_Int8 LayerTabBar::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( rEvt.mbLeaving )
+ EndSwitchPage();
+
+ if( !pDrViewSh->GetDocSh()->IsReadOnly() )
+ {
+ Point aPos( PixelToLogic( rEvt.maPosPixel ) );
+ OUString sLayerName( GetLayerName(GetPageId(aPos)) );
+ SdrLayerID nLayerId = pDrViewSh->GetView()->GetDoc().GetLayerAdmin().GetLayerID(sLayerName);
+
+ nRet = pDrViewSh->AcceptDrop( rEvt, *this, nullptr, SDRPAGE_NOTFOUND, nLayerId );
+
+ SwitchPage( aPos );
+ }
+
+ return nRet;
+}
+
+/**
+ * ExecuteDrop-Event
+ */
+sal_Int8 LayerTabBar::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ Point aPos( PixelToLogic(rEvt.maPosPixel) );
+ OUString sLayerName( GetLayerName(GetPageId(aPos)) );
+ SdrLayerID nLayerId = pDrViewSh->GetView()->GetDoc().GetLayerAdmin().GetLayerID(sLayerName);
+
+ sal_Int8 nRet = pDrViewSh->ExecuteDrop( rEvt, *this, nullptr, SDRPAGE_NOTFOUND, nLayerId );
+
+ EndSwitchPage();
+
+ return nRet;
+
+}
+
+void LayerTabBar::Command(const CommandEvent& rCEvt)
+{
+ if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
+ {
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->ExecutePopup("layertab");
+ }
+}
+
+bool LayerTabBar::StartRenaming()
+{
+ bool bOK = true;
+ OUString aLayerName = GetLayerName( GetEditPageId() );
+
+ if ( IsRealNameOfStandardLayer(aLayerName))
+ {
+ // It is not allowed to change these names
+ bOK = false;
+ }
+ else
+ {
+ ::sd::View* pView = pDrViewSh->GetView();
+
+ if ( pView->IsTextEdit() )
+ {
+ pView->SdrEndTextEdit();
+ }
+ }
+
+ return bOK;
+}
+
+TabBarAllowRenamingReturnCode LayerTabBar::AllowRenaming()
+{
+ bool bOK = true;
+
+ // Check if names already exists
+ ::sd::View* pView = pDrViewSh->GetView();
+ SdDrawDocument& rDoc = pView->GetDoc();
+ OUString aLayerName = pView->GetActiveLayer();
+ SdrLayerAdmin& rLayerAdmin = rDoc.GetLayerAdmin();
+ OUString aNewName( GetEditText() );
+
+ if (aNewName.isEmpty() ||
+ (rLayerAdmin.GetLayer( aNewName ) && aLayerName != aNewName) )
+ {
+ // Name already exists.
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pDrViewSh->GetViewFrame()->GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SdResId(STR_WARN_NAME_DUPLICATE)));
+ xWarn->run();
+ bOK = false;
+ }
+
+ if (bOK)
+ {
+ if ( IsLocalizedNameOfStandardLayer(aNewName) || IsRealNameOfStandardLayer(aNewName) )
+ {
+ // Standard layer names may not be changed.
+ bOK = false;
+ }
+ }
+
+ return bOK ? TABBAR_RENAMING_YES : TABBAR_RENAMING_NO;
+}
+
+void LayerTabBar::EndRenaming()
+{
+ if( IsEditModeCanceled() )
+ return;
+
+ ::sd::View* pView = pDrViewSh->GetView();
+ DrawView* pDrView = dynamic_cast<DrawView*>( pView );
+
+ SdDrawDocument& rDoc = pView->GetDoc();
+ OUString aLayerName = pView->GetActiveLayer();
+ SdrLayerAdmin& rLayerAdmin = rDoc.GetLayerAdmin();
+ SdrLayer* pLayer = rLayerAdmin.GetLayer(aLayerName);
+
+ if (!pLayer)
+ return;
+
+ OUString aNewName( GetEditText() );
+ assert (pDrView && "Rename layer undo action is only working with a SdDrawView");
+ if( pDrView )
+ {
+ SfxUndoManager* pManager = rDoc.GetDocSh()->GetUndoManager();
+ std::unique_ptr<SdLayerModifyUndoAction> pAction(new SdLayerModifyUndoAction(
+ &rDoc,
+ pLayer,
+ aLayerName,
+ pLayer->GetTitle(),
+ pLayer->GetDescription(),
+ pDrView->IsLayerVisible(aLayerName),
+ pDrView->IsLayerLocked(aLayerName),
+ pDrView->IsLayerPrintable(aLayerName),
+ aNewName,
+ pLayer->GetTitle(),
+ pLayer->GetDescription(),
+ pDrView->IsLayerVisible(aLayerName),
+ pDrView->IsLayerLocked(aLayerName),
+ pDrView->IsLayerPrintable(aLayerName)
+ ));
+ pManager->AddUndoAction( std::move(pAction) );
+ }
+
+ // First notify View since SetName() calls ResetActualLayer() and
+ // the View then already has to know the Layer
+ pView->SetActiveLayer(aNewName);
+ pLayer->SetName(aNewName);
+ rDoc.SetChanged();
+}
+
+void LayerTabBar::ActivatePage()
+{
+ if (pDrViewSh!=nullptr)
+ {
+
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute(SID_SWITCHLAYER, SfxCallMode::ASYNCHRON);
+ }
+}
+
+void LayerTabBar::SendActivatePageEvent()
+{
+ CallEventListeners (VclEventId::TabbarPageActivated,
+ reinterpret_cast<void*>(GetCurPageId()));
+}
+
+void LayerTabBar::SendDeactivatePageEvent()
+{
+ CallEventListeners (VclEventId::TabbarPageDeactivated,
+ reinterpret_cast<void*>(GetCurPageId()));
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/NavigatorChildWindow.cxx b/sd/source/ui/dlg/NavigatorChildWindow.cxx
new file mode 100644
index 000000000..6055c238a
--- /dev/null
+++ b/sd/source/ui/dlg/NavigatorChildWindow.cxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <NavigatorChildWindow.hxx>
+#include <navigatr.hxx>
+#include <app.hrc>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svl/eitem.hxx>
+
+namespace sd {
+
+static void RequestNavigatorUpdate (SfxBindings const * pBindings)
+{
+ if (pBindings != nullptr
+ && pBindings->GetDispatcher() != nullptr)
+ {
+ SfxBoolItem aItem (SID_NAVIGATOR_INIT, true);
+ pBindings->GetDispatcher()->ExecuteList(
+ SID_NAVIGATOR_INIT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aItem });
+ }
+}
+
+SdNavigatorFloat::SdNavigatorFloat(SfxBindings* _pBindings, SfxChildWindow* _pMgr,
+ vcl::Window* _pParent, SfxChildWinInfo* pInfo)
+ : SfxNavigator(_pBindings, _pMgr, _pParent, pInfo)
+ , m_xNavWin(std::make_unique<SdNavigatorWin>(m_xContainer.get(), _pBindings, this))
+ , m_bSetInitialFocusOnActivate(true)
+{
+ m_xNavWin->SetUpdateRequestFunctor(
+ [_pBindings] () { return RequestNavigatorUpdate(_pBindings); });
+
+ SetMinOutputSizePixel(GetOptimalSize());
+}
+
+void SdNavigatorFloat::Activate()
+{
+ SfxNavigator::Activate();
+ // tdf#141708 defer grabbing focus to preferred widget until the float is
+ // first activated
+ if (m_bSetInitialFocusOnActivate)
+ {
+ m_xNavWin->FirstFocus();
+ m_bSetInitialFocusOnActivate = false;
+ }
+}
+
+void SdNavigatorFloat::InitTreeLB(const SdDrawDocument* pDoc)
+{
+ m_xNavWin->InitTreeLB(pDoc);
+}
+
+void SdNavigatorFloat::FreshTree(const SdDrawDocument* pDoc)
+{
+ m_xNavWin->FreshTree(pDoc);
+}
+
+void SdNavigatorFloat::dispose()
+{
+ m_xNavWin.reset();
+ SfxNavigator::dispose();
+}
+
+SdNavigatorFloat::~SdNavigatorFloat()
+{
+ disposeOnce();
+}
+
+SFX_IMPL_DOCKINGWINDOW(SdNavigatorWrapper, SID_NAVIGATOR);
+
+SdNavigatorWrapper::SdNavigatorWrapper(vcl::Window *_pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo* pInfo)
+ : SfxNavigatorWrapper(_pParent, nId)
+{
+ SetWindow(VclPtr<SdNavigatorFloat>::Create(pBindings, this, _pParent, pInfo));
+ Initialize();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/PaneChildWindows.cxx b/sd/source/ui/dlg/PaneChildWindows.cxx
new file mode 100644
index 000000000..7f73e005b
--- /dev/null
+++ b/sd/source/ui/dlg/PaneChildWindows.cxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <PaneChildWindows.hxx>
+#include <PaneDockingWindow.hxx>
+#include <ViewShellBase.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <app.hrc>
+#include <strings.hrc>
+#include <sdresid.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+
+namespace sd {
+
+
+SFX_IMPL_DOCKINGWINDOW_WITHID(LeftPaneImpressChildWindow, SID_LEFT_PANE_IMPRESS)
+SFX_IMPL_DOCKINGWINDOW_WITHID(LeftPaneDrawChildWindow, SID_LEFT_PANE_DRAW)
+
+//===== PaneChildWindow =======================================================
+PaneChildWindow::PaneChildWindow (
+ vcl::Window* pParentWindow,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo,
+ TranslateId pTitleBarResId)
+ : SfxChildWindow (pParentWindow, nId)
+{
+ SetWindow( VclPtr<PaneDockingWindow>::Create(
+ pBindings,
+ this,
+ pParentWindow,
+ SdResId(pTitleBarResId)));
+ SetAlignment(SfxChildAlignment::LEFT);
+ SfxDockingWindow* pDockingWindow = static_cast<SfxDockingWindow*>(GetWindow());
+ pDockingWindow->EnableInput();
+ pDockingWindow->Initialize(pInfo);
+ SetHideNotDelete(true);
+
+ ViewShellBase* pBase = ViewShellBase::GetViewShellBase(pBindings->GetDispatcher()->GetFrame());
+ if (pBase != nullptr)
+ {
+ framework::FrameworkHelper::Instance(*pBase)->UpdateConfiguration();
+ }
+}
+
+PaneChildWindow::~PaneChildWindow()
+{
+ ViewShellBase* pBase = nullptr;
+ PaneDockingWindow* pDockingWindow = dynamic_cast<PaneDockingWindow*>(GetWindow());
+ if (pDockingWindow != nullptr)
+ pBase = ViewShellBase::GetViewShellBase(
+ pDockingWindow->GetBindings().GetDispatcher()->GetFrame());
+ if (pBase != nullptr)
+ framework::FrameworkHelper::Instance(*pBase)->UpdateConfiguration();
+}
+
+//===== LeftPaneImpressChildWindow ============================================
+LeftPaneImpressChildWindow::LeftPaneImpressChildWindow (
+ vcl::Window* pParentWindow,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo)
+ : PaneChildWindow(
+ pParentWindow,
+ nId,
+ pBindings,
+ pInfo,
+ STR_LEFT_PANE_IMPRESS_TITLE)
+{
+}
+
+//===== LeftPaneDrawChildWindow ===============================================
+LeftPaneDrawChildWindow::LeftPaneDrawChildWindow (
+ vcl::Window* pParentWindow,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo)
+ : PaneChildWindow(
+ pParentWindow,
+ nId,
+ pBindings,
+ pInfo,
+ STR_LEFT_PANE_DRAW_TITLE)
+{
+}
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/PaneDockingWindow.cxx b/sd/source/ui/dlg/PaneDockingWindow.cxx
new file mode 100644
index 000000000..6f7332ad9
--- /dev/null
+++ b/sd/source/ui/dlg/PaneDockingWindow.cxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <PaneDockingWindow.hxx>
+#include <ViewShellBase.hxx>
+#include <framework/FrameworkHelper.hxx>
+
+#include <sfx2/dispatch.hxx>
+#include <vcl/splitwin.hxx>
+#include <tools/wintypes.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::TitledDockingWindow;
+
+namespace sd {
+
+PaneDockingWindow::PaneDockingWindow(
+ SfxBindings *_pBindings, SfxChildWindow *pChildWindow, vcl::Window* pParent,
+ const OUString& rsTitle )
+ : TitledDockingWindow(_pBindings, pChildWindow, pParent)
+{
+ SetTitle(rsTitle);
+ SetSizePixel(LogicToPixel(Size(80,200), MapMode(MapUnit::MapAppFont)));
+}
+
+PaneDockingWindow::~PaneDockingWindow()
+{
+}
+
+void PaneDockingWindow::StateChanged( StateChangedType nType )
+{
+ switch (nType)
+ {
+ case StateChangedType::InitShow:
+ Resize();
+ GetContentWindow().SetStyle(GetContentWindow().GetStyle() | WB_DIALOGCONTROL);
+ break;
+
+ case StateChangedType::Visible:
+ {
+ // The visibility of the docking window has changed. Tell the
+ // ConfigurationController so that it can activate or deactivate
+ // a/the view for the pane.
+ // Without this the side panes remain empty after closing an
+ // in-place slide show.
+ ViewShellBase* pBase = ViewShellBase::GetViewShellBase(
+ GetBindings().GetDispatcher()->GetFrame());
+ if (pBase != nullptr)
+ {
+ framework::FrameworkHelper::Instance(*pBase)->UpdateConfiguration();
+ }
+ }
+ break;
+
+ default:;
+ }
+ SfxDockingWindow::StateChanged (nType);
+}
+
+void PaneDockingWindow::MouseButtonDown (const MouseEvent& rEvent)
+{
+ if (rEvent.GetButtons() == MOUSE_LEFT)
+ {
+ // For some strange reason we have to set the WB_DIALOGCONTROL at
+ // the content window in order to have it pass focus to its content
+ // window. Without setting this flag here that works only on views
+ // that have not been taken from the cash and relocated to this pane
+ // docking window.
+ GetContentWindow().SetStyle(GetContentWindow().GetStyle() | WB_DIALOGCONTROL);
+ GetContentWindow().GrabFocus();
+ }
+ SfxDockingWindow::MouseButtonDown(rEvent);
+}
+
+void PaneDockingWindow::SetValidSizeRange (const Range& rValidSizeRange)
+{
+ SplitWindow* pSplitWindow = dynamic_cast<SplitWindow*>(GetParent());
+ if (pSplitWindow == nullptr)
+ return;
+
+ const sal_uInt16 nId (pSplitWindow->GetItemId(static_cast< vcl::Window*>(this)));
+ const sal_uInt16 nSetId (pSplitWindow->GetSet(nId));
+ // Because the PaneDockingWindow paints its own decoration, we have
+ // to compensate the valid size range for that.
+ const SvBorder aBorder (GetDecorationBorder());
+ sal_Int32 nCompensation (pSplitWindow->IsHorizontal()
+ ? aBorder.Top() + aBorder.Bottom()
+ : aBorder.Left() + aBorder.Right());
+ pSplitWindow->SetItemSizeRange(
+ nSetId,
+ Range(
+ rValidSizeRange.Min() + nCompensation,
+ rValidSizeRange.Max() + nCompensation));
+}
+
+PaneDockingWindow::Orientation PaneDockingWindow::GetOrientation() const
+{
+ SplitWindow* pSplitWindow = dynamic_cast<SplitWindow*>(GetParent());
+ if (pSplitWindow == nullptr)
+ return UnknownOrientation;
+ else if (pSplitWindow->IsHorizontal())
+ return HorizontalOrientation;
+ else
+ return VerticalOrientation;
+}
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/PaneShells.cxx b/sd/source/ui/dlg/PaneShells.cxx
new file mode 100644
index 000000000..8870d1186
--- /dev/null
+++ b/sd/source/ui/dlg/PaneShells.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <PaneShells.hxx>
+
+#include <PaneChildWindows.hxx>
+
+#include <sfx2/msg.hxx>
+#include <sfx2/objface.hxx>
+
+namespace sd {
+
+//===== LeftImpressPaneShell ==================================================
+
+static SfxSlot aLeftImpressPaneShellSlots_Impl[] =
+{
+ { 0, SfxGroupId::NONE, SfxSlotMode::NONE, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, 0, SfxDisableFlags::NONE, nullptr }
+};
+
+SFX_IMPL_INTERFACE(LeftImpressPaneShell, SfxShell)
+
+void LeftImpressPaneShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterChildWindow(::sd::LeftPaneImpressChildWindow::GetChildWindowId());
+}
+
+
+LeftImpressPaneShell::LeftImpressPaneShell()
+{
+ SetName("LeftImpressPane");
+}
+
+LeftImpressPaneShell::~LeftImpressPaneShell()
+{
+}
+
+//===== LeftDrawPaneShell =====================================================
+
+static SfxSlot aLeftDrawPaneShellSlots_Impl[] =
+{
+ { 0, SfxGroupId::NONE, SfxSlotMode::NONE, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, 0, SfxDisableFlags::NONE, nullptr }
+};
+
+SFX_IMPL_INTERFACE(LeftDrawPaneShell, SfxShell)
+
+void LeftDrawPaneShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterChildWindow(::sd::LeftPaneDrawChildWindow::GetChildWindowId());
+}
+
+
+LeftDrawPaneShell::LeftDrawPaneShell()
+{
+ SetName("LeftDrawPane");
+}
+
+LeftDrawPaneShell::~LeftDrawPaneShell()
+{
+}
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/PhotoAlbumDialog.cxx b/sd/source/ui/dlg/PhotoAlbumDialog.cxx
new file mode 100644
index 000000000..f63afe7bb
--- /dev/null
+++ b/sd/source/ui/dlg/PhotoAlbumDialog.cxx
@@ -0,0 +1,775 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+* This file is part of the LibreOffice project.
+*
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.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 <comphelper/namedvaluecollection.hxx>
+#include <comphelper/processfactory.hxx>
+#include <svl/itemset.hxx>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <sfx2/filedlghelper.hxx>
+#include <tools/urlobj.hxx>
+
+#include <unotools/ucbstreamhelper.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflclit.hxx>
+#include <tools/diagnose_ex.h>
+#include <xmloff/autolayout.hxx>
+
+#include "PhotoAlbumDialog.hxx"
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+
+namespace sd
+{
+
+SdPhotoAlbumDialog::SdPhotoAlbumDialog(weld::Window* pWindow, SdDrawDocument* pActDoc)
+ : GenericDialogController(pWindow, "modules/simpress/ui/photoalbum.ui", "PhotoAlbumCreatorDialog")
+ , m_pDoc(pActDoc)
+ , m_aImg(m_xDialog.get())
+ , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
+ , m_xCreateBtn(m_xBuilder->weld_button("ok"))
+ , m_xAddBtn(m_xBuilder->weld_button("add_btn"))
+ , m_xUpBtn(m_xBuilder->weld_button("up_btn"))
+ , m_xDownBtn(m_xBuilder->weld_button("down_btn"))
+ , m_xRemoveBtn(m_xBuilder->weld_button("rem_btn"))
+ , m_xImagesLst(m_xBuilder->weld_tree_view("images_tree"))
+ , m_xImg(new weld::CustomWeld(*m_xBuilder, "preview_img", m_aImg))
+ , m_xInsTypeCombo(m_xBuilder->weld_combo_box("opt_combo"))
+ , m_xASRCheck(m_xBuilder->weld_check_button("asr_check"))
+ , m_xASRCheckCrop(m_xBuilder->weld_check_button("asr_check_crop"))
+ , m_xCapCheck(m_xBuilder->weld_check_button("cap_check"))
+ , m_xInsertAsLinkCheck(m_xBuilder->weld_check_button("insert_as_link_check"))
+{
+ m_xCancelBtn->connect_clicked(LINK(this, SdPhotoAlbumDialog, CancelHdl));
+ m_xCreateBtn->connect_clicked(LINK(this, SdPhotoAlbumDialog, CreateHdl));
+
+ m_xAddBtn->connect_clicked(LINK(this, SdPhotoAlbumDialog, FileHdl));
+ m_xUpBtn->connect_clicked(LINK(this, SdPhotoAlbumDialog, UpHdl));
+ m_xUpBtn->set_sensitive(false);
+ m_xDownBtn->connect_clicked(LINK(this, SdPhotoAlbumDialog, DownHdl));
+ m_xDownBtn->set_sensitive(false);
+ m_xRemoveBtn->connect_clicked(LINK(this, SdPhotoAlbumDialog, RemoveHdl));
+ m_xRemoveBtn->set_sensitive(false);
+ m_xImagesLst->connect_changed(LINK(this, SdPhotoAlbumDialog, SelectHdl));
+ m_xInsTypeCombo->connect_changed(LINK(this, SdPhotoAlbumDialog, TypeSelectHdl));
+
+ m_pGraphicFilter = new GraphicFilter;
+ m_xAddBtn->grab_focus();
+}
+
+SdPhotoAlbumDialog::~SdPhotoAlbumDialog()
+{
+}
+
+IMPL_LINK_NOARG(SdPhotoAlbumDialog, CancelHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_CANCEL);
+}
+
+IMPL_LINK_NOARG(SdPhotoAlbumDialog, CreateHdl, weld::Button&, void)
+{
+ if (m_xImagesLst->n_children() == 0)
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SdResId(STR_PHOTO_ALBUM_EMPTY_WARNING)));
+ xWarn->run();
+ }
+ else
+ {
+ Reference< drawing::XDrawPagesSupplier > xDPS( m_pDoc->getUnoModel(), uno::UNO_QUERY );
+ Reference< drawing::XDrawPages > xDrawPages = xDPS->getDrawPages();
+ Reference< lang::XMultiServiceFactory > xShapeFactory( m_pDoc->getUnoModel(), uno::UNO_QUERY );
+
+ Reference< XComponentContext > xContext(::comphelper::getProcessComponentContext());
+ Reference< graphic::XGraphicProvider> xProvider(graphic::GraphicProvider::create(xContext));
+
+ // determine if to use Captions (use TitleObject) and choose the correct AutoLayout
+ // from the beginning
+ const bool bCreateCaptions(m_xCapCheck->get_active());
+ const bool bInsertAsLink(m_xInsertAsLinkCheck->get_active());
+ const AutoLayout aAutoLayout(bCreateCaptions ? AUTOLAYOUT_TITLE_ONLY : AUTOLAYOUT_NONE);
+
+ // get the option
+ const int nOpt = m_xInsTypeCombo->get_active();
+ if (nOpt == ONE_IMAGE)
+ {
+ for( sal_Int32 i = 0; i < m_xImagesLst->n_children(); ++i )
+ {
+ OUString sUrl = m_xImagesLst->get_id(i);
+
+ Reference< drawing::XDrawPage > xSlide = appendNewSlide(aAutoLayout, xDrawPages);
+ Reference< beans::XPropertySet > xSlideProps( xSlide, uno::UNO_QUERY );
+ Reference< graphic::XGraphic > xGraphic = createXGraphicFromUrl(sUrl, xProvider);
+
+ Graphic aGraphic(xGraphic);
+ if (bInsertAsLink)
+ aGraphic.setOriginURL(sUrl);
+
+ // Save the original size, multiplied with 100
+ ::awt::Size aPicSize(aGraphic.GetSizePixel().Width()*100, aGraphic.GetSizePixel().Height()*100);
+
+ Reference< drawing::XShape > xShape(
+ xShapeFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ uno::UNO_QUERY);
+
+ Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
+ xProps->setPropertyValue("Graphic", ::uno::Any(xGraphic));
+
+ ::awt::Size aPageSize;
+
+ xSlideProps->getPropertyValue(
+ "Width") >>= aPageSize.Width;
+ xSlideProps->getPropertyValue(
+ "Height") >>= aPageSize.Height;
+
+ ::awt::Point aPicPos;
+
+ if (m_xASRCheck->get_active() && !m_xASRCheckCrop->get_active())
+ {
+ // Resize the image, with keeping ASR
+ aPicSize = createASRSize(aPicSize, aPageSize);
+ }
+ else if (m_xASRCheckCrop->get_active())
+ {
+ aPicSize = createASRSizeCrop(aPicSize, aPageSize);
+ }
+
+ xShape->setSize(aPicSize);
+ aPicPos.X = (aPageSize.Width - aPicSize.Width)/2;
+ aPicPos.Y = (aPageSize.Height - aPicSize.Height)/2;
+
+ xShape->setPosition(aPicPos);
+ try
+ {
+ xSlide->add(xShape);
+ if (bCreateCaptions)
+ createCaption( aPageSize );
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "" );
+ }
+ }
+ }
+ else if( nOpt == TWO_IMAGES )
+ {
+ for( sal_Int32 i = 0; i < m_xImagesLst->n_children(); i+=2 )
+ {
+ // create the slide
+ Reference< drawing::XDrawPage > xSlide = appendNewSlide(aAutoLayout, xDrawPages);
+ Reference< beans::XPropertySet > xSlideProps( xSlide, uno::UNO_QUERY );
+ //Slide dimensions
+ ::awt::Size aPageSize;
+
+ xSlideProps->getPropertyValue(
+ "Width") >>= aPageSize.Width;
+ xSlideProps->getPropertyValue(
+ "Height") >>= aPageSize.Height;
+
+ // grab the left one
+ OUString sUrl1 = m_xImagesLst->get_id(i);
+ // grab the right one
+ OUString sUrl2 = m_xImagesLst->get_id(i+1);
+
+ if( !sUrl1.isEmpty() )
+ {
+ Reference< graphic::XGraphic > xGraphic = createXGraphicFromUrl(sUrl1, xProvider);
+
+ Graphic aGraphic(xGraphic);
+ if (bInsertAsLink)
+ aGraphic.setOriginURL(sUrl1);
+ // Save the original size, multiplied with 100
+ ::awt::Size aPicSize(aGraphic.GetSizePixel().Width()*100, aGraphic.GetSizePixel().Height()*100);
+
+ Reference< drawing::XShape > xShape(
+ xShapeFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ uno::UNO_QUERY);
+
+ Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
+ xProps->setPropertyValue("Graphic", ::uno::Any(xGraphic));
+
+ ::awt::Point aPicPos;
+
+ if (m_xASRCheck->get_active())
+ {
+ // Resize the image, with keeping ASR
+ aPicSize = createASRSize(aPicSize, ::awt::Size(aPageSize.Width/2 - 100, aPageSize.Height/2 - 100));
+ }
+ else
+ {
+ aPicSize.Width = aPageSize.Width/2 - 100;
+ aPicSize.Height = aPageSize.Height/2 - 100;
+ }
+ xShape->setSize(aPicSize);
+ aPicPos.X = (aPageSize.Width/4 - aPicSize.Width/2);
+ aPicPos.Y = aPageSize.Height/2 - aPicSize.Height/2;
+
+ xShape->setPosition(aPicPos);
+ try
+ {
+ xSlide->add(xShape);
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "" );
+ }
+ }
+
+ if( !sUrl2.isEmpty() )
+ {
+ Reference< graphic::XGraphic > xGraphic = createXGraphicFromUrl(sUrl2, xProvider);
+
+ Graphic aGraphic(xGraphic);
+ if (bInsertAsLink)
+ aGraphic.setOriginURL(sUrl2);
+ // Save the original size, multiplied with 100
+ ::awt::Size aPicSize(aGraphic.GetSizePixel().Width()*100, aGraphic.GetSizePixel().Height()*100);
+
+ Reference< drawing::XShape > xShape(
+ xShapeFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ uno::UNO_QUERY);
+
+ Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
+ xProps->setPropertyValue("Graphic", ::uno::Any(xGraphic));
+
+ ::awt::Point aPicPos;
+
+ if (m_xASRCheck->get_active())
+ {
+ // Resize the image, with keeping ASR
+ aPicSize = createASRSize(aPicSize, ::awt::Size(aPageSize.Width/2 - 100, aPageSize.Height/2 - 100));
+ }
+ else
+ {
+ aPicSize.Width = aPageSize.Width/2 - 100;
+ aPicSize.Height = aPageSize.Height/2 - 100;
+ }
+ xShape->setSize(aPicSize);
+ aPicPos.X = (aPageSize.Width/4 - aPicSize.Width/2) + aPageSize.Width/2;
+ aPicPos.Y = aPageSize.Height/2 - aPicSize.Height/2;
+
+ xShape->setPosition(aPicPos);
+
+ try
+ {
+ xSlide->add(xShape);
+ if(bCreateCaptions)
+ createCaption( aPageSize );
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "" );
+ }
+ }
+ }
+ }
+ else if( nOpt == FOUR_IMAGES )
+ {
+ for( sal_Int32 i = 0; i < m_xImagesLst->n_children(); i+=4 )
+ {
+ // create the slide
+ Reference< drawing::XDrawPage > xSlide = appendNewSlide(aAutoLayout, xDrawPages);
+ Reference< beans::XPropertySet > xSlideProps( xSlide, uno::UNO_QUERY );
+ //Slide dimensions
+ ::awt::Size aPageSize;
+
+ xSlideProps->getPropertyValue(
+ "Width") >>= aPageSize.Width;
+ xSlideProps->getPropertyValue(
+ "Height") >>= aPageSize.Height;
+
+ // grab the upper left one
+ OUString sUrl1 = m_xImagesLst->get_id(i);
+
+ // grab the upper right one
+ OUString sUrl2 = m_xImagesLst->get_id(i+1);
+
+ // grab the lower left one
+ OUString sUrl3 = m_xImagesLst->get_id(i+2);
+
+ // grab the lower right one
+ OUString sUrl4 = m_xImagesLst->get_id(i+3);
+
+ if( !sUrl1.isEmpty() )
+ {
+ Reference< graphic::XGraphic > xGraphic = createXGraphicFromUrl(sUrl1, xProvider);
+
+ Graphic aGraphic(xGraphic);
+ if (bInsertAsLink)
+ aGraphic.setOriginURL(sUrl1);
+ // Save the original size, multiplied with 100
+ ::awt::Size aPicSize(aGraphic.GetSizePixel().Width()*100, aGraphic.GetSizePixel().Height()*100);
+
+ Reference< drawing::XShape > xShape(
+ xShapeFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ uno::UNO_QUERY);
+
+ Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
+ xProps->setPropertyValue("Graphic", ::uno::Any(xGraphic));
+
+ ::awt::Point aPicPos;
+
+ if (m_xASRCheck->get_active())
+ {
+ // Resize the image, with keeping ASR
+ aPicSize = createASRSize(aPicSize, ::awt::Size(aPageSize.Width/2 - 100, aPageSize.Height/2 - 100));
+ }
+ else
+ {
+ aPicSize.Width = aPageSize.Width/2 - 100;
+ aPicSize.Height = aPageSize.Height/2 - 100;
+ }
+ xShape->setSize(aPicSize);
+ aPicPos.X = (aPageSize.Width/4 - aPicSize.Width/2);
+ aPicPos.Y = aPageSize.Height/4 - aPicSize.Height/2;
+
+ xShape->setPosition(aPicPos);
+ try
+ {
+ xSlide->add(xShape);
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "" );
+ }
+ }
+ if( !sUrl2.isEmpty() )
+ {
+ Reference< graphic::XGraphic > xGraphic = createXGraphicFromUrl(sUrl2, xProvider);
+
+ Graphic aGraphic(xGraphic);
+ if (bInsertAsLink)
+ aGraphic.setOriginURL(sUrl2);
+ // Save the original size, multiplied with 100
+ ::awt::Size aPicSize(aGraphic.GetSizePixel().Width()*100, aGraphic.GetSizePixel().Height()*100);
+
+ Reference< drawing::XShape > xShape(
+ xShapeFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ uno::UNO_QUERY);
+
+ Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
+ xProps->setPropertyValue("Graphic", ::uno::Any(xGraphic));
+
+ ::awt::Point aPicPos;
+
+ if (m_xASRCheck->get_active())
+ {
+ // Resize the image, with keeping ASR
+ aPicSize = createASRSize(aPicSize, ::awt::Size(aPageSize.Width/2 - 100, aPageSize.Height/2 - 100));
+ }
+ else
+ {
+ aPicSize.Width = aPageSize.Width/2 - 100;
+ aPicSize.Height = aPageSize.Height/2 - 100;
+ }
+ xShape->setSize(aPicSize);
+ aPicPos.X = (aPageSize.Width/4 - aPicSize.Width/2) + aPageSize.Width/2;
+ aPicPos.Y = aPageSize.Height/4 - aPicSize.Height/2;
+
+ xShape->setPosition(aPicPos);
+ try
+ {
+ xSlide->add(xShape);
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "" );
+ }
+ }
+ if( !sUrl3.isEmpty() )
+ {
+ Reference< graphic::XGraphic > xGraphic = createXGraphicFromUrl(sUrl3, xProvider);
+
+ Graphic aGraphic(xGraphic);
+ if (bInsertAsLink)
+ aGraphic.setOriginURL(sUrl3);
+ // Save the original size, multiplied with 100
+ ::awt::Size aPicSize(aGraphic.GetSizePixel().Width()*100, aGraphic.GetSizePixel().Height()*100);
+
+ Reference< drawing::XShape > xShape(
+ xShapeFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ uno::UNO_QUERY);
+
+ Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
+ xProps->setPropertyValue("Graphic", ::uno::Any(xGraphic));
+
+ ::awt::Point aPicPos;
+
+ if (m_xASRCheck->get_active())
+ {
+ // Resize the image, with keeping ASR
+ aPicSize = createASRSize(aPicSize, ::awt::Size(aPageSize.Width/2 - 100, aPageSize.Height/2 - 100));
+ }
+ else
+ {
+ aPicSize.Width = aPageSize.Width/2 - 100;
+ aPicSize.Height = aPageSize.Height/2 - 100;
+ }
+ xShape->setSize(aPicSize);
+ aPicPos.X = (aPageSize.Width/4 - aPicSize.Width/2);
+ aPicPos.Y = aPageSize.Height/4 - aPicSize.Height/2 + aPageSize.Height/2;
+
+ xShape->setPosition(aPicPos);
+ try
+ {
+ xSlide->add(xShape);
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "" );
+ }
+ }
+ if( !sUrl4.isEmpty() )
+ {
+ Reference< graphic::XGraphic > xGraphic = createXGraphicFromUrl(sUrl4, xProvider);
+
+ Graphic aGraphic(xGraphic);
+ if (bInsertAsLink)
+ aGraphic.setOriginURL(sUrl4);
+ // Save the original size, multiplied with 100
+ ::awt::Size aPicSize(aGraphic.GetSizePixel().Width()*100, aGraphic.GetSizePixel().Height()*100);
+
+ Reference< drawing::XShape > xShape(
+ xShapeFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ uno::UNO_QUERY);
+
+ Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
+ xProps->setPropertyValue("Graphic", ::uno::Any(xGraphic));
+
+ ::awt::Point aPicPos;
+
+ if (m_xASRCheck->get_active())
+ {
+ // Resize the image, with keeping ASR
+ aPicSize = createASRSize(aPicSize, ::awt::Size(aPageSize.Width/2 - 100, aPageSize.Height/2 - 100));
+ }
+ else
+ {
+ aPicSize.Width = aPageSize.Width/2 - 100;
+ aPicSize.Height = aPageSize.Height/2 - 100;
+ }
+ xShape->setSize(aPicSize);
+ aPicPos.X = (aPageSize.Width/4 - aPicSize.Width/2) + aPageSize.Width/2;
+ aPicPos.Y = aPageSize.Height/4 - aPicSize.Height/2 + aPageSize.Height/2;
+
+ xShape->setPosition(aPicPos);
+ try
+ {
+ xSlide->add(xShape);
+ if(bCreateCaptions)
+ createCaption( aPageSize );
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "" );
+ }
+ }
+ }
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ "Function is not implemented!"));
+ xInfoBox->run();
+ }
+ m_xDialog->response(RET_OK);
+ }
+}
+
+IMPL_LINK_NOARG(SdPhotoAlbumDialog, FileHdl, weld::Button&, void)
+{
+ ::sfx2::FileDialogHelper aDlg(
+ css::ui::dialogs::TemplateDescription::FILEOPEN_PREVIEW,
+ FileDialogFlags::Graphic | FileDialogFlags::MultiSelection, m_xDialog.get());
+ aDlg.SetContext(sfx2::FileDialogHelper::ImpressPhotoDialog);
+
+ if ( aDlg.Execute() == ERRCODE_NONE )
+ {
+ const Sequence< OUString > aFilesArr = aDlg.GetSelectedFiles();
+ for ( const auto& rFile : aFilesArr )
+ {
+ // Store full path, show filename only. Use INetURLObject to display spaces in filename correctly
+ INetURLObject aUrl(rFile);
+ m_xImagesLst->append(aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE), aUrl.GetLastName(INetURLObject::DecodeMechanism::WithCharset), "");
+ }
+ }
+ EnableDisableButtons();
+}
+
+IMPL_LINK_NOARG(SdPhotoAlbumDialog, UpHdl, weld::Button&, void)
+{
+ const int nActPos = m_xImagesLst->get_selected_index();
+ if (nActPos != -1 && nActPos != 0)
+ {
+ OUString sActEntry(m_xImagesLst->get_text(nActPos));
+ // actual data
+ OUString sAct(m_xImagesLst->get_id(nActPos));
+
+ OUString sUpperEntry(m_xImagesLst->get_text(nActPos - 1));
+ // upper data
+ OUString sUpper(m_xImagesLst->get_id(nActPos - 1));
+
+ m_xImagesLst->remove_text(sActEntry);
+ m_xImagesLst->remove_text(sUpperEntry);
+
+ m_xImagesLst->insert(nActPos - 1, sActEntry, &sAct, nullptr, nullptr);
+ m_xImagesLst->insert(nActPos, sUpperEntry, &sUpper, nullptr, nullptr);
+
+ m_xImagesLst->select(nActPos - 1);
+ }
+
+ EnableDisableButtons();
+}
+
+IMPL_LINK_NOARG(SdPhotoAlbumDialog, DownHdl, weld::Button&, void)
+{
+ const int nActPos = m_xImagesLst->get_selected_index();
+ if (!m_xImagesLst->get_text(nActPos + 1).isEmpty())
+ {
+ OUString sActEntry(m_xImagesLst->get_selected_text());
+ OUString sAct(m_xImagesLst->get_selected_id());
+
+ OUString sDownEntry(m_xImagesLst->get_text(nActPos + 1));
+ OUString sDown(m_xImagesLst->get_id(nActPos + 1));
+
+ m_xImagesLst->remove_text(sActEntry);
+ m_xImagesLst->remove_text(sDownEntry);
+
+ m_xImagesLst->insert(nActPos, sDownEntry, &sDown, nullptr, nullptr);
+ m_xImagesLst->insert(nActPos + 1, sActEntry, &sAct, nullptr, nullptr);
+
+ m_xImagesLst->select(nActPos + 1);
+ }
+ EnableDisableButtons();
+}
+
+IMPL_LINK_NOARG(SdPhotoAlbumDialog, RemoveHdl, weld::Button&, void)
+{
+ m_xImagesLst->remove(m_xImagesLst->get_selected_index());
+ m_aImg.SetGraphic(Graphic());
+
+ EnableDisableButtons();
+}
+
+IMPL_LINK_NOARG(SdPhotoAlbumDialog, SelectHdl, weld::TreeView&, void)
+{
+ OUString sImgUrl = m_xImagesLst->get_selected_id();
+
+ if (sImgUrl != SdResId(STR_PHOTO_ALBUM_TEXTBOX))
+ {
+ Graphic aGraphic;
+ INetURLObject aURLObj( sImgUrl );
+
+ sal_uInt16 nFilter = GRFILTER_FORMAT_DONTKNOW;
+
+ if ( aURLObj.HasError() || INetProtocol::NotValid == aURLObj.GetProtocol() )
+ {
+ aURLObj.SetSmartProtocol( INetProtocol::File );
+ aURLObj.SetSmartURL( sImgUrl );
+ }
+
+ GraphicFilterImportFlags nFilterImportFlags = GraphicFilterImportFlags::SetLogsizeForJpeg;
+ // remote?
+ if ( INetProtocol::File != aURLObj.GetProtocol() )
+ {
+ std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream( sImgUrl, StreamMode::READ );
+
+ if( pStream )
+ m_pGraphicFilter->ImportGraphic( aGraphic, sImgUrl, *pStream, nFilter, nullptr, nFilterImportFlags );
+ else
+ m_pGraphicFilter->ImportGraphic( aGraphic, aURLObj, nFilter, nullptr, nFilterImportFlags );
+ }
+ else
+ {
+ m_pGraphicFilter->ImportGraphic( aGraphic, aURLObj, nFilter, nullptr, nFilterImportFlags );
+ }
+
+ BitmapEx aBmp = aGraphic.GetBitmapEx();
+ sal_Int32 nBmpWidth = aBmp.GetSizePixel().Width();
+ sal_Int32 nBmpHeight = aBmp.GetSizePixel().Height();
+
+ double nXRatio = double(200) / nBmpWidth;
+ double nYRatio = double(150) / nBmpHeight;
+ if ( nXRatio < nYRatio )
+ aBmp.Scale( nXRatio, nXRatio );
+ else
+ aBmp.Scale( nYRatio, nYRatio );
+
+ aBmp.Convert( BmpConversion::N24Bit );
+ m_aImg.SetGraphic(Graphic(aBmp));
+ }
+ else
+ {
+ m_aImg.SetGraphic(Graphic());
+ }
+ EnableDisableButtons();
+}
+
+IMPL_LINK_NOARG(SdPhotoAlbumDialog, TypeSelectHdl, weld::ComboBox&, void)
+{
+ // Enable "Fill Slide" only for one image
+ // If we want to have it for other images too, we need to implement the actual cropping.
+ bool const bEnable = m_xInsTypeCombo->get_active() == ONE_IMAGE;
+ m_xASRCheckCrop->set_sensitive(bEnable);
+ if (!bEnable)
+ m_xASRCheckCrop->set_active(false);
+}
+
+Reference< drawing::XDrawPage > SdPhotoAlbumDialog::appendNewSlide(AutoLayout aLayout,
+ const Reference< drawing::XDrawPages >& xDrawPages
+)
+{
+ // Create the slide
+ Reference< drawing::XDrawPage > xSlide = xDrawPages->insertNewByIndex( xDrawPages->getCount() );
+ SdPage* pSlide = m_pDoc->GetSdPage( m_pDoc->GetSdPageCount(PageKind::Standard)-1, PageKind::Standard);
+ pSlide->SetAutoLayout(aLayout, true); // Set the layout here
+ return xSlide;
+}
+
+awt::Size SdPhotoAlbumDialog::createASRSize(const awt::Size& aPicSize, const awt::Size& aMaxSize)
+{
+ double resizeWidth = aPicSize.Width;
+ double resizeHeight = aPicSize.Height;
+ double aspect = resizeWidth/resizeHeight;
+
+ if( resizeWidth > aMaxSize.Width )
+ {
+ resizeWidth = aMaxSize.Width;
+ resizeHeight = resizeWidth / aspect;
+ }
+
+ if( resizeHeight > aMaxSize.Height )
+ {
+ aspect = resizeWidth/resizeHeight;
+ resizeHeight = aMaxSize.Height;
+ resizeWidth = resizeHeight * aspect;
+ }
+ return awt::Size(resizeWidth, resizeHeight);
+}
+
+awt::Size SdPhotoAlbumDialog::createASRSizeCrop(const awt::Size& aPicSize, const awt::Size& aMaxSize)
+{
+ double resizeWidth = aPicSize.Width;
+ double resizeHeight = aPicSize.Height;
+ double imgAspect = resizeWidth / resizeHeight;
+ double windowAspectRatio = static_cast<double>(aMaxSize.Width) / aMaxSize.Height ;
+
+
+ //When both sides of an image are bigger than canvas size, image would be downscaled.
+ if( resizeWidth > aMaxSize.Width && resizeHeight > aMaxSize.Height )
+ {
+ if( imgAspect > windowAspectRatio )
+ {
+ resizeHeight = aMaxSize.Height;
+ resizeWidth = aMaxSize.Height * imgAspect;
+ }
+ else
+ {
+ resizeHeight = aMaxSize.Width / imgAspect;
+ resizeWidth = aMaxSize.Width;
+ }
+
+ }
+ //In all other cases image is upscaled
+ else
+ {
+ if( imgAspect > windowAspectRatio )
+ {
+ resizeHeight = aMaxSize.Height;
+ resizeWidth = aMaxSize.Height * imgAspect;
+ }
+ else
+ {
+ resizeWidth = aMaxSize.Width;
+ resizeHeight = aMaxSize.Width / imgAspect;
+ }
+ }
+ return awt::Size(resizeWidth, resizeHeight);
+}
+
+void SdPhotoAlbumDialog::createCaption(const awt::Size& aPageSize )
+{
+ Point CapPos;
+ Size CapSize;
+
+ CapSize.setWidth( aPageSize.Width );
+ CapSize.setHeight( aPageSize.Height/6 );
+ CapPos.setX( 0 );
+ CapPos.setY( aPageSize.Height - CapSize.Height() );
+ SdPage* pSlide = m_pDoc->GetSdPage( m_pDoc->GetSdPageCount(PageKind::Standard)-1, PageKind::Standard );
+
+ // try to get existing PresObj
+ const ::tools::Rectangle rRect(CapPos,CapSize);
+ SdrObject* pSdrObj = pSlide->GetPresObj(PresObjKind::Title);
+
+ if(!pSdrObj)
+ {
+ // if not exists, create. Beware: It is already inserted to the SdPage
+ pSdrObj = pSlide->CreatePresObj(PresObjKind::Title,false,rRect);
+ }
+ else
+ {
+ // if exists, bring to front and position it
+ const size_t nObjNum(pSlide->GetObjCount());
+
+ if(nObjNum)
+ {
+ pSlide->SetObjectOrdNum(pSdrObj->GetOrdNum(), nObjNum - 1);
+ }
+
+ pSdrObj->SetSnapRect(rRect);
+ }
+
+ if(pSdrObj)
+ {
+ // set color, style and some transparency
+ SfxItemSet aSet(m_pDoc->GetItemPool() );
+
+ aSet.Put( XFillStyleItem(drawing::FillStyle_SOLID) );
+ aSet.Put( XFillColorItem( "", COL_BLACK ) );
+ aSet.Put( XFillTransparenceItem( 20 ) );
+ pSdrObj->SetMergedItemSetAndBroadcast(aSet);
+ }
+}
+
+Reference< graphic::XGraphic> SdPhotoAlbumDialog::createXGraphicFromUrl(const OUString& sUrl,
+ const Reference< graphic::XGraphicProvider>& xProvider
+)
+{
+ // The same as above, except this returns an XGraphic from the image URL
+ ::comphelper::NamedValueCollection aMediaProperties;
+ aMediaProperties.put( "URL", sUrl );
+ Reference< graphic::XGraphic> xGraphic =
+ xProvider->queryGraphic( aMediaProperties.getPropertyValues() );
+ return xGraphic;
+}
+
+void SdPhotoAlbumDialog::EnableDisableButtons()
+{
+ m_xRemoveBtn->set_sensitive(m_xImagesLst->count_selected_rows() > 0);
+ m_xUpBtn->set_sensitive(m_xImagesLst->count_selected_rows() > 0 &&
+ m_xImagesLst->get_selected_index() != 0);
+ m_xDownBtn->set_sensitive(m_xImagesLst->count_selected_rows() > 0 &&
+ m_xImagesLst->get_selected_index() < m_xImagesLst->n_children() - 1);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/PhotoAlbumDialog.hxx b/sd/source/ui/dlg/PhotoAlbumDialog.hxx
new file mode 100644
index 000000000..f84ff5cc3
--- /dev/null
+++ b/sd/source/ui/dlg/PhotoAlbumDialog.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+* This file is part of the LibreOffice project.
+*
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/.
+*/
+
+#pragma once
+
+#include <tools/link.hxx>
+
+#include <vcl/weld.hxx>
+#include <svx/graphctl.hxx>
+#include <xmloff/autolayout.hxx>
+
+#include <com/sun/star/awt/Size.hpp>
+
+namespace com::sun::star::drawing { class XDrawPage; }
+namespace com::sun::star::drawing { class XDrawPages; }
+namespace com::sun::star::graphic { class XGraphicProvider; }
+
+class SdDrawDocument;
+class GraphicFilter;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd
+{
+
+class SdPhotoAlbumDialog : public weld::GenericDialogController
+{
+public:
+ SdPhotoAlbumDialog(weld::Window* pWindow, SdDrawDocument* pActDoc);
+ virtual ~SdPhotoAlbumDialog() override;
+
+private:
+ SdDrawDocument* m_pDoc;
+ GraphicFilter* m_pGraphicFilter;
+
+ GraphCtrl m_aImg;
+
+ std::unique_ptr<weld::Button> m_xCancelBtn;
+ std::unique_ptr<weld::Button> m_xCreateBtn;
+ std::unique_ptr<weld::Button> m_xAddBtn;
+ std::unique_ptr<weld::Button> m_xUpBtn;
+ std::unique_ptr<weld::Button> m_xDownBtn;
+ std::unique_ptr<weld::Button> m_xRemoveBtn;
+ std::unique_ptr<weld::TreeView> m_xImagesLst;
+ std::unique_ptr<weld::CustomWeld> m_xImg;
+ std::unique_ptr<weld::ComboBox> m_xInsTypeCombo;
+ std::unique_ptr<weld::CheckButton> m_xASRCheck;
+ std::unique_ptr<weld::CheckButton> m_xASRCheckCrop;
+ std::unique_ptr<weld::CheckButton> m_xCapCheck;
+ std::unique_ptr<weld::CheckButton> m_xInsertAsLinkCheck;
+
+ DECL_LINK(CancelHdl, weld::Button&, void);
+ DECL_LINK(CreateHdl, weld::Button&, void);
+
+ DECL_LINK(FileHdl, weld::Button&, void);
+ DECL_LINK(UpHdl, weld::Button&, void);
+ DECL_LINK(DownHdl, weld::Button&, void);
+ DECL_LINK(RemoveHdl, weld::Button&, void);
+
+ DECL_LINK(SelectHdl, weld::TreeView&, void);
+ DECL_LINK(TypeSelectHdl, weld::ComboBox&, void);
+
+ Reference< drawing::XDrawPage > appendNewSlide(AutoLayout aLayout,
+ const Reference< drawing::XDrawPages >& xDrawPages);
+
+ static awt::Size createASRSize(const awt::Size& aPicSize, const awt::Size& aMaxSize);
+ static awt::Size createASRSizeCrop(const awt::Size& aPicSize, const awt::Size& aMaxSize);
+ void createCaption(const awt::Size& aPageSize);
+ static Reference< graphic::XGraphic> createXGraphicFromUrl(const OUString& sUrl,
+ const Reference< graphic::XGraphicProvider>& xProvider);
+
+ void EnableDisableButtons();
+
+ enum SlideImageLayout
+ {
+ ONE_IMAGE=0,
+ TWO_IMAGES,
+ FOUR_IMAGES
+ };
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/RemoteDialog.cxx b/sd/source/ui/dlg/RemoteDialog.cxx
new file mode 100644
index 000000000..e28f57ecd
--- /dev/null
+++ b/sd/source/ui/dlg/RemoteDialog.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/.
+ */
+
+#include "RemoteDialog.hxx"
+#include <RemoteServer.hxx>
+
+using namespace ::sd;
+using namespace ::std;
+
+RemoteDialog::RemoteDialog(weld::Window* pWindow)
+ : GenericDialogController(pWindow, "modules/simpress/ui/remotedialog.ui", "RemoteDialog")
+ , m_xButtonConnect(m_xBuilder->weld_button("ok"))
+ , m_xClientBox(new sd::ClientBox(m_xBuilder->weld_scrolled_window("scroll"),
+ m_xBuilder->weld_container("tree")))
+{
+ m_xButtonConnect->connect_clicked(LINK(this, RemoteDialog, HandleConnectButton));
+}
+
+RemoteDialog::~RemoteDialog() {}
+
+IMPL_LINK_NOARG(RemoteDialog, HandleConnectButton, weld::Button&, void)
+{
+ weld::WaitObject(m_xDialog.get());
+#if defined(ENABLE_SDREMOTE)
+ auto xEntry = m_xClientBox->GetActiveEntry();
+ if (!xEntry)
+ return;
+ OUString aPin = xEntry->m_xPinBox->get_text();
+ if (RemoteServer::connectClient(xEntry->m_xClientInfo, aPin))
+ m_xDialog->response(RET_OK);
+#endif
+}
+
+short RemoteDialog::run()
+{
+ short nRet = weld::GenericDialogController::run();
+#ifdef ENABLE_SDREMOTE
+ RemoteServer::restoreDiscoverable();
+#endif
+ return nRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/RemoteDialog.hxx b/sd/source/ui/dlg/RemoteDialog.hxx
new file mode 100644
index 000000000..6c3f94ff8
--- /dev/null
+++ b/sd/source/ui/dlg/RemoteDialog.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+
+#include "RemoteDialogClientBox.hxx"
+
+namespace sd
+{
+class RemoteDialog : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::Button> m_xButtonConnect;
+ std::unique_ptr<ClientBox> m_xClientBox;
+
+ DECL_LINK(HandleConnectButton, weld::Button&, void);
+
+public:
+ explicit RemoteDialog(weld::Window* pWindow);
+ virtual short run() override;
+ virtual ~RemoteDialog() override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/RemoteDialogClientBox.cxx b/sd/source/ui/dlg/RemoteDialogClientBox.cxx
new file mode 100644
index 000000000..2371c4fb8
--- /dev/null
+++ b/sd/source/ui/dlg/RemoteDialogClientBox.cxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vector>
+
+#include "RemoteDialogClientBox.hxx"
+#include <RemoteServer.hxx>
+
+#include <vcl/svapp.hxx>
+
+namespace sd {
+
+// struct ClientBoxEntry
+
+ClientBoxEntry::ClientBoxEntry(ClientBox* pClientBox,
+ const std::shared_ptr<ClientInfo>& pClientInfo)
+ : m_xBuilder(Application::CreateBuilder(pClientBox->GetContainer(), "modules/simpress/ui/clientboxfragment.ui"))
+ , m_xContainer(m_xBuilder->weld_container("ClientboxFragment"))
+ , m_xDeviceName(m_xBuilder->weld_label("name"))
+ , m_xPinLabel(m_xBuilder->weld_label("pinlabel"))
+ , m_xPinBox(m_xBuilder->weld_entry("pin"))
+ , m_xDeauthoriseButton(m_xBuilder->weld_button("button"))
+ , m_xClientInfo(pClientInfo)
+ , m_pClientBox(pClientBox)
+{
+ m_xDeviceName->set_label(m_xClientInfo->mName);
+ m_xDeauthoriseButton->connect_clicked(LINK(this, ClientBoxEntry, DeauthoriseHdl));
+ m_xDeauthoriseButton->set_visible(m_xClientInfo->mbIsAlreadyAuthorised);
+ m_xPinBox->set_visible(!m_xClientInfo->mbIsAlreadyAuthorised);
+ m_xPinLabel->set_visible(!m_xClientInfo->mbIsAlreadyAuthorised);
+
+ m_xDeauthoriseButton->connect_focus_in(LINK(this, ClientBoxEntry, FocusHdl));
+ m_xPinBox->connect_focus_in(LINK(this, ClientBoxEntry, FocusHdl));
+}
+
+ClientBoxEntry::~ClientBoxEntry()
+{
+ m_pClientBox->GetContainer()->move(m_xContainer.get(), nullptr);
+}
+
+// ClientBox
+ClientBox::ClientBox(std::unique_ptr<weld::ScrolledWindow> xScroll,
+ std::unique_ptr<weld::Container> xContents)
+ : m_xScroll(std::move(xScroll))
+ , m_xContents(std::move(xContents))
+ , m_pActive(nullptr)
+{
+ Size aSize(m_xScroll->get_approximate_digit_width() * 40,
+ m_xScroll->get_text_height() * 16);
+ m_xScroll->set_size_request(aSize.Width(), aSize.Height());
+
+ m_xContents->set_stack_background();
+
+ populateEntries();
+}
+
+ClientBox::~ClientBox()
+{
+}
+
+ClientBoxEntry* ClientBox::GetActiveEntry()
+{
+ return m_pActive;
+}
+
+void ClientBox::addEntry( const std::shared_ptr<ClientInfo>& pClientInfo )
+{
+ TClientBoxEntry xEntry = std::make_shared<ClientBoxEntry>(this, pClientInfo);
+ m_vEntries.push_back(xEntry);
+}
+
+void ClientBox::setActive(ClientBoxEntry* pClientEntry)
+{
+ m_pActive = pClientEntry;
+}
+
+void ClientBox::clearEntries()
+{
+ m_vEntries.clear();
+ m_pActive = nullptr;
+}
+
+void ClientBox::populateEntries()
+{
+ clearEntries();
+
+#ifdef ENABLE_SDREMOTE
+ RemoteServer::ensureDiscoverable();
+
+ std::vector< std::shared_ptr< ClientInfo > > aClients( RemoteServer::getClients() );
+
+ for ( const auto& rxClient : aClients )
+ {
+ addEntry( rxClient );
+ }
+#endif
+
+}
+
+IMPL_LINK_NOARG(ClientBoxEntry, DeauthoriseHdl, weld::Button&, void)
+{
+#ifdef ENABLE_SDREMOTE
+ RemoteServer::deauthoriseClient(m_xClientInfo);
+#endif
+ m_pClientBox->populateEntries();
+}
+
+IMPL_LINK_NOARG(ClientBoxEntry, FocusHdl, weld::Widget&, void)
+{
+ if (ClientBoxEntry* pOldEntry = m_pClientBox->GetActiveEntry())
+ pOldEntry->m_xContainer->set_stack_background();
+ m_pClientBox->setActive(this);
+ m_xContainer->set_highlight_background();
+}
+
+} //namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/RemoteDialogClientBox.hxx b/sd/source/ui/dlg/RemoteDialogClientBox.hxx
new file mode 100644
index 000000000..c7a916dc9
--- /dev/null
+++ b/sd/source/ui/dlg/RemoteDialogClientBox.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+#include <memory>
+
+namespace sd {
+
+#define SMALL_ICON_SIZE 16
+#define TOP_OFFSET 5
+#define ICON_HEIGHT 42
+#define ICON_WIDTH 47
+#define ICON_OFFSET 72
+#define RIGHT_ICON_OFFSET 5
+#define SPACE_BETWEEN 3
+
+class ClientBox;
+struct ClientBoxEntry;
+struct ClientInfo;
+
+typedef std::shared_ptr<ClientBoxEntry> TClientBoxEntry;
+
+struct ClientBoxEntry
+{
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<weld::Label> m_xDeviceName;
+ std::unique_ptr<weld::Label> m_xPinLabel;
+ std::unique_ptr<weld::Entry> m_xPinBox;
+ std::unique_ptr<weld::Button> m_xDeauthoriseButton;
+
+ std::shared_ptr<ClientInfo> m_xClientInfo;
+ ClientBox* m_pClientBox;
+
+ DECL_LINK(DeauthoriseHdl, weld::Button&, void);
+ DECL_LINK(FocusHdl, weld::Widget&, void);
+
+ ClientBoxEntry(ClientBox* pClientBox, const std::shared_ptr<ClientInfo>& pClientInfo);
+ ~ClientBoxEntry();
+};
+
+class ClientBox
+{
+ std::unique_ptr<weld::ScrolledWindow> m_xScroll;
+ std::unique_ptr<weld::Container> m_xContents;
+
+ std::vector< TClientBoxEntry > m_vEntries;
+ ClientBoxEntry* m_pActive;
+
+public:
+ ClientBox(std::unique_ptr<weld::ScrolledWindow> xScroll, std::unique_ptr<weld::Container> xContents);
+ weld::Container* GetContainer() { return m_xContents.get(); }
+ ~ClientBox();
+
+ ClientBoxEntry* GetActiveEntry();
+
+ void addEntry(const std::shared_ptr<ClientInfo>& pClientInfo);
+ void setActive(ClientBoxEntry* pClientData);
+ void clearEntries();
+
+ void populateEntries();
+};
+
+} // end namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/SpellDialogChildWindow.cxx b/sd/source/ui/dlg/SpellDialogChildWindow.cxx
new file mode 100644
index 000000000..c87919346
--- /dev/null
+++ b/sd/source/ui/dlg/SpellDialogChildWindow.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <SpellDialogChildWindow.hxx>
+#include <svx/svxids.hrc>
+
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <DrawViewShell.hxx>
+#include <OutlineViewShell.hxx>
+#include <Outliner.hxx>
+#include <drawdoc.hxx>
+
+namespace sd {
+
+SFX_IMPL_CHILDWINDOW_WITHID(SpellDialogChildWindow, SID_SPELL_DIALOG)
+
+SpellDialogChildWindow::SpellDialogChildWindow (
+ vcl::Window* _pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SAL_UNUSED_PARAMETER SfxChildWinInfo* /*pInfo*/)
+ : svx::SpellDialogChildWindow (_pParent, nId, pBindings),
+ mpSdOutliner (nullptr),
+ mbOwnOutliner (false)
+{
+ ProvideOutliner();
+}
+
+SpellDialogChildWindow::~SpellDialogChildWindow()
+{
+ EndSpellingAndClearOutliner();
+}
+
+SfxChildWinInfo SpellDialogChildWindow::GetInfo() const
+{
+ return svx::SpellDialogChildWindow::GetInfo();
+}
+
+void SpellDialogChildWindow::InvalidateSpellDialog()
+{
+ svx::SpellDialogChildWindow::InvalidateSpellDialog();
+}
+
+svx::SpellPortions SpellDialogChildWindow::GetNextWrongSentence( bool /*bRecheck*/ )
+{
+ svx::SpellPortions aResult;
+
+ if (mpSdOutliner != nullptr)
+ {
+ ProvideOutliner();
+ aResult = mpSdOutliner->GetNextSpellSentence();
+ }
+ return aResult;
+}
+
+void SpellDialogChildWindow::ApplyChangedSentence (
+ const svx::SpellPortions& rChanged, bool bRecheck )
+{
+ if (mpSdOutliner != nullptr)
+ {
+ OutlinerView* pOutlinerView = mpSdOutliner->GetView(0);
+ if (pOutlinerView != nullptr)
+ mpSdOutliner->ApplyChangedSentence (
+ pOutlinerView->GetEditView(),
+ rChanged, bRecheck);
+ }
+}
+
+void SpellDialogChildWindow::GetFocus()
+{
+ // In order to detect a cursor movement we could compare the
+ // currently selected text shape with the one that was selected
+ // when LoseFocus() was called the last time.
+ // For the time being we instead rely on the DetectChange() method
+ // in the SdOutliner class.
+}
+
+void SpellDialogChildWindow::LoseFocus()
+{
+}
+
+void SpellDialogChildWindow::EndSpellingAndClearOutliner()
+{
+ if (!mpSdOutliner)
+ return;
+ EndListening(*mpSdOutliner->GetDoc());
+ mpSdOutliner->EndSpelling();
+ if (mbOwnOutliner)
+ delete mpSdOutliner;
+ mpSdOutliner = nullptr;
+ mbOwnOutliner = false;
+}
+
+void SpellDialogChildWindow::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ if (SdrHintKind::ModelCleared == pSdrHint->GetKind())
+ {
+ EndSpellingAndClearOutliner();
+ }
+}
+
+void SpellDialogChildWindow::ProvideOutliner()
+{
+ ViewShellBase* pViewShellBase = dynamic_cast<ViewShellBase*>( SfxViewShell::Current() );
+
+ if (pViewShellBase == nullptr)
+ return;
+
+ ViewShell* pViewShell = pViewShellBase->GetMainViewShell().get();
+ // If there already exists an outliner that has been created
+ // for another view shell then destroy it first.
+ if (mpSdOutliner != nullptr)
+ if(( dynamic_cast< const DrawViewShell *>( pViewShell ) != nullptr && ! mbOwnOutliner)
+ || (dynamic_cast< const OutlineViewShell *>( pViewShell ) != nullptr && mbOwnOutliner))
+ {
+ EndSpellingAndClearOutliner();
+ }
+
+ // Now create/get an outliner if none is present.
+ if (mpSdOutliner != nullptr)
+ return;
+
+ if( dynamic_cast< const DrawViewShell *>( pViewShell ) != nullptr)
+ {
+ // We need an outliner for the spell check so we have
+ // to create one.
+ mbOwnOutliner = true;
+ SdDrawDocument *pDoc = pViewShell->GetDoc();
+ mpSdOutliner = new SdOutliner(pDoc, OutlinerMode::TextObject);
+ StartListening(*pDoc);
+ }
+ else if( dynamic_cast< const OutlineViewShell *>( pViewShell ) != nullptr)
+ {
+ // An outline view is already visible. The SdOutliner
+ // will use it instead of creating its own.
+ mbOwnOutliner = false;
+ SdDrawDocument *pDoc = pViewShell->GetDoc();
+ mpSdOutliner = pDoc->GetOutliner();
+ StartListening(*pDoc);
+ }
+
+ // Initialize spelling.
+ if (mpSdOutliner != nullptr)
+ {
+ mpSdOutliner->PrepareSpelling();
+ mpSdOutliner->StartSpelling();
+ }
+}
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/TemplateScanner.cxx b/sd/source/ui/dlg/TemplateScanner.cxx
new file mode 100644
index 000000000..afd23ff85
--- /dev/null
+++ b/sd/source/ui/dlg/TemplateScanner.cxx
@@ -0,0 +1,342 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TemplateScanner.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/documentconstants.hxx>
+
+#include <sfx2/doctempl.hxx>
+#include <com/sun/star/frame/DocumentTemplates.hpp>
+#include <com/sun/star/frame/XDocumentTemplates.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+
+#include <set>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+constexpr OUStringLiteral TITLE = u"Title";
+
+class FolderDescriptor
+{
+public:
+ FolderDescriptor (
+ int nPriority,
+ const OUString& rsContentIdentifier,
+ const Reference<css::ucb::XCommandEnvironment>& rxFolderEnvironment)
+ : mnPriority(nPriority),
+ msContentIdentifier(rsContentIdentifier),
+ mxFolderEnvironment(rxFolderEnvironment)
+ { }
+ int mnPriority;
+ OUString msContentIdentifier;
+ // Reference<sdbc::XResultSet> mxFolderResultSet;
+ Reference<css::ucb::XCommandEnvironment> mxFolderEnvironment;
+
+ class Comparator
+ {
+ public:
+ bool operator() (const FolderDescriptor& r1, const FolderDescriptor& r2) const
+ { return r1.mnPriority < r2.mnPriority; }
+ };
+};
+
+/** Use a heuristic based on the URL of a top-level template folder to
+ assign a priority that is used to sort the folders.
+*/
+int Classify (std::u16string_view rsURL)
+{
+ int nPriority (0);
+
+ if (rsURL.empty())
+ nPriority = 100;
+ else if (rsURL.find(u"presnt") != std::u16string_view::npos)
+ {
+ nPriority = 30;
+ }
+ else if (rsURL.find(u"layout") != std::u16string_view::npos)
+ {
+ nPriority = 20;
+ }
+ else if (rsURL.find(u"educate") != std::u16string_view::npos)
+ {
+ nPriority = 40;
+ }
+ else if (rsURL.find(u"finance") != std::u16string_view::npos)
+ {
+ nPriority = 40;
+ }
+ else
+ {
+ // All other folders are taken for user supplied and have the
+ // highest priority.
+ nPriority = 10;
+ }
+
+ return nPriority;
+}
+
+} // end of anonymous namespace
+
+namespace sd
+{
+
+class TemplateScanner::FolderDescriptorList
+ : public ::std::multiset<FolderDescriptor,FolderDescriptor::Comparator>
+{
+};
+
+TemplateScanner::TemplateScanner()
+ : meState(INITIALIZE_SCANNING),
+ mpFolderDescriptors(new FolderDescriptorList)
+{
+ // empty;
+}
+
+TemplateScanner::~TemplateScanner()
+{
+}
+
+TemplateScanner::State TemplateScanner::GetTemplateRoot()
+{
+ Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ Reference<frame::XDocumentTemplates> xTemplates = frame::DocumentTemplates::create(xContext);
+ mxTemplateRoot = xTemplates->getContent();
+
+ return INITIALIZE_FOLDER_SCANNING;
+}
+
+TemplateScanner::State TemplateScanner::InitializeEntryScanning()
+{
+ State eNextState (SCAN_ENTRY);
+
+ if (maFolderContent.isFolder())
+ {
+ mxEntryEnvironment.clear();
+
+ // Create a cursor to iterate over the templates in this folders.
+ // We are interested only in three properties: the entry's name,
+ // its URL, and its content type.
+ mxEntryResultSet.set( maFolderContent.createCursor({ TITLE, "TargetURL", "TypeDescription" }, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY));
+ }
+ else
+ eNextState = ERROR;
+
+ return eNextState;
+}
+
+TemplateScanner::State TemplateScanner::ScanEntry()
+{
+ State eNextState (ERROR);
+
+ Reference<css::ucb::XContentAccess> xContentAccess (mxEntryResultSet, UNO_QUERY);
+ Reference<css::sdbc::XRow> xRow (mxEntryResultSet, UNO_QUERY);
+
+ if (xContentAccess.is() && xRow.is() && mxEntryResultSet.is())
+ {
+ if (mxEntryResultSet->next())
+ {
+ OUString sTitle (xRow->getString (1));
+ OUString sTargetURL (xRow->getString (2));
+ OUString sContentType (xRow->getString (3));
+
+ OUString aId = xContentAccess->queryContentIdentifierString();
+ ::ucbhelper::Content aContent(aId, mxEntryEnvironment, comphelper::getProcessComponentContext());
+ if (aContent.isDocument ())
+ {
+ // Check whether the entry is an impress template. If so
+ // add a new entry to the resulting list (which is created
+ // first if necessary).
+ // These strings are used to find impress templates in the tree of
+ // template files. Should probably be determined dynamically.
+ if ( (sContentType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII)
+ || (sContentType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII)
+ || (sContentType == "application/vnd.stardivision.impress")
+ || (sContentType == MIMETYPE_VND_SUN_XML_IMPRESS_ASCII)
+ // The following id comes from the bugdoc in #i2764#.
+ || (sContentType == "Impress 2.0"))
+ {
+ OUString sLocalisedTitle = SfxDocumentTemplates::ConvertResourceString(sTitle);
+ mpTemplateEntries.push_back(std::make_unique<TemplateEntry>(sLocalisedTitle, sTargetURL));
+ }
+ }
+
+ // Continue scanning entries.
+ eNextState = SCAN_ENTRY;
+ }
+ else
+ {
+ // Continue with scanning the next folder.
+ eNextState = SCAN_FOLDER;
+ }
+ }
+
+ return eNextState;
+}
+
+TemplateScanner::State TemplateScanner::InitializeFolderScanning()
+{
+ State eNextState (ERROR);
+
+ mxFolderResultSet.clear();
+
+ try
+ {
+ // Create content for template folders.
+ mxFolderEnvironment.clear();
+ ::ucbhelper::Content aTemplateDir (mxTemplateRoot, mxFolderEnvironment, comphelper::getProcessComponentContext());
+
+ // Create a cursor to iterate over the template folders.
+ mxFolderResultSet.set( aTemplateDir.createCursor({ TITLE, "TargetDirURL" }, ::ucbhelper::INCLUDE_FOLDERS_ONLY));
+ if (mxFolderResultSet.is())
+ eNextState = GATHER_FOLDER_LIST;
+ }
+ catch (css::uno::Exception&)
+ {
+ eNextState = ERROR;
+ }
+
+ return eNextState;
+}
+
+TemplateScanner::State TemplateScanner::GatherFolderList()
+{
+ State eNextState (ERROR);
+
+ Reference<css::ucb::XContentAccess> xContentAccess (mxFolderResultSet, UNO_QUERY);
+ if (xContentAccess.is() && mxFolderResultSet.is())
+ {
+ while (mxFolderResultSet->next())
+ {
+ Reference<sdbc::XRow> xRow (mxFolderResultSet, UNO_QUERY);
+ if (xRow.is())
+ {
+ OUString sTargetDir (xRow->getString (2));
+ OUString aId = xContentAccess->queryContentIdentifierString();
+
+ mpFolderDescriptors->insert(
+ FolderDescriptor(
+ Classify(sTargetDir),
+ aId,
+ mxFolderEnvironment));
+ }
+ }
+
+ eNextState = SCAN_FOLDER;
+ }
+
+ return eNextState;
+}
+
+TemplateScanner::State TemplateScanner::ScanFolder()
+{
+ State eNextState (ERROR);
+
+ if (!mpFolderDescriptors->empty())
+ {
+ FolderDescriptor aDescriptor (*mpFolderDescriptors->begin());
+ mpFolderDescriptors->erase(mpFolderDescriptors->begin());
+
+ OUString aId (aDescriptor.msContentIdentifier);
+
+ maFolderContent = ::ucbhelper::Content (aId, aDescriptor.mxFolderEnvironment, comphelper::getProcessComponentContext());
+ if (maFolderContent.isFolder())
+ {
+ // Scan the folder and insert it into the list of template
+ // folders.
+ // Continue with scanning all entries in the folder.
+ mpTemplateEntries.clear();
+ eNextState = INITIALIZE_ENTRY_SCAN;
+ }
+ }
+ else
+ {
+ eNextState = DONE;
+ }
+
+ return eNextState;
+}
+
+void TemplateScanner::RunNextStep()
+{
+ switch (meState)
+ {
+ case INITIALIZE_SCANNING:
+ meState = GetTemplateRoot();
+ break;
+
+ case INITIALIZE_FOLDER_SCANNING:
+ meState = InitializeFolderScanning();
+ break;
+
+ case SCAN_FOLDER:
+ meState = ScanFolder();
+ break;
+
+ case GATHER_FOLDER_LIST:
+ meState = GatherFolderList();
+ break;
+
+ case INITIALIZE_ENTRY_SCAN:
+ meState = InitializeEntryScanning();
+ break;
+
+ case SCAN_ENTRY:
+ meState = ScanEntry();
+ break;
+ default:
+ break;
+ }
+
+ switch (meState)
+ {
+ case DONE:
+ case ERROR:
+ mxTemplateRoot.clear();
+ mxFolderEnvironment.clear();
+ mxEntryEnvironment.clear();
+ mxFolderResultSet.clear();
+ mxEntryResultSet.clear();
+ break;
+ default:
+ break;
+ }
+}
+
+bool TemplateScanner::HasNextStep()
+{
+ switch (meState)
+ {
+ case DONE:
+ case ERROR:
+ return false;
+
+ default:
+ return true;
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/animobjs.cxx b/sd/source/ui/dlg/animobjs.cxx
new file mode 100644
index 000000000..b70848e23
--- /dev/null
+++ b/sd/source/ui/dlg/animobjs.cxx
@@ -0,0 +1,1134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <time.h>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdpagv.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/progress.hxx>
+#include <vcl/help.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/virdev.hxx>
+
+#include <anminfo.hxx>
+#include <animobjs.hxx>
+#include <app.hrc>
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+
+#include <ViewShell.hxx>
+
+#include <vcl/settings.hxx>
+
+#include <EffectMigration.hxx>
+
+#include <algorithm>
+
+using namespace ::com::sun::star;
+
+namespace sd {
+
+/**
+ * SdDisplay - Control
+ */
+SdDisplay::SdDisplay()
+ : aScale(1, 1)
+{
+}
+
+SdDisplay::~SdDisplay()
+{
+}
+
+void SdDisplay::SetBitmapEx( BitmapEx const * pBmpEx )
+{
+ if( pBmpEx )
+ {
+ aBitmapEx = *pBmpEx;
+ }
+ else
+ {
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ const Color aFillColor = rStyles.GetFieldColor();
+ aBitmapEx.Erase(aFillColor);
+ }
+}
+
+void SdDisplay::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapPixel));
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ rRenderContext.SetBackground( Wallpaper( rStyles.GetFieldColor() ) );
+ rRenderContext.Erase();
+
+ Point aPt;
+ Size aSize = GetOutputSizePixel();
+
+ Size aBmpSize = aBitmapEx.GetBitmap().GetSizePixel();
+ aBmpSize.setWidth( static_cast<::tools::Long>( static_cast<double>(aBmpSize.Width()) * static_cast<double>(aScale) ) );
+ aBmpSize.setHeight( static_cast<::tools::Long>( static_cast<double>(aBmpSize.Height()) * static_cast<double>(aScale) ) );
+
+ if( aBmpSize.Width() < aSize.Width() )
+ aPt.setX( ( aSize.Width() - aBmpSize.Width() ) / 2 );
+ if( aBmpSize.Height() < aSize.Height() )
+ aPt.setY( ( aSize.Height() - aBmpSize.Height() ) / 2 );
+
+ aBitmapEx.Draw(&rRenderContext, aPt, aBmpSize);
+
+ rRenderContext.Pop();
+}
+
+void SdDisplay::SetScale( const Fraction& rFrac )
+{
+ aScale = rFrac;
+}
+
+void SdDisplay::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(147, 87), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+}
+
+const size_t AnimationWindow::EMPTY_FRAMELIST = std::numeric_limits<size_t>::max();
+
+/**
+ * AnimationWindow - FloatingWindow
+ */
+AnimationWindow::AnimationWindow(SfxBindings* pInBindings, SfxChildWindow *pCW, vcl::Window* pParent)
+ : SfxDockingWindow(pInBindings, pCW, pParent,
+ "DockingAnimation", "modules/simpress/ui/dockinganimation.ui")
+ , m_xCtlDisplay(new SdDisplay)
+ , m_xCtlDisplayWin(new weld::CustomWeld(*m_xBuilder, "preview", *m_xCtlDisplay))
+ , m_xBtnFirst(m_xBuilder->weld_button("first"))
+ , m_xBtnReverse(m_xBuilder->weld_button("prev"))
+ , m_xBtnStop(m_xBuilder->weld_button("stop"))
+ , m_xBtnPlay(m_xBuilder->weld_button("next"))
+ , m_xBtnLast(m_xBuilder->weld_button("last"))
+ , m_xNumFldBitmap(m_xBuilder->weld_spin_button("numbitmap"))
+ , m_xTimeField(m_xBuilder->weld_formatted_spin_button("duration"))
+ , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
+ , m_xLbLoopCount(m_xBuilder->weld_combo_box("loopcount"))
+ , m_xBtnGetOneObject(m_xBuilder->weld_button("getone"))
+ , m_xBtnGetAllObjects(m_xBuilder->weld_button("getall"))
+ , m_xBtnRemoveBitmap(m_xBuilder->weld_button("delone"))
+ , m_xBtnRemoveAll(m_xBuilder->weld_button("delall"))
+ , m_xFiCount(m_xBuilder->weld_label("count"))
+ , m_xRbtGroup(m_xBuilder->weld_radio_button("group"))
+ , m_xRbtBitmap(m_xBuilder->weld_radio_button("bitmap"))
+ , m_xFtAdjustment(m_xBuilder->weld_label("alignmentft"))
+ , m_xLbAdjustment(m_xBuilder->weld_combo_box("alignment"))
+ , m_xBtnCreateGroup(m_xBuilder->weld_button("create"))
+ , m_xBtnHelp(m_xBuilder->weld_button("help"))
+ , m_nCurrentFrame(EMPTY_FRAMELIST)
+ , bMovie(false)
+ , bAllObjects(false)
+{
+ SetText(SdResId(STR_ANIMATION_DIALOG_TITLE));
+
+ m_xFormatter->SetDuration(true);
+ m_xFormatter->SetTimeFormat(TimeFieldFormat::F_SEC_CS);
+ m_xFormatter->EnableEmptyField(false);
+
+ // create new document with page
+ pMyDoc.reset( new SdDrawDocument(DocumentType::Impress, nullptr) );
+ rtl::Reference<SdPage> pPage = pMyDoc->AllocSdPage(false);
+ pMyDoc->InsertPage(pPage.get());
+
+ pControllerItem.reset( new AnimationControllerItem( SID_ANIMATOR_STATE, this, pInBindings ) );
+
+ m_xBtnFirst->connect_clicked( LINK( this, AnimationWindow, ClickFirstHdl ) );
+ m_xBtnReverse->connect_clicked( LINK( this, AnimationWindow, ClickPlayHdl ) );
+ m_xBtnStop->connect_clicked( LINK( this, AnimationWindow, ClickStopHdl ) );
+ m_xBtnPlay->connect_clicked( LINK( this, AnimationWindow, ClickPlayHdl ) );
+ m_xBtnLast->connect_clicked( LINK( this, AnimationWindow, ClickLastHdl ) );
+
+ m_xBtnGetOneObject->connect_clicked( LINK( this, AnimationWindow, ClickGetObjectHdl ) );
+ m_xBtnGetAllObjects->connect_clicked( LINK( this, AnimationWindow, ClickGetObjectHdl ) );
+ m_xBtnRemoveBitmap->connect_clicked( LINK( this, AnimationWindow, ClickRemoveBitmapHdl ) );
+ m_xBtnRemoveAll->connect_clicked( LINK( this, AnimationWindow, ClickRemoveBitmapHdl ) );
+
+ m_xRbtGroup->connect_toggled( LINK( this, AnimationWindow, ClickRbtHdl ) );
+ m_xRbtBitmap->connect_toggled( LINK( this, AnimationWindow, ClickRbtHdl ) );
+ m_xBtnCreateGroup->connect_clicked( LINK( this, AnimationWindow, ClickCreateGroupHdl ) );
+ m_xBtnHelp->connect_clicked( LINK( this, AnimationWindow, ClickHelpHdl ) );
+ m_xNumFldBitmap->connect_value_changed( LINK( this, AnimationWindow, ModifyBitmapHdl ) );
+ m_xTimeField->connect_value_changed( LINK( this, AnimationWindow, ModifyTimeHdl ) );
+
+ SetMinOutputSizePixel(GetOptimalSize());
+
+ ResetAttrs();
+
+ // the animator is empty; no animation group can be created
+ m_xBtnCreateGroup->set_sensitive(false);
+}
+
+AnimationWindow::~AnimationWindow()
+{
+ disposeOnce();
+}
+
+void AnimationWindow::dispose()
+{
+ pControllerItem.reset();
+
+ m_FrameList.clear();
+ m_nCurrentFrame = EMPTY_FRAMELIST;
+
+ // delete the clones
+ pMyDoc.reset();
+
+ m_xCtlDisplayWin.reset();
+ m_xCtlDisplay.reset();
+ m_xBtnFirst.reset();
+ m_xBtnReverse.reset();
+ m_xBtnStop.reset();
+ m_xBtnPlay.reset();
+ m_xBtnLast.reset();
+ m_xNumFldBitmap.reset();
+ m_xFormatter.reset();
+ m_xTimeField.reset();
+ m_xLbLoopCount.reset();
+ m_xBtnGetOneObject.reset();
+ m_xBtnGetAllObjects.reset();
+ m_xBtnRemoveBitmap.reset();
+ m_xBtnRemoveAll.reset();
+ m_xFiCount.reset();
+ m_xRbtGroup.reset();
+ m_xRbtBitmap.reset();
+ m_xFtAdjustment.reset();
+ m_xLbAdjustment.reset();
+ m_xBtnCreateGroup.reset();
+ m_xBtnHelp.reset();
+ SfxDockingWindow::dispose();
+}
+
+IMPL_LINK_NOARG(AnimationWindow, ClickFirstHdl, weld::Button&, void)
+{
+ m_nCurrentFrame = (m_FrameList.empty()) ? EMPTY_FRAMELIST : 0;
+ UpdateControl();
+}
+
+IMPL_LINK_NOARG(AnimationWindow, ClickStopHdl, weld::Button&, void)
+{
+ bMovie = false;
+}
+
+IMPL_LINK( AnimationWindow, ClickPlayHdl, weld::Button&, rButton, void )
+{
+ ScopeLockGuard aGuard( maPlayLock );
+
+ bMovie = true;
+ bool bDisableCtrls = false;
+ size_t const nCount = m_FrameList.size();
+ bool bReverse = &rButton == m_xBtnReverse.get();
+
+ // it is difficult to find it later on
+ bool bRbtGroupEnabled = m_xRbtGroup->get_sensitive();
+ bool bBtnGetAllObjectsEnabled = m_xBtnGetAllObjects->get_sensitive();
+ bool bBtnGetOneObjectEnabled = m_xBtnGetOneObject->get_sensitive();
+
+ // calculate overall time
+ ::tools::Time aTime( 0 );
+ ::tools::Long nFullTime;
+ if( m_xRbtBitmap->get_active() )
+ {
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ aTime += m_FrameList[i].second;
+ }
+ nFullTime = aTime.GetMSFromTime();
+ }
+ else
+ {
+ nFullTime = nCount * 100;
+ aTime.MakeTimeFromMS( nFullTime );
+ }
+
+ // StatusBarManager from 1 second
+ std::unique_ptr<SfxProgress> pProgress;
+ if( nFullTime >= 1000 )
+ {
+ bDisableCtrls = true;
+ m_xBtnStop->set_sensitive(true);
+ pProgress.reset(new SfxProgress( nullptr, "Animator:", nFullTime )); // "Animator:" here we should think about something smart
+ }
+
+ sal_uLong nTmpTime = 0;
+ size_t i = 0;
+ bool bCount = i < nCount;
+ if( bReverse )
+ {
+ i = nCount - 1;
+ }
+ while( bCount && bMovie )
+ {
+ // make list and view consistent
+ assert(i < m_FrameList.size());
+ m_nCurrentFrame = i;
+
+ UpdateControl(bDisableCtrls);
+
+ if( m_xRbtBitmap->get_active() )
+ {
+ ::tools::Time const & rTime = m_FrameList[i].second;
+
+ m_xFormatter->SetTime( rTime );
+ sal_uLong nTime = rTime.GetMSFromTime();
+
+ WaitInEffect( nTime, nTmpTime, pProgress.get() );
+ nTmpTime += nTime;
+ }
+ else
+ {
+ WaitInEffect( 100, nTmpTime, pProgress.get() );
+ nTmpTime += 100;
+ }
+ if( bReverse )
+ {
+ if (i == 0)
+ {
+ // Terminate loop.
+ bCount = false;
+ }
+ else
+ {
+ --i;
+ }
+ }
+ else
+ {
+ i++;
+ if (i >= nCount)
+ {
+ // Terminate loop.
+ bCount = false;
+ // Move i back into valid range.
+ i = nCount - 1;
+ }
+ }
+ }
+
+ // to re-enable the controls
+ bMovie = false;
+ if (nCount > 0)
+ {
+ assert(i == m_nCurrentFrame);
+ UpdateControl();
+ }
+
+ if( pProgress )
+ {
+ pProgress.reset();
+ m_xBtnStop->set_sensitive(false);
+ }
+
+ m_xRbtGroup->set_sensitive( bRbtGroupEnabled );
+ m_xBtnGetAllObjects->set_sensitive( bBtnGetAllObjectsEnabled );
+ m_xBtnGetOneObject->set_sensitive( bBtnGetOneObjectEnabled );
+}
+
+IMPL_LINK_NOARG(AnimationWindow, ClickLastHdl, weld::Button&, void)
+{
+ m_nCurrentFrame =
+ (m_FrameList.empty()) ? EMPTY_FRAMELIST : m_FrameList.size() - 1 ;
+ UpdateControl();
+}
+
+IMPL_LINK_NOARG(AnimationWindow, ClickRbtHdl, weld::Toggleable&, void)
+{
+ if (m_FrameList.empty() || m_xRbtGroup->get_active())
+ {
+ m_xTimeField->set_text( OUString() );
+ m_xTimeField->set_sensitive( false );
+ m_xLbLoopCount->set_sensitive( false );
+ }
+ else if (m_xRbtBitmap->get_active())
+ {
+ sal_uLong n = m_xNumFldBitmap->get_value();
+ if( n > 0 )
+ {
+ ::tools::Time const & rTime = m_FrameList[n - 1].second;
+ m_xFormatter->SetTime( rTime );
+ m_xFormatter->ReFormat();
+ }
+ m_xTimeField->set_sensitive(true);
+ m_xLbLoopCount->set_sensitive(true);
+ }
+}
+
+IMPL_LINK(AnimationWindow, ClickHelpHdl, weld::Button&, rButton, void)
+{
+ if (Help* pHelp = Application::GetHelp())
+ pHelp->Start(OUString::fromUtf8(m_xContainer->get_help_id()), &rButton);
+}
+
+IMPL_LINK( AnimationWindow, ClickGetObjectHdl, weld::Button&, rBtn, void )
+{
+ bAllObjects = &rBtn == m_xBtnGetAllObjects.get();
+
+ // Code now in AddObj()
+ SfxBoolItem aItem( SID_ANIMATOR_ADD, true );
+
+ GetBindings().GetDispatcher()->ExecuteList(
+ SID_ANIMATOR_ADD, SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK( AnimationWindow, ClickRemoveBitmapHdl, weld::Button&, rBtn, void )
+{
+ SdPage* pPage = pMyDoc->GetSdPage(0, PageKind::Standard);
+ SdrObject* pObject;
+
+ // tdf#95298 check m_nCurrentFrame for EMPTY_FRAMELIST to avoid out-of-bound array access
+ if (&rBtn == m_xBtnRemoveBitmap.get() && EMPTY_FRAMELIST != m_nCurrentFrame)
+ {
+ m_FrameList.erase(m_FrameList.begin() + m_nCurrentFrame);
+
+ pObject = pPage->GetObj(m_nCurrentFrame);
+ // Through acquisition of the AnimatedGIFs, objects does not need to
+ // exist.
+ if( pObject )
+ {
+ pObject = pPage->RemoveObject(m_nCurrentFrame);
+ DBG_ASSERT(pObject, "Clone not found during deletion");
+ SdrObject::Free( pObject );
+ pPage->RecalcObjOrdNums();
+ }
+
+ if (m_nCurrentFrame >= m_FrameList.size())
+ {
+ // tdf#95298 last frame was deleted, try to use the one before it or go on empty state
+ m_nCurrentFrame = m_FrameList.empty() ? EMPTY_FRAMELIST : m_FrameList.size() - 1;
+ }
+ }
+ else // delete everything
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::YesNo,
+ SdResId(STR_ASK_DELETE_ALL_PICTURES)));
+ short nReturn = xWarn->run();
+
+ if( nReturn == RET_YES )
+ {
+ // clear frame list
+ for (size_t i = m_FrameList.size(); i > 0; )
+ {
+ --i;
+ pObject = pPage->GetObj( i );
+ if( pObject )
+ {
+ pObject = pPage->RemoveObject( i );
+ DBG_ASSERT(pObject, "Clone not found during deletion");
+ SdrObject::Free( pObject );
+ //pPage->RecalcObjOrdNums();
+ }
+ }
+ m_FrameList.clear();
+ m_nCurrentFrame = EMPTY_FRAMELIST;
+ }
+ }
+
+ // can we create an animation group
+ if (m_FrameList.empty())
+ {
+ m_xBtnCreateGroup->set_sensitive(false);
+ // if previous disabled by acquisition of AnimatedGIFs:
+ //m_xRbtBitmap->set_sensitive(true);
+ m_xRbtGroup->set_sensitive(true);
+ }
+
+ // calculate and set zoom for DisplayWin
+ Fraction aFrac(GetScale());
+ m_xCtlDisplay->SetScale(aFrac);
+
+ UpdateControl();
+}
+
+IMPL_LINK_NOARG(AnimationWindow, ClickCreateGroupHdl, weld::Button&, void)
+{
+ // Code now in CreatePresObj()
+ SfxBoolItem aItem( SID_ANIMATOR_CREATE, true );
+
+ GetBindings().GetDispatcher()->ExecuteList(SID_ANIMATOR_CREATE,
+ SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK_NOARG(AnimationWindow, ModifyBitmapHdl, weld::SpinButton&, void)
+{
+ sal_uLong nBmp = m_xNumFldBitmap->get_value();
+
+ if (nBmp > m_FrameList.size())
+ {
+ nBmp = m_FrameList.size();
+ }
+
+ m_nCurrentFrame = nBmp - 1;
+
+ UpdateControl();
+}
+
+IMPL_LINK_NOARG(AnimationWindow, ModifyTimeHdl, weld::FormattedSpinButton&, void)
+{
+ sal_uLong nPos = m_xNumFldBitmap->get_value() - 1;
+
+ ::tools::Time & rTime = m_FrameList[nPos].second;
+
+ rTime = m_xFormatter->GetTime();
+}
+
+void AnimationWindow::UpdateControl(bool const bDisableCtrls)
+{
+ // tdf#95298 check m_nCurrentFrame for EMPTY_FRAMELIST to avoid out-of-bound array access
+ if (!m_FrameList.empty() && EMPTY_FRAMELIST != m_nCurrentFrame)
+ {
+ BitmapEx & rBmp(m_FrameList[m_nCurrentFrame].first);
+
+ SdPage* pPage = pMyDoc->GetSdPage(0, PageKind::Standard);
+ SdrObject *const pObject = pPage->GetObj(m_nCurrentFrame);
+ if( pObject )
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ ::tools::Rectangle aObjRect( pObject->GetCurrentBoundRect() );
+ Size aObjSize( aObjRect.GetSize() );
+ Point aOrigin( Point( -aObjRect.Left(), -aObjRect.Top() ) );
+ MapMode aMap( pVD->GetMapMode() );
+ aMap.SetMapUnit( MapUnit::Map100thMM );
+ aMap.SetOrigin( aOrigin );
+ pVD->SetMapMode( aMap );
+ pVD->SetOutputSize( aObjSize );
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ pVD->SetBackground( Wallpaper( rStyles.GetFieldColor() ) );
+ pVD->SetDrawMode( rStyles.GetHighContrastMode()
+ ? sd::OUTPUT_DRAWMODE_CONTRAST
+ : sd::OUTPUT_DRAWMODE_COLOR );
+ pVD->Erase();
+ pObject->SingleObjectPainter( *pVD );
+ rBmp = pVD->GetBitmapEx( aObjRect.TopLeft(), aObjSize );
+ }
+
+ m_xCtlDisplay->SetBitmapEx(&rBmp);
+ }
+ else
+ {
+ m_xCtlDisplay->SetBitmapEx(nullptr);
+ }
+
+ m_xCtlDisplay->Invalidate();
+
+ m_xFiCount->set_label(OUString::number(
+ m_FrameList.size()));
+
+ if (!m_FrameList.empty() && !bMovie)
+ {
+ size_t nIndex = m_nCurrentFrame + 1;
+ m_xNumFldBitmap->set_value(nIndex);
+
+ // if there is at least 1 object in the list
+ m_xBtnFirst->set_sensitive(true);
+ m_xBtnReverse->set_sensitive(true);
+ m_xBtnPlay->set_sensitive(true);
+ m_xBtnLast->set_sensitive(true);
+ m_xNumFldBitmap->set_sensitive(true);
+ m_xTimeField->set_sensitive(true);
+ m_xLbLoopCount->set_sensitive(true);
+ m_xBtnRemoveBitmap->set_sensitive(true);
+ m_xBtnRemoveAll->set_sensitive(true);
+ }
+ else
+ {
+ // if no object is in the list
+ m_xBtnFirst->set_sensitive( false );
+ m_xBtnReverse->set_sensitive( false );
+ m_xBtnPlay->set_sensitive( false );
+ m_xBtnLast->set_sensitive( false );
+ m_xNumFldBitmap->set_sensitive( false );
+ m_xTimeField->set_sensitive( false );
+ m_xLbLoopCount->set_sensitive( false );
+ m_xBtnRemoveBitmap->set_sensitive( false );
+ m_xBtnRemoveAll->set_sensitive( false );
+ }
+
+ if( bMovie && bDisableCtrls )
+ {
+ m_xBtnGetOneObject->set_sensitive( false );
+ m_xBtnGetAllObjects->set_sensitive( false );
+ m_xRbtGroup->set_sensitive( false );
+ m_xRbtBitmap->set_sensitive( false );
+ m_xBtnCreateGroup->set_sensitive( false );
+ m_xFtAdjustment->set_sensitive( false );
+ m_xLbAdjustment->set_sensitive( false );
+ }
+ else
+ {
+ // enable 'group object' only if it is not an Animated GIF
+ if (m_FrameList.empty())
+ {
+ m_xRbtGroup->set_sensitive(true);
+ }
+
+ m_xRbtBitmap->set_sensitive(true);
+ m_xBtnCreateGroup->set_sensitive(!m_FrameList.empty());
+ m_xFtAdjustment->set_sensitive(true);
+ m_xLbAdjustment->set_sensitive(true);
+ }
+
+ ClickRbtHdl(*m_xRbtGroup);
+}
+
+void AnimationWindow::ResetAttrs()
+{
+ m_xRbtGroup->set_active(true);
+ m_xLbAdjustment->set_active( BA_CENTER );
+ // LoopCount
+ m_xLbLoopCount->set_active( m_xLbLoopCount->get_count() - 1);
+
+ UpdateControl();
+}
+
+void AnimationWindow::WaitInEffect( sal_uLong nMilliSeconds, sal_uLong nTime,
+ SfxProgress* pProgress ) const
+{
+ sal_uInt64 aEnd = ::tools::Time::GetSystemTicks() + nMilliSeconds;
+ sal_uInt64 aCurrent = ::tools::Time::GetSystemTicks();
+ while (aCurrent < aEnd)
+ {
+ aCurrent = ::tools::Time::GetSystemTicks();
+
+ if( pProgress )
+ pProgress->SetState( nTime + nMilliSeconds + aCurrent - aEnd );
+
+ Application::Reschedule();
+
+ if( !bMovie )
+ return;
+ }
+}
+
+Fraction AnimationWindow::GetScale()
+{
+ Fraction aFrac;
+ size_t const nCount = m_FrameList.size();
+ if (nCount > 0)
+ {
+ Size aBmpSize(0, 0);
+ for (size_t i = 0; i < nCount; i++)
+ {
+ BitmapEx const & rBitmap = m_FrameList[i].first;
+ Size aTempSize( rBitmap.GetBitmap().GetSizePixel() );
+ aBmpSize.setWidth( std::max( aBmpSize.Width(), aTempSize.Width() ) );
+ aBmpSize.setHeight( std::max( aBmpSize.Height(), aTempSize.Height() ) );
+ }
+
+ aBmpSize.AdjustWidth(10 );
+ aBmpSize.AdjustHeight(10 );
+
+ Size aDisplaySize(m_xCtlDisplay->GetOutputSizePixel());
+
+ aFrac = Fraction( std::min( static_cast<double>(aDisplaySize.Width()) / static_cast<double>(aBmpSize.Width()),
+ static_cast<double>(aDisplaySize.Height()) / static_cast<double>(aBmpSize.Height()) ) );
+ }
+ return aFrac;
+}
+
+void AnimationWindow::Resize()
+{
+ SfxDockingWindow::Resize();
+ Fraction aFrac(GetScale());
+ m_xCtlDisplay->SetScale(aFrac);
+}
+
+bool AnimationWindow::Close()
+{
+ if( maPlayLock.isLocked() )
+ {
+ return false;
+ }
+ else
+ {
+ SfxBoolItem aItem( SID_ANIMATION_OBJECTS, false );
+
+ GetBindings().GetDispatcher()->ExecuteList(
+ SID_ANIMATION_OBJECTS, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aItem });
+
+ SfxDockingWindow::Close();
+
+ return true;
+ }
+}
+
+void AnimationWindow::AddObj (::sd::View& rView )
+{
+ // finish text entry mode to ensure that bitmap is identical with object
+ if( rView.IsTextEdit() )
+ rView.SdrEndTextEdit();
+
+ // clone object(s) and insert the clone(s) into the list
+ const SdrMarkList& rMarkList = rView.GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+ SdPage* pPage = pMyDoc->GetSdPage(0, PageKind::Standard);
+ const size_t nCloneCount = pPage->GetObjCount();
+
+ if (nMarkCount <= 0)
+ return;
+
+ // If it is ONE animation object or one group object, which was
+ // 'individually taken', we insert the objects separately
+ bool bAnimObj = false;
+ if( nMarkCount == 1 )
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObject = pMark->GetMarkedSdrObj();
+ SdAnimationInfo* pAnimInfo = SdDrawDocument::GetAnimationInfo( pObject );
+ SdrInventor nInv = pObject->GetObjInventor();
+ SdrObjKind nId = pObject->GetObjIdentifier();
+
+ // Animated Bitmap (GIF)
+ if( nInv == SdrInventor::Default && nId == SdrObjKind::Graphic && static_cast<SdrGrafObj*>( pObject )->IsAnimated() )
+ {
+ const SdrGrafObj* pGrafObj = static_cast<SdrGrafObj*>(pObject);
+ Graphic aGraphic( pGrafObj->GetTransformedGraphic() );
+ sal_uInt16 nCount = 0;
+
+ if( aGraphic.IsAnimated() )
+ nCount = aGraphic.GetAnimation().Count();
+
+ if( nCount > 0 )
+ {
+ const Animation aAnimation( aGraphic.GetAnimation() );
+
+ for( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ const AnimationBitmap& rAnimationBitmap = aAnimation.Get( i );
+
+ // LoopCount
+ if( i == 0 )
+ {
+ sal_uInt32 nLoopCount = aAnimation.GetLoopCount();
+
+ if( !nLoopCount ) // endless
+ m_xLbLoopCount->set_active( m_xLbLoopCount->get_count() - 1);
+ else
+ m_xLbLoopCount->set_active_text(OUString::number( nLoopCount ) );
+ }
+
+ ::tools::Long nTime = rAnimationBitmap.mnWait;
+ ::tools::Time aTime( 0, 0, nTime / 100, nTime % 100 );
+ size_t nIndex = m_nCurrentFrame + 1;
+ m_FrameList.insert(
+ m_FrameList.begin() + nIndex,
+ ::std::make_pair(rAnimationBitmap.maBitmapEx, aTime));
+
+ // increment => next one inserted after this one
+ ++m_nCurrentFrame;
+ }
+ // if an animated GIF is taken, only such one can be created
+ m_xRbtBitmap->set_active(true);
+ m_xRbtGroup->set_sensitive( false );
+ bAnimObj = true;
+ }
+ }
+ else if( bAllObjects || ( pAnimInfo && pAnimInfo->mbIsMovie ) )
+ {
+ // several objects
+ SdrObjList* pObjList = static_cast<SdrObjGroup*>(pObject)->GetSubList();
+
+ for( size_t nObject = 0; nObject < pObjList->GetObjCount(); ++nObject )
+ {
+ SdrObject* pSnapShot(pObjList->GetObj(nObject));
+ BitmapEx aBitmapEx(SdrExchangeView::GetObjGraphic(*pSnapShot).GetBitmapEx());
+ size_t nIndex = m_nCurrentFrame + 1;
+ m_FrameList.insert(
+ m_FrameList.begin() + nIndex,
+ ::std::make_pair(aBitmapEx, m_xFormatter->GetTime()));
+
+ // increment => next one inserted after this one
+ ++m_nCurrentFrame;
+
+ // Clone
+ pPage->InsertObject(
+ pSnapShot->CloneSdrObject(pPage->getSdrModelFromSdrPage()),
+ m_nCurrentFrame);
+ }
+ bAnimObj = true;
+ }
+ }
+ // also one single animated object
+ if( !bAnimObj && !( bAllObjects && nMarkCount > 1 ) )
+ {
+ BitmapEx aBitmapEx(rView.GetAllMarkedGraphic().GetBitmapEx());
+
+ ::tools::Time aTime( m_xFormatter->GetTime() );
+
+ size_t nIndex = m_nCurrentFrame + 1;
+ m_FrameList.insert(
+ m_FrameList.begin() + nIndex,
+ ::std::make_pair(aBitmapEx, aTime));
+ }
+
+ // one single object
+ if( nMarkCount == 1 && !bAnimObj )
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObject = pMark->GetMarkedSdrObj();
+ SdrObject* pClone(pObject->CloneSdrObject(pPage->getSdrModelFromSdrPage()));
+ size_t nIndex = m_nCurrentFrame + 1;
+ pPage->InsertObject(pClone, nIndex);
+ }
+ // several objects: group the clones
+ else if (nMarkCount > 1)
+ {
+ // take objects separately
+ if( bAllObjects )
+ {
+ for( size_t nObject= 0; nObject < nMarkCount; ++nObject )
+ {
+ // Clone
+ SdrObject* pObject(rMarkList.GetMark(nObject)->GetMarkedSdrObj());
+ BitmapEx aBitmapEx(SdrExchangeView::GetObjGraphic(*pObject).GetBitmapEx());
+ size_t nIndex = m_nCurrentFrame + 1;
+ m_FrameList.insert(
+ m_FrameList.begin() + nIndex,
+ ::std::make_pair(aBitmapEx, m_xFormatter->GetTime()));
+
+ // increment => next one inserted after this one
+ ++m_nCurrentFrame;
+
+ pPage->InsertObject(
+ pObject->CloneSdrObject(pPage->getSdrModelFromSdrPage()),
+ m_nCurrentFrame);
+ }
+ bAnimObj = true; // that we don't change again
+ }
+ else
+ {
+ SdrObjGroup* pCloneGroup = new SdrObjGroup(rView.getSdrModelFromSdrView());
+ SdrObjList* pObjList = pCloneGroup->GetSubList();
+
+ for (size_t nObject= 0; nObject < nMarkCount; ++nObject)
+ {
+ pObjList->InsertObject(
+ rMarkList.GetMark(nObject)->GetMarkedSdrObj()->CloneSdrObject(
+ pPage->getSdrModelFromSdrPage()));
+ }
+
+ size_t nIndex = m_nCurrentFrame + 1;
+ pPage->InsertObject(pCloneGroup, nIndex);
+ }
+ }
+
+ if( !bAnimObj )
+ {
+ ++m_nCurrentFrame;
+ }
+
+ // if there was nothing in the animator before but now is something
+ // there, we can create an animation group
+ if (nCloneCount == 0 && !m_FrameList.empty())
+ {
+ m_xBtnCreateGroup->set_sensitive(true);
+ }
+
+ // calculate and set zoom for DisplayWin
+ Fraction aFrac( GetScale() );
+ m_xCtlDisplay->SetScale(aFrac);
+
+ UpdateControl();
+}
+
+void AnimationWindow::CreateAnimObj (::sd::View& rView )
+{
+ vcl::Window* pOutWin = rView.GetFirstOutputDevice()->GetOwnerWindow(); // GetWin( 0 );
+ DBG_ASSERT( pOutWin, "Window does not exist!" );
+
+ // find window center
+ const MapMode aMap100( MapUnit::Map100thMM );
+ Size aMaxSizeLog;
+ Size aMaxSizePix;
+ Size aTemp( pOutWin->GetOutputSizePixel() );
+ const Point aWindowCenter( pOutWin->PixelToLogic( Point( aTemp.Width() >> 1, aTemp.Height() >> 1 ) ) );
+ const OutputDevice* pDefDev = Application::GetDefaultDevice();
+ const size_t nCount = m_FrameList.size();
+ BitmapAdjustment eBA = static_cast<BitmapAdjustment>(m_xLbAdjustment->get_active());
+
+ // find biggest bitmap
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ const BitmapEx& rBmpEx = m_FrameList[i].first;
+ const Graphic aGraphic( rBmpEx );
+ Size aTmpSizeLog;
+ const Size aTmpSizePix( rBmpEx.GetSizePixel() );
+
+ if ( aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
+ aTmpSizeLog = pDefDev->PixelToLogic( aGraphic.GetPrefSize(), aMap100 );
+ else
+ aTmpSizeLog = OutputDevice::LogicToLogic( aGraphic.GetPrefSize(), aGraphic.GetPrefMapMode(), aMap100 );
+
+ aMaxSizeLog.setWidth( std::max( aMaxSizeLog.Width(), aTmpSizeLog.Width() ) );
+ aMaxSizeLog.setHeight( std::max( aMaxSizeLog.Height(), aTmpSizeLog.Height() ) );
+
+ aMaxSizePix.setWidth( std::max( aMaxSizePix.Width(), aTmpSizePix.Width() ) );
+ aMaxSizePix.setHeight( std::max( aMaxSizePix.Height(), aTmpSizePix.Height() ) );
+ }
+
+ SdrPageView* pPV = rView.GetSdrPageView();
+
+ if( m_xRbtBitmap->get_active() )
+ {
+ // create bitmap group (Animated GIF)
+ Animation aAnimation;
+ Point aPt;
+
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ ::tools::Time const & rTime = m_FrameList[i].second;
+ ::tools::Long nTime = rTime.GetNanoSec();
+ nTime += rTime.GetSec() * 100;
+
+ BitmapEx const & rBitmapEx = m_FrameList[i].first;
+
+ // calculate offset for the specified direction
+ const Size aBitmapSize( rBitmapEx.GetSizePixel() );
+
+ switch( eBA )
+ {
+ case BA_LEFT_UP:
+ break;
+
+ case BA_LEFT:
+ aPt.setY( (aMaxSizePix.Height() - aBitmapSize.Height()) >> 1 );
+ break;
+
+ case BA_LEFT_DOWN:
+ aPt.setY( aMaxSizePix.Height() - aBitmapSize.Height() );
+ break;
+
+ case BA_UP:
+ aPt.setX( (aMaxSizePix.Width() - aBitmapSize.Width()) >> 1 );
+ break;
+
+ case BA_CENTER:
+ aPt.setX( (aMaxSizePix.Width() - aBitmapSize.Width()) >> 1 );
+ aPt.setY( (aMaxSizePix.Height() - aBitmapSize.Height()) >> 1 );
+ break;
+
+ case BA_DOWN:
+ aPt.setX( (aMaxSizePix.Width() - aBitmapSize.Width()) >> 1 );
+ aPt.setY( aMaxSizePix.Height() - aBitmapSize.Height() );
+ break;
+
+ case BA_RIGHT_UP:
+ aPt.setX( aMaxSizePix.Width() - aBitmapSize.Width() );
+ break;
+
+ case BA_RIGHT:
+ aPt.setX( aMaxSizePix.Width() - aBitmapSize.Width() );
+ aPt.setY( (aMaxSizePix.Height() - aBitmapSize.Height()) >> 1 );
+ break;
+
+ case BA_RIGHT_DOWN:
+ aPt.setX( aMaxSizePix.Width() - aBitmapSize.Width() );
+ aPt.setY( aMaxSizePix.Height() - aBitmapSize.Height() );
+ break;
+
+ }
+
+ // find LoopCount (number of passes)
+ AnimationBitmap aAnimationBitmap;
+ sal_uInt32 nLoopCount = 0;
+ sal_Int32 nPos = m_xLbLoopCount->get_active();
+
+ if( nPos != -1 && nPos != m_xLbLoopCount->get_count() - 1 ) // endless
+ nLoopCount = m_xLbLoopCount->get_active_text().toUInt32();
+
+ aAnimationBitmap.maBitmapEx = rBitmapEx;
+ aAnimationBitmap.maPositionPixel = aPt;
+ aAnimationBitmap.maSizePixel = aBitmapSize;
+ aAnimationBitmap.mnWait = nTime;
+ aAnimationBitmap.meDisposal = Disposal::Back;
+ aAnimationBitmap.mbUserInput = false;
+
+ aAnimation.Insert( aAnimationBitmap );
+ aAnimation.SetDisplaySizePixel( aMaxSizePix );
+ aAnimation.SetLoopCount( nLoopCount );
+ }
+
+ SdrGrafObj* pGrafObj = new SdrGrafObj(
+ rView.getSdrModelFromSdrView(),
+ Graphic(aAnimation));
+ const Point aOrg( aWindowCenter.X() - ( aMaxSizeLog.Width() >> 1 ), aWindowCenter.Y() - ( aMaxSizeLog.Height() >> 1 ) );
+
+ pGrafObj->SetLogicRect( ::tools::Rectangle( aOrg, aMaxSizeLog ) );
+ rView.InsertObjectAtView( pGrafObj, *pPV, SdrInsertFlags::SETDEFLAYER);
+ }
+ else
+ {
+ // calculate offset for the specified direction
+ Size aOffset;
+ SdrObject * pClone = nullptr;
+ SdPage* pPage = pMyDoc->GetSdPage(0, PageKind::Standard);
+
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ pClone = pPage->GetObj(i);
+ ::tools::Rectangle aRect( pClone->GetSnapRect() );
+
+ switch( eBA )
+ {
+ case BA_LEFT_UP:
+ break;
+
+ case BA_LEFT:
+ aOffset.setHeight( (aMaxSizeLog.Height() - aRect.GetHeight()) / 2 );
+ break;
+
+ case BA_LEFT_DOWN:
+ aOffset.setHeight( aMaxSizeLog.Height() - aRect.GetHeight() );
+ break;
+
+ case BA_UP:
+ aOffset.setWidth( (aMaxSizeLog.Width() - aRect.GetWidth()) / 2 );
+ break;
+
+ case BA_CENTER:
+ aOffset.setWidth( (aMaxSizeLog.Width() - aRect.GetWidth()) / 2 );
+ aOffset.setHeight( (aMaxSizeLog.Height() - aRect.GetHeight()) / 2 );
+ break;
+
+ case BA_DOWN:
+ aOffset.setWidth( (aMaxSizeLog.Width() - aRect.GetWidth()) / 2 );
+ aOffset.setHeight( aMaxSizeLog.Height() - aRect.GetHeight() );
+ break;
+
+ case BA_RIGHT_UP:
+ aOffset.setWidth( aMaxSizeLog.Width() - aRect.GetWidth() );
+ break;
+
+ case BA_RIGHT:
+ aOffset.setWidth( aMaxSizeLog.Width() - aRect.GetWidth() );
+ aOffset.setHeight( (aMaxSizeLog.Height() - aRect.GetHeight()) / 2 );
+ break;
+
+ case BA_RIGHT_DOWN:
+ aOffset.setWidth( aMaxSizeLog.Width() - aRect.GetWidth() );
+ aOffset.setHeight( aMaxSizeLog.Height() - aRect.GetHeight() );
+ break;
+
+ }
+ // Unfortunately, SetSnapRect is not implemented for ellipses !!!
+ Point aMovePt( aWindowCenter + Point( aOffset.Width(), aOffset.Height() ) - aRect.TopLeft() );
+ Size aMoveSize( aMovePt.X(), aMovePt.Y() );
+ pClone->NbcMove( aMoveSize );
+ }
+
+ // #i42894# Caution(!) variable pPage looks right, but it is a page from the local
+ // document the dialog is using (!), so get the target page from the target view
+ SdPage* pTargetSdPage = dynamic_cast< SdPage* >(rView.GetSdrPageView() ? rView.GetSdrPageView()->GetPage() : nullptr);
+
+ if(pTargetSdPage)
+ {
+ // create animation group
+ SdrObjGroup* pGroup = new SdrObjGroup(rView.getSdrModelFromSdrView());
+ SdrObjList* pObjList = pGroup->GetSubList();
+
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ // the clone remains in the animation; we insert a clone of the
+ // clone into the group
+ pClone = pPage->GetObj(i);
+ SdrObject* pCloneOfClone(pClone->CloneSdrObject(pTargetSdPage->getSdrModelFromSdrPage()));
+ //SdrObject* pCloneOfClone = pPage->GetObj(i)->Clone();
+ pObjList->InsertObject(pCloneOfClone);
+ }
+
+ // until now the top left corner of the group is in the window center;
+ // correct the position by half of the size of the group
+ aTemp = aMaxSizeLog;
+ aTemp.setHeight( - aTemp.Height() / 2 );
+ aTemp.setWidth( - aTemp.Width() / 2 );
+ pGroup->NbcMove(aTemp);
+
+ // #i42894# create needed SMIL stuff and move child objects to page directly (see
+ // comments at EffectMigration::CreateAnimatedGroup why this has to be done).
+ EffectMigration::CreateAnimatedGroup(*pGroup, *pTargetSdPage);
+
+ // #i42894# if that worked, delete the group again
+ if(!pGroup->GetSubList()->GetObjCount())
+ {
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pGroup);
+ SdrObject::Free(pTemp);
+ }
+ }
+ }
+
+ ClickFirstHdl(*m_xBtnFirst);
+}
+
+void AnimationWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ SfxDockingWindow::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ UpdateControl();
+ }
+}
+
+/**
+ * ControllerItem for Animator
+ */
+AnimationControllerItem::AnimationControllerItem(
+ sal_uInt16 _nId,
+ AnimationWindow* pAnimWin,
+ SfxBindings* _pBindings)
+ : SfxControllerItem( _nId, *_pBindings ),
+ pAnimationWin( pAnimWin )
+{
+}
+
+void AnimationControllerItem::StateChangedAtToolBoxControl( sal_uInt16 nSId,
+ SfxItemState eState, const SfxPoolItem* pItem )
+{
+ if( eState >= SfxItemState::DEFAULT && nSId == SID_ANIMATOR_STATE )
+ {
+ const SfxUInt16Item* pStateItem = dynamic_cast< const SfxUInt16Item*>( pItem );
+ assert(pStateItem); //SfxUInt16Item expected
+ if (pStateItem)
+ {
+ sal_uInt16 nState = pStateItem->GetValue();
+ pAnimationWin->m_xBtnGetOneObject->set_sensitive( nState & 1 );
+ pAnimationWin->m_xBtnGetAllObjects->set_sensitive( nState & 2 );
+ }
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/assclass.cxx b/sd/source/ui/dlg/assclass.cxx
new file mode 100644
index 000000000..4d48a327f
--- /dev/null
+++ b/sd/source/ui/dlg/assclass.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/debug.hxx>
+#include <vcl/weld.hxx>
+
+#include <assclass.hxx>
+
+Assistent::Assistent(int nNoOfPages)
+ : mnPages(nNoOfPages), mnCurrentPage(1)
+{
+ if(mnPages > MAX_PAGES)
+ mnPages = MAX_PAGES;
+
+ mpPageStatus.reset(new bool[mnPages]);
+
+ for(int i=0; i < mnPages; ++i)
+ mpPageStatus[i] = true;
+}
+
+bool Assistent::InsertControl(int nDestPage, weld::Widget* pUsedControl)
+{
+ DBG_ASSERT( (nDestPage > 0) && (nDestPage <= mnPages), "Page not available!");
+
+ if((nDestPage>0)&&(nDestPage<=mnPages))
+ {
+ maPages[nDestPage-1].emplace_back(pUsedControl);
+ pUsedControl->hide();
+ pUsedControl->set_sensitive(false);
+ return true;
+ }
+
+ return false;
+}
+
+void Assistent::NextPage()
+{
+ if(mnCurrentPage<mnPages)
+ {
+ int nPage = mnCurrentPage+1;
+ while(nPage <= mnPages && !mpPageStatus[nPage-1])
+ nPage++;
+
+ if(nPage <= mnPages)
+ GotoPage(nPage);
+ }
+}
+
+void Assistent::PreviousPage()
+{
+ if(mnCurrentPage>1)
+ {
+ int nPage = mnCurrentPage-1;
+ while(nPage >= 0 && !mpPageStatus[nPage-1])
+ nPage--;
+
+ if(nPage >= 0)
+ GotoPage(nPage);
+ }
+}
+
+bool Assistent::GotoPage(const int nPageToGo)
+{
+ DBG_ASSERT( (nPageToGo > 0) && (nPageToGo <= mnPages), "Page not available!");
+
+ if((nPageToGo>0)&&(nPageToGo<=mnPages)&&mpPageStatus[nPageToGo-1])
+ {
+ int nIndex=mnCurrentPage-1;
+
+ for(auto& rxPage : maPages[nIndex])
+ {
+ rxPage->set_sensitive(false);
+ rxPage->hide();
+ }
+
+ mnCurrentPage=nPageToGo;
+ nIndex=mnCurrentPage-1;
+
+ for(auto& rxPage : maPages[nIndex])
+ {
+ rxPage->set_sensitive(true);
+ rxPage->show();
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Assistent::IsLastPage() const
+{
+ if(mnCurrentPage == mnPages)
+ return true;
+
+ int nPage = mnCurrentPage+1;
+ while(nPage <= mnPages && !mpPageStatus[nPage-1])
+ nPage++;
+
+ return nPage > mnPages;
+}
+
+bool Assistent::IsFirstPage() const
+{
+ if(mnCurrentPage == 1)
+ return true;
+
+ int nPage = mnCurrentPage-1;
+ while(nPage > 0 && !mpPageStatus[nPage-1])
+ nPage--;
+
+ return nPage == 0;
+}
+
+bool Assistent::IsEnabled( int nPage ) const
+{
+ DBG_ASSERT( (nPage>0) && (nPage <= mnPages), "Page not available!" );
+
+ return (nPage>0) && (nPage <= mnPages && mpPageStatus[nPage-1]);
+}
+
+void Assistent::EnablePage( int nPage )
+{
+ DBG_ASSERT( (nPage>0) && (nPage <= mnPages), "Page not available!" );
+
+ if((nPage>0) && (nPage < mnPages && !mpPageStatus[nPage-1]))
+ {
+ mpPageStatus[nPage-1] = true;
+ }
+}
+
+void Assistent::DisablePage( int nPage )
+{
+ DBG_ASSERT( (nPage>0) && (nPage <= mnPages), "Page not available!" );
+
+ if((nPage>0) && (nPage <= mnPages && mpPageStatus[nPage-1]))
+ {
+ mpPageStatus[nPage-1] = false;
+ if(mnCurrentPage == nPage)
+ GotoPage(1);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/brkdlg.cxx b/sd/source/ui/dlg/brkdlg.cxx
new file mode 100644
index 000000000..bc1d0f5cf
--- /dev/null
+++ b/sd/source/ui/dlg/brkdlg.cxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <BreakDlg.hxx>
+#include <sfx2/progress.hxx>
+
+#include <svx/svdetc.hxx>
+#include <vcl/scheduler.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <sdresid.hxx>
+#include <drawview.hxx>
+#include <strings.hrc>
+#include <DrawDocShell.hxx>
+
+namespace sd {
+
+/**
+ * dialog to split metafiles
+ */
+
+BreakDlg::BreakDlg(weld::Window* pWindow, DrawView* pDrView, DrawDocShell* pShell,
+ sal_uLong nSumActionCount, sal_uLong nObjCount)
+ : SfxDialogController(pWindow, "modules/sdraw/ui/breakdialog.ui", "BreakDialog")
+ , m_xFiObjInfo(m_xBuilder->weld_label("metafiles"))
+ , m_xFiActInfo(m_xBuilder->weld_label("metaobjects"))
+ , m_xFiInsInfo(m_xBuilder->weld_label("drawingobjects"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_pDrView(pDrView)
+ , m_bCancel(false)
+ , m_aUpdateIdle( "sd::BreakDlg m_aUpdateIdle" )
+{
+ m_aUpdateIdle.SetPriority( TaskPriority::REPAINT );
+ m_aUpdateIdle.SetInvokeHandler( LINK( this, BreakDlg, InitialUpdate ) );
+
+ m_xBtnCancel->connect_clicked(LINK(this, BreakDlg, CancelButtonHdl));
+
+ m_xProgress.reset(new SfxProgress(pShell, SdResId(STR_BREAK_METAFILE), nSumActionCount*3));
+
+ m_xProgrInfo.reset(new SvdProgressInfo(LINK(this, BreakDlg, UpDate)));
+ // every action is edited 3 times in DoImport()
+ m_xProgrInfo->Init( nObjCount );
+}
+
+// Control-Handler for cancel button
+IMPL_LINK_NOARG(BreakDlg, CancelButtonHdl, weld::Button&, void)
+{
+ m_bCancel = true;
+ m_xBtnCancel->set_sensitive(false);
+}
+
+/**
+ * The working function has to call the UpDate method periodically.
+ * With the first call, the overall number of actions is provided.
+ * Every following call should contain the finished actions since the
+ * last call of UpDate.
+ */
+IMPL_LINK( BreakDlg, UpDate, void*, nInit, bool )
+{
+ if (!m_xProgrInfo)
+ return true;
+
+ // update status bar or show an error message?
+ if(nInit == reinterpret_cast<void*>(1))
+ {
+ std::unique_ptr<weld::MessageDialog> xErrBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SdResId(STR_BREAK_FAIL)));
+ xErrBox->run();
+ }
+ else
+ {
+ if (m_xProgress)
+ m_xProgress->SetState(m_xProgrInfo->GetSumCurAction());
+ }
+
+ // which object is shown at the moment?
+ OUString info = OUString::number(m_xProgrInfo->GetCurObj())
+ + "/"
+ + OUString::number(m_xProgrInfo->GetObjCount());
+ m_xFiObjInfo->set_label(info);
+
+ // how many actions are started?
+ if (m_xProgrInfo->GetActionCount() == 0)
+ {
+ m_xFiActInfo->set_label( OUString() );
+ }
+ else
+ {
+ info = OUString::number(m_xProgrInfo->GetCurAction())
+ + "/"
+ + OUString::number(m_xProgrInfo->GetActionCount());
+ m_xFiActInfo->set_label(info);
+ }
+
+ // and inserted????
+ if (m_xProgrInfo->GetInsertCount() == 0)
+ {
+ m_xFiInsInfo->set_label( OUString() );
+ }
+ else
+ {
+ info = OUString::number(m_xProgrInfo->GetCurInsert())
+ + "/"
+ + OUString::number(m_xProgrInfo->GetInsertCount());
+ m_xFiInsInfo->set_label(info);
+ }
+
+ // make sure dialog gets painted, it is intended to
+ // show the progress to the user. Also necessary to
+ // provide a clickable cancel button
+ Scheduler::ProcessEventsToIdle();
+
+ // return okay-value (-> !cancel)
+ return !m_bCancel;
+}
+
+/**
+ * open a modal dialog and start a timer which calls the working function after
+ * the opening of the dialog
+ */
+short BreakDlg::run()
+{
+ m_aUpdateIdle.Start();
+ return SfxDialogController::run();
+}
+
+/**
+ * link-method which starts the working function
+ */
+IMPL_LINK_NOARG(BreakDlg, InitialUpdate, Timer *, void)
+{
+ m_pDrView->DoImportMarkedMtf(m_xProgrInfo.get());
+ m_xDialog->response(RET_OK);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/copydlg.cxx b/sd/source/ui/dlg/copydlg.cxx
new file mode 100644
index 000000000..1fa8c2dab
--- /dev/null
+++ b/sd/source/ui/dlg/copydlg.cxx
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <copydlg.hxx>
+#include <svx/colorbox.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/sdangitm.hxx>
+#include <sfx2/module.hxx>
+#include <svx/xcolit.hxx>
+#include <svl/intitem.hxx>
+
+#include <unotools/viewoptions.hxx>
+#include <svtools/unitconv.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <sdattr.hrc>
+#include <View.hxx>
+#include <drawdoc.hxx>
+
+
+namespace sd {
+
+constexpr char TOKEN = ';';
+
+CopyDlg::CopyDlg(weld::Window* pWindow, const SfxItemSet& rInAttrs, ::sd::View* pInView)
+ : SfxDialogController(pWindow, "modules/sdraw/ui/copydlg.ui", "DuplicateDialog")
+ , mrOutAttrs(rInAttrs)
+ , maUIScale(pInView->GetDoc().GetUIScale())
+ , mpView(pInView)
+ , m_xNumFldCopies(m_xBuilder->weld_spin_button("copies"))
+ , m_xBtnSetViewData(m_xBuilder->weld_button("viewdata"))
+ , m_xMtrFldMoveX(m_xBuilder->weld_metric_spin_button("x", FieldUnit::CM))
+ , m_xMtrFldMoveY(m_xBuilder->weld_metric_spin_button("y", FieldUnit::CM))
+ , m_xMtrFldAngle(m_xBuilder->weld_metric_spin_button("angle", FieldUnit::DEGREE))
+ , m_xMtrFldWidth(m_xBuilder->weld_metric_spin_button("width", FieldUnit::CM))
+ , m_xMtrFldHeight(m_xBuilder->weld_metric_spin_button("height", FieldUnit::CM))
+ , m_xFtEndColor(m_xBuilder->weld_label("endlabel"))
+ , m_xBtnSetDefault(m_xBuilder->weld_button("default"))
+ , m_xLbStartColor(new ColorListBox(m_xBuilder->weld_menu_button("start"), [this]{ return m_xDialog.get(); } ))
+ , m_xLbEndColor(new ColorListBox(m_xBuilder->weld_menu_button("end"), [this]{ return m_xDialog.get(); } ))
+{
+ m_xLbStartColor->SetSelectHdl( LINK( this, CopyDlg, SelectColorHdl ) );
+ m_xBtnSetViewData->connect_clicked( LINK( this, CopyDlg, SetViewData ) );
+ m_xBtnSetDefault->connect_clicked( LINK( this, CopyDlg, SetDefault ) );
+
+ FieldUnit eFUnit( SfxModule::GetCurrentFieldUnit() );
+
+ SetFieldUnit( *m_xMtrFldMoveX, eFUnit, true );
+ SetFieldUnit( *m_xMtrFldMoveY, eFUnit, true );
+ SetFieldUnit( *m_xMtrFldWidth, eFUnit, true );
+ SetFieldUnit( *m_xMtrFldHeight, eFUnit, true );
+
+ Reset();
+}
+
+CopyDlg::~CopyDlg()
+{
+ SvtViewOptions aDlgOpt(EViewType::Dialog, OStringToOUString(m_xDialog->get_help_id(), RTL_TEXTENCODING_UTF8));
+ OUString sStr =
+ OUString::number(m_xNumFldCopies->get_value()) + OUStringChar(TOKEN) +
+ OUString::number(m_xMtrFldMoveX->get_value(FieldUnit::NONE)) + OUStringChar(TOKEN) +
+ OUString::number(m_xMtrFldMoveY->get_value(FieldUnit::NONE)) + OUStringChar(TOKEN) +
+ OUString::number(m_xMtrFldAngle->get_value(FieldUnit::NONE)) + OUStringChar(TOKEN) +
+ OUString::number(m_xMtrFldWidth->get_value(FieldUnit::NONE)) + OUStringChar(TOKEN) +
+ OUString::number(m_xMtrFldHeight->get_value(FieldUnit::NONE)) + OUStringChar(TOKEN) +
+ OUString::number(static_cast<sal_uInt32>(m_xLbStartColor->GetSelectEntryColor())) + OUStringChar(TOKEN) +
+ OUString::number(static_cast<sal_uInt32>(m_xLbEndColor->GetSelectEntryColor()));
+ aDlgOpt.SetUserItem("UserItem", css::uno::Any(sStr));
+}
+
+/**
+ * reads provided item set or evaluate ini string
+ */
+void CopyDlg::Reset()
+{
+ // Set Min/Max values
+ ::tools::Rectangle aRect = mpView->GetAllMarkedRect();
+ Size aPageSize = mpView->GetSdrPageView()->GetPage()->GetSize();
+
+ // tdf#125011 draw/impress sizes are in mm_100th already, "normalize" to
+ // decimal shift by number of decimal places the widgets are using (2) then
+ // scale by the ui scaling factor
+ auto nPageWidth = tools::Long(m_xMtrFldMoveX->normalize(aPageSize.Width()) / maUIScale);
+ auto nPageHeight = tools::Long(m_xMtrFldMoveX->normalize(aPageSize.Height()) / maUIScale);
+ auto nRectWidth = tools::Long(m_xMtrFldMoveX->normalize(aRect.GetWidth()) / maUIScale);
+ auto nRectHeight = tools::Long(m_xMtrFldMoveX->normalize(aRect.GetHeight()) / maUIScale);
+
+ m_xMtrFldMoveX->set_range(-nPageWidth, nPageWidth, FieldUnit::MM_100TH);
+ m_xMtrFldMoveY->set_range(-nPageHeight, nPageHeight, FieldUnit::MM_100TH);
+ m_xMtrFldWidth->set_range(-nRectWidth, nPageWidth, FieldUnit::MM_100TH);
+ m_xMtrFldHeight->set_range(-nRectHeight, nPageHeight, FieldUnit::MM_100TH);
+
+ OUString aStr;
+ SvtViewOptions aDlgOpt(EViewType::Dialog, OStringToOUString(m_xDialog->get_help_id(), RTL_TEXTENCODING_UTF8));
+ if (aDlgOpt.Exists())
+ {
+ css::uno::Any aUserItem = aDlgOpt.GetUserItem("UserItem");
+ aUserItem >>= aStr;
+ }
+
+ if (aStr.isEmpty())
+ {
+ if( const SfxUInt16Item* pPoolItem = mrOutAttrs.GetItemIfSet( ATTR_COPY_NUMBER ) )
+ m_xNumFldCopies->set_value(pPoolItem->GetValue());
+ else
+ m_xNumFldCopies->set_value(1);
+
+ tools::Long nMoveX = 500;
+ if( const SfxInt32Item* pPoolItem = mrOutAttrs.GetItemIfSet( ATTR_COPY_MOVE_X ) )
+ nMoveX = pPoolItem->GetValue();
+ SetMetricValue( *m_xMtrFldMoveX, tools::Long(nMoveX / maUIScale), MapUnit::Map100thMM);
+
+ tools::Long nMoveY = 500;
+ if( const SfxInt32Item* pPoolItem = mrOutAttrs.GetItemIfSet( ATTR_COPY_MOVE_Y ) )
+ nMoveY = pPoolItem->GetValue();
+ SetMetricValue( *m_xMtrFldMoveY, tools::Long(nMoveY / maUIScale), MapUnit::Map100thMM);
+
+ if( const SdrAngleItem* pPoolItem = mrOutAttrs.GetItemIfSet( ATTR_COPY_ANGLE ) )
+ m_xMtrFldAngle->set_value( pPoolItem->GetValue().get(), FieldUnit::NONE);
+ else
+ m_xMtrFldAngle->set_value(0, FieldUnit::NONE);
+
+ tools::Long nWidth = 0;
+ if( const SfxInt32Item* pPoolItem = mrOutAttrs.GetItemIfSet( ATTR_COPY_WIDTH ) )
+ nWidth = pPoolItem->GetValue();
+ SetMetricValue( *m_xMtrFldWidth, tools::Long(nWidth / maUIScale), MapUnit::Map100thMM);
+
+ tools::Long nHeight = 0;
+ if( const SfxInt32Item* pPoolItem = mrOutAttrs.GetItemIfSet( ATTR_COPY_HEIGHT ) )
+ nHeight = pPoolItem->GetValue();
+ SetMetricValue( *m_xMtrFldHeight, tools::Long(nHeight / maUIScale), MapUnit::Map100thMM);
+
+ if( const XColorItem* pPoolItem = mrOutAttrs.GetItemIfSet( ATTR_COPY_START_COLOR ) )
+ {
+ Color aColor = pPoolItem->GetColorValue();
+ m_xLbStartColor->SelectEntry( aColor );
+ m_xLbEndColor->SelectEntry( aColor );
+ }
+ else
+ {
+ m_xLbStartColor->SetNoSelection();
+ m_xLbEndColor->SetNoSelection();
+ m_xLbEndColor->set_sensitive(false);
+ m_xFtEndColor->set_sensitive(false);
+ }
+ }
+ else
+ {
+ sal_Int32 nIdx {0};
+ m_xNumFldCopies->set_value(o3tl::toInt64(o3tl::getToken(aStr, 0, TOKEN, nIdx)));
+ m_xMtrFldMoveX->set_value(o3tl::toInt64(o3tl::getToken(aStr, 0, TOKEN, nIdx)), FieldUnit::NONE);
+ m_xMtrFldMoveY->set_value(o3tl::toInt64(o3tl::getToken(aStr, 0, TOKEN, nIdx)), FieldUnit::NONE);
+ m_xMtrFldAngle->set_value(o3tl::toInt64(o3tl::getToken(aStr, 0, TOKEN, nIdx)), FieldUnit::NONE);
+ m_xMtrFldWidth->set_value(o3tl::toInt64(o3tl::getToken(aStr, 0, TOKEN, nIdx)), FieldUnit::NONE);
+ m_xMtrFldHeight->set_value(o3tl::toInt64(o3tl::getToken(aStr, 0, TOKEN, nIdx)), FieldUnit::NONE);
+ m_xLbStartColor->SelectEntry( Color( ColorTransparency, o3tl::toUInt32(o3tl::getToken(aStr, 0, TOKEN, nIdx)) ) );
+ m_xLbEndColor->SelectEntry( Color( ColorTransparency, o3tl::toUInt32(o3tl::getToken(aStr, 0, TOKEN, nIdx)) ) );
+ }
+
+}
+
+/**
+ * fills provided item set with dialog box attributes
+ */
+void CopyDlg::GetAttr( SfxItemSet& rOutAttrs )
+{
+ tools::Long nMoveX = tools::Long( GetCoreValue( *m_xMtrFldMoveX, MapUnit::Map100thMM) * maUIScale);
+ tools::Long nMoveY = tools::Long( GetCoreValue( *m_xMtrFldMoveY, MapUnit::Map100thMM) * maUIScale);
+ tools::Long nHeight = tools::Long( GetCoreValue( *m_xMtrFldHeight, MapUnit::Map100thMM) * maUIScale);
+ tools::Long nWidth = tools::Long( GetCoreValue( *m_xMtrFldWidth, MapUnit::Map100thMM) * maUIScale);
+
+ rOutAttrs.Put( SfxUInt16Item( ATTR_COPY_NUMBER, static_cast<sal_uInt16>(m_xNumFldCopies->get_value()) ) );
+ rOutAttrs.Put( SfxInt32Item( ATTR_COPY_MOVE_X, nMoveX ) );
+ rOutAttrs.Put( SfxInt32Item( ATTR_COPY_MOVE_Y, nMoveY ) );
+ rOutAttrs.Put( SdrAngleItem( ATTR_COPY_ANGLE, Degree100(static_cast<sal_Int32>(m_xMtrFldAngle->get_value(FieldUnit::DEGREE))) ) );
+ rOutAttrs.Put( SfxInt32Item( ATTR_COPY_WIDTH, nWidth ) );
+ rOutAttrs.Put( SfxInt32Item( ATTR_COPY_HEIGHT, nHeight ) );
+
+ NamedColor aColor = m_xLbStartColor->GetSelectedEntry();
+ rOutAttrs.Put(XColorItem(ATTR_COPY_START_COLOR, aColor.second, aColor.first));
+ aColor = m_xLbEndColor->GetSelectedEntry();
+ rOutAttrs.Put(XColorItem(ATTR_COPY_END_COLOR, aColor.second, aColor.first));
+}
+
+/**
+ * enables and selects end color LB
+ */
+IMPL_LINK_NOARG(CopyDlg, SelectColorHdl, ColorListBox&, void)
+{
+ const Color aColor = m_xLbStartColor->GetSelectEntryColor();
+
+ if (!m_xLbEndColor->get_sensitive())
+ {
+ m_xLbEndColor->SelectEntry(aColor);
+ m_xLbEndColor->set_sensitive(true);
+ m_xFtEndColor->set_sensitive(true);
+ }
+}
+
+/**
+ * sets values of selection
+ */
+IMPL_LINK_NOARG(CopyDlg, SetViewData, weld::Button&, void)
+{
+ ::tools::Rectangle aRect = mpView->GetAllMarkedRect();
+
+ SetMetricValue( *m_xMtrFldMoveX, tools::Long( aRect.GetWidth() /
+ maUIScale ), MapUnit::Map100thMM);
+ SetMetricValue( *m_xMtrFldMoveY, tools::Long( aRect.GetHeight() /
+ maUIScale ), MapUnit::Map100thMM);
+
+ // sets color attribute
+ if( const XColorItem* pPoolItem = mrOutAttrs.GetItemIfSet( ATTR_COPY_START_COLOR ) )
+ {
+ Color aColor = pPoolItem->GetColorValue();
+ m_xLbStartColor->SelectEntry( aColor );
+ }
+}
+
+/**
+ * resets values to default
+ */
+IMPL_LINK_NOARG(CopyDlg, SetDefault, weld::Button&, void)
+{
+ m_xNumFldCopies->set_value(1);
+
+ tools::Long nValue = 500;
+ SetMetricValue( *m_xMtrFldMoveX, tools::Long(nValue / maUIScale), MapUnit::Map100thMM);
+ SetMetricValue( *m_xMtrFldMoveY, tools::Long(nValue / maUIScale), MapUnit::Map100thMM);
+
+ nValue = 0;
+ m_xMtrFldAngle->set_value(nValue, FieldUnit::DEGREE);
+ SetMetricValue( *m_xMtrFldWidth, tools::Long(nValue / maUIScale), MapUnit::Map100thMM);
+ SetMetricValue( *m_xMtrFldHeight, tools::Long(nValue / maUIScale), MapUnit::Map100thMM);
+
+ // set color attribute
+ if( const XColorItem* pPoolItem = mrOutAttrs.GetItemIfSet( ATTR_COPY_START_COLOR ) )
+ {
+ Color aColor = pPoolItem->GetColorValue();
+ m_xLbStartColor->SelectEntry( aColor );
+ m_xLbEndColor->SelectEntry( aColor );
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/custsdlg.cxx b/sd/source/ui/dlg/custsdlg.cxx
new file mode 100644
index 000000000..bc421d7e4
--- /dev/null
+++ b/sd/source/ui/dlg/custsdlg.cxx
@@ -0,0 +1,478 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <custsdlg.hxx>
+
+#include <strings.hrc>
+#include <sdresid.hxx>
+
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <cusshow.hxx>
+#include <customshowlist.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/charclass.hxx>
+#include <tools/debug.hxx>
+
+// SdCustomShowDlg
+SdCustomShowDlg::SdCustomShowDlg(weld::Window* pWindow, SdDrawDocument& rDrawDoc)
+ : GenericDialogController(pWindow, "modules/simpress/ui/customslideshows.ui", "CustomSlideShows")
+ , rDoc(rDrawDoc)
+ , pCustomShowList(nullptr)
+ , m_xLbCustomShows(m_xBuilder->weld_tree_view("customshowlist"))
+ , m_xBtnNew(m_xBuilder->weld_button("new"))
+ , m_xBtnEdit(m_xBuilder->weld_button("edit"))
+ , m_xBtnRemove(m_xBuilder->weld_button("delete"))
+ , m_xBtnCopy(m_xBuilder->weld_button("copy"))
+ , m_xBtnHelp(m_xBuilder->weld_button("help"))
+ , m_xBtnStartShow(m_xBuilder->weld_button("startshow"))
+ , m_xBtnOK(m_xBuilder->weld_button("ok"))
+{
+ m_xLbCustomShows->set_size_request(m_xLbCustomShows->get_approximate_digit_width() * 32,
+ m_xLbCustomShows->get_height_rows(8));
+
+ Link<weld::Button&,void> aLink( LINK( this, SdCustomShowDlg, ClickButtonHdl ) );
+ m_xBtnNew->connect_clicked( aLink );
+ m_xBtnEdit->connect_clicked( aLink );
+ m_xBtnRemove->connect_clicked( aLink );
+ m_xBtnCopy->connect_clicked( aLink );
+ m_xLbCustomShows->connect_changed( LINK( this, SdCustomShowDlg, SelectListBoxHdl ) );
+
+ m_xBtnStartShow->connect_clicked( LINK( this, SdCustomShowDlg, StartShowHdl ) ); // for test
+
+ // get CustomShow list of docs
+ pCustomShowList = rDoc.GetCustomShowList();
+ if( pCustomShowList )
+ {
+ tools::Long nPosToSelect = pCustomShowList->GetCurPos();
+ // fill ListBox with CustomShows
+ for( SdCustomShow* pCustomShow = pCustomShowList->First();
+ pCustomShow != nullptr;
+ pCustomShow = pCustomShowList->Next() )
+ {
+ m_xLbCustomShows->append_text(pCustomShow->GetName());
+ }
+ m_xLbCustomShows->select(nPosToSelect);
+ pCustomShowList->Seek( nPosToSelect );
+ }
+
+ CheckState();
+}
+
+SdCustomShowDlg::~SdCustomShowDlg()
+{
+}
+
+void SdCustomShowDlg::CheckState()
+{
+ int nPos = m_xLbCustomShows->get_selected_index();
+
+ bool bEnable = nPos != -1;
+ m_xBtnEdit->set_sensitive( bEnable );
+ m_xBtnRemove->set_sensitive( bEnable );
+ m_xBtnCopy->set_sensitive( bEnable );
+ m_xBtnStartShow->set_sensitive(bEnable);
+
+ if (bEnable && pCustomShowList)
+ pCustomShowList->Seek( nPos );
+}
+
+IMPL_LINK( SdCustomShowDlg, ClickButtonHdl, weld::Button&, r, void )
+{
+ SelectHdl(&r);
+}
+
+IMPL_LINK( SdCustomShowDlg, SelectListBoxHdl, weld::TreeView&, rListBox, void )
+{
+ SelectHdl(&rListBox);
+}
+
+void SdCustomShowDlg::SelectHdl(void const *p)
+{
+ // new CustomShow
+ if (p == m_xBtnNew.get())
+ {
+ std::unique_ptr<SdCustomShow> pCustomShow;
+ SdDefineCustomShowDlg aDlg(m_xDialog.get(), rDoc, pCustomShow);
+ if (aDlg.run() == RET_OK)
+ {
+ if( pCustomShow )
+ {
+ if( !pCustomShowList )
+ pCustomShowList = rDoc.GetCustomShowList( true );
+
+ SdCustomShow* pCustomShowTmp = pCustomShow.get();
+ pCustomShowList->push_back( std::move(pCustomShow) );
+ pCustomShowList->Last();
+ m_xLbCustomShows->append_text( pCustomShowTmp->GetName() );
+ m_xLbCustomShows->select_text( pCustomShowTmp->GetName() );
+ }
+ }
+ }
+ // edit CustomShow
+ else if( p == m_xBtnEdit.get() )
+ {
+ int nPos = m_xLbCustomShows->get_selected_index();
+ if (nPos != -1)
+ {
+ DBG_ASSERT( pCustomShowList, "pCustomShowList does not exist" );
+ std::unique_ptr<SdCustomShow>& pCustomShow = (*pCustomShowList)[ nPos ];
+ SdDefineCustomShowDlg aDlg(m_xDialog.get(), rDoc, pCustomShow);
+
+ if (aDlg.run() == RET_OK)
+ {
+ pCustomShowList->Seek(nPos);
+ m_xLbCustomShows->remove(nPos);
+ m_xLbCustomShows->insert_text(nPos, pCustomShow->GetName());
+ m_xLbCustomShows->select(nPos);
+ }
+ }
+ }
+ // delete CustomShow
+ else if( p == m_xBtnRemove.get() )
+ {
+ int nPos = m_xLbCustomShows->get_selected_index();
+ if (nPos != -1)
+ {
+ pCustomShowList->erase( pCustomShowList->begin() + nPos );
+ m_xLbCustomShows->remove(nPos);
+ m_xLbCustomShows->select(nPos == 0 ? nPos : nPos - 1);
+ }
+ }
+ // copy CustomShow
+ else if( p == m_xBtnCopy.get() )
+ {
+ int nPos = m_xLbCustomShows->get_selected_index();
+ if (nPos != -1)
+ {
+ std::unique_ptr<SdCustomShow> pShow(new SdCustomShow( *(*pCustomShowList)[nPos] ));
+ OUString aStr( pShow->GetName() );
+ OUString aStrCopy( SdResId( STR_COPY_CUSTOMSHOW ) );
+
+ sal_Int32 nStrPos = aStr.indexOf( aStrCopy );
+ sal_Int32 nNum = 1;
+ if( nStrPos < 0 )
+ {
+ aStr += " (" + aStrCopy + OUString::number( nNum ) + ")";
+ nStrPos = aStr.indexOf( aStrCopy );
+ }
+ nStrPos = nStrPos + aStrCopy.getLength();
+ // that we do not access into the nirvana (--> endless loop)
+ if( nStrPos >= aStr.getLength() )
+ {
+ aStr += " " + OUString::number( nNum );
+ }
+
+ // check name...
+ bool bDifferent = false;
+ //long nPosToSelect = pCustomShowList->GetCurPos();
+ while( !bDifferent )
+ {
+ bDifferent = true;
+ for( SdCustomShow* pCustomShow = pCustomShowList->First();
+ pCustomShow != nullptr && bDifferent;
+ pCustomShow = pCustomShowList->Next() )
+ {
+ if( aStr == pCustomShow->GetName() )
+ bDifferent = false;
+ }
+ if( !bDifferent )
+ {
+ // replace number by a number increased by 1
+
+ const CharClass* pCharClass = rDoc.GetCharClass();
+ while( pCharClass->isDigit( aStr, nStrPos ) )
+ aStr = aStr.replaceAt( nStrPos, 1, u"" );
+ aStr = aStr.subView( 0, nStrPos) + OUString::number( ++nNum ) + aStr.subView( nStrPos);
+ }
+
+ }
+ //pCustomShowList->Seek( nPosToSelect );
+ pShow->SetName( aStr );
+
+ auto pShowTmp = pShow.get();
+ pCustomShowList->push_back( std::move(pShow) );
+ pCustomShowList->Last();
+ m_xLbCustomShows->append_text(pShowTmp->GetName());
+ m_xLbCustomShows->select_text(pShowTmp->GetName());
+ }
+ }
+ else if( p == m_xLbCustomShows.get() )
+ {
+ int nPos = m_xLbCustomShows->get_selected_index();
+ if (nPos != -1)
+ pCustomShowList->Seek(nPos);
+ }
+
+ CheckState();
+}
+
+// StartShow-Hdl
+IMPL_LINK_NOARG(SdCustomShowDlg, StartShowHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_YES);
+}
+
+// CheckState
+bool SdCustomShowDlg::IsCustomShow() const
+{
+ if (!pCustomShowList->empty())
+ return true;
+ else
+ return false;
+}
+
+// SdDefineCustomShowDlg
+SdDefineCustomShowDlg::SdDefineCustomShowDlg(weld::Window* pWindow, SdDrawDocument& rDrawDoc, std::unique_ptr<SdCustomShow>& rpCS)
+ : GenericDialogController(pWindow, "modules/simpress/ui/definecustomslideshow.ui", "DefineCustomSlideShow")
+ , rDoc(rDrawDoc)
+ , rpCustomShow(rpCS)
+ , bModified(false)
+ , m_xEdtName(m_xBuilder->weld_entry("customname"))
+ , m_xLbPages(m_xBuilder->weld_tree_view("pages"))
+ , m_xBtnAdd(m_xBuilder->weld_button("add"))
+ , m_xBtnRemove(m_xBuilder->weld_button("remove"))
+ , m_xLbCustomPages(m_xBuilder->weld_tree_view("custompages"))
+ , m_xDropTargetHelper(new weld::ReorderingDropTarget(*m_xLbCustomPages))
+ , m_xBtnOK(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xBtnHelp(m_xBuilder->weld_button("help"))
+{
+ Link<weld::Button&,void> aLink = LINK( this, SdDefineCustomShowDlg, ClickButtonHdl );
+ m_xBtnAdd->connect_clicked( aLink );
+ m_xBtnRemove->connect_clicked( aLink );
+ m_xEdtName->connect_changed( LINK( this, SdDefineCustomShowDlg, ClickButtonEditHdl ) );
+ m_xLbPages->connect_changed( LINK( this, SdDefineCustomShowDlg, ClickButtonHdl4 ) ); // because of status
+ m_xLbCustomPages->connect_changed( LINK( this, SdDefineCustomShowDlg, ClickButtonHdl3 ) ); // because of status
+
+ m_xBtnOK->connect_clicked( LINK( this, SdDefineCustomShowDlg, OKHdl ) );
+
+ m_xLbPages->set_selection_mode(SelectionMode::Multiple);
+
+ // shape 'em a bit
+ m_xLbPages->set_size_request(m_xLbPages->get_approximate_digit_width() * 24, m_xLbPages->get_height_rows(10));
+ m_xLbCustomPages->set_size_request(m_xLbPages->get_approximate_digit_width() * 24, m_xLbCustomPages->get_height_rows(10));
+
+ // fill Listbox with page names of Docs
+ for( tools::Long nPage = 0;
+ nPage < rDoc.GetSdPageCount( PageKind::Standard );
+ nPage++ )
+ {
+ SdPage* pPage = rDoc.GetSdPage( static_cast<sal_uInt16>(nPage), PageKind::Standard );
+ m_xLbPages->append_text(pPage->GetName());
+ }
+ // aLbPages.SelectEntryPos( 0 );
+
+ if( rpCustomShow )
+ {
+ aOldName = rpCustomShow->GetName();
+ m_xEdtName->set_text( aOldName );
+
+ // fill ListBox with CustomShow pages
+ for( const auto& rpPage : rpCustomShow->PagesVector() )
+ {
+ m_xLbCustomPages->append(weld::toId(rpPage), rpPage->GetName(), "");
+ }
+ }
+ else
+ {
+ rpCustomShow.reset(new SdCustomShow);
+ m_xEdtName->set_text( SdResId( STR_NEW_CUSTOMSHOW ) );
+ m_xEdtName->select_region(0, -1);
+ rpCustomShow->SetName( m_xEdtName->get_text() );
+ }
+
+ m_xBtnOK->set_sensitive( false );
+ CheckState();
+}
+
+SdDefineCustomShowDlg::~SdDefineCustomShowDlg()
+{
+}
+
+// CheckState
+void SdDefineCustomShowDlg::CheckState()
+{
+ bool bPages = m_xLbPages->count_selected_rows() > 0;
+ bool bCSPages = m_xLbCustomPages->get_selected_index() != -1;
+ bool bCount = m_xLbCustomPages->n_children() > 0;
+
+ m_xBtnOK->set_sensitive( bCount );
+ m_xBtnAdd->set_sensitive( bPages );
+ m_xBtnRemove->set_sensitive( bCSPages );
+}
+
+IMPL_LINK( SdDefineCustomShowDlg, ClickButtonHdl, weld::Button&, rWidget, void )
+{
+ ClickButtonHdl2(&rWidget);
+}
+
+IMPL_LINK( SdDefineCustomShowDlg, ClickButtonHdl3, weld::TreeView&, rWidget, void )
+{
+ ClickButtonHdl2(&rWidget);
+}
+
+IMPL_LINK( SdDefineCustomShowDlg, ClickButtonHdl4, weld::TreeView&, rListBox, void )
+{
+ ClickButtonHdl2(&rListBox);
+}
+
+IMPL_LINK( SdDefineCustomShowDlg, ClickButtonEditHdl, weld::Entry&, rEdit, void )
+{
+ ClickButtonHdl2(&rEdit);
+}
+
+// ButtonHdl()
+void SdDefineCustomShowDlg::ClickButtonHdl2(void const * p)
+{
+ if( p == m_xBtnAdd.get() )
+ {
+ auto aRows = m_xLbPages->get_selected_rows();
+ if (!aRows.empty())
+ {
+ int nPosCP = m_xLbCustomPages->get_selected_index();
+ if (nPosCP != -1)
+ ++nPosCP;
+
+ for (auto i : aRows)
+ {
+ OUString aStr = m_xLbPages->get_text(i);
+ SdPage* pPage = rDoc.GetSdPage(i, PageKind::Standard);
+ OUString sId(weld::toId(pPage));
+ m_xLbCustomPages->insert(nPosCP, aStr, &sId, nullptr, nullptr);
+ m_xLbCustomPages->select(nPosCP != -1 ? nPosCP : m_xLbCustomPages->n_children() - 1);
+
+ if (nPosCP != -1)
+ ++nPosCP;
+ }
+ bModified = true;
+ }
+ }
+ else if (p == m_xBtnRemove.get())
+ {
+ int nPos = m_xLbCustomPages->get_selected_index();
+ if (nPos != -1)
+ {
+ m_xLbCustomPages->remove(nPos);
+ m_xLbCustomPages->select(nPos == 0 ? nPos : nPos - 1);
+ bModified = true;
+ }
+ }
+ else if( p == m_xEdtName.get() )
+ {
+ bModified = true;
+ }
+
+ CheckState();
+}
+
+/**
+ * Checks the page pointer of the Show since entries can be moved and copied
+ * by TreeLB.
+ */
+void SdDefineCustomShowDlg::CheckCustomShow()
+{
+ bool bDifferent = false;
+
+ // compare count
+ size_t nCount = m_xLbCustomPages->n_children();
+ if (rpCustomShow->PagesVector().size() != nCount)
+ {
+ rpCustomShow->PagesVector().clear();
+ bDifferent = true;
+ }
+
+ // compare page pointer
+ if( !bDifferent )
+ {
+ size_t i = 0;
+ for (const auto& rpPage : rpCustomShow->PagesVector())
+ {
+ SdPage* pPage = weld::fromId<SdPage*>(m_xLbCustomPages->get_id(i));
+ if (rpPage != pPage)
+ {
+ rpCustomShow->PagesVector().clear();
+ bDifferent = true;
+ break;
+ }
+
+ ++i;
+ }
+ }
+
+ // set new page pointer
+ if( bDifferent )
+ {
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ SdPage* pPage = weld::fromId<SdPage*>(m_xLbCustomPages->get_id(i));
+ rpCustomShow->PagesVector().push_back(pPage);
+ }
+ bModified = true;
+ }
+
+ // compare name and set name if necessary
+ OUString aStr( m_xEdtName->get_text() );
+ if( rpCustomShow->GetName() != aStr )
+ {
+ rpCustomShow->SetName( aStr );
+ bModified = true;
+ }
+}
+
+// OK-Hdl
+IMPL_LINK_NOARG(SdDefineCustomShowDlg, OKHdl, weld::Button&, void)
+{
+ // check name...
+ bool bDifferent = true;
+ SdCustomShowList* pCustomShowList = rDoc.GetCustomShowList();
+ if( pCustomShowList )
+ {
+ OUString aName( m_xEdtName->get_text() );
+ SdCustomShow* pCustomShow;
+
+ tools::Long nPosToSelect = pCustomShowList->GetCurPos();
+ for( pCustomShow = pCustomShowList->First();
+ pCustomShow != nullptr;
+ pCustomShow = pCustomShowList->Next() )
+ {
+ if( aName == pCustomShow->GetName() && aName != aOldName )
+ bDifferent = false;
+ }
+ pCustomShowList->Seek( nPosToSelect );
+ }
+
+ if( bDifferent )
+ {
+ CheckCustomShow();
+
+ m_xDialog->response(RET_OK);
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SdResId(STR_WARN_NAME_DUPLICATE)));
+ xWarn->run();
+ m_xEdtName->grab_focus();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/diactrl.cxx b/sd/source/ui/dlg/diactrl.cxx
new file mode 100644
index 000000000..233550809
--- /dev/null
+++ b/sd/source/ui/dlg/diactrl.cxx
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/fieldvalues.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/toolbox.hxx>
+#include <svl/intitem.hxx>
+
+#include <strings.hrc>
+
+#include <diactrl.hxx>
+
+#include <sdresid.hxx>
+#include <app.hrc>
+
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+
+using namespace ::com::sun::star;
+
+SFX_IMPL_TOOLBOX_CONTROL( SdTbxCtlDiaPages, SfxUInt16Item )
+
+namespace
+{
+ OUString format_number(int nSlides)
+ {
+ OUString aSlides(SdResId(STR_SLIDES, nSlides));
+ return aSlides.replaceFirst("%1", OUString::number(nSlides));
+ }
+}
+
+// SdPagesField
+SdPagesField::SdPagesField( vcl::Window* pParent,
+ const uno::Reference< frame::XFrame >& rFrame )
+ : InterimItemWindow(pParent, "modules/simpress/ui/pagesfieldbox.ui", "PagesFieldBox")
+ , m_xWidget(m_xBuilder->weld_spin_button("pagesfield"))
+ , m_xFrame(rFrame)
+{
+ InitControlBase(m_xWidget.get());
+
+ // set parameter of MetricFields
+ m_xWidget->set_digits(0);
+ m_xWidget->set_range(1, 15);
+ m_xWidget->set_increments(1, 5);
+ m_xWidget->connect_value_changed(LINK(this, SdPagesField, ModifyHdl));
+ m_xWidget->connect_output(LINK(this, SdPagesField, OutputHdl));
+ m_xWidget->connect_input(LINK(this, SdPagesField, spin_button_input));
+ m_xWidget->connect_key_press(LINK(this, SdPagesField, KeyInputHdl));
+
+ auto width = std::max(m_xWidget->get_pixel_size(format_number(1)).Width(),
+ m_xWidget->get_pixel_size(format_number(15)).Width());
+ int chars = ceil(width / m_xWidget->get_approximate_digit_width());
+ m_xWidget->set_width_chars(chars);
+
+ SetSizePixel(m_xWidget->get_preferred_size());
+}
+
+IMPL_LINK(SdPagesField, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return ChildKeyInput(rKEvt);
+}
+
+void SdPagesField::dispose()
+{
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+}
+
+SdPagesField::~SdPagesField()
+{
+ disposeOnce();
+}
+
+void SdPagesField::set_sensitive(bool bSensitive)
+{
+ Enable(bSensitive);
+ m_xWidget->set_sensitive(bSensitive);
+ if (!bSensitive)
+ m_xWidget->set_text("");
+}
+
+void SdPagesField::UpdatePagesField( const SfxUInt16Item* pItem )
+{
+ if (pItem)
+ m_xWidget->set_value(pItem->GetValue());
+ else
+ m_xWidget->set_text(OUString());
+}
+
+IMPL_STATIC_LINK(SdPagesField, OutputHdl, weld::SpinButton&, rSpinButton, void)
+{
+ rSpinButton.set_text(format_number(rSpinButton.get_value()));
+}
+
+IMPL_LINK(SdPagesField, spin_button_input, int*, result, bool)
+{
+ const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
+ double fResult(0.0);
+ bool bRet = vcl::TextToValue(m_xWidget->get_text(), fResult, 0, m_xWidget->get_digits(), rLocaleData, FieldUnit::NONE);
+ if (bRet)
+ {
+ if (fResult > SAL_MAX_INT32)
+ fResult = SAL_MAX_INT32;
+ else if (fResult < SAL_MIN_INT32)
+ fResult = SAL_MIN_INT32;
+ *result = fResult;
+ }
+ return bRet;
+}
+
+IMPL_LINK_NOARG(SdPagesField, ModifyHdl, weld::SpinButton&, void)
+{
+ SfxUInt16Item aItem(SID_PAGES_PER_ROW, m_xWidget->get_value());
+
+ uno::Any a;
+ aItem.QueryValue( a );
+ uno::Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue("PagesPerRow", a) };
+ SfxToolBoxControl::Dispatch( ::uno::Reference< ::frame::XDispatchProvider >( m_xFrame->getController(), ::uno::UNO_QUERY ),
+ ".uno:PagesPerRow",
+ aArgs );
+}
+
+SdTbxCtlDiaPages::SdTbxCtlDiaPages( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+SdTbxCtlDiaPages::~SdTbxCtlDiaPages()
+{
+}
+
+void SdTbxCtlDiaPages::StateChangedAtToolBoxControl( sal_uInt16,
+ SfxItemState eState, const SfxPoolItem* pState )
+{
+ SdPagesField* pFld = static_cast<SdPagesField*>( GetToolBox().GetItemWindow( GetId() ) );
+ DBG_ASSERT( pFld, "Window not found" );
+
+ if ( eState == SfxItemState::DISABLED )
+ {
+ pFld->set_sensitive(false);
+ }
+ else
+ {
+ pFld->set_sensitive(true);
+
+ const SfxUInt16Item* pItem = nullptr;
+ if ( eState == SfxItemState::DEFAULT )
+ {
+ pItem = dynamic_cast< const SfxUInt16Item* >( pState );
+ DBG_ASSERT( pItem, "sd::SdTbxCtlDiaPages::StateChanged(), wrong item type!" );
+ }
+
+ pFld->UpdatePagesField( pItem );
+ }
+}
+
+VclPtr<InterimItemWindow> SdTbxCtlDiaPages::CreateItemWindow( vcl::Window* pParent )
+{
+ VclPtr<SdPagesField> pWindow = VclPtr<SdPagesField>::Create(pParent, m_xFrame);
+ pWindow->Show();
+
+ return pWindow;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/dlgchar.cxx b/sd/source/ui/dlg/dlgchar.cxx
new file mode 100644
index 000000000..df1b24179
--- /dev/null
+++ b/sd/source/ui/dlg/dlgchar.cxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialogs.hrc>
+#include <editeng/flstitem.hxx>
+#include <svx/flagsdef.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/sfxdlg.hxx>
+
+#include <dlg_char.hxx>
+#include <svx/svxids.hrc>
+#include <svl/intitem.hxx>
+
+/**
+ * Constructor of tab dialog: append pages to dialog
+ */
+SdCharDlg::SdCharDlg(weld::Window* pParent, const SfxItemSet* pAttr,
+ const SfxObjectShell* pDocShell)
+ : SfxTabDialogController(pParent, "modules/sdraw/ui/drawchardialog.ui",
+ "DrawCharDialog", pAttr)
+ , rDocShell(*pDocShell)
+{
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+
+ AddTabPage("RID_SVXPAGE_CHAR_NAME", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_CHAR_NAME), nullptr);
+ AddTabPage("RID_SVXPAGE_CHAR_EFFECTS", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_CHAR_EFFECTS), nullptr);
+ AddTabPage("RID_SVXPAGE_CHAR_POSITION", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_CHAR_POSITION), nullptr);
+ AddTabPage("RID_SVXPAGE_BKG", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_BKG), nullptr);
+}
+
+void SdCharDlg::PageCreated(const OString& rId, SfxTabPage &rPage)
+{
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ if (rId == "RID_SVXPAGE_CHAR_NAME")
+ {
+ SvxFontListItem aItem(* static_cast<const SvxFontListItem*>( rDocShell.GetItem( SID_ATTR_CHAR_FONTLIST) ) );
+
+ aSet.Put (SvxFontListItem( aItem.GetFontList(), SID_ATTR_CHAR_FONTLIST));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_CHAR_EFFECTS")
+ {
+ // Opt in for character transparency.
+ aSet.Put(SfxUInt32Item(SID_FLAG_TYPE, SVX_ENABLE_CHAR_TRANSPARENCY));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_BKG")
+ {
+ aSet.Put(SfxUInt32Item(SID_FLAG_TYPE,static_cast<sal_uInt32>(SvxBackgroundTabFlags::SHOW_CHAR_BKGCOLOR)));
+ rPage.PageCreated(aSet);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/dlgfield.cxx b/sd/source/ui/dlg/dlgfield.cxx
new file mode 100644
index 000000000..75263a17c
--- /dev/null
+++ b/sd/source/ui/dlg/dlgfield.cxx
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <svl/itemset.hxx>
+#include <svx/langbox.hxx>
+#include <editeng/langitem.hxx>
+#include <unotools/useroptions.hxx>
+
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <sdmod.hxx>
+#include <dlgfield.hxx>
+#include <DrawDocShell.hxx>
+
+/**
+ * dialog to edit field commands
+ */
+SdModifyFieldDlg::SdModifyFieldDlg(weld::Window* pWindow, const SvxFieldData* pInField, const SfxItemSet& rSet)
+ : GenericDialogController(pWindow, "modules/simpress/ui/dlgfield.ui", "EditFieldsDialog")
+ , m_aInputSet(rSet)
+ , m_pField(pInField)
+ , m_xRbtFix(m_xBuilder->weld_radio_button("fixedRB"))
+ , m_xRbtVar(m_xBuilder->weld_radio_button("varRB"))
+ , m_xLbLanguage(new SvxLanguageBox(m_xBuilder->weld_combo_box("languageLB")))
+ , m_xLbFormat(m_xBuilder->weld_combo_box("formatLB"))
+{
+ m_xLbLanguage->SetLanguageList( SvxLanguageListFlags::ALL|SvxLanguageListFlags::ONLY_KNOWN, false );
+ m_xLbLanguage->connect_changed(LINK(this, SdModifyFieldDlg, LanguageChangeHdl));
+ FillControls();
+}
+
+SdModifyFieldDlg::~SdModifyFieldDlg()
+{
+}
+
+/**
+ * Returns the new field, owned by caller.
+ * Returns NULL if nothing has changed.
+ */
+SvxFieldData* SdModifyFieldDlg::GetField()
+{
+ SvxFieldData* pNewField = nullptr;
+
+ if( m_xRbtFix->get_state_changed_from_saved() ||
+ m_xRbtVar->get_state_changed_from_saved() ||
+ m_xLbFormat->get_value_changed_from_saved() )
+ {
+ if( auto pDateField = dynamic_cast< const SvxDateField *>( m_pField ) )
+ {
+ SvxDateType eType;
+ SvxDateFormat eFormat;
+
+ if( m_xRbtFix->get_active() )
+ eType = SvxDateType::Fix;
+ else
+ eType = SvxDateType::Var;
+
+ eFormat = static_cast<SvxDateFormat>( m_xLbFormat->get_active() + 2 );
+
+ pNewField = new SvxDateField( *pDateField );
+ static_cast<SvxDateField*>( pNewField )->SetType( eType );
+ static_cast<SvxDateField*>( pNewField )->SetFormat( eFormat );
+ }
+ else if( auto pTimeField = dynamic_cast< const SvxExtTimeField *>( m_pField ) )
+ {
+ SvxTimeType eType;
+ SvxTimeFormat eFormat;
+
+ if( m_xRbtFix->get_active() )
+ eType = SvxTimeType::Fix;
+ else
+ eType = SvxTimeType::Var;
+
+ eFormat = static_cast<SvxTimeFormat>( m_xLbFormat->get_active() + 2 );
+
+ pNewField = new SvxExtTimeField( *pTimeField );
+ static_cast<SvxExtTimeField*>( pNewField )->SetType( eType );
+ static_cast<SvxExtTimeField*>( pNewField )->SetFormat( eFormat );
+ }
+ else if( dynamic_cast< const SvxExtFileField *>( m_pField ) != nullptr )
+ {
+ SvxFileType eType;
+ SvxFileFormat eFormat;
+
+ if( m_xRbtFix->get_active() )
+ eType = SvxFileType::Fix;
+ else
+ eType = SvxFileType::Var;
+
+ eFormat = static_cast<SvxFileFormat>( m_xLbFormat->get_active() );
+
+ ::sd::DrawDocShell* pDocSh = dynamic_cast< ::sd::DrawDocShell* >(SfxObjectShell::Current() );
+
+ if( pDocSh )
+ {
+ OUString aName;
+ if( pDocSh->HasName() )
+ aName = pDocSh->GetMedium()->GetName();
+
+ // Get current filename, not the one stored in the old field
+ pNewField = new SvxExtFileField( aName );
+ static_cast<SvxExtFileField*>( pNewField )->SetType( eType );
+ static_cast<SvxExtFileField*>( pNewField )->SetFormat( eFormat );
+ }
+ }
+ else if( dynamic_cast< const SvxAuthorField *>( m_pField ) != nullptr )
+ {
+ SvxAuthorType eType;
+ SvxAuthorFormat eFormat;
+
+ if( m_xRbtFix->get_active() )
+ eType = SvxAuthorType::Fix;
+ else
+ eType = SvxAuthorType::Var;
+
+ eFormat = static_cast<SvxAuthorFormat>( m_xLbFormat->get_active() );
+
+ // Get current state of address, not the old one
+ SvtUserOptions aUserOptions;
+ pNewField = new SvxAuthorField( aUserOptions.GetFirstName(), aUserOptions.GetLastName(), aUserOptions.GetID() );
+ static_cast<SvxAuthorField*>( pNewField )->SetType( eType );
+ static_cast<SvxAuthorField*>( pNewField )->SetFormat( eFormat );
+ }
+ }
+
+ return pNewField;
+}
+
+void SdModifyFieldDlg::FillFormatList()
+{
+ LanguageType eLangType = m_xLbLanguage->get_active_id();
+
+ m_xLbFormat->clear();
+
+ if( auto pDateField = dynamic_cast< const SvxDateField *>( m_pField ) )
+ {
+ SvxDateField aDateField( *pDateField );
+
+ //SvxDateFormat::AppDefault, // not used
+ //SvxDateFormat::System, // not used
+ m_xLbFormat->append_text( SdResId( STR_STANDARD_SMALL ) );
+ m_xLbFormat->append_text( SdResId( STR_STANDARD_BIG ) );
+
+ SvNumberFormatter* pNumberFormatter = SD_MOD()->GetNumberFormatter();
+ aDateField.SetFormat( SvxDateFormat::A ); // 13.02.96
+ m_xLbFormat->append_text( aDateField.GetFormatted( *pNumberFormatter, eLangType ) );
+ aDateField.SetFormat( SvxDateFormat::B ); // 13.02.1996
+ m_xLbFormat->append_text( aDateField.GetFormatted( *pNumberFormatter, eLangType ) );
+ aDateField.SetFormat( SvxDateFormat::C ); // 13.Feb 1996
+ m_xLbFormat->append_text( aDateField.GetFormatted( *pNumberFormatter, eLangType ) );
+ aDateField.SetFormat( SvxDateFormat::D ); // 13.Februar 1996
+ m_xLbFormat->append_text( aDateField.GetFormatted( *pNumberFormatter, eLangType ) );
+ aDateField.SetFormat( SvxDateFormat::E ); // Die, 13.Februar 1996
+ m_xLbFormat->append_text( aDateField.GetFormatted( *pNumberFormatter, eLangType ) );
+ aDateField.SetFormat( SvxDateFormat::F ); // Dienstag, 13.Februar 1996
+ m_xLbFormat->append_text( aDateField.GetFormatted( *pNumberFormatter, eLangType ) );
+
+ m_xLbFormat->set_active( static_cast<sal_uInt16>(pDateField->GetFormat()) - 2 );
+ }
+ else if( auto pTimeField = dynamic_cast< const SvxExtTimeField *>( m_pField ) )
+ {
+ SvxExtTimeField aTimeField( *pTimeField );
+
+ //SvxTimeFormat::AppDefault, // not used
+ //SvxTimeFormat::System, // not used
+ m_xLbFormat->append_text( SdResId( STR_STANDARD_NORMAL ) );
+
+ SvNumberFormatter* pNumberFormatter = SD_MOD()->GetNumberFormatter();
+ aTimeField.SetFormat( SvxTimeFormat::HH24_MM ); // 13:49
+ m_xLbFormat->append_text( aTimeField.GetFormatted( *pNumberFormatter, eLangType ) );
+ aTimeField.SetFormat( SvxTimeFormat::HH24_MM_SS ); // 13:49:38
+ m_xLbFormat->append_text( aTimeField.GetFormatted( *pNumberFormatter, eLangType ) );
+ aTimeField.SetFormat( SvxTimeFormat::HH24_MM_SS_00 ); // 13:49:38.78
+ m_xLbFormat->append_text( aTimeField.GetFormatted( *pNumberFormatter, eLangType ) );
+ aTimeField.SetFormat( SvxTimeFormat::HH12_MM ); // 01:49
+ m_xLbFormat->append_text( aTimeField.GetFormatted( *pNumberFormatter, eLangType ) );
+ aTimeField.SetFormat( SvxTimeFormat::HH12_MM_SS ); // 01:49:38
+ m_xLbFormat->append_text( aTimeField.GetFormatted( *pNumberFormatter, eLangType ) );
+ aTimeField.SetFormat( SvxTimeFormat::HH12_MM_SS_00 ); // 01:49:38.78
+ m_xLbFormat->append_text( aTimeField.GetFormatted( *pNumberFormatter, eLangType ) );
+ //SvxTimeFormat::HH12_MM_AMPM, // 01:49 PM
+ //SvxTimeFormat::HH12_MM_SS_AMPM, // 01:49:38 PM
+ //SvxTimeFormat::HH12_MM_SS_00_AMPM // 01:49:38.78 PM
+
+ m_xLbFormat->set_active( static_cast<sal_uInt16>(pTimeField->GetFormat()) - 2 );
+ }
+ else if( auto pFileField = dynamic_cast< const SvxExtFileField *>( m_pField ) )
+ {
+ m_xLbFormat->append_text( SdResId( STR_FILEFORMAT_NAME_EXT ) );
+ m_xLbFormat->append_text( SdResId( STR_FILEFORMAT_FULLPATH ) );
+ m_xLbFormat->append_text( SdResId( STR_FILEFORMAT_PATH ) );
+ m_xLbFormat->append_text( SdResId( STR_FILEFORMAT_NAME ) );
+
+ m_xLbFormat->set_active( static_cast<sal_uInt16>( pFileField->GetFormat() ) );
+ }
+ else if( auto pAuthorField = dynamic_cast< const SvxAuthorField *>( m_pField ) )
+ {
+ SvxAuthorField aAuthorField( *pAuthorField );
+
+ for( sal_uInt16 i = 0; i < 4; i++ )
+ {
+ aAuthorField.SetFormat( static_cast<SvxAuthorFormat>(i) );
+ m_xLbFormat->append_text( aAuthorField.GetFormatted() );
+ }
+
+ m_xLbFormat->set_active( static_cast<sal_uInt16>( pAuthorField->GetFormat() ) );
+
+ }
+
+}
+
+void SdModifyFieldDlg::FillControls()
+{
+ m_xLbFormat->clear();
+
+ if( auto pDateField = dynamic_cast< const SvxDateField *>( m_pField ) )
+ {
+ if( pDateField->GetType() == SvxDateType::Fix )
+ m_xRbtFix->set_active(true);
+ else
+ m_xRbtVar->set_active(true);
+ }
+ else if( auto pTimeField = dynamic_cast< const SvxExtTimeField *>( m_pField ) )
+ {
+ if( pTimeField->GetType() == SvxTimeType::Fix )
+ m_xRbtFix->set_active(true);
+ else
+ m_xRbtVar->set_active(true);
+ }
+ else if( auto pFileField = dynamic_cast< const SvxExtFileField *>( m_pField ) )
+ {
+ if( pFileField->GetType() == SvxFileType::Fix )
+ m_xRbtFix->set_active(true);
+ else
+ m_xRbtVar->set_active(true);
+ }
+ else if( auto pAuthorField = dynamic_cast< const SvxAuthorField *>( m_pField ) )
+ {
+ if( pAuthorField->GetType() == SvxAuthorType::Fix )
+ m_xRbtFix->set_active(true);
+ else
+ m_xRbtVar->set_active(true);
+ }
+ m_xRbtFix->save_state();
+ m_xRbtVar->save_state();
+
+ if( const SvxLanguageItem* pItem = m_aInputSet.GetItemIfSet(EE_CHAR_LANGUAGE ) )
+ m_xLbLanguage->set_active_id(pItem->GetLanguage());
+
+ m_xLbLanguage->save_active_id();
+
+ FillFormatList();
+ m_xLbFormat->save_value();
+}
+
+IMPL_LINK_NOARG(SdModifyFieldDlg, LanguageChangeHdl, weld::ComboBox&, void)
+{
+ FillFormatList();
+}
+
+SfxItemSet SdModifyFieldDlg::GetItemSet() const
+{
+ SfxItemSet aOutput( *m_aInputSet.GetPool(), svl::Items<EE_CHAR_LANGUAGE, EE_CHAR_LANGUAGE_CTL> );
+
+ if (m_xLbLanguage->get_active_id_changed_from_saved())
+ {
+ LanguageType eLangType = m_xLbLanguage->get_active_id();
+ SvxLanguageItem aItem( eLangType, EE_CHAR_LANGUAGE );
+ aOutput.Put( aItem );
+
+ SvxLanguageItem aItemCJK( eLangType, EE_CHAR_LANGUAGE_CJK );
+ aOutput.Put( aItemCJK );
+
+ SvxLanguageItem aItemCTL( eLangType, EE_CHAR_LANGUAGE_CTL );
+ aOutput.Put( aItemCTL );
+ }
+
+ return aOutput;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/dlgolbul.cxx b/sd/source/ui/dlg/dlgolbul.cxx
new file mode 100644
index 000000000..41c00efa8
--- /dev/null
+++ b/sd/source/ui/dlg/dlgolbul.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <OutlineBulletDlg.hxx>
+
+#include <svx/svxids.hrc>
+#include <editeng/eeitem.hxx>
+
+#include <editeng/numitem.hxx>
+
+#include <tools/debug.hxx>
+#include <svx/dialogs.hrc>
+#include <svx/svdmark.hxx>
+#include <View.hxx>
+#include <svx/svdobj.hxx>
+#include <svl/style.hxx>
+#include <svl/intitem.hxx>
+#include <drawdoc.hxx>
+
+#include <strings.hxx>
+#include <bulmaper.hxx>
+#include <DrawDocShell.hxx>
+
+namespace sd {
+
+/**
+ * Constructor of tab dialog: append pages to the dialog
+ */
+OutlineBulletDlg::OutlineBulletDlg(weld::Window* pParent, const SfxItemSet* pAttr, ::sd::View* pView)
+ : SfxTabDialogController(pParent, "modules/sdraw/ui/bulletsandnumbering.ui", "BulletsAndNumberingDialog")
+ , m_aInputSet(*pAttr)
+ , m_bTitle(false)
+ , m_pSdView(pView)
+{
+ m_aInputSet.MergeRange(SID_PARAM_NUM_PRESET, SID_PARAM_CUR_NUM_LEVEL);
+ m_aInputSet.Put(*pAttr);
+
+ m_xOutputSet.reset( new SfxItemSet( *pAttr ) );
+ m_xOutputSet->ClearItem();
+
+ bool bOutliner = false;
+
+ // special treatment if a title object is selected
+ if (pView)
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+ for(size_t nNum = 0; nNum < nCount; ++nNum)
+ {
+ SdrObject* pObj = rMarkList.GetMark(nNum)->GetMarkedSdrObj();
+ if( pObj->GetObjInventor() == SdrInventor::Default )
+ {
+ switch(pObj->GetObjIdentifier())
+ {
+ case SdrObjKind::TitleText:
+ m_bTitle = true;
+ break;
+ case SdrObjKind::OutlineText:
+ bOutliner = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if( SfxItemState::SET != m_aInputSet.GetItemState(EE_PARA_NUMBULLET))
+ {
+ const SvxNumBulletItem *pItem = nullptr;
+ if(bOutliner)
+ {
+ SfxStyleSheetBasePool* pSSPool = pView->GetDocSh()->GetStyleSheetPool();
+ SfxStyleSheetBase* pFirstStyleSheet = pSSPool->Find( STR_LAYOUT_OUTLINE + " 1", SfxStyleFamily::Pseudo);
+ if( pFirstStyleSheet )
+ pItem = pFirstStyleSheet->GetItemSet().GetItemIfSet(EE_PARA_NUMBULLET, false);
+ }
+
+ if( pItem == nullptr )
+ pItem = m_aInputSet.GetPool()->GetSecondaryPool()->GetPoolDefaultItem(EE_PARA_NUMBULLET);
+
+ DBG_ASSERT( pItem, "No EE_PARA_NUMBULLET in Pool! [CL]" );
+
+ m_aInputSet.Put(pItem->CloneSetWhich(EE_PARA_NUMBULLET));
+ }
+
+ if (m_bTitle && m_aInputSet.GetItemState(EE_PARA_NUMBULLET) == SfxItemState::SET )
+ {
+ const SvxNumBulletItem* pItem = m_aInputSet.GetItem<SvxNumBulletItem>(EE_PARA_NUMBULLET);
+ const SvxNumRule& rRule = pItem->GetNumRule();
+ SvxNumRule aNewRule( rRule );
+ aNewRule.SetFeatureFlag( SvxNumRuleFlags::NO_NUMBERS );
+
+ SvxNumBulletItem aNewItem( std::move(aNewRule), EE_PARA_NUMBULLET );
+ m_aInputSet.Put(aNewItem);
+ }
+
+ SetInputSet(&m_aInputSet);
+
+ if (m_bTitle)
+ RemoveTabPage("singlenum");
+
+ AddTabPage("customize", RID_SVXPAGE_NUM_OPTIONS);
+ AddTabPage("position", RID_SVXPAGE_NUM_POSITION);
+}
+
+OutlineBulletDlg::~OutlineBulletDlg()
+{
+}
+
+void OutlineBulletDlg::PageCreated(const OString& rId, SfxTabPage &rPage)
+{
+ if (!m_pSdView)
+ return;
+ if (rId == "customize")
+ {
+ FieldUnit eMetric = m_pSdView->GetDoc().GetUIUnit();
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ aSet.Put ( SfxUInt16Item(SID_METRIC_ITEM,static_cast<sal_uInt16>(eMetric)));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "position")
+ {
+ FieldUnit eMetric = m_pSdView->GetDoc().GetUIUnit();
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ aSet.Put ( SfxUInt16Item(SID_METRIC_ITEM,static_cast<sal_uInt16>(eMetric)));
+ rPage.PageCreated(aSet);
+ }
+}
+
+const SfxItemSet* OutlineBulletDlg::GetBulletOutputItemSet() const
+{
+ SfxItemSet aSet(*GetOutputItemSet());
+ m_xOutputSet->Put(aSet);
+
+ const SfxPoolItem *pItem = nullptr;
+ if( SfxItemState::SET == m_xOutputSet->GetItemState(m_xOutputSet->GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE), false, &pItem ))
+ {
+ SdBulletMapper::MapFontsInNumRule(const_cast<SvxNumRule&>(static_cast<const SvxNumBulletItem*>(pItem)->GetNumRule()), *m_xOutputSet);
+ // #i35937 - removed EE_PARA_BULLETSTATE setting
+ }
+
+ if (m_bTitle && m_xOutputSet->GetItemState(EE_PARA_NUMBULLET) == SfxItemState::SET)
+ {
+ const SvxNumBulletItem* pBulletItem = m_xOutputSet->GetItem<SvxNumBulletItem>(EE_PARA_NUMBULLET);
+ SvxNumRule& rRule = const_cast<SvxNumRule&>(pBulletItem->GetNumRule());
+ rRule.SetFeatureFlag( SvxNumRuleFlags::NO_NUMBERS, false );
+ }
+
+ return m_xOutputSet.get();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/dlgpage.cxx b/sd/source/ui/dlg/dlgpage.cxx
new file mode 100644
index 000000000..e3bc5978b
--- /dev/null
+++ b/sd/source/ui/dlg/dlgpage.cxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/intitem.hxx>
+#include <svx/dialogs.hrc>
+#include <svx/svxids.hrc>
+#include <svx/drawitem.hxx>
+#include <i18nutil/paper.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/sfxdlg.hxx>
+
+#include <dlgpage.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+
+#include <svl/eitem.hxx>
+#include <svx/flagsdef.hxx>
+
+/**
+ * Constructor of tab dialog: appends pages to the dialog
+ */
+SdPageDlg::SdPageDlg(SfxObjectShell const* pDocSh, weld::Window* pParent, const SfxItemSet* pAttr,
+ bool bAreaPage, bool bIsImpressDoc, bool bIsImpressMaster)
+ : SfxTabDialogController(pParent, "modules/sdraw/ui/drawpagedialog.ui", "DrawPageDialog", pAttr)
+ , mbIsImpressDoc(bIsImpressDoc)
+{
+ SvxColorListItem const* pColorListItem = pDocSh->GetItem(SID_COLOR_TABLE);
+ SvxGradientListItem const* pGradientListItem = pDocSh->GetItem(SID_GRADIENT_LIST);
+ SvxBitmapListItem const* pBitmapListItem = pDocSh->GetItem(SID_BITMAP_LIST);
+ SvxPatternListItem const* pPatternListItem = pDocSh->GetItem(SID_PATTERN_LIST);
+ SvxHatchListItem const* pHatchListItem = pDocSh->GetItem(SID_HATCH_LIST);
+
+ mpColorList = pColorListItem->GetColorList();
+ mpGradientList = pGradientListItem->GetGradientList();
+ mpHatchingList = pHatchListItem->GetHatchList();
+ mpBitmapList = pBitmapListItem->GetBitmapList();
+ mpPatternList = pPatternListItem->GetPatternList();
+
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+
+ AddTabPage("RID_SVXPAGE_PAGE", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_PAGE), nullptr);
+ AddTabPage("RID_SVXPAGE_AREA", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_AREA), nullptr);
+ AddTabPage("RID_SVXPAGE_TRANSPARENCE", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_TRANSPARENCE),
+ nullptr);
+ AddTabPage("RID_SVXPAGE_THEME", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_THEME), nullptr);
+
+ if (!bAreaPage) // I have to add the page before I remove it !
+ {
+ RemoveTabPage("RID_SVXPAGE_AREA");
+ RemoveTabPage("RID_SVXPAGE_TRANSPARENCE");
+ }
+
+ if (!bIsImpressMaster)
+ {
+ // Only slide masters can have a theme.
+ RemoveTabPage("RID_SVXPAGE_THEME");
+ }
+
+ if (mbIsImpressDoc)
+ {
+ set_title(SdResId(STR_SLIDE_SETUP_TITLE));
+ m_xTabCtrl->set_tab_label_text("RID_SVXPAGE_PAGE", SdResId(STR_SLIDE_NAME));
+ }
+}
+
+void SdPageDlg::PageCreated(const OString& rId, SfxTabPage& rPage)
+{
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ if (rId == "RID_SVXPAGE_PAGE")
+ {
+ aSet.Put(SfxUInt16Item(sal_uInt16(SID_ENUM_PAGE_MODE), SVX_PAGE_MODE_PRESENTATION));
+ aSet.Put(SfxUInt16Item(SID_PAPER_START, PAPER_A0));
+ aSet.Put(SfxUInt16Item(SID_PAPER_END, PAPER_E));
+
+ if (mbIsImpressDoc)
+ aSet.Put(SfxBoolItem(SID_IMPRESS_DOC, true));
+
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_AREA")
+ {
+ aSet.Put(SvxColorListItem(mpColorList, SID_COLOR_TABLE));
+ aSet.Put(SvxGradientListItem(mpGradientList, SID_GRADIENT_LIST));
+ aSet.Put(SvxHatchListItem(mpHatchingList, SID_HATCH_LIST));
+ aSet.Put(SvxBitmapListItem(mpBitmapList, SID_BITMAP_LIST));
+ aSet.Put(SvxPatternListItem(mpPatternList, SID_PATTERN_LIST));
+ aSet.Put(SfxUInt16Item(SID_PAGE_TYPE, 0));
+ aSet.Put(SfxUInt16Item(SID_DLG_TYPE, 1));
+ aSet.Put(SfxUInt16Item(SID_TABPAGE_POS, 0));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_TRANSPARENCE")
+ {
+ aSet.Put(SfxUInt16Item(SID_PAGE_TYPE, 0));
+ aSet.Put(SfxUInt16Item(SID_DLG_TYPE, 1));
+ rPage.PageCreated(aSet);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/dlgsnap.cxx b/sd/source/ui/dlg/dlgsnap.cxx
new file mode 100644
index 000000000..9b1383089
--- /dev/null
+++ b/sd/source/ui/dlg/dlgsnap.cxx
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svxids.hrc>
+#include <svx/svdpagv.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+#include <svtools/unitconv.hxx>
+#include <tools/debug.hxx>
+
+#include <sdattr.hrc>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <dlgsnap.hxx>
+#include <sdenumdef.hxx>
+
+/**
+ * dialog to adjust grid (scarcely ESO!)
+ */
+SdSnapLineDlg::SdSnapLineDlg(weld::Window* pWindow, const SfxItemSet& rInAttrs, ::sd::View const * pView)
+ : GenericDialogController(pWindow, "modules/sdraw/ui/dlgsnap.ui", "SnapObjectDialog")
+ , aUIScale(pView->GetDoc().GetUIScale())
+ , m_xFtX(m_xBuilder->weld_label("xlabel"))
+ , m_xMtrFldX(m_xBuilder->weld_metric_spin_button("x", FieldUnit::CM))
+ , m_xFtY(m_xBuilder->weld_label("ylabel"))
+ , m_xMtrFldY(m_xBuilder->weld_metric_spin_button("y", FieldUnit::CM))
+ , m_xRadioGroup(m_xBuilder->weld_widget("radiogroup"))
+ , m_xRbPoint(m_xBuilder->weld_radio_button("point"))
+ , m_xRbVert(m_xBuilder->weld_radio_button("vert"))
+ , m_xRbHorz(m_xBuilder->weld_radio_button("horz"))
+ , m_xBtnDelete(m_xBuilder->weld_button("delete"))
+{
+ m_xRbHorz->connect_toggled(LINK(this, SdSnapLineDlg, ToggleHdl));
+ m_xRbVert->connect_toggled(LINK(this, SdSnapLineDlg, ToggleHdl));
+ m_xRbPoint->connect_toggled(LINK(this, SdSnapLineDlg, ToggleHdl));
+
+ m_xBtnDelete->connect_clicked(LINK(this, SdSnapLineDlg, ClickHdl));
+
+ FieldUnit eUIUnit = pView->GetDoc().GetUIUnit();
+ SetFieldUnit(*m_xMtrFldX, eUIUnit, true);
+ SetFieldUnit(*m_xMtrFldY, eUIUnit, true);
+
+ // get WorkArea
+ ::tools::Rectangle aWorkArea = pView->GetWorkArea();
+
+ // determine PoolUnit
+ SfxItemPool* pPool = rInAttrs.GetPool();
+ DBG_ASSERT( pPool, "Where's the Pool?" );
+ MapUnit ePoolUnit = pPool->GetMetric( SID_ATTR_FILL_HATCH );
+
+ // #i48497# Consider page origin
+ SdrPageView* pPV = pView->GetSdrPageView();
+ Point aLeftTop(aWorkArea.Left()+1, aWorkArea.Top()+1);
+ pPV->LogicToPagePos(aLeftTop);
+ Point aRightBottom(aWorkArea.Right()-2, aWorkArea.Bottom()-2);
+ pPV->LogicToPagePos(aRightBottom);
+
+ // determine max and min values depending on
+ // WorkArea, PoolUnit and FieldUnit:
+ auto const map = [ePoolUnit](std::unique_ptr<weld::MetricSpinButton> const & msb, tools::Long value) {
+ auto const n1 = OutputDevice::LogicToLogic(value, ePoolUnit, MapUnit::Map100thMM);
+ auto const n2 = msb->normalize(n1);
+ auto const n3 = msb->convert_value_from(n2, FieldUnit::MM_100TH);
+ auto const n4 = msb->convert_value_to(n3, FieldUnit::NONE);
+ return n4;
+ };
+ m_xMtrFldX->set_range(map(m_xMtrFldX, sal_Int32(aLeftTop.X() / aUIScale)),
+ map(m_xMtrFldX, sal_Int32(aRightBottom.X() / aUIScale)),
+ FieldUnit::NONE);
+ m_xMtrFldY->set_range(map(m_xMtrFldY, sal_Int32(aLeftTop.Y() / aUIScale)),
+ map(m_xMtrFldY, sal_Int32(aRightBottom.Y() / aUIScale)),
+ FieldUnit::NONE);
+
+ // set values
+ nXValue = static_cast<const SfxInt32Item&>( rInAttrs.Get(ATTR_SNAPLINE_X)).GetValue();
+ nYValue = static_cast<const SfxInt32Item&>( rInAttrs.Get(ATTR_SNAPLINE_Y)).GetValue();
+ nXValue = sal_Int32(nXValue / aUIScale);
+ nYValue = sal_Int32(nYValue / aUIScale);
+ SetMetricValue(*m_xMtrFldX, nXValue, MapUnit::Map100thMM);
+ SetMetricValue(*m_xMtrFldY, nYValue, MapUnit::Map100thMM);
+
+ m_xRbPoint->set_active(true);
+}
+
+SdSnapLineDlg::~SdSnapLineDlg()
+{
+}
+
+/**
+ * fills provided item sets with dialog box attributes
+ */
+IMPL_LINK(SdSnapLineDlg, ToggleHdl, weld::Toggleable&, rBtn, void)
+{
+ if (!rBtn.get_active())
+ return;
+ if (m_xRbPoint->get_active())
+ SetInputFields(true, true);
+ else if (m_xRbHorz->get_active())
+ SetInputFields(false, true);
+ else if (m_xRbVert->get_active())
+ SetInputFields(true, false);
+}
+
+IMPL_LINK( SdSnapLineDlg, ClickHdl, weld::Button&, rBtn, void )
+{
+ if (&rBtn == m_xBtnDelete.get())
+ m_xDialog->response(RET_SNAP_DELETE);
+}
+
+/**
+ * fills provided item sets with dialog box attributes
+ */
+void SdSnapLineDlg::GetAttr(SfxItemSet& rOutAttrs)
+{
+ SnapKind eKind;
+
+ if (m_xRbHorz->get_active()) eKind = SnapKind::Horizontal;
+ else if (m_xRbVert->get_active()) eKind = SnapKind::Vertical;
+ else eKind = SnapKind::Point;
+
+ nXValue = sal_Int32(GetCoreValue(*m_xMtrFldX, MapUnit::Map100thMM) * aUIScale);
+ nYValue = sal_Int32(GetCoreValue(*m_xMtrFldY, MapUnit::Map100thMM) * aUIScale);
+
+ rOutAttrs.Put(SfxUInt16Item(ATTR_SNAPLINE_KIND, static_cast<sal_uInt16>(eKind)));
+ rOutAttrs.Put(SfxInt32Item(ATTR_SNAPLINE_X, nXValue));
+ rOutAttrs.Put(SfxInt32Item(ATTR_SNAPLINE_Y, nYValue));
+}
+
+void SdSnapLineDlg::HideRadioGroup()
+{
+ m_xRadioGroup->hide();
+}
+
+/**
+ * disable X or Y input fields
+ */
+void SdSnapLineDlg::SetInputFields(bool bEnableX, bool bEnableY)
+{
+ if ( bEnableX )
+ {
+ if (!m_xMtrFldX->get_sensitive())
+ m_xMtrFldX->set_value(nXValue, FieldUnit::NONE);
+ m_xMtrFldX->set_sensitive(true);
+ m_xFtX->set_sensitive(true);
+ }
+ else if (m_xMtrFldX->get_sensitive())
+ {
+ nXValue = m_xMtrFldX->get_value(FieldUnit::NONE);
+ m_xMtrFldX->set_text(OUString());
+ m_xMtrFldX->set_sensitive(false);
+ m_xFtX->set_sensitive(false);
+ }
+ if ( bEnableY )
+ {
+ if (!m_xMtrFldY->get_sensitive())
+ m_xMtrFldY->set_value(nYValue, FieldUnit::NONE);
+ m_xMtrFldY->set_sensitive(true);
+ m_xFtY->set_sensitive(true);
+ }
+ else if (m_xMtrFldY->get_sensitive())
+ {
+ nYValue = m_xMtrFldY->get_value(FieldUnit::NONE);
+ m_xMtrFldY->set_text(OUString());
+ m_xMtrFldY->set_sensitive(false);
+ m_xFtY->set_sensitive(false);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/filedlg.cxx b/sd/source/ui/dlg/filedlg.cxx
new file mode 100644
index 000000000..b2087c408
--- /dev/null
+++ b/sd/source/ui/dlg/filedlg.cxx
@@ -0,0 +1,267 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <com/sun/star/media/XPlayer.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
+#include <com/sun/star/ui/dialogs/FilePickerEvent.hpp>
+#include <vcl/idle.hxx>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <filedlg.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+
+// ----------- SdFileDialog_Imp ---------------------------
+
+class SdFileDialog_Imp : public sfx2::FileDialogHelper
+{
+private:
+ friend class SdOpenSoundFileDialog;
+
+ css::uno::Reference< css::ui::dialogs::XFilePickerControlAccess > mxControlAccess;
+
+ css::uno::Reference< css::media::XPlayer > mxPlayer;
+ ImplSVEvent * mnPlaySoundEvent;
+ bool mbLabelPlaying;
+ Idle maUpdateIdle;
+
+ DECL_LINK( PlayMusicHdl, void *, void );
+ DECL_LINK( IsMusicStoppedHdl, Timer *, void );
+
+public:
+ explicit SdFileDialog_Imp(weld::Window *pParent);
+ virtual ~SdFileDialog_Imp() override;
+
+ // overwritten from FileDialogHelper, to receive user feedback
+ virtual void ControlStateChanged( const css::ui::dialogs::FilePickerEvent& aEvent ) override;
+};
+
+void SdFileDialog_Imp::ControlStateChanged( const css::ui::dialogs::FilePickerEvent& aEvent )
+{
+ SolarMutexGuard aGuard;
+
+ switch( aEvent.ElementId )
+ {
+ case css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY:
+ if( mxControlAccess.is() )
+ {
+ if( mnPlaySoundEvent )
+ Application::RemoveUserEvent( mnPlaySoundEvent );
+
+ mnPlaySoundEvent = Application::PostUserEvent( LINK( this, SdFileDialog_Imp, PlayMusicHdl ) );
+ }
+ break;
+ }
+}
+
+IMPL_LINK_NOARG(SdFileDialog_Imp, PlayMusicHdl, void*, void)
+{
+ maUpdateIdle.Stop();
+ mnPlaySoundEvent = nullptr;
+
+ if (mxPlayer.is())
+ {
+ if (mxPlayer->isPlaying())
+ mxPlayer->stop();
+ mxPlayer.clear();
+ }
+
+#if HAVE_FEATURE_AVMEDIA
+ if( mbLabelPlaying )
+ {
+ try
+ {
+ mxControlAccess->setLabel( css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY,
+ SdResId( STR_PLAY ) );
+ mbLabelPlaying = false;
+ }
+ catch(const css::lang::IllegalArgumentException&)
+ {
+#ifdef DBG_UTIL
+ OSL_FAIL( "Cannot access play button" );
+#endif
+ }
+ }
+ else
+ {
+ OUString aUrl( GetPath() );
+ if ( !aUrl.isEmpty() )
+ {
+ try
+ {
+ mxPlayer.set( avmedia::MediaWindow::createPlayer( aUrl, "" ), css::uno::UNO_SET_THROW );
+ mxPlayer->start();
+ maUpdateIdle.Start();
+ }
+ catch (const css::uno::Exception&)
+ {
+ mxPlayer.clear();
+ }
+
+ if (mxPlayer.is())
+ {
+ try
+ {
+ mxControlAccess->setLabel( css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY,
+ SdResId( STR_STOP ) );
+ mbLabelPlaying = true;
+ }
+ catch (const css::lang::IllegalArgumentException&)
+ {
+#ifdef DBG_UTIL
+ OSL_FAIL( "Cannot access play button" );
+#endif
+ }
+ }
+ }
+ }
+#endif
+}
+
+IMPL_LINK_NOARG(SdFileDialog_Imp, IsMusicStoppedHdl, Timer *, void)
+{
+ SolarMutexGuard aGuard;
+
+ if (mxPlayer.is() && mxPlayer->isPlaying() &&
+ mxPlayer->getMediaTime() < mxPlayer->getDuration())
+ {
+ maUpdateIdle.Start();
+ return;
+ }
+
+ if( !mxControlAccess.is() )
+ return;
+
+ try
+ {
+ mxControlAccess->setLabel( css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY,
+ SdResId( STR_PLAY ) );
+ mbLabelPlaying = false;
+ }
+ catch (const css::lang::IllegalArgumentException&)
+ {
+#ifdef DBG_UTIL
+ OSL_FAIL( "Cannot access play button" );
+#endif
+ }
+}
+
+SdFileDialog_Imp::SdFileDialog_Imp(weld::Window* pParent)
+ : FileDialogHelper(css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PLAY, FileDialogFlags::NONE, pParent)
+ , mnPlaySoundEvent(nullptr)
+ , mbLabelPlaying(false)
+ , maUpdateIdle( "SdFileDialog_Imp maUpdateIdle" )
+{
+ maUpdateIdle.SetInvokeHandler(LINK(this, SdFileDialog_Imp, IsMusicStoppedHdl));
+
+ css::uno::Reference < css::ui::dialogs::XFilePicker3 > xFileDlg = GetFilePicker();
+
+ // get the control access
+ mxControlAccess.set( xFileDlg, css::uno::UNO_QUERY );
+
+ if( !mxControlAccess.is() )
+ return;
+
+ try
+ {
+ mxControlAccess->setLabel( css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY,
+ SdResId( STR_PLAY ) );
+ }
+ catch (const css::lang::IllegalArgumentException&)
+ {
+#ifdef DBG_UTIL
+ OSL_FAIL( "Cannot set play button label" );
+#endif
+ }
+}
+
+SdFileDialog_Imp::~SdFileDialog_Imp()
+{
+ if( mnPlaySoundEvent )
+ Application::RemoveUserEvent( mnPlaySoundEvent );
+}
+
+// ----------- SdOpenSoundFileDialog -----------------------
+
+// these are simple forwarders
+SdOpenSoundFileDialog::SdOpenSoundFileDialog(weld::Window *pParent)
+ : mpImpl(new SdFileDialog_Imp(pParent))
+{
+ OUString aDescr = SdResId(STR_ALL_FILES);
+ mpImpl->AddFilter( aDescr, "*.*");
+ mpImpl->SetContext(sfx2::FileDialogHelper::DrawImpressOpenSound);
+
+ // setup filter
+#if defined UNX
+ aDescr = SdResId(STR_AU_FILE);
+ mpImpl->AddFilter( aDescr, "*.au;*.snd");
+ aDescr = SdResId(STR_VOC_FILE);
+ mpImpl->AddFilter( aDescr, "*.voc");
+ aDescr = SdResId(STR_WAV_FILE);
+ mpImpl->AddFilter( aDescr, "*.wav");
+ aDescr = SdResId(STR_AIFF_FILE);
+ mpImpl->AddFilter( aDescr, "*.aiff");
+ aDescr = SdResId(STR_SVX_FILE);
+ mpImpl->AddFilter( aDescr, "*.svx");
+#else
+ aDescr = SdResId(STR_WAV_FILE);
+ mpImpl->AddFilter( aDescr, "*.wav;*.mp3;*.ogg" );
+ aDescr = SdResId(STR_MIDI_FILE);
+ mpImpl->AddFilter( aDescr, "*.mid" );
+#endif
+}
+
+SdOpenSoundFileDialog::~SdOpenSoundFileDialog()
+{
+}
+
+ErrCode SdOpenSoundFileDialog::Execute()
+{
+ return mpImpl->Execute();
+}
+
+OUString SdOpenSoundFileDialog::GetPath() const
+{
+ return mpImpl->GetPath();
+}
+
+void SdOpenSoundFileDialog::SetPath( const OUString& rPath )
+{
+ mpImpl->SetDisplayDirectory( rPath );
+}
+
+// WIP, please don't remove, dear Clang plugins
+bool SdOpenSoundFileDialog::IsInsertAsLinkSelected() const
+{
+ bool bInsertAsLinkSelected = false;
+ css::uno::Reference<css::ui::dialogs::XFilePicker3> const xFilePicker(mpImpl->GetFilePicker());
+ css::uno::Reference<css::ui::dialogs::XFilePickerControlAccess> const xControlAccess(xFilePicker, css::uno::UNO_QUERY_THROW);
+ xControlAccess->getValue(css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK, 0) >>= bInsertAsLinkSelected;
+ return bInsertAsLinkSelected;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/gluectrl.cxx b/sd/source/ui/dlg/gluectrl.cxx
new file mode 100644
index 000000000..a6baf3e92
--- /dev/null
+++ b/sd/source/ui/dlg/gluectrl.cxx
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <svx/svdglue.hxx>
+#include <svl/intitem.hxx>
+#include <vcl/toolbox.hxx>
+
+#include <strings.hrc>
+#include <gluectrl.hxx>
+#include <sdresid.hxx>
+#include <app.hrc>
+
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+
+// at the moment, Joe only supports the methods specified below
+#define ESCDIR_COUNT 5
+const SdrEscapeDirection aEscDirArray[] =
+{
+ SdrEscapeDirection::SMART,
+ SdrEscapeDirection::LEFT,
+ SdrEscapeDirection::RIGHT,
+ SdrEscapeDirection::TOP,
+ SdrEscapeDirection::BOTTOM
+};
+
+SFX_IMPL_TOOLBOX_CONTROL( SdTbxCtlGlueEscDir, SfxUInt16Item )
+
+/**
+ * Constructor for gluepoint escape direction Listbox
+ */
+GlueEscDirLB::GlueEscDirLB(vcl::Window* pParent, const Reference<XFrame>& rFrame)
+ : InterimItemWindow(pParent, "modules/simpress/ui/gluebox.ui", "GlueBox")
+ , m_xFrame(rFrame)
+ , m_xWidget(m_xBuilder->weld_combo_box("gluetype"))
+{
+ InitControlBase(m_xWidget.get());
+
+ Fill();
+
+ m_xWidget->connect_changed(LINK(this, GlueEscDirLB, SelectHdl));
+ m_xWidget->connect_key_press(LINK(this, GlueEscDirLB, KeyInputHdl));
+
+ SetSizePixel(m_xWidget->get_preferred_size());
+
+ Show();
+}
+
+void GlueEscDirLB::dispose()
+{
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+}
+
+GlueEscDirLB::~GlueEscDirLB()
+{
+ disposeOnce();
+}
+
+void GlueEscDirLB::set_sensitive(bool bSensitive)
+{
+ Enable(bSensitive);
+ m_xWidget->set_sensitive(bSensitive);
+}
+
+IMPL_LINK(GlueEscDirLB, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return ChildKeyInput(rKEvt);
+}
+
+/**
+ * Determines the escape direction and sends the corresponding slot
+ */
+IMPL_LINK(GlueEscDirLB, SelectHdl, weld::ComboBox&, rBox, void)
+{
+ sal_Int32 nPos = rBox.get_active();
+ SfxUInt16Item aItem( SID_GLUE_ESCDIR, static_cast<sal_uInt16>(aEscDirArray[ nPos ]) );
+
+ if ( m_xFrame.is() )
+ {
+ Any a;
+ aItem.QueryValue( a );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("GlueEscapeDirection", a) };
+ SfxToolBoxControl::Dispatch( Reference< XDispatchProvider >( m_xFrame->getController(), UNO_QUERY ),
+ ".uno:GlueEscapeDirection",
+ aArgs );
+ }
+}
+
+/**
+ * Fills the Listbox with strings
+ */
+void GlueEscDirLB::Fill()
+{
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_SMART ) );
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_LEFT ) );
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_RIGHT ) );
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_TOP ) );
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_BOTTOM ) );
+ /*
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_LO ) );
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_LU ) );
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_RO ) );
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_RU ) );
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_HORZ ) );
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_VERT ) );
+ m_xWidget->append_text( SdResId( STR_GLUE_ESCDIR_ALL ) );
+ */
+}
+
+/**
+ * Constructor for gluepoint escape direction toolbox control
+ */
+SdTbxCtlGlueEscDir::SdTbxCtlGlueEscDir(
+ sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+/**
+ * Represents state in the listbox of the controller
+ */
+void SdTbxCtlGlueEscDir::StateChangedAtToolBoxControl( sal_uInt16 nSId,
+ SfxItemState eState, const SfxPoolItem* pState )
+{
+ if( eState == SfxItemState::DEFAULT )
+ {
+ GlueEscDirLB* pGlueEscDirLB = static_cast<GlueEscDirLB*> ( GetToolBox().
+ GetItemWindow( GetId() ) );
+ if( pGlueEscDirLB )
+ {
+ if( pState )
+ {
+ pGlueEscDirLB->set_sensitive(true);
+ if ( IsInvalidItem( pState ) )
+ {
+ pGlueEscDirLB->set_active(-1);
+ }
+ else
+ {
+ SdrEscapeDirection nEscDir = static_cast<SdrEscapeDirection>(static_cast<const SfxUInt16Item*>( pState )->GetValue());
+ pGlueEscDirLB->set_active( GetEscDirPos( nEscDir ) );
+ }
+ }
+ else
+ {
+ pGlueEscDirLB->set_sensitive(false);
+ pGlueEscDirLB->set_active(-1);
+ }
+ }
+ }
+
+ SfxToolBoxControl::StateChangedAtToolBoxControl( nSId, eState, pState );
+}
+
+VclPtr<InterimItemWindow> SdTbxCtlGlueEscDir::CreateItemWindow( vcl::Window *pParent )
+{
+ if( GetSlotId() == SID_GLUE_ESCDIR )
+ return VclPtr<GlueEscDirLB>::Create( pParent, m_xFrame ).get();
+
+ return VclPtr<InterimItemWindow>();
+}
+
+/**
+ * Returns position in the array for EscDir (Mapping for Listbox)
+ */
+sal_uInt16 SdTbxCtlGlueEscDir::GetEscDirPos( SdrEscapeDirection nEscDir )
+{
+ for( sal_uInt16 i = 0; i < ESCDIR_COUNT; i++ )
+ {
+ if( aEscDirArray[ i ] == nEscDir )
+ return i;
+ }
+ return 99;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/headerfooterdlg.cxx b/sd/source/ui/dlg/headerfooterdlg.cxx
new file mode 100644
index 000000000..703f2f598
--- /dev/null
+++ b/sd/source/ui/dlg/headerfooterdlg.cxx
@@ -0,0 +1,759 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/langitem.hxx>
+#include <svx/langbox.hxx>
+#include <svx/svdotext.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/outlobj.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <tools/debug.hxx>
+
+#include <Outliner.hxx>
+#include <headerfooterdlg.hxx>
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <ViewShell.hxx>
+#include <sdmod.hxx>
+
+// preview control for presentation layout
+#include <tools/color.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <svtools/colorcfg.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/svapp.hxx>
+
+#include <undoheaderfooter.hxx>
+#include <sdundogr.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+namespace sd
+{
+
+namespace {
+
+class PresLayoutPreview : public weld::CustomWidgetController
+{
+private:
+ SdPage* mpMaster;
+ HeaderFooterSettings maSettings;
+ Size maPageSize;
+ ::tools::Rectangle maOutRect;
+
+private:
+ void Paint(vcl::RenderContext& rRenderContext, SdrTextObj const * pObj, bool bVisible, bool bDotted = false);
+
+public:
+ explicit PresLayoutPreview();
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+ virtual void Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect) override;
+
+ void init(SdPage* pMaster);
+ void update(HeaderFooterSettings const & rSettings);
+};
+
+}
+
+}
+
+// tab page for slide & header'n'notes
+
+namespace sd
+{
+
+const int nDateTimeFormatsCount = 12;
+
+namespace {
+
+struct DateAndTimeFormat {
+ SvxDateFormat meDateFormat;
+ SvxTimeFormat meTimeFormat;
+};
+
+}
+
+DateAndTimeFormat const nDateTimeFormats[nDateTimeFormatsCount] =
+{
+ { SvxDateFormat::A, SvxTimeFormat::AppDefault },
+ { SvxDateFormat::B, SvxTimeFormat::AppDefault },
+ { SvxDateFormat::C, SvxTimeFormat::AppDefault },
+ { SvxDateFormat::D, SvxTimeFormat::AppDefault },
+ { SvxDateFormat::E, SvxTimeFormat::AppDefault },
+ { SvxDateFormat::F, SvxTimeFormat::AppDefault },
+
+ { SvxDateFormat::A, SvxTimeFormat::HH24_MM },
+ { SvxDateFormat::A, SvxTimeFormat::HH12_MM },
+
+ { SvxDateFormat::AppDefault, SvxTimeFormat::HH24_MM },
+ { SvxDateFormat::AppDefault, SvxTimeFormat::HH24_MM_SS },
+
+ { SvxDateFormat::AppDefault, SvxTimeFormat::HH12_MM },
+ { SvxDateFormat::AppDefault, SvxTimeFormat::HH12_MM_SS },
+};
+
+class HeaderFooterTabPage
+{
+private:
+ SdDrawDocument* mpDoc;
+ LanguageType meOldLanguage;
+ bool mbHandoutMode;
+
+ std::unique_ptr<weld::Builder> mxBuilder;
+ std::unique_ptr<weld::Container> mxContainer;
+ std::unique_ptr<weld::Label> mxFTIncludeOn;
+ std::unique_ptr<weld::CheckButton> mxCBHeader;
+ std::unique_ptr<weld::Widget> mxHeaderBox;
+ std::unique_ptr<weld::Entry> mxTBHeader;
+ std::unique_ptr<weld::CheckButton> mxCBDateTime;
+ std::unique_ptr<weld::RadioButton> mxRBDateTimeFixed;
+ std::unique_ptr<weld::RadioButton> mxRBDateTimeAutomatic;
+ std::unique_ptr<weld::Entry> mxTBDateTimeFixed;
+ std::unique_ptr<weld::ComboBox> mxCBDateTimeFormat;
+ std::unique_ptr<weld::Label> mxFTDateTimeLanguage;
+ std::unique_ptr<SvxLanguageBox> mxCBDateTimeLanguage;
+ std::unique_ptr<weld::CheckButton> mxCBFooter;
+ std::unique_ptr<weld::Widget> mxFooterBox;
+ std::unique_ptr<weld::Entry> mxTBFooter;
+ std::unique_ptr<weld::CheckButton> mxCBSlideNumber;
+ std::unique_ptr<weld::CheckButton> mxCBNotOnTitle;
+ std::unique_ptr<weld::Label> mxReplacementA;
+ std::unique_ptr<weld::Label> mxReplacementB;
+ std::unique_ptr<PresLayoutPreview> mxCTPreview;
+ std::unique_ptr<weld::CustomWeld> mxCTPreviewWin;
+
+
+ DECL_LINK( UpdateOnToggleHdl, weld::Toggleable&, void );
+ DECL_LINK( LanguageChangeHdl, weld::ComboBox&, void );
+
+ void FillFormatList(sal_Int32 nSelectedPos);
+ void GetOrSetDateTimeLanguage( LanguageType &rLanguage, bool bSet );
+ void GetOrSetDateTimeLanguage( LanguageType &rLanguage, bool bSet, SdPage* pPage );
+
+public:
+ HeaderFooterTabPage(weld::Container* pParent, SdDrawDocument* pDoc, SdPage* pActualPage, bool bHandoutMode );
+
+ void init( const HeaderFooterSettings& rSettings, bool bNotOnTitle );
+ void getData( HeaderFooterSettings& rSettings, bool& rNotOnTitle );
+ void update();
+};
+
+}
+
+using namespace ::sd;
+
+HeaderFooterDialog::HeaderFooterDialog(ViewShell* pViewShell, weld::Window* pParent, SdDrawDocument* pDoc, SdPage* pCurrentPage)
+ : GenericDialogController(pParent, "modules/simpress/ui/headerfooterdialog.ui", "HeaderFooterDialog")
+ , mpDoc( pDoc )
+ , mpCurrentPage( pCurrentPage )
+ , mpViewShell( pViewShell )
+ , mxTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
+ , mxPBApplyToAll(m_xBuilder->weld_button("apply_all"))
+ , mxPBApply(m_xBuilder->weld_button("apply"))
+ , mxPBCancel(m_xBuilder->weld_button("cancel"))
+{
+ SdPage* pSlide;
+ SdPage* pNotes;
+ if( pCurrentPage->GetPageKind() == PageKind::Standard )
+ {
+ pSlide = pCurrentPage;
+ pNotes = static_cast<SdPage*>(pDoc->GetPage( pCurrentPage->GetPageNum() + 1 ));
+ }
+ else if( pCurrentPage->GetPageKind() == PageKind::Notes )
+ {
+ pNotes = pCurrentPage;
+ pSlide = static_cast<SdPage*>(pDoc->GetPage( pCurrentPage->GetPageNum() -1 ));
+ mpCurrentPage = pSlide;
+ }
+ else
+ {
+ // handout
+ pSlide = pDoc->GetSdPage( 0, PageKind::Standard );
+ pNotes = pDoc->GetSdPage( 0, PageKind::Notes );
+ mpCurrentPage = nullptr;
+ }
+
+ mxSlideTabPage.reset(new HeaderFooterTabPage(mxTabCtrl->get_page("slides"), pDoc, pSlide, false));
+ mxNotesHandoutsTabPage.reset(new HeaderFooterTabPage(mxTabCtrl->get_page("notes"), pDoc, pNotes, true));
+
+ pDoc->StopWorkStartupDelay();
+ mxTabCtrl->show();
+
+ ActivatePageHdl(mxTabCtrl->get_current_page_ident());
+
+ mxTabCtrl->connect_enter_page( LINK( this, HeaderFooterDialog, ActivatePageHdl ) );
+
+ mxPBApplyToAll->connect_clicked( LINK( this, HeaderFooterDialog, ClickApplyToAllHdl ) );
+ mxPBApply->connect_clicked( LINK( this, HeaderFooterDialog, ClickApplyHdl ) );
+ mxPBCancel->connect_clicked( LINK( this, HeaderFooterDialog, ClickCancelHdl ) );
+
+ maSlideSettings = pSlide->getHeaderFooterSettings();
+
+ const HeaderFooterSettings& rTitleSettings = mpDoc->GetSdPage(0, PageKind::Standard)->getHeaderFooterSettings();
+ bool bNotOnTitle = !rTitleSettings.mbFooterVisible && !rTitleSettings.mbSlideNumberVisible && !rTitleSettings.mbDateTimeVisible;
+
+ mxSlideTabPage->init( maSlideSettings, bNotOnTitle );
+
+ maNotesHandoutSettings = pNotes->getHeaderFooterSettings();
+ mxNotesHandoutsTabPage->init( maNotesHandoutSettings, false );
+}
+
+HeaderFooterDialog::~HeaderFooterDialog()
+{
+}
+
+IMPL_LINK(HeaderFooterDialog, ActivatePageHdl, const OString&, rIdent, void)
+{
+ mxPBApply->set_visible(rIdent == "slides");
+ mxPBApply->set_sensitive(mpCurrentPage != nullptr);
+}
+
+IMPL_LINK_NOARG(HeaderFooterDialog, ClickApplyToAllHdl, weld::Button&, void)
+{
+ ApplyToAll();
+}
+
+IMPL_LINK_NOARG(HeaderFooterDialog, ClickApplyHdl, weld::Button&, void)
+{
+ Apply();
+}
+
+IMPL_LINK_NOARG(HeaderFooterDialog, ClickCancelHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_CANCEL);
+}
+
+short HeaderFooterDialog::run()
+{
+ short nRet = GenericDialogController::run();
+ if (nRet)
+ mpViewShell->GetDocSh()->SetModified();
+ return nRet;
+}
+
+void HeaderFooterDialog::ApplyToAll()
+{
+ OString tabId = mxTabCtrl->get_current_page_ident();
+ apply(true, tabId == "slides");
+ m_xDialog->response(RET_OK);
+}
+
+void HeaderFooterDialog::Apply()
+{
+ OString tabId = mxTabCtrl->get_current_page_ident();
+ apply(false, tabId == "slides");
+ m_xDialog->response(RET_OK);
+}
+
+void HeaderFooterDialog::apply( bool bToAll, bool bForceSlides )
+{
+ std::unique_ptr<SdUndoGroup> pUndoGroup(new SdUndoGroup(mpDoc));
+ OUString aComment( m_xDialog->get_title() );
+ pUndoGroup->SetComment( aComment );
+
+ HeaderFooterSettings aNewSettings;
+ bool bNewNotOnTitle;
+
+ // change slide settings first ...
+
+ mxSlideTabPage->getData( aNewSettings, bNewNotOnTitle );
+
+ // only if we pressed apply or apply all on the slide tab page or if the slide settings
+ // have been changed
+ if( bForceSlides || !(aNewSettings == maSlideSettings) )
+ {
+ // apply to all slides
+ if( bToAll )
+ {
+ int nPageCount = mpDoc->GetSdPageCount( PageKind::Standard );
+ int nPage;
+ for( nPage = 0; nPage < nPageCount; nPage++ )
+ {
+ SdPage* pPage = mpDoc->GetSdPage( static_cast<sal_uInt16>(nPage), PageKind::Standard );
+ change( pUndoGroup.get(), pPage, aNewSettings );
+ }
+ }
+ else
+ {
+ // apply only to the current slide
+ DBG_ASSERT( mpCurrentPage && mpCurrentPage->GetPageKind() == PageKind::Standard, "no current page to apply to!" );
+ if( mpCurrentPage && (mpCurrentPage->GetPageKind() == PageKind::Standard) )
+ {
+ change( pUndoGroup.get(), mpCurrentPage, aNewSettings );
+ }
+ }
+ }
+
+ // if we don't want to have header&footer on the first slide
+ if( bNewNotOnTitle )
+ {
+ // just hide them, plain simple UI feature
+ HeaderFooterSettings aTempSettings = mpDoc->GetSdPage( 0, PageKind::Standard )->getHeaderFooterSettings();
+
+ aTempSettings.mbFooterVisible = false;
+ aTempSettings.mbSlideNumberVisible = false;
+ aTempSettings.mbDateTimeVisible = false;
+
+ change( pUndoGroup.get(), mpDoc->GetSdPage( 0, PageKind::Standard ), aTempSettings );
+ }
+
+ // now notes settings
+
+ mxNotesHandoutsTabPage->getData( aNewSettings, bNewNotOnTitle );
+
+ // only if we pressed apply or apply all on the notes tab page or if the notes settings
+ // have been changed
+ if( !bForceSlides || !(aNewSettings == maNotesHandoutSettings) )
+ {
+ // first set to all notes pages
+ int nPageCount = mpDoc->GetSdPageCount( PageKind::Notes );
+ int nPage;
+ for( nPage = 0; nPage < nPageCount; nPage++ )
+ {
+ SdPage* pPage = mpDoc->GetSdPage( static_cast<sal_uInt16>(nPage), PageKind::Notes );
+
+ change( pUndoGroup.get(), pPage, aNewSettings );
+ }
+
+ // and last but not least to the handout page
+ change( pUndoGroup.get(), mpDoc->GetMasterSdPage( 0, PageKind::Handout ), aNewSettings );
+ }
+
+ // give the undo group to the undo manager
+ mpViewShell->GetViewFrame()->GetObjectShell()->GetUndoManager()->AddUndoAction(std::move(pUndoGroup));
+}
+
+void HeaderFooterDialog::change( SdUndoGroup* pUndoGroup, SdPage* pPage, const HeaderFooterSettings& rNewSettings )
+{
+ pUndoGroup->AddAction(new SdHeaderFooterUndoAction(mpDoc, pPage, rNewSettings ));
+ pPage->setHeaderFooterSettings( rNewSettings );
+}
+
+HeaderFooterTabPage::HeaderFooterTabPage(weld::Container* pParent, SdDrawDocument* pDoc, SdPage* pActualPage, bool bHandoutMode)
+ : mpDoc(pDoc)
+ , mbHandoutMode(bHandoutMode)
+ , mxBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/headerfootertab.ui"))
+ , mxContainer(mxBuilder->weld_container("HeaderFooterTab"))
+ , mxFTIncludeOn(mxBuilder->weld_label("include_label"))
+ , mxCBHeader(mxBuilder->weld_check_button("header_cb" ))
+ , mxHeaderBox(mxBuilder->weld_widget("header_box"))
+ , mxTBHeader(mxBuilder->weld_entry("header_text"))
+ , mxCBDateTime(mxBuilder->weld_check_button("datetime_cb"))
+ , mxRBDateTimeFixed(mxBuilder->weld_radio_button("rb_fixed"))
+ , mxRBDateTimeAutomatic(mxBuilder->weld_radio_button("rb_auto"))
+ , mxTBDateTimeFixed(mxBuilder->weld_entry("datetime_value"))
+ , mxCBDateTimeFormat(mxBuilder->weld_combo_box("datetime_format_list"))
+ , mxFTDateTimeLanguage(mxBuilder->weld_label("language_label"))
+ , mxCBDateTimeLanguage(new SvxLanguageBox(mxBuilder->weld_combo_box("language_list")))
+ , mxCBFooter(mxBuilder->weld_check_button("footer_cb"))
+ , mxFooterBox(mxBuilder->weld_widget("footer_box" ))
+ , mxTBFooter(mxBuilder->weld_entry("footer_text"))
+ , mxCBSlideNumber(mxBuilder->weld_check_button("slide_number"))
+ , mxCBNotOnTitle(mxBuilder->weld_check_button("not_on_title"))
+ , mxReplacementA(mxBuilder->weld_label("replacement_a"))
+ , mxReplacementB(mxBuilder->weld_label("replacement_b"))
+ , mxCTPreview(new PresLayoutPreview)
+ , mxCTPreviewWin(new weld::CustomWeld(*mxBuilder, "preview", *mxCTPreview))
+{
+ mxCTPreview->init( pActualPage ?
+ (pActualPage->IsMasterPage() ? pActualPage : static_cast<SdPage*>(&(pActualPage->TRG_GetMasterPage()))) :
+ (pDoc->GetMasterSdPage( 0, bHandoutMode ? PageKind::Notes : PageKind::Standard )) );
+
+ if( mbHandoutMode )
+ {
+ OUString sPageNo = mxReplacementA->get_label();
+ mxCBSlideNumber->set_label( sPageNo );
+
+ OUString sFrameTitle = mxReplacementB->get_label();
+ mxFTIncludeOn->set_label( sFrameTitle );
+ }
+
+ mxCBHeader->set_visible( mbHandoutMode );
+ mxHeaderBox->set_visible( mbHandoutMode );
+ mxCBNotOnTitle->set_visible( !mbHandoutMode );
+
+ mxCBDateTime->connect_toggled( LINK( this, HeaderFooterTabPage, UpdateOnToggleHdl ) );
+ mxRBDateTimeFixed->connect_toggled( LINK( this, HeaderFooterTabPage, UpdateOnToggleHdl ) );
+ mxRBDateTimeAutomatic->connect_toggled( LINK( this, HeaderFooterTabPage, UpdateOnToggleHdl ) );
+ mxCBFooter->connect_toggled( LINK( this, HeaderFooterTabPage, UpdateOnToggleHdl ) );
+ mxCBHeader->connect_toggled( LINK( this, HeaderFooterTabPage, UpdateOnToggleHdl ) );
+ mxCBSlideNumber->connect_toggled( LINK( this, HeaderFooterTabPage, UpdateOnToggleHdl ) );
+
+ mxCBDateTimeLanguage->SetLanguageList( SvxLanguageListFlags::ALL|SvxLanguageListFlags::ONLY_KNOWN, false, false );
+ mxCBDateTimeLanguage->connect_changed( LINK( this, HeaderFooterTabPage, LanguageChangeHdl ) );
+
+ GetOrSetDateTimeLanguage( meOldLanguage, false );
+ meOldLanguage = MsLangId::getRealLanguage( meOldLanguage );
+ mxCBDateTimeLanguage->set_active_id( meOldLanguage );
+
+ FillFormatList(0);
+}
+
+IMPL_LINK_NOARG(HeaderFooterTabPage, LanguageChangeHdl, weld::ComboBox&, void)
+{
+ FillFormatList( mxCBDateTimeFormat->get_active() );
+}
+
+void HeaderFooterTabPage::FillFormatList( sal_Int32 nSelectedPos )
+{
+ LanguageType eLanguage = mxCBDateTimeLanguage->get_active_id();
+
+ mxCBDateTimeFormat->clear();
+
+ DateTime aDateTime( DateTime::SYSTEM );
+
+ for (int nFormat = 0; nFormat < nDateTimeFormatsCount; ++nFormat)
+ {
+ OUString aStr( SvxDateTimeField::GetFormatted(
+ aDateTime, aDateTime,
+ nDateTimeFormats[nFormat].meDateFormat, nDateTimeFormats[nFormat].meTimeFormat,
+ *(SD_MOD()->GetNumberFormatter()), eLanguage ) );
+ mxCBDateTimeFormat->append_text(aStr);
+ if (nFormat == nSelectedPos)
+ mxCBDateTimeFormat->set_active(nFormat);
+ }
+}
+
+void HeaderFooterTabPage::init( const HeaderFooterSettings& rSettings, bool bNotOnTitle )
+{
+ mxCBDateTime->set_active( rSettings.mbDateTimeVisible );
+ mxRBDateTimeFixed->set_active( rSettings.mbDateTimeIsFixed );
+ mxRBDateTimeAutomatic->set_active( !rSettings.mbDateTimeIsFixed );
+ mxTBDateTimeFixed->set_text( rSettings.maDateTimeText );
+
+ mxCBHeader->set_active( rSettings.mbHeaderVisible );
+ mxTBHeader->set_text( rSettings.maHeaderText );
+
+ mxCBFooter->set_active( rSettings.mbFooterVisible );
+ mxTBFooter->set_text( rSettings.maFooterText );
+
+ mxCBSlideNumber->set_active( rSettings.mbSlideNumberVisible );
+
+ mxCBNotOnTitle->set_active( bNotOnTitle );
+
+ mxCBDateTimeLanguage->set_active_id( meOldLanguage );
+
+ for (sal_Int32 nPos = 0, nEntryCount = mxCBDateTimeFormat->get_count(); nPos < nEntryCount; ++nPos)
+ {
+ if( nDateTimeFormats[nPos].meDateFormat == rSettings.meDateFormat && nDateTimeFormats[nPos].meTimeFormat == rSettings.meTimeFormat )
+ {
+ mxCBDateTimeFormat->set_active(nPos);
+ break;
+ }
+ }
+
+ update();
+}
+
+void HeaderFooterTabPage::getData( HeaderFooterSettings& rSettings, bool& rNotOnTitle )
+{
+ rSettings.mbDateTimeVisible = mxCBDateTime->get_active();
+ rSettings.mbDateTimeIsFixed = mxRBDateTimeFixed->get_active();
+ rSettings.maDateTimeText = mxTBDateTimeFixed->get_text();
+ rSettings.mbFooterVisible = mxCBFooter->get_active();
+ rSettings.maFooterText = mxTBFooter->get_text();
+ rSettings.mbSlideNumberVisible = mxCBSlideNumber->get_active();
+ rSettings.mbHeaderVisible = mxCBHeader->get_active();
+ rSettings.maHeaderText = mxTBHeader->get_text();
+
+ int nPos = mxCBDateTimeFormat->get_active();
+ if (nPos != -1)
+ {
+ rSettings.meDateFormat = nDateTimeFormats[nPos].meDateFormat;
+ rSettings.meTimeFormat = nDateTimeFormats[nPos].meTimeFormat;
+ }
+
+ LanguageType eLanguage = mxCBDateTimeLanguage->get_active_id();
+ if( eLanguage != meOldLanguage )
+ GetOrSetDateTimeLanguage( eLanguage, true );
+
+ rNotOnTitle = mxCBNotOnTitle->get_active();
+}
+
+void HeaderFooterTabPage::update()
+{
+ mxRBDateTimeFixed->set_sensitive( mxCBDateTime->get_active() );
+ mxTBDateTimeFixed->set_sensitive( mxRBDateTimeFixed->get_active() && mxCBDateTime->get_active() );
+ mxRBDateTimeAutomatic->set_sensitive( mxCBDateTime->get_active() );
+ mxCBDateTimeFormat->set_sensitive( mxCBDateTime->get_active() && mxRBDateTimeAutomatic->get_active() );
+ mxFTDateTimeLanguage->set_sensitive( mxCBDateTime->get_active() && mxRBDateTimeAutomatic->get_active() );
+ mxCBDateTimeLanguage->set_sensitive( mxCBDateTime->get_active() && mxRBDateTimeAutomatic->get_active() );
+ mxFooterBox->set_sensitive( mxCBFooter->get_active() );
+ mxHeaderBox->set_sensitive( mxCBHeader->get_active() );
+
+ HeaderFooterSettings aSettings;
+ bool bNotOnTitle;
+ getData( aSettings, bNotOnTitle );
+ mxCTPreview->update( aSettings );
+}
+
+IMPL_LINK_NOARG(HeaderFooterTabPage, UpdateOnToggleHdl, weld::Toggleable&, void)
+{
+ update();
+}
+
+void HeaderFooterTabPage::GetOrSetDateTimeLanguage( LanguageType &rLanguage, bool bSet )
+{
+ if( mbHandoutMode )
+ {
+ // if set, set it on all notes master pages
+ if( bSet )
+ {
+ sal_uInt16 nPageCount = mpDoc->GetMasterSdPageCount( PageKind::Notes );
+ sal_uInt16 nPage;
+ for( nPage = 0; nPage < nPageCount; nPage++ )
+ {
+ GetOrSetDateTimeLanguage( rLanguage, bSet, mpDoc->GetMasterSdPage( nPage, PageKind::Notes ) );
+ }
+ }
+
+ // #i119985# and set it, or just get it from the notes master page
+ GetOrSetDateTimeLanguage( rLanguage, bSet, mpDoc->GetMasterSdPage( 0, PageKind::Notes ) );
+ }
+ else
+ {
+ // get the language from the first master page
+ // or set it to all master pages
+ sal_uInt16 nPageCount = bSet ? mpDoc->GetMasterSdPageCount( PageKind::Notes ) : 1;
+ sal_uInt16 nPage;
+ for( nPage = 0; nPage < nPageCount; nPage++ )
+ {
+ GetOrSetDateTimeLanguage( rLanguage, bSet, mpDoc->GetMasterSdPage( nPage, PageKind::Standard ) );
+ }
+ }
+}
+
+void HeaderFooterTabPage::GetOrSetDateTimeLanguage( LanguageType &rLanguage, bool bSet, SdPage* pPage )
+{
+ if( !pPage )
+ return;
+
+ SdrTextObj* pObj = static_cast<SdrTextObj*>(pPage->GetPresObj( PresObjKind::DateTime ));
+ if( !pObj )
+ return;
+
+ Outliner* pOutl = mpDoc->GetInternalOutliner();
+ pOutl->Init( OutlinerMode::TextObject );
+ OutlinerMode nOutlMode = pOutl->GetOutlinerMode();
+
+ EditEngine* pEdit = const_cast< EditEngine* >(&pOutl->GetEditEngine());
+
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+ if( pOPO )
+ pOutl->SetText( *pOPO );
+
+ EPosition aDateFieldPosition;
+ bool bHasDateFieldItem = false;
+
+ sal_Int32 nParaCount = pEdit->GetParagraphCount();
+ for (sal_Int32 nPara = 0; (nPara < nParaCount) && !bHasDateFieldItem; ++nPara)
+ {
+ sal_uInt16 nFieldCount = pEdit->GetFieldCount(nPara);
+ for (sal_uInt16 nField = 0; (nField < nFieldCount); ++nField)
+ {
+ EFieldInfo aFieldInfo = pEdit->GetFieldInfo(nPara, nField);
+ if (aFieldInfo.pFieldItem)
+ {
+ const SvxFieldData* pFieldData = aFieldInfo.pFieldItem->GetField();
+ if (dynamic_cast<const SvxDateTimeField*>(pFieldData) != nullptr ||
+ dynamic_cast<const SvxDateField*>(pFieldData) != nullptr)
+ {
+ bHasDateFieldItem = true;
+ aDateFieldPosition = aFieldInfo.aPosition;
+ break;
+ }
+ }
+ }
+ }
+
+ if (bHasDateFieldItem)
+ {
+ if( bSet )
+ {
+ SfxItemSet aSet(pEdit->GetAttribs(aDateFieldPosition.nPara,
+ aDateFieldPosition.nIndex,
+ aDateFieldPosition.nIndex+1,
+ GetAttribsFlags::CHARATTRIBS));
+
+ SvxLanguageItem aItem( rLanguage, EE_CHAR_LANGUAGE );
+ aSet.Put( aItem );
+
+ SvxLanguageItem aItemCJK( rLanguage, EE_CHAR_LANGUAGE_CJK );
+ aSet.Put( aItemCJK );
+
+ SvxLanguageItem aItemCTL( rLanguage, EE_CHAR_LANGUAGE_CTL );
+ aSet.Put( aItemCTL );
+
+ ESelection aSel(aDateFieldPosition.nPara, aDateFieldPosition.nIndex,
+ aDateFieldPosition.nPara, aDateFieldPosition.nIndex+1 );
+ pEdit->QuickSetAttribs( aSet, aSel );
+
+ pObj->SetOutlinerParaObject( pOutl->CreateParaObject() );
+ pOutl->UpdateFields();
+ }
+ else
+ {
+ rLanguage = pOutl->GetLanguage(aDateFieldPosition.nPara,
+ aDateFieldPosition.nIndex );
+ }
+ }
+
+ pOutl->Clear();
+ pOutl->Init( nOutlMode );
+}
+
+PresLayoutPreview::PresLayoutPreview()
+ : mpMaster(nullptr)
+{
+}
+
+void PresLayoutPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(80, 80), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ SetOutputSizePixel(aSize);
+}
+
+void PresLayoutPreview::init( SdPage *pMaster )
+{
+ mpMaster = pMaster;
+ maPageSize = pMaster->GetSize();
+}
+
+void PresLayoutPreview::update( HeaderFooterSettings const & rSettings )
+{
+ maSettings = rSettings;
+ Invalidate();
+}
+
+void PresLayoutPreview::Paint(vcl::RenderContext& rRenderContext, SdrTextObj const * pObj, bool bVisible, bool bDotted /* = false*/ )
+{
+ // get object transformation
+ basegfx::B2DHomMatrix aObjectTransform;
+ basegfx::B2DPolyPolygon aObjectPolyPolygon;
+ pObj->TRGetBaseGeometry(aObjectTransform, aObjectPolyPolygon);
+
+ // build complete transformation by adding view transformation from
+ // logic page coordinates to local pixel coordinates
+ const double fScaleX(static_cast<double>(maOutRect.getWidth()) / static_cast<double>(maPageSize.Width()));
+ const double fScaleY(static_cast<double>(maOutRect.getHeight()) / static_cast<double>(maPageSize.Height()));
+ aObjectTransform.scale(fScaleX, fScaleY);
+ aObjectTransform.translate(maOutRect.Left(), maOutRect.Top());
+
+ // create geometry using unit range and object transform
+ basegfx::B2DPolyPolygon aGeometry(basegfx::utils::createUnitPolygon());
+ aGeometry.transform(aObjectTransform);
+
+ // apply line pattern if wanted
+ if (bDotted)
+ {
+ static const double fFactor(1.0);
+ std::vector<double> aPattern
+ {
+ 3.0 * fFactor,
+ 1.0 * fFactor
+ };
+
+ basegfx::B2DPolyPolygon aDashed;
+ basegfx::utils::applyLineDashing(aGeometry, aPattern, &aDashed);
+ aGeometry = aDashed;
+ }
+
+ // determine line color
+ svtools::ColorConfig aColorConfig;
+ svtools::ColorConfigValue aColor( aColorConfig.GetColorValue( bVisible ? svtools::FONTCOLOR : svtools::OBJECTBOUNDARIES ) );
+
+ // paint at OutDev
+ rRenderContext.SetLineColor(aColor.nColor);
+ rRenderContext.SetFillColor();
+
+ for (sal_uInt32 a(0); a < aGeometry.count(); a++)
+ {
+ rRenderContext.DrawPolyLine(aGeometry.getB2DPolygon(a));
+ }
+}
+
+void PresLayoutPreview::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle&)
+{
+ rRenderContext.Push();
+
+ maOutRect = ::tools::Rectangle(Point(0,0), rRenderContext.GetOutputSize());
+
+ // calculate page size with correct aspect ratio
+ int nWidth, nHeight;
+ if( maPageSize.Width() > maPageSize.Height() )
+ {
+ nWidth = maOutRect.GetWidth();
+ nHeight = maPageSize.Width() == 0 ? 0 : tools::Long( static_cast<double>(nWidth * maPageSize.Height()) / static_cast<double>(maPageSize.Width()) );
+ }
+ else
+ {
+ nHeight = maOutRect.GetHeight();
+ nWidth = maPageSize.Height() == 0 ? 0 : tools::Long( static_cast<double>(nHeight * maPageSize.Width()) / static_cast<double>(maPageSize.Height()) );
+ }
+
+ maOutRect.AdjustLeft((maOutRect.GetWidth() - nWidth) >> 1 );
+ maOutRect.SetRight( maOutRect.Left() + nWidth - 1 );
+ maOutRect.AdjustTop((maOutRect.GetHeight() - nHeight) >> 1 );
+ maOutRect.SetBottom( maOutRect.Top() + nHeight - 1 );
+
+ // draw decoration frame
+ DecorationView aDecoView(&rRenderContext);
+ maOutRect = aDecoView.DrawFrame(maOutRect, DrawFrameStyle::In);
+
+ // draw page background
+ rRenderContext.SetFillColor(COL_WHITE);
+ rRenderContext.DrawRect(maOutRect);
+
+ // paint presentation objects from masterpage
+ if (nullptr != mpMaster)
+ {
+ SdrTextObj* pMasterTitle = static_cast<SdrTextObj*>(mpMaster->GetPresObj(PresObjKind::Title));
+ SdrTextObj* pMasterOutline = static_cast<SdrTextObj*>(mpMaster->GetPresObj(mpMaster->GetPageKind() == PageKind::Notes ? PresObjKind::Notes : PresObjKind::Outline));
+ SdrTextObj* pHeader = static_cast<SdrTextObj*>(mpMaster->GetPresObj(PresObjKind::Header));
+ SdrTextObj* pFooter = static_cast<SdrTextObj*>(mpMaster->GetPresObj(PresObjKind::Footer));
+ SdrTextObj* pDate = static_cast<SdrTextObj*>(mpMaster->GetPresObj(PresObjKind::DateTime));
+ SdrTextObj* pNumber = static_cast<SdrTextObj*>(mpMaster->GetPresObj(PresObjKind::SlideNumber));
+
+ if (pMasterTitle)
+ Paint(rRenderContext, pMasterTitle, true, true);
+ if (pMasterOutline)
+ Paint(rRenderContext, pMasterOutline, true, true);
+ if (pHeader)
+ Paint(rRenderContext, pHeader, maSettings.mbHeaderVisible);
+ if (pFooter)
+ Paint(rRenderContext, pFooter, maSettings.mbFooterVisible);
+ if (pDate)
+ Paint(rRenderContext, pDate, maSettings.mbDateTimeVisible);
+ if (pNumber)
+ Paint(rRenderContext, pNumber, maSettings.mbSlideNumberVisible);
+ }
+
+ rRenderContext.Pop();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/ins_paste.cxx b/sd/source/ui/dlg/ins_paste.cxx
new file mode 100644
index 000000000..f1020c0cb
--- /dev/null
+++ b/sd/source/ui/dlg/ins_paste.cxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ins_paste.hxx>
+
+SdInsertPasteDlg::SdInsertPasteDlg(weld::Window* pWindow)
+ : GenericDialogController(pWindow, "modules/simpress/ui/insertslides.ui", "InsertSlidesDialog")
+ , m_xRbBefore(m_xBuilder->weld_radio_button("before"))
+ , m_xRbAfter(m_xBuilder->weld_radio_button("after"))
+{
+ m_xRbAfter->set_active(true);
+}
+
+SdInsertPasteDlg::~SdInsertPasteDlg() {}
+
+bool SdInsertPasteDlg::IsInsertBefore() const { return m_xRbBefore->get_active(); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/inspagob.cxx b/sd/source/ui/dlg/inspagob.cxx
new file mode 100644
index 000000000..5c984dd23
--- /dev/null
+++ b/sd/source/ui/dlg/inspagob.cxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <inspagob.hxx>
+#include <sdtreelb.hxx>
+
+#include <strings.hrc>
+
+#include <bitmaps.hlst>
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+
+SdInsertPagesObjsDlg::SdInsertPagesObjsDlg(
+ weld::Window* pWindow, const SdDrawDocument* pInDoc,
+ SfxMedium* pSfxMedium, const OUString& rFileName )
+ : GenericDialogController(pWindow, "modules/sdraw/ui/insertslidesdialog.ui", "InsertSlidesDialog")
+ , m_pMedium(pSfxMedium)
+ , m_pDoc(pInDoc)
+ , m_rName(rFileName)
+ , m_xLbTree(new SdPageObjsTLV(m_xBuilder->weld_tree_view("tree")))
+ , m_xCbxLink(m_xBuilder->weld_check_button("links"))
+ , m_xCbxMasters(m_xBuilder->weld_check_button("backgrounds"))
+{
+ m_xLbTree->set_size_request(m_xLbTree->get_approximate_digit_width() * 48,
+ m_xLbTree->get_height_rows(12));
+
+ m_xLbTree->SetViewFrame( pInDoc->GetDocSh()->GetViewShell()->GetViewFrame() );
+
+ m_xLbTree->connect_changed(LINK(this, SdInsertPagesObjsDlg, SelectObjectHdl));
+
+ // insert text
+ if (!m_pMedium)
+ m_xDialog->set_title(SdResId(STR_INSERT_TEXT));
+ else if (m_pDoc && m_pDoc->GetDocumentType() == DocumentType::Draw)
+ m_xDialog->set_title(SdResId(STR_INSERT_PAGES));
+
+ Reset();
+}
+
+SdInsertPagesObjsDlg::~SdInsertPagesObjsDlg()
+{
+}
+
+/**
+ * Fills the TreeLB dependent on the medium. Is not medium available, then
+ * it is a text and not a draw document.
+ */
+void SdInsertPagesObjsDlg::Reset()
+{
+ if( m_pMedium )
+ {
+ m_xLbTree->set_selection_mode(SelectionMode::Multiple);
+
+ // transfer ownership of Medium
+ m_xLbTree->Fill( m_pDoc, m_pMedium, m_rName );
+ }
+ else
+ {
+ m_xLbTree->InsertEntry(m_rName, BMP_DOC_TEXT);
+ }
+
+ m_xCbxMasters->set_active(true);
+}
+
+std::vector<OUString> SdInsertPagesObjsDlg::GetList( const sal_uInt16 nType )
+{
+ // With Draw documents, we have to return NULL on selection of the document
+ if( m_pMedium )
+ {
+ // to ensure that bookmarks are opened
+ // (when the whole document is selected)
+ m_xLbTree->GetBookmarkDoc();
+
+ // If the document is selected (too) or nothing is selected,
+ // the whole document is inserted (but not more!)
+ std::unique_ptr<weld::TreeIter> xIter(m_xLbTree->make_iterator());
+ if (!m_xLbTree->get_iter_first(*xIter) || m_xLbTree->is_selected(*xIter))
+ return std::vector<OUString>();
+ }
+
+ return m_xLbTree->GetSelectEntryList( nType );
+}
+
+/**
+ * is link checked
+ */
+bool SdInsertPagesObjsDlg::IsLink() const
+{
+ return m_xCbxLink->get_active();
+}
+
+/**
+ * is link checked
+ */
+bool SdInsertPagesObjsDlg::IsRemoveUnnecessaryMasterPages() const
+{
+ return m_xCbxMasters->get_active();
+}
+
+/**
+ * Enabled and selects end-color-LB
+ */
+IMPL_LINK_NOARG(SdInsertPagesObjsDlg, SelectObjectHdl, weld::TreeView&, void)
+{
+ m_xCbxLink->set_sensitive(m_xLbTree->IsLinkableSelected());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/layeroptionsdlg.cxx b/sd/source/ui/dlg/layeroptionsdlg.cxx
new file mode 100644
index 000000000..a70c71f47
--- /dev/null
+++ b/sd/source/ui/dlg/layeroptionsdlg.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/itemset.hxx>
+
+#include <sdattr.hxx>
+#include <layeroptionsdlg.hxx>
+
+SdInsertLayerDlg::SdInsertLayerDlg(weld::Window* pWindow, const SfxItemSet& rInAttrs,
+ bool bDeletable, const OUString& rStr)
+ : GenericDialogController(pWindow, "modules/sdraw/ui/insertlayer.ui", "InsertLayerDialog")
+ , m_xEdtName(m_xBuilder->weld_entry("name"))
+ , m_xEdtTitle(m_xBuilder->weld_entry("title"))
+ , m_xEdtDesc(m_xBuilder->weld_text_view("textview"))
+ , m_xCbxVisible(m_xBuilder->weld_check_button("visible"))
+ , m_xCbxPrintable(m_xBuilder->weld_check_button("printable"))
+ , m_xCbxLocked(m_xBuilder->weld_check_button("locked"))
+ , m_xNameFrame(m_xBuilder->weld_widget("nameframe"))
+{
+ m_xDialog->set_title(rStr);
+
+ m_xEdtName->set_text( static_cast<const SfxStringItem&>( rInAttrs.Get( ATTR_LAYER_NAME ) ).GetValue() );
+ m_xEdtTitle->set_text( static_cast<const SfxStringItem&>( rInAttrs.Get( ATTR_LAYER_TITLE ) ).GetValue() );
+ m_xEdtDesc->set_text( static_cast<const SfxStringItem&>( rInAttrs.Get( ATTR_LAYER_DESC ) ).GetValue() );
+ m_xEdtDesc->set_size_request(-1, m_xEdtDesc->get_height_rows(4));
+ m_xCbxVisible->set_active( static_cast<const SfxBoolItem&>( rInAttrs.Get( ATTR_LAYER_VISIBLE ) ).GetValue() );
+ m_xCbxPrintable->set_active( static_cast<const SfxBoolItem&>( rInAttrs.Get( ATTR_LAYER_PRINTABLE ) ).GetValue() );
+ m_xCbxLocked->set_active( static_cast<const SfxBoolItem&>( rInAttrs.Get( ATTR_LAYER_LOCKED ) ).GetValue() );
+ m_xNameFrame->set_sensitive(bDeletable);
+}
+
+SdInsertLayerDlg::~SdInsertLayerDlg()
+{
+}
+
+void SdInsertLayerDlg::GetAttr( SfxItemSet& rAttrs )
+{
+ rAttrs.Put( makeSdAttrLayerName( m_xEdtName->get_text() ) );
+ rAttrs.Put( makeSdAttrLayerTitle( m_xEdtTitle->get_text() ) );
+ rAttrs.Put( makeSdAttrLayerDesc( m_xEdtDesc->get_text() ) );
+ rAttrs.Put( makeSdAttrLayerVisible( m_xCbxVisible->get_active() ) );
+ rAttrs.Put( makeSdAttrLayerPrintable( m_xCbxPrintable->get_active() ) );
+ rAttrs.Put( makeSdAttrLayerLocked( m_xCbxLocked->get_active() ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/masterlayoutdlg.cxx b/sd/source/ui/dlg/masterlayoutdlg.cxx
new file mode 100644
index 000000000..ce4e069b0
--- /dev/null
+++ b/sd/source/ui/dlg/masterlayoutdlg.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 <masterlayoutdlg.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::sd;
+
+MasterLayoutDialog::MasterLayoutDialog(weld::Window* pParent, SdDrawDocument* pDoc, SdPage* pCurrentPage)
+ : GenericDialogController(pParent, "modules/simpress/ui/masterlayoutdlg.ui", "MasterLayoutDialog")
+ , mpDoc(pDoc)
+ , mpCurrentPage(pCurrentPage)
+ , mxCBDate(m_xBuilder->weld_check_button("datetime"))
+ , mxCBPageNumber(m_xBuilder->weld_check_button("pagenumber"))
+ , mxCBSlideNumber(m_xBuilder->weld_check_button("slidenumber"))
+ , mxCBHeader(m_xBuilder->weld_check_button("header"))
+ , mxCBFooter(m_xBuilder->weld_check_button("footer"))
+{
+ if( mpCurrentPage && !mpCurrentPage->IsMasterPage() )
+ {
+ mpCurrentPage = static_cast<SdPage*>(&(mpCurrentPage->TRG_GetMasterPage()));
+ }
+
+ if( mpCurrentPage == nullptr )
+ {
+ mpCurrentPage = pDoc->GetMasterSdPage( 0, PageKind::Standard );
+ OSL_FAIL( "MasterLayoutDialog::MasterLayoutDialog() - no current page?" );
+ }
+
+ switch( mpCurrentPage->GetPageKind() )
+ {
+ case PageKind::Standard:
+ {
+ mxCBHeader->set_sensitive(false);
+ mxCBPageNumber->set_label(mxCBSlideNumber->get_label());
+ break;
+ }
+ case PageKind::Notes:
+ break;
+ case PageKind::Handout:
+ break;
+ }
+
+ mbOldHeader = mpCurrentPage->GetPresObj( PresObjKind::Header ) != nullptr;
+ mbOldDate = mpCurrentPage->GetPresObj( PresObjKind::DateTime ) != nullptr;
+ mbOldFooter = mpCurrentPage->GetPresObj( PresObjKind::Footer ) != nullptr;
+ mbOldPageNumber = mpCurrentPage->GetPresObj( PresObjKind::SlideNumber ) != nullptr;
+
+ mxCBHeader->set_active( mbOldHeader );
+ mxCBDate->set_active( mbOldDate );
+ mxCBFooter->set_active( mbOldFooter );
+ mxCBPageNumber->set_active( mbOldPageNumber );
+}
+
+MasterLayoutDialog::~MasterLayoutDialog()
+{
+}
+
+short MasterLayoutDialog::run()
+{
+ if (GenericDialogController::run() == RET_OK)
+ applyChanges();
+ return RET_OK;
+}
+
+void MasterLayoutDialog::applyChanges()
+{
+ mpDoc->BegUndo(m_xDialog->get_title());
+
+ if( (mpCurrentPage->GetPageKind() != PageKind::Standard) && (mbOldHeader != mxCBHeader->get_active() ) )
+ {
+ if( mbOldHeader )
+ remove( PresObjKind::Header );
+ else
+ create( PresObjKind::Header );
+ }
+
+ if( mbOldFooter != mxCBFooter->get_active() )
+ {
+ if( mbOldFooter )
+ remove( PresObjKind::Footer );
+ else
+ create( PresObjKind::Footer );
+ }
+
+ if( mbOldDate != mxCBDate->get_active() )
+ {
+ if( mbOldDate )
+ remove( PresObjKind::DateTime );
+ else
+ create( PresObjKind::DateTime );
+ }
+
+ if( mbOldPageNumber != mxCBPageNumber->get_active() )
+ {
+ if( mbOldPageNumber )
+ remove( PresObjKind::SlideNumber );
+ else
+ create( PresObjKind::SlideNumber );
+ }
+
+ mpDoc->EndUndo();
+}
+
+void MasterLayoutDialog::create(PresObjKind eKind)
+{
+ mpCurrentPage->CreateDefaultPresObj(eKind);
+}
+
+void MasterLayoutDialog::remove( PresObjKind eKind )
+{
+ mpCurrentPage->DestroyDefaultPresObj(eKind);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/morphdlg.cxx b/sd/source/ui/dlg/morphdlg.cxx
new file mode 100644
index 000000000..c0d7f4e5a
--- /dev/null
+++ b/sd/source/ui/dlg/morphdlg.cxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <morphdlg.hxx>
+
+#include <sdmod.hxx>
+#include <sdiocmpt.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/svdobj.hxx>
+#include <svl/itemset.hxx>
+#include <com/sun/star/drawing/LineStyle.hpp>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+MorphDlg::MorphDlg(weld::Window* pParent, const SdrObject* pObj1, const SdrObject* pObj2 )
+ : GenericDialogController(pParent, "modules/sdraw/ui/crossfadedialog.ui", "CrossFadeDialog")
+ , m_xMtfSteps(m_xBuilder->weld_spin_button("increments"))
+ , m_xCbxAttributes(m_xBuilder->weld_check_button("attributes"))
+ , m_xCbxOrientation(m_xBuilder->weld_check_button("orientation"))
+{
+ LoadSettings();
+
+ SfxItemPool & rPool = pObj1->GetObjectItemPool();
+ SfxItemSet aSet1( rPool );
+ SfxItemSet aSet2( rPool );
+
+ aSet1.Put(pObj1->GetMergedItemSet());
+ aSet2.Put(pObj2->GetMergedItemSet());
+
+ const drawing::LineStyle eLineStyle1 = aSet1.Get( XATTR_LINESTYLE ).GetValue();
+ const drawing::LineStyle eLineStyle2 = aSet2.Get( XATTR_LINESTYLE ).GetValue();
+ const drawing::FillStyle eFillStyle1 = aSet1.Get( XATTR_FILLSTYLE ).GetValue();
+ const drawing::FillStyle eFillStyle2 = aSet2.Get( XATTR_FILLSTYLE ).GetValue();
+
+ if ( ( ( eLineStyle1 == drawing::LineStyle_NONE ) || ( eLineStyle2 == drawing::LineStyle_NONE ) ) &&
+ ( ( eFillStyle1 != drawing::FillStyle_SOLID ) || ( eFillStyle2 != drawing::FillStyle_SOLID ) ) )
+ {
+ m_xCbxAttributes->set_sensitive(false);
+ }
+}
+
+MorphDlg::~MorphDlg()
+{
+}
+
+void MorphDlg::LoadSettings()
+{
+ tools::SvRef<SotStorageStream> xIStm( SD_MOD()->GetOptionStream( SD_OPTION_MORPHING ,
+ SdOptionStreamMode::Load ) );
+ sal_uInt16 nSteps;
+ bool bOrient, bAttrib;
+
+ if( xIStm.is() )
+ {
+ SdIOCompat aCompat( *xIStm, StreamMode::READ );
+
+ xIStm->ReadUInt16( nSteps ).ReadCharAsBool( bOrient ).ReadCharAsBool( bAttrib );
+ }
+ else
+ {
+ nSteps = 16;
+ bOrient = bAttrib = true;
+ }
+
+ m_xMtfSteps->set_value(nSteps);
+ m_xCbxOrientation->set_active(bOrient);
+ m_xCbxAttributes->set_active(bAttrib);
+}
+
+void MorphDlg::SaveSettings() const
+{
+ tools::SvRef<SotStorageStream> xOStm( SD_MOD()->GetOptionStream( SD_OPTION_MORPHING ,
+ SdOptionStreamMode::Store ) );
+
+ if( xOStm.is() )
+ {
+ SdIOCompat aCompat( *xOStm, StreamMode::WRITE, 1 );
+
+ xOStm->WriteUInt16( m_xMtfSteps->get_value() )
+ .WriteBool( m_xCbxOrientation->get_active() )
+ .WriteBool( m_xCbxAttributes->get_active() );
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/navigatr.cxx b/sd/source/ui/dlg/navigatr.cxx
new file mode 100644
index 000000000..78525efe5
--- /dev/null
+++ b/sd/source/ui/dlg/navigatr.cxx
@@ -0,0 +1,735 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+
+#include <osl/file.hxx>
+#include <tools/urlobj.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/docfile.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/dispatch.hxx>
+
+#include <sfx2/viewfrm.hxx>
+
+#include <pres.hxx>
+#include <navigatr.hxx>
+#include <pgjump.hxx>
+#include <app.hrc>
+
+#include <bitmaps.hlst>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <slideshow.hxx>
+#include <FrameView.hxx>
+#include <Window.hxx>
+
+#include <DrawViewShell.hxx>
+
+/**
+ * SdNavigatorWin - FloatingWindow
+ */
+SdNavigatorWin::SdNavigatorWin(weld::Widget* pParent, SfxBindings* pInBindings, SfxNavigator* pNavigatorDlg)
+ : PanelLayout(pParent, "NavigatorPanel", "modules/simpress/ui/navigatorpanel.ui")
+ , mxToolbox(m_xBuilder->weld_toolbar("toolbox"))
+ , mxTlbObjects(new SdPageObjsTLV(m_xBuilder->weld_tree_view("tree")))
+ , mxLbDocs(m_xBuilder->weld_combo_box("documents"))
+ , mxDragModeMenu(m_xBuilder->weld_menu("dragmodemenu"))
+ , mxShapeMenu(m_xBuilder->weld_menu("shapemenu"))
+ , mxNavigatorDlg(pNavigatorDlg)
+ , mbDocImported ( false )
+ // On changes of the DragType: adjust SelectionMode of TLB!
+ , meDragType ( NAVIGATOR_DRAGTYPE_EMBEDDED )
+ , mpBindings ( pInBindings )
+{
+ mxTlbObjects->SetViewFrame( mpBindings->GetDispatcher()->GetFrame() );
+
+ mxTlbObjects->connect_row_activated(LINK(this, SdNavigatorWin, ClickObjectHdl));
+ mxTlbObjects->set_selection_mode(SelectionMode::Single);
+
+ mxToolbox->connect_clicked(LINK(this, SdNavigatorWin, SelectToolboxHdl));
+ mxToolbox->connect_menu_toggled(LINK(this, SdNavigatorWin, DropdownClickToolBoxHdl));
+
+ mxToolbox->set_item_menu("dragmode", mxDragModeMenu.get());
+ mxDragModeMenu->connect_activate(LINK(this, SdNavigatorWin, MenuSelectHdl));
+
+ // Shape filter drop down menu.
+ mxToolbox->set_item_menu("shapes", mxShapeMenu.get());
+ mxShapeMenu->connect_activate(LINK(this, SdNavigatorWin, ShapeFilterCallback));
+
+ mxTlbObjects->SetSdNavigator(this);
+
+ // DragTypeListBox
+ mxLbDocs->set_size_request(42, -1); // set a nominal width so it takes width of surroundings
+ mxLbDocs->connect_changed(LINK(this, SdNavigatorWin, SelectDocumentHdl));
+
+ SetDragImage();
+
+ mxToolbox->connect_key_press(LINK(this, SdNavigatorWin, KeyInputHdl));
+ mxTlbObjects->connect_key_press(LINK(this, SdNavigatorWin, KeyInputHdl));
+ mxLbDocs->connect_key_press(LINK(this, SdNavigatorWin, KeyInputHdl));
+}
+
+void SdNavigatorWin::FirstFocus()
+{
+ // set focus to listbox, otherwise it is in the toolbox which is only useful
+ // for keyboard navigation
+ mxTlbObjects->grab_focus();
+}
+
+weld::Window* SdNavigatorWin::GetFrameWeld() const
+{
+ if (mxNavigatorDlg)
+ return mxNavigatorDlg->GetFrameWeld();
+ return PanelLayout::GetFrameWeld();
+}
+
+void SdNavigatorWin::SetUpdateRequestFunctor(const UpdateRequestFunctor& rUpdateRequest)
+{
+ mpNavigatorCtrlItem.reset( new SdNavigatorControllerItem(SID_NAVIGATOR_STATE, this, mpBindings, rUpdateRequest) );
+ mpPageNameCtrlItem.reset( new SdPageNameControllerItem(SID_NAVIGATOR_PAGENAME, this, mpBindings) );
+
+ // InitTlb; is initiated over Slot
+ if (rUpdateRequest)
+ rUpdateRequest();
+}
+
+SdNavigatorWin::~SdNavigatorWin()
+{
+ mpNavigatorCtrlItem.reset();
+ mpPageNameCtrlItem.reset();
+ mxDragModeMenu.reset();
+ mxShapeMenu.reset();
+ mxToolbox.reset();
+ mxTlbObjects.reset();
+ mxLbDocs.reset();
+}
+
+//when object is marked , fresh the corresponding entry tree .
+void SdNavigatorWin::FreshTree( const SdDrawDocument* pDoc )
+{
+ SdDrawDocument* pNonConstDoc = const_cast<SdDrawDocument*>(pDoc); // const as const can...
+ sd::DrawDocShell* pDocShell = pNonConstDoc->GetDocSh();
+ const OUString& aDocShName( pDocShell->GetName() );
+ OUString aDocName = pDocShell->GetMedium()->GetName();
+ mxTlbObjects->Fill( pDoc, false, aDocName ); // Only normal pages
+ RefreshDocumentLB();
+ mxLbDocs->set_active_text(aDocShName);
+}
+
+void SdNavigatorWin::InitTreeLB( const SdDrawDocument* pDoc )
+{
+ SdDrawDocument* pNonConstDoc = const_cast<SdDrawDocument*>(pDoc); // const as const can...
+ ::sd::DrawDocShell* pDocShell = pNonConstDoc->GetDocSh();
+ OUString aDocShName( pDocShell->GetName() );
+ ::sd::ViewShell* pViewShell = pDocShell->GetViewShell();
+
+ // Restore the 'ShowAllShapes' flag from the last time (in this session)
+ // that the navigator was shown.
+ if (pViewShell != nullptr)
+ {
+ ::sd::FrameView* pFrameView = pViewShell->GetFrameView();
+ if (pFrameView != nullptr)
+ mxTlbObjects->SetShowAllShapes(pFrameView->IsNavigatorShowingAllShapes(), false);
+ }
+
+ // Disable the shape filter drop down menu when there is a running slide
+ // show.
+ if (pViewShell!=nullptr && sd::SlideShow::IsRunning( pViewShell->GetViewShellBase() ))
+ mxToolbox->set_item_sensitive("shapes", false);
+ else
+ mxToolbox->set_item_sensitive("shapes", true);
+
+ if( !mxTlbObjects->IsEqualToDoc( pDoc ) )
+ {
+ OUString aDocName = pDocShell->GetMedium()->GetName();
+ mxTlbObjects->clear();
+ mxTlbObjects->Fill( pDoc, false, aDocName ); // only normal pages
+
+ RefreshDocumentLB();
+ mxLbDocs->set_active_text(aDocShName);
+ }
+ else
+ {
+ mxLbDocs->set_active(-1);
+ mxLbDocs->set_active_text(aDocShName);
+
+// commented in order to fix 30246
+// if( mxLbDocs->get_active() == -1 )
+ {
+ RefreshDocumentLB();
+ mxLbDocs->set_active_text(aDocShName);
+ }
+ }
+
+ SfxViewFrame* pViewFrame = ( ( pViewShell && pViewShell->GetViewFrame() ) ? pViewShell->GetViewFrame() : SfxViewFrame::Current() );
+ if( pViewFrame )
+ pViewFrame->GetBindings().Invalidate(SID_NAVIGATOR_PAGENAME, true, true);
+}
+
+/**
+ * DragType is set on dependence if a Drag is even possible. For example,
+ * under certain circumstances, it is not allowed to drag graphics (#31038#).
+ */
+NavigatorDragType SdNavigatorWin::GetNavigatorDragType()
+{
+ NavigatorDragType eDT = meDragType;
+ NavDocInfo* pInfo = GetDocInfo();
+
+ if( ( eDT == NAVIGATOR_DRAGTYPE_LINK ) && ( ( pInfo && !pInfo->HasName() ) || !mxTlbObjects->IsLinkableSelected() ) )
+ eDT = NAVIGATOR_DRAGTYPE_NONE;
+
+ return eDT;
+}
+
+SdPageObjsTLV& SdNavigatorWin::GetObjects()
+{
+ return *mxTlbObjects;
+}
+
+IMPL_LINK(SdNavigatorWin, SelectToolboxHdl, const OString&, rCommand, void)
+{
+ PageJump ePage = PAGE_NONE;
+
+ if (rCommand == "first")
+ ePage = PAGE_FIRST;
+ else if (rCommand == "previous")
+ ePage = PAGE_PREVIOUS;
+ else if (rCommand == "next")
+ ePage = PAGE_NEXT;
+ else if (rCommand == "last")
+ ePage = PAGE_LAST;
+ else if (rCommand == "dragmode")
+ mxToolbox->set_menu_item_active("dragmode", !mxToolbox->get_menu_item_active("dragmode"));
+ else if (rCommand == "shapes")
+ mxToolbox->set_menu_item_active("shapes", !mxToolbox->get_menu_item_active("shapes"));
+
+ if (ePage != PAGE_NONE)
+ {
+ SfxUInt16Item aItem( SID_NAVIGATOR_PAGE, static_cast<sal_uInt16>(ePage) );
+ mpBindings->GetDispatcher()->ExecuteList(SID_NAVIGATOR_PAGE,
+ SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
+ }
+}
+
+IMPL_LINK(SdNavigatorWin, DropdownClickToolBoxHdl, const OString&, rCommand, void)
+{
+ if (!mxToolbox->get_menu_item_active(rCommand))
+ return;
+
+ if (rCommand == "dragmode")
+ {
+ NavDocInfo* pInfo = GetDocInfo();
+ if( ( pInfo && !pInfo->HasName() ) || !mxTlbObjects->IsLinkableSelected() )
+ {
+ mxDragModeMenu->set_sensitive(OString::number(NAVIGATOR_DRAGTYPE_LINK), false);
+ mxDragModeMenu->set_sensitive(OString::number(NAVIGATOR_DRAGTYPE_URL), false);
+ meDragType = NAVIGATOR_DRAGTYPE_EMBEDDED;
+ }
+
+ mxDragModeMenu->set_active(OString::number(meDragType), true);
+ }
+ else if (rCommand == "shapes")
+ {
+ bool bAll = mxTlbObjects->GetShowAllShapes();
+ mxShapeMenu->set_active("named", !bAll);
+ mxShapeMenu->set_active("all", bAll);
+ }
+}
+
+IMPL_LINK_NOARG(SdNavigatorWin, ClickObjectHdl, weld::TreeView&, bool)
+{
+ if( !mbDocImported || mxLbDocs->get_active() != 0 )
+ {
+ NavDocInfo* pInfo = GetDocInfo();
+
+ // if it is the active window, we jump to the page
+ if( pInfo && pInfo->IsActive() )
+ {
+ OUString aStr(mxTlbObjects->get_selected_text());
+
+ if( !aStr.isEmpty() )
+ {
+ SfxStringItem aItem( SID_NAVIGATOR_OBJECT, aStr );
+ mpBindings->GetDispatcher()->ExecuteList(
+ SID_NAVIGATOR_OBJECT,
+ SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
+
+ // moved here from SetGetFocusHdl. Reset the
+ // focus only if something has been selected in the
+ // document.
+ SfxViewShell* pCurSh = SfxViewShell::Current();
+
+ if ( pCurSh )
+ {
+ vcl::Window* pShellWnd = pCurSh->GetWindow();
+ if ( pShellWnd )
+ pShellWnd->GrabFocus();
+ }
+
+ // We navigated to an object, but the current shell may be
+ // still the slide sorter. Explicitly try to grab the draw
+ // shell focus, so follow-up operations work with the object
+ // and not with the whole slide.
+ sd::DrawDocShell* pDocShell = pInfo->mpDocShell;
+ if (pDocShell)
+ {
+ sd::ViewShell* pViewShell = pDocShell->GetViewShell();
+ if (pViewShell)
+ {
+ vcl::Window* pWindow = pViewShell->GetActiveWindow();
+ if (pWindow)
+ pWindow->GrabFocus();
+ }
+ }
+
+ if (!mxTlbObjects->IsNavigationGrabsFocus())
+ // This is the case when keyboard navigation inside the
+ // navigator should continue to work.
+ mxTlbObjects->grab_focus();
+ }
+ }
+ }
+ return false;
+}
+
+IMPL_LINK_NOARG(SdNavigatorWin, SelectDocumentHdl, weld::ComboBox&, void)
+{
+ OUString aStrLb = mxLbDocs->get_active_text();
+ tools::Long nPos = mxLbDocs->get_active();
+ bool bFound = false;
+ ::sd::DrawDocShell* pDocShell = nullptr;
+ NavDocInfo* pInfo = GetDocInfo();
+
+ // is it a dragged object?
+ if( mbDocImported && nPos == 0 )
+ {
+ // construct document in TLB
+ InsertFile( aStrLb );
+ }
+ else if (pInfo)
+ {
+ pDocShell = pInfo->mpDocShell;
+
+ bFound = true;
+ }
+
+ if( bFound )
+ {
+ SdDrawDocument* pDoc = pDocShell->GetDoc();
+ if( !mxTlbObjects->IsEqualToDoc( pDoc ) )
+ {
+ SdDrawDocument* pNonConstDoc = pDoc; // const as const can...
+ ::sd::DrawDocShell* pNCDocShell = pNonConstDoc->GetDocSh();
+ OUString aDocName = pNCDocShell->GetMedium()->GetName();
+ mxTlbObjects->clear();
+ mxTlbObjects->Fill( pDoc, false, aDocName ); // only normal pages
+ }
+ }
+
+ // check if link or url is possible
+ if( ( pInfo && !pInfo->HasName() ) || !mxTlbObjects->IsLinkableSelected() || ( meDragType != NAVIGATOR_DRAGTYPE_EMBEDDED ) )
+ {
+ meDragType = NAVIGATOR_DRAGTYPE_EMBEDDED;
+ SetDragImage();
+ }
+}
+
+/**
+ * Set DrageType and set image accordingly to it.
+ */
+IMPL_LINK(SdNavigatorWin, MenuSelectHdl, const OString&, rIdent, void)
+{
+ sal_uInt32 nMenuId = rIdent.toUInt32();
+
+ NavigatorDragType eDT = static_cast<NavigatorDragType>(nMenuId);
+ if( meDragType == eDT )
+ return;
+
+ meDragType = eDT;
+ SetDragImage();
+
+ if( meDragType == NAVIGATOR_DRAGTYPE_URL )
+ {
+ // patch, prevents endless loop
+ if (mxTlbObjects->count_selected_rows() > 1)
+ mxTlbObjects->unselect_all();
+
+ mxTlbObjects->set_selection_mode(SelectionMode::Single);
+ }
+ else
+ mxTlbObjects->set_selection_mode(SelectionMode::Multiple);
+}
+
+IMPL_LINK( SdNavigatorWin, ShapeFilterCallback, const OString&, rIdent, void )
+{
+ bool bShowAllShapes(mxTlbObjects->GetShowAllShapes());
+ if (rIdent == "named")
+ bShowAllShapes = false;
+ else if (rIdent == "all")
+ bShowAllShapes = true;
+ else
+ OSL_FAIL("SdNavigatorWin::ShapeFilterCallback called for unknown menu entry");
+
+ mxTlbObjects->SetShowAllShapes(bShowAllShapes, true);
+
+ // Remember the selection in the FrameView.
+ NavDocInfo* pInfo = GetDocInfo();
+ if (pInfo == nullptr)
+ return;
+
+ ::sd::DrawDocShell* pDocShell = pInfo->mpDocShell;
+ if (pDocShell != nullptr)
+ {
+ ::sd::ViewShell* pViewShell = pDocShell->GetViewShell();
+ if (pViewShell != nullptr)
+ {
+ ::sd::FrameView* pFrameView = pViewShell->GetFrameView();
+ if (pFrameView != nullptr)
+ {
+ pFrameView->SetIsNavigatorShowingAllShapes(bShowAllShapes);
+ }
+ }
+ }
+}
+
+bool SdNavigatorWin::InsertFile(const OUString& rFileName)
+{
+ INetURLObject aURL( rFileName );
+
+ if( aURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ OUString aURLStr;
+ osl::FileBase::getFileURLFromSystemPath( rFileName, aURLStr );
+ aURL = INetURLObject( aURLStr );
+ }
+
+ // get adjusted FileName
+ OUString aFileName( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ if (aFileName.isEmpty())
+ {
+ // show actual document again
+ maDropFileName = aFileName;
+ }
+ else
+ {
+ // show dragged-in document
+ std::shared_ptr<const SfxFilter> pFilter;
+ ErrCode nErr = ERRCODE_NONE;
+
+ if (aFileName != maDropFileName)
+ {
+ SfxMedium aMed(aFileName, (StreamMode::READ | StreamMode::SHARE_DENYNONE));
+ SfxFilterMatcher aMatch( "simpress" );
+ aMed.UseInteractionHandler( true );
+ nErr = aMatch.GuessFilter(aMed, pFilter);
+ }
+
+ if ((pFilter && !nErr) || aFileName == maDropFileName)
+ {
+ // The medium may be opened with READ/WRITE. Therefore, we first
+ // check if it contains a Storage.
+ std::unique_ptr<SfxMedium> xMedium(new SfxMedium(aFileName,
+ StreamMode::READ | StreamMode::NOCREATE));
+
+ if (xMedium->IsStorage())
+ {
+ // Now depending on mode:
+ // mxTlbObjects->set_selection_mode(SelectionMode::Multiple);
+ // handover of ownership of xMedium;
+ SdDrawDocument* pDropDoc = mxTlbObjects->GetBookmarkDoc(xMedium.release());
+
+ if (pDropDoc)
+ {
+ mxTlbObjects->clear();
+ maDropFileName = aFileName;
+
+ if( !mxTlbObjects->IsEqualToDoc( pDropDoc ) )
+ {
+ // only normal pages
+ mxTlbObjects->Fill(pDropDoc, false, maDropFileName);
+ RefreshDocumentLB( &maDropFileName );
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void SdNavigatorWin::RefreshDocumentLB( const OUString* pDocName )
+{
+ sal_Int32 nPos = 0;
+
+ if( pDocName )
+ {
+ if( mbDocImported )
+ mxLbDocs->remove(0);
+
+ mxLbDocs->insert_text(0, *pDocName);
+ mbDocImported = true;
+ }
+ else
+ {
+ nPos = mxLbDocs->get_active();
+ if (nPos == -1)
+ nPos = 0;
+
+ OUString aStr;
+ if( mbDocImported )
+ aStr = mxLbDocs->get_text(0);
+
+ mxLbDocs->clear();
+
+ // delete list of DocInfos
+ maDocList.clear();
+
+ if( mbDocImported )
+ mxLbDocs->insert_text(0, aStr);
+
+ ::sd::DrawDocShell* pCurrentDocShell =
+ dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
+ SfxObjectShell* pSfxDocShell = SfxObjectShell::GetFirst([](const SfxObjectShell*){return true;}, false);
+ while( pSfxDocShell )
+ {
+ ::sd::DrawDocShell* pDocShell = dynamic_cast< ::sd::DrawDocShell *>( pSfxDocShell );
+ if( pDocShell && !pDocShell->IsInDestruction() && ( pDocShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED ) )
+ {
+ NavDocInfo aInfo ;
+ aInfo.mpDocShell = pDocShell;
+
+ SfxMedium *pMedium = pDocShell->GetMedium();
+ aStr = pMedium ? pMedium->GetName() : OUString();
+ if( !aStr.isEmpty() )
+ aInfo.SetName( true );
+ else
+ aInfo.SetName( false );
+ // at the moment, we use the name of the shell again (i.e.
+ // without path) since Koose thinks it is an error if the path
+ // is shown in url notation!
+ aStr = pDocShell->GetName();
+
+ mxLbDocs->append_text(aStr);
+
+ if( pDocShell == pCurrentDocShell )
+ aInfo.SetActive( true );
+ else
+ aInfo.SetActive( false );
+
+ maDocList.push_back( aInfo );
+ }
+ pSfxDocShell = SfxObjectShell::GetNext( *pSfxDocShell, [](const SfxObjectShell*){return true;}, false );
+ }
+ }
+ mxLbDocs->set_active(nPos);
+}
+
+OUString SdNavigatorWin::GetDragTypeSdBmpId(NavigatorDragType eDT)
+{
+ switch( eDT )
+ {
+ case NAVIGATOR_DRAGTYPE_NONE:
+ return OUString();
+ case NAVIGATOR_DRAGTYPE_URL:
+ return BMP_HYPERLINK;
+ case NAVIGATOR_DRAGTYPE_EMBEDDED:
+ return BMP_EMBEDDED;
+ case NAVIGATOR_DRAGTYPE_LINK:
+ return BMP_LINK;
+ default: OSL_FAIL( "No resource for DragType available!" );
+ }
+ return OUString();
+}
+
+NavDocInfo* SdNavigatorWin::GetDocInfo()
+{
+ sal_uInt32 nPos = mxLbDocs->get_active();
+
+ if( mbDocImported )
+ {
+ if( nPos == 0 )
+ {
+ return nullptr;
+ }
+ nPos--;
+ }
+
+ return nPos < maDocList.size() ? &(maDocList[ nPos ]) : nullptr;
+}
+
+/**
+ * catch ESCAPE in order to end show
+ */
+IMPL_LINK(SdNavigatorWin, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bConsumed = false;
+
+ if (KEY_ESCAPE == rKEvt.GetKeyCode().GetCode())
+ {
+ // during drag'n'drop we just stop the drag but do not close the navigator
+ if (!SdPageObjsTLV::IsInDrag())
+ {
+ ::sd::ViewShellBase* pBase = ::sd::ViewShellBase::GetViewShellBase( mpBindings->GetDispatcher()->GetFrame());
+ if (pBase)
+ sd::SlideShow::Stop(*pBase);
+ bConsumed = true;
+ }
+ }
+
+ return bConsumed;
+}
+
+void SdNavigatorWin::SetDragImage()
+{
+ mxToolbox->set_item_icon_name("dragmode", GetDragTypeSdBmpId(meDragType));
+}
+
+/**
+ * ControllerItem for Navigator
+ */
+SdNavigatorControllerItem::SdNavigatorControllerItem(
+ sal_uInt16 _nId,
+ SdNavigatorWin* pNavWin,
+ SfxBindings* _pBindings,
+ const SdNavigatorWin::UpdateRequestFunctor& rUpdateRequest)
+ : SfxControllerItem( _nId, *_pBindings ),
+ pNavigatorWin( pNavWin ),
+ maUpdateRequest(rUpdateRequest)
+{
+}
+
+void SdNavigatorControllerItem::StateChangedAtToolBoxControl( sal_uInt16 nSId,
+ SfxItemState eState, const SfxPoolItem* pItem )
+{
+ if( eState < SfxItemState::DEFAULT || nSId != SID_NAVIGATOR_STATE )
+ return;
+
+ // only if doc in LB is the active
+ NavDocInfo* pInfo = pNavigatorWin->GetDocInfo();
+ if( !(pInfo && pInfo->IsActive()) )
+ return;
+
+ if (::sd::DrawDocShell* pDrawDocShell = pInfo->GetDrawDocShell())
+ {
+ const auto pDrawViewShell =
+ static_cast<::sd::DrawViewShell *>(pDrawDocShell->GetViewShell());
+ if (pDrawViewShell)
+ {
+ bool bEditModePage(pDrawViewShell->GetEditMode() == EditMode::Page);
+ pNavigatorWin->mxToolbox->set_sensitive(bEditModePage);
+ pNavigatorWin->mxLbDocs->set_sensitive(bEditModePage);
+ pNavigatorWin->mxTlbObjects->set_sensitive(bEditModePage);
+ }
+ }
+
+ const SfxUInt32Item& rStateItem = dynamic_cast<const SfxUInt32Item&>(*pItem);
+ NavState nState = static_cast<NavState>(rStateItem.GetValue());
+
+ // First
+ if (nState & NavState::BtnFirstEnabled &&
+ !pNavigatorWin->mxToolbox->get_item_sensitive("first"))
+ pNavigatorWin->mxToolbox->set_item_sensitive("first", true);
+ if (nState & NavState::BtnFirstDisabled &&
+ pNavigatorWin->mxToolbox->get_item_sensitive("first"))
+ pNavigatorWin->mxToolbox->set_item_sensitive("first", false);
+
+ // Prev
+ if (nState & NavState::BtnPrevEnabled &&
+ !pNavigatorWin->mxToolbox->get_item_sensitive("previous"))
+ pNavigatorWin->mxToolbox->set_item_sensitive("previous", true);
+ if (nState & NavState::BtnPrevDisabled &&
+ pNavigatorWin->mxToolbox->get_item_sensitive("previous"))
+ pNavigatorWin->mxToolbox->set_item_sensitive("previous", false);
+
+ // Last
+ if (nState & NavState::BtnLastEnabled &&
+ !pNavigatorWin->mxToolbox->get_item_sensitive("last"))
+ pNavigatorWin->mxToolbox->set_item_sensitive("last", true);
+ if (nState & NavState::BtnLastDisabled &&
+ pNavigatorWin->mxToolbox->get_item_sensitive("last"))
+ pNavigatorWin->mxToolbox->set_item_sensitive("last", false);
+
+ // Next
+ if (nState & NavState::BtnNextEnabled &&
+ !pNavigatorWin->mxToolbox->get_item_sensitive("next"))
+ pNavigatorWin->mxToolbox->set_item_sensitive("next", true);
+ if (nState & NavState::BtnNextDisabled &&
+ pNavigatorWin->mxToolbox->get_item_sensitive("next"))
+ pNavigatorWin->mxToolbox->set_item_sensitive("next", false);
+
+ if (nState & NavState::TableUpdate)
+ {
+ // InitTlb; is initiated by Slot
+ if (maUpdateRequest)
+ maUpdateRequest();
+ }
+}
+
+/**
+ * ControllerItem for Navigator to show page in TreeLB
+ */
+SdPageNameControllerItem::SdPageNameControllerItem(
+ sal_uInt16 _nId,
+ SdNavigatorWin* pNavWin,
+ SfxBindings* _pBindings)
+ : SfxControllerItem( _nId, *_pBindings ),
+ pNavigatorWin( pNavWin )
+{
+}
+
+void SdPageNameControllerItem::StateChangedAtToolBoxControl( sal_uInt16 nSId,
+ SfxItemState eState, const SfxPoolItem* pItem )
+{
+ if( eState < SfxItemState::DEFAULT || nSId != SID_NAVIGATOR_PAGENAME )
+ return;
+
+ // only if doc in LB is the active
+ NavDocInfo* pInfo = pNavigatorWin->GetDocInfo();
+ if( !(pInfo && pInfo->IsActive()) )
+ return;
+
+ const SfxStringItem& rStateItem = dynamic_cast<const SfxStringItem&>(*pItem);
+ const OUString& aPageName = rStateItem.GetValue();
+
+ if( !pNavigatorWin->mxTlbObjects->HasSelectedChildren( aPageName ) )
+ {
+ if (pNavigatorWin->mxTlbObjects->get_selection_mode() == SelectionMode::Multiple)
+ {
+ // because otherwise it is always additional select
+ pNavigatorWin->mxTlbObjects->unselect_all();
+ }
+ pNavigatorWin->mxTlbObjects->SelectEntry( aPageName );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/paragr.cxx b/sd/source/ui/dlg/paragr.cxx
new file mode 100644
index 000000000..be9df558e
--- /dev/null
+++ b/sd/source/ui/dlg/paragr.cxx
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/cjkoptions.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+
+#include <svx/dialogs.hrc>
+#include <svx/svxids.hrc>
+#include <svx/flagsdef.hxx>
+#include <svx/xcolit.hxx>
+
+#include <paragr.hxx>
+#include <sdattr.hrc>
+
+namespace {
+
+class SdParagraphNumTabPage : public SfxTabPage
+{
+public:
+ SdParagraphNumTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet);
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet );
+
+ static WhichRangesContainer GetRanges();
+
+ virtual bool FillItemSet( SfxItemSet* rSet ) override;
+ virtual void Reset( const SfxItemSet* rSet ) override;
+
+private:
+ bool mbModified;
+ std::unique_ptr<weld::CheckButton> m_xNewStartCB;
+ std::unique_ptr<weld::CheckButton> m_xNewStartNumberCB;
+ std::unique_ptr<weld::SpinButton> m_xNewStartNF;
+
+ DECL_LINK( ImplNewStartHdl, weld::Toggleable&, void );
+};
+
+}
+
+SdParagraphNumTabPage::SdParagraphNumTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttr)
+ : SfxTabPage(pPage, pController, "modules/sdraw/ui/paranumberingtab.ui", "DrawParaNumbering", &rAttr)
+ , mbModified(false)
+ , m_xNewStartCB(m_xBuilder->weld_check_button("checkbuttonCB_NEW_START"))
+ , m_xNewStartNumberCB(m_xBuilder->weld_check_button("checkbuttonCB_NUMBER_NEW_START"))
+ , m_xNewStartNF(m_xBuilder->weld_spin_button("spinbuttonNF_NEW_START"))
+{
+ m_xNewStartCB->connect_toggled(LINK(this, SdParagraphNumTabPage, ImplNewStartHdl));
+ m_xNewStartNumberCB->connect_toggled(LINK(this, SdParagraphNumTabPage, ImplNewStartHdl));
+}
+
+std::unique_ptr<SfxTabPage> SdParagraphNumTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet * rAttrSet)
+{
+ return std::make_unique<SdParagraphNumTabPage>(pPage, pController, *rAttrSet);
+}
+
+WhichRangesContainer SdParagraphNumTabPage::GetRanges()
+{
+ return WhichRangesContainer(svl::Items<ATTR_PARANUMBERING_START, ATTR_PARANUMBERING_END>);
+}
+
+bool SdParagraphNumTabPage::FillItemSet( SfxItemSet* rSet )
+{
+ if (m_xNewStartCB->get_state_changed_from_saved() ||
+ m_xNewStartNumberCB->get_state_changed_from_saved()||
+ m_xNewStartNF->get_value_changed_from_saved())
+ {
+ mbModified = true;
+ bool bNewStartChecked = TRISTATE_TRUE == m_xNewStartCB->get_state();
+ bool bNumberNewStartChecked = TRISTATE_TRUE == m_xNewStartNumberCB->get_state();
+ rSet->Put(SfxBoolItem(ATTR_NUMBER_NEWSTART, bNewStartChecked));
+
+ const sal_Int16 nStartAt = static_cast<sal_Int16>(m_xNewStartNF->get_value());
+ rSet->Put(SfxInt16Item(ATTR_NUMBER_NEWSTART_AT, bNumberNewStartChecked && bNewStartChecked ? nStartAt : -1));
+ }
+
+ return mbModified;
+}
+
+void SdParagraphNumTabPage::Reset( const SfxItemSet* rSet )
+{
+ SfxItemState eItemState = rSet->GetItemState( ATTR_NUMBER_NEWSTART );
+ if(eItemState > SfxItemState::DEFAULT )
+ {
+ const SfxBoolItem& rStart = rSet->Get(ATTR_NUMBER_NEWSTART);
+ m_xNewStartCB->set_state( rStart.GetValue() ? TRISTATE_TRUE : TRISTATE_FALSE );
+ }
+ else
+ {
+ m_xNewStartCB->set_state(TRISTATE_INDET);
+ m_xNewStartCB->set_sensitive(false);
+ }
+ m_xNewStartCB->save_state();
+
+ eItemState = rSet->GetItemState( ATTR_NUMBER_NEWSTART_AT);
+ if( eItemState > SfxItemState::DEFAULT )
+ {
+ sal_Int16 nNewStart = rSet->Get(ATTR_NUMBER_NEWSTART_AT).GetValue();
+ m_xNewStartNumberCB->set_active(-1 != nNewStart);
+ if(-1 == nNewStart)
+ nNewStart = 1;
+
+ m_xNewStartNF->set_value(nNewStart);
+ }
+ else
+ {
+ m_xNewStartCB->set_state(TRISTATE_INDET);
+ }
+ ImplNewStartHdl(*m_xNewStartCB);
+ m_xNewStartNF->save_value();
+ m_xNewStartNumberCB->save_state();
+ mbModified = false;
+}
+
+IMPL_LINK_NOARG(SdParagraphNumTabPage, ImplNewStartHdl, weld::Toggleable&, void)
+{
+ bool bEnable = m_xNewStartCB->get_active();
+ m_xNewStartNumberCB->set_sensitive(bEnable);
+ m_xNewStartNF->set_sensitive(bEnable && m_xNewStartNumberCB->get_active());
+}
+
+SdParagraphDlg::SdParagraphDlg(weld::Window* pParent, const SfxItemSet* pAttr)
+ : SfxTabDialogController(pParent, "modules/sdraw/ui/drawparadialog.ui",
+ "DrawParagraphPropertiesDialog", pAttr)
+{
+ AddTabPage( "labelTP_PARA_STD", RID_SVXPAGE_STD_PARAGRAPH);
+
+ if( SvtCJKOptions::IsAsianTypographyEnabled() )
+ AddTabPage( "labelTP_PARA_ASIAN", RID_SVXPAGE_PARA_ASIAN);
+ else
+ RemoveTabPage( "labelTP_PARA_ASIAN" );
+
+ AddTabPage( "labelTP_PARA_ALIGN", RID_SVXPAGE_ALIGN_PARAGRAPH);
+
+ static const bool bShowParaNumbering = ( getenv( "SD_SHOW_NUMBERING_PAGE" ) != nullptr );
+ if( bShowParaNumbering )
+ AddTabPage( "labelNUMBERING", SdParagraphNumTabPage::Create, SdParagraphNumTabPage::GetRanges );
+ else
+ RemoveTabPage( "labelNUMBERING" );
+
+ AddTabPage("labelTP_TABULATOR", RID_SVXPAGE_TABULATOR);
+}
+
+void SdParagraphDlg::PageCreated(const OString& rId, SfxTabPage &rPage)
+{
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ if (rId == "labelTP_PARA_STD")
+ {
+ aSet.Put(SfxUInt32Item(SID_SVXSTDPARAGRAPHTABPAGE_ABSLINEDIST, MM50/2));
+ rPage.PageCreated(aSet);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/present.cxx b/sd/source/ui/dlg/present.cxx
new file mode 100644
index 000000000..73932ba62
--- /dev/null
+++ b/sd/source/ui/dlg/present.cxx
@@ -0,0 +1,323 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/itemset.hxx>
+#include <svl/intitem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/svapp.hxx>
+
+#include <sdattr.hrc>
+#include <present.hxx>
+#include <cusshow.hxx>
+#include <customshowlist.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+SdStartPresentationDlg::SdStartPresentationDlg(weld::Window* pWindow, const SfxItemSet& rInAttrs,
+ const std::vector<OUString> &rPageNames, SdCustomShowList* pCSList)
+ : GenericDialogController(pWindow, "modules/simpress/ui/presentationdialog.ui", "PresentationDialog")
+ , pCustomShowList(pCSList)
+ , rOutAttrs(rInAttrs)
+ , mnMonitors(0)
+ , m_xRbtAll(m_xBuilder->weld_radio_button("allslides"))
+ , m_xRbtAtDia(m_xBuilder->weld_radio_button("from"))
+ , m_xRbtCustomshow(m_xBuilder->weld_radio_button("customslideshow"))
+ , m_xLbDias(m_xBuilder->weld_combo_box("from_cb"))
+ , m_xLbCustomshow(m_xBuilder->weld_combo_box("customslideshow_cb"))
+ , m_xRbtStandard(m_xBuilder->weld_radio_button("default"))
+ , m_xRbtWindow(m_xBuilder->weld_radio_button("window"))
+ , m_xRbtAuto(m_xBuilder->weld_radio_button("auto"))
+ , m_xTmfPause(m_xBuilder->weld_formatted_spin_button("pauseduration"))
+ , m_xFormatter(new weld::TimeFormatter(*m_xTmfPause))
+ , m_xCbxAutoLogo(m_xBuilder->weld_check_button("showlogo"))
+ , m_xCbxManuel(m_xBuilder->weld_check_button("manualslides"))
+ , m_xCbxMousepointer(m_xBuilder->weld_check_button("pointervisible"))
+ , m_xCbxPen(m_xBuilder->weld_check_button("pointeraspen"))
+ , m_xCbxAnimationAllowed(m_xBuilder->weld_check_button("animationsallowed"))
+ , m_xCbxChangePage(m_xBuilder->weld_check_button("changeslidesbyclick"))
+ , m_xCbxAlwaysOnTop(m_xBuilder->weld_check_button("alwaysontop"))
+ , m_xFtMonitor(m_xBuilder->weld_label("presdisplay_label"))
+ , m_xLBMonitor(m_xBuilder->weld_combo_box("presdisplay_cb"))
+ , m_xMonitor(m_xBuilder->weld_label("monitor_str"))
+ , m_xAllMonitors(m_xBuilder->weld_label("allmonitors_str"))
+ , m_xMonitorExternal(m_xBuilder->weld_label("externalmonitor_str"))
+ , m_xExternal(m_xBuilder->weld_label("external_str"))
+{
+ m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
+ m_xFormatter->EnableEmptyField(false);
+
+ Link<weld::Toggleable&,void> aLink( LINK( this, SdStartPresentationDlg, ChangeRangeHdl ) );
+
+ m_xRbtAll->connect_toggled( aLink );
+ m_xRbtAtDia->connect_toggled( aLink );
+ m_xRbtCustomshow->connect_toggled( aLink );
+
+ aLink = LINK( this, SdStartPresentationDlg, ClickWindowPresentationHdl );
+ m_xRbtStandard->connect_toggled( aLink );
+ m_xRbtWindow->connect_toggled( aLink );
+ m_xRbtAuto->connect_toggled( aLink );
+
+ m_xTmfPause->connect_value_changed( LINK( this, SdStartPresentationDlg, ChangePauseHdl ) );
+
+ // fill Listbox with page names
+ for (const auto& rPageName : rPageNames)
+ m_xLbDias->append_text(rPageName);
+
+ if( pCustomShowList )
+ {
+ sal_uInt16 nPosToSelect = pCustomShowList->GetCurPos();
+ SdCustomShow* pCustomShow;
+ // fill Listbox with CustomShows
+ for( pCustomShow = pCustomShowList->First();
+ pCustomShow != nullptr;
+ pCustomShow = pCustomShowList->Next() )
+ {
+ m_xLbCustomshow->append_text( pCustomShow->GetName() );
+ }
+ m_xLbCustomshow->set_active( nPosToSelect );
+ pCustomShowList->Seek( nPosToSelect );
+ }
+ else
+ m_xRbtCustomshow->set_sensitive(false);
+
+ if( static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_CUSTOMSHOW ) ).GetValue() && pCSList )
+ m_xRbtCustomshow->set_active(true);
+ else if( static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_ALL ) ).GetValue() )
+ m_xRbtAll->set_active(true);
+ else
+ m_xRbtAtDia->set_active(true);
+
+ m_xLbDias->set_active_text( static_cast<const SfxStringItem&>( rOutAttrs.Get( ATTR_PRESENT_DIANAME ) ).GetValue() );
+ m_xCbxManuel->set_active( static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_MANUEL ) ).GetValue() );
+ m_xCbxMousepointer->set_active( static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_MOUSE ) ).GetValue() );
+ m_xCbxPen->set_active( static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_PEN ) ).GetValue() );
+ m_xCbxAnimationAllowed->set_active( static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_ANIMATION_ALLOWED ) ).GetValue() );
+ m_xCbxChangePage->set_active( static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_CHANGE_PAGE ) ).GetValue() );
+ m_xCbxAlwaysOnTop->set_active( static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_ALWAYS_ON_TOP ) ).GetValue() );
+
+ const bool bEndless = static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_ENDLESS ) ).GetValue();
+ const bool bWindow = !static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_FULLSCREEN ) ).GetValue();
+ const tools::Long nPause = static_cast<const SfxUInt32Item&>( rOutAttrs.Get( ATTR_PRESENT_PAUSE_TIMEOUT ) ).GetValue();
+
+ m_xFormatter->SetTime( tools::Time( 0, 0, nPause ) );
+ // set cursor in timefield to end
+ m_xTmfPause->set_position(-1);
+
+ m_xCbxAutoLogo->set_active( static_cast<const SfxBoolItem&>( rOutAttrs.Get( ATTR_PRESENT_SHOW_PAUSELOGO ) ).GetValue() );
+
+ if( bWindow )
+ m_xRbtWindow->set_active(true);
+ else if( bEndless )
+ m_xRbtAuto->set_active(true);
+ else
+ m_xRbtStandard->set_active(true);
+
+ InitMonitorSettings();
+
+ ChangeRangeHdl(*m_xRbtCustomshow);
+
+ ClickWindowPresentationHdl(*m_xRbtStandard);
+ ChangePause();
+}
+
+SdStartPresentationDlg::~SdStartPresentationDlg()
+{
+}
+
+OUString SdStartPresentationDlg::GetDisplayName( sal_Int32 nDisplay,
+ DisplayType eType )
+{
+ OUString aName;
+
+ switch ( eType )
+ {
+ case EXTERNAL_IS_NUMBER:
+ aName = m_xExternal->get_label();
+ break;
+ case MONITOR_IS_EXTERNAL:
+ aName = m_xMonitorExternal->get_label();
+ break;
+ default:
+ case MONITOR_NORMAL:
+ aName = m_xMonitor->get_label();
+ break;
+ }
+ aName = aName.replaceFirst( "%1", OUString::number( nDisplay ) );
+
+ return aName;
+}
+
+/// Store display index together with name in user data
+sal_Int32 SdStartPresentationDlg::InsertDisplayEntry(const OUString &aName,
+ sal_Int32 nDisplay)
+{
+ m_xLBMonitor->append(OUString::number(nDisplay), aName);
+ return m_xLBMonitor->get_count() - 1;
+}
+
+void SdStartPresentationDlg::InitMonitorSettings()
+{
+ try
+ {
+ m_xFtMonitor->show();
+ m_xLBMonitor->show();
+
+ mnMonitors = Application::GetScreenCount();
+
+ if( mnMonitors <= 1 )
+ {
+ m_xFtMonitor->set_sensitive( false );
+ m_xLBMonitor->set_sensitive( false );
+ }
+ else
+ {
+ bool bUnifiedDisplay = Application::IsUnifiedDisplay();
+ sal_Int32 nExternalIndex = Application::GetDisplayExternalScreen();
+
+ sal_Int32 nSelectedIndex (-1);
+ sal_Int32 nDefaultExternalIndex (-1);
+ const sal_Int32 nDefaultSelectedDisplay (
+ static_cast<const SfxInt32Item&>( rOutAttrs.Get( ATTR_PRESENT_DISPLAY ) ).GetValue());
+
+ // Un-conditionally add a version for '0' the default external display
+ sal_Int32 nInsertedEntry;
+
+ // Initial entry - the auto-detected external monitor
+ OUString aName = GetDisplayName( nExternalIndex + 1, EXTERNAL_IS_NUMBER);
+ nInsertedEntry = InsertDisplayEntry( aName, 0 );
+ if( nDefaultSelectedDisplay == 0)
+ nSelectedIndex = nInsertedEntry;
+
+ // The user data contains the real setting
+ for( sal_Int32 nDisplay = 0; nDisplay < mnMonitors; nDisplay++ )
+ {
+ aName = GetDisplayName( nDisplay + 1,
+ nDisplay == nExternalIndex ?
+ MONITOR_IS_EXTERNAL : MONITOR_NORMAL );
+ nInsertedEntry = InsertDisplayEntry( aName, nDisplay + 1 );
+
+ // Remember the index of the default selection.
+ if( nDisplay + 1 == nDefaultSelectedDisplay )
+ nSelectedIndex = nInsertedEntry;
+
+ // Remember index of the default display.
+ if( nDisplay == nExternalIndex )
+ nDefaultExternalIndex = nInsertedEntry;
+ }
+
+ if( bUnifiedDisplay )
+ {
+ nInsertedEntry = InsertDisplayEntry( m_xAllMonitors->get_label(), -1 );
+ if( nDefaultSelectedDisplay == -1 )
+ nSelectedIndex = nInsertedEntry;
+ }
+
+ if (nSelectedIndex < 0)
+ {
+ if (nExternalIndex < 0)
+ nSelectedIndex = 0;
+ else
+ nSelectedIndex = nDefaultExternalIndex;
+ }
+
+ m_xLBMonitor->set_active(nSelectedIndex);
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+/**
+ * sets the selected attributes of the dialog
+ */
+void SdStartPresentationDlg::GetAttr( SfxItemSet& rAttr )
+{
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_ALL, m_xRbtAll->get_active() ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_CUSTOMSHOW, m_xRbtCustomshow->get_active() ) );
+ rAttr.Put( SfxStringItem ( ATTR_PRESENT_DIANAME, m_xLbDias->get_active_text() ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_MANUEL, m_xCbxManuel->get_active() ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_MOUSE, m_xCbxMousepointer->get_active() ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_PEN, m_xCbxPen->get_active() ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_ANIMATION_ALLOWED, m_xCbxAnimationAllowed->get_active() ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_CHANGE_PAGE, m_xCbxChangePage->get_active() ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_ALWAYS_ON_TOP, m_xCbxAlwaysOnTop->get_active() ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_FULLSCREEN, !m_xRbtWindow->get_active() ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_ENDLESS, m_xRbtAuto->get_active() ) );
+ rAttr.Put( SfxUInt32Item ( ATTR_PRESENT_PAUSE_TIMEOUT, m_xFormatter->GetTime().GetMSFromTime() / 1000 ) );
+ rAttr.Put( SfxBoolItem ( ATTR_PRESENT_SHOW_PAUSELOGO, m_xCbxAutoLogo->get_active() ) );
+
+ int nPos = m_xLBMonitor->get_active();
+ if (nPos != -1)
+ rAttr.Put(SfxInt32Item(ATTR_PRESENT_DISPLAY, m_xLBMonitor->get_id(nPos).toInt32()));
+
+ nPos = m_xLbCustomshow->get_active();
+ if (nPos != -1)
+ pCustomShowList->Seek( nPos );
+}
+
+/**
+ * Handler: Enabled/Disabled Listbox "Dias"
+ */
+IMPL_LINK_NOARG(SdStartPresentationDlg, ChangeRangeHdl, weld::Toggleable&, void)
+{
+ m_xLbDias->set_sensitive( m_xRbtAtDia->get_active() );
+ m_xLbCustomshow->set_sensitive( m_xRbtCustomshow->get_active() );
+}
+
+/**
+ * Handler: Enabled/Disabled Checkbox "AlwaysOnTop"
+ */
+IMPL_LINK_NOARG(SdStartPresentationDlg, ClickWindowPresentationHdl, weld::Toggleable&, void)
+{
+ const bool bAuto = m_xRbtAuto->get_active();
+ const bool bWindow = m_xRbtWindow->get_active();
+
+ m_xTmfPause->set_sensitive( bAuto );
+ m_xCbxAutoLogo->set_sensitive( bAuto && ( m_xFormatter->GetTime().GetMSFromTime() > 0 ) );
+
+ const bool bDisplay = !bWindow && ( mnMonitors > 1 );
+ m_xFtMonitor->set_sensitive( bDisplay );
+ m_xLBMonitor->set_sensitive( bDisplay );
+
+ if( bWindow )
+ {
+ m_xCbxAlwaysOnTop->set_sensitive(false);
+ m_xCbxAlwaysOnTop->set_active(false);
+ }
+ else
+ m_xCbxAlwaysOnTop->set_sensitive(true);
+}
+
+/**
+ * Handler: Enabled/Disabled Checkbox "AlwaysOnTop"
+ */
+IMPL_LINK_NOARG(SdStartPresentationDlg, ChangePauseHdl, weld::FormattedSpinButton&, void)
+{
+ ChangePause();
+}
+
+void SdStartPresentationDlg::ChangePause()
+{
+ m_xCbxAutoLogo->set_sensitive(m_xRbtAuto->get_active() && ( m_xFormatter->GetTime().GetMSFromTime() > 0 ));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/prltempl.cxx b/sd/source/ui/dlg/prltempl.cxx
new file mode 100644
index 000000000..869f13c83
--- /dev/null
+++ b/sd/source/ui/dlg/prltempl.cxx
@@ -0,0 +1,305 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/log.hxx>
+#include <svx/dialogs.hrc>
+#include <svx/svxids.hrc>
+#include <editeng/flstitem.hxx>
+#include <svx/drawitem.hxx>
+#include <svl/style.hxx>
+#include <svx/svdobjkind.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/numitem.hxx>
+#include <svl/cjkoptions.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/sfxdlg.hxx>
+
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <prltempl.hxx>
+#include <bulmaper.hxx>
+#include <svl/intitem.hxx>
+#include <svx/flagsdef.hxx>
+
+#define IS_OUTLINE(x) (x >= PresentationObjects::Outline_1 && x <= PresentationObjects::Outline_9)
+
+/**
+ * Constructor of Tab dialog: appends pages to the dialog
+ */
+SdPresLayoutTemplateDlg::SdPresLayoutTemplateDlg(SfxObjectShell const * pDocSh,
+ weld::Window* pParent,
+ bool bBackground,
+ SfxStyleSheetBase& rStyleBase,
+ PresentationObjects _ePO,
+ SfxStyleSheetBasePool* pSSPool)
+ : SfxTabDialogController(pParent, "modules/sdraw/ui/drawprtldialog.ui", "DrawPRTLDialog")
+ , mpDocShell(pDocSh)
+ , ePO(_ePO)
+ , aInputSet(*rStyleBase.GetItemSet().GetPool(), svl::Items<SID_PARAM_NUM_PRESET, SID_PARAM_CUR_NUM_LEVEL>)
+{
+ const SfxItemSet* pOrgSet(&rStyleBase.GetItemSet());
+
+ if( IS_OUTLINE(ePO))
+ {
+ // Unfortunately, the Itemsets of our style sheets are not discrete...
+ const WhichRangesContainer& pPtr = pOrgSet->GetRanges();
+ sal_uInt16 p1, p2;
+ for( sal_Int32 i = 0; i < pPtr.size(); ++i )
+ {
+ p1 = pPtr[i].first;
+ p2 = pPtr[i].second;
+
+ // first, we make it discrete
+ while(i < pPtr.size() - 1 && (pPtr[i+1].first - p2 == 1))
+ {
+ p2 = pPtr[i+1].second;
+ ++i;
+ }
+ aInputSet.MergeRange( p1, p2 );
+ }
+
+ aInputSet.Put( rStyleBase.GetItemSet() );
+
+ // need parent-relationship
+ const SfxItemSet* pParentItemSet = rStyleBase.GetItemSet().GetParent();
+ if( pParentItemSet )
+ aInputSet.SetParent( pParentItemSet );
+
+ pOutSet.reset( new SfxItemSet( rStyleBase.GetItemSet() ) );
+ pOutSet->ClearItem();
+
+ // If there is no bullet item in this stylesheet, we get it
+ // from 'Outline 1' style sheet.
+ const SfxPoolItem *pItem = nullptr;
+ if( SfxItemState::SET != aInputSet.GetItemState(EE_PARA_NUMBULLET, false, &pItem ))
+ {
+ OUString aStyleName(SdResId(STR_PSEUDOSHEET_OUTLINE) + " 1");
+ SfxStyleSheetBase* pFirstStyleSheet = pSSPool->Find( aStyleName, SfxStyleFamily::Pseudo);
+
+ if(pFirstStyleSheet)
+ if( SfxItemState::SET == pFirstStyleSheet->GetItemSet().GetItemState(EE_PARA_NUMBULLET, false, &pItem) )
+ aInputSet.Put( *pItem );
+ }
+
+ // preselect selected layer in dialog
+ aInputSet.Put( SfxUInt16Item( SID_PARAM_CUR_NUM_LEVEL, 1<<GetOutlineLevel()));
+
+ SetInputSet(&aInputSet);
+ }
+ else {
+ SetInputSet(pOrgSet);
+ }
+
+ SvxColorListItem const *pColorListItem = mpDocShell->GetItem( SID_COLOR_TABLE );
+ SvxGradientListItem const *pGradientListItem = mpDocShell->GetItem( SID_GRADIENT_LIST );
+ SvxBitmapListItem const *pBitmapListItem = mpDocShell->GetItem( SID_BITMAP_LIST );
+ SvxPatternListItem const *pPatternListItem = mpDocShell->GetItem( SID_PATTERN_LIST );
+ SvxHatchListItem const *pHatchListItem = mpDocShell->GetItem( SID_HATCH_LIST );
+ SvxDashListItem const *pDashListItem = mpDocShell->GetItem( SID_DASH_LIST );
+ SvxLineEndListItem const *pLineEndListItem = mpDocShell->GetItem( SID_LINEEND_LIST );
+
+ pColorTab = pColorListItem->GetColorList();
+ pDashList = pDashListItem->GetDashList();
+ pLineEndList = pLineEndListItem->GetLineEndList();
+ pGradientList = pGradientListItem->GetGradientList();
+ pHatchingList = pHatchListItem->GetHatchList();
+ pBitmapList = pBitmapListItem->GetBitmapList();
+ pPatternList = pPatternListItem->GetPatternList();
+
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+
+ AddTabPage( "RID_SVXPAGE_LINE", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_LINE ), nullptr );
+ AddTabPage( "RID_SVXPAGE_AREA", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_AREA ), nullptr );
+ AddTabPage( "RID_SVXPAGE_SHADOW", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_SHADOW ), nullptr );
+ AddTabPage( "RID_SVXPAGE_TRANSPARENCE", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_TRANSPARENCE ), nullptr );
+ AddTabPage( "RID_SVXPAGE_CHAR_NAME", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_NAME ), nullptr );
+ AddTabPage( "RID_SVXPAGE_CHAR_EFFECTS", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_EFFECTS ), nullptr );
+ AddTabPage( "RID_SVXPAGE_STD_PARAGRAPH", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_STD_PARAGRAPH ), nullptr );
+ AddTabPage( "RID_SVXPAGE_TEXTATTR", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_TEXTATTR ), nullptr );
+ AddTabPage( "RID_SVXPAGE_PICK_BULLET", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_PICK_BULLET ), nullptr );
+ AddTabPage( "RID_SVXPAGE_PICK_SINGLE_NUM", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_PICK_SINGLE_NUM ), nullptr );
+ AddTabPage( "RID_SVXPAGE_PICK_BMP", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_PICK_BMP ), nullptr );
+ AddTabPage( "RID_SVXPAGE_NUM_OPTIONS", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_NUM_OPTIONS ), nullptr );
+ AddTabPage( "RID_SVXPAGE_TABULATOR", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_TABULATOR ), nullptr );
+ AddTabPage( "RID_SVXPAGE_PARA_ASIAN", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_PARA_ASIAN ), nullptr );
+ AddTabPage( "RID_SVXPAGE_ALIGN_PARAGRAPH", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_ALIGN_PARAGRAPH ), nullptr );
+ AddTabPage( "RID_SVXPAGE_BKG", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), nullptr);
+
+ if( !SvtCJKOptions::IsAsianTypographyEnabled() )
+ RemoveTabPage( "RID_SVXPAGE_PARA_ASIAN" );
+
+ if (bBackground)
+ {
+ RemoveTabPage( "RID_SVXPAGE_LINE");
+
+ RemoveTabPage( "RID_SVXPAGE_SHADOW");
+ RemoveTabPage( "RID_SVXPAGE_TRANSPARENCE");
+ RemoveTabPage( "RID_SVXPAGE_CHAR_NAME");
+ RemoveTabPage( "RID_SVXPAGE_CHAR_EFFECTS");
+ RemoveTabPage( "RID_SVXPAGE_STD_PARAGRAPH");
+ RemoveTabPage( "RID_SVXPAGE_TEXTATTR");
+ RemoveTabPage( "RID_SVXPAGE_PICK_BULLET");
+ RemoveTabPage( "RID_SVXPAGE_PICK_SINGLE_NUM");
+ RemoveTabPage( "RID_SVXPAGE_PICK_BMP");
+ RemoveTabPage( "RID_SVXPAGE_NUM_OPTIONS");
+ RemoveTabPage( "RID_SVXPAGE_TABULATOR");
+ RemoveTabPage( "RID_SVXPAGE_ALIGN_PARAGRAPH");
+ RemoveTabPage( "RID_SVXPAGE_PARA_ASIAN" );
+ RemoveTabPage( "RID_SVXPAGE_BKG" );
+ }
+
+ // set title and add corresponding pages to dialog
+ OUString aTitle;
+
+ switch( ePO )
+ {
+ case PresentationObjects::Title:
+ aTitle = SdResId(STR_PSEUDOSHEET_TITLE);
+ break;
+
+ case PresentationObjects::Subtitle:
+ aTitle = SdResId(STR_PSEUDOSHEET_SUBTITLE);
+ break;
+
+ case PresentationObjects::Background:
+ aTitle = SdResId(STR_PSEUDOSHEET_BACKGROUND);
+ break;
+
+ case PresentationObjects::BackgroundObjects:
+ aTitle = SdResId(STR_PSEUDOSHEET_BACKGROUNDOBJECTS);
+ break;
+
+ case PresentationObjects::Outline_1:
+ case PresentationObjects::Outline_2:
+ case PresentationObjects::Outline_3:
+ case PresentationObjects::Outline_4:
+ case PresentationObjects::Outline_5:
+ case PresentationObjects::Outline_6:
+ case PresentationObjects::Outline_7:
+ case PresentationObjects::Outline_8:
+ case PresentationObjects::Outline_9:
+ aTitle = SdResId(STR_PSEUDOSHEET_OUTLINE) + " " +
+ OUString::number( static_cast<int>(ePO) - static_cast<int>(PresentationObjects::Outline_1) + 1 );
+ break;
+
+ case PresentationObjects::Notes:
+ aTitle = SdResId(STR_PSEUDOSHEET_NOTES);
+ break;
+ }
+ m_xDialog->set_title(aTitle);
+}
+
+SdPresLayoutTemplateDlg::~SdPresLayoutTemplateDlg()
+{
+}
+
+void SdPresLayoutTemplateDlg::PageCreated(const OString& rId, SfxTabPage &rPage)
+{
+ SfxAllItemSet aSet(*(aInputSet.GetPool()));
+
+ if (rId == "RID_SVXPAGE_LINE")
+ {
+ aSet.Put (SvxColorListItem(pColorTab,SID_COLOR_TABLE));
+ aSet.Put (SvxDashListItem(pDashList,SID_DASH_LIST));
+ aSet.Put (SvxLineEndListItem(pLineEndList,SID_LINEEND_LIST));
+ aSet.Put (SfxUInt16Item(SID_DLG_TYPE,1));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_AREA")
+ {
+ aSet.Put (SvxColorListItem(pColorTab,SID_COLOR_TABLE));
+ aSet.Put (SvxGradientListItem(pGradientList,SID_GRADIENT_LIST));
+ aSet.Put (SvxHatchListItem(pHatchingList,SID_HATCH_LIST));
+ aSet.Put (SvxBitmapListItem(pBitmapList,SID_BITMAP_LIST));
+ aSet.Put (SvxPatternListItem(pPatternList,SID_PATTERN_LIST));
+ aSet.Put (SfxUInt16Item(SID_PAGE_TYPE,0));
+ aSet.Put (SfxUInt16Item(SID_DLG_TYPE,1));
+ aSet.Put (SfxUInt16Item(SID_TABPAGE_POS,0));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_SHADOW")
+ {
+ aSet.Put (SvxColorListItem(pColorTab,SID_COLOR_TABLE));
+ aSet.Put (SfxUInt16Item(SID_PAGE_TYPE,0));
+ aSet.Put (SfxUInt16Item(SID_DLG_TYPE,1));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_TRANSPARENCE")
+ {
+ aSet.Put (SfxUInt16Item(SID_PAGE_TYPE,0));
+ aSet.Put (SfxUInt16Item(SID_DLG_TYPE,1));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_CHAR_NAME")
+ {
+ SvxFontListItem aItem(*static_cast<const SvxFontListItem*>(mpDocShell->GetItem( SID_ATTR_CHAR_FONTLIST) ) );
+ aSet.Put (SvxFontListItem( aItem.GetFontList(), SID_ATTR_CHAR_FONTLIST));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_CHAR_EFFECTS")
+ {
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_TEXTATTR")
+ {
+ aSet.Put(CntUInt16Item(SID_SVXTEXTATTRPAGE_OBJKIND, static_cast<sal_uInt16>(SdrObjKind::Text)));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "RID_SVXPAGE_BKG")
+ {
+ aSet.Put(SfxUInt32Item(SID_FLAG_TYPE,static_cast<sal_uInt32>(SvxBackgroundTabFlags::SHOW_CHAR_BKGCOLOR)));
+ rPage.PageCreated(aSet);
+ }
+}
+
+const SfxItemSet* SdPresLayoutTemplateDlg::GetOutputItemSet() const
+{
+ if (pOutSet)
+ {
+ pOutSet->Put(*SfxTabDialogController::GetOutputItemSet());
+
+ const SvxNumBulletItem *pSvxNumBulletItem = pOutSet->GetItemIfSet(EE_PARA_NUMBULLET, false);
+ if (pSvxNumBulletItem)
+ SdBulletMapper::MapFontsInNumRule( const_cast<SvxNumRule&>(pSvxNumBulletItem->GetNumRule()), *pOutSet );
+ return pOutSet.get();
+ }
+ else
+ return SfxTabDialogController::GetOutputItemSet();
+}
+
+sal_uInt16 SdPresLayoutTemplateDlg::GetOutlineLevel() const
+{
+ switch( ePO )
+ {
+ case PresentationObjects::Outline_1: return 0;
+ case PresentationObjects::Outline_2: return 1;
+ case PresentationObjects::Outline_3: return 2;
+ case PresentationObjects::Outline_4: return 3;
+ case PresentationObjects::Outline_5: return 4;
+ case PresentationObjects::Outline_6: return 5;
+ case PresentationObjects::Outline_7: return 6;
+ case PresentationObjects::Outline_8: return 7;
+ case PresentationObjects::Outline_9: return 8;
+ default:
+ SAL_WARN( "sd", "Wrong Po! [CL]");
+ }
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/prntopts.cxx b/sd/source/ui/dlg/prntopts.cxx
new file mode 100644
index 000000000..4b50875bb
--- /dev/null
+++ b/sd/source/ui/dlg/prntopts.cxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdattr.hrc>
+#include <optsitem.hxx>
+#include <prntopts.hxx>
+#include <app.hrc>
+#include <svl/intitem.hxx>
+
+/**
+ * dialog to adjust print options
+ */
+SdPrintOptions::SdPrintOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs)
+ : SfxTabPage(pPage, pController, "modules/simpress/ui/prntopts.ui", "prntopts", &rInAttrs)
+ , m_xFrmContent(m_xBuilder->weld_frame("contentframe"))
+ , m_xCbxDraw(m_xBuilder->weld_check_button("drawingcb"))
+ , m_xCbxNotes(m_xBuilder->weld_check_button("notecb"))
+ , m_xCbxHandout(m_xBuilder->weld_check_button("handoutcb"))
+ , m_xCbxOutline(m_xBuilder->weld_check_button("outlinecb"))
+ , m_xRbtColor(m_xBuilder->weld_radio_button("defaultrb"))
+ , m_xRbtGrayscale(m_xBuilder->weld_radio_button("grayscalerb"))
+ , m_xRbtBlackWhite(m_xBuilder->weld_radio_button("blackwhiterb"))
+ , m_xCbxPagename(m_xBuilder->weld_check_button("pagenmcb"))
+ , m_xCbxDate(m_xBuilder->weld_check_button("datecb"))
+ , m_xCbxTime(m_xBuilder->weld_check_button("timecb"))
+ , m_xCbxHiddenPages(m_xBuilder->weld_check_button("hiddenpgcb"))
+ , m_xRbtDefault(m_xBuilder->weld_radio_button("pagedefaultrb"))
+ , m_xRbtPagesize(m_xBuilder->weld_radio_button("fittopgrb"))
+ , m_xRbtPagetile(m_xBuilder->weld_radio_button("tilepgrb"))
+ , m_xRbtBooklet(m_xBuilder->weld_radio_button("brouchrb"))
+ , m_xCbxFront(m_xBuilder->weld_check_button("frontcb"))
+ , m_xCbxBack(m_xBuilder->weld_check_button("backcb"))
+ , m_xCbxPaperbin(m_xBuilder->weld_check_button("papertryfrmprntrcb"))
+{
+ Link<weld::Toggleable&,void> aLink = LINK( this, SdPrintOptions, ClickBookletHdl );
+ m_xRbtDefault->connect_toggled( aLink );
+ m_xRbtPagesize->connect_toggled( aLink );
+ m_xRbtPagetile->connect_toggled( aLink );
+ m_xRbtBooklet->connect_toggled( aLink );
+
+ aLink = LINK( this, SdPrintOptions, ClickCheckboxHdl );
+ m_xCbxDraw->connect_toggled( aLink );
+ m_xCbxNotes->connect_toggled( aLink );
+ m_xCbxHandout->connect_toggled( aLink );
+ m_xCbxOutline->connect_toggled( aLink );
+
+#ifndef MACOSX
+ SetDrawMode();
+#endif
+}
+
+SdPrintOptions::~SdPrintOptions()
+{
+}
+
+bool SdPrintOptions::FillItemSet( SfxItemSet* rAttrs )
+{
+ if( m_xCbxDraw->get_state_changed_from_saved() ||
+ m_xCbxNotes->get_state_changed_from_saved() ||
+ m_xCbxHandout->get_state_changed_from_saved() ||
+ m_xCbxOutline->get_state_changed_from_saved() ||
+ m_xCbxDate->get_state_changed_from_saved() ||
+ m_xCbxTime->get_state_changed_from_saved() ||
+ m_xCbxPagename->get_state_changed_from_saved() ||
+ m_xCbxHiddenPages->get_state_changed_from_saved() ||
+ m_xRbtPagesize->get_state_changed_from_saved() ||
+ m_xRbtPagetile->get_state_changed_from_saved() ||
+ m_xRbtBooklet->get_state_changed_from_saved() ||
+ m_xCbxFront->get_state_changed_from_saved() ||
+ m_xCbxBack->get_state_changed_from_saved() ||
+ m_xCbxPaperbin->get_state_changed_from_saved() ||
+ m_xRbtColor->get_state_changed_from_saved() ||
+ m_xRbtGrayscale->get_state_changed_from_saved()||
+ m_xRbtBlackWhite->get_state_changed_from_saved())
+ {
+ SdOptionsPrintItem aOptions;
+
+ aOptions.GetOptionsPrint().SetDraw( m_xCbxDraw->get_active() );
+ aOptions.GetOptionsPrint().SetNotes( m_xCbxNotes->get_active() );
+ aOptions.GetOptionsPrint().SetHandout( m_xCbxHandout->get_active() );
+ aOptions.GetOptionsPrint().SetOutline( m_xCbxOutline->get_active() );
+ aOptions.GetOptionsPrint().SetDate( m_xCbxDate->get_active() );
+ aOptions.GetOptionsPrint().SetTime( m_xCbxTime->get_active() );
+ aOptions.GetOptionsPrint().SetPagename( m_xCbxPagename->get_active() );
+ aOptions.GetOptionsPrint().SetHiddenPages( m_xCbxHiddenPages->get_active() );
+ aOptions.GetOptionsPrint().SetPagesize( m_xRbtPagesize->get_active() );
+ aOptions.GetOptionsPrint().SetPagetile( m_xRbtPagetile->get_active() );
+ aOptions.GetOptionsPrint().SetBooklet( m_xRbtBooklet->get_active() );
+ aOptions.GetOptionsPrint().SetFrontPage( m_xCbxFront->get_active() );
+ aOptions.GetOptionsPrint().SetBackPage( m_xCbxBack->get_active() );
+ aOptions.GetOptionsPrint().SetPaperbin( m_xCbxPaperbin->get_active() );
+
+ sal_uInt16 nQuality = 0; // Standard, also Color
+ if( m_xRbtGrayscale->get_active() )
+ nQuality = 1;
+ if( m_xRbtBlackWhite->get_active() )
+ nQuality = 2;
+ aOptions.GetOptionsPrint().SetOutputQuality( nQuality );
+
+ rAttrs->Put( aOptions );
+
+ return true;
+ }
+ return false;
+}
+
+void SdPrintOptions::Reset( const SfxItemSet* rAttrs )
+{
+ const SdOptionsPrintItem* pPrintOpts = rAttrs->GetItemIfSet( ATTR_OPTIONS_PRINT, false);
+ if( pPrintOpts )
+ {
+ m_xCbxDraw->set_active( pPrintOpts->GetOptionsPrint().IsDraw() );
+ m_xCbxNotes->set_active( pPrintOpts->GetOptionsPrint().IsNotes() );
+ m_xCbxHandout->set_active( pPrintOpts->GetOptionsPrint().IsHandout() );
+ m_xCbxOutline->set_active( pPrintOpts->GetOptionsPrint().IsOutline() );
+ m_xCbxDate->set_active( pPrintOpts->GetOptionsPrint().IsDate() );
+ m_xCbxTime->set_active( pPrintOpts->GetOptionsPrint().IsTime() );
+ m_xCbxPagename->set_active( pPrintOpts->GetOptionsPrint().IsPagename() );
+ m_xCbxHiddenPages->set_active( pPrintOpts->GetOptionsPrint().IsHiddenPages() );
+ m_xRbtPagesize->set_active( pPrintOpts->GetOptionsPrint().IsPagesize() );
+ m_xRbtPagetile->set_active( pPrintOpts->GetOptionsPrint().IsPagetile() );
+ m_xRbtBooklet->set_active( pPrintOpts->GetOptionsPrint().IsBooklet() );
+ m_xCbxFront->set_active( pPrintOpts->GetOptionsPrint().IsFrontPage() );
+ m_xCbxBack->set_active( pPrintOpts->GetOptionsPrint().IsBackPage() );
+ m_xCbxPaperbin->set_active( pPrintOpts->GetOptionsPrint().IsPaperbin() );
+
+ if( !m_xRbtPagesize->get_active() &&
+ !m_xRbtPagetile->get_active() &&
+ !m_xRbtBooklet->get_active() )
+ {
+ m_xRbtDefault->set_active(true);
+ }
+
+ sal_uInt16 nQuality = pPrintOpts->GetOptionsPrint().GetOutputQuality();
+ if( nQuality == 0 )
+ m_xRbtColor->set_active(true);
+ else if( nQuality == 1 )
+ m_xRbtGrayscale->set_active(true);
+ else
+ m_xRbtBlackWhite->set_active(true);
+ }
+ m_xCbxDraw->save_state();
+ m_xCbxNotes->save_state();
+ m_xCbxHandout->save_state();
+ m_xCbxOutline->save_state();
+ m_xCbxDate->save_state();
+ m_xCbxTime->save_state();
+ m_xCbxPagename->save_state();
+ m_xCbxHiddenPages->save_state();
+ m_xRbtPagesize->save_state();
+ m_xRbtPagetile->save_state();
+ m_xRbtBooklet->save_state();
+ m_xCbxPaperbin->save_state();
+ m_xRbtColor->save_state();
+ m_xRbtGrayscale->save_state();
+ m_xRbtBlackWhite->save_state();
+
+ updateControls();
+}
+
+std::unique_ptr<SfxTabPage> SdPrintOptions::Create( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rOutAttrs )
+{
+ return std::make_unique<SdPrintOptions>( pPage, pController, *rOutAttrs );
+}
+
+IMPL_LINK(SdPrintOptions, ClickCheckboxHdl, weld::Toggleable&, rCbx, void)
+{
+ // there must be at least one of them checked
+ if( !m_xCbxDraw->get_active() && !m_xCbxNotes->get_active() && !m_xCbxOutline->get_active() && !m_xCbxHandout->get_active() )
+ rCbx.set_active(true);
+
+ updateControls();
+}
+
+IMPL_LINK_NOARG(SdPrintOptions, ClickBookletHdl, weld::Toggleable&, void)
+{
+ updateControls();
+}
+
+void SdPrintOptions::updateControls()
+{
+ m_xCbxFront->set_sensitive(m_xRbtBooklet->get_active());
+ m_xCbxBack->set_sensitive(m_xRbtBooklet->get_active());
+
+ m_xCbxDate->set_sensitive( !m_xRbtBooklet->get_active() );
+ m_xCbxTime->set_sensitive( !m_xRbtBooklet->get_active() );
+
+ m_xCbxPagename->set_sensitive( !m_xRbtBooklet->get_active() && (m_xCbxDraw->get_active() || m_xCbxNotes->get_active() || m_xCbxOutline->get_active()) );
+}
+
+void SdPrintOptions::SetDrawMode()
+{
+ if (m_xCbxNotes->get_visible())
+ {
+ m_xFrmContent->hide();
+ }
+}
+
+void SdPrintOptions::PageCreated (const SfxAllItemSet&
+#ifdef MACOSX
+ aSet
+#endif
+ )
+{
+#ifdef MACOSX
+ const SfxUInt32Item* pFlagItem = aSet.GetItem<SfxUInt32Item>(SID_SDMODE_FLAG, false);
+ if (pFlagItem)
+ {
+ sal_uInt32 nFlags=pFlagItem->GetValue();
+ if ( ( nFlags & SD_DRAW_MODE ) == SD_DRAW_MODE )
+ SetDrawMode();
+ }
+#else
+ SetDrawMode();
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/sdabstdlg.cxx b/sd/source/ui/dlg/sdabstdlg.cxx
new file mode 100644
index 000000000..2b686a3e8
--- /dev/null
+++ b/sd/source/ui/dlg/sdabstdlg.cxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdabstdlg.hxx>
+
+#include <osl/module.hxx>
+
+typedef SdAbstractDialogFactory* (*SdFuncPtrCreateDialogFactory)();
+
+#ifndef DISABLE_DYNLOADING
+
+extern "C" {
+static void thisModule() {}
+}
+
+#else
+
+extern "C" SdAbstractDialogFactory* SdCreateDialogFactory();
+
+#endif
+
+SdAbstractDialogFactory* SdAbstractDialogFactory::Create()
+{
+ SdFuncPtrCreateDialogFactory fp = nullptr;
+#ifndef DISABLE_DYNLOADING
+ static ::osl::Module aDialogLibrary;
+ static constexpr OUStringLiteral sLibName(u"" SDUI_DLL_NAME);
+ if (aDialogLibrary.is() || aDialogLibrary.loadRelative(&thisModule, sLibName))
+ fp = reinterpret_cast<SdAbstractDialogFactory*(SAL_CALL*)()>(
+ aDialogLibrary.getFunctionSymbol("SdCreateDialogFactory"));
+#else
+ fp = SdCreateDialogFactory;
+#endif
+ if (fp)
+ return fp();
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/sddlgfact.cxx b/sd/source/ui/dlg/sddlgfact.cxx
new file mode 100644
index 000000000..c526df75d
--- /dev/null
+++ b/sd/source/ui/dlg/sddlgfact.cxx
@@ -0,0 +1,739 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "sddlgfact.hxx"
+#include <BreakDlg.hxx>
+#include <copydlg.hxx>
+#include <custsdlg.hxx>
+#include <dlg_char.hxx>
+#include <dlgpage.hxx>
+#include <dlgfield.hxx>
+#include <dlgsnap.hxx>
+#include <layeroptionsdlg.hxx>
+#include <inspagob.hxx>
+#include <morphdlg.hxx>
+#include <OutlineBulletDlg.hxx>
+#include <paragr.hxx>
+#include <present.hxx>
+#include "RemoteDialog.hxx"
+#include <prltempl.hxx>
+#include <sdpreslt.hxx>
+#include <tabtempl.hxx>
+#include <tpaction.hxx>
+#include <vectdlg.hxx>
+#include <tpoption.hxx>
+#include <prntopts.hxx>
+#include <pubdlg.hxx>
+#include <masterlayoutdlg.hxx>
+#include <headerfooterdlg.hxx>
+#include "PhotoAlbumDialog.hxx"
+#include <vcl/virdev.hxx>
+
+short AbstractSvxBulletAndPositionDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short SdAbstractGenericDialog_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+BitmapEx SdAbstractGenericDialog_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString SdAbstractGenericDialog_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+const SfxItemSet* AbstractSvxBulletAndPositionDlg_Impl::GetOutputItemSet( SfxItemSet* pSet ) const
+{
+ return m_xDlg->GetOutputItemSet( pSet );
+}
+
+bool AbstractSvxBulletAndPositionDlg_Impl::IsApplyToMaster()
+{
+ return m_xDlg->IsApplyToMaster();
+}
+
+bool AbstractSvxBulletAndPositionDlg_Impl::IsSlideScope()
+{
+ return m_xDlg->IsSlideScope();
+}
+
+short AbstractCopyDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractSdCustomShowDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short SdPresLayoutTemplateDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool SdPresLayoutTemplateDlg_Impl::StartExecuteAsync(AsyncContext &rCtx)
+{
+ return SfxTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+short AbstractSdModifyFieldDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractSdSnapLineDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractSdInsertLayerDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractSdInsertPagesObjsDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractMorphDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractSdStartPresDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractSdPresLayoutDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short SdAbstractSfxDialog_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractSdVectorizeDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractSdPublishingDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractHeaderFooterDialog_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractHeaderFooterDialog_Impl::StartExecuteAsync(AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+BitmapEx AbstractHeaderFooterDialog_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractHeaderFooterDialog_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+short AbstractBulletDialog_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractBulletDialog_Impl::StartExecuteAsync(AsyncContext &rCtx)
+{
+ return SfxTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+AbstractBreakDlg_Impl::AbstractBreakDlg_Impl(std::unique_ptr<::sd::BreakDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+{
+}
+
+short AbstractBreakDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+BitmapEx AbstractBreakDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractBreakDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+AbstractMasterLayoutDialog_Impl::AbstractMasterLayoutDialog_Impl(std::unique_ptr<::sd::MasterLayoutDialog> pDlg)
+ : m_xDlg(std::move(pDlg))
+{
+}
+
+short AbstractMasterLayoutDialog_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+BitmapEx AbstractMasterLayoutDialog_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractMasterLayoutDialog_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractCopyDlg_Impl::GetAttr( SfxItemSet& rOutAttrs )
+{
+ m_xDlg->GetAttr( rOutAttrs );
+}
+
+BitmapEx AbstractCopyDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractCopyDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+bool AbstractSdCustomShowDlg_Impl::IsCustomShow() const
+{
+ return m_xDlg->IsCustomShow();
+}
+
+BitmapEx AbstractSdCustomShowDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractSdCustomShowDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+short SdAbstractTabController_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+void SdAbstractTabController_Impl::SetCurPageId( const OString &rName )
+{
+ m_xDlg->SetCurPageId( rName );
+}
+
+const SfxItemSet* SdAbstractTabController_Impl::GetOutputItemSet() const
+{
+ return m_xDlg->GetOutputItemSet();
+}
+
+WhichRangesContainer SdAbstractTabController_Impl::GetInputRanges(const SfxItemPool& pItem )
+{
+ return m_xDlg->GetInputRanges( pItem );
+}
+
+void SdAbstractTabController_Impl::SetInputSet( const SfxItemSet* pInSet )
+{
+ m_xDlg->SetInputSet( pInSet );
+}
+
+bool SdAbstractTabController_Impl::StartExecuteAsync(AsyncContext &rCtx)
+{
+ return SfxTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+//From class Window.
+void SdAbstractTabController_Impl::SetText( const OUString& rStr )
+{
+ m_xDlg->set_title(rStr);
+}
+
+BitmapEx SdAbstractTabController_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString SdAbstractTabController_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractBulletDialog_Impl::SetCurPageId( const OString& rName )
+{
+ m_xDlg->SetCurPageId( rName );
+}
+
+const SfxItemSet* AbstractBulletDialog_Impl::GetOutputItemSet() const
+{
+ return static_cast< ::sd::OutlineBulletDlg*>(m_xDlg.get())->GetBulletOutputItemSet();
+}
+
+WhichRangesContainer AbstractBulletDialog_Impl::GetInputRanges(const SfxItemPool& pItem )
+{
+ return m_xDlg->GetInputRanges(pItem);
+}
+
+void AbstractBulletDialog_Impl::SetInputSet( const SfxItemSet* pInSet )
+{
+ m_xDlg->SetInputSet(pInSet);
+}
+
+void AbstractBulletDialog_Impl::SetText( const OUString& rStr )
+{
+ m_xDlg->set_title(rStr);
+}
+
+BitmapEx AbstractBulletDialog_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractBulletDialog_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void SdPresLayoutTemplateDlg_Impl::SetCurPageId( const OString& rName )
+{
+ m_xDlg->SetCurPageId( rName );
+}
+
+const SfxItemSet* SdPresLayoutTemplateDlg_Impl::GetOutputItemSet() const
+{
+ return m_xDlg->GetOutputItemSet();
+}
+
+WhichRangesContainer SdPresLayoutTemplateDlg_Impl::GetInputRanges(const SfxItemPool& pItem )
+{
+ return m_xDlg->GetInputRanges( pItem );
+}
+
+void SdPresLayoutTemplateDlg_Impl::SetInputSet( const SfxItemSet* pInSet )
+{
+ m_xDlg->SetInputSet( pInSet );
+}
+
+void SdPresLayoutTemplateDlg_Impl::SetText( const OUString& rStr )
+{
+ m_xDlg->set_title(rStr);
+}
+
+BitmapEx SdPresLayoutTemplateDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString SdPresLayoutTemplateDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+SvxFieldData* AbstractSdModifyFieldDlg_Impl::GetField()
+{
+ return m_xDlg->GetField();
+}
+
+SfxItemSet AbstractSdModifyFieldDlg_Impl::GetItemSet()
+{
+ return m_xDlg->GetItemSet();
+}
+
+BitmapEx AbstractSdModifyFieldDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractSdModifyFieldDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractSdSnapLineDlg_Impl::GetAttr(SfxItemSet& rOutAttrs)
+{
+ m_xDlg->GetAttr(rOutAttrs);
+}
+
+void AbstractSdSnapLineDlg_Impl::HideRadioGroup()
+{
+ m_xDlg->HideRadioGroup();
+}
+
+void AbstractSdSnapLineDlg_Impl::HideDeleteBtn()
+{
+ m_xDlg->HideDeleteBtn();
+}
+
+void AbstractSdSnapLineDlg_Impl::SetInputFields(bool bEnableX, bool bEnableY)
+{
+ m_xDlg->SetInputFields(bEnableX, bEnableY);
+}
+
+void AbstractSdSnapLineDlg_Impl::SetText( const OUString& rStr )
+{
+ m_xDlg->set_title(rStr);
+}
+
+BitmapEx AbstractSdSnapLineDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractSdSnapLineDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractSdInsertLayerDlg_Impl::GetAttr( SfxItemSet& rOutAttrs )
+{
+ m_xDlg->GetAttr(rOutAttrs);
+}
+
+void AbstractSdInsertLayerDlg_Impl::SetHelpId( const OString& rHelpId )
+{
+ m_xDlg->set_help_id(rHelpId);
+}
+
+BitmapEx AbstractSdInsertLayerDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractSdInsertLayerDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+std::vector<OUString> AbstractSdInsertPagesObjsDlg_Impl::GetList(const sal_uInt16 nType)
+{
+ return m_xDlg->GetList(nType);
+}
+
+bool AbstractSdInsertPagesObjsDlg_Impl::IsLink()
+{
+ return m_xDlg->IsLink();
+}
+
+bool AbstractSdInsertPagesObjsDlg_Impl::IsRemoveUnnecessaryMasterPages() const
+{
+ return m_xDlg->IsRemoveUnnecessaryMasterPages();
+}
+
+BitmapEx AbstractSdInsertPagesObjsDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractSdInsertPagesObjsDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractMorphDlg_Impl::SaveSettings() const
+{
+ m_xDlg->SaveSettings();
+}
+
+sal_uInt16 AbstractMorphDlg_Impl::GetFadeSteps() const
+{
+ return m_xDlg->GetFadeSteps();
+}
+
+bool AbstractMorphDlg_Impl::IsAttributeFade() const
+{
+ return m_xDlg->IsAttributeFade();
+}
+
+bool AbstractMorphDlg_Impl::IsOrientationFade() const
+{
+ return m_xDlg->IsOrientationFade();
+}
+
+BitmapEx AbstractMorphDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractMorphDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractSdStartPresDlg_Impl::GetAttr( SfxItemSet& rOutAttrs )
+{
+ m_xDlg->GetAttr(rOutAttrs);
+}
+
+BitmapEx AbstractSdStartPresDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractSdStartPresDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractSdPresLayoutDlg_Impl::GetAttr( SfxItemSet& rOutAttrs )
+{
+ m_xDlg->GetAttr(rOutAttrs);
+}
+
+BitmapEx AbstractSdPresLayoutDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractSdPresLayoutDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+const SfxItemSet* SdAbstractSfxDialog_Impl::GetOutputItemSet() const
+{
+ return m_xDlg->GetOutputItemSet();
+}
+
+void SdAbstractSfxDialog_Impl::SetText( const OUString& rStr )
+{
+ m_xDlg->set_title(rStr);
+}
+
+const GDIMetaFile& AbstractSdVectorizeDlg_Impl::GetGDIMetaFile() const
+{
+ return m_xDlg->GetGDIMetaFile();
+}
+
+BitmapEx AbstractSdVectorizeDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractSdVectorizeDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractSdPublishingDlg_Impl::GetParameterSequence( css::uno::Sequence< css::beans::PropertyValue >& rParams )
+{
+ m_xDlg->GetParameterSequence( rParams );
+}
+
+BitmapEx AbstractSdPublishingDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractSdPublishingDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+//-------------- SdAbstractDialogFactory implementation--------------
+
+VclPtr<AbstractSvxBulletAndPositionDlg> SdAbstractDialogFactory_Impl::CreateSvxBulletAndPositionDlg(weld::Window* pParent, const SfxItemSet* pAttr, ::sd::View* pView)
+{
+ return VclPtr<AbstractSvxBulletAndPositionDlg_Impl>::Create(std::make_unique<SvxBulletAndPositionDlg>(pParent, *pAttr, pView));
+}
+
+VclPtr<VclAbstractDialog> SdAbstractDialogFactory_Impl::CreateBreakDlg(
+ weld::Window* pParent,
+ ::sd::DrawView* pDrView,
+ ::sd::DrawDocShell* pShell,
+ sal_uLong nSumActionCount,
+ sal_uLong nObjCount )
+{
+ return VclPtr<AbstractBreakDlg_Impl>::Create(std::make_unique<::sd::BreakDlg>(pParent, pDrView, pShell, nSumActionCount, nObjCount));
+}
+
+VclPtr<AbstractCopyDlg> SdAbstractDialogFactory_Impl::CreateCopyDlg(weld::Window* pParent,
+ const SfxItemSet& rInAttrs,
+ ::sd::View* pView )
+{
+ return VclPtr<AbstractCopyDlg_Impl>::Create(std::make_unique<::sd::CopyDlg>(pParent, rInAttrs, pView));
+}
+
+VclPtr<AbstractSdCustomShowDlg> SdAbstractDialogFactory_Impl::CreateSdCustomShowDlg(weld::Window* pParent, SdDrawDocument& rDrawDoc )
+{
+ return VclPtr<AbstractSdCustomShowDlg_Impl>::Create(std::make_unique<SdCustomShowDlg>(pParent, rDrawDoc));
+}
+
+VclPtr<SfxAbstractTabDialog> SdAbstractDialogFactory_Impl::CreateSdTabCharDialog(weld::Window* pParent, const SfxItemSet* pAttr, SfxObjectShell* pDocShell)
+{
+ return VclPtr<SdAbstractTabController_Impl>::Create(std::make_shared<SdCharDlg>(pParent, pAttr, pDocShell));
+}
+
+VclPtr<SfxAbstractTabDialog> SdAbstractDialogFactory_Impl::CreateSdTabPageDialog(weld::Window* pParent, const SfxItemSet* pAttr, SfxObjectShell* pDocShell, bool bAreaPage, bool bIsImpressDoc, bool bIsImpressMaster )
+{
+ return VclPtr<SdAbstractTabController_Impl>::Create(std::make_shared<SdPageDlg>(pDocShell, pParent, pAttr, bAreaPage, bIsImpressDoc, bIsImpressMaster));
+}
+
+VclPtr<AbstractSdModifyFieldDlg> SdAbstractDialogFactory_Impl::CreateSdModifyFieldDlg(weld::Window* pParent, const SvxFieldData* pInField, const SfxItemSet& rSet)
+{
+ return VclPtr<AbstractSdModifyFieldDlg_Impl>::Create(std::make_unique<SdModifyFieldDlg>(pParent, pInField, rSet));
+}
+
+VclPtr<AbstractSdSnapLineDlg> SdAbstractDialogFactory_Impl::CreateSdSnapLineDlg(weld::Window* pParent, const SfxItemSet& rInAttrs, ::sd::View* pView)
+{
+ return VclPtr<AbstractSdSnapLineDlg_Impl>::Create(std::make_unique<SdSnapLineDlg>(pParent, rInAttrs, pView));
+}
+
+VclPtr<AbstractSdInsertLayerDlg> SdAbstractDialogFactory_Impl::CreateSdInsertLayerDlg(weld::Window* pParent, const SfxItemSet& rInAttrs, bool bDeletable, const OUString& aStr)
+{
+ return VclPtr<AbstractSdInsertLayerDlg_Impl>::Create(std::make_unique<SdInsertLayerDlg>(pParent, rInAttrs, bDeletable, aStr));
+}
+
+VclPtr<AbstractSdInsertPagesObjsDlg> SdAbstractDialogFactory_Impl::CreateSdInsertPagesObjsDlg(weld::Window* pParent, const SdDrawDocument* pDoc, SfxMedium* pSfxMedium, const OUString& rFileName)
+{
+ return VclPtr<AbstractSdInsertPagesObjsDlg_Impl>::Create(std::make_unique<SdInsertPagesObjsDlg>(pParent, pDoc, pSfxMedium, rFileName));
+}
+
+VclPtr<AbstractMorphDlg> SdAbstractDialogFactory_Impl::CreateMorphDlg(weld::Window* pParent, const SdrObject* pObj1, const SdrObject* pObj2)
+{
+ return VclPtr<AbstractMorphDlg_Impl>::Create(std::make_unique<::sd::MorphDlg>(pParent, pObj1, pObj2));
+}
+
+VclPtr<SfxAbstractTabDialog> SdAbstractDialogFactory_Impl::CreateSdOutlineBulletTabDlg(weld::Window* pParent, const SfxItemSet* pAttr, ::sd::View* pView)
+{
+ return VclPtr<AbstractBulletDialog_Impl>::Create(std::make_shared<::sd::OutlineBulletDlg>(pParent, pAttr, pView));
+}
+
+VclPtr<SfxAbstractTabDialog> SdAbstractDialogFactory_Impl::CreateSdParagraphTabDlg(weld::Window* pParent, const SfxItemSet* pAttr )
+{
+ return VclPtr<SdAbstractTabController_Impl>::Create(std::make_shared<SdParagraphDlg>(pParent, pAttr));
+}
+
+VclPtr<AbstractSdStartPresDlg> SdAbstractDialogFactory_Impl::CreateSdStartPresentationDlg(weld::Window* pParent,
+ const SfxItemSet& rInAttrs, const std::vector<OUString> &rPageNames, SdCustomShowList* pCSList)
+{
+ return VclPtr<AbstractSdStartPresDlg_Impl>::Create(std::make_unique<SdStartPresentationDlg>(pParent, rInAttrs, rPageNames, pCSList));
+}
+
+VclPtr<VclAbstractDialog> SdAbstractDialogFactory_Impl::CreateRemoteDialog(weld::Window* pParent)
+{
+ return VclPtr<SdAbstractGenericDialog_Impl>::Create(std::make_unique<::sd::RemoteDialog>(pParent));
+}
+
+VclPtr<SfxAbstractTabDialog> SdAbstractDialogFactory_Impl::CreateSdPresLayoutTemplateDlg(SfxObjectShell* pDocSh, weld::Window* pParent, bool bBackgroundDlg, SfxStyleSheetBase& rStyleBase, PresentationObjects ePO, SfxStyleSheetBasePool* pSSPool)
+{
+ return VclPtr<SdPresLayoutTemplateDlg_Impl>::Create(std::make_shared<SdPresLayoutTemplateDlg>(pDocSh, pParent, bBackgroundDlg, rStyleBase, ePO, pSSPool));
+}
+
+VclPtr<AbstractSdPresLayoutDlg> SdAbstractDialogFactory_Impl::CreateSdPresLayoutDlg(weld::Window* pParent, ::sd::DrawDocShell* pDocShell, const SfxItemSet& rInAttrs)
+{
+ return VclPtr<AbstractSdPresLayoutDlg_Impl>::Create(std::make_unique<SdPresLayoutDlg>(pDocShell, pParent, rInAttrs));
+}
+
+VclPtr<SfxAbstractTabDialog> SdAbstractDialogFactory_Impl::CreateSdTabTemplateDlg(weld::Window* pParent, const SfxObjectShell* pDocShell, SfxStyleSheetBase& rStyleBase, SdrModel* pModel, SdrView* pView)
+{
+ return VclPtr<SdAbstractTabController_Impl>::Create(std::make_shared<SdTabTemplateDlg>(pParent, pDocShell, rStyleBase, pModel, pView));
+}
+
+VclPtr<SfxAbstractDialog> SdAbstractDialogFactory_Impl::CreatSdActionDialog(weld::Window* pParent, const SfxItemSet* pAttr, ::sd::View* pView )
+{
+ return VclPtr<SdAbstractSfxDialog_Impl>::Create(std::make_unique<SdActionDlg>(pParent, pAttr, pView));
+}
+
+VclPtr<AbstractSdVectorizeDlg> SdAbstractDialogFactory_Impl::CreateSdVectorizeDlg(weld::Window* pParent, const Bitmap& rBmp, ::sd::DrawDocShell* pDocShell)
+{
+ return VclPtr<AbstractSdVectorizeDlg_Impl>::Create(std::make_unique<SdVectorizeDlg>(pParent, rBmp, pDocShell));
+}
+
+VclPtr<AbstractSdPublishingDlg> SdAbstractDialogFactory_Impl::CreateSdPublishingDlg(weld::Window* pParent, DocumentType eDocType)
+{
+ return VclPtr<AbstractSdPublishingDlg_Impl>::Create(std::make_unique<SdPublishingDlg>(pParent, eDocType));
+}
+
+// Factories for TabPages
+CreateTabPage SdAbstractDialogFactory_Impl::GetSdOptionsContentsTabPageCreatorFunc()
+{
+ return SdTpOptionsContents::Create;
+}
+
+CreateTabPage SdAbstractDialogFactory_Impl::GetSdPrintOptionsTabPageCreatorFunc()
+{
+ return SdPrintOptions::Create;
+}
+
+CreateTabPage SdAbstractDialogFactory_Impl::GetSdOptionsMiscTabPageCreatorFunc()
+{
+ return SdTpOptionsMisc::Create;
+}
+
+CreateTabPage SdAbstractDialogFactory_Impl::GetSdOptionsSnapTabPageCreatorFunc()
+{
+ return SdTpOptionsSnap::Create;
+}
+
+VclPtr<VclAbstractDialog> SdAbstractDialogFactory_Impl::CreateMasterLayoutDialog(weld::Window* pParent, SdDrawDocument* pDoc, SdPage* pCurrentPage)
+{
+ return VclPtr<AbstractMasterLayoutDialog_Impl>::Create(std::make_unique<::sd::MasterLayoutDialog>(pParent, pDoc, pCurrentPage));
+}
+
+VclPtr<AbstractHeaderFooterDialog> SdAbstractDialogFactory_Impl::CreateHeaderFooterDialog(sd::ViewShell* pViewShell,
+ weld::Window* pParent, SdDrawDocument* pDoc, SdPage* pCurrentPage)
+{
+ return VclPtr<AbstractHeaderFooterDialog_Impl>::Create(std::make_shared<::sd::HeaderFooterDialog>(pViewShell, pParent, pDoc, pCurrentPage));
+}
+
+VclPtr<VclAbstractDialog> SdAbstractDialogFactory_Impl::CreateSdPhotoAlbumDialog(weld::Window* pParent, SdDrawDocument* pDoc)
+{
+ return VclPtr<SdAbstractGenericDialog_Impl>::Create(std::make_unique<sd::SdPhotoAlbumDialog>(pParent, pDoc));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/sddlgfact.hxx b/sd/source/ui/dlg/sddlgfact.hxx
new file mode 100644
index 000000000..8da5c74dd
--- /dev/null
+++ b/sd/source/ui/dlg/sddlgfact.hxx
@@ -0,0 +1,448 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sdabstdlg.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <svx/svxdlg.hxx>
+
+#include <morphdlg.hxx>
+#include <copydlg.hxx>
+#include <BreakDlg.hxx>
+#include <headerfooterdlg.hxx>
+#include <masterlayoutdlg.hxx>
+#include <custsdlg.hxx>
+#include <layeroptionsdlg.hxx>
+#include <inspagob.hxx>
+#include <dlgfield.hxx>
+#include <sdpreslt.hxx>
+#include <prltempl.hxx>
+#include <pubdlg.hxx>
+#include <dlgsnap.hxx>
+#include <present.hxx>
+#include <vectdlg.hxx>
+#include <BulletAndPositionDlg.hxx>
+
+//namespace sd {
+// class MorphDlg;
+// class CopyDlg;
+// class BreakDlg;
+// class HeaderFooterDialog;
+// class MasterLayoutDialog;
+//}
+
+class SvxBulletAndPositionDlg;
+
+/// Provides managing and getting information from the numbering and position dialog.
+class AbstractSvxBulletAndPositionDlg_Impl :public AbstractSvxBulletAndPositionDlg
+{
+ std::unique_ptr<SvxBulletAndPositionDlg> m_xDlg;
+public:
+ explicit AbstractSvxBulletAndPositionDlg_Impl(std::unique_ptr<SvxBulletAndPositionDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual const SfxItemSet* GetOutputItemSet( SfxItemSet* ) const override ;
+ virtual bool IsApplyToMaster() override;
+ virtual bool IsSlideScope() override;
+};
+
+class SdAbstractGenericDialog_Impl : public VclAbstractDialog
+{
+ std::unique_ptr<weld::GenericDialogController> m_xDlg;
+public:
+ explicit SdAbstractGenericDialog_Impl(std::unique_ptr<weld::GenericDialogController> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractMasterLayoutDialog_Impl : public VclAbstractDialog
+{
+private:
+ std::unique_ptr<sd::MasterLayoutDialog> m_xDlg;
+public:
+ AbstractMasterLayoutDialog_Impl(std::unique_ptr<::sd::MasterLayoutDialog> pDlg);
+ virtual short Execute() override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractBreakDlg_Impl : public VclAbstractDialog
+{
+private:
+ std::unique_ptr<sd::BreakDlg> m_xDlg;
+public:
+ AbstractBreakDlg_Impl(std::unique_ptr<::sd::BreakDlg> pDlg);
+ virtual short Execute() override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractCopyDlg_Impl : public AbstractCopyDlg
+{
+private:
+ std::unique_ptr<sd::CopyDlg> m_xDlg;
+public:
+ AbstractCopyDlg_Impl(std::unique_ptr<::sd::CopyDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual void GetAttr( SfxItemSet& rOutAttrs ) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractSdCustomShowDlg_Impl : public AbstractSdCustomShowDlg
+{
+private:
+ std::unique_ptr<SdCustomShowDlg> m_xDlg;
+public:
+ AbstractSdCustomShowDlg_Impl(std::unique_ptr<SdCustomShowDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool IsCustomShow() const override ;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class SdAbstractTabController_Impl : public SfxAbstractTabDialog
+{
+ std::shared_ptr<SfxTabDialogController> m_xDlg;
+public:
+ explicit SdAbstractTabController_Impl(std::shared_ptr<SfxTabDialogController> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(AsyncContext &rCtx) override;
+ virtual void SetCurPageId( const OString &rName ) override;
+ virtual const SfxItemSet* GetOutputItemSet() const override;
+ virtual WhichRangesContainer GetInputRanges( const SfxItemPool& pItem ) override;
+ virtual void SetInputSet( const SfxItemSet* pInSet ) override;
+ virtual void SetText( const OUString& rStr ) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractBulletDialog_Impl : public SfxAbstractTabDialog
+{
+ std::shared_ptr<SfxTabDialogController> m_xDlg;
+public:
+ explicit AbstractBulletDialog_Impl(std::shared_ptr<SfxTabDialogController> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(AsyncContext &rCtx) override;
+ virtual void SetCurPageId( const OString& rName ) override;
+ virtual const SfxItemSet* GetOutputItemSet() const override;
+ virtual WhichRangesContainer GetInputRanges( const SfxItemPool& pItem ) override;
+ virtual void SetInputSet( const SfxItemSet* pInSet ) override;
+ virtual void SetText( const OUString& rStr ) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class SdPresLayoutTemplateDlg_Impl : public SfxAbstractTabDialog
+{
+ std::shared_ptr<SdPresLayoutTemplateDlg> m_xDlg;
+public:
+ explicit SdPresLayoutTemplateDlg_Impl(std::shared_ptr<SdPresLayoutTemplateDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(AsyncContext &rCtx) override;
+ virtual void SetCurPageId( const OString& rName ) override;
+ virtual const SfxItemSet* GetOutputItemSet() const override;
+ virtual WhichRangesContainer GetInputRanges( const SfxItemPool& pItem ) override;
+ virtual void SetInputSet( const SfxItemSet* pInSet ) override;
+ virtual void SetText( const OUString& rStr ) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractSdModifyFieldDlg_Impl : public AbstractSdModifyFieldDlg
+{
+private:
+ std::unique_ptr<SdModifyFieldDlg> m_xDlg;
+public:
+ AbstractSdModifyFieldDlg_Impl(std::unique_ptr<SdModifyFieldDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual SvxFieldData* GetField() override;
+ virtual SfxItemSet GetItemSet() override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractSdSnapLineDlg_Impl : public AbstractSdSnapLineDlg
+{
+private:
+ std::unique_ptr<SdSnapLineDlg> m_xDlg;
+public:
+ AbstractSdSnapLineDlg_Impl(std::unique_ptr<SdSnapLineDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual void GetAttr(SfxItemSet& rOutAttrs) override;
+ virtual void HideRadioGroup() override;
+ virtual void HideDeleteBtn() override;
+ virtual void SetInputFields(bool bEnableX, bool bEnableY) override;
+ virtual void SetText( const OUString& rStr ) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractSdInsertLayerDlg_Impl : public AbstractSdInsertLayerDlg
+{
+private:
+ std::unique_ptr<SdInsertLayerDlg> m_xDlg;
+public:
+ AbstractSdInsertLayerDlg_Impl(std::unique_ptr<SdInsertLayerDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual void GetAttr( SfxItemSet& rOutAttrs ) override ;
+ virtual void SetHelpId( const OString& rHelpId ) override ;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractSdInsertPagesObjsDlg_Impl : public AbstractSdInsertPagesObjsDlg
+{
+private:
+ std::unique_ptr<SdInsertPagesObjsDlg> m_xDlg;
+public:
+ AbstractSdInsertPagesObjsDlg_Impl(std::unique_ptr<SdInsertPagesObjsDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual std::vector<OUString> GetList ( const sal_uInt16 nType ) override;
+ virtual bool IsLink() override;
+ virtual bool IsRemoveUnnecessaryMasterPages() const override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractMorphDlg_Impl : public AbstractMorphDlg
+{
+private:
+ std::unique_ptr<sd::MorphDlg> m_xDlg;
+public:
+ AbstractMorphDlg_Impl(std::unique_ptr<::sd::MorphDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual void SaveSettings() const override;
+ virtual sal_uInt16 GetFadeSteps() const override;
+ virtual bool IsAttributeFade() const override ;
+ virtual bool IsOrientationFade() const override ;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractSdStartPresDlg_Impl : public AbstractSdStartPresDlg
+{
+private:
+ std::unique_ptr<SdStartPresentationDlg> m_xDlg;
+public:
+ AbstractSdStartPresDlg_Impl(std::unique_ptr<SdStartPresentationDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual void GetAttr( SfxItemSet& rOutAttrs ) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractSdPresLayoutDlg_Impl : public AbstractSdPresLayoutDlg
+{
+private:
+ std::unique_ptr<SdPresLayoutDlg> m_xDlg;
+public:
+ AbstractSdPresLayoutDlg_Impl(std::unique_ptr<SdPresLayoutDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual void GetAttr(SfxItemSet& rOutAttrs) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class SdAbstractSfxDialog_Impl : public SfxAbstractDialog
+{
+private:
+ std::unique_ptr<SfxSingleTabDialogController> m_xDlg;
+public:
+ SdAbstractSfxDialog_Impl(std::unique_ptr<SfxSingleTabDialogController> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual const SfxItemSet* GetOutputItemSet() const override;
+ virtual void SetText( const OUString& rStr ) override;
+};
+
+class AbstractSdVectorizeDlg_Impl :public AbstractSdVectorizeDlg
+{
+private:
+ std::unique_ptr<SdVectorizeDlg> m_xDlg;
+public:
+ AbstractSdVectorizeDlg_Impl(std::unique_ptr<SdVectorizeDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual const GDIMetaFile& GetGDIMetaFile() const override ;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractSdPublishingDlg_Impl :public AbstractSdPublishingDlg
+{
+private:
+ std::unique_ptr<SdPublishingDlg> m_xDlg;
+public:
+ AbstractSdPublishingDlg_Impl(std::unique_ptr<SdPublishingDlg> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual void GetParameterSequence( css::uno::Sequence< css::beans::PropertyValue >& rParams ) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractHeaderFooterDialog_Impl :public AbstractHeaderFooterDialog
+{
+private:
+ std::shared_ptr<::sd::HeaderFooterDialog> m_xDlg;
+public:
+ AbstractHeaderFooterDialog_Impl(std::shared_ptr<::sd::HeaderFooterDialog> pDlg)
+ : m_xDlg(std::move(pDlg))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(AsyncContext &rCtx) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+//AbstractDialogFactory_Impl implementations
+class SdAbstractDialogFactory_Impl : public SdAbstractDialogFactory
+{
+
+public:
+ virtual ~SdAbstractDialogFactory_Impl() {}
+
+ virtual VclPtr<AbstractSvxBulletAndPositionDlg> CreateSvxBulletAndPositionDlg(weld::Window* pParent, const SfxItemSet* pAttr, ::sd::View* pView) override;
+ virtual VclPtr<VclAbstractDialog> CreateBreakDlg(weld::Window* pWindow, ::sd::DrawView* pDrView, ::sd::DrawDocShell* pShell, sal_uLong nSumActionCount, sal_uLong nObjCount) override;
+ virtual VclPtr<AbstractCopyDlg> CreateCopyDlg(weld::Window* pParent, const SfxItemSet& rInAttrs, ::sd::View* pView) override;
+ virtual VclPtr<AbstractSdCustomShowDlg> CreateSdCustomShowDlg(weld::Window* pParent, SdDrawDocument& rDrawDoc) override;
+ virtual VclPtr<SfxAbstractTabDialog> CreateSdTabCharDialog(weld::Window* pWindow, const SfxItemSet* pAttr, SfxObjectShell* pDocShell) override;
+ virtual VclPtr<SfxAbstractTabDialog> CreateSdTabPageDialog(weld::Window* pWindow, const SfxItemSet* pAttr, SfxObjectShell* pDocShell, bool bAreaPage, bool bIsImpressDoc, bool bIsImpressMaster) override;
+ virtual VclPtr<AbstractSdModifyFieldDlg> CreateSdModifyFieldDlg(weld::Window* pWindow, const SvxFieldData* pInField, const SfxItemSet& rSet) override;
+ virtual VclPtr<AbstractSdSnapLineDlg> CreateSdSnapLineDlg(weld::Window* pParent, const SfxItemSet& rInAttrs, ::sd::View* pView) override;
+ virtual VclPtr<AbstractSdInsertLayerDlg> CreateSdInsertLayerDlg(weld::Window* pParent, const SfxItemSet& rInAttrs, bool bDeletable, const OUString& aStr) override;
+ virtual VclPtr<AbstractSdInsertPagesObjsDlg> CreateSdInsertPagesObjsDlg(weld::Window* pParent, const SdDrawDocument* pDoc, SfxMedium* pSfxMedium, const OUString& rFileName ) override;
+ virtual VclPtr<AbstractMorphDlg> CreateMorphDlg(weld::Window* pParent, const SdrObject* pObj1, const SdrObject* pObj2) override;
+ virtual VclPtr<SfxAbstractTabDialog> CreateSdOutlineBulletTabDlg(weld::Window* pParent, const SfxItemSet* pAttr, ::sd::View* pView) override;
+ virtual VclPtr<SfxAbstractTabDialog> CreateSdParagraphTabDlg(weld::Window* pParent, const SfxItemSet* pAttr) override;
+ virtual VclPtr<AbstractSdStartPresDlg> CreateSdStartPresentationDlg(weld::Window* pWindow, const SfxItemSet& rInAttrs,
+ const std::vector<OUString> &rPageNames, SdCustomShowList* pCSList ) override;
+ virtual VclPtr<VclAbstractDialog> CreateRemoteDialog(weld::Window* pWindow) override; // add for RemoteDialog
+ virtual VclPtr<SfxAbstractTabDialog> CreateSdPresLayoutTemplateDlg(SfxObjectShell* pDocSh, weld::Window* pParent, bool bBackgroundDlg, SfxStyleSheetBase& rStyleBase, PresentationObjects ePO, SfxStyleSheetBasePool* pSSPool) override;
+ virtual VclPtr<AbstractSdPresLayoutDlg> CreateSdPresLayoutDlg(weld::Window* pParent, ::sd::DrawDocShell* pDocShell, const SfxItemSet& rInAttrs) override;
+ virtual VclPtr<SfxAbstractTabDialog> CreateSdTabTemplateDlg(weld::Window* pParent, const SfxObjectShell* pDocShell, SfxStyleSheetBase& rStyleBase, SdrModel* pModel, SdrView* pView ) override;
+ virtual VclPtr<SfxAbstractDialog> CreatSdActionDialog(weld::Window* pParent, const SfxItemSet* pAttr, ::sd::View* pView) override;
+ virtual VclPtr<AbstractSdVectorizeDlg> CreateSdVectorizeDlg(weld::Window* pParent, const Bitmap& rBmp, ::sd::DrawDocShell* pDocShell) override;
+ virtual VclPtr<AbstractSdPublishingDlg> CreateSdPublishingDlg(weld::Window* pWindow, DocumentType eDocType) override;
+
+ virtual VclPtr<VclAbstractDialog> CreateSdPhotoAlbumDialog(weld::Window* pWindow, SdDrawDocument* pDoc) override;
+
+ virtual VclPtr<VclAbstractDialog> CreateMasterLayoutDialog(weld::Window* pParent, SdDrawDocument* pDoc, SdPage*) override;
+
+ virtual VclPtr<AbstractHeaderFooterDialog> CreateHeaderFooterDialog(sd::ViewShell* pViewShell,
+ weld::Window* pParent,
+ SdDrawDocument* pDoc,
+ SdPage* pCurrentPage) override;
+
+ // For TabPage
+ virtual CreateTabPage GetSdOptionsContentsTabPageCreatorFunc() override;
+ virtual CreateTabPage GetSdPrintOptionsTabPageCreatorFunc() override;
+ virtual CreateTabPage GetSdOptionsMiscTabPageCreatorFunc() override;
+ virtual CreateTabPage GetSdOptionsSnapTabPageCreatorFunc() override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/sdpreslt.cxx b/sd/source/ui/dlg/sdpreslt.cxx
new file mode 100644
index 000000000..dd54611e2
--- /dev/null
+++ b/sd/source/ui/dlg/sdpreslt.cxx
@@ -0,0 +1,267 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/itemset.hxx>
+#include <svl/eitem.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/new.hxx>
+#include <svtools/valueset.hxx>
+#include <tools/debug.hxx>
+#include <vcl/image.hxx>
+
+#include <strings.hrc>
+
+#include <bitmaps.hlst>
+#include <sdpreslt.hxx>
+#include <sdattr.hrc>
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <DrawDocShell.hxx>
+#include <memory>
+
+SdPresLayoutDlg::SdPresLayoutDlg(::sd::DrawDocShell* pDocShell,
+ weld::Window* pWindow, const SfxItemSet& rInAttrs)
+ : GenericDialogController(pWindow, "modules/simpress/ui/slidedesigndialog.ui", "SlideDesignDialog")
+ , mpDocSh(pDocShell)
+ , mrOutAttrs(rInAttrs)
+ , maStrNone(SdResId(STR_NULL))
+ , m_xCbxMasterPage(m_xBuilder->weld_check_button("masterpage"))
+ , m_xCbxCheckMasters(m_xBuilder->weld_check_button("checkmasters"))
+ , m_xBtnLoad(m_xBuilder->weld_button("load"))
+ , m_xVS(new ValueSet(m_xBuilder->weld_scrolled_window("selectwin", true)))
+ , m_xVSWin(new weld::CustomWeld(*m_xBuilder, "select", *m_xVS))
+{
+ m_xVSWin->set_size_request(m_xBtnLoad->get_approximate_digit_width() * 60,
+ m_xBtnLoad->get_text_height() * 20);
+
+ m_xVS->SetDoubleClickHdl(LINK(this, SdPresLayoutDlg, ClickLayoutHdl));
+ m_xBtnLoad->connect_clicked(LINK(this, SdPresLayoutDlg, ClickLoadHdl));
+
+ Reset();
+}
+
+SdPresLayoutDlg::~SdPresLayoutDlg()
+{
+}
+
+/**
+ * Initialize
+ */
+void SdPresLayoutDlg::Reset()
+{
+ tools::Long nName;
+
+ // replace master page
+ if( const SfxBoolItem* pPoolItem = mrOutAttrs.GetItemIfSet( ATTR_PRESLAYOUT_MASTER_PAGE, false ) )
+ {
+ bool bMasterPage = pPoolItem->GetValue();
+ m_xCbxMasterPage->set_sensitive( !bMasterPage );
+ m_xCbxMasterPage->set_active( bMasterPage );
+ }
+
+ // remove not used master pages
+ m_xCbxCheckMasters->set_active(false);
+
+ if( const SfxStringItem* pPoolItem = mrOutAttrs.GetItemIfSet(ATTR_PRESLAYOUT_NAME) )
+ maName = pPoolItem->GetValue();
+ else
+ maName.clear();
+
+ FillValueSet();
+
+ mnLayoutCount = maLayoutNames.size();
+ for( nName = 0; nName < mnLayoutCount; nName++ )
+ {
+ if (maLayoutNames[nName] == maName)
+ break;
+ }
+ DBG_ASSERT(nName < mnLayoutCount, "Layout not found");
+
+ m_xVS->SelectItem(static_cast<sal_uInt16>(nName) + 1); // Indices of the ValueSets start at 1
+
+}
+
+/**
+ * Fills the provided Item-Set with dialog box attributes
+ */
+void SdPresLayoutDlg::GetAttr(SfxItemSet& rOutAttrs)
+{
+ short nId = m_xVS->GetSelectedItemId();
+ bool bLoad = nId > mnLayoutCount;
+ rOutAttrs.Put( SfxBoolItem( ATTR_PRESLAYOUT_LOAD, bLoad ) );
+
+ OUString aLayoutName;
+
+ if( bLoad )
+ {
+ aLayoutName = maName + "#" + maLayoutNames[ nId - 1 ];
+ }
+ else if (nId)
+ {
+ aLayoutName = maLayoutNames[ nId - 1 ];
+ if( aLayoutName == maStrNone )
+ aLayoutName.clear(); // that way we encode "- nothing -" (see below)
+ }
+
+ rOutAttrs.Put( SfxStringItem( ATTR_PRESLAYOUT_NAME, aLayoutName ) );
+ rOutAttrs.Put( SfxBoolItem( ATTR_PRESLAYOUT_MASTER_PAGE, m_xCbxMasterPage->get_active() ) );
+ rOutAttrs.Put( SfxBoolItem( ATTR_PRESLAYOUT_CHECK_MASTERS, m_xCbxCheckMasters->get_active() ) );
+}
+
+/**
+ * Fills ValueSet with bitmaps
+ */
+void SdPresLayoutDlg::FillValueSet()
+{
+ m_xVS->SetStyle(m_xVS->GetStyle() | WB_ITEMBORDER | WB_DOUBLEBORDER
+ | WB_VSCROLL | WB_NAMEFIELD);
+
+ m_xVS->SetColCount(2);
+ m_xVS->SetLineCount(2);
+ m_xVS->SetExtraSpacing(2);
+
+ SdDrawDocument* pDoc = mpDocSh->GetDoc();
+
+ sal_uInt16 nCount = pDoc->GetMasterPageCount();
+
+ for (sal_uInt16 nLayout = 0; nLayout < nCount; nLayout++)
+ {
+ SdPage* pMaster = static_cast<SdPage*>(pDoc->GetMasterPage(nLayout));
+ if (pMaster->GetPageKind() == PageKind::Standard)
+ {
+ OUString aLayoutName(pMaster->GetLayoutName());
+ aLayoutName = aLayoutName.copy(0, aLayoutName.indexOf(SD_LT_SEPARATOR));
+ maLayoutNames.push_back(aLayoutName);
+
+ Image aBitmap(mpDocSh->GetPagePreviewBitmap(pMaster));
+ m_xVS->InsertItem(static_cast<sal_uInt16>(maLayoutNames.size()), aBitmap, aLayoutName);
+ }
+ }
+
+ m_xVS->Show();
+}
+
+/**
+ * DoubleClick handler
+ */
+IMPL_LINK_NOARG(SdPresLayoutDlg, ClickLayoutHdl, ValueSet*, void)
+{
+ m_xDialog->response(RET_OK);
+}
+
+/**
+ * Click handler for load button
+ */
+IMPL_LINK_NOARG(SdPresLayoutDlg, ClickLoadHdl, weld::Button&, void)
+{
+ SfxNewFileDialog aDlg(m_xDialog.get(), SfxNewFileDialogMode::Preview);
+ aDlg.set_title(SdResId(STR_LOAD_PRESENTATION_LAYOUT));
+ sal_uInt16 nResult = aDlg.run();
+
+ bool bCancel = false;
+
+ switch (nResult)
+ {
+ case RET_OK:
+ {
+ if (aDlg.IsTemplate())
+ {
+ maName = aDlg.GetTemplateFileName();
+ }
+ else
+ {
+ // that way we encode "- nothing -"
+ maName.clear();
+ }
+ }
+ break;
+
+ default:
+ bCancel = true;
+ }
+
+ if( bCancel )
+ return;
+
+ // check if template already exists
+ OUString aCompareStr(maName);
+ if (aCompareStr.isEmpty())
+ aCompareStr = maStrNone;
+
+ auto it = std::find(maLayoutNames.begin(), maLayoutNames.end(), aCompareStr);
+ if (it != maLayoutNames.end())
+ {
+ sal_uInt16 aPos = static_cast<sal_uInt16>(std::distance(maLayoutNames.begin(), it));
+ // select template
+ m_xVS->SelectItem( aPos + 1 );
+ }
+ else
+ {
+ // load document in order to determine preview bitmap (if template is selected)
+ if (!maName.isEmpty())
+ {
+ // determine document in order to call OpenBookmarkDoc
+ SdDrawDocument* pDoc = mpDocSh->GetDoc();
+ SdDrawDocument* pTemplDoc = pDoc->OpenBookmarkDoc( maName );
+
+ if (pTemplDoc)
+ {
+ ::sd::DrawDocShell* pTemplDocSh= pTemplDoc->GetDocSh();
+
+ sal_uInt16 nCount = pTemplDoc->GetMasterPageCount();
+
+ for (sal_uInt16 nLayout = 0; nLayout < nCount; nLayout++)
+ {
+ SdPage* pMaster = static_cast<SdPage*>( pTemplDoc->GetMasterPage(nLayout) );
+ if (pMaster->GetPageKind() == PageKind::Standard)
+ {
+ OUString aLayoutName(pMaster->GetLayoutName());
+ aLayoutName = aLayoutName.copy(0, aLayoutName.indexOf(SD_LT_SEPARATOR));
+ maLayoutNames.push_back(aLayoutName);
+
+ Image aBitmap(pTemplDocSh->GetPagePreviewBitmap(pMaster));
+ m_xVS->InsertItem(static_cast<sal_uInt16>(maLayoutNames.size()), aBitmap, aLayoutName);
+ }
+ }
+ }
+ else
+ {
+ bCancel = true;
+ }
+
+ pDoc->CloseBookmarkDoc();
+ }
+ else
+ {
+ // empty layout
+ maLayoutNames.push_back(maStrNone);
+ m_xVS->InsertItem( static_cast<sal_uInt16>(maLayoutNames.size()),
+ Image(BMP_SLIDE_NONE), maStrNone );
+ }
+
+ if (!bCancel)
+ {
+ // select template
+ m_xVS->SelectItem( static_cast<sal_uInt16>(maLayoutNames.size()) );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/sdtreelb.cxx b/sd/source/ui/dlg/sdtreelb.cxx
new file mode 100644
index 000000000..c15a2ea09
--- /dev/null
+++ b/sd/source/ui/dlg/sdtreelb.cxx
@@ -0,0 +1,1206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <sot/formats.hxx>
+#include <vcl/weld.hxx>
+#include <svx/svditer.hxx>
+#include <sfx2/docfile.hxx>
+#include <svx/svdoole2.hxx>
+#include <vcl/svapp.hxx>
+#include <cusshow.hxx>
+
+#include <sfx2/viewfrm.hxx>
+
+#include <sdtreelb.hxx>
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <sdmod.hxx>
+#include <sdresid.hxx>
+#include <navigatr.hxx>
+#include <strings.hrc>
+
+#include <bitmaps.hlst>
+#include <customshowlist.hxx>
+#include <ViewShell.hxx>
+#include <DrawController.hxx>
+#include <ViewShellBase.hxx>
+
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <svtools/acceleratorexecute.hxx>
+#include <svtools/embedtransfer.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/processfactory.hxx>
+
+
+using namespace com::sun::star;
+
+bool SdPageObjsTLV::bIsInDrag = false;
+
+bool SdPageObjsTLV::IsInDrag()
+{
+ return bIsInDrag;
+}
+
+SotClipboardFormatId SdPageObjsTLV::SdPageObjsTransferable::mnListBoxDropFormatId = static_cast<SotClipboardFormatId>(SAL_MAX_UINT32);
+
+SdPageObjsTLV::SdPageObjsTransferable::SdPageObjsTransferable(
+ const INetBookmark& rBookmark,
+ ::sd::DrawDocShell& rDocShell,
+ NavigatorDragType eDragType)
+ : SdTransferable(rDocShell.GetDoc(), nullptr, true),
+ maBookmark( rBookmark ),
+ mrDocShell( rDocShell ),
+ meDragType( eDragType )
+{
+}
+
+SdPageObjsTLV::SdPageObjsTransferable::~SdPageObjsTransferable()
+{
+}
+
+void SdPageObjsTLV::SdPageObjsTransferable::AddSupportedFormats()
+{
+ AddFormat(SotClipboardFormatId::NETSCAPE_BOOKMARK);
+ AddFormat(SotClipboardFormatId::TREELISTBOX);
+ AddFormat(GetListBoxDropFormatId());
+}
+
+bool SdPageObjsTLV::SdPageObjsTransferable::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+{
+ SotClipboardFormatId nFormatId = SotExchange::GetFormat( rFlavor );
+ switch (nFormatId)
+ {
+ case SotClipboardFormatId::NETSCAPE_BOOKMARK:
+ SetINetBookmark( maBookmark, rFlavor );
+ return true;
+
+ case SotClipboardFormatId::TREELISTBOX:
+ {
+ css::uno::Any aTreeListBoxData; // empty for now
+ SetAny(aTreeListBoxData);
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+void SdPageObjsTLV::SdPageObjsTransferable::DragFinished( sal_Int8 nDropAction )
+{
+ SdPageObjsTLV::OnDragFinished();
+ SdTransferable::DragFinished(nDropAction);
+}
+
+sal_Int64 SAL_CALL SdPageObjsTLV::SdPageObjsTransferable::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<SdTransferable>{});
+}
+
+const css::uno::Sequence<sal_Int8>& SdPageObjsTLV::SdPageObjsTransferable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theSdPageObjsTLBUnoTunnelId;
+ return theSdPageObjsTLBUnoTunnelId.getSeq();
+}
+
+SdPageObjsTLV::SdPageObjsTransferable* SdPageObjsTLV::SdPageObjsTransferable::getImplementation( const css::uno::Reference< css::uno::XInterface >& rxData )
+ noexcept
+{
+ try
+ {
+ return comphelper::getFromUnoTunnel<SdPageObjsTLV::SdPageObjsTransferable>(rxData);
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+ return nullptr;
+}
+
+SotClipboardFormatId SdPageObjsTLV::SdPageObjsTransferable::GetListBoxDropFormatId()
+{
+ if (mnListBoxDropFormatId == static_cast<SotClipboardFormatId>(SAL_MAX_UINT32))
+ mnListBoxDropFormatId = SotExchange::RegisterFormatMimeType("application/x-openoffice-treelistbox-moveonly;windows_formatname=\"SV_LBOX_DD_FORMAT_MOVE\"");
+ return mnListBoxDropFormatId;
+}
+
+/**
+ * @return true if children of the specified string are selected
+ */
+bool SdPageObjsTLV::HasSelectedChildren( std::u16string_view rName )
+{
+ bool bChildren = false;
+
+ if( !rName.empty() )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ OUString aTmp;
+
+ if (m_xTreeView->get_iter_first(*xEntry))
+ {
+ do
+ {
+ aTmp = m_xTreeView->get_text(*xEntry);
+ if (aTmp == rName)
+ {
+
+ // see if any of the selected nodes are subchildren of this node
+ m_xTreeView->selected_foreach([this, &bChildren, &xEntry](weld::TreeIter& rEntry){
+ std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
+ while (!bChildren && m_xTreeView->iter_parent(*xParent))
+ bChildren = m_xTreeView->iter_compare(*xParent, *xEntry) == 0;
+ return bChildren;
+ });
+
+ break;
+ }
+ }
+ while (m_xTreeView->iter_next(*xEntry));
+ }
+ }
+
+ return bChildren;
+}
+
+void SdPageObjsTLV::SetShowAllShapes (
+ const bool bShowAllShapes,
+ const bool bFillList)
+{
+ m_bShowAllShapes = bShowAllShapes;
+ if (bFillList)
+ {
+ if (m_pMedium == nullptr)
+ Fill(m_pDoc, m_bShowAllPages, m_aDocName);
+ else
+ Fill(m_pDoc, m_pMedium, m_aDocName);
+ }
+}
+
+bool SdPageObjsTLV::IsEqualToShapeList(std::unique_ptr<weld::TreeIter>& rEntry, const SdrObjList& rList,
+ std::u16string_view rListName)
+{
+ if (!rEntry)
+ return false;
+ OUString aName = m_xTreeView->get_text(*rEntry);
+
+ if (rListName != aName)
+ return false;
+
+ if (!m_xTreeView->iter_next(*rEntry))
+ rEntry.reset();
+
+ SdrObjListIter aIter(&rList,
+ !rList.HasObjectNavigationOrder() /* use navigation order, if available */,
+ SdrIterMode::Flat);
+
+ while (aIter.IsMore())
+ {
+ SdrObject* pObj = aIter.Next();
+
+ const OUString aObjectName(GetObjectName(pObj));
+
+ if (!aObjectName.isEmpty())
+ {
+ if (!rEntry)
+ return false;
+
+ aName = m_xTreeView->get_text(*rEntry);
+
+ if (aObjectName != aName)
+ return false;
+
+ if (pObj->IsGroupObject())
+ {
+ bool bRet = IsEqualToShapeList(rEntry, *pObj->GetSubList(), aObjectName);
+ if (!bRet)
+ return false;
+ }
+ else
+ {
+ if (!m_xTreeView->iter_next(*rEntry))
+ rEntry.reset();
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Checks if the pages (PageKind::Standard) of a doc and the objects on the pages
+ * are identical to the TreeLB.
+ * If a doc is provided, this will be the used doc (important by more than
+ * one document).
+ */
+bool SdPageObjsTLV::IsEqualToDoc( const SdDrawDocument* pInDoc )
+{
+ if( pInDoc )
+ m_pDoc = pInDoc;
+
+ if( !m_pDoc )
+ return false;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_iter_first(*xEntry))
+ xEntry.reset();
+
+ // compare all pages including the objects
+ sal_uInt16 nPage = 0;
+ const sal_uInt16 nMaxPages = m_pDoc->GetPageCount();
+
+ while( nPage < nMaxPages )
+ {
+ const SdPage* pPage = static_cast<const SdPage*>( m_pDoc->GetPage( nPage ) );
+ if( pPage->GetPageKind() == PageKind::Standard )
+ {
+ bool bRet = IsEqualToShapeList(xEntry, *pPage, pPage->GetName());
+ if (!bRet)
+ return false;
+ }
+ nPage++;
+ }
+ // If there are still entries in the listbox,
+ // then objects (with names) or pages were deleted
+ return !xEntry;
+}
+
+IMPL_LINK(SdPageObjsTLV, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ if (m_xAccel->execute(rKeyCode))
+ {
+ // the accelerator consumed the event
+ return true;
+ }
+ if (rKeyCode.GetCode() == KEY_RETURN)
+ {
+ std::unique_ptr<weld::TreeIter> xCursor(m_xTreeView->make_iterator());
+ if (m_xTreeView->get_cursor(xCursor.get()) && m_xTreeView->iter_has_child(*xCursor))
+ {
+ if (m_xTreeView->get_row_expanded(*xCursor))
+ m_xTreeView->collapse_row(*xCursor);
+ else
+ m_xTreeView->expand_row(*xCursor);
+ }
+ m_aRowActivatedHdl.Call(*m_xTreeView);
+ return true;
+ }
+ return m_aKeyPressHdl.Call(rKEvt);
+}
+
+IMPL_LINK(SdPageObjsTLV, MousePressHdl, const MouseEvent&, rMEvt, bool)
+{
+ m_bSelectionHandlerNavigates = rMEvt.GetClicks() == 1;
+ m_bNavigationGrabsFocus = rMEvt.GetClicks() != 1;
+ return false;
+}
+
+IMPL_LINK_NOARG(SdPageObjsTLV, MouseReleaseHdl, const MouseEvent&, bool)
+{
+ m_bSelectionHandlerNavigates = false;
+ m_bNavigationGrabsFocus = true;
+ return false;
+}
+
+IMPL_LINK(SdPageObjsTLV, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+{
+ rUnsetDragIcon = false;
+ return StartDrag();
+}
+
+namespace
+{
+ bool CanDragSource(const weld::TreeView& rTreeView)
+ {
+ std::unique_ptr<weld::TreeIter> xSource(rTreeView.make_iterator());
+ if (!rTreeView.get_selected(xSource.get()))
+ return false;
+
+ std::unique_ptr<weld::TreeIter> xSourceParent(rTreeView.make_iterator(xSource.get()));
+ bool bSourceHasParent = rTreeView.iter_parent(*xSourceParent);
+ // level 1 objects only
+ if (!bSourceHasParent || rTreeView.get_iter_depth(*xSourceParent))
+ return false;
+
+ SdrObject* pSourceObject = weld::fromId<SdrObject*>(rTreeView.get_id(*xSource));
+ if (pSourceObject == reinterpret_cast<SdrObject*>(1))
+ pSourceObject = nullptr;
+
+ if (!pSourceObject)
+ return false;
+
+ SdrPage* pObjectList = pSourceObject->getSdrPageFromSdrObject();
+ if (!pObjectList)
+ return false;
+
+ return true;
+ }
+}
+
+/**
+ * StartDrag-Request
+ */
+bool SdPageObjsTLV::StartDrag()
+{
+ return !CanDragSource(*m_xTreeView) || DoDrag();
+}
+
+/**
+ * Begin drag
+ */
+bool SdPageObjsTLV::DoDrag()
+{
+ if (!m_pNavigator)
+ return true;
+
+ if (!m_xHelper)
+ return true;
+
+ // Get the view.
+ ::sd::DrawDocShell* pDocShell = m_pDoc->GetDocSh();
+ ::sd::ViewShell* pViewShell = GetViewShellForDocShell(*pDocShell);
+ if (pViewShell == nullptr)
+ {
+ OSL_ASSERT(pViewShell!=nullptr);
+ return true;
+ }
+ sd::View* pView = pViewShell->GetView();
+ if (pView == nullptr)
+ {
+ OSL_ASSERT(pView!=nullptr);
+ return true;
+ }
+
+ bIsInDrag = true;
+
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ bool bUserData = m_xTreeView->get_cursor(xEntry.get());
+
+ SdrObject* pObject = nullptr;
+ sal_Int64 nUserData = bUserData ? m_xTreeView->get_id(*xEntry).toInt64() : 0;
+ if (nUserData != 1)
+ pObject = reinterpret_cast<SdrObject*>(nUserData);
+ if (pObject != nullptr)
+ {
+ // For shapes without a user supplied name (the automatically
+ // created name does not count), a different drag and drop technique
+ // is used.
+ if (GetObjectName(pObject, false).isEmpty())
+ {
+ AddShapeToTransferable(*m_xHelper, *pObject);
+ m_xHelper->SetView(pView);
+ SD_MOD()->pTransferDrag = m_xHelper.get();
+ }
+
+ // Unnamed shapes have to be selected to be recognized by the
+ // current drop implementation. In order to have a consistent
+ // behaviour for all shapes, every shape that is to be dragged is
+ // selected first.
+ SdrPageView* pPageView = pView->GetSdrPageView();
+ pView->UnmarkAllObj(pPageView);
+ pView->MarkObj(pObject, pPageView);
+ }
+ else
+ {
+ m_xHelper->SetView(pView);
+ SD_MOD()->pTransferDrag = m_xHelper.get();
+ }
+
+ return false;
+}
+
+void SdPageObjsTLV::OnDragFinished()
+{
+ bIsInDrag = false;
+}
+
+SdPageObjsTLVDropTarget::SdPageObjsTLVDropTarget(weld::TreeView& rTreeView)
+ : DropTargetHelper(rTreeView.get_drop_target())
+ , m_rTreeView(rTreeView)
+{
+}
+
+/**
+ * AcceptDrop-Event
+ */
+sal_Int8 SdPageObjsTLVDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ weld::TreeView* pSource = m_rTreeView.get_drag_source();
+ // only dragging within the same widget allowed
+ if (!pSource || pSource != &m_rTreeView)
+ return DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xTarget(m_rTreeView.make_iterator());
+ if (!m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
+ return DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xSource(m_rTreeView.make_iterator());
+ if (!m_rTreeView.get_selected(xSource.get()))
+ return DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xTargetParent(m_rTreeView.make_iterator(xTarget.get()));
+ while (m_rTreeView.get_iter_depth(*xTargetParent))
+ m_rTreeView.iter_parent(*xTargetParent);
+
+ std::unique_ptr<weld::TreeIter> xSourceParent(m_rTreeView.make_iterator(xSource.get()));
+ while (m_rTreeView.get_iter_depth(*xSourceParent))
+ m_rTreeView.iter_parent(*xSourceParent);
+
+ // can only drop within the same page
+ if (m_rTreeView.iter_compare(*xTargetParent, *xSourceParent) != 0)
+ return DND_ACTION_NONE;
+
+ return DND_ACTION_MOVE;
+}
+
+/**
+ * ExecuteDrop-Event
+ */
+sal_Int8 SdPageObjsTLVDropTarget::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ weld::TreeView* pSource = m_rTreeView.get_drag_source();
+ // only dragging within the same widget allowed
+ if (!pSource || pSource != &m_rTreeView)
+ return DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xSource(m_rTreeView.make_iterator());
+ if (!m_rTreeView.get_selected(xSource.get()))
+ return DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xTarget(m_rTreeView.make_iterator());
+ if (!m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
+ return DND_ACTION_NONE;
+ int nTargetPos = m_rTreeView.get_iter_index_in_parent(*xTarget) + 1;
+
+ SdrObject* pTargetObject = weld::fromId<SdrObject*>(m_rTreeView.get_id(*xTarget));
+ SdrObject* pSourceObject = weld::fromId<SdrObject*>(m_rTreeView.get_id(*xSource));
+ if (pSourceObject == reinterpret_cast<SdrObject*>(1))
+ pSourceObject = nullptr;
+
+ if (pTargetObject != nullptr && pSourceObject != nullptr)
+ {
+ SdrPage* pObjectList = pSourceObject->getSdrPageFromSdrObject();
+ if (pObjectList != nullptr)
+ {
+ sal_uInt32 nNewPosition;
+ if (pTargetObject == reinterpret_cast<SdrObject*>(1))
+ {
+ nNewPosition = 0;
+ nTargetPos = 0;
+ }
+ else
+ nNewPosition = pTargetObject->GetNavigationPosition() + 1;
+ pObjectList->SetObjectNavigationPosition(*pSourceObject, nNewPosition);
+ }
+
+ std::unique_ptr<weld::TreeIter> xSourceParent(m_rTreeView.make_iterator(xSource.get()));
+ m_rTreeView.iter_parent(*xSourceParent);
+
+ m_rTreeView.move_subtree(*xSource, xSourceParent.get(), nTargetPos);
+ }
+
+ return DND_ACTION_NONE;
+}
+
+void SdPageObjsTLV::AddShapeToTransferable (
+ SdTransferable& rTransferable,
+ const SdrObject& rObject) const
+{
+ std::unique_ptr<TransferableObjectDescriptor> pObjectDescriptor(new TransferableObjectDescriptor);
+ bool bIsDescriptorFillingPending (true);
+
+ const SdrOle2Obj* pOleObject = dynamic_cast<const SdrOle2Obj*>(&rObject);
+ if (pOleObject != nullptr && pOleObject->GetObjRef().is())
+ {
+ // If object has no persistence it must be copied as part of the document
+ try
+ {
+ uno::Reference< embed::XEmbedPersist > xPersObj (pOleObject->GetObjRef(), uno::UNO_QUERY );
+ if (xPersObj.is() && xPersObj->hasEntry())
+ {
+ SvEmbedTransferHelper::FillTransferableObjectDescriptor(
+ *pObjectDescriptor,
+ pOleObject->GetObjRef(),
+ pOleObject->GetGraphic(),
+ pOleObject->GetAspect());
+ bIsDescriptorFillingPending = false;
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+
+ ::sd::DrawDocShell* pDocShell = m_pDoc->GetDocSh();
+ if (bIsDescriptorFillingPending && pDocShell!=nullptr)
+ {
+ pDocShell->FillTransferableObjectDescriptor(*pObjectDescriptor);
+ }
+
+ Point aDragPos (rObject.GetCurrentBoundRect().Center());
+ pObjectDescriptor->maDragStartPos = aDragPos;
+ if (pDocShell != nullptr)
+ pObjectDescriptor->maDisplayName = pDocShell->GetMedium()->GetURLObject().GetURLNoPass();
+ else
+ pObjectDescriptor->maDisplayName.clear();
+
+ rTransferable.SetStartPos(aDragPos);
+ rTransferable.SetObjectDescriptor( std::move(pObjectDescriptor) );
+}
+
+::sd::ViewShell* SdPageObjsTLV::GetViewShellForDocShell (::sd::DrawDocShell& rDocShell)
+{
+ {
+ ::sd::ViewShell* pViewShell = rDocShell.GetViewShell();
+ if (pViewShell != nullptr)
+ return pViewShell;
+ }
+
+ try
+ {
+ // Get a component enumeration from the desktop and search it for documents.
+ uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext());
+
+ uno::Reference<frame::XDesktop2> xDesktop = frame::Desktop::create(xContext);
+
+ if ( ! xDesktop.is())
+ return nullptr;
+
+ uno::Reference<container::XIndexAccess> xFrameAccess = xDesktop->getFrames();
+ if ( ! xFrameAccess.is())
+ return nullptr;
+
+ for (sal_Int32 nIndex=0,nCount=xFrameAccess->getCount(); nIndex<nCount; ++nIndex)
+ {
+ uno::Reference<frame::XFrame> xFrame;
+ if ( ! (xFrameAccess->getByIndex(nIndex) >>= xFrame))
+ continue;
+
+ auto xController = xFrame->getController();
+ ::sd::DrawController* pController = dynamic_cast<sd::DrawController*>(xController.get());
+ if (pController == nullptr)
+ continue;
+ ::sd::ViewShellBase* pBase = pController->GetViewShellBase();
+ if (pBase == nullptr)
+ continue;
+ if (pBase->GetDocShell() != &rDocShell)
+ continue;
+
+ const std::shared_ptr<sd::ViewShell> pViewShell (pBase->GetMainViewShell());
+ if (pViewShell)
+ return pViewShell.get();
+ }
+ }
+ catch (uno::Exception &)
+ {
+ // When there is an exception then simply use the default value of
+ // bIsEnabled and disable the controls.
+ }
+ return nullptr;
+}
+
+SdPageObjsTLV::SdPageObjsTLV(std::unique_ptr<weld::TreeView> xTreeView)
+ : m_xTreeView(std::move(xTreeView))
+ , m_xScratchIter(m_xTreeView->make_iterator())
+ , m_xDropTargetHelper(new SdPageObjsTLVDropTarget(*m_xTreeView))
+ , m_xAccel(::svt::AcceleratorExecute::createAcceleratorHelper())
+ , m_pNavigator(nullptr)
+ , m_pDoc(nullptr)
+ , m_pBookmarkDoc(nullptr)
+ , m_pMedium(nullptr)
+ , m_pOwnMedium(nullptr)
+ , m_bLinkableSelected(false)
+ , m_bShowAllShapes(false)
+ , m_bShowAllPages(false)
+ , m_bSelectionHandlerNavigates(false)
+ , m_bNavigationGrabsFocus(true)
+ , m_eSelectionMode(SelectionMode::Single)
+ , m_nSelectEventId(nullptr)
+ , m_nRowActivateEventId(nullptr)
+{
+ m_xTreeView->connect_expanding(LINK(this, SdPageObjsTLV, RequestingChildrenHdl));
+ m_xTreeView->connect_changed(LINK(this, SdPageObjsTLV, SelectHdl));
+ m_xTreeView->connect_row_activated(LINK(this, SdPageObjsTLV, RowActivatedHdl));
+ m_xTreeView->connect_drag_begin(LINK(this, SdPageObjsTLV, DragBeginHdl));
+ m_xTreeView->connect_key_press(LINK(this, SdPageObjsTLV, KeyInputHdl));
+ m_xTreeView->connect_mouse_press(LINK(this, SdPageObjsTLV, MousePressHdl));
+ m_xTreeView->connect_mouse_release(LINK(this, SdPageObjsTLV, MouseReleaseHdl));
+
+ m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 28,
+ m_xTreeView->get_text_height() * 8);
+}
+
+IMPL_LINK_NOARG(SdPageObjsTLV, SelectHdl, weld::TreeView&, void)
+{
+ if (m_nSelectEventId)
+ Application::RemoveUserEvent(m_nSelectEventId);
+ // post the event to process select event after mouse press event
+ m_nSelectEventId = Application::PostUserEvent(LINK(this, SdPageObjsTLV, AsyncSelectHdl));
+}
+
+IMPL_LINK_NOARG(SdPageObjsTLV, RowActivatedHdl, weld::TreeView&, bool)
+{
+ if (m_nRowActivateEventId)
+ Application::RemoveUserEvent(m_nRowActivateEventId);
+ // post the event to process row activate after mouse press event
+ m_nRowActivateEventId = Application::PostUserEvent(LINK(this, SdPageObjsTLV, AsyncRowActivatedHdl));
+ return true;
+}
+
+IMPL_LINK_NOARG(SdPageObjsTLV, AsyncSelectHdl, void*, void)
+{
+ Select();
+}
+
+void SdPageObjsTLV::Select()
+{
+ m_nSelectEventId = nullptr;
+
+ m_bLinkableSelected = true;
+
+ m_xTreeView->selected_foreach([this](weld::TreeIter& rEntry){
+ if (m_xTreeView->get_id(rEntry).toInt64() == 0)
+ m_bLinkableSelected = false;
+ return false;
+ });
+
+ m_aChangeHdl.Call(*m_xTreeView);
+
+ if (m_bSelectionHandlerNavigates)
+ {
+ // Page items in the tree are given user data value 1.
+ // Drawing object items are given user data value of the object pointer they represent.
+ sal_Int64 nUserData = m_xTreeView->get_selected_id().toInt64();
+ if (nUserData != 1)
+ {
+ SdrObject* pObject = reinterpret_cast<SdrObject*>(nUserData);
+ if (pObject && pObject->GetName().isEmpty())
+ {
+ const bool bUndo = pObject->getSdrModelFromSdrObject().IsUndoEnabled();
+ pObject->getSdrModelFromSdrObject().EnableUndo(false);
+ pObject->SetName(m_xTreeView->get_selected_text(), false);
+ pObject->getSdrModelFromSdrObject().EnableUndo(bUndo);
+ m_aRowActivatedHdl.Call(*m_xTreeView);
+ pObject->getSdrModelFromSdrObject().EnableUndo(false);
+ pObject->SetName(OUString(), false);
+ pObject->getSdrModelFromSdrObject().EnableUndo(bUndo);
+ }
+ else
+ m_aRowActivatedHdl.Call(*m_xTreeView);
+ }
+ else
+ m_aRowActivatedHdl.Call(*m_xTreeView);
+ }
+
+ if (!m_pNavigator)
+ {
+ m_xHelper.clear();
+ return;
+ }
+
+ ::sd::DrawDocShell* pDocShell = m_pDoc->GetDocSh();
+ OUString aURL = INetURLObject(pDocShell->GetMedium()->GetPhysicalName(), INetProtocol::File).GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ NavigatorDragType eDragType = m_pNavigator->GetNavigatorDragType();
+
+ OUString sSelectedEntry = m_xTreeView->get_selected_text();
+ aURL += "#" + sSelectedEntry;
+
+ INetBookmark aBookmark(aURL, sSelectedEntry);
+ sal_Int8 nDNDActions = DND_ACTION_COPYMOVE;
+
+ if( eDragType == NAVIGATOR_DRAGTYPE_LINK )
+ nDNDActions = DND_ACTION_LINK; // Either COPY *or* LINK, never both!
+ else if (m_pDoc->GetSdPageCount(PageKind::Standard) == 1)
+ {
+ // Can not move away the last slide in a document.
+ nDNDActions = DND_ACTION_COPY;
+ }
+
+ // object is destroyed by internal reference mechanism
+ m_xHelper.set(new SdPageObjsTLV::SdPageObjsTransferable(aBookmark, *pDocShell, eDragType));
+ rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
+ m_xTreeView->enable_drag_source(xHelper, nDNDActions);
+}
+
+IMPL_LINK_NOARG(SdPageObjsTLV, AsyncRowActivatedHdl, void*, void)
+{
+ m_nRowActivateEventId = nullptr;
+ m_aRowActivatedHdl.Call(*m_xTreeView);
+}
+
+OUString SdPageObjsTLV::GetObjectName(
+ const SdrObject* pObject,
+ const bool bCreate) const
+{
+ OUString aRet;
+
+ if ( pObject )
+ {
+ aRet = pObject->GetName();
+
+ if (aRet.isEmpty())
+ if (auto pOleObj = dynamic_cast<const SdrOle2Obj* >(pObject))
+ aRet = pOleObj->GetPersistName();
+ }
+
+ if (bCreate
+ && m_bShowAllShapes
+ && aRet.isEmpty()
+ && pObject!=nullptr)
+ {
+ aRet = SdResId(STR_NAVIGATOR_SHAPE_BASE_NAME) + " (" + pObject->TakeObjNameSingul() +")";
+ aRet = aRet.replaceFirst("%1", OUString::number(pObject->GetOrdNum() + 1));
+ }
+
+ return aRet;
+}
+
+std::vector<OUString> SdPageObjsTLV::GetSelectEntryList(const int nDepth) const
+{
+ std::vector<OUString> aEntries;
+
+ m_xTreeView->selected_foreach([this, nDepth, &aEntries](weld::TreeIter& rEntry){
+ int nListDepth = m_xTreeView->get_iter_depth(rEntry);
+ if (nListDepth == nDepth)
+ aEntries.push_back(m_xTreeView->get_text(rEntry));
+ return false;
+ });
+
+ return aEntries;
+}
+
+/**
+ * Checks if it is a draw file and opens the BookmarkDoc depending of
+ * the provided Docs
+ */
+SdDrawDocument* SdPageObjsTLV::GetBookmarkDoc(SfxMedium* pMed)
+{
+ if (
+ !m_pBookmarkDoc ||
+ (pMed && (!m_pOwnMedium || m_pOwnMedium->GetName() != pMed->GetName()))
+ )
+ {
+ // create a new BookmarkDoc if now one exists or if a new Medium is provided
+ if (m_pOwnMedium != pMed)
+ {
+ CloseBookmarkDoc();
+ }
+
+ if (pMed)
+ {
+ // it looks that it is undefined if a Medium was set by Fill() already
+ DBG_ASSERT( !m_pMedium, "SfxMedium confusion!" );
+ delete m_pMedium;
+ m_pMedium = nullptr;
+
+ // take over this Medium (currently used only be Navigator)
+ m_pOwnMedium = pMed;
+ }
+
+ DBG_ASSERT( m_pMedium || pMed, "No SfxMedium provided!" );
+
+ if( pMed )
+ {
+ // in this mode the document is also owned and controlled by this instance
+ m_xBookmarkDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::STANDARD, true, DocumentType::Impress);
+ if (m_xBookmarkDocShRef->DoLoad(pMed))
+ m_pBookmarkDoc = m_xBookmarkDocShRef->GetDoc();
+ else
+ m_pBookmarkDoc = nullptr;
+ }
+ else if ( m_pMedium )
+ // in this mode the document is owned and controlled by the SdDrawDocument
+ // it can be released by calling the corresponding CloseBookmarkDoc method
+ // successful creation of a document makes this the owner of the medium
+ m_pBookmarkDoc = const_cast<SdDrawDocument*>(m_pDoc)->OpenBookmarkDoc(m_pMedium);
+
+ if ( !m_pBookmarkDoc )
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xTreeView.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, SdResId(STR_READ_DATA_ERROR)));
+ xErrorBox->run();
+ m_pMedium = nullptr; //On failure the SfxMedium is invalid
+ }
+ }
+
+ return m_pBookmarkDoc;
+}
+
+/**
+ * Entries are inserted only by request (double click)
+ */
+IMPL_LINK(SdPageObjsTLV, RequestingChildrenHdl, const weld::TreeIter&, rFileEntry, bool)
+{
+ if (!m_xTreeView->iter_has_child(rFileEntry))
+ {
+ if (GetBookmarkDoc())
+ {
+ SdrObject* pObj = nullptr;
+
+ OUString sImgPage(BMP_PAGE);
+ OUString sImgPageObjs(BMP_PAGEOBJS);
+ OUString sImgObjects(BMP_OBJECTS);
+ OUString sImgOle(BMP_OLE);
+ OUString sImgGraphic(BMP_GRAPHIC);
+
+ // document name already inserted
+
+ // only insert all "normal" ? slides with objects
+ sal_uInt16 nPage = 0;
+ const sal_uInt16 nMaxPages = m_pBookmarkDoc->GetPageCount();
+
+ std::unique_ptr<weld::TreeIter> xPageEntry;
+ while (nPage < nMaxPages)
+ {
+ SdPage* pPage = static_cast<SdPage*>(m_pBookmarkDoc->GetPage(nPage));
+ if (pPage->GetPageKind() == PageKind::Standard)
+ {
+ OUString sId(OUString::number(1));
+ m_xTreeView->insert(&rFileEntry, -1, &pPage->GetName(), &sId,
+ nullptr, nullptr, false, m_xScratchIter.get());
+ m_xTreeView->set_image(*m_xScratchIter, sImgPage);
+
+ if (!xPageEntry)
+ {
+ xPageEntry = m_xTreeView->make_iterator(&rFileEntry);
+ (void)m_xTreeView->iter_children(*xPageEntry);
+ }
+ else
+ (void)m_xTreeView->iter_next_sibling(*xPageEntry);
+
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+
+ while( aIter.IsMore() )
+ {
+ pObj = aIter.Next();
+ OUString aStr( GetObjectName( pObj ) );
+ if( !aStr.isEmpty() )
+ {
+ if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::OLE2 )
+ {
+ m_xTreeView->insert(xPageEntry.get(), -1, &aStr, nullptr,
+ nullptr, nullptr, false, m_xScratchIter.get());
+ m_xTreeView->set_image(*m_xScratchIter, sImgOle);
+ }
+ else if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::Graphic )
+ {
+ m_xTreeView->insert(xPageEntry.get(), -1, &aStr, nullptr,
+ nullptr, nullptr, false, m_xScratchIter.get());
+ m_xTreeView->set_image(*m_xScratchIter, sImgGraphic);
+ }
+ else
+ {
+ m_xTreeView->insert(xPageEntry.get(), -1, &aStr, nullptr,
+ nullptr, nullptr, false, m_xScratchIter.get());
+ m_xTreeView->set_image(*m_xScratchIter, sImgObjects);
+ }
+ }
+ }
+ if (m_xTreeView->iter_has_child(*xPageEntry))
+ {
+ m_xTreeView->set_image(*xPageEntry, sImgPageObjs);
+ }
+ }
+ nPage++;
+ }
+ }
+ }
+ return true;
+}
+
+void SdPageObjsTLV::SetSdNavigator(SdNavigatorWin* pNavigator)
+{
+ m_pNavigator = pNavigator;
+}
+
+void SdPageObjsTLV::SetViewFrame(const SfxViewFrame* pViewFrame)
+{
+ sd::ViewShellBase* pBase = sd::ViewShellBase::GetViewShellBase(pViewFrame);
+ std::shared_ptr<sd::ViewShell> xViewShell = pBase->GetMainViewShell();
+ SAL_WARN_IF(!xViewShell, "sd", "null pBaseViewFrame");
+ const css::uno::Reference< css::frame::XFrame > xFrame = xViewShell ? xViewShell->GetViewFrame()->GetFrame().GetFrameInterface() : nullptr;
+ m_xAccel->init(::comphelper::getProcessComponentContext(), xFrame);
+}
+
+/**
+ * Close and delete bookmark document
+ */
+void SdPageObjsTLV::CloseBookmarkDoc()
+{
+ if (m_xBookmarkDocShRef.is())
+ {
+ m_xBookmarkDocShRef->DoClose();
+ m_xBookmarkDocShRef.clear();
+
+ // Medium is owned by document, so it's destroyed already
+ m_pOwnMedium = nullptr;
+ }
+ else if (m_pBookmarkDoc)
+ {
+ DBG_ASSERT(!m_pOwnMedium, "SfxMedium confusion!");
+ if (m_pDoc)
+ {
+ // The document owns the Medium, so the Medium will be invalid after closing the document
+ const_cast<SdDrawDocument*>(m_pDoc)->CloseBookmarkDoc();
+ m_pMedium = nullptr;
+ }
+ }
+ else
+ {
+ // perhaps mpOwnMedium provided, but no successful creation of BookmarkDoc
+ delete m_pOwnMedium;
+ m_pOwnMedium = nullptr;
+ }
+
+ m_pBookmarkDoc = nullptr;
+}
+
+bool SdPageObjsTLV::PageBelongsToCurrentShow(const SdPage* pPage) const
+{
+ // Return <TRUE/> as default when there is no custom show or when none
+ // is used. The page does then belong to the standard show.
+ bool bBelongsToShow = true;
+
+ if (m_pDoc->getPresentationSettings().mbCustomShow)
+ {
+ // Get the current custom show.
+ SdCustomShow* pCustomShow = nullptr;
+ SdCustomShowList* pShowList = const_cast<SdDrawDocument*>(m_pDoc)->GetCustomShowList();
+ if (pShowList != nullptr)
+ {
+ sal_uLong nCurrentShowIndex = pShowList->GetCurPos();
+ pCustomShow = (*pShowList)[nCurrentShowIndex].get();
+ }
+
+ // Check whether the given page is part of that custom show.
+ if (pCustomShow != nullptr)
+ {
+ bBelongsToShow = false;
+ size_t nPageCount = pCustomShow->PagesVector().size();
+ for (size_t i=0; i<nPageCount && !bBelongsToShow; i++)
+ if (pPage == pCustomShow->PagesVector()[i])
+ bBelongsToShow = true;
+ }
+ }
+
+ return bBelongsToShow;
+}
+
+void SdPageObjsTLV::AddShapeList (
+ const SdrObjList& rList,
+ const SdrObject* pShape,
+ const OUString& rsName,
+ const bool bIsExcluded,
+ const weld::TreeIter* pParentEntry)
+{
+ OUString aIcon(BMP_PAGE);
+ if (bIsExcluded)
+ aIcon = BMP_PAGE_EXCLUDED;
+ else if (pShape != nullptr)
+ aIcon = BMP_GROUP;
+
+ OUString aUserData("1");
+ if (pShape != nullptr)
+ aUserData = weld::toId(pShape);
+
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ InsertEntry(pParentEntry, aUserData, rsName, aIcon, xEntry.get());
+
+ SdrObjListIter aIter(
+ &rList,
+ !rList.HasObjectNavigationOrder() /* use navigation order, if available */,
+ SdrIterMode::Flat);
+
+ while( aIter.IsMore() )
+ {
+ SdrObject* pObj = aIter.Next();
+ OSL_ASSERT(pObj!=nullptr);
+
+ // Get the shape name.
+ OUString aStr (GetObjectName( pObj ) );
+ OUString sId(weld::toId(pObj));
+
+ if( !aStr.isEmpty() )
+ {
+ if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::OLE2 )
+ {
+ InsertEntry(xEntry.get(), sId, aStr, BMP_OLE);
+ }
+ else if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::Graphic )
+ {
+ InsertEntry(xEntry.get(), sId, aStr, BMP_GRAPHIC);
+ }
+ else if (pObj->IsGroupObject())
+ {
+ AddShapeList(
+ *pObj->GetSubList(),
+ pObj,
+ aStr,
+ false,
+ xEntry.get());
+ }
+ else
+ {
+ InsertEntry(xEntry.get(), sId, aStr, BMP_OBJECTS);
+ }
+ }
+ }
+
+ if (!m_xTreeView->iter_has_child(*xEntry))
+ return;
+
+ if (bIsExcluded)
+ m_xTreeView->set_image(*xEntry, BMP_PAGEOBJS_EXCLUDED);
+ else
+ m_xTreeView->set_image(*xEntry, BMP_PAGEOBJS);
+ m_xTreeView->expand_row(*xEntry);
+}
+
+/**
+ * Fill TreeLB with pages and objects
+ */
+void SdPageObjsTLV::Fill(const SdDrawDocument* pInDoc, bool bAllPages, const OUString& rDocName)
+{
+ OUString aSelection = m_xTreeView->get_selected_text();
+ clear();
+
+ m_pDoc = pInDoc;
+ m_aDocName = rDocName;
+ m_bShowAllPages = bAllPages;
+ m_pMedium = nullptr;
+
+ // first insert all pages including objects
+ sal_uInt16 nPage = 0;
+ const sal_uInt16 nMaxPages = m_pDoc->GetPageCount();
+
+ while( nPage < nMaxPages )
+ {
+ const SdPage* pPage = static_cast<const SdPage*>( m_pDoc->GetPage( nPage ) );
+ if( (m_bShowAllPages || pPage->GetPageKind() == PageKind::Standard)
+ && (pPage->GetPageKind() != PageKind::Handout) ) //#94954# never list the normal handout page ( handout-masterpage is used instead )
+ {
+ bool bPageExcluded = pPage->IsExcluded();
+
+ bool bPageBelongsToShow = PageBelongsToCurrentShow (pPage);
+ bPageExcluded |= !bPageBelongsToShow;
+
+ AddShapeList(*pPage, nullptr, pPage->GetName(), bPageExcluded, nullptr);
+ }
+ nPage++;
+ }
+
+ // then insert all master pages including objects
+ if( m_bShowAllPages )
+ {
+ nPage = 0;
+ const sal_uInt16 nMaxMasterPages = m_pDoc->GetMasterPageCount();
+
+ while( nPage < nMaxMasterPages )
+ {
+ const SdPage* pPage = static_cast<const SdPage*>( m_pDoc->GetMasterPage( nPage ) );
+ AddShapeList(*pPage, nullptr, pPage->GetName(), false, nullptr);
+ nPage++;
+ }
+ }
+ if (!aSelection.isEmpty())
+ {
+ m_xTreeView->all_foreach([this, &aSelection](weld::TreeIter& rEntry){
+ if (m_xTreeView->get_text(rEntry) == aSelection)
+ {
+ m_xTreeView->select(rEntry);
+ return true;
+ }
+ return false;
+ });
+ }
+}
+
+/**
+ * We insert only the first entry. Children are created on demand.
+ */
+void SdPageObjsTLV::Fill( const SdDrawDocument* pInDoc, SfxMedium* pInMedium,
+ const OUString& rDocName )
+{
+ m_pDoc = pInDoc;
+
+ // this object now owns the Medium
+ m_pMedium = pInMedium;
+ m_aDocName = rDocName;
+
+ OUString sId(OUString::number(1));
+ // insert document name
+ m_xTreeView->insert(nullptr, -1, &m_aDocName, &sId, nullptr, nullptr, true, m_xScratchIter.get());
+ m_xTreeView->set_image(*m_xScratchIter, BMP_DOC_OPEN);
+}
+
+/**
+ * select an entry in TreeLB
+ */
+bool SdPageObjsTLV::SelectEntry( std::u16string_view rName )
+{
+ bool bFound = false;
+
+ if (!rName.empty())
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ OUString aTmp;
+
+ if (m_xTreeView->get_iter_first(*xEntry))
+ {
+ do
+ {
+ aTmp = m_xTreeView->get_text(*xEntry);
+ if (aTmp == rName)
+ {
+ m_xTreeView->set_cursor(*xEntry);
+ m_xTreeView->select(*xEntry);
+ bFound = true;
+ break;
+ }
+ }
+ while (m_xTreeView->iter_next(*xEntry));
+ }
+ }
+
+ return bFound;
+}
+
+SdPageObjsTLV::~SdPageObjsTLV()
+{
+ if (m_nSelectEventId)
+ Application::RemoveUserEvent(m_nSelectEventId);
+ if (m_nRowActivateEventId)
+ Application::RemoveUserEvent(m_nRowActivateEventId);
+
+ if (m_pBookmarkDoc)
+ CloseBookmarkDoc();
+ else
+ {
+ // no document was created from m_pMedium, so this object is still the owner of it
+ delete m_pMedium;
+ }
+ m_xAccel.reset();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/sduiexp.cxx b/sd/source/ui/dlg/sduiexp.cxx
new file mode 100644
index 000000000..62901c70d
--- /dev/null
+++ b/sd/source/ui/dlg/sduiexp.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 "sddlgfact.hxx"
+#include <sal/types.h>
+
+class SdAbstractDialogFactory;
+
+extern "C" {
+SAL_DLLPUBLIC_EXPORT SdAbstractDialogFactory* SdCreateDialogFactory()
+{
+ static SdAbstractDialogFactory_Impl aFactory;
+ return &aFactory;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/tabtempl.cxx b/sd/source/ui/dlg/tabtempl.cxx
new file mode 100644
index 000000000..e5db39e68
--- /dev/null
+++ b/sd/source/ui/dlg/tabtempl.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/flstitem.hxx>
+
+#include <svx/svxids.hrc>
+
+#include <svx/drawitem.hxx>
+#include <svl/intitem.hxx>
+#include <svx/ofaitem.hxx>
+#include <svx/svdmodel.hxx>
+#include <svl/cjkoptions.hxx>
+#include <sfx2/objsh.hxx>
+#include <svx/dialogs.hrc>
+#include <svl/style.hxx>
+
+#include <tabtempl.hxx>
+#include <svx/flagsdef.hxx>
+
+/**
+ * Constructor of the Tab dialog: appends pages to the dialog
+ */
+SdTabTemplateDlg::SdTabTemplateDlg(weld::Window* pParent,
+ const SfxObjectShell* pDocShell,
+ SfxStyleSheetBase& rStyleBase,
+ SdrModel const * pModel,
+ SdrView* pView)
+ : SfxStyleDialogController(pParent, "modules/simpress/ui/templatedialog.ui",
+ "TemplateDialog", rStyleBase)
+ , rDocShell(*pDocShell)
+ , pSdrView(pView)
+ , pColorList(pModel->GetColorList())
+ , pGradientList(pModel->GetGradientList())
+ , pHatchingList(pModel->GetHatchList())
+ , pBitmapList(pModel->GetBitmapList())
+ , pPatternList(pModel->GetPatternList())
+ , pDashList(pModel->GetDashList())
+ , pLineEndList(pModel->GetLineEndList())
+{
+ // fill Listbox and set Select-Handler
+
+ AddTabPage("line", RID_SVXPAGE_LINE);
+ AddTabPage("area", RID_SVXPAGE_AREA);
+ AddTabPage("shadowing", RID_SVXPAGE_SHADOW);
+ AddTabPage("transparency", RID_SVXPAGE_TRANSPARENCE);
+ AddTabPage("font", RID_SVXPAGE_CHAR_NAME);
+ AddTabPage("fonteffect", RID_SVXPAGE_CHAR_EFFECTS);
+ AddTabPage("background", RID_SVXPAGE_BKG);
+ AddTabPage("indents", RID_SVXPAGE_STD_PARAGRAPH);
+ AddTabPage("text", RID_SVXPAGE_TEXTATTR);
+ AddTabPage("animation", RID_SVXPAGE_TEXTANIMATION);
+ AddTabPage("dimensioning", RID_SVXPAGE_MEASURE);
+ AddTabPage("connector", RID_SVXPAGE_CONNECTION);
+ AddTabPage("alignment", RID_SVXPAGE_ALIGN_PARAGRAPH);
+ AddTabPage("tabs", RID_SVXPAGE_TABULATOR);
+ if( SvtCJKOptions::IsAsianTypographyEnabled() )
+ AddTabPage("asiantypo", RID_SVXPAGE_PARA_ASIAN);
+ else
+ RemoveTabPage("asiantypo");
+}
+
+void SdTabTemplateDlg::PageCreated(const OString& rId, SfxTabPage &rPage)
+{
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ if (rId == "line")
+ {
+ aSet.Put (SvxColorListItem(pColorList,SID_COLOR_TABLE));
+ aSet.Put (SvxDashListItem(pDashList,SID_DASH_LIST));
+ aSet.Put (SvxLineEndListItem(pLineEndList,SID_LINEEND_LIST));
+ aSet.Put (SfxUInt16Item(SID_DLG_TYPE,1));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "area")
+ {
+ aSet.Put (SvxColorListItem(pColorList,SID_COLOR_TABLE));
+ aSet.Put (SvxGradientListItem(pGradientList,SID_GRADIENT_LIST));
+ aSet.Put (SvxHatchListItem(pHatchingList,SID_HATCH_LIST));
+ aSet.Put (SvxBitmapListItem(pBitmapList,SID_BITMAP_LIST));
+ aSet.Put (SfxUInt16Item(SID_PAGE_TYPE,0));
+ aSet.Put (SfxUInt16Item(SID_DLG_TYPE,1));
+ aSet.Put (SfxUInt16Item(SID_TABPAGE_POS,0));
+ aSet.Put (SvxPatternListItem(pPatternList,SID_PATTERN_LIST));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "shadowing")
+ {
+ aSet.Put (SvxColorListItem(pColorList,SID_COLOR_TABLE));
+ aSet.Put (SfxUInt16Item(SID_PAGE_TYPE,0));
+ aSet.Put (SfxUInt16Item(SID_DLG_TYPE,1));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "transparency")
+ {
+ aSet.Put (SfxUInt16Item(SID_PAGE_TYPE,0));
+ aSet.Put (SfxUInt16Item(SID_DLG_TYPE,1));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "font")
+ {
+ SvxFontListItem aItem(*static_cast<const SvxFontListItem*>(
+ rDocShell.GetItem( SID_ATTR_CHAR_FONTLIST) ) );
+
+ aSet.Put (SvxFontListItem( aItem.GetFontList(), SID_ATTR_CHAR_FONTLIST));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "fonteffect")
+ {
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "background")
+ {
+ aSet.Put(SfxUInt32Item(SID_FLAG_TYPE,static_cast<sal_uInt32>(SvxBackgroundTabFlags::SHOW_CHAR_BKGCOLOR)));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "text")
+ {
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "dimensioning")
+ {
+ aSet.Put (OfaPtrItem(SID_OBJECT_LIST,pSdrView));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "connector")
+ {
+ aSet.Put (OfaPtrItem(SID_OBJECT_LIST,pSdrView));
+ rPage.PageCreated(aSet);
+ }
+}
+
+void SdTabTemplateDlg::RefreshInputSet()
+{
+ SfxItemSet* pInputSet = GetInputSetImpl();
+
+ if( pInputSet )
+ {
+ pInputSet->ClearItem();
+ pInputSet->SetParent( GetStyleSheet().GetItemSet().GetParent() );
+ }
+ else
+ SetInputSet(&GetStyleSheet().GetItemSet());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/titledockwin.cxx b/sd/source/ui/dlg/titledockwin.cxx
new file mode 100644
index 000000000..f2aa744c2
--- /dev/null
+++ b/sd/source/ui/dlg/titledockwin.cxx
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/eitem.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/toolbox.hxx>
+
+#include <bitmaps.hlst>
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <titledockwin.hxx>
+
+namespace sd
+{
+ //= TitledDockingWindow
+ TitledDockingWindow::TitledDockingWindow( SfxBindings* i_pBindings, SfxChildWindow* i_pChildWindow, vcl::Window* i_pParent )
+ :SfxDockingWindow( i_pBindings, i_pChildWindow, i_pParent, WB_MOVEABLE|WB_CLOSEABLE|WB_DOCKABLE|WB_HIDE|WB_3DLOOK )
+ ,m_aToolbox( VclPtr<ToolBox>::Create(this) )
+ ,m_aContentWindow( VclPtr<vcl::Window>::Create(this, WB_DIALOGCONTROL) )
+ ,m_aBorder( 3, 1, 3, 3 )
+ ,m_nTitleBarHeight(0)
+ {
+ SetBackground( Wallpaper() );
+
+ m_aToolbox->SetSelectHdl( LINK( this, TitledDockingWindow, OnToolboxItemSelected ) );
+ m_aToolbox->SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetDialogColor() ) );
+ m_aToolbox->Show();
+ impl_resetToolBox();
+
+ m_aContentWindow->Show();
+ }
+
+ TitledDockingWindow::~TitledDockingWindow()
+ {
+ disposeOnce();
+ }
+
+ void TitledDockingWindow::dispose()
+ {
+ m_aToolbox.disposeAndClear();
+ m_aContentWindow.disposeAndClear();
+ SfxDockingWindow::dispose();
+ }
+
+ void TitledDockingWindow::SetTitle( const OUString& i_rTitle )
+ {
+ m_sTitle = i_rTitle;
+ Invalidate();
+ }
+
+
+ void TitledDockingWindow::SetText( const OUString& i_rText )
+ {
+ SfxDockingWindow::SetText( i_rText );
+ if ( m_sTitle.isEmpty() )
+ // our text is used as title, too => repaint
+ Invalidate();
+ }
+
+
+ void TitledDockingWindow::Resize()
+ {
+ SfxDockingWindow::Resize();
+ impl_layout();
+ }
+
+
+ void TitledDockingWindow::impl_layout()
+ {
+ m_aToolbox->ShowItem( ToolBoxItemId(1), !IsFloatingMode() );
+
+ const Size aToolBoxSize( m_aToolbox->CalcWindowSizePixel() );
+ Size aWindowSize( GetOutputSizePixel() );
+
+ // position the tool box
+ m_nTitleBarHeight = GetSettings().GetStyleSettings().GetTitleHeight();
+ if ( aToolBoxSize.Height() > m_nTitleBarHeight )
+ m_nTitleBarHeight = aToolBoxSize.Height();
+ m_aToolbox->SetPosSizePixel(
+ Point(
+ aWindowSize.Width() - aToolBoxSize.Width(),
+ ( m_nTitleBarHeight - aToolBoxSize.Height() ) / 2
+ ),
+ aToolBoxSize
+ );
+
+ // Place the content window.
+ if ( m_nTitleBarHeight < aToolBoxSize.Height() )
+ m_nTitleBarHeight = aToolBoxSize.Height();
+ aWindowSize.AdjustHeight( -m_nTitleBarHeight );
+ m_aContentWindow->SetPosSizePixel(
+ Point( m_aBorder.Left(), m_nTitleBarHeight + m_aBorder.Top() ),
+ Size(
+ aWindowSize.Width() - m_aBorder.Left() - m_aBorder.Right(),
+ aWindowSize.Height() - m_aBorder.Top() - m_aBorder.Bottom()
+ )
+ );
+ }
+
+ void TitledDockingWindow::ApplySettings(vcl::RenderContext& rRenderContext)
+ {
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+
+ // Font
+ ApplyControlFont(rRenderContext, rStyleSettings.GetAppFont());
+
+ // Color
+ ApplyControlForeground(rRenderContext, rStyleSettings.GetButtonTextColor());
+ rRenderContext.SetTextFillColor();
+ }
+
+ void TitledDockingWindow::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& i_rArea)
+ {
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+
+ SfxDockingWindow::Paint(rRenderContext, i_rArea);
+
+ rRenderContext.Push(vcl::PushFlags::FONT | vcl::PushFlags::FILLCOLOR | vcl::PushFlags::LINECOLOR);
+
+ rRenderContext.SetFillColor(rStyleSettings.GetDialogColor());
+ rRenderContext.SetLineColor();
+
+ // bold font
+ vcl::Font aFont(rRenderContext.GetFont());
+ aFont.SetWeight(WEIGHT_BOLD);
+ rRenderContext.SetFont(aFont);
+
+ // Set border values.
+ Size aWindowSize(GetOutputSizePixel());
+ int nOuterLeft = 0;
+ int nInnerLeft = nOuterLeft + m_aBorder.Left() - 1;
+ int nOuterRight = aWindowSize.Width() - 1;
+ int nInnerRight = nOuterRight - m_aBorder.Right() + 1;
+ int nInnerTop = m_nTitleBarHeight + m_aBorder.Top() - 1;
+ int nOuterBottom = aWindowSize.Height() - 1;
+ int nInnerBottom = nOuterBottom - m_aBorder.Bottom() + 1;
+
+ // Paint title bar background.
+ ::tools::Rectangle aTitleBarBox(::tools::Rectangle(nOuterLeft, 0, nOuterRight, nInnerTop - 1));
+ rRenderContext.DrawRect(aTitleBarBox);
+
+ if (nInnerLeft > nOuterLeft)
+ rRenderContext.DrawRect(::tools::Rectangle(nOuterLeft, nInnerTop, nInnerLeft, nInnerBottom));
+ if (nOuterRight > nInnerRight)
+ rRenderContext.DrawRect(::tools::Rectangle(nInnerRight, nInnerTop, nOuterRight, nInnerBottom));
+ if (nInnerBottom < nOuterBottom)
+ rRenderContext.DrawRect(::tools::Rectangle(nOuterLeft, nInnerBottom, nOuterRight, nOuterBottom));
+
+ // Paint bevel border.
+ rRenderContext.SetFillColor();
+ rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
+ if (m_aBorder.Top() > 0)
+ rRenderContext.DrawLine(Point(nInnerLeft, nInnerTop), Point(nInnerLeft, nInnerBottom));
+ if (m_aBorder.Left() > 0)
+ rRenderContext.DrawLine(Point(nInnerLeft, nInnerTop), Point(nInnerRight, nInnerTop));
+
+ rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
+ if (m_aBorder.Bottom() > 0)
+ rRenderContext.DrawLine(Point(nInnerRight, nInnerBottom), Point(nInnerLeft, nInnerBottom));
+ if (m_aBorder.Right() > 0)
+ rRenderContext.DrawLine(Point(nInnerRight, nInnerBottom), Point(nInnerRight, nInnerTop));
+
+ // Paint title bar text.
+ rRenderContext.SetLineColor(rStyleSettings.GetActiveTextColor());
+ aTitleBarBox.AdjustLeft(3 );
+ rRenderContext.DrawText(aTitleBarBox,
+ !m_sTitle.isEmpty() ? m_sTitle : GetText(),
+ DrawTextFlags::Left | DrawTextFlags::VCenter | DrawTextFlags::MultiLine | DrawTextFlags::WordBreak);
+
+ // Restore original values of the output device.
+ rRenderContext.Pop();
+ }
+
+
+ void TitledDockingWindow::impl_resetToolBox()
+ {
+ m_aToolbox->Clear();
+
+ // Get the closer bitmap and set it as right most button.
+ m_aToolbox->InsertItem(ToolBoxItemId(1), Image(StockImage::Yes, SFX_BMP_CLOSE_DOC));
+ m_aToolbox->SetQuickHelpText(ToolBoxItemId(1), SdResId(STR_CLOSE_PANE));
+ m_aToolbox->ShowItem( ToolBoxItemId(1) );
+ }
+
+
+ IMPL_LINK( TitledDockingWindow, OnToolboxItemSelected, ToolBox*, pToolBox, void )
+ {
+ const ToolBoxItemId nId = pToolBox->GetCurItemId();
+
+ if ( nId == ToolBoxItemId(1) )
+ {
+ // the closer
+ EndTracking();
+ const sal_uInt16 nChildWindowId( GetChildWindow_Impl()->GetType() );
+ const SfxBoolItem aVisibility( nChildWindowId, false );
+ GetBindings().GetDispatcher()->ExecuteList(
+ nChildWindowId,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aVisibility }
+ );
+ }
+ }
+
+
+ void TitledDockingWindow::StateChanged( StateChangedType i_nType )
+ {
+ switch ( i_nType )
+ {
+ case StateChangedType::InitShow:
+ impl_layout();
+ break;
+ default:;
+ }
+ SfxDockingWindow::StateChanged( i_nType );
+ }
+
+ void TitledDockingWindow::DataChanged( const DataChangedEvent& i_rDataChangedEvent )
+ {
+ SfxDockingWindow::DataChanged( i_rDataChangedEvent );
+
+ switch ( i_rDataChangedEvent.GetType() )
+ {
+ case DataChangedEventType::SETTINGS:
+ if ( !( i_rDataChangedEvent.GetFlags() & AllSettingsFlags::STYLE ) )
+ break;
+ [[fallthrough]];
+ case DataChangedEventType::FONTS:
+ case DataChangedEventType::FONTSUBSTITUTION:
+ {
+ impl_layout();
+ Invalidate();
+ }
+ break;
+ default: break;
+ }
+ }
+
+
+} // namespace sfx2
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/tpaction.cxx b/sd/source/ui/dlg/tpaction.cxx
new file mode 100644
index 000000000..f89fa51f5
--- /dev/null
+++ b/sd/source/ui/dlg/tpaction.cxx
@@ -0,0 +1,801 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svxids.hrc>
+#include <com/sun/star/presentation/ClickAction.hpp>
+#include <com/sun/star/embed/NeedsRunningStateException.hpp>
+#include <com/sun/star/embed/VerbDescriptor.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <comphelper/string.hxx>
+#include <com/sun/star/embed/VerbAttributes.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+
+#include <sdattr.hrc>
+#include <sfx2/sfxresid.hxx>
+#include <sfx2/strings.hrc>
+#include <o3tl/safeint.hxx>
+#include <tools/debug.hxx>
+#include <sfx2/app.hxx>
+#include <svx/svdograf.hxx>
+#include <svl/stritem.hxx>
+#include <svx/svdoole2.hxx>
+#include <sfx2/docfile.hxx>
+#include <svx/xtable.hxx>
+#include <vcl/mnemonic.hxx>
+#include <svl/intitem.hxx>
+#include <svl/urihelper.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <svx/drawitem.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+#include <View.hxx>
+#include <sdresid.hxx>
+#include <tpaction.hxx>
+#include <ViewShell.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <strings.hrc>
+
+#include <filedlg.hxx>
+
+#include <algorithm>
+
+using namespace ::com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+
+#define DOCUMENT_TOKEN '#'
+
+// XML content stream
+constexpr OUStringLiteral pStarDrawXMLContent( u"content.xml" );
+
+/**
+ * Constructor of the Tab dialog: appends the pages to the dialog
+ */
+SdActionDlg::SdActionDlg(weld::Window* pParent, const SfxItemSet* pAttr, ::sd::View const * pView)
+ : SfxSingleTabDialogController(pParent, pAttr, "modules/simpress/ui/interactiondialog.ui",
+ "InteractionDialog")
+{
+ std::unique_ptr<SfxTabPage> xNewPage = SdTPAction::Create(get_content_area(), this, *pAttr);
+
+ // formerly in PageCreated
+ static_cast<SdTPAction*>( xNewPage.get() )->SetView( pView );
+ static_cast<SdTPAction*>( xNewPage.get() )->Construct();
+
+ SetTabPage(std::move(xNewPage));
+}
+
+/**
+ * Action-TabPage
+ */
+SdTPAction::SdTPAction(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs)
+ : SfxTabPage(pPage, pController, "modules/simpress/ui/interactionpage.ui", "InteractionPage", &rInAttrs)
+ , mpView(nullptr)
+ , mpDoc(nullptr)
+ , bTreeUpdated(false)
+ , m_xLbAction(m_xBuilder->weld_combo_box("listbox"))
+ , m_xFtTree(m_xBuilder->weld_label("fttree"))
+ , m_xLbTree(new SdPageObjsTLV(m_xBuilder->weld_tree_view("tree")))
+ , m_xLbTreeDocument(new SdPageObjsTLV(m_xBuilder->weld_tree_view("treedoc")))
+ , m_xLbOLEAction(m_xBuilder->weld_tree_view("oleaction"))
+ , m_xFrame(m_xBuilder->weld_frame("frame"))
+ , m_xEdtSound(m_xBuilder->weld_entry("sound"))
+ , m_xEdtBookmark(m_xBuilder->weld_entry("bookmark"))
+ , m_xEdtDocument(m_xBuilder->weld_entry("document"))
+ , m_xEdtProgram(m_xBuilder->weld_entry("program"))
+ , m_xEdtMacro(m_xBuilder->weld_entry("macro"))
+ , m_xBtnSearch(m_xBuilder->weld_button("browse"))
+ , m_xBtnSeek(m_xBuilder->weld_button("find"))
+{
+ m_xLbOLEAction->set_size_request(m_xLbOLEAction->get_approximate_digit_width() * 48,
+ m_xLbOLEAction->get_height_rows(12));
+
+ m_xBtnSearch->connect_clicked( LINK( this, SdTPAction, ClickSearchHdl ) );
+ m_xBtnSeek->connect_clicked( LINK( this, SdTPAction, ClickSearchHdl ) );
+
+ // this page needs ExchangeSupport
+ SetExchangeSupport();
+
+ m_xLbAction->connect_changed( LINK( this, SdTPAction, ClickActionHdl ) );
+ m_xLbTree->connect_changed( LINK( this, SdTPAction, SelectTreeHdl ) );
+ m_xEdtDocument->connect_focus_out( LINK( this, SdTPAction, CheckFileHdl ) );
+ m_xEdtMacro->connect_focus_out( LINK( this, SdTPAction, CheckFileHdl ) );
+
+ //Lock to initial max size
+ Size aSize(m_xContainer->get_preferred_size());
+ m_xContainer->set_size_request(aSize.Width(), aSize.Height());
+
+ ClickActionHdl( *m_xLbAction );
+}
+
+SdTPAction::~SdTPAction()
+{
+}
+
+void SdTPAction::SetView( const ::sd::View* pSdView )
+{
+ mpView = pSdView;
+
+ // get ColorTable and fill ListBox
+ ::sd::DrawDocShell* pDocSh = mpView->GetDocSh();
+ if( pDocSh && pDocSh->GetViewShell() )
+ {
+ mpDoc = pDocSh->GetDoc();
+ SfxViewFrame* pFrame = pDocSh->GetViewShell()->GetViewFrame();
+ m_xLbTree->SetViewFrame( pFrame );
+ m_xLbTreeDocument->SetViewFrame( pFrame );
+
+ pColList = pDocSh->GetItem( SID_COLOR_TABLE )->GetColorList();
+ DBG_ASSERT( pColList.is(), "No color table available!" );
+ }
+ else
+ {
+ OSL_FAIL("sd::SdTPAction::SetView(), no docshell or viewshell?");
+ }
+}
+
+void SdTPAction::Construct()
+{
+ // fill OLE-Actionlistbox
+ SdrOle2Obj* pOleObj = nullptr;
+ SdrGrafObj* pGrafObj = nullptr;
+ bool bOLEAction = false;
+
+ if ( mpView->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+
+ if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::OLE2)
+ {
+ pOleObj = static_cast<SdrOle2Obj*>(pObj);
+ }
+ else if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::Graphic)
+ {
+ pGrafObj = static_cast<SdrGrafObj*>(pObj);
+ }
+ }
+ }
+ if( pGrafObj )
+ {
+ bOLEAction = true;
+
+ aVerbVector.push_back( 0 );
+ m_xLbOLEAction->append_text( MnemonicGenerator::EraseAllMnemonicChars( SdResId( STR_EDIT_OBJ ) ) );
+ }
+ else if( pOleObj )
+ {
+ const uno::Reference < embed::XEmbeddedObject >& xObj = pOleObj->GetObjRef();
+ if ( xObj.is() )
+ {
+ bOLEAction = true;
+ uno::Sequence < embed::VerbDescriptor > aVerbs;
+ try
+ {
+ aVerbs = xObj->getSupportedVerbs();
+ }
+ catch ( embed::NeedsRunningStateException& )
+ {
+ xObj->changeState( embed::EmbedStates::RUNNING );
+ aVerbs = xObj->getSupportedVerbs();
+ }
+
+ for( const embed::VerbDescriptor& aVerb : std::as_const(aVerbs) )
+ {
+ if( aVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU )
+ {
+ OUString aTmp( aVerb.VerbName );
+ aVerbVector.push_back( aVerb.VerbID );
+ m_xLbOLEAction->append_text( MnemonicGenerator::EraseAllMnemonicChars( aTmp ) );
+ }
+ }
+ }
+ }
+
+ maCurrentActions.push_back( presentation::ClickAction_NONE );
+ maCurrentActions.push_back( presentation::ClickAction_PREVPAGE );
+ maCurrentActions.push_back( presentation::ClickAction_NEXTPAGE );
+ maCurrentActions.push_back( presentation::ClickAction_FIRSTPAGE );
+ maCurrentActions.push_back( presentation::ClickAction_LASTPAGE );
+ maCurrentActions.push_back( presentation::ClickAction_BOOKMARK );
+ maCurrentActions.push_back( presentation::ClickAction_DOCUMENT );
+ maCurrentActions.push_back( presentation::ClickAction_SOUND );
+ if( bOLEAction && m_xLbOLEAction->n_children() )
+ maCurrentActions.push_back( presentation::ClickAction_VERB );
+ maCurrentActions.push_back( presentation::ClickAction_PROGRAM );
+ maCurrentActions.push_back( presentation::ClickAction_MACRO );
+ maCurrentActions.push_back( presentation::ClickAction_STOPPRESENTATION );
+
+ // fill Action-Listbox
+ for (const presentation::ClickAction & rAction : maCurrentActions)
+ {
+ TranslateId pRId = GetClickActionSdResId(rAction);
+ m_xLbAction->append_text(SdResId(pRId));
+ }
+
+}
+
+bool SdTPAction::FillItemSet( SfxItemSet* rAttrs )
+{
+ bool bModified = false;
+ presentation::ClickAction eCA = presentation::ClickAction_NONE;
+
+ if (m_xLbAction->get_active() != -1)
+ eCA = GetActualClickAction();
+
+ if( m_xLbAction->get_value_changed_from_saved() )
+ {
+ rAttrs->Put( SfxUInt16Item( ATTR_ACTION, static_cast<sal_uInt16>(eCA) ) );
+ bModified = true;
+ }
+ else
+ rAttrs->InvalidateItem( ATTR_ACTION );
+
+ OUString aFileName = GetEditText( true );
+ if( aFileName.isEmpty() )
+ rAttrs->InvalidateItem( ATTR_ACTION_FILENAME );
+ else
+ {
+ if( mpDoc && mpDoc->GetDocSh() && mpDoc->GetDocSh()->GetMedium() )
+ {
+ OUString aBaseURL = mpDoc->GetDocSh()->GetMedium()->GetBaseURL();
+ if( eCA == presentation::ClickAction_SOUND ||
+ eCA == presentation::ClickAction_DOCUMENT ||
+ eCA == presentation::ClickAction_PROGRAM )
+ aFileName = ::URIHelper::SmartRel2Abs( INetURLObject(aBaseURL), aFileName, URIHelper::GetMaybeFileHdl(), true, false,
+ INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::Unambiguous );
+
+ rAttrs->Put( SfxStringItem( ATTR_ACTION_FILENAME, aFileName ) );
+ bModified = true;
+ }
+ else
+ {
+ OSL_FAIL("sd::SdTPAction::FillItemSet(), I need a medium!");
+ }
+ }
+
+ return bModified;
+}
+
+void SdTPAction::Reset( const SfxItemSet* rAttrs )
+{
+ presentation::ClickAction eCA = presentation::ClickAction_NONE;
+ OUString aFileName;
+
+ // m_xLbAction
+ if( rAttrs->GetItemState( ATTR_ACTION ) != SfxItemState::DONTCARE )
+ {
+ eCA = static_cast<presentation::ClickAction>(static_cast<const SfxUInt16Item&>( rAttrs->
+ Get( ATTR_ACTION ) ).GetValue());
+ SetActualClickAction( eCA );
+ }
+ else
+ m_xLbAction->set_active(-1);
+
+ // m_xEdtSound
+ if( rAttrs->GetItemState( ATTR_ACTION_FILENAME ) != SfxItemState::DONTCARE )
+ {
+ aFileName = static_cast<const SfxStringItem&>( rAttrs->Get( ATTR_ACTION_FILENAME ) ).GetValue();
+ SetEditText( aFileName );
+ }
+
+ switch( eCA )
+ {
+ case presentation::ClickAction_BOOKMARK:
+ {
+ if (!m_xLbTree->SelectEntry(aFileName))
+ m_xLbTree->unselect_all();
+ }
+ break;
+
+ case presentation::ClickAction_DOCUMENT:
+ {
+ if( comphelper::string::getTokenCount(aFileName, DOCUMENT_TOKEN) == 2 )
+ m_xLbTreeDocument->SelectEntry( o3tl::getToken(aFileName, 1, DOCUMENT_TOKEN ) );
+ }
+ break;
+
+ default:
+ break;
+ }
+ ClickActionHdl( *m_xLbAction );
+
+ m_xLbAction->save_value();
+ m_xEdtSound->save_value();
+}
+
+void SdTPAction::ActivatePage( const SfxItemSet& )
+{
+}
+
+DeactivateRC SdTPAction::DeactivatePage( SfxItemSet* pPageSet )
+{
+ if( pPageSet )
+ FillItemSet( pPageSet );
+
+ return DeactivateRC::LeavePage;
+}
+
+std::unique_ptr<SfxTabPage> SdTPAction::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrs)
+{
+ return std::make_unique<SdTPAction>( pPage, pController, rAttrs );
+}
+
+void SdTPAction::UpdateTree()
+{
+ if( !bTreeUpdated && mpDoc && mpDoc->GetDocSh() && mpDoc->GetDocSh()->GetMedium() )
+ {
+ m_xLbTree->Fill( mpDoc, true, mpDoc->GetDocSh()->GetMedium()->GetName() );
+ bTreeUpdated = true;
+ }
+}
+
+void SdTPAction::OpenFileDialog()
+{
+ // Soundpreview only for interaction with sound
+ presentation::ClickAction eCA = GetActualClickAction();
+ bool bSound = ( eCA == presentation::ClickAction_SOUND );
+ bool bPage = ( eCA == presentation::ClickAction_BOOKMARK );
+ bool bDocument = ( eCA == presentation::ClickAction_DOCUMENT ||
+ eCA == presentation::ClickAction_PROGRAM );
+ bool bMacro = ( eCA == presentation::ClickAction_MACRO );
+
+ if( bPage )
+ {
+ // search in the TreeLB for the specified object
+ m_xLbTree->SelectEntry(GetEditText());
+ }
+ else
+ {
+ OUString aFile( GetEditText() );
+
+ if (bSound)
+ {
+ SdOpenSoundFileDialog aFileDialog(GetFrameWeld());
+
+ if( !aFile.isEmpty() )
+ aFileDialog.SetPath( aFile );
+
+ if( aFileDialog.Execute() == ERRCODE_NONE )
+ {
+ aFile = aFileDialog.GetPath();
+ SetEditText( aFile );
+ }
+ }
+ else if (bMacro)
+ {
+ // choose macro dialog
+ OUString aScriptURL = SfxApplication::ChooseScript(GetFrameWeld());
+
+ if ( !aScriptURL.isEmpty() )
+ {
+ SetEditText( aScriptURL );
+ }
+ }
+ else
+ {
+ sfx2::FileDialogHelper aFileDialog(
+ ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
+ FileDialogFlags::NONE, GetFrameWeld());
+ aFileDialog.SetContext(sfx2::FileDialogHelper::ImpressClickAction);
+
+ // The following is a workaround for #i4306#:
+ // The addition of the implicitly existing "all files"
+ // filter makes the (Windows system) open file dialog follow
+ // links on the desktop to directories.
+ aFileDialog.AddFilter (
+ SfxResId(STR_SFX_FILTERNAME_ALL),
+ "*.*");
+
+ if( aFileDialog.Execute() == ERRCODE_NONE )
+ {
+ aFile = aFileDialog.GetPath();
+ SetEditText( aFile );
+ }
+ if( bDocument )
+ CheckFileHdl( *m_xEdtDocument );
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SdTPAction, ClickSearchHdl, weld::Button&, void)
+{
+ OpenFileDialog();
+}
+
+IMPL_LINK_NOARG(SdTPAction, ClickActionHdl, weld::ComboBox&, void)
+{
+ presentation::ClickAction eCA = GetActualClickAction();
+
+ // hide controls we don't need
+ switch( eCA )
+ {
+ case presentation::ClickAction_NONE:
+ case presentation::ClickAction_INVISIBLE:
+ case presentation::ClickAction_PREVPAGE:
+ case presentation::ClickAction_NEXTPAGE:
+ case presentation::ClickAction_FIRSTPAGE:
+ case presentation::ClickAction_LASTPAGE:
+ case presentation::ClickAction_STOPPRESENTATION:
+ default:
+ m_xFtTree->hide();
+ m_xLbTree->hide();
+ m_xLbTreeDocument->hide();
+ m_xLbOLEAction->hide();
+
+ m_xFrame->hide();
+ m_xEdtSound->hide();
+ m_xEdtBookmark->hide();
+ m_xEdtDocument->hide();
+ m_xEdtProgram->hide();
+ m_xEdtMacro->hide();
+ m_xBtnSearch->hide();
+ m_xBtnSeek->hide();
+ break;
+
+ case presentation::ClickAction_SOUND:
+ case presentation::ClickAction_PROGRAM:
+ case presentation::ClickAction_MACRO:
+ m_xFtTree->hide();
+ m_xLbTree->hide();
+ m_xLbTreeDocument->hide();
+ m_xLbOLEAction->hide();
+
+ m_xEdtDocument->hide();
+
+ if( eCA == presentation::ClickAction_MACRO )
+ {
+ m_xEdtSound->hide();
+ m_xEdtProgram->hide();
+ }
+ else if( eCA == presentation::ClickAction_PROGRAM )
+ {
+ m_xEdtSound->hide();
+ m_xEdtMacro->hide();
+ }
+ else if( eCA == presentation::ClickAction_SOUND )
+ {
+ m_xEdtProgram->hide();
+ m_xEdtMacro->hide();
+ }
+
+ m_xBtnSeek->hide();
+ break;
+
+ case presentation::ClickAction_DOCUMENT:
+ m_xLbTree->hide();
+ m_xLbOLEAction->hide();
+
+ m_xEdtSound->hide();
+ m_xEdtProgram->hide();
+ m_xEdtMacro->hide();
+ m_xEdtBookmark->hide();
+ m_xBtnSeek->hide();
+ break;
+
+ case presentation::ClickAction_BOOKMARK:
+ m_xLbTreeDocument->hide();
+ m_xLbOLEAction->hide();
+ m_xEdtSound->hide();
+ m_xEdtDocument->hide();
+ m_xEdtProgram->hide();
+ m_xEdtMacro->hide();
+ m_xBtnSearch->hide();
+ break;
+
+ case presentation::ClickAction_VERB:
+ m_xLbTree->hide();
+ m_xEdtDocument->hide();
+ m_xEdtProgram->hide();
+ m_xEdtBookmark->hide();
+ m_xEdtMacro->hide();
+ m_xBtnSearch->hide();
+ m_xFrame->hide();
+ m_xEdtSound->hide();
+ m_xBtnSeek->hide();
+ break;
+ }
+
+ // show controls we do need
+ switch( eCA )
+ {
+ case presentation::ClickAction_NONE:
+ case presentation::ClickAction_INVISIBLE:
+ case presentation::ClickAction_PREVPAGE:
+ case presentation::ClickAction_NEXTPAGE:
+ case presentation::ClickAction_FIRSTPAGE:
+ case presentation::ClickAction_LASTPAGE:
+ case presentation::ClickAction_STOPPRESENTATION:
+ // none
+ break;
+
+ case presentation::ClickAction_SOUND:
+ m_xFrame->show();
+ m_xEdtSound->show();
+ m_xEdtSound->set_sensitive(true);
+ m_xBtnSearch->show();
+ m_xBtnSearch->set_sensitive(true);
+ m_xFrame->set_label( SdResId( STR_EFFECTDLG_SOUND ) );
+ break;
+
+ case presentation::ClickAction_PROGRAM:
+ case presentation::ClickAction_MACRO:
+ m_xFrame->show();
+ m_xBtnSearch->show();
+ m_xBtnSearch->set_sensitive(true);
+ if( eCA == presentation::ClickAction_MACRO )
+ {
+ m_xEdtMacro->show();
+ m_xFrame->set_label( SdResId( STR_EFFECTDLG_MACRO ) );
+ }
+ else
+ {
+ m_xEdtProgram->show();
+ m_xFrame->set_label( SdResId( STR_EFFECTDLG_PROGRAM ) );
+ }
+ break;
+
+ case presentation::ClickAction_DOCUMENT:
+ m_xFtTree->show();
+ m_xLbTreeDocument->show();
+
+ m_xFrame->show();
+ m_xEdtDocument->show();
+ m_xBtnSearch->show();
+ m_xBtnSearch->set_sensitive(true);
+
+ m_xFtTree->set_label( SdResId( STR_EFFECTDLG_JUMP ) );
+ m_xFrame->set_label( SdResId( STR_EFFECTDLG_DOCUMENT ) );
+
+ CheckFileHdl( *m_xEdtDocument );
+ break;
+
+ case presentation::ClickAction_VERB:
+ m_xFtTree->show();
+ m_xLbOLEAction->show();
+
+ m_xFtTree->set_label( SdResId( STR_EFFECTDLG_ACTION ) );
+ break;
+
+ case presentation::ClickAction_BOOKMARK:
+ UpdateTree();
+
+ m_xFtTree->show();
+ m_xLbTree->show();
+
+ m_xFrame->show();
+ m_xEdtBookmark->show();
+ m_xBtnSeek->show();
+
+ m_xFtTree->set_label( SdResId( STR_EFFECTDLG_JUMP ) );
+ m_xFrame->set_label( SdResId( STR_EFFECTDLG_PAGE_OBJECT ) );
+ break;
+ default:
+ break;
+ }
+}
+
+IMPL_LINK_NOARG(SdTPAction, SelectTreeHdl, weld::TreeView&, void)
+{
+ m_xEdtBookmark->set_text( m_xLbTree->get_selected_text() );
+}
+
+IMPL_LINK_NOARG(SdTPAction, CheckFileHdl, weld::Widget&, void)
+{
+ OUString aFile( GetEditText() );
+
+ if( aFile == aLastFile )
+ return;
+
+ bool bHideTreeDocument = true;
+
+ if (mpDoc)
+ {
+ // check if it is a valid draw file
+ SfxMedium aMedium( aFile,
+ StreamMode::READ | StreamMode::NOCREATE );
+
+ if( aMedium.IsStorage() )
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+
+ // is it a draw file?
+ // open with READ, otherwise the Storages might write into the file!
+ uno::Reference < embed::XStorage > xStorage = aMedium.GetStorage();
+ DBG_ASSERT( xStorage.is(), "No storage!" );
+
+ if (xStorage.is())
+ {
+ try
+ {
+ if (xStorage->hasByName(pStarDrawXMLContent))
+ {
+ if (SdDrawDocument* pBookmarkDoc = mpDoc->OpenBookmarkDoc(aFile))
+ {
+ aLastFile = aFile;
+
+ m_xLbTreeDocument->clear();
+ m_xLbTreeDocument->Fill(pBookmarkDoc, true, aFile);
+ mpDoc->CloseBookmarkDoc();
+ m_xLbTreeDocument->show();
+ bHideTreeDocument = false;
+ }
+ }
+ }
+ catch (...)
+ {
+ }
+ }
+ }
+ }
+
+ if (bHideTreeDocument)
+ m_xLbTreeDocument->hide();
+}
+
+presentation::ClickAction SdTPAction::GetActualClickAction()
+{
+ presentation::ClickAction eCA = presentation::ClickAction_NONE;
+ int nPos = m_xLbAction->get_active();
+ if (nPos != -1 && o3tl::make_unsigned(nPos) < maCurrentActions.size())
+ eCA = maCurrentActions[ nPos ];
+ return eCA;
+}
+
+void SdTPAction::SetActualClickAction( presentation::ClickAction eCA )
+{
+ std::vector<css::presentation::ClickAction>::const_iterator pIter =
+ std::find(maCurrentActions.begin(),maCurrentActions.end(),eCA);
+
+ if ( pIter != maCurrentActions.end() )
+ m_xLbAction->set_active(pIter-maCurrentActions.begin());
+}
+
+void SdTPAction::SetEditText( OUString const & rStr )
+{
+ presentation::ClickAction eCA = GetActualClickAction();
+ OUString aText(rStr);
+
+ // possibly convert URI back to system path
+ switch( eCA )
+ {
+ case presentation::ClickAction_DOCUMENT:
+ if( comphelper::string::getTokenCount(rStr, DOCUMENT_TOKEN) == 2 )
+ aText = rStr.getToken( 0, DOCUMENT_TOKEN );
+
+ [[fallthrough]];
+ case presentation::ClickAction_SOUND:
+ case presentation::ClickAction_PROGRAM:
+ {
+ INetURLObject aURL( aText );
+
+ // try to convert to system path
+ OUString aTmpStr(aURL.getFSysPath(FSysStyle::Detect));
+
+ if( !aTmpStr.isEmpty() )
+ aText = aTmpStr; // was a system path
+ }
+ break;
+ default:
+ break;
+ }
+
+ // set the string to the corresponding control
+ switch( eCA )
+ {
+ case presentation::ClickAction_SOUND:
+ m_xEdtSound->set_text(aText );
+ break;
+ case presentation::ClickAction_VERB:
+ {
+ ::std::vector< tools::Long >::iterator aFound( ::std::find( aVerbVector.begin(), aVerbVector.end(), rStr.toInt32() ) );
+ if( aFound != aVerbVector.end() )
+ m_xLbOLEAction->select(aFound - aVerbVector.begin());
+ }
+ break;
+ case presentation::ClickAction_PROGRAM:
+ m_xEdtProgram->set_text( aText );
+ break;
+ case presentation::ClickAction_MACRO:
+ m_xEdtMacro->set_text( aText );
+ break;
+ case presentation::ClickAction_DOCUMENT:
+ m_xEdtDocument->set_text( aText );
+ break;
+ case presentation::ClickAction_BOOKMARK:
+ m_xEdtBookmark->set_text( aText );
+ break;
+ default:
+ break;
+ }
+}
+
+OUString SdTPAction::GetEditText( bool bFullDocDestination )
+{
+ OUString aStr;
+ presentation::ClickAction eCA = GetActualClickAction();
+
+ switch( eCA )
+ {
+ case presentation::ClickAction_SOUND:
+ aStr = m_xEdtSound->get_text();
+ break;
+ case presentation::ClickAction_VERB:
+ {
+ const int nPos = m_xLbOLEAction->get_selected_index();
+ if (nPos != -1 && o3tl::make_unsigned(nPos) < aVerbVector.size() )
+ aStr = OUString::number( aVerbVector[ nPos ] );
+ return aStr;
+ }
+ case presentation::ClickAction_DOCUMENT:
+ aStr = m_xEdtDocument->get_text();
+ break;
+
+ case presentation::ClickAction_PROGRAM:
+ aStr = m_xEdtProgram->get_text();
+ break;
+
+ case presentation::ClickAction_MACRO:
+ {
+ return m_xEdtMacro->get_text();
+ }
+
+ case presentation::ClickAction_BOOKMARK:
+ return m_xEdtBookmark->get_text();
+
+ default:
+ break;
+ }
+
+ // validate file URI
+ INetURLObject aURL( aStr );
+ OUString aBaseURL;
+ if( mpDoc && mpDoc->GetDocSh() && mpDoc->GetDocSh()->GetMedium() )
+ aBaseURL = mpDoc->GetDocSh()->GetMedium()->GetBaseURL();
+
+ if( !aStr.isEmpty() && aURL.GetProtocol() == INetProtocol::NotValid )
+ aURL = INetURLObject( ::URIHelper::SmartRel2Abs( INetURLObject(aBaseURL), aStr, URIHelper::GetMaybeFileHdl() ) );
+
+ // get adjusted file name
+ aStr = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ if( bFullDocDestination &&
+ eCA == presentation::ClickAction_DOCUMENT &&
+ m_xLbTreeDocument->get_visible() &&
+ m_xLbTreeDocument->get_selected() )
+ {
+ OUString aTmpStr( m_xLbTreeDocument->get_selected_text() );
+ if( !aTmpStr.isEmpty() )
+ {
+ aStr += OUStringChar(DOCUMENT_TOKEN) + aTmpStr;
+ }
+ }
+
+ return aStr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/tpoption.cxx b/sd/source/ui/dlg/tpoption.cxx
new file mode 100644
index 000000000..0c534682d
--- /dev/null
+++ b/sd/source/ui/dlg/tpoption.cxx
@@ -0,0 +1,618 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/document/PrinterIndependentLayout.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include <sfx2/module.hxx>
+#include <svx/svxids.hrc>
+#include <svx/strarray.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svtools/unitconv.hxx>
+
+#include <sdattr.hrc>
+#include <sdresid.hxx>
+#include <optsitem.hxx>
+#include <tpoption.hxx>
+#include <strings.hrc>
+#include <app.hrc>
+#include <svl/intitem.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+SdTpOptionsSnap::SdTpOptionsSnap(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs)
+ : SvxGridTabPage(pPage, pController, rInAttrs)
+{
+ m_xSnapFrames->show();
+}
+
+SdTpOptionsSnap::~SdTpOptionsSnap()
+{
+}
+
+bool SdTpOptionsSnap::FillItemSet( SfxItemSet* rAttrs )
+{
+ SvxGridTabPage::FillItemSet(rAttrs);
+ SdOptionsSnapItem aOptsItem;
+
+ aOptsItem.GetOptionsSnap().SetSnapHelplines( m_xCbxSnapHelplines->get_active() );
+ aOptsItem.GetOptionsSnap().SetSnapBorder( m_xCbxSnapBorder->get_active() );
+ aOptsItem.GetOptionsSnap().SetSnapFrame( m_xCbxSnapFrame->get_active() );
+ aOptsItem.GetOptionsSnap().SetSnapPoints( m_xCbxSnapPoints->get_active() );
+ aOptsItem.GetOptionsSnap().SetOrtho( m_xCbxOrtho->get_active() );
+ aOptsItem.GetOptionsSnap().SetBigOrtho( m_xCbxBigOrtho->get_active() );
+ aOptsItem.GetOptionsSnap().SetRotate( m_xCbxRotate->get_active() );
+ aOptsItem.GetOptionsSnap().SetSnapArea(static_cast<sal_Int16>(m_xMtrFldSnapArea->get_value(FieldUnit::PIXEL)));
+ aOptsItem.GetOptionsSnap().SetAngle(Degree100(m_xMtrFldAngle->get_value(FieldUnit::DEGREE)));
+ aOptsItem.GetOptionsSnap().SetEliminatePolyPointLimitAngle(Degree100(m_xMtrFldBezAngle->get_value(FieldUnit::DEGREE)));
+
+ rAttrs->Put( aOptsItem );
+
+ // we get a possible existing GridItem, this ensures that we do not set
+ // some default values by accident
+ return true;
+}
+
+void SdTpOptionsSnap::Reset( const SfxItemSet* rAttrs )
+{
+ SvxGridTabPage::Reset(rAttrs);
+
+ SdOptionsSnapItem aOptsItem( rAttrs->Get( ATTR_OPTIONS_SNAP ) );
+
+ m_xCbxSnapHelplines->set_active( aOptsItem.GetOptionsSnap().IsSnapHelplines() );
+ m_xCbxSnapBorder->set_active( aOptsItem.GetOptionsSnap().IsSnapBorder() );
+ m_xCbxSnapFrame->set_active( aOptsItem.GetOptionsSnap().IsSnapFrame() );
+ m_xCbxSnapPoints->set_active( aOptsItem.GetOptionsSnap().IsSnapPoints() );
+ m_xCbxOrtho->set_active( aOptsItem.GetOptionsSnap().IsOrtho() );
+ m_xCbxBigOrtho->set_active( aOptsItem.GetOptionsSnap().IsBigOrtho() );
+ m_xCbxRotate->set_active( aOptsItem.GetOptionsSnap().IsRotate() );
+ m_xMtrFldSnapArea->set_value(aOptsItem.GetOptionsSnap().GetSnapArea(), FieldUnit::PIXEL);
+ m_xMtrFldAngle->set_value(aOptsItem.GetOptionsSnap().GetAngle().get(), FieldUnit::DEGREE);
+ m_xMtrFldBezAngle->set_value(aOptsItem.GetOptionsSnap().GetEliminatePolyPointLimitAngle().get(), FieldUnit::DEGREE);
+
+ ClickRotateHdl_Impl(*m_xCbxRotate);
+}
+
+std::unique_ptr<SfxTabPage> SdTpOptionsSnap::Create( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rAttrs )
+{
+ return std::make_unique<SdTpOptionsSnap>(pPage, pController, *rAttrs);
+}
+
+/*************************************************************************
+|*
+|* TabPage to adjust the content options
+|*
+\************************************************************************/
+SdTpOptionsContents::SdTpOptionsContents(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs)
+ : SfxTabPage(pPage, pController, "modules/simpress/ui/sdviewpage.ui", "SdViewPage", &rInAttrs)
+ , m_xCbxRuler(m_xBuilder->weld_check_button("ruler"))
+ , m_xCbxDragStripes(m_xBuilder->weld_check_button("dragstripes"))
+ , m_xCbxHandlesBezier(m_xBuilder->weld_check_button("handlesbezier"))
+ , m_xCbxMoveOutline(m_xBuilder->weld_check_button("moveoutline"))
+{
+}
+
+SdTpOptionsContents::~SdTpOptionsContents()
+{
+}
+
+bool SdTpOptionsContents::FillItemSet( SfxItemSet* rAttrs )
+{
+ bool bModified = false;
+
+ if( m_xCbxRuler->get_state_changed_from_saved() ||
+ m_xCbxMoveOutline->get_state_changed_from_saved() ||
+ m_xCbxDragStripes->get_state_changed_from_saved() ||
+ m_xCbxHandlesBezier->get_state_changed_from_saved() )
+ {
+ SdOptionsLayoutItem aOptsItem;
+
+ aOptsItem.GetOptionsLayout().SetRulerVisible( m_xCbxRuler->get_active() );
+ aOptsItem.GetOptionsLayout().SetMoveOutline( m_xCbxMoveOutline->get_active() );
+ aOptsItem.GetOptionsLayout().SetDragStripes( m_xCbxDragStripes->get_active() );
+ aOptsItem.GetOptionsLayout().SetHandlesBezier( m_xCbxHandlesBezier->get_active() );
+
+ rAttrs->Put( aOptsItem );
+ bModified = true;
+ }
+ return bModified;
+}
+
+void SdTpOptionsContents::Reset( const SfxItemSet* rAttrs )
+{
+ SdOptionsLayoutItem aLayoutItem( rAttrs->Get( ATTR_OPTIONS_LAYOUT ) );
+
+ m_xCbxRuler->set_active( aLayoutItem.GetOptionsLayout().IsRulerVisible() );
+ m_xCbxMoveOutline->set_active( aLayoutItem.GetOptionsLayout().IsMoveOutline() );
+ m_xCbxDragStripes->set_active( aLayoutItem.GetOptionsLayout().IsDragStripes() );
+ m_xCbxHandlesBezier->set_active( aLayoutItem.GetOptionsLayout().IsHandlesBezier() );
+
+ m_xCbxRuler->save_state();
+ m_xCbxMoveOutline->save_state();
+ m_xCbxDragStripes->save_state();
+ m_xCbxHandlesBezier->save_state();
+}
+
+std::unique_ptr<SfxTabPage> SdTpOptionsContents::Create( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rAttrs )
+{
+ return std::make_unique<SdTpOptionsContents>(pPage, pController, *rAttrs);
+}
+
+/*************************************************************************
+|*
+|* TabPage to adjust the misc options
+|*
+\************************************************************************/
+#define TABLE_COUNT 12
+#define TOKEN ':'
+
+SdTpOptionsMisc::SdTpOptionsMisc(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs)
+ : SfxTabPage(pPage, pController, "modules/simpress/ui/optimpressgeneralpage.ui", "OptSavePage", &rInAttrs)
+ , nWidth(0)
+ , nHeight(0)
+ , m_xCbxQuickEdit(m_xBuilder->weld_check_button("qickedit"))
+ , m_xCbxPickThrough(m_xBuilder->weld_check_button("textselected"))
+ , m_xNewDocumentFrame(m_xBuilder->weld_frame("newdocumentframe"))
+ , m_xCbxStartWithTemplate(m_xBuilder->weld_check_button("startwithwizard"))
+ , m_xCbxMasterPageCache(m_xBuilder->weld_check_button("backgroundback"))
+ , m_xCbxCopy(m_xBuilder->weld_check_button("copywhenmove"))
+ , m_xCbxMarkedHitMovesAlways(m_xBuilder->weld_check_button("objalwymov"))
+ , m_xPresentationFrame(m_xBuilder->weld_frame("presentationframe"))
+ , m_xLbMetric(m_xBuilder->weld_combo_box("units"))
+ , m_xMtrFldTabstop(m_xBuilder->weld_metric_spin_button("metricFields", FieldUnit::MM))
+ , m_xCbxEnableSdremote(m_xBuilder->weld_check_button("enremotcont"))
+ , m_xCbxEnablePresenterScreen(m_xBuilder->weld_check_button("enprsntcons"))
+ , m_xCbxUsePrinterMetrics(m_xBuilder->weld_check_button("printermetrics"))
+ , m_xCbxCompatibility(m_xBuilder->weld_check_button("cbCompatibility"))
+ , m_xScaleFrame(m_xBuilder->weld_frame("scaleframe"))
+ , m_xCbScale(m_xBuilder->weld_combo_box("scaleBox"))
+ , m_xNewDocLb(m_xBuilder->weld_label("newdoclbl"))
+ , m_xFiInfo1(m_xBuilder->weld_label("info1"))
+ , m_xMtrFldOriginalWidth(m_xBuilder->weld_metric_spin_button("metricWidthFields", FieldUnit::MM))
+ , m_xWidthLb(m_xBuilder->weld_label("widthlbl"))
+ , m_xHeightLb(m_xBuilder->weld_label("heightlbl"))
+ , m_xFiInfo2(m_xBuilder->weld_label("info2"))
+ , m_xMtrFldOriginalHeight(m_xBuilder->weld_metric_spin_button("metricHeightFields", FieldUnit::MM))
+ , m_xCbxDistort(m_xBuilder->weld_check_button("distortcb"))
+ , m_xMtrFldInfo1(m_xBuilder->weld_metric_spin_button("metricInfo1Fields", FieldUnit::MM))
+ , m_xMtrFldInfo2(m_xBuilder->weld_metric_spin_button("metricInfo2Fields", FieldUnit::MM))
+{
+ SetExchangeSupport();
+
+ // set metric
+ FieldUnit eFUnit;
+
+ sal_uInt16 nWhich = GetWhich( SID_ATTR_METRIC );
+ if ( rInAttrs.GetItemState( nWhich ) >= SfxItemState::DEFAULT )
+ {
+ const SfxUInt16Item& rItem = static_cast<const SfxUInt16Item&>(rInAttrs.Get( nWhich ));
+ eFUnit = static_cast<FieldUnit>(rItem.GetValue());
+ }
+ else
+ eFUnit = SfxModule::GetCurrentFieldUnit();
+
+ SetFieldUnit( *m_xMtrFldTabstop , eFUnit );
+ // tdf#148292 - avoid right frame to change position depending on width of this control
+ m_xMtrFldTabstop->set_size_request(150, -1);
+ // Impress is default mode, let' hide the entire scale frame etc.
+ m_xCbxDistort->hide();
+ m_xScaleFrame->hide();
+
+ // fill ListBox with metrics
+ for (sal_uInt32 i = 0; i < SvxFieldUnitTable::Count(); ++i)
+ {
+ OUString sMetric = SvxFieldUnitTable::GetString(i);
+ sal_uInt32 nFieldUnit = sal_uInt32(SvxFieldUnitTable::GetValue(i));
+ m_xLbMetric->append(OUString::number(nFieldUnit), sMetric);
+ }
+ m_xLbMetric->connect_changed( LINK( this, SdTpOptionsMisc, SelectMetricHdl_Impl ) );
+
+ SetFieldUnit( *m_xMtrFldOriginalWidth, eFUnit );
+ SetFieldUnit( *m_xMtrFldOriginalHeight, eFUnit );
+ m_xMtrFldOriginalWidth->set_max(999999999, FieldUnit::NONE);
+ m_xMtrFldOriginalHeight->set_max(999999999, FieldUnit::NONE);
+
+ // temporary fields for info texts (for formatting/calculation)
+ m_xMtrFldInfo1->set_unit( eFUnit );
+ m_xMtrFldInfo1->set_max(999999999, FieldUnit::NONE);
+ m_xMtrFldInfo1->set_digits( 2 );
+ m_xMtrFldInfo2->set_unit( eFUnit );
+ m_xMtrFldInfo2->set_max(999999999, FieldUnit::NONE);
+ m_xMtrFldInfo2->set_digits( 2 );
+
+ // determine PoolUnit
+ SfxItemPool* pPool = rInAttrs.GetPool();
+ DBG_ASSERT( pPool, "Where is the Pool?" );
+ ePoolUnit = pPool->GetMetric( SID_ATTR_FILL_HATCH );
+
+ // Fill the CB
+ sal_uInt16 aTable[ TABLE_COUNT ] =
+ { 1, 2, 4, 5, 8, 10, 16, 20, 30, 40, 50, 100 };
+
+ for( sal_uInt16 i = TABLE_COUNT-1; i > 0 ; i-- )
+ m_xCbScale->append_text( GetScale( 1, aTable[i] ) );
+ for( sal_uInt16 i = 0; i < TABLE_COUNT; i++ )
+ m_xCbScale->append_text( GetScale( aTable[i], 1 ) );
+}
+
+SdTpOptionsMisc::~SdTpOptionsMisc()
+{
+}
+
+void SdTpOptionsMisc::ActivatePage( const SfxItemSet& rSet )
+{
+ // We have to call save_state again since it can happen that the value
+ // has no effect on other TabPages
+ m_xLbMetric->save_value();
+ // change metric if necessary (since TabPage is in the Dialog where
+ // the metric is set)
+ const SfxUInt16Item* pAttr = rSet.GetItemIfSet( SID_ATTR_METRIC , false );
+ if( !pAttr )
+ return;
+
+ FieldUnit eFUnit = static_cast<FieldUnit>(static_cast<tools::Long>(pAttr->GetValue()));
+
+ if( eFUnit == m_xMtrFldOriginalWidth->get_unit() )
+ return;
+
+ // set metrics
+ sal_Int64 nVal = m_xMtrFldOriginalWidth->denormalize( m_xMtrFldOriginalWidth->get_value( FieldUnit::TWIP ) );
+ SetFieldUnit( *m_xMtrFldOriginalWidth, eFUnit, true );
+ m_xMtrFldOriginalWidth->set_value( m_xMtrFldOriginalWidth->normalize( nVal ), FieldUnit::TWIP );
+
+ nVal = m_xMtrFldOriginalHeight->denormalize( m_xMtrFldOriginalHeight->get_value( FieldUnit::TWIP ) );
+ SetFieldUnit( *m_xMtrFldOriginalHeight, eFUnit, true );
+ m_xMtrFldOriginalHeight->set_value( m_xMtrFldOriginalHeight->normalize( nVal ), FieldUnit::TWIP );
+
+ if( nWidth == 0 || nHeight == 0 )
+ return;
+
+ m_xMtrFldInfo1->set_unit( eFUnit );
+ m_xMtrFldInfo2->set_unit( eFUnit );
+
+ SetMetricValue( *m_xMtrFldInfo1, nWidth, ePoolUnit );
+ aInfo1 = m_xMtrFldInfo1->get_text();
+ m_xFiInfo1->set_label( aInfo1 );
+
+ SetMetricValue( *m_xMtrFldInfo2, nHeight, ePoolUnit );
+ aInfo2 = m_xMtrFldInfo2->get_text();
+ m_xFiInfo2->set_label( aInfo2 );
+}
+
+DeactivateRC SdTpOptionsMisc::DeactivatePage( SfxItemSet* pActiveSet )
+{
+ // check parser
+ sal_Int32 nX, nY;
+ if( SetScale( m_xCbScale->get_active_text(), nX, nY ) )
+ {
+ if( pActiveSet )
+ FillItemSet( pActiveSet );
+ return DeactivateRC::LeavePage;
+ }
+
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::YesNo,
+ SdResId(STR_WARN_SCALE_FAIL)));
+ if (xWarn->run() == RET_YES)
+ return DeactivateRC::KeepPage;
+
+ if( pActiveSet )
+ FillItemSet( pActiveSet );
+
+ return DeactivateRC::LeavePage;
+}
+
+bool SdTpOptionsMisc::FillItemSet( SfxItemSet* rAttrs )
+{
+ bool bModified = false;
+
+ if( m_xCbxStartWithTemplate->get_state_changed_from_saved() ||
+ m_xCbxMarkedHitMovesAlways->get_state_changed_from_saved() ||
+ m_xCbxQuickEdit->get_state_changed_from_saved() ||
+ m_xCbxPickThrough->get_state_changed_from_saved() ||
+ m_xCbxMasterPageCache->get_state_changed_from_saved() ||
+ m_xCbxCopy->get_state_changed_from_saved() ||
+ m_xCbxEnableSdremote->get_state_changed_from_saved() ||
+ m_xCbxEnablePresenterScreen->get_state_changed_from_saved() ||
+ m_xCbxCompatibility->get_state_changed_from_saved() ||
+ m_xCbxUsePrinterMetrics->get_state_changed_from_saved() ||
+ m_xCbxDistort->get_state_changed_from_saved())
+ {
+ SdOptionsMiscItem aOptsItem;
+
+ aOptsItem.GetOptionsMisc().SetStartWithTemplate( m_xCbxStartWithTemplate->get_active() );
+ aOptsItem.GetOptionsMisc().SetMarkedHitMovesAlways( m_xCbxMarkedHitMovesAlways->get_active() );
+ aOptsItem.GetOptionsMisc().SetQuickEdit( m_xCbxQuickEdit->get_active() );
+ aOptsItem.GetOptionsMisc().SetPickThrough( m_xCbxPickThrough->get_active() );
+ aOptsItem.GetOptionsMisc().SetMasterPagePaintCaching( m_xCbxMasterPageCache->get_active() );
+ aOptsItem.GetOptionsMisc().SetDragWithCopy( m_xCbxCopy->get_active() );
+ aOptsItem.GetOptionsMisc().SetEnableSdremote( m_xCbxEnableSdremote->get_active() );
+ aOptsItem.GetOptionsMisc().SetEnablePresenterScreen( m_xCbxEnablePresenterScreen->get_active() );
+ aOptsItem.GetOptionsMisc().SetSummationOfParagraphs( m_xCbxCompatibility->get_active() );
+ aOptsItem.GetOptionsMisc().SetPrinterIndependentLayout (
+ m_xCbxUsePrinterMetrics->get_active()
+ ? css::document::PrinterIndependentLayout::DISABLED
+ : css::document::PrinterIndependentLayout::ENABLED);
+ aOptsItem.GetOptionsMisc().SetCrookNoContortion( m_xCbxDistort->get_active() );
+ rAttrs->Put( aOptsItem );
+
+ bModified = true;
+ }
+
+ // metric
+ if (m_xLbMetric->get_value_changed_from_saved())
+ {
+ const sal_Int32 nMPos = m_xLbMetric->get_active();
+ sal_uInt16 nFieldUnit = m_xLbMetric->get_id(nMPos).toUInt32();
+ rAttrs->Put( SfxUInt16Item( GetWhich( SID_ATTR_METRIC ), nFieldUnit ) );
+ bModified = true;
+ }
+
+ // tabulator space
+ if( m_xMtrFldTabstop->get_value_changed_from_saved() )
+ {
+ MapUnit eUnit = rAttrs->GetPool()->GetMetric( SID_ATTR_DEFTABSTOP );
+ SfxUInt16Item aDef( SID_ATTR_DEFTABSTOP, static_cast<sal_uInt16>(GetCoreValue( *m_xMtrFldTabstop, eUnit )) );
+ rAttrs->Put( aDef );
+ bModified = true;
+ }
+
+ sal_Int32 nX, nY;
+ if( SetScale( m_xCbScale->get_active_text(), nX, nY ) )
+ {
+ rAttrs->Put( SfxInt32Item( ATTR_OPTIONS_SCALE_X, nX ) );
+ rAttrs->Put( SfxInt32Item( ATTR_OPTIONS_SCALE_Y, nY ) );
+
+ bModified = true;
+ }
+
+ return bModified;
+}
+
+void SdTpOptionsMisc::Reset( const SfxItemSet* rAttrs )
+{
+ SdOptionsMiscItem aOptsItem( rAttrs->Get( ATTR_OPTIONS_MISC ) );
+
+ m_xCbxStartWithTemplate->set_active( aOptsItem.GetOptionsMisc().IsStartWithTemplate() );
+ m_xCbxMarkedHitMovesAlways->set_active( aOptsItem.GetOptionsMisc().IsMarkedHitMovesAlways() );
+ m_xCbxQuickEdit->set_active( aOptsItem.GetOptionsMisc().IsQuickEdit() );
+ m_xCbxPickThrough->set_active( aOptsItem.GetOptionsMisc().IsPickThrough() );
+ m_xCbxMasterPageCache->set_active( aOptsItem.GetOptionsMisc().IsMasterPagePaintCaching() );
+ m_xCbxCopy->set_active( aOptsItem.GetOptionsMisc().IsDragWithCopy() );
+ m_xCbxEnableSdremote->set_active( aOptsItem.GetOptionsMisc().IsEnableSdremote() );
+ m_xCbxEnablePresenterScreen->set_active( aOptsItem.GetOptionsMisc().IsEnablePresenterScreen() );
+ m_xCbxCompatibility->set_active( aOptsItem.GetOptionsMisc().IsSummationOfParagraphs() );
+ m_xCbxUsePrinterMetrics->set_active( aOptsItem.GetOptionsMisc().GetPrinterIndependentLayout()==1 );
+ m_xCbxDistort->set_active( aOptsItem.GetOptionsMisc().IsCrookNoContortion() );
+ m_xCbxStartWithTemplate->save_state();
+ m_xCbxMarkedHitMovesAlways->save_state();
+ m_xCbxQuickEdit->save_state();
+ m_xCbxPickThrough->save_state();
+
+ m_xCbxMasterPageCache->save_state();
+ m_xCbxCopy->save_state();
+ m_xCbxEnableSdremote->save_state();
+ m_xCbxEnablePresenterScreen->save_state();
+ m_xCbxCompatibility->save_state();
+ m_xCbxUsePrinterMetrics->save_state();
+ m_xCbxDistort->save_state();
+
+ // metric
+ sal_uInt16 nWhich = GetWhich( SID_ATTR_METRIC );
+ m_xLbMetric->set_active(-1);
+
+ if ( rAttrs->GetItemState( nWhich ) >= SfxItemState::DEFAULT )
+ {
+ const SfxUInt16Item& rItem = static_cast<const SfxUInt16Item&>(rAttrs->Get( nWhich ));
+ sal_uInt32 nFieldUnit = static_cast<sal_uInt32>(rItem.GetValue());
+
+ for (sal_Int32 i = 0, nEntryCount = m_xLbMetric->get_count(); i < nEntryCount; ++i)
+ {
+ if (m_xLbMetric->get_id(i).toUInt32() == nFieldUnit)
+ {
+ m_xLbMetric->set_active( i );
+ break;
+ }
+ }
+ }
+
+ // tabulator space
+ constexpr auto nWhich2 = SID_ATTR_DEFTABSTOP;
+ if( rAttrs->GetItemState( nWhich2 ) >= SfxItemState::DEFAULT )
+ {
+ MapUnit eUnit = rAttrs->GetPool()->GetMetric( nWhich2 );
+ const SfxUInt16Item& rItem = rAttrs->Get( nWhich2 );
+ SetMetricValue( *m_xMtrFldTabstop, rItem.GetValue(), eUnit );
+ }
+ m_xLbMetric->save_value();
+ m_xMtrFldTabstop->save_value();
+ //Scale
+ sal_Int32 nX = rAttrs->Get( ATTR_OPTIONS_SCALE_X ).GetValue();
+ sal_Int32 nY = rAttrs->Get( ATTR_OPTIONS_SCALE_Y ).GetValue();
+ nWidth = static_cast<const SfxUInt32Item&>( rAttrs->
+ Get( ATTR_OPTIONS_SCALE_WIDTH ) ).GetValue();
+ nHeight = static_cast<const SfxUInt32Item&>( rAttrs->
+ Get( ATTR_OPTIONS_SCALE_HEIGHT ) ).GetValue();
+
+ m_xCbScale->set_entry_text( GetScale( nX, nY ) );
+
+ m_xMtrFldOriginalWidth->hide();
+ m_xMtrFldOriginalWidth->set_text( aInfo1 ); // empty
+ m_xMtrFldOriginalHeight->hide();
+ m_xMtrFldOriginalHeight->set_text( aInfo2 ); //empty
+ m_xFiInfo1->hide();
+ m_xFiInfo2->hide();
+
+ UpdateCompatibilityControls ();
+}
+
+std::unique_ptr<SfxTabPage> SdTpOptionsMisc::Create( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rAttrs )
+{
+ return std::make_unique<SdTpOptionsMisc>( pPage, pController, *rAttrs );
+}
+
+IMPL_LINK_NOARG(SdTpOptionsMisc, SelectMetricHdl_Impl, weld::ComboBox&, void)
+{
+ int nPos = m_xLbMetric->get_active();
+ if (nPos != -1)
+ {
+ FieldUnit eUnit = static_cast<FieldUnit>(m_xLbMetric->get_id(nPos).toUInt32());
+ sal_Int64 nVal =
+ m_xMtrFldTabstop->denormalize(m_xMtrFldTabstop->get_value(FieldUnit::TWIP));
+ SetFieldUnit( *m_xMtrFldTabstop, eUnit );
+ m_xMtrFldTabstop->set_value( m_xMtrFldTabstop->normalize( nVal ), FieldUnit::TWIP );
+ }
+}
+
+void SdTpOptionsMisc::SetImpressMode()
+{
+#ifndef ENABLE_SDREMOTE
+ m_xCbxEnableSdremote->hide();
+#else
+ (void) this; // loplugin:staticmethods
+#endif
+}
+
+void SdTpOptionsMisc::SetDrawMode()
+{
+ m_xScaleFrame->show();
+ m_xNewDocumentFrame->hide();
+ m_xCbxEnableSdremote->hide();
+ m_xCbxEnablePresenterScreen->hide();
+ m_xCbxCompatibility->hide();
+ m_xNewDocLb->hide();
+ m_xCbScale->show();
+ m_xPresentationFrame->hide();
+ m_xMtrFldInfo1->hide();
+ m_xMtrFldInfo2->hide();
+ m_xWidthLb->hide();
+ m_xHeightLb->hide();
+ m_xFiInfo1->show();
+ m_xMtrFldOriginalWidth->show();
+ m_xFiInfo2->show();
+ m_xMtrFldOriginalHeight->show();
+ m_xCbxDistort->show();
+ m_xCbxCompatibility->hide();
+}
+
+OUString SdTpOptionsMisc::GetScale( sal_Int32 nX, sal_Int32 nY )
+{
+ return OUString::number(nX) + OUStringChar(TOKEN) + OUString::number(nY);
+}
+
+bool SdTpOptionsMisc::SetScale( std::u16string_view aScale, sal_Int32& rX, sal_Int32& rY )
+{
+ if (aScale.empty())
+ return false;
+
+ sal_Int32 nIdx {0};
+
+ std::u16string_view aTmp(o3tl::getToken(aScale, 0, TOKEN, nIdx));
+ if (nIdx<0)
+ return false; // we expect another token!
+
+ if (!comphelper::string::isdigitAsciiString(aTmp))
+ return false;
+
+ rX = static_cast<tools::Long>(o3tl::toInt32(aTmp));
+ if( rX == 0 )
+ return false;
+
+ aTmp = o3tl::getToken(aScale, 0, TOKEN, nIdx);
+ if (nIdx>=0)
+ return false; // we require just 2 tokens!
+
+ if (!comphelper::string::isdigitAsciiString(aTmp))
+ return false;
+
+ rY = static_cast<tools::Long>(o3tl::toInt32(aTmp));
+ return rY != 0;
+}
+
+void SdTpOptionsMisc::UpdateCompatibilityControls()
+{
+ // Disable the compatibility controls by default. Enable them only when
+ // there is at least one open document.
+ bool bIsEnabled = false;
+
+ try
+ {
+ // Get a component enumeration from the desktop and search it for documents.
+ Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext());
+ do
+ {
+ Reference<frame::XDesktop2> xDesktop = frame::Desktop::create(xContext);
+
+ Reference<container::XEnumerationAccess> xComponents =
+ xDesktop->getComponents();
+ if ( ! xComponents.is())
+ break;
+
+ Reference<container::XEnumeration> xEnumeration (
+ xComponents->createEnumeration());
+ if ( ! xEnumeration.is())
+ break;
+
+ while (xEnumeration->hasMoreElements())
+ {
+ Reference<frame::XModel> xModel (xEnumeration->nextElement(), UNO_QUERY);
+ if (xModel.is())
+ {
+ // There is at least one model/document: Enable the compatibility controls.
+ bIsEnabled = true;
+ break;
+ }
+ }
+
+ }
+ while (false); // One 'loop'.
+ }
+ catch (const uno::Exception&)
+ {
+ // When there is an exception then simply use the default value of
+ // bIsEnabled and disable the controls.
+ }
+
+ m_xCbxCompatibility->set_sensitive(bIsEnabled);
+ m_xCbxUsePrinterMetrics->set_sensitive(bIsEnabled);
+}
+
+void SdTpOptionsMisc::PageCreated(const SfxAllItemSet& aSet)
+{
+ const SfxUInt32Item* pFlagItem = aSet.GetItem<SfxUInt32Item>(SID_SDMODE_FLAG, false);
+ if (pFlagItem)
+ {
+ sal_uInt32 nFlags=pFlagItem->GetValue();
+ if ( ( nFlags & SD_DRAW_MODE ) == SD_DRAW_MODE )
+ SetDrawMode();
+ if ( ( nFlags & SD_IMPRESS_MODE ) == SD_IMPRESS_MODE )
+ SetImpressMode();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/unchss.cxx b/sd/source/ui/dlg/unchss.cxx
new file mode 100644
index 000000000..7d963cddf
--- /dev/null
+++ b/sd/source/ui/dlg/unchss.cxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svl/hint.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpool.hxx>
+#include <tools/debug.hxx>
+
+#include <unchss.hxx>
+
+#include <strings.hrc>
+#include <glob.hxx>
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <stlsheet.hxx>
+#include <strings.hxx>
+
+StyleSheetUndoAction::StyleSheetUndoAction(SdDrawDocument* pTheDoc,
+ SfxStyleSheet* pTheStyleSheet,
+ const SfxItemSet* pTheNewItemSet) :
+ SdUndoAction(pTheDoc)
+{
+ DBG_ASSERT(pTheStyleSheet, "Undo without StyleSheet ???");
+ mpStyleSheet = pTheStyleSheet;
+
+ // Create ItemSets; Attention, it is possible that the new one is from a,
+ // different pool. Therefore we clone it with its items.
+ mpNewSet = std::make_unique<SfxItemSet>(static_cast<SfxItemPool&>(SdrObject::GetGlobalDrawObjectItemPool()), pTheNewItemSet->GetRanges());
+ SdrModel::MigrateItemSet( pTheNewItemSet, mpNewSet.get(), pTheDoc );
+
+ mpOldSet = std::make_unique<SfxItemSet>(static_cast<SfxItemPool&>(SdrObject::GetGlobalDrawObjectItemPool()), mpStyleSheet->GetItemSet().GetRanges());
+ SdrModel::MigrateItemSet( &mpStyleSheet->GetItemSet(), mpOldSet.get(), pTheDoc );
+
+ OUString aComment(SdResId(STR_UNDO_CHANGE_PRES_OBJECT));
+ OUString aName(mpStyleSheet->GetName());
+
+ // delete layout name and separator
+ sal_Int32 nPos = aName.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ aName = aName.copy(nPos + SD_LT_SEPARATOR.getLength());
+
+ if (aName == STR_LAYOUT_TITLE)
+ {
+ aName = SdResId(STR_PSEUDOSHEET_TITLE);
+ }
+ else if (aName == STR_LAYOUT_SUBTITLE)
+ {
+ aName = SdResId(STR_PSEUDOSHEET_SUBTITLE);
+ }
+ else if (aName == STR_LAYOUT_BACKGROUND)
+ {
+ aName = SdResId(STR_PSEUDOSHEET_BACKGROUND);
+ }
+ else if (aName == STR_LAYOUT_BACKGROUNDOBJECTS)
+ {
+ aName = SdResId(STR_PSEUDOSHEET_BACKGROUNDOBJECTS);
+ }
+ else if (aName == STR_LAYOUT_NOTES)
+ {
+ aName = SdResId(STR_PSEUDOSHEET_NOTES);
+ }
+ else
+ {
+ OUString aOutlineStr(SdResId(STR_PSEUDOSHEET_OUTLINE));
+ nPos = aName.indexOf(aOutlineStr);
+ if (nPos != -1)
+ {
+ std::u16string_view aNumStr(aName.subView(aOutlineStr.getLength()));
+ aName = STR_LAYOUT_OUTLINE + aNumStr;
+ }
+ }
+
+ // replace placeholder with template name
+ SetComment(aComment.replaceFirst("$", aName));
+}
+
+void StyleSheetUndoAction::Undo()
+{
+ SfxItemSet aNewSet( mpDoc->GetItemPool(), mpOldSet->GetRanges() );
+ SdrModel::MigrateItemSet( mpOldSet.get(), &aNewSet, mpDoc );
+
+ mpStyleSheet->GetItemSet().Set(aNewSet);
+ if( mpStyleSheet->GetFamily() == SfxStyleFamily::Pseudo )
+ static_cast<SdStyleSheet*>(mpStyleSheet)->GetRealStyleSheet()->Broadcast(SfxHint(SfxHintId::DataChanged));
+ else
+ mpStyleSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+}
+
+void StyleSheetUndoAction::Redo()
+{
+ SfxItemSet aNewSet( mpDoc->GetItemPool(), mpOldSet->GetRanges() );
+ SdrModel::MigrateItemSet( mpNewSet.get(), &aNewSet, mpDoc );
+
+ mpStyleSheet->GetItemSet().Set(aNewSet);
+ if( mpStyleSheet->GetFamily() == SfxStyleFamily::Pseudo )
+ static_cast<SdStyleSheet*>(mpStyleSheet)->GetRealStyleSheet()->Broadcast(SfxHint(SfxHintId::DataChanged));
+ else
+ mpStyleSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/dlg/vectdlg.cxx b/sd/source/ui/dlg/vectdlg.cxx
new file mode 100644
index 000000000..2db041e7e
--- /dev/null
+++ b/sd/source/ui/dlg/vectdlg.cxx
@@ -0,0 +1,336 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/vclenum.hxx>
+#include <vcl/BitmapReadAccess.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/BitmapSimpleColorQuantizationFilter.hxx>
+#include <vcl/svapp.hxx>
+
+#include <DrawDocShell.hxx>
+#include <sdmod.hxx>
+#include <sdiocmpt.hxx>
+#include <vectdlg.hxx>
+
+#define VECTORIZE_MAX_EXTENT 512
+
+SdVectorizeDlg::SdVectorizeDlg(weld::Window* pParent, const Bitmap& rBmp, ::sd::DrawDocShell* pDocShell)
+ : GenericDialogController(pParent, "modules/sdraw/ui/vectorize.ui", "VectorizeDialog")
+ , m_pDocSh(pDocShell)
+ , aBmp(rBmp)
+ , m_aBmpWin(m_xDialog.get())
+ , m_aMtfWin(m_xDialog.get())
+ , m_xNmLayers(m_xBuilder->weld_spin_button("colors"))
+ , m_xMtReduce(m_xBuilder->weld_metric_spin_button("points", FieldUnit::PIXEL))
+ , m_xFtFillHoles(m_xBuilder->weld_label("tilesft"))
+ , m_xMtFillHoles(m_xBuilder->weld_metric_spin_button("tiles", FieldUnit::PIXEL))
+ , m_xCbFillHoles(m_xBuilder->weld_check_button("fillholes"))
+ , m_xBmpWin(new weld::CustomWeld(*m_xBuilder, "source", m_aBmpWin))
+ , m_xMtfWin(new weld::CustomWeld(*m_xBuilder, "vectorized", m_aMtfWin))
+ , m_xPrgs(m_xBuilder->weld_progress_bar("progressbar"))
+ , m_xBtnOK(m_xBuilder->weld_button("ok"))
+ , m_xBtnPreview(m_xBuilder->weld_button("preview"))
+{
+ const int nWidth = m_xFtFillHoles->get_approximate_digit_width() * 32;
+ const int nHeight = m_xFtFillHoles->get_text_height() * 16;
+ m_xBmpWin->set_size_request(nWidth, nHeight);
+ m_xMtfWin->set_size_request(nWidth, nHeight);
+
+ m_xBtnPreview->connect_clicked( LINK( this, SdVectorizeDlg, ClickPreviewHdl ) );
+ m_xBtnOK->connect_clicked( LINK( this, SdVectorizeDlg, ClickOKHdl ) );
+ m_xNmLayers->connect_value_changed( LINK( this, SdVectorizeDlg, ModifyHdl ) );
+ m_xMtReduce->connect_value_changed( LINK( this, SdVectorizeDlg, MetricModifyHdl ) );
+ m_xMtFillHoles->connect_value_changed( LINK( this, SdVectorizeDlg, MetricModifyHdl ) );
+ m_xCbFillHoles->connect_toggled( LINK( this, SdVectorizeDlg, ToggleHdl ) );
+
+ LoadSettings();
+ InitPreviewBmp();
+}
+
+SdVectorizeDlg::~SdVectorizeDlg()
+{
+}
+
+::tools::Rectangle SdVectorizeDlg::GetRect( const Size& rDispSize, const Size& rBmpSize )
+{
+ ::tools::Rectangle aRect;
+
+ if( rBmpSize.Width() && rBmpSize.Height() && rDispSize.Width() && rDispSize.Height() )
+ {
+ Size aBmpSize( rBmpSize );
+ const double fGrfWH = static_cast<double>(aBmpSize.Width()) / aBmpSize.Height();
+ const double fWinWH = static_cast<double>(rDispSize.Width()) / rDispSize.Height();
+
+ if( fGrfWH < fWinWH )
+ {
+ aBmpSize.setWidth( static_cast<tools::Long>( rDispSize.Height() * fGrfWH ) );
+ aBmpSize.setHeight( rDispSize.Height() );
+ }
+ else
+ {
+ aBmpSize.setWidth( rDispSize.Width() );
+ aBmpSize.setHeight( static_cast<tools::Long>( rDispSize.Width() / fGrfWH) );
+ }
+
+ const Point aBmpPos( ( rDispSize.Width() - aBmpSize.Width() ) >> 1,
+ ( rDispSize.Height() - aBmpSize.Height() ) >> 1 );
+
+ aRect = ::tools::Rectangle( aBmpPos, aBmpSize );
+ }
+
+ return aRect;
+}
+
+void SdVectorizeDlg::InitPreviewBmp()
+{
+ const ::tools::Rectangle aRect( GetRect( m_aBmpWin.GetOutputSizePixel(), aBmp.GetSizePixel() ) );
+
+ aPreviewBmp = aBmp;
+ aPreviewBmp.Scale( aRect.GetSize() );
+ m_aBmpWin.SetGraphic(BitmapEx(aPreviewBmp));
+}
+
+Bitmap SdVectorizeDlg::GetPreparedBitmap( Bitmap const & rBmp, Fraction& rScale )
+{
+ Bitmap aNew( rBmp );
+ const Size aSizePix( aNew.GetSizePixel() );
+
+ if( aSizePix.Width() > VECTORIZE_MAX_EXTENT || aSizePix.Height() > VECTORIZE_MAX_EXTENT )
+ {
+ const ::tools::Rectangle aRect( GetRect( Size( VECTORIZE_MAX_EXTENT, VECTORIZE_MAX_EXTENT ), aSizePix ) );
+ rScale = Fraction( aSizePix.Width(), aRect.GetWidth() );
+ aNew.Scale( aRect.GetSize() );
+ }
+ else
+ rScale = Fraction( 1, 1 );
+
+ BitmapEx aNewBmpEx(aNew);
+ BitmapFilter::Filter(aNewBmpEx, BitmapSimpleColorQuantizationFilter(m_xNmLayers->get_value()));
+ aNew = aNewBmpEx.GetBitmap();
+
+ return aNew;
+}
+
+void SdVectorizeDlg::Calculate( Bitmap const & rBmp, GDIMetaFile& rMtf )
+{
+ m_pDocSh->SetWaitCursor( true );
+ m_xPrgs->set_percentage(0);
+
+ Fraction aScale;
+ Bitmap aTmp( GetPreparedBitmap( rBmp, aScale ) );
+
+ if( !aTmp.IsEmpty() )
+ {
+ const Link<::tools::Long,void> aPrgsHdl( LINK( this, SdVectorizeDlg, ProgressHdl ) );
+ aTmp.Vectorize( rMtf, static_cast<sal_uInt8>(m_xMtReduce->get_value(FieldUnit::NONE)), &aPrgsHdl );
+
+ if (m_xCbFillHoles->get_active())
+ {
+ GDIMetaFile aNewMtf;
+ Bitmap::ScopedReadAccess pRAcc(aTmp);
+
+ if( pRAcc )
+ {
+ const tools::Long nWidth = pRAcc->Width();
+ const tools::Long nHeight = pRAcc->Height();
+ const tools::Long nTileX = m_xMtFillHoles->get_value(FieldUnit::NONE);
+ const tools::Long nTileY = m_xMtFillHoles->get_value(FieldUnit::NONE);
+ assert(nTileX && "div-by-zero");
+ const tools::Long nCountX = nWidth / nTileX;
+ assert(nTileY && "div-by-zero");
+ const tools::Long nCountY = nHeight / nTileY;
+ const tools::Long nRestX = nWidth % nTileX;
+ const tools::Long nRestY = nHeight % nTileY;
+
+ MapMode aMap( rMtf.GetPrefMapMode() );
+ aNewMtf.SetPrefSize( rMtf.GetPrefSize() );
+ aNewMtf.SetPrefMapMode( aMap );
+
+ for( tools::Long nTY = 0; nTY < nCountY; nTY++ )
+ {
+ const tools::Long nY = nTY * nTileY;
+
+ for( tools::Long nTX = 0; nTX < nCountX; nTX++ )
+ AddTile( pRAcc.get(), aNewMtf, nTX * nTileX, nTY * nTileY, nTileX, nTileY );
+
+ if( nRestX )
+ AddTile( pRAcc.get(), aNewMtf, nCountX * nTileX, nY, nRestX, nTileY );
+ }
+
+ if( nRestY )
+ {
+ const tools::Long nY = nCountY * nTileY;
+
+ for( tools::Long nTX = 0; nTX < nCountX; nTX++ )
+ AddTile( pRAcc.get(), aNewMtf, nTX * nTileX, nY, nTileX, nRestY );
+
+ if( nRestX )
+ AddTile( pRAcc.get(), aNewMtf, nCountX * nTileX, nCountY * nTileY, nRestX, nRestY );
+ }
+
+ pRAcc.reset();
+
+ for( size_t n = 0, nCount = rMtf.GetActionSize(); n < nCount; n++ )
+ aNewMtf.AddAction( rMtf.GetAction( n )->Clone() );
+
+ aMap.SetScaleX( aMap.GetScaleX() * aScale );
+ aMap.SetScaleY( aMap.GetScaleY() * aScale );
+ aNewMtf.SetPrefMapMode( aMap );
+ rMtf = aNewMtf;
+ }
+ }
+ }
+
+ m_xPrgs->set_percentage(0);
+ m_pDocSh->SetWaitCursor( false );
+}
+
+void SdVectorizeDlg::AddTile( BitmapReadAccess const * pRAcc, GDIMetaFile& rMtf,
+ tools::Long nPosX, tools::Long nPosY, tools::Long nWidth, tools::Long nHeight )
+{
+ sal_uLong nSumR = 0, nSumG = 0, nSumB = 0;
+ const tools::Long nRight = nPosX + nWidth - 1;
+ const tools::Long nBottom = nPosY + nHeight - 1;
+ const double fMult = 1.0 / ( nWidth * nHeight );
+
+ for( tools::Long nY = nPosY; nY <= nBottom; nY++ )
+ {
+ for( tools::Long nX = nPosX; nX <= nRight; nX++ )
+ {
+ const BitmapColor aPixel( pRAcc->GetColor( nY, nX ) );
+
+ nSumR += aPixel.GetRed();
+ nSumG += aPixel.GetGreen();
+ nSumB += aPixel.GetBlue();
+ }
+ }
+
+ const Color aColor( static_cast<sal_uInt8>(FRound( nSumR * fMult )),
+ static_cast<sal_uInt8>(FRound( nSumG * fMult )),
+ static_cast<sal_uInt8>(FRound( nSumB * fMult )) );
+
+ ::tools::Rectangle aRect( Point( nPosX, nPosY ), Size( nWidth + 1, nHeight + 1 ) );
+ const Size& rMaxSize = rMtf.GetPrefSize();
+
+ aRect = Application::GetDefaultDevice()->PixelToLogic(aRect, rMtf.GetPrefMapMode());
+
+ if( aRect.Right() > ( rMaxSize.Width() - 1 ) )
+ aRect.SetRight( rMaxSize.Width() - 1 );
+
+ if( aRect.Bottom() > ( rMaxSize.Height() - 1 ) )
+ aRect.SetBottom( rMaxSize.Height() - 1 );
+
+ rMtf.AddAction( new MetaLineColorAction( aColor, true ) );
+ rMtf.AddAction( new MetaFillColorAction( aColor, true ) );
+ rMtf.AddAction( new MetaRectAction( aRect ) );
+}
+
+IMPL_LINK( SdVectorizeDlg, ProgressHdl, tools::Long, nData, void )
+{
+ m_xPrgs->set_percentage(nData);
+}
+
+IMPL_LINK_NOARG(SdVectorizeDlg, ClickPreviewHdl, weld::Button&, void)
+{
+ Calculate( aBmp, aMtf );
+ m_aMtfWin.SetGraphic( aMtf );
+ m_xBtnPreview->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(SdVectorizeDlg, ClickOKHdl, weld::Button&, void)
+{
+ if (m_xBtnPreview->get_sensitive())
+ Calculate( aBmp, aMtf );
+
+ SaveSettings();
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK( SdVectorizeDlg, ToggleHdl, weld::Toggleable&, rCb, void )
+{
+ if (rCb.get_active())
+ {
+ m_xFtFillHoles->set_sensitive(true);
+ m_xMtFillHoles->set_sensitive(true);
+ }
+ else
+ {
+ m_xFtFillHoles->set_sensitive(false);
+ m_xMtFillHoles->set_sensitive(false);
+ }
+
+ m_xBtnPreview->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SdVectorizeDlg, ModifyHdl, weld::SpinButton&, void)
+{
+ m_xBtnPreview->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SdVectorizeDlg, MetricModifyHdl, weld::MetricSpinButton&, void)
+{
+ m_xBtnPreview->set_sensitive(true);
+}
+
+void SdVectorizeDlg::LoadSettings()
+{
+ tools::SvRef<SotStorageStream> xIStm( SD_MOD()->GetOptionStream(
+ SD_OPTION_VECTORIZE ,
+ SdOptionStreamMode::Load ) );
+ sal_uInt16 nLayers;
+ sal_uInt16 nReduce;
+ sal_uInt16 nFillHoles;
+ bool bFillHoles;
+
+ if( xIStm.is() )
+ {
+ SdIOCompat aCompat( *xIStm, StreamMode::READ );
+ xIStm->ReadUInt16( nLayers ).ReadUInt16( nReduce ).ReadUInt16( nFillHoles ).ReadCharAsBool( bFillHoles );
+ }
+ else
+ {
+ nLayers = 8;
+ nReduce = 0;
+ nFillHoles = 32;
+ bFillHoles = false;
+ }
+
+ m_xNmLayers->set_value(nLayers);
+ m_xMtReduce->set_value(nReduce, FieldUnit::NONE);
+ m_xMtFillHoles->set_value(nFillHoles, FieldUnit::NONE);
+ m_xCbFillHoles->set_active(bFillHoles);
+
+ ToggleHdl(*m_xCbFillHoles);
+}
+
+void SdVectorizeDlg::SaveSettings() const
+{
+ tools::SvRef<SotStorageStream> xOStm( SD_MOD()->GetOptionStream(
+ SD_OPTION_VECTORIZE ,
+ SdOptionStreamMode::Store ) );
+
+ if( xOStm.is() )
+ {
+ SdIOCompat aCompat( *xOStm, StreamMode::WRITE, 1 );
+ xOStm->WriteUInt16( m_xNmLayers->get_value() ).WriteUInt16(m_xMtReduce->get_value(FieldUnit::NONE));
+ xOStm->WriteUInt16( m_xMtFillHoles->get_value(FieldUnit::NONE) ).WriteBool(m_xCbFillHoles->get_active());
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/docshell/docshel2.cxx b/sd/source/ui/docshell/docshel2.cxx
new file mode 100644
index 000000000..160c64a66
--- /dev/null
+++ b/sd/source/ui/docshell/docshel2.cxx
@@ -0,0 +1,416 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <DrawDocShell.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svxdlg.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <helpids.h>
+#include <ViewShell.hxx>
+#include <FrameView.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <ClientView.hxx>
+#include <Window.hxx>
+#include <strings.hrc>
+
+#include <sdresid.hxx>
+#include <fupoor.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <rtl/character.hxx>
+#include <tools/debug.hxx>
+
+namespace sd {
+
+/**
+ * Drawing of DocShell (with the helper class SdDrawViewShell)
+ */
+void DrawDocShell::Draw(OutputDevice* pOut, const JobSetup&, sal_uInt16 nAspect)
+{
+ if (nAspect == ASPECT_THUMBNAIL)
+ {
+ // THUMBNAIL: here we may can set the draft mode
+ }
+
+ std::optional<ClientView> pView( std::in_place, this, pOut );
+
+ pView->SetHlplVisible(false);
+ pView->SetGridVisible(false);
+ pView->SetBordVisible(false);
+ pView->SetPageVisible(false);
+ pView->SetGlueVisible(false);
+
+ SdPage* pSelectedPage = nullptr;
+
+ const std::vector<std::unique_ptr<sd::FrameView>> &rViews = mpDoc->GetFrameViewList();
+ if( !rViews.empty() )
+ {
+ sd::FrameView* pFrameView = rViews[0].get();
+ if( pFrameView->GetPageKind() == PageKind::Standard )
+ {
+ sal_uInt16 nSelectedPage = pFrameView->GetSelectedPage();
+ pSelectedPage = mpDoc->GetSdPage(nSelectedPage, PageKind::Standard);
+ }
+ }
+
+ if( nullptr == pSelectedPage )
+ {
+ SdPage* pPage = nullptr;
+ sal_uInt16 nPageCnt = mpDoc->GetSdPageCount(PageKind::Standard);
+
+ for (sal_uInt16 i = 0; i < nPageCnt; i++)
+ {
+ pPage = mpDoc->GetSdPage(i, PageKind::Standard);
+
+ if ( pPage->IsSelected() )
+ pSelectedPage = pPage;
+ }
+
+ if( nullptr == pSelectedPage )
+ pSelectedPage = mpDoc->GetSdPage(0, PageKind::Standard);
+ }
+
+ ::tools::Rectangle aVisArea = GetVisArea(nAspect);
+ pOut->IntersectClipRegion(aVisArea);
+ pView->ShowSdrPage(pSelectedPage);
+
+ if (pOut->GetOutDevType() == OUTDEV_WINDOW)
+ return;
+
+ MapMode aOldMapMode = pOut->GetMapMode();
+
+ if (pOut->GetOutDevType() == OUTDEV_PRINTER)
+ {
+ MapMode aMapMode = aOldMapMode;
+ Point aOrigin = aMapMode.GetOrigin();
+ aOrigin.AdjustX(1 );
+ aOrigin.AdjustY(1 );
+ aMapMode.SetOrigin(aOrigin);
+ pOut->SetMapMode(aMapMode);
+ }
+
+ vcl::Region aRegion(aVisArea);
+ pView->CompleteRedraw(pOut, aRegion);
+
+ if (pOut->GetOutDevType() == OUTDEV_PRINTER)
+ {
+ pOut->SetMapMode(aOldMapMode);
+ }
+}
+
+::tools::Rectangle DrawDocShell::GetVisArea(sal_uInt16 nAspect) const
+{
+ ::tools::Rectangle aVisArea;
+
+ if( ( ASPECT_THUMBNAIL == nAspect ) || ( ASPECT_DOCPRINT == nAspect ) )
+ {
+ // provide size of first page
+ aVisArea.SetSize(mpDoc->GetSdPage(0, PageKind::Standard)->GetSize());
+ }
+ else
+ {
+ aVisArea = SfxObjectShell::GetVisArea(nAspect);
+ }
+
+ if (aVisArea.IsEmpty() && mpViewShell)
+ {
+ vcl::Window* pWin = mpViewShell->GetActiveWindow();
+
+ if (pWin)
+ {
+ aVisArea = pWin->PixelToLogic(::tools::Rectangle(Point(0,0), pWin->GetOutputSizePixel()));
+ }
+ }
+
+ return aVisArea;
+}
+
+void DrawDocShell::Connect(ViewShell* pViewSh)
+{
+ mpViewShell = pViewSh;
+}
+
+void DrawDocShell::Disconnect(ViewShell const * pViewSh)
+{
+ if (mpViewShell == pViewSh)
+ {
+ mpViewShell = nullptr;
+ }
+}
+
+FrameView* DrawDocShell::GetFrameView()
+{
+ FrameView* pFrameView = nullptr;
+
+ if (mpViewShell)
+ {
+ pFrameView = mpViewShell->GetFrameView();
+ }
+
+ return pFrameView;
+}
+
+/**
+ * Creates a bitmap of an arbitrary page
+ */
+BitmapEx DrawDocShell::GetPagePreviewBitmap(SdPage* pPage)
+{
+ const sal_uInt16 nMaxEdgePixel = 90;
+ MapMode aMapMode( MapUnit::Map100thMM );
+ const Size aSize( pPage->GetSize() );
+ const Point aNullPt;
+ ScopedVclPtrInstance< VirtualDevice > pVDev( *Application::GetDefaultDevice() );
+
+ pVDev->SetMapMode( aMapMode );
+
+ const Size aPixSize( pVDev->LogicToPixel( aSize ) );
+ const sal_uLong nMaxEdgePix = std::max( aPixSize.Width(), aPixSize.Height() );
+ Fraction aFrac( nMaxEdgePixel, nMaxEdgePix );
+
+ aMapMode.SetScaleX( aFrac );
+ aMapMode.SetScaleY( aFrac );
+ pVDev->SetMapMode( aMapMode );
+ pVDev->SetOutputSize( aSize );
+
+ // that we also get the dark lines at the right and bottom page margin
+ aFrac = Fraction( nMaxEdgePixel - 1, nMaxEdgePix );
+ aMapMode.SetScaleX( aFrac );
+ aMapMode.SetScaleY( aFrac );
+ pVDev->SetMapMode( aMapMode );
+
+ std::optional<ClientView> pView( std::in_place, this, pVDev );
+ FrameView* pFrameView = GetFrameView();
+ pView->ShowSdrPage( pPage );
+
+ if ( GetFrameView() )
+ {
+ // initialize the drawing-(screen) attributes
+ pView->SetGridCoarse( pFrameView->GetGridCoarse() );
+ pView->SetGridFine( pFrameView->GetGridFine() );
+ pView->SetSnapGridWidth(pFrameView->GetSnapGridWidthX(), pFrameView->GetSnapGridWidthY());
+ pView->SetGridVisible( pFrameView->IsGridVisible() );
+ pView->SetGridFront( pFrameView->IsGridFront() );
+ pView->SetSnapAngle( pFrameView->GetSnapAngle() );
+ pView->SetGridSnap( pFrameView->IsGridSnap() );
+ pView->SetBordSnap( pFrameView->IsBordSnap() );
+ pView->SetHlplSnap( pFrameView->IsHlplSnap() );
+ pView->SetOFrmSnap( pFrameView->IsOFrmSnap() );
+ pView->SetOPntSnap( pFrameView->IsOPntSnap() );
+ pView->SetOConSnap( pFrameView->IsOConSnap() );
+ pView->SetDragStripes( pFrameView->IsDragStripes() );
+ pView->SetFrameDragSingles( pFrameView->IsFrameDragSingles() );
+ pView->SetSnapMagneticPixel( pFrameView->GetSnapMagneticPixel() );
+ pView->SetMarkedHitMovesAlways( pFrameView->IsMarkedHitMovesAlways() );
+ pView->SetMoveOnlyDragging( pFrameView->IsMoveOnlyDragging() );
+ pView->SetSlantButShear( pFrameView->IsSlantButShear() );
+ pView->SetNoDragXorPolys( pFrameView->IsNoDragXorPolys() );
+ pView->SetCrookNoContortion( pFrameView->IsCrookNoContortion() );
+ pView->SetAngleSnapEnabled( pFrameView->IsAngleSnapEnabled() );
+ pView->SetBigOrtho( pFrameView->IsBigOrtho() );
+ pView->SetOrtho( pFrameView->IsOrtho() );
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if (pPageView)
+ {
+ if ( pPageView->GetVisibleLayers() != pFrameView->GetVisibleLayers() )
+ pPageView->SetVisibleLayers( pFrameView->GetVisibleLayers() );
+
+ if ( pPageView->GetPrintableLayers() != pFrameView->GetPrintableLayers() )
+ pPageView->SetPrintableLayers( pFrameView->GetPrintableLayers() );
+
+ if ( pPageView->GetLockedLayers() != pFrameView->GetLockedLayers() )
+ pPageView->SetLockedLayers( pFrameView->GetLockedLayers() );
+
+ pPageView->SetHelpLines( pFrameView->GetStandardHelpLines() );
+ }
+
+ if ( pView->GetActiveLayer() != pFrameView->GetActiveLayer() )
+ pView->SetActiveLayer( pFrameView->GetActiveLayer() );
+ }
+
+ pView->CompleteRedraw( pVDev, vcl::Region(::tools::Rectangle(aNullPt, aSize)) );
+
+ // IsRedrawReady() always gives sal_True while ( !pView->IsRedrawReady() ) {}
+ pView.reset();
+
+ pVDev->SetMapMode( MapMode() );
+
+ BitmapEx aPreview( pVDev->GetBitmapEx( aNullPt, pVDev->GetOutputSizePixel() ) );
+
+ DBG_ASSERT(!aPreview.IsEmpty(), "Preview-Bitmap could not be generated");
+
+ return aPreview;
+}
+
+/**
+ * Checks if the page exists. If so, we force the user to enter a not yet used
+ * name.
+ * @return sal_False if the user cancels the action.
+ */
+bool DrawDocShell::CheckPageName(weld::Window* pWin, OUString& rName)
+{
+ const OUString aStrForDlg( rName );
+ bool bIsNameValid = IsNewPageNameValid( rName, true );
+
+ if( ! bIsNameValid )
+ {
+ OUString aDesc;
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+
+ if (GetDocumentType() == DocumentType::Draw)
+ aDesc = SdResId( STR_WARN_PAGE_EXISTS_DRAW );
+ else
+ aDesc = SdResId( STR_WARN_PAGE_EXISTS );
+
+ ScopedVclPtr<AbstractSvxNameDialog> aNameDlg(pFact->CreateSvxNameDialog(pWin, aStrForDlg, aDesc));
+ aNameDlg->SetEditHelpId( HID_SD_NAMEDIALOG_PAGE );
+
+ aNameDlg->SetCheckNameHdl( LINK( this, DrawDocShell, RenameSlideHdl ) );
+
+ rtl::Reference<FuPoor> xFunc( mpViewShell->GetCurrentFunction() );
+ if( xFunc.is() )
+ xFunc->cancel();
+
+ if( aNameDlg->Execute() == RET_OK )
+ {
+ aNameDlg->GetName( rName );
+ bIsNameValid = IsNewPageNameValid( rName );
+ }
+ }
+
+ return bIsNameValid;
+}
+
+bool DrawDocShell::IsNewPageNameValid( OUString & rInOutPageName, bool bResetStringIfStandardName /* = false */ )
+{
+ bool bCanUseNewName = false;
+
+ // check if name is something like 'Slide n'
+ OUString aStrPage(SdResId(STR_SD_PAGE) + " ");
+
+ bool bIsStandardName = false;
+
+ // prevent also _future_ slide names of the form "'STR_SD_PAGE' + ' ' + '[0-9]+|[a-z]|[A-Z]|[CDILMVX]+|[cdilmvx]+'"
+ // (arabic, lower- and upper case single letter, lower- and upper case roman numbers)
+ if (rInOutPageName.startsWith(aStrPage) &&
+ rInOutPageName.getLength() > aStrPage.getLength())
+ {
+ sal_Int32 nIdx{ aStrPage.getLength() };
+ std::u16string_view sRemainder = o3tl::getToken(rInOutPageName, 0, ' ', nIdx);
+ if (!sRemainder.empty() && sRemainder[0] >= '0' && sRemainder[0] <= '9')
+ {
+ // check for arabic numbering
+
+ size_t nIndex = 1;
+ // skip all following numbers
+ while (nIndex < sRemainder.size() &&
+ sRemainder[nIndex] >= '0' && sRemainder[nIndex] <= '9')
+ {
+ nIndex++;
+ }
+
+ // EOL? Reserved name!
+ if (nIndex >= sRemainder.size())
+ {
+ bIsStandardName = true;
+ }
+ }
+ else if (sRemainder.size() == 1 &&
+ rtl::isAsciiLowerCase(sRemainder[0]))
+ {
+ // lower case, single character: reserved
+ bIsStandardName = true;
+ }
+ else if (sRemainder.size() == 1 &&
+ rtl::isAsciiUpperCase(sRemainder[0]))
+ {
+ // upper case, single character: reserved
+ bIsStandardName = true;
+ }
+ else
+ {
+ // check for upper/lower case roman numbering
+ OUString sReserved("cdilmvx");
+
+ // skip all following characters contained in one reserved class
+ if (sReserved.indexOf(sRemainder[0]) == -1)
+ sReserved = sReserved.toAsciiUpperCase();
+
+ size_t nIndex = 0;
+ while (nIndex < sRemainder.size() &&
+ sReserved.indexOf(sRemainder[nIndex]) != -1)
+ {
+ nIndex++;
+ }
+
+ // EOL? Reserved name!
+ if (nIndex >= sRemainder.size())
+ {
+ bIsStandardName = true;
+ }
+ }
+ }
+
+ if( bIsStandardName )
+ {
+ if( bResetStringIfStandardName )
+ {
+ // this is for insertion of slides from other files with standard
+ // name. They get a new standard name, if the string is set to an
+ // empty one.
+ rInOutPageName.clear();
+ bCanUseNewName = true;
+ }
+ else
+ bCanUseNewName = false;
+ }
+ else
+ {
+ if (!rInOutPageName.isEmpty())
+ {
+ bool bOutDummy;
+ sal_uInt16 nExistingPageNum = mpDoc->GetPageByName( rInOutPageName, bOutDummy );
+ bCanUseNewName = ( nExistingPageNum == SDRPAGE_NOTFOUND );
+ }
+ else
+ bCanUseNewName = false;
+ }
+
+ return bCanUseNewName;
+}
+
+bool DrawDocShell::IsPageNameUnique( std::u16string_view rPageName ) const
+{
+ return mpDoc->IsPageNameUnique(rPageName);
+}
+
+IMPL_LINK( DrawDocShell, RenameSlideHdl, AbstractSvxNameDialog&, rDialog, bool )
+{
+ OUString aNewName;
+ rDialog.GetName( aNewName );
+ return IsNewPageNameValid( aNewName );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/docshell/docshel3.cxx b/sd/source/ui/docshell/docshel3.cxx
new file mode 100644
index 000000000..be045818a
--- /dev/null
+++ b/sd/source/ui/docshell/docshel3.cxx
@@ -0,0 +1,443 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawDocShell.hxx>
+
+#include <svx/svxids.hrc>
+
+#include <svx/ofaitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/srchitem.hxx>
+#include <svl/languageoptions.hxx>
+#include <svtools/langtab.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/abstdlg.hxx>
+#include <svx/drawitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <com/sun/star/i18n/TextConversionOption.hpp>
+#include <sfx2/notebookbar/SfxNotebookBar.hxx>
+#include <editeng/editeng.hxx>
+#include <osl/diagnose.h>
+
+#include <sdmod.hxx>
+#include <drawdoc.hxx>
+#include <fusearch.hxx>
+#include <ViewShell.hxx>
+#include <slideshow.hxx>
+#include <fuhhconv.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+static void lcl_setLanguageForObj( SdrObject *pObj, LanguageType nLang, bool bLanguageNone )
+{
+ const sal_uInt16 aLangWhichId_EE[3] =
+ {
+ EE_CHAR_LANGUAGE,
+ EE_CHAR_LANGUAGE_CJK,
+ EE_CHAR_LANGUAGE_CTL
+ };
+
+ if( bLanguageNone )
+ nLang = LANGUAGE_NONE;
+
+ if( nLang != LANGUAGE_DONTKNOW )
+ {
+ if( nLang == LANGUAGE_NONE )
+ {
+ for(sal_uInt16 n : aLangWhichId_EE)
+ pObj->SetMergedItem( SvxLanguageItem( nLang, n ) );
+ }
+ else
+ {
+ sal_uInt16 nLangWhichId = 0;
+ SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( nLang );
+ switch (nScriptType)
+ {
+ case SvtScriptType::LATIN : nLangWhichId = EE_CHAR_LANGUAGE; break;
+ case SvtScriptType::ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break;
+ case SvtScriptType::COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break;
+ default:
+ OSL_FAIL("unexpected case" );
+ return;
+ }
+ pObj->SetMergedItem( SvxLanguageItem( nLang, nLangWhichId ) );
+
+ // Reset shape text language to default, so it inherits the shape language set above.
+ OutlinerParaObject* pOutliner = pObj->GetOutlinerParaObject();
+ if (pOutliner)
+ {
+ EditTextObject& rEditTextObject
+ = const_cast<EditTextObject&>(pOutliner->GetTextObject());
+ for (sal_uInt16 n : aLangWhichId_EE)
+ {
+ rEditTextObject.RemoveCharAttribs(n);
+ }
+ }
+ }
+ }
+ else // Reset to default
+ {
+ for(sal_uInt16 n : aLangWhichId_EE)
+ pObj->ClearMergedItem( n );
+ }
+}
+
+static void lcl_setLanguage( const SdDrawDocument *pDoc, std::u16string_view rLanguage, bool bLanguageNone = false )
+{
+ LanguageType nLang = SvtLanguageTable::GetLanguageType( rLanguage );
+
+ // Do it for SdDrawDocument->SetLanguage as well?
+
+ sal_uInt16 nPageCount = pDoc->GetPageCount(); // Pick All Pages
+ for( sal_uInt16 nPage = 0; nPage < nPageCount; nPage++ )
+ {
+ const SdrPage *pPage = pDoc->GetPage( nPage );
+ const size_t nObjCount = pPage->GetObjCount();
+ for( size_t nObj = 0; nObj < nObjCount; ++nObj )
+ {
+ SdrObject *pObj = pPage->GetObj( nObj );
+ if (pObj->GetObjIdentifier() != SdrObjKind::Page)
+ lcl_setLanguageForObj( pObj, nLang, bLanguageNone );
+ }
+ }
+}
+
+/**
+ * Handles SFX-Requests
+ */
+void DrawDocShell::Execute( SfxRequest& rReq )
+{
+ if(mpViewShell && SlideShow::IsRunning( mpViewShell->GetViewShellBase() ))
+ {
+ // during a running presentation no slot will be executed
+ return;
+ }
+
+ switch ( rReq.GetSlot() )
+ {
+ case SID_SEARCH_ITEM:
+ {
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ if (pReqArgs)
+ {
+ const SvxSearchItem & rSearchItem = pReqArgs->Get(SID_SEARCH_ITEM);
+
+ SD_MOD()->SetSearchItem(std::unique_ptr<SvxSearchItem>(rSearchItem.Clone()));
+ }
+
+ rReq.Done();
+ }
+ break;
+
+ case FID_SEARCH_ON:
+ {
+ // no action needed
+ rReq.Done();
+ }
+ break;
+
+ case FID_SEARCH_OFF:
+ {
+ if (mpViewShell)
+ {
+ sd::View* pView = mpViewShell->GetView();
+ if (pView)
+ {
+ auto& rFunctionContext = pView->getSearchContext();
+ rtl::Reference<FuSearch>& xFuSearch(rFunctionContext.getFunctionSearch());
+
+ if (xFuSearch.is())
+ {
+ // End Search&Replace in all docshells
+ SfxObjectShell* pFirstShell = SfxObjectShell::GetFirst();
+ SfxObjectShell* pShell = pFirstShell;
+
+ while (pShell)
+ {
+ auto pDrawDocShell = dynamic_cast<DrawDocShell*>(pShell);
+ if (pDrawDocShell)
+ pDrawDocShell->CancelSearching();
+
+ pShell = SfxObjectShell::GetNext(*pShell);
+
+ if (pShell == pFirstShell)
+ pShell = nullptr;
+ }
+
+ rFunctionContext.resetSearchFunction();
+ Invalidate();
+ rReq.Done();
+ }
+ }
+ }
+ }
+ break;
+
+ case FID_SEARCH_NOW:
+ {
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ if (pReqArgs && mpViewShell)
+ {
+ sd::View* pView = mpViewShell->GetView();
+ if (pView)
+ {
+ rtl::Reference<FuSearch> & xFuSearch = pView->getSearchContext().getFunctionSearch();
+
+ if (!xFuSearch.is())
+ {
+ xFuSearch = rtl::Reference<FuSearch>(
+ FuSearch::createPtr(mpViewShell,
+ mpViewShell->GetActiveWindow(),
+ pView, mpDoc, rReq));
+
+ pView->getSearchContext().setSearchFunction(xFuSearch);
+ }
+
+ if (xFuSearch.is())
+ {
+ const SvxSearchItem& rSearchItem = pReqArgs->Get(SID_SEARCH_ITEM);
+
+ SD_MOD()->SetSearchItem(std::unique_ptr<SvxSearchItem>(rSearchItem.Clone()));
+ xFuSearch->SearchAndReplace(&rSearchItem);
+ }
+ }
+ }
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_CLOSEDOC:
+ {
+ ExecuteSlot(rReq, SfxObjectShell::GetStaticInterface());
+ }
+ break;
+
+ case SID_GET_COLORLIST:
+ {
+ const SvxColorListItem* pColItem = GetItem( SID_COLOR_TABLE );
+ const XColorListRef& pList = pColItem->GetColorList();
+ rReq.SetReturnValue( OfaXColorListItem( SID_GET_COLORLIST, pList ) );
+ }
+ break;
+
+ case SID_VERSION:
+ {
+ ExecuteSlot( rReq, SfxObjectShell::GetStaticInterface() );
+ }
+ break;
+
+ case SID_HANGUL_HANJA_CONVERSION:
+ {
+ if( mpViewShell )
+ {
+ rtl::Reference<FuPoor> aFunc( FuHangulHanjaConversion::Create( mpViewShell, mpViewShell->GetActiveWindow(), mpViewShell->GetView(), mpDoc, rReq ) );
+ static_cast< FuHangulHanjaConversion* >( aFunc.get() )->StartConversion( LANGUAGE_KOREAN, LANGUAGE_KOREAN, nullptr, i18n::TextConversionOption::CHARACTER_BY_CHARACTER, true );
+ }
+ }
+ break;
+
+ case SID_CHINESE_CONVERSION:
+ {
+ if( mpViewShell )
+ {
+ rtl::Reference<FuPoor> aFunc( FuHangulHanjaConversion::Create( mpViewShell, mpViewShell->GetActiveWindow(), mpViewShell->GetView(), mpDoc, rReq ) );
+ static_cast< FuHangulHanjaConversion* >( aFunc.get() )->StartChineseConversion();
+ }
+ }
+ break;
+ case SID_LANGUAGE_STATUS:
+ {
+ OUString aNewLangTxt;
+ const SfxStringItem* pItem = rReq.GetArg<SfxStringItem>(SID_LANGUAGE_STATUS);
+ if (pItem)
+ aNewLangTxt = pItem->GetValue();
+
+ if (aNewLangTxt == "*" )
+ {
+ // open the dialog "Tools/Options/Language Settings - Language"
+ if (mpViewShell)
+ {
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateVclDialog( mpViewShell->GetFrameWeld(), SID_LANGUAGE_OPTIONS ));
+ pDlg->Execute();
+ }
+ }
+ else
+ {
+ if( mpViewShell )
+ {
+ // setting the new language...
+ if (!aNewLangTxt.isEmpty())
+ {
+ static const OUStringLiteral aSelectionLangPrefix(u"Current_");
+ static const OUStringLiteral aParagraphLangPrefix(u"Paragraph_");
+ static const OUStringLiteral aDocumentLangPrefix(u"Default_");
+
+ bool bSelection = false;
+ bool bParagraph = false;
+
+ SdDrawDocument* pDoc = mpViewShell->GetDoc();
+ sal_Int32 nPos = -1;
+ if (-1 != (nPos = aNewLangTxt.indexOf( aDocumentLangPrefix )))
+ {
+ aNewLangTxt = aNewLangTxt.replaceAt( nPos, aDocumentLangPrefix.getLength(), u"" );
+
+ if (aNewLangTxt == "LANGUAGE_NONE")
+ lcl_setLanguage( pDoc, u"", true );
+ else if (aNewLangTxt == "RESET_LANGUAGES")
+ lcl_setLanguage( pDoc, u"" );
+ else
+ lcl_setLanguage( pDoc, aNewLangTxt );
+ }
+ else if (-1 != (nPos = aNewLangTxt.indexOf( aSelectionLangPrefix )))
+ {
+ bSelection = true;
+ aNewLangTxt = aNewLangTxt.replaceAt( nPos, aSelectionLangPrefix.getLength(), u"" );
+ }
+ else if (-1 != (nPos = aNewLangTxt.indexOf( aParagraphLangPrefix )))
+ {
+ bParagraph = true;
+ aNewLangTxt = aNewLangTxt.replaceAt( nPos, aParagraphLangPrefix.getLength(), u"" );
+ }
+
+ if (bSelection || bParagraph)
+ {
+ SdrView* pSdrView = mpViewShell->GetDrawView();
+ if (!pSdrView)
+ return;
+
+ EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView();
+ const LanguageType nLangToUse = SvtLanguageTable::GetLanguageType( aNewLangTxt );
+ SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( nLangToUse );
+
+ SfxItemSet aAttrs = rEditView.GetEditEngine()->GetEmptyItemSet();
+ if (nScriptType == SvtScriptType::LATIN)
+ aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE ) );
+ if (nScriptType == SvtScriptType::COMPLEX)
+ aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CTL ) );
+ if (nScriptType == SvtScriptType::ASIAN)
+ aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CJK ) );
+ ESelection aOldSel;
+ if (bParagraph)
+ {
+ ESelection aSel = rEditView.GetSelection();
+ aOldSel = aSel;
+ aSel.nStartPos = 0;
+ aSel.nEndPos = EE_TEXTPOS_ALL;
+ rEditView.SetSelection( aSel );
+ }
+
+ rEditView.SetAttribs( aAttrs );
+ if (bParagraph)
+ rEditView.SetSelection( aOldSel );
+ }
+
+ if ( pDoc->GetOnlineSpell() )
+ {
+ pDoc->StartOnlineSpelling();
+ }
+ }
+ }
+ }
+ Broadcast(SfxHint(SfxHintId::LanguageChanged));
+ }
+ break;
+ case SID_SPELLCHECK_IGNORE_ALL:
+ {
+ if (!mpViewShell)
+ return;
+ SdrView* pSdrView = mpViewShell->GetDrawView();
+ if (!pSdrView)
+ return;
+
+ EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView();
+ OUString sIgnoreText;
+ const SfxStringItem* pItem2 = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pItem2)
+ sIgnoreText = pItem2->GetValue();
+
+ if(sIgnoreText == "Spelling")
+ {
+ ESelection aOldSel = rEditView.GetSelection();
+ rEditView.SpellIgnoreWord();
+ rEditView.SetSelection( aOldSel );
+ }
+ }
+ break;
+ case SID_SPELLCHECK_APPLY_SUGGESTION:
+ {
+ if (!mpViewShell)
+ return;
+ SdrView* pSdrView = mpViewShell->GetDrawView();
+ if (!pSdrView)
+ return;
+
+ EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView();
+ OUString sApplyText;
+ const SfxStringItem* pItem2 = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pItem2)
+ sApplyText = pItem2->GetValue();
+
+ static const OUStringLiteral sSpellingRule(u"Spelling_");
+ sal_Int32 nPos = 0;
+ if(-1 != (nPos = sApplyText.indexOf( sSpellingRule )))
+ {
+ sApplyText = sApplyText.replaceAt(nPos, sSpellingRule.getLength(), u"");
+ rEditView.InsertText( sApplyText );
+ }
+ }
+ break;
+
+ case SID_NOTEBOOKBAR:
+ {
+ const SfxStringItem* pFile = rReq.GetArg<SfxStringItem>( SID_NOTEBOOKBAR );
+
+ if ( mpViewShell )
+ {
+ SfxBindings& rBindings( mpViewShell->GetFrame()->GetBindings() );
+
+ if ( sfx2::SfxNotebookBar::IsActive() )
+ sfx2::SfxNotebookBar::ExecMethod( rBindings, pFile ? pFile->GetValue() : "" );
+ else
+ sfx2::SfxNotebookBar::CloseMethod( rBindings );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/docshell/docshel4.cxx b/sd/source/ui/docshell/docshel4.cxx
new file mode 100644
index 000000000..6fe599e44
--- /dev/null
+++ b/sd/source/ui/docshell/docshel4.cxx
@@ -0,0 +1,1002 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <memory>
+#include <utility>
+
+#include <DrawDocShell.hxx>
+#include <com/sun/star/document/PrinterIndependentLayout.hpp>
+#include <editeng/outlobj.hxx>
+#include <tools/urlobj.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/editeng.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/flstitem.hxx>
+#include <svl/flagitem.hxx>
+#include <sot/storage.hxx>
+#include <sfx2/dinfdlg.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svdotext.hxx>
+#include <sfx2/printer.hxx>
+#include <svtools/ctrltool.hxx>
+#include <comphelper/classids.hxx>
+#include <sot/formats.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/syswin.hxx>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/drawing/XDrawView.hpp>
+
+#include <app.hrc>
+#include <strings.hrc>
+#include <FrameView.hxx>
+#include <optsitem.hxx>
+#include <Outliner.hxx>
+#include <sdattr.hrc>
+#include <drawdoc.hxx>
+#include <ViewShell.hxx>
+#include <sdmod.hxx>
+#include <View.hxx>
+#include <EffectMigration.hxx>
+#include <CustomAnimationEffect.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <OutlineView.hxx>
+#include <OutlineViewShell.hxx>
+#include <sdxmlwrp.hxx>
+#include <sdpptwrp.hxx>
+#include <sdcgmfilter.hxx>
+#include <sdgrffilter.hxx>
+#include <sdhtmlfilter.hxx>
+#include <sdpdffilter.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <sfx2/zoomitem.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using ::sd::framework::FrameworkHelper;
+
+// PowerPoint-Filter
+constexpr OUStringLiteral pFilterPowerPoint97( u"MS PowerPoint 97" );
+constexpr OUStringLiteral pFilterPowerPoint97Template( u"MS PowerPoint 97 Vorlage" );
+constexpr OUStringLiteral pFilterPowerPoint97AutoPlay( u"MS PowerPoint 97 AutoPlay" );
+
+namespace sd {
+
+/**
+ * Creates (if necessary) and returns a SfxPrinter
+ */
+SfxPrinter* DrawDocShell::GetPrinter(bool bCreate)
+{
+ if (bCreate && !mpPrinter)
+ {
+ // create ItemSet with special pool area
+ auto pSet = std::make_unique<SfxItemSetFixed<
+ SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
+ SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC,
+ ATTR_OPTIONS_PRINT, ATTR_OPTIONS_PRINT>>( GetPool() );
+ // set PrintOptionsSet
+ SdOptionsPrintItem aPrintItem( SD_MOD()->GetSdOptions(mpDoc->GetDocumentType()) );
+ SfxFlagItem aFlagItem( SID_PRINTER_CHANGESTODOC );
+ SfxPrinterChangeFlags nFlags =
+ (aPrintItem.GetOptionsPrint().IsWarningSize() ? SfxPrinterChangeFlags::CHG_SIZE : SfxPrinterChangeFlags::NONE) |
+ (aPrintItem.GetOptionsPrint().IsWarningOrientation() ? SfxPrinterChangeFlags::CHG_ORIENTATION : SfxPrinterChangeFlags::NONE);
+ aFlagItem.SetValue( static_cast<int>(nFlags) );
+
+ pSet->Put( aPrintItem );
+ pSet->Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aPrintItem.GetOptionsPrint().IsWarningPrinter() ) );
+ pSet->Put( aFlagItem );
+
+ mpPrinter = VclPtr<SfxPrinter>::Create(std::move(pSet));
+ mbOwnPrinter = true;
+
+ // set output quality
+ sal_uInt16 nQuality = aPrintItem.GetOptionsPrint().GetOutputQuality();
+
+ DrawModeFlags nMode = DrawModeFlags::Default;
+ // 1 == Grayscale, 2 == Black & White (with grayscale images)
+ if( nQuality == 1 )
+ nMode = DrawModeFlags::GrayLine | DrawModeFlags::GrayFill | DrawModeFlags::GrayText | DrawModeFlags::GrayBitmap | DrawModeFlags::GrayGradient;
+ else if( nQuality == 2 )
+ nMode = DrawModeFlags::BlackLine | DrawModeFlags::WhiteFill | DrawModeFlags::BlackText | DrawModeFlags::GrayBitmap | DrawModeFlags::WhiteGradient;
+
+ mpPrinter->SetDrawMode( nMode );
+
+ MapMode aMM (mpPrinter->GetMapMode());
+ aMM.SetMapUnit(MapUnit::Map100thMM);
+ mpPrinter->SetMapMode(aMM);
+ UpdateRefDevice();
+ }
+ return mpPrinter;
+}
+
+/**
+ * Set new SfxPrinter (transfer of ownership)
+ */
+void DrawDocShell::SetPrinter(SfxPrinter *pNewPrinter)
+{
+ if ( mpViewShell )
+ {
+ ::sd::View* pView = mpViewShell->GetView();
+ if ( pView->IsTextEdit() )
+ pView->SdrEndTextEdit();
+ }
+
+ if ( mpPrinter && mbOwnPrinter && (mpPrinter.get() != pNewPrinter) )
+ mpPrinter.disposeAndClear();
+
+ mpPrinter = pNewPrinter;
+ mbOwnPrinter = true;
+ if ( mpDoc->GetPrinterIndependentLayout() == css::document::PrinterIndependentLayout::DISABLED )
+ UpdateFontList();
+ UpdateRefDevice();
+}
+
+void DrawDocShell::UpdateFontList()
+{
+ mpFontList.reset();
+ OutputDevice* pRefDevice = nullptr;
+ if ( mpDoc->GetPrinterIndependentLayout() == css::document::PrinterIndependentLayout::DISABLED )
+ pRefDevice = GetPrinter(true);
+ else
+ pRefDevice = SD_MOD()->GetVirtualRefDevice();
+ mpFontList.reset( new FontList(pRefDevice, nullptr) );
+ SvxFontListItem aFontListItem( mpFontList.get(), SID_ATTR_CHAR_FONTLIST );
+ PutItem( aFontListItem );
+}
+
+Printer* DrawDocShell::GetDocumentPrinter()
+{
+ return GetPrinter(false);
+}
+
+void DrawDocShell::OnDocumentPrinterChanged(Printer* pNewPrinter)
+{
+ // if we already have a printer, see if it's the same
+ if( mpPrinter )
+ {
+ // easy case
+ if( mpPrinter == pNewPrinter )
+ return;
+
+ // compare if it's the same printer with the same job setup
+ if( (mpPrinter->GetName() == pNewPrinter->GetName()) &&
+ (mpPrinter->GetJobSetup() == pNewPrinter->GetJobSetup()))
+ return;
+ }
+
+ SfxPrinter* const pSfxPrinter = dynamic_cast<SfxPrinter*>(pNewPrinter);
+ if (pSfxPrinter)
+ {
+ SetPrinter(pSfxPrinter);
+
+ // container owns printer
+ mbOwnPrinter = false;
+ }
+}
+
+void DrawDocShell::UpdateRefDevice()
+{
+ if( !mpDoc )
+ return;
+
+ // Determine the device for which the output will be formatted.
+ VclPtr< OutputDevice > pRefDevice;
+ switch (mpDoc->GetPrinterIndependentLayout())
+ {
+ case css::document::PrinterIndependentLayout::DISABLED:
+ pRefDevice = mpPrinter.get();
+ break;
+
+ case css::document::PrinterIndependentLayout::ENABLED:
+ pRefDevice = SD_MOD()->GetVirtualRefDevice();
+ break;
+
+ default:
+ // We are confronted with an invalid or un-implemented
+ // layout mode. Use the printer as formatting device
+ // as a fall-back.
+ SAL_WARN( "sd", "DrawDocShell::UpdateRefDevice(): Unexpected printer layout mode");
+
+ pRefDevice = mpPrinter.get();
+ break;
+ }
+ mpDoc->SetRefDevice( pRefDevice.get() );
+
+ SdOutliner* pOutl = mpDoc->GetOutliner( false );
+
+ if( pOutl )
+ pOutl->SetRefDevice( pRefDevice );
+
+ SdOutliner* pInternalOutl = mpDoc->GetInternalOutliner( false );
+
+ if( pInternalOutl )
+ pInternalOutl->SetRefDevice( pRefDevice );
+}
+
+/**
+ * Creates new document, opens streams
+ */
+bool DrawDocShell::InitNew( const css::uno::Reference< css::embed::XStorage >& xStorage )
+{
+ bool bRet = SfxObjectShell::InitNew( xStorage );
+
+ ::tools::Rectangle aVisArea( Point(0, 0), Size(14100, 10000) );
+ SetVisArea(aVisArea);
+
+ if (bRet)
+ {
+ if( !mbSdDataObj )
+ mpDoc->NewOrLoadCompleted(DocCreationMode::New); // otherwise calling
+ // NewOrLoadCompleted(NEW_LOADED) in
+ // SdDrawDocument::AllocModel()
+ }
+ return bRet;
+}
+
+/**
+ * loads pools and document
+ */
+bool DrawDocShell::Load( SfxMedium& rMedium )
+{
+ // If this is an ODF file being loaded, then by default, use legacy processing
+ // for tdf#99729 (if required, it will be overridden in *::ReadUserDataSequence())
+ if (IsOwnStorageFormat(rMedium))
+ {
+ mpDoc->SetAnchoredTextOverflowLegacy(true);
+ }
+
+ bool bRet = false;
+ bool bStartPresentation = false;
+ ErrCode nError = ERRCODE_NONE;
+
+ SfxItemSet* pSet = rMedium.GetItemSet();
+
+ if( pSet )
+ {
+ if( ( SfxItemState::SET == pSet->GetItemState(SID_PREVIEW ) ) && pSet->Get( SID_PREVIEW ).GetValue() )
+ {
+ mpDoc->SetStarDrawPreviewMode( true );
+ }
+
+ if( SfxItemState::SET == pSet->GetItemState(SID_DOC_STARTPRESENTATION)&&
+ pSet->Get( SID_DOC_STARTPRESENTATION ).GetValue() )
+ {
+ bStartPresentation = true;
+ mpDoc->SetStartWithPresentation( true );
+ }
+ }
+
+ bRet = SfxObjectShell::Load( rMedium );
+ if (bRet)
+ {
+ comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = getEmbeddedObjectContainer();
+ rEmbeddedObjectContainer.setUserAllowsLinkUpdate(false);
+ bRet = SdXMLFilter( rMedium, *this, SdXMLFilterMode::Normal, SotStorage::GetVersion( rMedium.GetStorage() ) ).Import( nError );
+ }
+
+ if( bRet )
+ {
+ // for legacy markup in OOoXML filter, convert the animations now
+ EffectMigration::DocumentLoaded(*GetDoc());
+ UpdateTablePointers();
+
+ // If we're an embedded OLE object, use tight bounds
+ // for our visArea. No point in showing the user lots of empty
+ // space. Had to remove the check for empty VisArea below,
+ // since XML load always sets a VisArea before.
+ //TODO/LATER: looks a little bit strange!
+ if( ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED ) && SfxObjectShell::GetVisArea( ASPECT_CONTENT ).IsEmpty() )
+ {
+ SdPage* pPage = mpDoc->GetSdPage( 0, PageKind::Standard );
+
+ if( pPage )
+ SetVisArea( pPage->GetAllObjBoundRect() );
+ }
+
+ FinishedLoading();
+
+ const INetURLObject aUrl;
+ SfxObjectShell::SetAutoLoad( aUrl, 0, false );
+ }
+ else
+ {
+ if( nError == ERRCODE_IO_BROKENPACKAGE )
+ SetError(ERRCODE_IO_BROKENPACKAGE);
+
+ // TODO/LATER: correct error handling?!
+ //pStore->SetError(SVSTREAM_WRONGVERSION);
+ else
+ SetError(ERRCODE_ABORT);
+ }
+
+ // tell SFX to change viewshell when in preview mode
+ if( IsPreview() || bStartPresentation )
+ {
+ SfxItemSet *pMediumSet = GetMedium()->GetItemSet();
+ if( pMediumSet )
+ pMediumSet->Put( SfxUInt16Item( SID_VIEW_ID, bStartPresentation ? 1 : 5 ) );
+ }
+
+ return bRet;
+}
+
+/**
+ * loads content for organizer
+ */
+bool DrawDocShell::LoadFrom( SfxMedium& rMedium )
+{
+ std::unique_ptr<weld::WaitObject> pWait;
+ if( mpViewShell )
+ pWait.reset(new weld::WaitObject(mpViewShell->GetFrameWeld()));
+
+ mpDoc->NewOrLoadCompleted( DocCreationMode::New );
+ mpDoc->CreateFirstPages();
+ mpDoc->StopWorkStartupDelay();
+
+ // TODO/LATER: nobody is interested in the error code?!
+ ErrCode nError = ERRCODE_NONE;
+ bool bRet = SdXMLFilter( rMedium, *this, SdXMLFilterMode::Organizer, SotStorage::GetVersion( rMedium.GetStorage() ) ).Import( nError );
+
+ // tell SFX to change viewshell when in preview mode
+ if( IsPreview() )
+ {
+ SfxItemSet *pSet = GetMedium()->GetItemSet();
+
+ if( pSet )
+ pSet->Put( SfxUInt16Item( SID_VIEW_ID, 5 ) );
+ }
+
+ return bRet;
+}
+
+/**
+ * load from 3rd party format
+ */
+bool DrawDocShell::ImportFrom(SfxMedium &rMedium,
+ uno::Reference<text::XTextRange> const& xInsertPosition)
+{
+ const OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
+ if (aFilterName == "Impress MS PowerPoint 2007 XML" ||
+ aFilterName == "Impress MS PowerPoint 2007 XML AutoPlay" ||
+ aFilterName == "Impress MS PowerPoint 2007 XML VBA")
+ {
+ // As this is a MSFT format, we should use the "MS Compat"
+ // mode for spacing before and after paragraphs.
+
+ // This is copied from what is done for .ppt import in
+ // ImplSdPPTImport::Import() in sd/source/filter/ppt/pptin.cxx
+ // in. We need to tell both the edit engine of the draw outliner,
+ // and the document, to do "summation of paragraphs".
+ SdrOutliner& rOutl = mpDoc->GetDrawOutliner();
+ EEControlBits nControlWord = rOutl.GetEditEngine().GetControlWord();
+ nControlWord |= EEControlBits::ULSPACESUMMATION;
+ const_cast<EditEngine&>(rOutl.GetEditEngine()).SetControlWord( nControlWord );
+
+ mpDoc->SetSummationOfParagraphs();
+ }
+
+ if (aFilterName == "Impress MS PowerPoint 2007 XML" ||
+ aFilterName == "Impress MS PowerPoint 2007 XML AutoPlay" ||
+ aFilterName == "Impress MS PowerPoint 2007 XML VBA" ||
+ aFilterName == "Impress Office Open XML")
+ {
+ // We need to be able to set the default tab size for each text object.
+ // This is possible at the moment only for the whole document. See
+ // TextParagraphPropertiesContext constructor. So default tab width
+ // of the LibreOffice is 1270 but MSO is 2540 on general settings.
+ mpDoc->SetDefaultTabulator( 2540 );
+ }
+
+ const bool bRet = SfxObjectShell::ImportFrom(rMedium, xInsertPosition);
+
+ SfxItemSet* pSet = rMedium.GetItemSet();
+ if( pSet )
+ {
+ if( SfxItemState::SET == pSet->GetItemState(SID_DOC_STARTPRESENTATION)&&
+ pSet->Get( SID_DOC_STARTPRESENTATION ).GetValue() )
+ {
+ mpDoc->SetStartWithPresentation( true );
+
+ // tell SFX to change viewshell when in preview mode
+ if( IsPreview() )
+ {
+ SfxItemSet *pMediumSet = GetMedium()->GetItemSet();
+ if( pMediumSet )
+ pMediumSet->Put( SfxUInt16Item( SID_VIEW_ID, 1 ) );
+ }
+ }
+ }
+
+ return bRet;
+}
+
+/**
+ * load from a foreign format
+ */
+bool DrawDocShell::ConvertFrom( SfxMedium& rMedium )
+{
+ const OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
+ bool bRet = false;
+ bool bStartPresentation = false;
+
+ SetWaitCursor( true );
+
+ SfxItemSet* pSet = rMedium.GetItemSet();
+ if( pSet )
+ {
+ if( ( SfxItemState::SET == pSet->GetItemState(SID_PREVIEW ) ) && pSet->Get( SID_PREVIEW ).GetValue() )
+ {
+ mpDoc->SetStarDrawPreviewMode( true );
+ }
+
+ if( SfxItemState::SET == pSet->GetItemState(SID_DOC_STARTPRESENTATION)&&
+ pSet->Get( SID_DOC_STARTPRESENTATION ).GetValue() )
+ {
+ bStartPresentation = true;
+ mpDoc->SetStartWithPresentation( true );
+ }
+ }
+
+ if( aFilterName == pFilterPowerPoint97
+ || aFilterName == pFilterPowerPoint97Template
+ || aFilterName == pFilterPowerPoint97AutoPlay)
+ {
+ mpDoc->StopWorkStartupDelay();
+ bRet = SdPPTFilter( rMedium, *this ).Import();
+ }
+ else if (aFilterName.indexOf("impress8") >= 0 ||
+ aFilterName.indexOf("draw8") >= 0)
+ {
+ // TODO/LATER: nobody is interested in the error code?!
+ mpDoc->CreateFirstPages();
+ mpDoc->StopWorkStartupDelay();
+ ErrCode nError = ERRCODE_NONE;
+ bRet = SdXMLFilter( rMedium, *this ).Import( nError );
+
+ }
+ else if (aFilterName.indexOf("StarOffice XML (Draw)") >= 0 ||
+ aFilterName.indexOf("StarOffice XML (Impress)") >= 0)
+ {
+ // TODO/LATER: nobody is interested in the error code?!
+ mpDoc->CreateFirstPages();
+ mpDoc->StopWorkStartupDelay();
+ ErrCode nError = ERRCODE_NONE;
+ bRet = SdXMLFilter( rMedium, *this, SdXMLFilterMode::Normal, SOFFICE_FILEFORMAT_60 ).Import( nError );
+ }
+ else if (aFilterName == "CGM - Computer Graphics Metafile")
+ {
+ mpDoc->CreateFirstPages();
+ mpDoc->StopWorkStartupDelay();
+ bRet = SdCGMFilter( rMedium, *this ).Import();
+ }
+ else if (aFilterName == "draw_pdf_import")
+ {
+ mpDoc->CreateFirstPages();
+ mpDoc->StopWorkStartupDelay();
+ bRet = SdPdfFilter(rMedium, *this).Import();
+ }
+ else
+ {
+ mpDoc->CreateFirstPages();
+ mpDoc->StopWorkStartupDelay();
+ bRet = SdGRFFilter( rMedium, *this ).Import();
+ }
+
+ FinishedLoading();
+
+ // tell SFX to change viewshell when in preview mode
+ if( IsPreview() )
+ {
+ SfxItemSet *pMediumSet = GetMedium()->GetItemSet();
+
+ if( pMediumSet )
+ pMediumSet->Put( SfxUInt16Item( SID_VIEW_ID, 5 ) );
+ }
+ SetWaitCursor( false );
+
+ // tell SFX to change viewshell when in preview mode
+ if( IsPreview() || bStartPresentation )
+ {
+ SfxItemSet *pMediumSet = GetMedium()->GetItemSet();
+ if( pMediumSet )
+ pMediumSet->Put( SfxUInt16Item( SID_VIEW_ID, bStartPresentation ? 1 : 5 ) );
+ }
+
+ return bRet;
+}
+
+/**
+ * Writes pools and document to the open streams
+ */
+bool DrawDocShell::Save()
+{
+ mpDoc->StopWorkStartupDelay();
+
+ //TODO/LATER: why this?!
+ if( GetCreateMode() == SfxObjectCreateMode::STANDARD )
+ SfxObjectShell::SetVisArea( ::tools::Rectangle() );
+
+ bool bRet = SfxObjectShell::Save();
+
+ if( bRet )
+ bRet = SdXMLFilter( *GetMedium(), *this, SdXMLFilterMode::Normal, SotStorage::GetVersion( GetMedium()->GetStorage() ) ).Export();
+
+ return bRet;
+}
+
+/**
+ * Writes pools and document to the provided storage
+ */
+bool DrawDocShell::SaveAs( SfxMedium& rMedium )
+{
+ mpDoc->setDocAccTitle(OUString());
+ if (SfxViewFrame* pFrame1 = SfxViewFrame::GetFirst(this))
+ {
+ if (vcl::Window* pSysWin = pFrame1->GetWindow().GetSystemWindow())
+ {
+ pSysWin->SetAccessibleName(OUString());
+ }
+ }
+ mpDoc->StopWorkStartupDelay();
+
+ //With custom animation, if Outliner is modified, update text before saving
+ if( mpViewShell )
+ {
+ SdPage* pPage = mpViewShell->getCurrentPage();
+ if( pPage && pPage->getMainSequence()->getCount() )
+ {
+ SdrObject* pObj = mpViewShell->GetView()->GetTextEditObject();
+ SdrOutliner* pOutl = mpViewShell->GetView()->GetTextEditOutliner();
+ if( pObj && pOutl && pOutl->IsModified() )
+ {
+ std::optional<OutlinerParaObject> pNewText = pOutl->CreateParaObject( 0, pOutl->GetParagraphCount() );
+ pObj->SetOutlinerParaObject( std::move(pNewText) );
+ pOutl->ClearModifyFlag();
+ }
+ }
+ }
+
+ //TODO/LATER: why this?!
+ if( GetCreateMode() == SfxObjectCreateMode::STANDARD )
+ SfxObjectShell::SetVisArea( ::tools::Rectangle() );
+
+ bool bRet = SfxObjectShell::SaveAs( rMedium );
+
+ if( bRet )
+ bRet = SdXMLFilter( rMedium, *this, SdXMLFilterMode::Normal, SotStorage::GetVersion( rMedium.GetStorage() ) ).Export();
+
+ if( GetError() == ERRCODE_NONE )
+ SetError(ERRCODE_NONE);
+
+ return bRet;
+}
+
+/**
+ * save to foreign format
+ */
+bool DrawDocShell::ConvertTo( SfxMedium& rMedium )
+{
+ bool bRet = false;
+
+ if( mpDoc->GetPageCount() )
+ {
+ std::shared_ptr<const SfxFilter> pMediumFilter = rMedium.GetFilter();
+ const OUString aTypeName( pMediumFilter->GetTypeName() );
+ std::unique_ptr<SdFilter> xFilter;
+
+ if( aTypeName.indexOf( "graphic_HTML" ) >= 0 )
+ {
+ xFilter = std::make_unique<SdHTMLFilter>(rMedium, *this);
+ }
+ else if( aTypeName.indexOf( "MS_PowerPoint_97" ) >= 0 )
+ {
+ xFilter = std::make_unique<SdPPTFilter>(rMedium, *this);
+ static_cast<SdPPTFilter*>(xFilter.get())->PreSaveBasic();
+ }
+ else if ( aTypeName.indexOf( "CGM_Computer_Graphics_Metafile" ) >= 0 )
+ {
+ xFilter = std::make_unique<SdCGMFilter>(rMedium, *this);
+ }
+ else if( aTypeName.indexOf( "draw8" ) >= 0 ||
+ aTypeName.indexOf( "impress8" ) >= 0 )
+ {
+ xFilter = std::make_unique<SdXMLFilter>(rMedium, *this);
+ }
+ else if( aTypeName.indexOf( "StarOffice_XML_Impress" ) >= 0 ||
+ aTypeName.indexOf( "StarOffice_XML_Draw" ) >= 0 )
+ {
+ xFilter = std::make_unique<SdXMLFilter>(rMedium, *this, SdXMLFilterMode::Normal, SOFFICE_FILEFORMAT_60);
+ }
+ else
+ {
+ xFilter = std::make_unique<SdGRFFilter>(rMedium, *this);
+ }
+
+ if (xFilter)
+ {
+ if ( mpViewShell )
+ {
+ ::sd::View* pView = mpViewShell->GetView();
+ if ( pView->IsTextEdit() )
+ pView->SdrEndTextEdit();
+ }
+
+ bRet = xFilter->Export();
+ }
+ }
+
+ return bRet;
+}
+
+/**
+ * Reopen own streams to ensure that nobody else can prevent use from opening
+ * them.
+ */
+bool DrawDocShell::SaveCompleted( const css::uno::Reference< css::embed::XStorage >& xStorage )
+{
+ bool bRet = false;
+
+ if( SfxObjectShell::SaveCompleted(xStorage) )
+ {
+ mpDoc->NbcSetChanged( false );
+
+ if( mpViewShell )
+ {
+ if( dynamic_cast< OutlineViewShell *>( mpViewShell ) != nullptr )
+ static_cast<OutlineView*>(mpViewShell->GetView())
+ ->GetOutliner().ClearModifyFlag();
+
+ SdrOutliner* pOutl = mpViewShell->GetView()->GetTextEditOutliner();
+ if( pOutl )
+ {
+ SdrObject* pObj = mpViewShell->GetView()->GetTextEditObject();
+ if( pObj )
+ pObj->NbcSetOutlinerParaObject( pOutl->CreateParaObject() );
+
+ pOutl->ClearModifyFlag();
+ }
+ }
+
+ bRet = true;
+
+ SfxViewFrame* pFrame = ( mpViewShell && mpViewShell->GetViewFrame() ) ?
+ mpViewShell->GetViewFrame() :
+ SfxViewFrame::Current();
+
+ if( pFrame )
+ pFrame->GetBindings().Invalidate( SID_NAVIGATOR_STATE, true );
+ }
+ return bRet;
+}
+
+SfxStyleSheetBasePool* DrawDocShell::GetStyleSheetPool()
+{
+ return mpDoc->GetStyleSheetPool();
+}
+
+void DrawDocShell::GotoBookmark(std::u16string_view rBookmark)
+{
+ auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell );
+ if (!pDrawViewShell)
+ return;
+
+ ViewShellBase& rBase (mpViewShell->GetViewShellBase());
+
+ bool bIsMasterPage = false;
+ sal_uInt16 nPageNumber = SDRPAGE_NOTFOUND;
+ SdrObject* pObj = nullptr;
+
+ static constexpr std::u16string_view sInteraction( u"action?" );
+ if ( o3tl::starts_with(rBookmark, sInteraction ) )
+ {
+ static constexpr std::u16string_view sJump( u"jump=" );
+ if ( o3tl::starts_with(rBookmark.substr( sInteraction.size() ), sJump ) )
+ {
+ std::u16string_view aDestination( rBookmark.substr( sInteraction.size() + sJump.size() ) );
+ if ( o3tl::starts_with(aDestination, u"firstslide" ) )
+ {
+ nPageNumber = 1;
+ }
+ else if ( o3tl::starts_with(aDestination, u"lastslide" ) )
+ {
+ nPageNumber = mpDoc->GetPageCount() - 2;
+ }
+ else if ( o3tl::starts_with(aDestination, u"previousslide" ) )
+ {
+ SdPage* pPage = pDrawViewShell->GetActualPage();
+ nPageNumber = pPage->GetPageNum();
+ nPageNumber = nPageNumber > 2 ? nPageNumber - 2 : SDRPAGE_NOTFOUND;
+ }
+ else if ( o3tl::starts_with(aDestination, u"nextslide" ) )
+ {
+ SdPage* pPage = pDrawViewShell->GetActualPage();
+ nPageNumber = pPage->GetPageNum() + 2;
+ if ( nPageNumber >= mpDoc->GetPageCount() )
+ nPageNumber = SDRPAGE_NOTFOUND;
+ }
+ }
+ }
+ else
+ {
+ // Is the bookmark a page?
+ nPageNumber = mpDoc->GetPageByName( rBookmark, bIsMasterPage );
+
+ if (nPageNumber == SDRPAGE_NOTFOUND)
+ {
+ // Is the bookmark an object?
+ pObj = mpDoc->GetObj(rBookmark);
+
+ if (pObj)
+ {
+ nPageNumber = pObj->getSdrPageFromSdrObject()->GetPageNum();
+ }
+ }
+ }
+ if (nPageNumber != SDRPAGE_NOTFOUND)
+ {
+ // Jump to the bookmarked page. This is done in three steps.
+
+ SdPage* pPage;
+ if (bIsMasterPage)
+ pPage = static_cast<SdPage*>( mpDoc->GetMasterPage(nPageNumber) );
+ else
+ pPage = static_cast<SdPage*>( mpDoc->GetPage(nPageNumber) );
+
+ // 1.) Change the view shell to the edit view, the notes view,
+ // or the handout view.
+ PageKind eNewPageKind = pPage->GetPageKind();
+
+ if( (eNewPageKind != PageKind::Standard) && (mpDoc->GetDocumentType() == DocumentType::Draw) )
+ return;
+
+ if (eNewPageKind != pDrawViewShell->GetPageKind())
+ {
+ // change work area
+ GetFrameView()->SetPageKind(eNewPageKind);
+ OUString sViewURL;
+ switch (eNewPageKind)
+ {
+ case PageKind::Standard:
+ sViewURL = FrameworkHelper::msImpressViewURL;
+ break;
+ case PageKind::Notes:
+ sViewURL = FrameworkHelper::msNotesViewURL;
+ break;
+ case PageKind::Handout:
+ sViewURL = FrameworkHelper::msHandoutViewURL;
+ break;
+ default:
+ break;
+ }
+ if (!sViewURL.isEmpty())
+ {
+ std::shared_ptr<FrameworkHelper> pHelper (
+ FrameworkHelper::Instance(rBase));
+ pHelper->RequestView(
+ sViewURL,
+ FrameworkHelper::msCenterPaneURL);
+ pHelper->WaitForUpdate();
+
+ // Get the new DrawViewShell.
+ mpViewShell = pHelper->GetViewShell(FrameworkHelper::msCenterPaneURL).get();
+ pDrawViewShell = dynamic_cast<sd::DrawViewShell*>(mpViewShell);
+ }
+ else
+ {
+ pDrawViewShell = nullptr;
+ }
+ }
+
+ if (pDrawViewShell != nullptr)
+ {
+ setEditMode(pDrawViewShell, bIsMasterPage);
+
+ // Make the bookmarked page the current page. This is done
+ // by using the API because this takes care of all the
+ // little things to be done. Especially writing the view
+ // data to the frame view.
+ sal_uInt16 nSdPgNum = (nPageNumber - 1) / 2;
+ Reference<drawing::XDrawView> xController (rBase.GetController(), UNO_QUERY);
+ if (xController.is())
+ {
+ Reference<drawing::XDrawPage> xDrawPage (pPage->getUnoPage(), UNO_QUERY);
+ xController->setCurrentPage (xDrawPage);
+ }
+ else
+ {
+ // As a fall back switch to the page via the core.
+ DBG_ASSERT (xController.is(),
+ "DrawDocShell::GotoBookmark: can't switch page via API");
+ pDrawViewShell->SwitchPage(nSdPgNum);
+ }
+
+ if (pDrawViewShell->GetDispatcher())
+ {
+ // show page
+ SvxZoomItem aZoom;
+ aZoom.SetType( SvxZoomType::WHOLEPAGE );
+ pDrawViewShell->GetDispatcher()->ExecuteList(SID_ATTR_ZOOM, SfxCallMode::ASYNCHRON, { &aZoom });
+ }
+
+ if (pObj != nullptr)
+ {
+ // select object
+ pDrawViewShell->GetView()->UnmarkAll();
+ pDrawViewShell->GetView()->MarkObj(
+ pObj,
+ pDrawViewShell->GetView()->GetSdrPageView());
+ }
+ }
+ }
+
+ SfxBindings& rBindings = ((pDrawViewShell && pDrawViewShell->GetViewFrame()!=nullptr)
+ ? pDrawViewShell->GetViewFrame()
+ : SfxViewFrame::Current() )->GetBindings();
+
+ rBindings.Invalidate(SID_NAVIGATOR_STATE, true);
+ rBindings.Invalidate(SID_NAVIGATOR_PAGENAME);
+}
+
+/**
+ * If it should become a document template.
+ */
+bool DrawDocShell::SaveAsOwnFormat( SfxMedium& rMedium )
+{
+
+ std::shared_ptr<const SfxFilter> pFilter = rMedium.GetFilter();
+
+ if (pFilter->IsOwnTemplateFormat())
+ {
+ /* now the StarDraw specialty:
+ we assign known layout names to the layout template of the first
+ page, we set the layout names of the affected masterpages and pages.
+ We inform all text objects of the affected standard, note and
+ masterpages about the name change.
+ */
+
+ OUString aLayoutName;
+
+ SfxStringItem const * pLayoutItem = rMedium.GetItemSet()->GetItemIfSet(SID_TEMPLATE_NAME, false);
+ if( pLayoutItem )
+ {
+ aLayoutName = pLayoutItem->GetValue();
+ }
+ else
+ {
+ INetURLObject aURL( rMedium.GetName() );
+ aURL.removeExtension();
+ aLayoutName = aURL.getName();
+ }
+
+ if (aLayoutName.isEmpty())
+ {
+ sal_uInt32 nCount = mpDoc->GetMasterSdPageCount(PageKind::Standard);
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ OUString aOldPageLayoutName = mpDoc->GetMasterSdPage(i, PageKind::Standard)->GetLayoutName();
+ OUString aNewLayoutName = aLayoutName;
+ // Don't add suffix for the first master page
+ if( i > 0 )
+ aNewLayoutName += OUString::number(i);
+
+ mpDoc->RenameLayoutTemplate(aOldPageLayoutName, aNewLayoutName);
+ }
+ }
+ }
+
+ return SfxObjectShell::SaveAsOwnFormat(rMedium);
+}
+
+void DrawDocShell::FillClass(SvGlobalName* pClassName,
+ SotClipboardFormatId* pFormat,
+ OUString* pFullTypeName,
+ sal_Int32 nFileFormat,
+ bool bTemplate /* = false */) const
+{
+ if (nFileFormat == SOFFICE_FILEFORMAT_60)
+ {
+ if ( meDocType == DocumentType::Draw )
+ {
+ *pClassName = SvGlobalName(SO3_SDRAW_CLASSID_60);
+ *pFormat = SotClipboardFormatId::STARDRAW_60;
+ *pFullTypeName = SdResId(STR_GRAPHIC_DOCUMENT_FULLTYPE_60);
+ }
+ else
+ {
+ *pClassName = SvGlobalName(SO3_SIMPRESS_CLASSID_60);
+ *pFormat = SotClipboardFormatId::STARIMPRESS_60;
+ *pFullTypeName = SdResId(STR_IMPRESS_DOCUMENT_FULLTYPE_60);
+ }
+ }
+ else if (nFileFormat == SOFFICE_FILEFORMAT_8)
+ {
+ if ( meDocType == DocumentType::Draw )
+ {
+ *pClassName = SvGlobalName(SO3_SDRAW_CLASSID_60);
+ *pFormat = bTemplate ? SotClipboardFormatId::STARDRAW_8_TEMPLATE : SotClipboardFormatId::STARDRAW_8;
+ *pFullTypeName = SdResId(STR_GRAPHIC_DOCUMENT_FULLTYPE_80); // HACK: method will be removed with new storage API
+ }
+ else
+ {
+ *pClassName = SvGlobalName(SO3_SIMPRESS_CLASSID_60);
+ *pFormat = bTemplate ? SotClipboardFormatId::STARIMPRESS_8_TEMPLATE : SotClipboardFormatId::STARIMPRESS_8;
+ *pFullTypeName = SdResId(STR_IMPRESS_DOCUMENT_FULLTYPE_80); // HACK: method will be removed with new storage API
+ }
+ }
+}
+
+OutputDevice* DrawDocShell::GetDocumentRefDev()
+{
+ OutputDevice* pReferenceDevice = SfxObjectShell::GetDocumentRefDev ();
+ // Only when our parent does not have a reference device then we return
+ // our own.
+ if (pReferenceDevice == nullptr && mpDoc != nullptr)
+ pReferenceDevice = mpDoc->GetRefDevice ();
+ return pReferenceDevice;
+}
+
+/** executes the SID_OPENDOC slot to let the framework open a document
+ with the given URL and this document as a referer */
+void DrawDocShell::OpenBookmark( const OUString& rBookmarkURL )
+{
+ SfxStringItem aStrItem( SID_FILE_NAME, rBookmarkURL );
+ SfxStringItem aReferer( SID_REFERER, GetMedium()->GetName() );
+ const SfxPoolItem* ppArgs[] = { &aStrItem, &aReferer, nullptr };
+ ( mpViewShell ? mpViewShell->GetViewFrame() : SfxViewFrame::Current() )->GetBindings().Execute( SID_OPENHYPERLINK, ppArgs );
+}
+
+std::shared_ptr<SfxDocumentInfoDialog> DrawDocShell::CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet &rSet)
+{
+ std::shared_ptr<SfxDocumentInfoDialog> xDlg = std::make_shared<SfxDocumentInfoDialog>(pParent, rSet);
+ DrawDocShell* pDocSh = dynamic_cast<DrawDocShell*>(SfxObjectShell::Current());
+ if( pDocSh == this )
+ {
+ xDlg->AddFontTabPage();
+ }
+ return xDlg;
+}
+
+void DrawDocShell::setEditMode(DrawViewShell* pDrawViewShell, bool isMasterPage)
+{
+ // Set the edit mode to either the normal edit mode or the
+ // master page mode.
+ EditMode eNewEditMode = EditMode::Page;
+ if (isMasterPage)
+ {
+ eNewEditMode = EditMode::MasterPage;
+ }
+
+ if (eNewEditMode != pDrawViewShell->GetEditMode())
+ {
+ // Set EditMode
+ pDrawViewShell->ChangeEditMode(eNewEditMode, false);
+ }
+}
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/docshell/docshell.cxx b/sd/source/ui/docshell/docshell.cxx
new file mode 100644
index 000000000..78279687a
--- /dev/null
+++ b/sd/source/ui/docshell/docshell.cxx
@@ -0,0 +1,515 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawDocShell.hxx>
+
+#include <officecfg/Office/Common.hxx>
+#include <unotools/configmgr.hxx>
+
+#include <sfx2/docfac.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svxids.hrc>
+#include <svl/srchitem.hxx>
+#include <svx/srchdlg.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svditer.hxx>
+#include <editeng/flstitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/printer.hxx>
+#include <svx/drawitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/whiter.hxx>
+#include <svl/itempool.hxx>
+#include <svl/stritem.hxx>
+#include <svtools/ctrltool.hxx>
+#include <svtools/langtab.hxx>
+#include <comphelper/classids.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/visitem.hxx>
+
+#include <app.hrc>
+#include <sdmod.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+
+#include <ViewShell.hxx>
+#include <unomodel.hxx>
+#include <undo/undomanager.hxx>
+#include <undo/undofactory.hxx>
+#include <OutlineView.hxx>
+#include <ViewShellBase.hxx>
+#include <sfx2/notebookbar/SfxNotebookBar.hxx>
+#include <comphelper/lok.hxx>
+#include <DrawViewShell.hxx>
+#include <sdpage.hxx>
+
+using namespace sd;
+#define ShellClass_DrawDocShell
+#include <sdslots.hxx>
+
+SFX_IMPL_SUPERCLASS_INTERFACE(DrawDocShell, SfxObjectShell);
+
+void DrawDocShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterChildWindow(SvxSearchDialogWrapper::GetChildWindowId());
+}
+
+namespace sd {
+
+/**
+ * slotmaps and definitions of SFX
+ */
+
+SFX_IMPL_OBJECTFACTORY(
+ DrawDocShell,
+ SvGlobalName(SO3_SIMPRESS_CLASSID),
+ "simpress" )
+
+void DrawDocShell::Construct( bool bClipboard )
+{
+ mbInDestruction = false;
+ SetSlotFilter(); // resets the filter
+
+ mbOwnDocument = mpDoc == nullptr;
+ if( mbOwnDocument )
+ mpDoc = new SdDrawDocument(meDocType, this);
+
+ // The document has been created so we can call UpdateRefDevice() to set
+ // the document's ref device.
+ UpdateRefDevice();
+
+ SetBaseModel( new SdXImpressDocument( this, bClipboard ) );
+ SetPool( &mpDoc->GetItemPool() );
+ std::unique_ptr<sd::UndoManager> pUndoManager(new sd::UndoManager);
+ pUndoManager->SetDocShell(this);
+ mpUndoManager = std::move(pUndoManager);
+
+ if (!utl::ConfigManager::IsFuzzing()
+ && officecfg::Office::Common::Undo::Steps::get() < 1)
+ {
+ mpUndoManager->EnableUndo(false); // tdf#108863 disable if 0 steps
+ }
+ mpDoc->SetSdrUndoManager( mpUndoManager.get() );
+ mpDoc->SetSdrUndoFactory( new sd::UndoFactory );
+ UpdateTablePointers();
+ SetStyleFamily(SfxStyleFamily::Pseudo);
+}
+
+DrawDocShell::DrawDocShell(SfxObjectCreateMode eMode,
+ bool bDataObject,
+ DocumentType eDocumentType) :
+ SfxObjectShell( eMode == SfxObjectCreateMode::INTERNAL ? SfxObjectCreateMode::EMBEDDED : eMode),
+ mpDoc(nullptr),
+ mpPrinter(nullptr),
+ mpViewShell(nullptr),
+ meDocType(eDocumentType),
+ mbSdDataObj(bDataObject),
+ mbOwnPrinter(false)
+{
+ Construct( eMode == SfxObjectCreateMode::INTERNAL );
+}
+
+DrawDocShell::DrawDocShell( SfxModelFlags nModelCreationFlags, bool bDataObject, DocumentType eDocumentType ) :
+ SfxObjectShell( nModelCreationFlags ),
+ mpDoc(nullptr),
+ mpPrinter(nullptr),
+ mpViewShell(nullptr),
+ meDocType(eDocumentType),
+ mbSdDataObj(bDataObject),
+ mbOwnPrinter(false)
+{
+ Construct( false );
+}
+
+DrawDocShell::DrawDocShell(SdDrawDocument* pDoc, SfxObjectCreateMode eMode,
+ bool bDataObject,
+ DocumentType eDocumentType) :
+ SfxObjectShell(eMode == SfxObjectCreateMode::INTERNAL ? SfxObjectCreateMode::EMBEDDED : eMode),
+ mpDoc(pDoc),
+ mpPrinter(nullptr),
+ mpViewShell(nullptr),
+ meDocType(eDocumentType),
+ mbSdDataObj(bDataObject),
+ mbOwnPrinter(false)
+{
+ Construct( eMode == SfxObjectCreateMode::INTERNAL );
+}
+
+DrawDocShell::~DrawDocShell()
+{
+ // Tell all listeners that the doc shell is about to be
+ // destroyed. This has been introduced for the PreviewRenderer to
+ // free its view (that uses the item poll of the doc shell) but
+ // may be useful in other places as well.
+ Broadcast(SfxHint(SfxHintId::Dying));
+
+ mbInDestruction = true;
+
+ if (mpViewShell)
+ {
+ auto* pView = mpViewShell->GetView();
+ if (pView)
+ {
+ auto & pSearchContext = pView->getSearchContext();
+ pSearchContext.resetSearchFunction();
+ }
+ }
+
+ mpFontList.reset();
+
+ if( mpDoc )
+ mpDoc->SetSdrUndoManager( nullptr );
+ mpUndoManager.reset();
+
+ if (mbOwnPrinter)
+ mpPrinter.disposeAndClear();
+
+ if( mbOwnDocument )
+ delete mpDoc;
+
+ // that the navigator get informed about the disappearance of the document
+ SfxBoolItem aItem(SID_NAVIGATOR_INIT, true);
+ SfxViewFrame* pFrame = mpViewShell ? mpViewShell->GetFrame() : GetFrame();
+
+ if( !pFrame )
+ pFrame = SfxViewFrame::GetFirst( this );
+
+ if( pFrame )
+ {
+ pFrame->GetDispatcher()->ExecuteList(
+ SID_NAVIGATOR_INIT, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aItem });
+ }
+}
+
+void DrawDocShell::GetState(SfxItemSet &rSet)
+{
+
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while ( nWhich )
+ {
+ sal_uInt16 nSlotId = SfxItemPool::IsWhich(nWhich)
+ ? GetPool().GetSlotId(nWhich)
+ : nWhich;
+
+ switch ( nSlotId )
+ {
+ case SID_ATTR_CHAR_FONTLIST:
+ rSet.Put( SvxFontListItem( mpFontList.get(), nSlotId ) );
+ break;
+
+ case SID_SEARCH_ITEM:
+ {
+ rSet.Put( *SD_MOD()->GetSearchItem() );
+ }
+ break;
+
+ case SID_CLOSEDOC:
+ GetSlotState(SID_CLOSEDOC, SfxObjectShell::GetInterface(), &rSet);
+ break;
+
+ case SID_SEARCH_OPTIONS:
+ {
+ SearchOptionFlags nOpt = SearchOptionFlags::SEARCH |
+ SearchOptionFlags::WHOLE_WORDS |
+ SearchOptionFlags::BACKWARDS |
+ SearchOptionFlags::REG_EXP |
+ SearchOptionFlags::EXACT |
+ SearchOptionFlags::SIMILARITY |
+ SearchOptionFlags::SELECTION;
+
+ if (!IsReadOnly())
+ {
+ nOpt |= SearchOptionFlags::REPLACE;
+ nOpt |= SearchOptionFlags::REPLACE_ALL;
+ }
+
+ rSet.Put(SfxUInt16Item(nWhich, static_cast<sal_uInt16>(nOpt)));
+ }
+ break;
+
+ case SID_VERSION:
+ {
+ GetSlotState( SID_VERSION, SfxObjectShell::GetInterface(), &rSet );
+ }
+ break;
+
+ case SID_CHINESE_CONVERSION:
+ case SID_HANGUL_HANJA_CONVERSION:
+ {
+ rSet.Put(SfxVisibilityItem(nWhich, SvtCJKOptions::IsAnyEnabled()));
+ }
+ break;
+ case SID_LANGUAGE_STATUS:
+ {
+ SdrObject* pObj = nullptr;
+ bool bLanguageFound = false;
+ OutlinerParaObject* pParaObj = nullptr;
+ LanguageType eLanguage( LANGUAGE_DONTKNOW );
+ sal_uInt16 nCount = mpDoc->GetPageCount();
+ for ( sal_uInt16 itPage = 0; itPage < nCount && !bLanguageFound; itPage++ )
+ {
+ SdrObjListIter aListIter(mpDoc->GetPage(itPage), SdrIterMode::DeepWithGroups);
+ while ( aListIter.IsMore() && !bLanguageFound )
+ {
+ pObj = aListIter.Next();
+ if ( pObj )
+ {
+ pParaObj = pObj->GetOutlinerParaObject();
+ if ( pParaObj )
+ {
+ SdrOutliner aOutliner(&mpDoc->GetPool(), OutlinerMode::TextObject);
+ aOutliner.SetText(*pParaObj);
+ eLanguage = aOutliner.GetLanguage(0, 0);
+ bLanguageFound = eLanguage != LANGUAGE_DONTKNOW;
+ }
+ }
+ }
+ }
+
+ if ( eLanguage == LANGUAGE_DONTKNOW )
+ {
+ eLanguage = mpDoc->GetLanguage( EE_CHAR_LANGUAGE );
+ }
+
+ OUString aLanguage = SvtLanguageTable::GetLanguageString(eLanguage);
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (eLanguage == LANGUAGE_DONTKNOW)
+ {
+ aLanguage += ";-";
+ }
+ else
+ {
+ aLanguage += ";" + LanguageTag(eLanguage).getBcp47(false);
+ }
+ }
+ rSet.Put(SfxStringItem(nWhich, aLanguage));
+ }
+ break;
+
+ case SID_NOTEBOOKBAR:
+ {
+ if (mpViewShell)
+ {
+ bool bImpress = mpDoc->GetDocumentType() == DocumentType::Impress;
+ bool bVisible = false;
+ if(bImpress)
+ {
+ bVisible = sfx2::SfxNotebookBar::StateMethod(mpViewShell->GetFrame()->GetBindings(),
+ u"modules/simpress/ui/");
+ }
+ else
+ {
+ bVisible = sfx2::SfxNotebookBar::StateMethod(mpViewShell->GetFrame()->GetBindings(),
+ u"modules/sdraw/ui/");
+ }
+ rSet.Put( SfxBoolItem( SID_NOTEBOOKBAR, bVisible ) );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+
+ SfxViewFrame* pFrame = SfxViewFrame::Current();
+
+ if (pFrame)
+ {
+ if (rSet.GetItemState(SID_RELOAD) != SfxItemState::UNKNOWN)
+ {
+ pFrame->GetSlotState(SID_RELOAD,
+ pFrame->GetInterface(), &rSet);
+ }
+ }
+}
+
+void DrawDocShell::Activate( bool bMDI)
+{
+ if (bMDI)
+ {
+ ApplySlotFilter();
+ mpDoc->StartOnlineSpelling();
+ }
+}
+
+void DrawDocShell::Deactivate( bool )
+{
+}
+
+SfxUndoManager* DrawDocShell::GetUndoManager()
+{
+ return mpUndoManager.get();
+}
+
+void DrawDocShell::UpdateTablePointers()
+{
+ PutItem( SvxColorListItem( mpDoc->GetColorList(), SID_COLOR_TABLE ) );
+ PutItem( SvxGradientListItem( mpDoc->GetGradientList(), SID_GRADIENT_LIST ) );
+ PutItem( SvxHatchListItem( mpDoc->GetHatchList(), SID_HATCH_LIST ) );
+ PutItem( SvxBitmapListItem( mpDoc->GetBitmapList(), SID_BITMAP_LIST ) );
+ PutItem( SvxPatternListItem( mpDoc->GetPatternList(), SID_PATTERN_LIST ) );
+ PutItem( SvxDashListItem( mpDoc->GetDashList(), SID_DASH_LIST ) );
+ PutItem( SvxLineEndListItem( mpDoc->GetLineEndList(), SID_LINEEND_LIST ) );
+
+ UpdateFontList();
+}
+
+void DrawDocShell::CancelSearching()
+{
+ if (mpViewShell)
+ {
+ auto* pView = mpViewShell->GetView();
+ if (pView)
+ {
+ auto & pSearchContext = pView->getSearchContext();
+ pSearchContext.resetSearchFunction();
+ }
+ }
+}
+
+/**
+ * apply configured slot filters
+ */
+void DrawDocShell::ApplySlotFilter() const
+{
+ SfxViewShell* pTestViewShell = SfxViewShell::GetFirst();
+
+ while( pTestViewShell )
+ {
+ if( pTestViewShell->GetObjectShell()
+ == this
+ && pTestViewShell->GetViewFrame()
+ && pTestViewShell->GetViewFrame()->GetDispatcher() )
+ {
+ SfxDispatcher* pDispatcher = pTestViewShell->GetViewFrame()->GetDispatcher();
+
+ if( !mpFilterSIDs.empty() )
+ pDispatcher->SetSlotFilter( mbFilterEnable ? SfxSlotFilterState::ENABLED : SfxSlotFilterState::DISABLED, mpFilterSIDs );
+ else
+ pDispatcher->SetSlotFilter();
+
+ if( pDispatcher->GetBindings() )
+ pDispatcher->GetBindings()->InvalidateAll( true );
+ }
+
+ pTestViewShell = SfxViewShell::GetNext( *pTestViewShell );
+ }
+}
+
+void DrawDocShell::SetModified( bool bSet /* = true */ )
+{
+ SfxObjectShell::SetModified( bSet );
+
+ // change model state, too
+ // only set the changed state if modification is enabled
+ if( IsEnableSetModified() )
+ {
+ if ( mpDoc )
+ mpDoc->NbcSetChanged( bSet );
+
+ Broadcast( SfxHint( SfxHintId::DocChanged ) );
+ }
+}
+
+/**
+ * Callback for ExecuteSpellPopup()
+ */
+// ExecuteSpellPopup now handled by DrawDocShell. This is necessary
+// to get hands on the outliner and the text object.
+IMPL_LINK(DrawDocShell, OnlineSpellCallback, SpellCallbackInfo&, rInfo, void)
+{
+ SdrObject* pObj = nullptr;
+ SdrOutliner* pOutl = nullptr;
+
+ if(GetViewShell())
+ {
+ pOutl = GetViewShell()->GetView()->GetTextEditOutliner();
+ pObj = GetViewShell()->GetView()->GetTextEditObject();
+ }
+
+ mpDoc->ImpOnlineSpellCallback(&rInfo, pObj, pOutl);
+}
+
+void DrawDocShell::ClearUndoBuffer()
+{
+ // clear possible undo buffers of outliners
+ SfxViewFrame* pSfxViewFrame = SfxViewFrame::GetFirst(this, false);
+ while(pSfxViewFrame)
+ {
+ ViewShellBase* pViewShellBase = dynamic_cast< ViewShellBase* >( pSfxViewFrame->GetViewShell() );
+ if( pViewShellBase )
+ {
+ std::shared_ptr<ViewShell> pViewSh( pViewShellBase->GetMainViewShell() );
+ if( pViewSh )
+ {
+ ::sd::View* pView = pViewSh->GetView();
+ if( pView )
+ {
+ pView->SdrEndTextEdit();
+ sd::OutlineView* pOutlView = dynamic_cast< sd::OutlineView* >( pView );
+ if( pOutlView )
+ {
+ pOutlView->GetOutliner().GetUndoManager().Clear();
+ }
+ }
+ }
+ }
+ pSfxViewFrame = SfxViewFrame::GetNext(*pSfxViewFrame, this, false);
+ }
+
+ SfxUndoManager* pUndoManager = GetUndoManager();
+ if(pUndoManager && pUndoManager->GetUndoActionCount())
+ pUndoManager->Clear();
+}
+
+std::vector<Color> DrawDocShell::GetThemeColors()
+{
+ auto pViewShell = dynamic_cast<sd::DrawViewShell*>(GetViewShell());
+ if (!pViewShell)
+ {
+ return {};
+ }
+
+ SdPage* pPage = pViewShell->getCurrentPage();
+ svx::Theme* pTheme = pPage->getSdrPageProperties().GetTheme();
+ if (!pPage->IsMasterPage())
+ {
+ pTheme = pPage->TRG_GetMasterPage().getSdrPageProperties().GetTheme();
+ }
+
+ if (!pTheme)
+ {
+ return {};
+ }
+
+ return pTheme->GetColors();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/docshell/grdocsh.cxx b/sd/source/ui/docshell/grdocsh.cxx
new file mode 100644
index 000000000..f0f5af956
--- /dev/null
+++ b/sd/source/ui/docshell/grdocsh.cxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svxids.hrc>
+#include <tools/globname.hxx>
+
+#include <comphelper/classids.hxx>
+
+#include <sfx2/objface.hxx>
+
+#include <GraphicDocShell.hxx>
+#include <DrawDocShell.hxx>
+
+using namespace sd;
+#define ShellClass_GraphicDocShell
+#include <sdgslots.hxx>
+
+namespace sd
+{
+SFX_IMPL_SUPERCLASS_INTERFACE(GraphicDocShell, SfxObjectShell)
+
+void GraphicDocShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterChildWindow(SID_SEARCH_DLG);
+}
+
+SFX_IMPL_OBJECTFACTORY(GraphicDocShell, SvGlobalName(SO3_SDRAW_CLASSID_60), "sdraw")
+
+GraphicDocShell::GraphicDocShell(SfxObjectCreateMode eMode)
+ : DrawDocShell(eMode, /*bDataObject*/ true, DocumentType::Draw)
+{
+ SetStyleFamily(SfxStyleFamily::Para);
+}
+
+GraphicDocShell::GraphicDocShell(SfxModelFlags nModelCreationFlags)
+ : DrawDocShell(nModelCreationFlags, /*bDataObject*/ false, DocumentType::Draw)
+{
+ SetStyleFamily(SfxStyleFamily::Para);
+}
+
+GraphicDocShell::~GraphicDocShell() {}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/docshell/sdclient.cxx b/sd/source/ui/docshell/sdclient.cxx
new file mode 100644
index 000000000..02521c257
--- /dev/null
+++ b/sd/source/ui/docshell/sdclient.cxx
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <Client.hxx>
+#include <svx/svdoole2.hxx>
+#include <tools/debug.hxx>
+
+#include <ViewShell.hxx>
+#include <View.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+Client::Client(SdrOle2Obj* pObj, ViewShell* pViewShell, vcl::Window* pWindow) :
+ SfxInPlaceClient(pViewShell->GetViewShell(), pWindow, pObj->GetAspect() ),
+ mpViewShell(pViewShell),
+ pSdrOle2Obj(pObj)
+{
+ SetObject( pObj->GetObjRef() );
+ DBG_ASSERT( GetObject().is(), "No object connected!" );
+}
+
+Client::~Client()
+{
+}
+
+/**
+ * If IP active, then we get this request to increase the visible section of the
+ * object.
+ */
+void Client::RequestNewObjectArea( ::tools::Rectangle& aObjRect )
+{
+ ::sd::View* pView = mpViewShell->GetView();
+
+ bool bSizeProtect = false;
+ bool bPosProtect = false;
+
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ // no need to check for changes, this method is called only if the area really changed
+ bSizeProtect = pObj->IsResizeProtect();
+ bPosProtect = pObj->IsMoveProtect();
+ }
+
+ ::tools::Rectangle aOldRect = GetObjArea();
+ if ( bPosProtect )
+ aObjRect.SetPos( aOldRect.TopLeft() );
+
+ if ( bSizeProtect )
+ aObjRect.SetSize( aOldRect.GetSize() );
+
+ ::tools::Rectangle aWorkArea( pView->GetWorkArea() );
+ if ( aWorkArea.Contains(aObjRect) || bPosProtect || aObjRect == aOldRect )
+ return;
+
+ // correct position
+ Point aPos = aObjRect.TopLeft();
+ Size aSize = aObjRect.GetSize();
+ Point aWorkAreaTL = aWorkArea.TopLeft();
+ Point aWorkAreaBR = aWorkArea.BottomRight();
+
+ aPos.setX( std::max(aPos.X(), aWorkAreaTL.X()) );
+ aPos.setX( std::min(aPos.X(), aWorkAreaBR.X()-aSize.Width()) );
+ aPos.setY( std::max(aPos.Y(), aWorkAreaTL.Y()) );
+ aPos.setY( std::min(aPos.Y(), aWorkAreaBR.Y()-aSize.Height()) );
+
+ aObjRect.SetPos(aPos);
+}
+
+void Client::ObjectAreaChanged()
+{
+ ::sd::View* pView = mpViewShell->GetView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() != 1)
+ return;
+
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrOle2Obj* pObj = dynamic_cast< SdrOle2Obj* >(pMark->GetMarkedSdrObj());
+
+ if(!pObj)
+ return;
+
+ // no need to check for changes, this method is called only if the area really changed
+ ::tools::Rectangle aNewRectangle(GetScaledObjArea());
+
+ // #i118524# if sheared/rotated, center to non-rotated LogicRect
+ pObj->setSuppressSetVisAreaSize(true);
+
+ if(pObj->GetGeoStat().nRotationAngle || pObj->GetGeoStat().nShearAngle)
+ {
+ pObj->SetLogicRect( aNewRectangle );
+
+ const ::tools::Rectangle& rBoundRect = pObj->GetCurrentBoundRect();
+ const Point aDelta(aNewRectangle.Center() - rBoundRect.Center());
+
+ aNewRectangle.Move(aDelta.X(), aDelta.Y());
+ }
+
+ pObj->SetLogicRect( aNewRectangle );
+ pObj->setSuppressSetVisAreaSize(false);
+}
+
+void Client::ViewChanged()
+{
+ if ( GetAspect() == embed::Aspects::MSOLE_ICON )
+ {
+ // the iconified object seems not to need such a scaling handling
+ // since the replacement image and the size a completely controlled by the container
+ // TODO/LATER: when the icon exchange is implemented the scaling handling might be required again here
+
+ pSdrOle2Obj->ActionChanged(); // draw needs it to remove lines in slide preview
+ return;
+ }
+
+ //TODO/LATER: should we try to avoid the recalculation of the visareasize
+ //if we know that it didn't change?
+ if (!mpViewShell->GetActiveWindow())
+ return;
+
+ ::sd::View* pView = mpViewShell->GetView();
+ if (!pView)
+ return;
+
+ ::tools::Rectangle aLogicRect( pSdrOle2Obj->GetLogicRect() );
+ Size aLogicSize( aLogicRect.GetWidth(), aLogicRect.GetHeight() );
+
+ if( pSdrOle2Obj->IsChart() )
+ {
+ //charts never should be stretched see #i84323# for example
+ pSdrOle2Obj->SetLogicRect( ::tools::Rectangle( aLogicRect.TopLeft(), aLogicSize ) );
+ pSdrOle2Obj->BroadcastObjectChange();
+ return;
+ }
+
+ // TODO/LEAN: maybe we can do this without requesting the VisualArea?
+ // working with the visual area might need running state, so the object may switch itself to this state
+ MapMode aMap100( MapUnit::Map100thMM );
+ ::tools::Rectangle aVisArea;
+ Size aSize = pSdrOle2Obj->GetOrigObjSize( &aMap100 );
+
+ aVisArea.SetSize( aSize );
+ Size aScaledSize( static_cast< ::tools::Long >( GetScaleWidth() * Fraction( aVisArea.GetWidth() ) ),
+ static_cast< ::tools::Long >( GetScaleHeight() * Fraction( aVisArea.GetHeight() ) ) );
+
+ // react to the change if the difference is bigger than one pixel
+ Size aPixelDiff =
+ Application::GetDefaultDevice()->LogicToPixel(
+ Size( aLogicRect.GetWidth() - aScaledSize.Width(),
+ aLogicRect.GetHeight() - aScaledSize.Height() ),
+ aMap100 );
+ if( aPixelDiff.Width() || aPixelDiff.Height() )
+ {
+ pSdrOle2Obj->SetLogicRect( ::tools::Rectangle( aLogicRect.TopLeft(), aScaledSize ) );
+ pSdrOle2Obj->BroadcastObjectChange();
+ }
+ else
+ pSdrOle2Obj->ActionChanged();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueue.cxx b/sd/source/ui/framework/configuration/ChangeRequestQueue.cxx
new file mode 100644
index 000000000..0168c162b
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ChangeRequestQueue.cxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ChangeRequestQueue.hxx"
+
+namespace sd::framework
+{
+ChangeRequestQueue::ChangeRequestQueue() {}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueue.hxx b/sd/source/ui/framework/configuration/ChangeRequestQueue.hxx
new file mode 100644
index 000000000..e60b5b527
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ChangeRequestQueue.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <queue>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfigurationChangeRequest;
+}
+
+namespace sd::framework
+{
+/** The ChangeRequestQueue stores the pending requests for changes to the
+ requested configuration. It is the task of the
+ ChangeRequestQueueProcessor to process these requests.
+*/
+class ChangeRequestQueue
+ : public ::std::queue<css::uno::Reference<css::drawing::framework::XConfigurationChangeRequest>>
+{
+public:
+ /** Create an empty queue.
+ */
+ ChangeRequestQueue();
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx
new file mode 100644
index 000000000..da633a540
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.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 "debugtrace.hxx"
+#include "ChangeRequestQueueProcessor.hxx"
+#include "ConfigurationTracer.hxx"
+
+#include "ConfigurationUpdater.hxx"
+
+#include <vcl/svapp.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationChangeRequest.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace {
+
+#if DEBUG_SD_CONFIGURATION_TRACE
+
+void TraceRequest (const Reference<XConfigurationChangeRequest>& rxRequest)
+{
+ Reference<container::XNamed> xNamed (rxRequest, UNO_QUERY);
+ if (xNamed.is())
+ SAL_INFO("sd.fwk", __func__ << ": " << xNamed->getName());
+}
+
+#endif
+
+} // end of anonymous namespace
+
+namespace sd::framework {
+
+ChangeRequestQueueProcessor::ChangeRequestQueueProcessor (
+ const std::shared_ptr<ConfigurationUpdater>& rpConfigurationUpdater)
+ : mnUserEventId(nullptr),
+ mpConfigurationUpdater(rpConfigurationUpdater)
+{
+}
+
+ChangeRequestQueueProcessor::~ChangeRequestQueueProcessor()
+{
+ if (mnUserEventId != nullptr)
+ Application::RemoveUserEvent(mnUserEventId);
+}
+
+void ChangeRequestQueueProcessor::SetConfiguration (
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ mxConfiguration = rxConfiguration;
+ StartProcessing();
+}
+
+void ChangeRequestQueueProcessor::AddRequest (
+ const Reference<XConfigurationChangeRequest>& rxRequest)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+#if DEBUG_SD_CONFIGURATION_TRACE
+ if (maQueue.empty())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": Adding requests to empty queue");
+ ConfigurationTracer::TraceConfiguration(
+ mxConfiguration, "current configuration of queue processor");
+ }
+ SAL_INFO("sd.fwk", __func__ << ": Adding request");
+ TraceRequest(rxRequest);
+#endif
+
+ maQueue.push(rxRequest);
+ StartProcessing();
+}
+
+void ChangeRequestQueueProcessor::StartProcessing()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ if (mnUserEventId == nullptr
+ && mxConfiguration.is()
+ && ! maQueue.empty())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": ChangeRequestQueueProcessor scheduling processing");
+ mnUserEventId = Application::PostUserEvent(
+ LINK(this,ChangeRequestQueueProcessor,ProcessEvent));
+ }
+}
+
+IMPL_LINK_NOARG(ChangeRequestQueueProcessor, ProcessEvent, void*, void)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ mnUserEventId = nullptr;
+
+ ProcessOneEvent();
+
+ if ( ! maQueue.empty())
+ {
+ // Schedule the processing of the next event.
+ StartProcessing();
+ }
+}
+
+void ChangeRequestQueueProcessor::ProcessOneEvent()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ SAL_INFO("sd.fwk", __func__ << ": ProcessOneEvent");
+
+ if (!mxConfiguration.is() || maQueue.empty())
+ return;
+
+ // Get and remove the first entry from the queue.
+ Reference<XConfigurationChangeRequest> xRequest (maQueue.front());
+ maQueue.pop();
+
+ // Execute the change request.
+ if (xRequest.is())
+ {
+#if DEBUG_SD_CONFIGURATION_TRACE
+ TraceRequest(xRequest);
+#endif
+ xRequest->execute(mxConfiguration);
+ }
+
+ if (!maQueue.empty())
+ return;
+
+ SAL_INFO("sd.fwk", __func__ << ": All requests are processed");
+ // The queue is empty so tell the ConfigurationManager to update
+ // its state.
+ if (mpConfigurationUpdater != nullptr)
+ {
+#if DEBUG_SD_CONFIGURATION_TRACE
+ ConfigurationTracer::TraceConfiguration (
+ mxConfiguration, "updating to configuration");
+#endif
+ mpConfigurationUpdater->RequestUpdate(mxConfiguration);
+ }
+}
+
+bool ChangeRequestQueueProcessor::IsEmpty() const
+{
+ return maQueue.empty();
+}
+
+void ChangeRequestQueueProcessor::ProcessUntilEmpty()
+{
+ while ( ! IsEmpty())
+ ProcessOneEvent();
+}
+
+void ChangeRequestQueueProcessor::Clear()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ ChangeRequestQueue().swap(maQueue);
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx
new file mode 100644
index 000000000..4afd5af76
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ChangeRequestQueue.hxx"
+#include <osl/mutex.hxx>
+
+#include <tools/link.hxx>
+
+#include <memory>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfiguration;
+}
+namespace com::sun::star::drawing::framework
+{
+class XConfigurationChangeRequest;
+}
+
+struct ImplSVEvent;
+
+namespace sd::framework
+{
+class ConfigurationUpdater;
+
+/** The ChangeRequestQueueProcessor owns the ChangeRequestQueue and
+ processes the configuration change requests.
+
+ When after processing one entry the queue is empty then the
+ XConfigurationController::update() method is called so that the changes
+ made to the local XConfiguration reference are reflected by the UI.
+
+ Queue entries are processed asynchronously by calling PostUserEvent().
+*/
+class ChangeRequestQueueProcessor
+{
+public:
+ /** The queue processor is created with a reference to an
+ ConfigurationController so that its UpdateConfiguration() method can
+ be called when the queue becomes empty.
+ */
+ explicit ChangeRequestQueueProcessor(const std::shared_ptr<ConfigurationUpdater>& rpUpdater);
+ ~ChangeRequestQueueProcessor();
+
+ /** Sets the configuration who will be changed by subsequent change
+ requests. This method should be called only by the configuration
+ controller who owns the configuration.
+ */
+ void SetConfiguration(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+
+ /** The given request is appended to the end of the queue and will
+ eventually be processed when all other entries in front of it have
+ been processed.
+ */
+ void AddRequest(
+ const css::uno::Reference<css::drawing::framework::XConfigurationChangeRequest>& rxRequest);
+
+ /** Returns </sal_True> when the queue is empty.
+ */
+ bool IsEmpty() const;
+
+ /** Process all events in the queue synchronously.
+
+ <p>This method is typically called when the framework is shut down
+ to establish an empty configuration.</p>
+ */
+ void ProcessUntilEmpty();
+
+ /** Process the first event in queue.
+ */
+ void ProcessOneEvent();
+
+ /** Remove all events from the queue.
+
+ <p>This method is typically called when the framework is shut down
+ to avoid the processing of still pending activation requests.</p>
+ */
+ void Clear();
+
+private:
+ mutable ::osl::Mutex maMutex;
+
+ ChangeRequestQueue maQueue;
+
+ /** The id returned by the last PostUserEvent() call. This id is stored
+ so that a pending user event can be removed when the queue processor
+ is destroyed.
+ */
+ ImplSVEvent* mnUserEventId;
+
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxConfiguration;
+
+ std::shared_ptr<ConfigurationUpdater> mpConfigurationUpdater;
+
+ /** Initiate the processing of the entries in the queue. The actual
+ processing starts asynchronously.
+ */
+ void StartProcessing();
+
+ /** Callback function for the PostUserEvent() call.
+ */
+ DECL_LINK(ProcessEvent, void*, void);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/Configuration.cxx b/sd/source/ui/framework/configuration/Configuration.cxx
new file mode 100644
index 000000000..7b813a42b
--- /dev/null
+++ b/sd/source/ui/framework/configuration/Configuration.cxx
@@ -0,0 +1,311 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <framework/Configuration.hxx>
+
+#include <framework/FrameworkHelper.hxx>
+
+#include <com/sun/star/drawing/framework/ConfigurationChangeEvent.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationControllerBroadcaster.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::framework::FrameworkHelper;
+
+namespace {
+/** Use the XResourceId::compareTo() method to implement a compare operator
+ for STL containers.
+*/
+class XResourceIdLess
+{
+public:
+ bool operator () (const Reference<XResourceId>& rId1, const Reference<XResourceId>& rId2) const
+ {
+ return rId1->compareTo(rId2) == -1;
+ }
+};
+
+} // end of anonymous namespace
+
+namespace sd::framework {
+
+class Configuration::ResourceContainer
+ : public ::std::set<Reference<XResourceId>, XResourceIdLess>
+{
+public:
+ ResourceContainer() {}
+};
+
+//===== Configuration =========================================================
+
+Configuration::Configuration (
+ const Reference<XConfigurationControllerBroadcaster>& rxBroadcaster,
+ bool bBroadcastRequestEvents)
+ : mpResourceContainer(new ResourceContainer()),
+ mxBroadcaster(rxBroadcaster),
+ mbBroadcastRequestEvents(bBroadcastRequestEvents)
+{
+}
+
+Configuration::Configuration (
+ const Reference<XConfigurationControllerBroadcaster>& rxBroadcaster,
+ bool bBroadcastRequestEvents,
+ const ResourceContainer& rResourceContainer)
+ : mpResourceContainer(new ResourceContainer(rResourceContainer)),
+ mxBroadcaster(rxBroadcaster),
+ mbBroadcastRequestEvents(bBroadcastRequestEvents)
+{
+}
+
+Configuration::~Configuration()
+{
+}
+
+void Configuration::disposing(std::unique_lock<std::mutex>&)
+{
+ mpResourceContainer->clear();
+ mxBroadcaster = nullptr;
+}
+
+//----- XConfiguration --------------------------------------------------------
+
+void SAL_CALL Configuration::addResource (const Reference<XResourceId>& rxResourceId)
+{
+ ThrowIfDisposed();
+
+ if ( ! rxResourceId.is() || rxResourceId->getResourceURL().isEmpty())
+ throw css::lang::IllegalArgumentException();
+
+ if (mpResourceContainer->insert(rxResourceId).second)
+ {
+ SAL_INFO("sd.fwk", __func__ << ": Configuration::addResource() " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+ PostEvent(rxResourceId, true);
+ }
+}
+
+void SAL_CALL Configuration::removeResource (const Reference<XResourceId>& rxResourceId)
+{
+ ThrowIfDisposed();
+
+ if ( ! rxResourceId.is() || rxResourceId->getResourceURL().isEmpty())
+ throw css::lang::IllegalArgumentException();
+
+ ResourceContainer::iterator iResource (mpResourceContainer->find(rxResourceId));
+ if (iResource != mpResourceContainer->end())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": Configuration::removeResource() " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+ PostEvent(rxResourceId,false);
+ mpResourceContainer->erase(iResource);
+ }
+}
+
+Sequence<Reference<XResourceId> > SAL_CALL Configuration::getResources (
+ const Reference<XResourceId>& rxAnchorId,
+ const OUString& rsResourceURLPrefix,
+ AnchorBindingMode eMode)
+{
+ std::unique_lock aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ const bool bFilterResources (!rsResourceURLPrefix.isEmpty());
+
+ // Collect the matching resources in a vector.
+ ::std::vector<Reference<XResourceId> > aResources;
+ for (const auto& rxResource : *mpResourceContainer)
+ {
+ if ( ! rxResource->isBoundTo(rxAnchorId,eMode))
+ continue;
+
+ if (bFilterResources)
+ {
+ // Apply the given resource prefix as filter.
+
+ // Make sure that the resource is bound directly to the anchor.
+ if (eMode != AnchorBindingMode_DIRECT
+ && ! rxResource->isBoundTo(rxAnchorId, AnchorBindingMode_DIRECT))
+ {
+ continue;
+ }
+
+ // Make sure that the resource URL matches the given prefix.
+ if ( ! rxResource->getResourceURL().match(rsResourceURLPrefix))
+ {
+ continue;
+ }
+ }
+
+ aResources.push_back(rxResource);
+ }
+
+ return comphelper::containerToSequence(aResources);
+}
+
+sal_Bool SAL_CALL Configuration::hasResource (const Reference<XResourceId>& rxResourceId)
+{
+ std::unique_lock aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ return rxResourceId.is()
+ && mpResourceContainer->find(rxResourceId) != mpResourceContainer->end();
+}
+
+//----- XCloneable ------------------------------------------------------------
+
+Reference<util::XCloneable> SAL_CALL Configuration::createClone()
+{
+ std::unique_lock aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ return new Configuration(
+ mxBroadcaster,
+ mbBroadcastRequestEvents,
+ *mpResourceContainer);
+}
+
+//----- XNamed ----------------------------------------------------------------
+
+OUString SAL_CALL Configuration::getName()
+{
+ std::unique_lock aGuard (m_aMutex);
+ OUStringBuffer aString;
+
+ if (m_bDisposed)
+ aString.append("DISPOSED ");
+ aString.append("Configuration[");
+
+ ResourceContainer::const_iterator iResource;
+ for (iResource=mpResourceContainer->begin();
+ iResource!=mpResourceContainer->end();
+ ++iResource)
+ {
+ if (iResource != mpResourceContainer->begin())
+ aString.append(", ");
+ aString.append(FrameworkHelper::ResourceIdToString(*iResource));
+ }
+ aString.append("]");
+
+ return aString.makeStringAndClear();
+}
+
+void SAL_CALL Configuration::setName (const OUString&)
+{
+ // ignored.
+}
+
+OUString Configuration::getImplementationName()
+{
+ return
+ "com.sun.star.comp.Draw.framework.configuration.Configuration";
+}
+
+sal_Bool Configuration::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> Configuration::getSupportedServiceNames()
+{
+ return css::uno::Sequence<OUString>{
+ "com.sun.star.drawing.framework.Configuration"};
+}
+
+void Configuration::PostEvent (
+ const Reference<XResourceId>& rxResourceId,
+ const bool bActivation)
+{
+ OSL_ASSERT(rxResourceId.is());
+
+ if (!mxBroadcaster.is())
+ return;
+
+ ConfigurationChangeEvent aEvent;
+ aEvent.ResourceId = rxResourceId;
+ if (bActivation)
+ if (mbBroadcastRequestEvents)
+ aEvent.Type = FrameworkHelper::msResourceActivationRequestEvent;
+ else
+ aEvent.Type = FrameworkHelper::msResourceActivationEvent;
+ else
+ if (mbBroadcastRequestEvents)
+ aEvent.Type = FrameworkHelper::msResourceDeactivationRequestEvent;
+ else
+ aEvent.Type = FrameworkHelper::msResourceDeactivationEvent;
+ aEvent.Configuration = this;
+
+ mxBroadcaster->notifyEvent(aEvent);
+}
+
+void Configuration::ThrowIfDisposed() const
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("Configuration object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+bool AreConfigurationsEquivalent (
+ const Reference<XConfiguration>& rxConfiguration1,
+ const Reference<XConfiguration>& rxConfiguration2)
+{
+ if (rxConfiguration1.is() != rxConfiguration2.is())
+ return false;
+ if ( ! rxConfiguration1.is() && ! rxConfiguration2.is())
+ return true;
+
+ // Get the lists of resources from the two given configurations.
+ const Sequence<Reference<XResourceId> > aResources1(
+ rxConfiguration1->getResources(
+ nullptr, OUString(), AnchorBindingMode_INDIRECT));
+ const Sequence<Reference<XResourceId> > aResources2(
+ rxConfiguration2->getResources(
+ nullptr, OUString(), AnchorBindingMode_INDIRECT));
+
+ // When the number of resources differ then the configurations can not
+ // be equivalent.
+ // Comparison of the two lists of resource ids relies on their
+ // ordering.
+ return std::equal(aResources1.begin(), aResources1.end(), aResources2.begin(), aResources2.end(),
+ [](const Reference<XResourceId>& a, const Reference<XResourceId>& b) {
+ if (a.is() && b.is())
+ return a->compareTo(b) == 0;
+ return a.is() == b.is();
+ });
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_configuration_Configuration_get_implementation(
+ css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::Configuration(nullptr, false));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationClassifier.cxx b/sd/source/ui/framework/configuration/ConfigurationClassifier.cxx
new file mode 100644
index 000000000..99fc1297d
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationClassifier.cxx
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ConfigurationClassifier.hxx"
+
+#include <framework/FrameworkHelper.hxx>
+#include <com/sun/star/drawing/framework/XConfiguration.hpp>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+ConfigurationClassifier::ConfigurationClassifier (
+ const Reference<XConfiguration>& rxConfiguration1,
+ const Reference<XConfiguration>& rxConfiguration2)
+ : mxConfiguration1(rxConfiguration1),
+ mxConfiguration2(rxConfiguration2)
+{
+}
+
+bool ConfigurationClassifier::Partition()
+{
+ maC1minusC2.clear();
+ maC2minusC1.clear();
+
+ PartitionResources(
+ mxConfiguration1->getResources(nullptr, OUString(), AnchorBindingMode_DIRECT),
+ mxConfiguration2->getResources(nullptr, OUString(), AnchorBindingMode_DIRECT));
+
+ return !maC1minusC2.empty() || !maC2minusC1.empty();
+}
+
+void ConfigurationClassifier::PartitionResources (
+ const css::uno::Sequence<Reference<XResourceId> >& rS1,
+ const css::uno::Sequence<Reference<XResourceId> >& rS2)
+{
+ ResourceIdVector aC1minusC2;
+ ResourceIdVector aC2minusC1;
+ ResourceIdVector aC1andC2;
+
+ // Classify the resources in the configurations that are not bound to
+ // other resources.
+ ClassifyResources(
+ rS1,
+ rS2,
+ aC1minusC2,
+ aC2minusC1,
+ aC1andC2);
+
+ SAL_INFO("sd.fwk", __func__ << ": copying resource ids to C1-C2");
+ CopyResources(aC1minusC2, mxConfiguration1, maC1minusC2);
+ SAL_INFO("sd.fwk", __func__ << ": copying resource ids to C2-C1");
+ CopyResources(aC2minusC1, mxConfiguration2, maC2minusC1);
+
+ // Process the unique resources that belong to both configurations.
+ for (const auto& rxResource : aC1andC2)
+ {
+ PartitionResources(
+ mxConfiguration1->getResources(rxResource, OUString(), AnchorBindingMode_DIRECT),
+ mxConfiguration2->getResources(rxResource, OUString(), AnchorBindingMode_DIRECT));
+ }
+}
+
+void ConfigurationClassifier::ClassifyResources (
+ const css::uno::Sequence<Reference<XResourceId> >& rS1,
+ const css::uno::Sequence<Reference<XResourceId> >& rS2,
+ ResourceIdVector& rS1minusS2,
+ ResourceIdVector& rS2minusS1,
+ ResourceIdVector& rS1andS2)
+{
+ // Find all elements in rS1 and place them in rS1minusS2 or rS1andS2
+ // depending on whether they are in rS2 or not.
+ for (const Reference<XResourceId>& rA1 : rS1)
+ {
+ bool bFound = std::any_of(rS2.begin(), rS2.end(),
+ [&rA1](const Reference<XResourceId>& rA2) {
+ return rA1->getResourceURL() == rA2->getResourceURL(); });
+
+ if (bFound)
+ rS1andS2.push_back(rA1);
+ else
+ rS1minusS2.push_back(rA1);
+ }
+
+ // Find all elements in rS2 that are not in rS1. The elements that are
+ // in both rS1 and rS2 have been handled above and are therefore ignored
+ // here.
+ for (const Reference<XResourceId>& rA2 : rS2)
+ {
+ bool bFound = std::any_of(rS1.begin(), rS1.end(),
+ [&rA2](const Reference<XResourceId>& rA1) {
+ return rA2->getResourceURL() == rA1->getResourceURL(); });
+
+ if ( ! bFound)
+ rS2minusS1.push_back(rA2);
+ }
+}
+
+void ConfigurationClassifier::CopyResources (
+ const ResourceIdVector& rSource,
+ const Reference<XConfiguration>& rxConfiguration,
+ ResourceIdVector& rTarget)
+{
+ // Copy all resources bound to the ones in aC1minusC2Unique to rC1minusC2.
+ for (const auto& rxResource : rSource)
+ {
+ const Sequence<Reference<XResourceId> > aBoundResources (
+ rxConfiguration->getResources(
+ rxResource,
+ OUString(),
+ AnchorBindingMode_INDIRECT));
+ const sal_Int32 nL (aBoundResources.getLength());
+
+ rTarget.reserve(rTarget.size() + 1 + nL);
+ rTarget.push_back(rxResource);
+
+ SAL_INFO("sd.fwk", __func__ << ": copying " <<
+ FrameworkHelper::ResourceIdToString(rxResource));
+
+ for (const Reference<XResourceId>& rBoundResource : aBoundResources)
+ {
+ rTarget.push_back(rBoundResource);
+ SAL_INFO("sd.fwk", __func__ << ": copying " <<
+ FrameworkHelper::ResourceIdToString(rBoundResource));
+ }
+ }
+}
+
+#if DEBUG_SD_CONFIGURATION_TRACE
+
+void ConfigurationClassifier::TraceResourceIdVector (
+ const char* pMessage,
+ const ResourceIdVector& rResources)
+{
+
+ SAL_INFO("sd.fwk", __func__ << ": " << pMessage);
+ for (const auto& rxResource : rResources)
+ {
+ OUString sResource (FrameworkHelper::ResourceIdToString(rxResource));
+ SAL_INFO("sd.fwk", __func__ << ": " << sResource);
+ }
+}
+
+#endif
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationClassifier.hxx b/sd/source/ui/framework/configuration/ConfigurationClassifier.hxx
new file mode 100644
index 000000000..e9384713b
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationClassifier.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "debugtrace.hxx"
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <vector>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfiguration;
+}
+namespace com::sun::star::drawing::framework
+{
+class XResourceId;
+}
+
+namespace sd::framework
+{
+/** A ConfigurationClassifier object compares two configurations of
+ resources and gives access to the differences. It is used mainly when
+ changes to the current configuration have been requested and the various
+ resource controllers have to be supplied with the set of resources that
+ are to be activated or deactivated.
+*/
+class ConfigurationClassifier
+{
+public:
+ /** Create a new ConfigurationClassifier object that will compare the
+ two given configurations.
+ */
+ ConfigurationClassifier(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration1,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration2);
+
+ /** Calculate three lists of resource ids. These contain the resources
+ that belong to one configuration but not the other, or that belong
+ to both configurations.
+ @return
+ When the two configurations differ then return <TRUE/>. When
+ they are equivalent then return <FALSE/>.
+ */
+ bool Partition();
+
+ typedef ::std::vector<css::uno::Reference<css::drawing::framework::XResourceId>>
+ ResourceIdVector;
+
+ /** Return the resources that belong to the configuration given as
+ rxConfiguration1 to the constructor but that do not belong to
+ rxConfiguration2.
+ @return
+ A reference to the, possibly empty, list of resources is
+ returned. This reference remains valid as long as the called
+ ConfigurationClassifier object stays alive.
+ */
+ const ResourceIdVector& GetC1minusC2() const { return maC1minusC2; }
+
+ /** Return the resources that belong to the configuration given as
+ rxConfiguration2 to the constructor but that do not belong to
+ rxConfiguration1.
+ @return
+ A reference to the, possibly empty, list of resources is
+ returned. This reference remains valid as long as the called
+ ConfigurationClassifier object stays alive.
+ */
+ const ResourceIdVector& GetC2minusC1() const { return maC2minusC1; }
+
+#if DEBUG_SD_CONFIGURATION_TRACE
+
+ /** Return the resources that belong to both the configurations that
+ where given to the constructor.
+ @return
+ A reference to the, possibly empty, list of resources is
+ returned. This reference remains valid as long as the called
+ ConfigurationClassifier object stays alive.
+ */
+ const ResourceIdVector& GetC1andC2() const { return maC1andC2; }
+
+ static void TraceResourceIdVector(const char* pMessage, const ResourceIdVector& rResources);
+
+#endif
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxConfiguration1;
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxConfiguration2;
+
+ /** After the call to Classify() this vector holds all elements from
+ mxConfiguration1 that are not in mxConfiguration2.
+ */
+ ResourceIdVector maC1minusC2;
+
+ /** After the call to Classify() this vector holds all elements from
+ mxConfiguration2 that are not in mxConfiguration1.
+ */
+ ResourceIdVector maC2minusC1;
+
+ /** Put all the elements in the two given sequences of resource ids and
+ copy them into one of the resource id result vectors maC1minusC2,
+ maC2minusC1, and maC1andC2. This is done by using only the resource
+ URLs for classification. Therefore this method calls itself
+ recursively.
+ @param rS1
+ One sequence of XResourceId objects.
+ @param rS2
+ Another sequence of XResourceId objects.
+ */
+ void PartitionResources(
+ const css::uno::Sequence<css::uno::Reference<css::drawing::framework::XResourceId>>& rS1,
+ const css::uno::Sequence<css::uno::Reference<css::drawing::framework::XResourceId>>& rS2);
+
+ /** Compare the given sequences of resource ids and put their elements
+ in one of three vectors depending on whether an element belongs to
+ both sequences or to one but not the other. Note that only the
+ resource URLs of the XResourceId objects are used for the
+ classification.
+ @param rS1
+ One sequence of XResourceId objects.
+ @param rS2
+ Another sequence of XResourceId objects.
+ */
+ static void ClassifyResources(
+ const css::uno::Sequence<css::uno::Reference<css::drawing::framework::XResourceId>>& rS1,
+ const css::uno::Sequence<css::uno::Reference<css::drawing::framework::XResourceId>>& rS2,
+ ResourceIdVector& rS1minusS2, ResourceIdVector& rS2minusS1, ResourceIdVector& rS1andS2);
+
+ /** Copy the resources given in rSource to the list of resources
+ specified by rTarget. Resources bound to the ones in rSource,
+ either directly or indirectly, are copied as well.
+ @param rSource
+ All resources and the ones bound to them, either directly or
+ indirectly, are copied.
+ @param rxConfiguration
+ This configuration is used to determine the resources bound to
+ the ones in rSource.
+ @param rTarget
+ This list is filled with resources from rSource and the ones
+ bound to them.
+ */
+ static void CopyResources(
+ const ResourceIdVector& rSource,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration,
+ ResourceIdVector& rTarget);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationController.cxx b/sd/source/ui/framework/configuration/ConfigurationController.cxx
new file mode 100644
index 000000000..3fc95adb9
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationController.cxx
@@ -0,0 +1,541 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <framework/ConfigurationController.hxx>
+#include <framework/Configuration.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include "ConfigurationUpdater.hxx"
+#include "ConfigurationControllerBroadcaster.hxx"
+#include "ConfigurationTracer.hxx"
+#include "GenericConfigurationChangeRequest.hxx"
+#include "ConfigurationControllerResourceManager.hxx"
+#include "ResourceFactoryManager.hxx"
+#include "UpdateRequest.hxx"
+#include "ChangeRequestQueueProcessor.hxx"
+#include "ConfigurationClassifier.hxx"
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/frame/XController.hpp>
+
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+#include <vcl/svapp.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::framework::FrameworkHelper;
+
+namespace sd::framework {
+
+//----- ConfigurationController::Implementation -------------------------------
+
+class ConfigurationController::Implementation
+{
+public:
+ Implementation (
+ ConfigurationController& rController,
+ const Reference<frame::XController>& rxController);
+
+ Reference<XControllerManager> mxControllerManager;
+
+ /** The Broadcaster class implements storing and calling of listeners.
+ */
+ std::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster;
+
+ /** The requested configuration which is modified (asynchronously) by
+ calls to requestResourceActivation() and
+ requestResourceDeactivation(). The mpConfigurationUpdater makes the
+ current configuration reflect the content of this one.
+ */
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxRequestedConfiguration;
+
+ std::shared_ptr<ResourceFactoryManager> mpResourceFactoryContainer;
+
+ std::shared_ptr<ConfigurationControllerResourceManager> mpResourceManager;
+
+ std::shared_ptr<ConfigurationUpdater> mpConfigurationUpdater;
+
+ /** The queue processor owns the queue of configuration change request
+ objects and processes the objects.
+ */
+ std::unique_ptr<ChangeRequestQueueProcessor> mpQueueProcessor;
+
+ std::shared_ptr<ConfigurationUpdaterLock> mpConfigurationUpdaterLock;
+
+ sal_Int32 mnLockCount;
+};
+
+//===== ConfigurationController::Lock =========================================
+
+ConfigurationController::Lock::Lock (const Reference<XConfigurationController>& rxController)
+ : mxController(rxController)
+{
+ OSL_ASSERT(mxController.is());
+
+ if (mxController.is())
+ mxController->lock();
+}
+
+ConfigurationController::Lock::~Lock()
+{
+ if (mxController.is())
+ mxController->unlock();
+}
+
+//===== ConfigurationController ===============================================
+
+ConfigurationController::ConfigurationController() noexcept
+ : ConfigurationControllerInterfaceBase(m_aMutex)
+ , mbIsDisposed(false)
+{
+}
+
+ConfigurationController::~ConfigurationController() noexcept
+{
+}
+
+void SAL_CALL ConfigurationController::disposing()
+{
+ if (mpImplementation == nullptr)
+ return;
+
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::disposing");
+ SAL_INFO("sd.fwk", __func__ << ": requesting empty configuration");
+ // To destroy all resources an empty configuration is requested and then,
+ // synchronously, all resulting requests are processed.
+ mpImplementation->mpQueueProcessor->Clear();
+ restoreConfiguration(new Configuration(this,false));
+ mpImplementation->mpQueueProcessor->ProcessUntilEmpty();
+ SAL_INFO("sd.fwk", __func__ << ": all requests processed");
+
+ // Now that all resources have been deactivated, mark the controller as
+ // disposed.
+ mbIsDisposed = true;
+
+ // Release the listeners.
+ lang::EventObject aEvent;
+ aEvent.Source = uno::Reference<uno::XInterface>(static_cast<cppu::OWeakObject*>(this));
+
+ {
+ const SolarMutexGuard aSolarGuard;
+ mpImplementation->mpBroadcaster->DisposeAndClear();
+ }
+
+ mpImplementation->mpQueueProcessor.reset();
+ mpImplementation->mxRequestedConfiguration = nullptr;
+ mpImplementation.reset();
+}
+
+void ConfigurationController::ProcessEvent()
+{
+ if (mpImplementation != nullptr)
+ {
+ OSL_ASSERT(mpImplementation->mpQueueProcessor != nullptr);
+
+ mpImplementation->mpQueueProcessor->ProcessOneEvent();
+ }
+}
+
+void ConfigurationController::RequestSynchronousUpdate()
+{
+ if (mpImplementation == nullptr)
+ return;
+ if (mpImplementation->mpQueueProcessor == nullptr)
+ return;
+ mpImplementation->mpQueueProcessor->ProcessUntilEmpty();
+}
+
+//----- XConfigurationControllerBroadcaster -----------------------------------
+
+void SAL_CALL ConfigurationController::addConfigurationChangeListener (
+ const Reference<XConfigurationChangeListener>& rxListener,
+ const OUString& rsEventType,
+ const Any& rUserData)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ ThrowIfDisposed();
+ OSL_ASSERT(mpImplementation != nullptr);
+ mpImplementation->mpBroadcaster->AddListener(rxListener, rsEventType, rUserData);
+}
+
+void SAL_CALL ConfigurationController::removeConfigurationChangeListener (
+ const Reference<XConfigurationChangeListener>& rxListener)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ ThrowIfDisposed();
+ mpImplementation->mpBroadcaster->RemoveListener(rxListener);
+}
+
+void SAL_CALL ConfigurationController::notifyEvent (
+ const ConfigurationChangeEvent& rEvent)
+{
+ ThrowIfDisposed();
+ mpImplementation->mpBroadcaster->NotifyListeners(rEvent);
+}
+
+//----- XConfigurationController ----------------------------------------------
+
+void SAL_CALL ConfigurationController::lock()
+{
+ OSL_ASSERT(mpImplementation != nullptr);
+ OSL_ASSERT(mpImplementation->mpConfigurationUpdater != nullptr);
+
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ ++mpImplementation->mnLockCount;
+ if (mpImplementation->mpConfigurationUpdaterLock == nullptr)
+ mpImplementation->mpConfigurationUpdaterLock
+ = mpImplementation->mpConfigurationUpdater->GetLock();
+}
+
+void SAL_CALL ConfigurationController::unlock()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ // Allow unlocking while the ConfigurationController is being disposed
+ // (but not when that is done and the controller is disposed.)
+ if (rBHelper.bDisposed)
+ ThrowIfDisposed();
+
+ OSL_ASSERT(mpImplementation->mnLockCount>0);
+ --mpImplementation->mnLockCount;
+ if (mpImplementation->mnLockCount == 0)
+ mpImplementation->mpConfigurationUpdaterLock.reset();
+}
+
+void SAL_CALL ConfigurationController::requestResourceActivation (
+ const Reference<XResourceId>& rxResourceId,
+ ResourceActivationMode eMode)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ // Check whether we are being disposed. This is handled differently
+ // then being completely disposed because the first thing disposing()
+ // does is to deactivate all remaining resources. This is done via
+ // regular methods which must not throw DisposedExceptions. Therefore
+ // we just return silently during that stage.
+ if (rBHelper.bInDispose)
+ {
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::requestResourceActivation(): ignoring " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+ return;
+ }
+
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::requestResourceActivation() " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+
+ if (!rxResourceId.is())
+ return;
+
+ if (eMode == ResourceActivationMode_REPLACE)
+ {
+ // Get a list of the matching resources and create deactivation
+ // requests for them.
+ const Sequence<Reference<XResourceId> > aResourceList (
+ mpImplementation->mxRequestedConfiguration->getResources(
+ rxResourceId->getAnchor(),
+ rxResourceId->getResourceTypePrefix(),
+ AnchorBindingMode_DIRECT));
+
+ for (const auto& rResource : aResourceList)
+ {
+ // Do not request the deactivation of the resource for which
+ // this method was called. Doing it would not change the
+ // outcome but would result in unnecessary work.
+ if (rxResourceId->compareTo(rResource) == 0)
+ continue;
+
+ // Request the deactivation of a resource and all resources
+ // linked to it.
+ requestResourceDeactivation(rResource);
+ }
+ }
+
+ Reference<XConfigurationChangeRequest> xRequest(
+ new GenericConfigurationChangeRequest(
+ rxResourceId,
+ GenericConfigurationChangeRequest::Activation));
+ postChangeRequest(xRequest);
+}
+
+void SAL_CALL ConfigurationController::requestResourceDeactivation (
+ const Reference<XResourceId>& rxResourceId)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::requestResourceDeactivation() " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+
+ if (!rxResourceId.is())
+ return;
+
+ // Request deactivation of all resources linked to the specified one
+ // as well.
+ const Sequence<Reference<XResourceId> > aLinkedResources (
+ mpImplementation->mxRequestedConfiguration->getResources(
+ rxResourceId,
+ OUString(),
+ AnchorBindingMode_DIRECT));
+ for (const auto& rLinkedResource : aLinkedResources)
+ {
+ // We do not add deactivation requests directly but call this
+ // method recursively, so that when one time there are resources
+ // linked to linked resources, these are handled correctly, too.
+ requestResourceDeactivation(rLinkedResource);
+ }
+
+ // Add a deactivation request for the specified resource.
+ Reference<XConfigurationChangeRequest> xRequest(
+ new GenericConfigurationChangeRequest(
+ rxResourceId,
+ GenericConfigurationChangeRequest::Deactivation));
+ postChangeRequest(xRequest);
+}
+
+Reference<XResource> SAL_CALL ConfigurationController::getResource (
+ const Reference<XResourceId>& rxResourceId)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ ConfigurationControllerResourceManager::ResourceDescriptor aDescriptor (
+ mpImplementation->mpResourceManager->GetResource(rxResourceId));
+ return aDescriptor.mxResource;
+}
+
+void SAL_CALL ConfigurationController::update()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ if (mpImplementation->mpQueueProcessor->IsEmpty())
+ {
+ // The queue is empty. Add another request that does nothing but
+ // asynchronously trigger a request for an update.
+ mpImplementation->mpQueueProcessor->AddRequest(new UpdateRequest());
+ }
+ else
+ {
+ // The queue is not empty, so we rely on the queue processor to
+ // request an update automatically when the queue becomes empty.
+ }
+}
+
+sal_Bool SAL_CALL ConfigurationController::hasPendingRequests()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ return ! mpImplementation->mpQueueProcessor->IsEmpty();
+}
+
+void SAL_CALL ConfigurationController::postChangeRequest (
+ const Reference<XConfigurationChangeRequest>& rxRequest)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ mpImplementation->mpQueueProcessor->AddRequest(rxRequest);
+}
+
+Reference<XConfiguration> SAL_CALL ConfigurationController::getRequestedConfiguration()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ if (mpImplementation->mxRequestedConfiguration.is())
+ return Reference<XConfiguration>(
+ mpImplementation->mxRequestedConfiguration->createClone(), UNO_QUERY);
+ else
+ return Reference<XConfiguration>();
+}
+
+Reference<XConfiguration> SAL_CALL ConfigurationController::getCurrentConfiguration()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ Reference<XConfiguration> xCurrentConfiguration(
+ mpImplementation->mpConfigurationUpdater->GetCurrentConfiguration());
+ if (xCurrentConfiguration.is())
+ return Reference<XConfiguration>(xCurrentConfiguration->createClone(), UNO_QUERY);
+ else
+ return Reference<XConfiguration>();
+}
+
+/** The given configuration is restored by generating the appropriate set of
+ activation and deactivation requests.
+*/
+void SAL_CALL ConfigurationController::restoreConfiguration (
+ const Reference<XConfiguration>& rxNewConfiguration)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ // We will probably be making a couple of activation and deactivation
+ // requests so lock the configuration controller and let it later update
+ // all changes at once.
+ std::shared_ptr<ConfigurationUpdaterLock> pLock (
+ mpImplementation->mpConfigurationUpdater->GetLock());
+
+ // Get lists of resources that are to be activated or deactivated.
+ Reference<XConfiguration> xCurrentConfiguration (mpImplementation->mxRequestedConfiguration);
+#if OSL_DEBUG_LEVEL >=1
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::restoreConfiguration(");
+ ConfigurationTracer::TraceConfiguration(rxNewConfiguration, "requested configuration");
+ ConfigurationTracer::TraceConfiguration(xCurrentConfiguration, "current configuration");
+#endif
+ ConfigurationClassifier aClassifier (rxNewConfiguration, xCurrentConfiguration);
+ aClassifier.Partition();
+#if DEBUG_SD_CONFIGURATION_TRACE
+ aClassifier.TraceResourceIdVector(
+ "requested but not current resources:\n", aClassifier.GetC1minusC2());
+ aClassifier.TraceResourceIdVector(
+ "current but not requested resources:\n", aClassifier.GetC2minusC1());
+ aClassifier.TraceResourceIdVector(
+ "requested and current resources:\n", aClassifier.GetC1andC2());
+#endif
+
+ // Request the deactivation of resources that are not requested in the
+ // new configuration.
+ const ConfigurationClassifier::ResourceIdVector& rResourcesToDeactivate (
+ aClassifier.GetC2minusC1());
+ for (const auto& rxResource : rResourcesToDeactivate)
+ {
+ requestResourceDeactivation(rxResource);
+ }
+
+ // Request the activation of resources that are requested in the
+ // new configuration but are not part of the current configuration.
+ const ConfigurationClassifier::ResourceIdVector& rResourcesToActivate (
+ aClassifier.GetC1minusC2());
+ for (const auto& rxResource : rResourcesToActivate)
+ {
+ requestResourceActivation(rxResource, ResourceActivationMode_ADD);
+ }
+
+ pLock.reset();
+}
+
+//----- XResourceFactoryManager -----------------------------------------------
+
+void SAL_CALL ConfigurationController::addResourceFactory(
+ const OUString& sResourceURL,
+ const Reference<XResourceFactory>& rxResourceFactory)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+ mpImplementation->mpResourceFactoryContainer->AddFactory(sResourceURL, rxResourceFactory);
+}
+
+void SAL_CALL ConfigurationController::removeResourceFactoryForURL(
+ const OUString& sResourceURL)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+ mpImplementation->mpResourceFactoryContainer->RemoveFactoryForURL(sResourceURL);
+}
+
+void SAL_CALL ConfigurationController::removeResourceFactoryForReference(
+ const Reference<XResourceFactory>& rxResourceFactory)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+ mpImplementation->mpResourceFactoryContainer->RemoveFactoryForReference(rxResourceFactory);
+}
+
+Reference<XResourceFactory> SAL_CALL ConfigurationController::getResourceFactory (
+ const OUString& sResourceURL)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ return mpImplementation->mpResourceFactoryContainer->GetFactory(sResourceURL);
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL ConfigurationController::initialize (const Sequence<Any>& aArguments)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ if (aArguments.getLength() == 1)
+ {
+ const SolarMutexGuard aSolarGuard;
+
+ mpImplementation.reset(new Implementation(
+ *this,
+ Reference<frame::XController>(aArguments[0], UNO_QUERY_THROW)));
+ }
+}
+
+void ConfigurationController::ThrowIfDisposed () const
+{
+ if (mbIsDisposed)
+ {
+ throw lang::DisposedException ("ConfigurationController object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+
+ if (mpImplementation == nullptr)
+ {
+ OSL_ASSERT(mpImplementation != nullptr);
+ throw RuntimeException("ConfigurationController not initialized",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+//===== ConfigurationController::Implementation ===============================
+
+ConfigurationController::Implementation::Implementation (
+ ConfigurationController& rController,
+ const Reference<frame::XController>& rxController)
+ : mxControllerManager(rxController, UNO_QUERY_THROW),
+ mpBroadcaster(std::make_shared<ConfigurationControllerBroadcaster>(&rController)),
+ mxRequestedConfiguration(new Configuration(&rController, true)),
+ mpResourceFactoryContainer(std::make_shared<ResourceFactoryManager>(mxControllerManager)),
+ mpResourceManager(
+ std::make_shared<ConfigurationControllerResourceManager>(mpResourceFactoryContainer,mpBroadcaster)),
+ mpConfigurationUpdater(
+ std::make_shared<ConfigurationUpdater>(mpBroadcaster, mpResourceManager,mxControllerManager)),
+ mpQueueProcessor(new ChangeRequestQueueProcessor(mpConfigurationUpdater)),
+ mnLockCount(0)
+{
+ mpQueueProcessor->SetConfiguration(mxRequestedConfiguration);
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_configuration_ConfigurationController_get_implementation(
+ css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::ConfigurationController());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx
new file mode 100644
index 000000000..5d9f22255
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ConfigurationControllerBroadcaster.hxx"
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <com/sun/star/drawing/framework/XResource.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+ConfigurationControllerBroadcaster::ConfigurationControllerBroadcaster (
+ const Reference<XConfigurationController>& rxController)
+ : mxConfigurationController(rxController)
+{
+}
+
+void ConfigurationControllerBroadcaster::AddListener(
+ const Reference<XConfigurationChangeListener>& rxListener,
+ const OUString& rsEventType,
+ const Any& rUserData)
+{
+ if ( ! rxListener.is())
+ throw lang::IllegalArgumentException("invalid listener",
+ mxConfigurationController,
+ 0);
+
+ maListenerMap.try_emplace(rsEventType);
+
+ ListenerDescriptor aDescriptor;
+ aDescriptor.mxListener = rxListener;
+ aDescriptor.maUserData = rUserData;
+ maListenerMap[rsEventType].push_back(aDescriptor);
+}
+
+void ConfigurationControllerBroadcaster::RemoveListener(
+ const Reference<XConfigurationChangeListener>& rxListener)
+{
+ if ( ! rxListener.is())
+ throw lang::IllegalArgumentException("invalid listener",
+ mxConfigurationController,
+ 0);
+
+ ListenerList::iterator iList;
+ for (auto& rMap : maListenerMap)
+ {
+ iList = std::find_if(rMap.second.begin(), rMap.second.end(),
+ [&rxListener](const ListenerDescriptor& rList) { return rList.mxListener == rxListener; });
+ if (iList != rMap.second.end())
+ rMap.second.erase(iList);
+ }
+}
+
+void ConfigurationControllerBroadcaster::NotifyListeners (
+ const ListenerList& rList,
+ const ConfigurationChangeEvent& rEvent)
+{
+ // Create a local copy of the event in which the user data is modified
+ // for every listener.
+ ConfigurationChangeEvent aEvent (rEvent);
+
+ for (const auto& rListener : rList)
+ {
+ try
+ {
+ aEvent.UserData = rListener.maUserData;
+ rListener.mxListener->notifyConfigurationChange(aEvent);
+ }
+ catch (const lang::DisposedException& rException)
+ {
+ // When the exception comes from the listener itself then
+ // unregister it.
+ if (rException.Context == rListener.mxListener)
+ RemoveListener(rListener.mxListener);
+ }
+ catch (const RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ }
+}
+
+void ConfigurationControllerBroadcaster::NotifyListeners (const ConfigurationChangeEvent& rEvent)
+{
+ // Notify the specialized listeners.
+ ListenerMap::const_iterator iMap (maListenerMap.find(rEvent.Type));
+ if (iMap != maListenerMap.end())
+ {
+ // Create a local list of the listeners to avoid problems with
+ // concurrent changes and to be able to remove disposed listeners.
+ ListenerList aList (iMap->second.begin(), iMap->second.end());
+ NotifyListeners(aList,rEvent);
+ }
+
+ // Notify the universal listeners.
+ iMap = maListenerMap.find(OUString());
+ if (iMap != maListenerMap.end())
+ {
+ // Create a local list of the listeners to avoid problems with
+ // concurrent changes and to be able to remove disposed listeners.
+ ListenerList aList (iMap->second.begin(), iMap->second.end());
+ NotifyListeners(aList,rEvent);
+ }
+}
+
+void ConfigurationControllerBroadcaster::NotifyListeners (
+ const OUString& rsEventType,
+ const Reference<XResourceId>& rxResourceId,
+ const Reference<XResource>& rxResourceObject)
+{
+ ConfigurationChangeEvent aEvent;
+ aEvent.Type = rsEventType;
+ aEvent.ResourceId = rxResourceId;
+ aEvent.ResourceObject = rxResourceObject;
+ try
+ {
+ NotifyListeners(aEvent);
+ }
+ catch (const lang::DisposedException&)
+ {
+ }
+}
+
+void ConfigurationControllerBroadcaster::DisposeAndClear()
+{
+ lang::EventObject aEvent;
+ aEvent.Source = mxConfigurationController;
+ while (!maListenerMap.empty())
+ {
+ ListenerMap::iterator iMap (maListenerMap.begin());
+ if (iMap == maListenerMap.end())
+ break;
+
+ // When the first vector is empty then remove it from the map.
+ if (iMap->second.empty())
+ {
+ maListenerMap.erase(iMap);
+ continue;
+ }
+ else
+ {
+ Reference<XConfigurationChangeListener> xListener (
+ iMap->second.front().mxListener );
+ if (xListener.is())
+ {
+ // Tell the listener that the configuration controller is
+ // being disposed and remove the listener (for all event
+ // types).
+ try
+ {
+ RemoveListener(xListener);
+ xListener->disposing(aEvent);
+ }
+ catch (const RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ }
+ else
+ {
+ // Remove just this reference to the listener.
+ iMap->second.erase(iMap->second.begin());
+ }
+ }
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx
new file mode 100644
index 000000000..5dfd6843d
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <unordered_map>
+#include <vector>
+
+namespace com::sun::star::drawing::framework { class XConfigurationChangeListener; }
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XResource; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+namespace com::sun::star::drawing::framework { struct ConfigurationChangeEvent; }
+
+namespace sd::framework {
+
+/** This class manages the set of XConfigurationChangeListeners and
+ calls them when the ConfigurationController wants to broadcast an
+ event.
+
+ For every registered combination of listener and event type a user data
+ object is stored. This user data object is then given to the listener
+ whenever it is called for an event. With this the listener can use
+ a switch statement to handle different event types.
+*/
+class ConfigurationControllerBroadcaster
+{
+public:
+ /** The given controller is used as origin of thrown exceptions.
+ */
+ explicit ConfigurationControllerBroadcaster (
+ const css::uno::Reference<
+ css::drawing::framework::XConfigurationController>& rxController);
+
+ /** Add a listener for one type of event. When one listener is
+ interested in more than one event type this method has to be called
+ once for every event type. Alternatively it can register as
+ universal listener that will be called for all event types.
+ @param rxListener
+ A valid reference to a listener.
+ @param rsEventType
+ The type of event that the listener will be called for. The
+ empty string is a special value in that the listener will be
+ called for all event types.
+ @param rUserData
+ This object is passed to the listener whenever it is called for
+ the specified event type. For different event types different
+ user data objects can be provided.
+ @throws IllegalArgumentException
+ when an empty listener reference is given.
+ */
+ void AddListener(
+ const css::uno::Reference<
+ css::drawing::framework::XConfigurationChangeListener>& rxListener,
+ const OUString& rsEventType,
+ const css::uno::Any& rUserData);
+
+ /** Remove all references to the given listener. When one listener has
+ been registered for more than one type of event then it is removed
+ for all of them.
+ @param rxListener
+ A valid reference to a listener.
+ @throws IllegalArgumentException
+ when an empty listener reference is given.
+ */
+ void RemoveListener(
+ const css::uno::Reference<
+ css::drawing::framework::XConfigurationChangeListener>& rxListener);
+
+ /** Broadcast the given event to all listeners that have been registered
+ for its type of event as well as all universal listeners.
+
+ When calling a listener results in a DisposedException being thrown
+ the listener is unregistered automatically.
+ */
+ void NotifyListeners (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent);
+
+ /** This convenience variant of NotifyListeners create the event from
+ the given arguments.
+ */
+ void NotifyListeners (
+ const OUString& rsEventType,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const css::uno::Reference<css::drawing::framework::XResource>& rxResourceObject);
+
+ /** Call all listeners and inform them that the
+ ConfigurationController is being disposed. When this method returns
+ the list of registered listeners is empty. Further calls to
+ RemoveListener() are not necessary but do not result in an error.
+ */
+ void DisposeAndClear();
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfigurationController> mxConfigurationController;
+ class ListenerDescriptor
+ {
+ public:
+ css::uno::Reference<css::drawing::framework::XConfigurationChangeListener> mxListener;
+ css::uno::Any maUserData;
+ };
+ typedef std::vector<ListenerDescriptor> ListenerList;
+ typedef std::unordered_map
+ <OUString,
+ ListenerList> ListenerMap;
+ ListenerMap maListenerMap;
+
+ /** Broadcast the given event to all listeners in the given list.
+
+ When calling a listener results in a DisposedException being thrown
+ the listener is unregistered automatically.
+ */
+ void NotifyListeners (
+ const ListenerList& rList,
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx
new file mode 100644
index 000000000..904011d7d
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx
@@ -0,0 +1,303 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ConfigurationControllerResourceManager.hxx"
+#include "ConfigurationControllerBroadcaster.hxx"
+#include "ResourceFactoryManager.hxx"
+#include <framework/FrameworkHelper.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/drawing/framework/XConfiguration.hpp>
+#include <com/sun/star/drawing/framework/XResourceFactory.hpp>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <algorithm>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+//===== ConfigurationControllerResourceManager ================================
+
+ConfigurationControllerResourceManager::ConfigurationControllerResourceManager (
+ const std::shared_ptr<ResourceFactoryManager>& rpResourceFactoryContainer,
+ const std::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster)
+ : maResourceMap(ResourceComparator()),
+ mpResourceFactoryContainer(rpResourceFactoryContainer),
+ mpBroadcaster(rpBroadcaster)
+{
+}
+
+ConfigurationControllerResourceManager::~ConfigurationControllerResourceManager()
+{
+}
+
+ConfigurationControllerResourceManager::ResourceDescriptor
+ ConfigurationControllerResourceManager::GetResource (
+ const Reference<XResourceId>& rxResourceId)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ ResourceMap::const_iterator iResource (maResourceMap.find(rxResourceId));
+ if (iResource != maResourceMap.end())
+ return iResource->second;
+ else
+ return ResourceDescriptor();
+}
+
+void ConfigurationControllerResourceManager::ActivateResources (
+ const ::std::vector<Reference<XResourceId> >& rResources,
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ // Iterate in normal order over the resources that are to be
+ // activated so that resources on which others depend are activated
+ // before the depending resources are activated.
+ for (const Reference<XResourceId>& xResource : rResources)
+ ActivateResource(xResource, rxConfiguration);
+}
+
+void ConfigurationControllerResourceManager::DeactivateResources (
+ const ::std::vector<Reference<XResourceId> >& rResources,
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ // Iterate in reverse order over the resources that are to be
+ // deactivated so that resources on which others depend are deactivated
+ // only when the depending resources have already been deactivated.
+ ::std::for_each(
+ rResources.rbegin(),
+ rResources.rend(),
+ [&] (Reference<XResourceId> const& xResource) {
+ return DeactivateResource(xResource, rxConfiguration);
+ } );
+}
+
+/* In this method we do following steps.
+ 1. Get the factory with which the resource will be created.
+ 2. Create the resource.
+ 3. Add the resource to the URL->Object map of the configuration
+ controller.
+ 4. Add the resource id to the current configuration.
+ 5. Notify listeners.
+*/
+void ConfigurationControllerResourceManager::ActivateResource (
+ const Reference<XResourceId>& rxResourceId,
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ if ( ! rxResourceId.is())
+ {
+ OSL_ASSERT(rxResourceId.is());
+ return;
+ }
+
+ SAL_INFO("sd.fwk", __func__ << ": activating resource " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+
+ // 1. Get the factory.
+ const OUString sResourceURL (rxResourceId->getResourceURL());
+ Reference<XResourceFactory> xFactory (mpResourceFactoryContainer->GetFactory(sResourceURL));
+ if ( ! xFactory.is())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": no factory found for " << sResourceURL);
+ return;
+ }
+
+ try
+ {
+ // 2. Create the resource.
+ Reference<XResource> xResource;
+ try
+ {
+ xResource = xFactory->createResource(rxResourceId);
+ }
+ catch (lang::DisposedException&)
+ {
+ // The factory is disposed and can be removed from the list
+ // of registered factories.
+ mpResourceFactoryContainer->RemoveFactoryForReference(xFactory);
+ }
+ catch (Exception&) {}
+
+ if (xResource.is())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": successfully created");
+ // 3. Add resource to URL->Object map.
+ AddResource(xResource, xFactory);
+
+ // 4. Add resource id to current configuration.
+ rxConfiguration->addResource(rxResourceId);
+
+ // 5. Notify the new resource to listeners of the ConfigurationController.
+ mpBroadcaster->NotifyListeners(
+ FrameworkHelper::msResourceActivationEvent,
+ rxResourceId,
+ xResource);
+ }
+ else
+ {
+ SAL_INFO("sd.fwk", __func__ << ": resource creation failed");
+ }
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+/* In this method we do following steps.
+ 1. Remove the resource from the URL->Object map of the configuration
+ controller.
+ 2. Notify listeners that deactivation has started.
+ 3. Remove the resource id from the current configuration.
+ 4. Release the resource.
+ 5. Notify listeners about that deactivation is completed.
+*/
+void ConfigurationControllerResourceManager::DeactivateResource (
+ const Reference<XResourceId>& rxResourceId,
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ if ( ! rxResourceId.is())
+ return;
+
+#if OSL_DEBUG_LEVEL >= 1
+ bool bSuccess (false);
+#endif
+ try
+ {
+ // 1. Remove resource from URL->Object map.
+ ResourceDescriptor aDescriptor (RemoveResource(rxResourceId));
+
+ if (aDescriptor.mxResource.is() && aDescriptor.mxResourceFactory.is())
+ {
+ // 2. Notify listeners that the resource is being deactivated.
+ mpBroadcaster->NotifyListeners(
+ FrameworkHelper::msResourceDeactivationEvent,
+ rxResourceId,
+ aDescriptor.mxResource);
+
+ // 3. Remove resource id from current configuration.
+ rxConfiguration->removeResource(rxResourceId);
+
+ // 4. Release the resource.
+ try
+ {
+ aDescriptor.mxResourceFactory->releaseResource(aDescriptor.mxResource);
+ }
+ catch (const lang::DisposedException& rException)
+ {
+ if ( ! rException.Context.is()
+ || rException.Context == aDescriptor.mxResourceFactory)
+ {
+ // The factory is disposed and can be removed from the
+ // list of registered factories.
+ mpResourceFactoryContainer->RemoveFactoryForReference(
+ aDescriptor.mxResourceFactory);
+ }
+ }
+
+#if OSL_DEBUG_LEVEL >= 1
+ bSuccess = true;
+#endif
+ }
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+
+ // 5. Notify listeners that the resource is being deactivated.
+ mpBroadcaster->NotifyListeners(
+ FrameworkHelper::msResourceDeactivationEndEvent,
+ rxResourceId,
+ nullptr);
+
+#if OSL_DEBUG_LEVEL >= 1
+ if (bSuccess)
+ SAL_INFO("sd.fwk", __func__ << ": successfully deactivated " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+ else
+ SAL_INFO("sd.fwk", __func__ << ": activating resource " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId)
+ << " failed");
+#endif
+}
+
+void ConfigurationControllerResourceManager::AddResource (
+ const Reference<XResource>& rxResource,
+ const Reference<XResourceFactory>& rxFactory)
+{
+ if ( ! rxResource.is())
+ {
+ OSL_ASSERT(rxResource.is());
+ return;
+ }
+
+ // Add the resource to the resource container.
+ ResourceDescriptor aDescriptor;
+ aDescriptor.mxResource = rxResource;
+ aDescriptor.mxResourceFactory = rxFactory;
+ maResourceMap[rxResource->getResourceId()] = aDescriptor;
+
+#if OSL_DEBUG_LEVEL >= 2
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationControllerResourceManager::AddResource(): added " <<
+ FrameworkHelper::ResourceIdToString(rxResource->getResourceId()) <<
+ " -> " << rxResource.get());
+#endif
+}
+
+ConfigurationControllerResourceManager::ResourceDescriptor
+ ConfigurationControllerResourceManager::RemoveResource (
+ const Reference<XResourceId>& rxResourceId)
+{
+ ResourceDescriptor aDescriptor;
+
+ ResourceMap::iterator iResource (maResourceMap.find(rxResourceId));
+ if (iResource != maResourceMap.end())
+ {
+#if OSL_DEBUG_LEVEL >= 2
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationControllerResourceManager::RemoveResource(): removing " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId) <<
+ " -> " << &iResource);
+#endif
+
+ aDescriptor = iResource->second;
+ maResourceMap.erase(rxResourceId);
+ }
+
+ return aDescriptor;
+}
+
+//===== ConfigurationControllerResourceManager::ResourceComparator ============
+
+bool ConfigurationControllerResourceManager::ResourceComparator::operator() (
+ const Reference<XResourceId>& rxId1,
+ const Reference<XResourceId>& rxId2) const
+{
+ if (rxId1.is() && rxId2.is())
+ return rxId1->compareTo(rxId2)<0;
+ else if (rxId1.is())
+ return true;
+ else
+ return false;
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx
new file mode 100644
index 000000000..f3a3d6d76
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.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 .
+ */
+
+#pragma once
+
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <map>
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::drawing::framework { class XConfiguration; }
+namespace com::sun::star::drawing::framework { class XResourceFactory; }
+namespace com::sun::star::drawing::framework { class XResource; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+
+namespace sd::framework {
+
+class ConfigurationControllerBroadcaster;
+class ResourceFactoryManager;
+
+/** Manage the set of active resources. Activate and deactivate resources.
+*/
+class ConfigurationControllerResourceManager
+{
+public:
+ /** For every active resource both the resource itself as well as its
+ creating factory are remembered, so that on deactivation, the
+ resource can be deactivated by this factory.
+ */
+ class ResourceDescriptor
+ {
+ public:
+ css::uno::Reference<css::drawing::framework::XResource> mxResource;
+ css::uno::Reference<css::drawing::framework::XResourceFactory> mxResourceFactory;
+ };
+
+ /** A new ResourceManager object is created with the resource factory
+ container for creating resources and the event broadcaster for
+ notifying ConfigurationChangeListeners of activated or deactivated
+ resources.
+ */
+ ConfigurationControllerResourceManager (
+ const std::shared_ptr<ResourceFactoryManager>& rpResourceFactoryContainer,
+ const std::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster);
+
+ ~ConfigurationControllerResourceManager();
+
+ /// Forbid copy construction and copy assignment
+ ConfigurationControllerResourceManager(const ConfigurationControllerResourceManager&) = delete;
+ ConfigurationControllerResourceManager& operator=(const ConfigurationControllerResourceManager&) = delete;
+
+ /** Activate all the resources that are specified by resource ids in
+ rResources. The resource ids of activated resources are added to
+ the given configuration. Activated resources are notified to all
+ interested ConfigurationChangeListeners.
+ */
+ void ActivateResources (
+ const ::std::vector<
+ css::uno::Reference<css::drawing::framework::XResourceId> >& rResources,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+
+ /** Deactivate all the resources that are specified by resource ids in
+ rResources. The resource ids of deactivated resources are removed
+ from the given configuration. Activated resources are notified to all
+ interested ConfigurationChangeListeners.
+ */
+ void DeactivateResources (
+ const ::std::vector<
+ css::uno::Reference<css::drawing::framework::XResourceId> >& rResources,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+
+ /** Return the descriptor for the specified resource.
+ @return
+ When there is no active resource for the given resource id then
+ an empty descriptor is returned.
+ */
+ ResourceDescriptor GetResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId);
+
+private:
+ osl::Mutex maMutex;
+
+ class ResourceComparator
+ {
+ public:
+ bool operator() (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxId1,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxId2) const;
+ };
+
+ typedef ::std::map<
+ css::uno::Reference<css::drawing::framework::XResourceId>,
+ ResourceDescriptor,
+ ResourceComparator> ResourceMap;
+ ResourceMap maResourceMap;
+
+ std::shared_ptr<ResourceFactoryManager> mpResourceFactoryContainer;
+
+ /** This broadcaster is used to notify the activation and deactivation
+ of resources.
+ */
+ std::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster;
+
+ void ActivateResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+
+ void DeactivateResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+
+ void AddResource (
+ const css::uno::Reference<css::drawing::framework::XResource>& rxResource,
+ const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxFactory);
+
+ ResourceDescriptor RemoveResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationTracer.cxx b/sd/source/ui/framework/configuration/ConfigurationTracer.cxx
new file mode 100644
index 000000000..00ddd5ff1
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationTracer.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 "ConfigurationTracer.hxx"
+
+#include <com/sun/star/drawing/framework/XConfiguration.hpp>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+void ConfigurationTracer::TraceConfiguration (
+ const Reference<XConfiguration>& rxConfiguration,
+ const char* pMessage)
+{
+#if OSL_DEBUG_LEVEL >=1
+ SAL_INFO("sd.ui","" << pMessage << " at " << rxConfiguration.get() << " {");
+ if (rxConfiguration.is())
+ {
+ TraceBoundResources(rxConfiguration, nullptr, 0);
+ }
+ else
+ {
+ SAL_INFO("sd.ui"," empty");
+ }
+ SAL_INFO("sd.ui","}");
+#else
+ (void)rxConfiguration;
+ (void)pMessage;
+#endif
+}
+
+#if OSL_DEBUG_LEVEL >=1
+void ConfigurationTracer::TraceBoundResources (
+ const Reference<XConfiguration>& rxConfiguration,
+ const Reference<XResourceId>& rxResourceId,
+ const int nIndentation)
+{
+ const Sequence<Reference<XResourceId> > aResourceList (
+ rxConfiguration->getResources(rxResourceId, OUString(), AnchorBindingMode_DIRECT));
+ static const OUStringLiteral sIndentation (u" ");
+ for (Reference<XResourceId> const & resourceId : aResourceList)
+ {
+ OUString sLine (resourceId->getResourceURL());
+ for (int i=0; i<nIndentation; ++i)
+ sLine = sIndentation + sLine;
+ SAL_INFO("sd.ui", "" << sLine);
+ TraceBoundResources(rxConfiguration, resourceId, nIndentation+1);
+ }
+}
+#endif
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationTracer.hxx b/sd/source/ui/framework/configuration/ConfigurationTracer.hxx
new file mode 100644
index 000000000..337fae569
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationTracer.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfiguration;
+}
+namespace com::sun::star::drawing::framework
+{
+class XResourceId;
+}
+namespace com::sun::star::uno
+{
+template <typename> class Reference;
+}
+
+namespace sd::framework
+{
+/** Print debug information about configurations to the standard error
+ output channel.
+*/
+class ConfigurationTracer
+{
+public:
+ static void TraceConfiguration(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration,
+ const char* pMessage);
+#if OSL_DEBUG_LEVEL >= 1
+ static void TraceBoundResources(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const int nIndentation);
+#endif
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationUpdater.cxx b/sd/source/ui/framework/configuration/ConfigurationUpdater.cxx
new file mode 100644
index 000000000..96ac74186
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationUpdater.cxx
@@ -0,0 +1,376 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ConfigurationUpdater.hxx"
+#include "ConfigurationTracer.hxx"
+#include "ConfigurationClassifier.hxx"
+#include "ConfigurationControllerBroadcaster.hxx"
+#include "ConfigurationControllerResourceManager.hxx"
+#include <framework/Configuration.hxx>
+#include <framework/FrameworkHelper.hxx>
+
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <comphelper/scopeguard.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::framework::FrameworkHelper;
+using ::std::vector;
+
+namespace {
+const sal_Int32 snShortTimeout (100);
+const sal_Int32 snNormalTimeout (1000);
+const sal_Int32 snLongTimeout (10000);
+const sal_Int32 snShortTimeoutCountThreshold (1);
+const sal_Int32 snNormalTimeoutCountThreshold (5);
+}
+
+namespace sd::framework {
+
+//===== ConfigurationUpdaterLock ==============================================
+
+class ConfigurationUpdaterLock
+{
+public:
+ explicit ConfigurationUpdaterLock (ConfigurationUpdater& rUpdater)
+ : mrUpdater(rUpdater) { mrUpdater.LockUpdates(); }
+ ~ConfigurationUpdaterLock() { mrUpdater.UnlockUpdates(); }
+private:
+ ConfigurationUpdater& mrUpdater;
+};
+
+//===== ConfigurationUpdater ==================================================
+
+ConfigurationUpdater::ConfigurationUpdater (
+ const std::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster,
+ const std::shared_ptr<ConfigurationControllerResourceManager>& rpResourceManager,
+ const Reference<XControllerManager>& rxControllerManager)
+ : mpBroadcaster(rpBroadcaster),
+ mxCurrentConfiguration(Reference<XConfiguration>(new Configuration(nullptr, false))),
+ mbUpdatePending(false),
+ mbUpdateBeingProcessed(false),
+ mnLockCount(0),
+ maUpdateTimer("sd::ConfigurationUpdater maUpdateTimer"),
+ mnFailedUpdateCount(0),
+ mpResourceManager(rpResourceManager)
+{
+ // Prepare the timer that is started when after an update the current
+ // and the requested configuration differ. With the timer we try
+ // updates until the two configurations are the same.
+ maUpdateTimer.SetTimeout(snNormalTimeout);
+ maUpdateTimer.SetInvokeHandler(LINK(this,ConfigurationUpdater,TimeoutHandler));
+ mxControllerManager = rxControllerManager;
+}
+
+ConfigurationUpdater::~ConfigurationUpdater()
+{
+ maUpdateTimer.Stop();
+}
+
+void ConfigurationUpdater::RequestUpdate (
+ const Reference<XConfiguration>& rxRequestedConfiguration)
+{
+ mxRequestedConfiguration = rxRequestedConfiguration;
+
+ // Find out whether we really can update the configuration.
+ if (IsUpdatePossible())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": UpdateConfiguration start");
+
+ // Call UpdateConfiguration while that is possible and while someone
+ // set mbUpdatePending to true in the middle of it.
+ do
+ {
+ UpdateConfiguration();
+ }
+ while (mbUpdatePending && IsUpdatePossible());
+ }
+ else
+ {
+ mbUpdatePending = true;
+ SAL_INFO("sd.fwk", __func__ << ": scheduling update for later");
+ }
+}
+
+bool ConfigurationUpdater::IsUpdatePossible() const
+{
+ return ! mbUpdateBeingProcessed
+ && mxControllerManager.is()
+ && mnLockCount==0
+ && mxRequestedConfiguration.is()
+ && mxCurrentConfiguration.is();
+}
+
+void ConfigurationUpdater::UpdateConfiguration()
+{
+ SAL_INFO("sd.fwk", __func__ << ": UpdateConfiguration update");
+ SetUpdateBeingProcessed(true);
+ comphelper::ScopeGuard aScopeGuard (
+ [this] () { return this->SetUpdateBeingProcessed(false); });
+
+ try
+ {
+ mbUpdatePending = false;
+
+ CleanRequestedConfiguration();
+ ConfigurationClassifier aClassifier(mxRequestedConfiguration, mxCurrentConfiguration);
+ if (aClassifier.Partition())
+ {
+#if DEBUG_SD_CONFIGURATION_TRACE
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationUpdater::UpdateConfiguration(");
+ ConfigurationTracer::TraceConfiguration(
+ mxRequestedConfiguration, "requested configuration");
+ ConfigurationTracer::TraceConfiguration(
+ mxCurrentConfiguration, "current configuration");
+#endif
+ // Notify the beginning of the update.
+ ConfigurationChangeEvent aEvent;
+ aEvent.Type = FrameworkHelper::msConfigurationUpdateStartEvent;
+ aEvent.Configuration = mxRequestedConfiguration;
+ mpBroadcaster->NotifyListeners(aEvent);
+
+ // Do the actual update. All exceptions are caught and ignored,
+ // so that the end of the update is notified always.
+ try
+ {
+ if (mnLockCount == 0)
+ UpdateCore(aClassifier);
+ }
+ catch(const RuntimeException&)
+ {
+ }
+
+ // Notify the end of the update.
+ aEvent.Type = FrameworkHelper::msConfigurationUpdateEndEvent;
+ mpBroadcaster->NotifyListeners(aEvent);
+
+ CheckUpdateSuccess();
+ }
+ else
+ {
+ SAL_INFO("sd.fwk", __func__ << ": nothing to do");
+#if DEBUG_SD_CONFIGURATION_TRACE
+ ConfigurationTracer::TraceConfiguration(
+ mxRequestedConfiguration, "requested configuration");
+ ConfigurationTracer::TraceConfiguration(
+ mxCurrentConfiguration, "current configuration");
+#endif
+ }
+ }
+ catch(const RuntimeException &)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationUpdater::UpdateConfiguration)");
+ SAL_INFO("sd.fwk", __func__ << ": UpdateConfiguration end");
+}
+
+void ConfigurationUpdater::CleanRequestedConfiguration()
+{
+ if (!mxControllerManager.is())
+ return;
+
+ // Request the deactivation of pure anchors that have no child.
+ vector<Reference<XResourceId> > aResourcesToDeactivate;
+ CheckPureAnchors(mxRequestedConfiguration, aResourcesToDeactivate);
+ if (!aResourcesToDeactivate.empty())
+ {
+ Reference<XConfigurationController> xCC (
+ mxControllerManager->getConfigurationController());
+ for (const auto& rxId : aResourcesToDeactivate)
+ if (rxId.is())
+ xCC->requestResourceDeactivation(rxId);
+ }
+}
+
+void ConfigurationUpdater::CheckUpdateSuccess()
+{
+ // When the two configurations differ then start the timer to call
+ // another update later.
+ if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration))
+ {
+ if (mnFailedUpdateCount <= snShortTimeoutCountThreshold)
+ maUpdateTimer.SetTimeout(snShortTimeout);
+ else if (mnFailedUpdateCount < snNormalTimeoutCountThreshold)
+ maUpdateTimer.SetTimeout(snNormalTimeout);
+ else
+ maUpdateTimer.SetTimeout(snLongTimeout);
+ ++mnFailedUpdateCount;
+ maUpdateTimer.Start();
+ }
+ else
+ {
+ // Update was successful. Reset the failed update count.
+ mnFailedUpdateCount = 0;
+ }
+}
+
+void ConfigurationUpdater::UpdateCore (const ConfigurationClassifier& rClassifier)
+{
+ try
+ {
+#if DEBUG_SD_CONFIGURATION_TRACE
+ rClassifier.TraceResourceIdVector(
+ "requested but not current resources:", rClassifier.GetC1minusC2());
+ rClassifier.TraceResourceIdVector(
+ "current but not requested resources:", rClassifier.GetC2minusC1());
+ rClassifier.TraceResourceIdVector(
+ "requested and current resources:", rClassifier.GetC1andC2());
+#endif
+
+ // Updating of the sub controllers is done in two steps. In the
+ // first the sub controllers typically shut down resources that are
+ // not requested anymore. In the second the sub controllers
+ // typically set up resources that have been newly requested.
+ mpResourceManager->DeactivateResources(rClassifier.GetC2minusC1(), mxCurrentConfiguration);
+ mpResourceManager->ActivateResources(rClassifier.GetC1minusC2(), mxCurrentConfiguration);
+
+#if DEBUG_SD_CONFIGURATION_TRACE
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::UpdateConfiguration)");
+ ConfigurationTracer::TraceConfiguration(
+ mxRequestedConfiguration, "requested configuration");
+ ConfigurationTracer::TraceConfiguration(
+ mxCurrentConfiguration, "current configuration");
+#endif
+
+ // Deactivate pure anchors that have no child.
+ vector<Reference<XResourceId> > aResourcesToDeactivate;
+ CheckPureAnchors(mxCurrentConfiguration, aResourcesToDeactivate);
+ if (!aResourcesToDeactivate.empty())
+ mpResourceManager->DeactivateResources(aResourcesToDeactivate, mxCurrentConfiguration);
+ }
+ catch(const RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+void ConfigurationUpdater::CheckPureAnchors (
+ const Reference<XConfiguration>& rxConfiguration,
+ vector<Reference<XResourceId> >& rResourcesToDeactivate)
+{
+ if ( ! rxConfiguration.is())
+ return;
+
+ // Get a list of all resources in the configuration.
+ Sequence<Reference<XResourceId> > aResources(
+ rxConfiguration->getResources(
+ nullptr, OUString(), AnchorBindingMode_INDIRECT));
+ auto aResourcesRange = asNonConstRange(aResources);
+ sal_Int32 nCount (aResources.getLength());
+
+ // Prepare the list of pure anchors that have to be deactivated.
+ rResourcesToDeactivate.clear();
+
+ // Iterate over the list in reverse order because when there is a chain
+ // of pure anchors with only the last one having no child then the whole
+ // list has to be deactivated.
+ sal_Int32 nIndex (nCount-1);
+ while (nIndex >= 0)
+ {
+ const Reference<XResourceId> xResourceId (aResources[nIndex]);
+ const Reference<XResource> xResource (
+ mpResourceManager->GetResource(xResourceId).mxResource);
+ bool bDeactiveCurrentResource (false);
+
+ // Skip all resources that are no pure anchors.
+ if (xResource.is() && xResource->isAnchorOnly())
+ {
+ // When xResource is not an anchor of the next resource in
+ // the list then it is the anchor of no resource at all.
+ if (nIndex == nCount-1)
+ {
+ // No following anchors, deactivate this one, then remove it
+ // from the list.
+ bDeactiveCurrentResource = true;
+ }
+ else
+ {
+ const Reference<XResourceId> xPrevResourceId (aResources[nIndex+1]);
+ if ( ! xPrevResourceId.is()
+ || ! xPrevResourceId->isBoundTo(xResourceId, AnchorBindingMode_DIRECT))
+ {
+ // The previous resource (id) does not exist or is not bound to
+ // the current anchor.
+ bDeactiveCurrentResource = true;
+ }
+ }
+ }
+
+ if (bDeactiveCurrentResource)
+ {
+ SAL_INFO("sd.fwk", __func__ << ": deactivating pure anchor " <<
+ FrameworkHelper::ResourceIdToString(xResourceId) <<
+ "because it has no children");
+ // Erase element from current configuration.
+ for (sal_Int32 nI=nIndex; nI<nCount-2; ++nI)
+ aResourcesRange[nI] = aResources[nI+1];
+ nCount -= 1;
+
+ rResourcesToDeactivate.push_back(xResourceId);
+ }
+ nIndex -= 1;
+ }
+}
+
+void ConfigurationUpdater::LockUpdates()
+{
+ ++mnLockCount;
+}
+
+void ConfigurationUpdater::UnlockUpdates()
+{
+ --mnLockCount;
+ if (mnLockCount == 0 && mbUpdatePending)
+ {
+ RequestUpdate(mxRequestedConfiguration);
+ }
+}
+
+std::shared_ptr<ConfigurationUpdaterLock> ConfigurationUpdater::GetLock()
+{
+ return std::make_shared<ConfigurationUpdaterLock>(*this);
+}
+
+void ConfigurationUpdater::SetUpdateBeingProcessed (bool bValue)
+{
+ mbUpdateBeingProcessed = bValue;
+}
+
+IMPL_LINK_NOARG(ConfigurationUpdater, TimeoutHandler, Timer *, void)
+{
+ if ( ! mbUpdateBeingProcessed
+ && mxCurrentConfiguration.is()
+ && mxRequestedConfiguration.is())
+ {
+ if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration))
+ {
+ RequestUpdate(mxRequestedConfiguration);
+ }
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationUpdater.hxx b/sd/source/ui/framework/configuration/ConfigurationUpdater.hxx
new file mode 100644
index 000000000..9fba364b1
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationUpdater.hxx
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <vcl/timer.hxx>
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfiguration;
+}
+namespace com::sun::star::drawing::framework
+{
+class XControllerManager;
+}
+namespace com::sun::star::drawing::framework
+{
+class XResourceId;
+}
+
+namespace sd::framework
+{
+class ConfigurationClassifier;
+class ConfigurationUpdaterLock;
+class ConfigurationControllerResourceManager;
+class ConfigurationControllerBroadcaster;
+
+/** This is a helper class for the ConfigurationController. It handles the
+ update of the current configuration so that it looks like a requested
+ configuration. An update is made by activating or deactivating drawing
+ framework resources.
+
+ When an update is not successful, i.e. after the update the current
+ configuration is not equivalent to the requested configuration, then a
+ timer is started to repeat the update after a short time.
+*/
+class ConfigurationUpdater
+{
+public:
+ /** Create a new ConfigurationUpdater object that notifies configuration
+ changes and the start and end of updates via the given broadcaster.
+ */
+ ConfigurationUpdater(
+ const std::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster,
+ const std::shared_ptr<ConfigurationControllerResourceManager>& rpResourceManager,
+ const css::uno::Reference<css::drawing::framework::XControllerManager>&
+ rxControllerManager);
+ ~ConfigurationUpdater();
+
+ /** Request an update of the current configuration so that it looks like
+ the given requested configuration. It checks whether an update of
+ the current configuration can be done. Calls UpdateConfiguration()
+ if that is the case. Otherwise it schedules a later call to
+ UpdateConfiguration().
+ */
+ void RequestUpdate(const css::uno::Reference<css::drawing::framework::XConfiguration>&
+ rxRequestedConfiguration);
+
+ const css::uno::Reference<css::drawing::framework::XConfiguration>&
+ GetCurrentConfiguration() const
+ {
+ return mxCurrentConfiguration;
+ }
+
+ friend class ConfigurationUpdaterLock;
+ /** Return a lock of the called ConfigurationUpdater. While the
+ returned object exists no update of the current configuration is
+ made.
+ */
+ std::shared_ptr<ConfigurationUpdaterLock> GetLock();
+
+private:
+ /** A reference to the XControllerManager is kept so that
+ UpdateConfiguration() has access to the other sub controllers.
+ */
+ css::uno::Reference<css::drawing::framework::XControllerManager> mxControllerManager;
+
+ std::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster;
+
+ /** The current configuration holds the resources that are currently
+ active. It is modified during an update.
+ */
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxCurrentConfiguration;
+
+ /** The requested configuration holds the resources that have been
+ requested to activate or to deactivate since the last update. It is
+ (usually) not modified during an update. This configuration is
+ maintained by the ConfigurationController and given to the
+ ConfigurationUpdater in the RequestUpdate() method.
+ */
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxRequestedConfiguration;
+
+ /** This flag is set to </sal_True> when an update of the current
+ configuration was requested (because the last request in the queue
+ was processed) but could not be executed because the
+ ConfigurationController was locked. A call to UpdateConfiguration()
+ resets the flag to </sal_False>.
+ */
+ bool mbUpdatePending;
+
+ /** This flag is set to </sal_True> while the UpdateConfiguration() method
+ is running. It is used to prevent reentrance problems with this
+ method.
+ */
+ bool mbUpdateBeingProcessed;
+
+ /** The ConfigurationController is locked when this count has a value
+ larger then zero. If the controller is locked then updates of the
+ current configuration are not made.
+ */
+ sal_Int32 mnLockCount;
+
+ /** This timer is used to check from time to time whether the requested
+ configuration and the current configuration are identical and request
+ an update when they are not.
+ This is used to overcome problems with resources that become
+ available asynchronously.
+ */
+ Timer maUpdateTimer;
+
+ /** The number of failed updates (those after which the current
+ configuration is not equivalent to the requested configuration) is
+ used to determine how long to wait before another update is made.
+ */
+ sal_Int32 mnFailedUpdateCount;
+
+ std::shared_ptr<ConfigurationControllerResourceManager> mpResourceManager;
+
+ /** This method does the main work of an update. It calls the sub
+ controllers that are responsible for the various types of resources
+ and tells them to update their active resources. It notifies
+ listeners about the start and end of the configuration update.
+ */
+ void UpdateConfiguration();
+
+ /** Basically calls UpdaterStart() andUpdateEnd() and makes some debug
+ output.
+ */
+ void UpdateCore(const ConfigurationClassifier& rClassifier);
+
+ /** Check for all pure anchors if they have at least one child.
+ Childless pure anchors are deactivated.
+ This affects only the current configuration.
+ */
+ void CheckPureAnchors(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration,
+ ::std::vector<css::uno::Reference<css::drawing::framework::XResourceId>>&
+ rResourcesToDeactivate);
+
+ /** Remove from the requested configuration all pure anchors that have no
+ child. Requested but not yet activated anchors can not be removed
+ because without the actual resource the 'pureness' of an anchor can
+ not be determined.
+ */
+ void CleanRequestedConfiguration();
+
+ /** Check the success of a recently executed configuration update.
+ When the update failed then start the timer.
+ */
+ void CheckUpdateSuccess();
+
+ /** This method sets the mbUpdateBeingProcessed member that is used to
+ prevent reentrance problems. This method allows function objects
+ easily and safely to modify the variable.
+ */
+ void SetUpdateBeingProcessed(bool bValue);
+
+ /** Return whether it is possible to do an update of the configuration.
+ This takes into account whether another update is currently being
+ executed, the lock count, and whether the configuration controller
+ is still valid.
+ */
+ bool IsUpdatePossible() const;
+
+ /** Lock updates of the current configuration. For intermediate requests
+ for updates mbUpdatePending is set to <TRUE/>.
+ */
+ void LockUpdates();
+
+ /** When an update was requested since the last LockUpdates() call then
+ RequestUpdate() is called.
+ */
+ void UnlockUpdates();
+
+ DECL_LINK(TimeoutHandler, Timer*, void);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx
new file mode 100644
index 000000000..fa6d41503
--- /dev/null
+++ b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.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 <sal/config.h>
+
+#include <string_view>
+
+#include "GenericConfigurationChangeRequest.hxx"
+
+#include <framework/FrameworkHelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+GenericConfigurationChangeRequest::GenericConfigurationChangeRequest (
+ const Reference<XResourceId>& rxResourceId,
+ const Mode eMode)
+ : mxResourceId(rxResourceId),
+ meMode(eMode)
+{
+ if ( ! rxResourceId.is() || rxResourceId->getResourceURL().isEmpty())
+ throw css::lang::IllegalArgumentException();
+}
+
+GenericConfigurationChangeRequest::~GenericConfigurationChangeRequest() noexcept
+{
+}
+
+void SAL_CALL GenericConfigurationChangeRequest::execute (
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ if (!rxConfiguration.is())
+ return;
+
+ switch (meMode)
+ {
+ case Activation:
+ rxConfiguration->addResource(mxResourceId);
+ break;
+
+ case Deactivation:
+ rxConfiguration->removeResource(mxResourceId);
+ break;
+ }
+}
+
+OUString SAL_CALL GenericConfigurationChangeRequest::getName()
+{
+ return OUString::Concat("GenericConfigurationChangeRequest ")
+ + (meMode==Activation
+ ? std::u16string_view(u"activate ") : std::u16string_view(u"deactivate "))
+ + FrameworkHelper::ResourceIdToString(mxResourceId);
+}
+
+void SAL_CALL GenericConfigurationChangeRequest::setName (const OUString&)
+{
+ // Ignored.
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx
new file mode 100644
index 000000000..3caa7a8ca
--- /dev/null
+++ b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeRequest.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::drawing::framework { class XConfiguration; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeRequest,
+ css::container::XNamed
+ > GenericConfigurationChangeRequestInterfaceBase;
+
+/** This implementation of the XConfigurationChangeRequest interface
+ represents a single explicit request for a configuration change. On its
+ execution it may result in other, implicit, configuration changes. For
+ example this is the case when the deactivation of a unique resource is
+ requested: the resources linked to it have to be deactivated as well.
+*/
+class GenericConfigurationChangeRequest final
+ : public GenericConfigurationChangeRequestInterfaceBase
+{
+public:
+ /** This enum specified whether the activation or deactivation of a
+ resource is requested.
+ */
+ enum Mode { Activation, Deactivation };
+
+ /** Create a new object that represents the request for activation or
+ deactivation of the specified resource.
+ @param rxsResourceId
+ Id of the resource that is to be activated or deactivated.
+ @param eMode
+ The mode specifies whether to activate or to deactivate the
+ resource.
+ @throws css::css::lang::IllegalArgumentException
+ */
+ GenericConfigurationChangeRequest (
+ const css::uno::Reference<css::drawing::framework::XResourceId>&
+ rxResourceId,
+ const Mode eMode);
+
+ virtual ~GenericConfigurationChangeRequest() noexcept override;
+
+ // XConfigurationChangeOperation
+
+ /** The requested configuration change is executed on the given
+ configuration. Additionally to the explicitly requested change
+ other changes have to be made as well. See class description for an
+ example.
+ @param rxConfiguration
+ The configuration to which the requested change is made.
+ */
+ virtual void SAL_CALL execute (
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration) override;
+
+ // XNamed
+
+ /** Return a human readable string representation. This is used for
+ debugging purposes.
+ */
+ virtual OUString SAL_CALL getName() override;
+
+ /** This call is ignored because the XNamed interface is (mis)used to
+ give access to a human readable name for debugging purposes.
+ */
+ virtual void SAL_CALL setName (const OUString& rName) override;
+
+private:
+ const css::uno::Reference<css::drawing::framework::XResourceId> mxResourceId;
+ const Mode meMode;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ResourceFactoryManager.cxx b/sd/source/ui/framework/configuration/ResourceFactoryManager.cxx
new file mode 100644
index 000000000..4817c1360
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ResourceFactoryManager.cxx
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ResourceFactoryManager.hxx"
+#include <tools/wldcrd.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <comphelper/processfactory.hxx>
+#include <sal/log.hxx>
+
+#include <algorithm>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+#undef VERBOSE
+//#define VERBOSE 1
+
+namespace sd::framework {
+
+ResourceFactoryManager::ResourceFactoryManager (const Reference<XControllerManager>& rxManager)
+ : mxControllerManager(rxManager)
+{
+ // Create the URL transformer.
+ Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ mxURLTransformer = util::URLTransformer::create(xContext);
+}
+
+ResourceFactoryManager::~ResourceFactoryManager()
+{
+ for (auto& rXInterfaceResource : maFactoryMap)
+ {
+ Reference<lang::XComponent> xComponent (rXInterfaceResource.second, UNO_QUERY);
+ rXInterfaceResource.second = nullptr;
+ if (xComponent.is())
+ xComponent->dispose();
+ }
+
+ Reference<lang::XComponent> xComponent (mxURLTransformer, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+}
+
+void ResourceFactoryManager::AddFactory (
+ const OUString& rsURL,
+ const Reference<XResourceFactory>& rxFactory)
+{
+ if ( ! rxFactory.is())
+ throw lang::IllegalArgumentException();
+ if (rsURL.isEmpty())
+ throw lang::IllegalArgumentException();
+
+ std::scoped_lock aGuard (maMutex);
+
+ if (rsURL.indexOf('*') >= 0 || rsURL.indexOf('?') >= 0)
+ {
+ // The URL is a URL pattern not a single URL.
+ maFactoryPatternList.emplace_back(rsURL, rxFactory);
+
+#if defined VERBOSE && VERBOSE>=1
+ SAL_INFO("sd","ResourceFactoryManager::AddFactory pattern " << rsURL << std::hex << rxFactory.get());
+#endif
+ }
+ else
+ {
+ maFactoryMap[rsURL] = rxFactory;
+
+#if defined VERBOSE && VERBOSE>=1
+ SAL_INFO("sd", "ResourceFactoryManager::AddFactory fixed " << rsURL << " 0x" << std::hex << rxFactory.get());
+#endif
+ }
+}
+
+void ResourceFactoryManager::RemoveFactoryForURL (
+ const OUString& rsURL)
+{
+ if (rsURL.isEmpty())
+ throw lang::IllegalArgumentException();
+
+ std::scoped_lock aGuard (maMutex);
+
+ FactoryMap::iterator iFactory (maFactoryMap.find(rsURL));
+ if (iFactory != maFactoryMap.end())
+ {
+ maFactoryMap.erase(iFactory);
+ }
+ else
+ {
+ // The URL may be a pattern. Look that up.
+ auto iPattern = std::find_if(maFactoryPatternList.begin(), maFactoryPatternList.end(),
+ [&rsURL](const FactoryPatternList::value_type& rPattern) { return rPattern.first == rsURL; });
+ if (iPattern != maFactoryPatternList.end())
+ {
+ // Found the pattern. Remove it.
+ maFactoryPatternList.erase(iPattern);
+ }
+ }
+}
+
+void ResourceFactoryManager::RemoveFactoryForReference(
+ const Reference<XResourceFactory>& rxFactory)
+{
+ std::scoped_lock aGuard (maMutex);
+
+ // Collect a list with all keys that map to the given factory.
+ ::std::vector<OUString> aKeys;
+ for (const auto& rFactory : maFactoryMap)
+ if (rFactory.second == rxFactory)
+ aKeys.push_back(rFactory.first);
+
+ // Remove the entries whose keys we just have collected.
+ for (const auto& rKey : aKeys)
+ maFactoryMap.erase(rKey);
+
+ // Remove the pattern entries whose factories are identical to the given
+ // factory.
+ maFactoryPatternList.erase(
+ std::remove_if(
+ maFactoryPatternList.begin(),
+ maFactoryPatternList.end(),
+ [&] (FactoryPatternList::value_type const& it) { return it.second == rxFactory; }),
+ maFactoryPatternList.end());
+}
+
+Reference<XResourceFactory> ResourceFactoryManager::GetFactory (
+ const OUString& rsCompleteURL)
+{
+ OUString sURLBase (rsCompleteURL);
+ if (mxURLTransformer.is())
+ {
+ util::URL aURL;
+ aURL.Complete = rsCompleteURL;
+ if (mxURLTransformer->parseStrict(aURL))
+ sURLBase = aURL.Main;
+ }
+
+ Reference<XResourceFactory> xFactory = FindFactory(sURLBase);
+
+ if ( ! xFactory.is() && mxControllerManager.is())
+ {
+ Reference<XModuleController> xModuleController(mxControllerManager->getModuleController());
+ if (xModuleController.is())
+ {
+ // Ask the module controller to provide a factory of the
+ // requested view type. Note that this can (and should) cause
+ // intermediate calls to AddFactory().
+ xModuleController->requestResource(sURLBase);
+
+ xFactory = FindFactory(sURLBase);
+ }
+ }
+
+ return xFactory;
+}
+
+Reference<XResourceFactory> ResourceFactoryManager::FindFactory (const OUString& rsURLBase)
+{
+ std::scoped_lock aGuard (maMutex);
+ FactoryMap::const_iterator iFactory (maFactoryMap.find(rsURLBase));
+ if (iFactory != maFactoryMap.end())
+ return iFactory->second;
+ else
+ {
+ // Check the URL patterns.
+ auto iPattern = std::find_if(maFactoryPatternList.begin(), maFactoryPatternList.end(),
+ [&rsURLBase](const FactoryPatternList::value_type& rPattern) {
+ WildCard aWildCard (rPattern.first);
+ return aWildCard.Matches(rsURLBase);
+ });
+ if (iPattern != maFactoryPatternList.end())
+ return iPattern->second;
+ }
+ return nullptr;
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ResourceFactoryManager.hxx b/sd/source/ui/framework/configuration/ResourceFactoryManager.hxx
new file mode 100644
index 000000000..61daf383b
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ResourceFactoryManager.hxx
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <mutex>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <rtl/ustring.hxx>
+
+namespace com::sun::star::drawing::framework { class XControllerManager; }
+namespace com::sun::star::drawing::framework { class XResourceFactory; }
+namespace com::sun::star::util { class XURLTransformer; }
+
+namespace sd::framework {
+
+/** Container of resource factories of the drawing framework.
+*/
+class ResourceFactoryManager
+{
+public:
+ explicit ResourceFactoryManager (
+ const css::uno::Reference<css::drawing::framework::XControllerManager>& rxManager);
+
+ ~ResourceFactoryManager();
+
+ /** Register a resource factory for one type of resource.
+ @param rsURL
+ The type of the resource that will be created by the factory.
+ @param rxFactory
+ The factory that will create resource objects of the specified type.
+ @throws css::uno::RuntimeException
+ */
+ void AddFactory (
+ const OUString& rsURL,
+ const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxFactory);
+
+ /** Unregister the specified factory.
+ @param rsURL
+ Unregister only the factory for this URL. When the same factory
+ is registered for other URLs then these remain registered.
+ @throws css::uno::RuntimeException
+ */
+ void RemoveFactoryForURL(
+ const OUString& rsURL);
+
+ /** Unregister the specified factory.
+ @param rxFactory
+ Unregister the this factory for all URLs that it has been
+ registered for.
+ @throws css::uno::RuntimeException
+ */
+ void RemoveFactoryForReference(
+ const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxFactory);
+
+ /** Return a factory that can create resources specified by the given URL.
+ @param rsCompleteURL
+ This URL specifies the type of the resource. It may contain arguments.
+ @return
+ When a factory for the specified URL has been registered by a
+ previous call to AddFactory() then a reference to that factory
+ is returned. Otherwise an empty reference is returned.
+ @throws css::uno::RuntimeException
+ */
+ css::uno::Reference<css::drawing::framework::XResourceFactory> GetFactory (
+ const OUString& rsURL);
+
+private:
+ std::mutex maMutex;
+ typedef std::unordered_map<
+ OUString,
+ css::uno::Reference<css::drawing::framework::XResourceFactory> > FactoryMap;
+ FactoryMap maFactoryMap;
+
+ typedef ::std::vector<
+ ::std::pair<
+ OUString,
+ css::uno::Reference<css::drawing::framework::XResourceFactory> > >
+ FactoryPatternList;
+ FactoryPatternList maFactoryPatternList;
+
+ css::uno::Reference<css::drawing::framework::XControllerManager> mxControllerManager;
+ css::uno::Reference<css::util::XURLTransformer> mxURLTransformer;
+
+ /** Look up the factory for the given URL.
+ @param rsURLBase
+ The css::tools::URL.Main part of a URL. Arguments have to be
+ stripped off by the caller.
+ @return
+ When the factory has not yet been added then return NULL.
+ @throws css::uno::RuntimeException
+ */
+ css::uno::Reference<css::drawing::framework::XResourceFactory> FindFactory (
+ const OUString& rsURLBase);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ResourceId.cxx b/sd/source/ui/framework/configuration/ResourceId.cxx
new file mode 100644
index 000000000..1845b353f
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ResourceId.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 <framework/ResourceId.hxx>
+#include <tools/SdGlobalResourceContainer.hxx>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <rtl/ref.hxx>
+
+#include <algorithm>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing::framework;
+
+/** When the USE_OPTIMIZATIONS symbol is defined then at some optimizations
+ are activated that work only together with XResourceId objects that are
+ implemented by the ResourceId class. For other implementations of when
+ the USE_OPTIMIZATIONS symbol is not defined then alternative code is
+ used instead.
+*/
+#define USE_OPTIMIZATIONS
+
+namespace sd::framework {
+
+//===== ResourceId ============================================================
+
+WeakReference<util::XURLTransformer> ResourceId::mxURLTransformerWeak;
+
+ResourceId::ResourceId()
+ : maResourceURLs(0)
+{
+}
+
+ResourceId::ResourceId (
+ std::vector<OUString>&& rResourceURLs)
+ : maResourceURLs(std::move(rResourceURLs))
+{
+ ParseResourceURL();
+}
+
+ResourceId::ResourceId (
+ const OUString& rsResourceURL)
+ : maResourceURLs(1, rsResourceURL)
+{
+ // Handle the special case of an empty resource URL.
+ if (rsResourceURL.isEmpty())
+ maResourceURLs.clear();
+ ParseResourceURL();
+}
+
+ResourceId::ResourceId (
+ const OUString& rsResourceURL,
+ const OUString& rsAnchorURL)
+ : maResourceURLs(2)
+{
+ maResourceURLs[0] = rsResourceURL;
+ maResourceURLs[1] = rsAnchorURL;
+ ParseResourceURL();
+}
+
+ResourceId::ResourceId (
+ const OUString& rsResourceURL,
+ const OUString& rsFirstAnchorURL,
+ const Sequence<OUString>& rAnchorURLs)
+ : maResourceURLs(2+rAnchorURLs.getLength())
+{
+ maResourceURLs[0] = rsResourceURL;
+ maResourceURLs[1] = rsFirstAnchorURL;
+ std::copy(rAnchorURLs.begin(), rAnchorURLs.end(), std::next(maResourceURLs.begin(), 2));
+ ParseResourceURL();
+}
+
+ResourceId::~ResourceId()
+{
+ mpURL.reset();
+}
+
+OUString SAL_CALL
+ ResourceId::getResourceURL()
+{
+ if (!maResourceURLs.empty())
+ return maResourceURLs[0];
+ else
+ return OUString();
+}
+
+util::URL SAL_CALL
+ ResourceId::getFullResourceURL()
+{
+ if (mpURL != nullptr)
+ return *mpURL;
+
+ Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak);
+ if (xURLTransformer.is() && !maResourceURLs.empty() )
+ {
+ mpURL.reset(new util::URL);
+ mpURL->Complete = maResourceURLs[0];
+ xURLTransformer->parseStrict(*mpURL);
+ return *mpURL;
+ }
+
+ util::URL aURL;
+ if (!maResourceURLs.empty())
+ aURL.Complete = maResourceURLs[0];
+ return aURL;
+}
+
+sal_Bool SAL_CALL
+ ResourceId::hasAnchor()
+{
+ return maResourceURLs.size()>1;
+}
+
+Reference<XResourceId> SAL_CALL
+ ResourceId::getAnchor()
+{
+ ::rtl::Reference<ResourceId> rResourceId (new ResourceId());
+ const sal_Int32 nAnchorCount (maResourceURLs.size()-1);
+ if (nAnchorCount > 0)
+ {
+ rResourceId->maResourceURLs.resize(nAnchorCount);
+ for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex)
+ rResourceId->maResourceURLs[nIndex] = maResourceURLs[nIndex+1];
+ }
+ return rResourceId;
+}
+
+Sequence<OUString> SAL_CALL
+ ResourceId::getAnchorURLs()
+{
+ const sal_Int32 nAnchorCount (maResourceURLs.size() - 1);
+ if (nAnchorCount > 0)
+ {
+ Sequence<OUString> aAnchorURLs (nAnchorCount);
+ std::copy_n(maResourceURLs.begin() + 1, nAnchorCount, aAnchorURLs.getArray());
+ return aAnchorURLs;
+ }
+ else
+ return Sequence<OUString>();
+}
+
+OUString SAL_CALL
+ ResourceId::getResourceTypePrefix()
+{
+ if (!maResourceURLs.empty() )
+ {
+ // Return the "private:resource/<type>/" prefix.
+
+ // Get the prefix that ends with the second "/".
+ const OUString& rsResourceURL (maResourceURLs[0]);
+ sal_Int32 nPrefixEnd (rsResourceURL.indexOf('/'));
+ if (nPrefixEnd >= 0)
+ nPrefixEnd = rsResourceURL.indexOf('/', nPrefixEnd+1) + 1;
+ else
+ nPrefixEnd = 0;
+
+ return rsResourceURL.copy(0,nPrefixEnd);
+ }
+ else
+ return OUString();
+}
+
+sal_Int16 SAL_CALL
+ ResourceId::compareTo (const Reference<XResourceId>& rxResourceId)
+{
+ sal_Int16 nResult (0);
+
+ if ( ! rxResourceId.is())
+ {
+ // The empty reference is interpreted as empty resource id object.
+ if (!maResourceURLs.empty())
+ nResult = +1;
+ else
+ nResult = 0;
+ }
+ else
+ {
+ ResourceId* pId = nullptr;
+#ifdef USE_OPTIMIZATIONS
+ pId = dynamic_cast<ResourceId*>(rxResourceId.get());
+#endif
+ if (pId != nullptr)
+ {
+ // We have direct access to the implementation of the given
+ // resource id object.
+ nResult = CompareToLocalImplementation(*pId);
+ }
+ else
+ {
+ // We have to do the comparison via the UNO interface of the
+ // given resource id object.
+ nResult = CompareToExternalImplementation(rxResourceId);
+ }
+ }
+
+ return nResult;
+}
+
+sal_Int16 ResourceId::CompareToLocalImplementation (const ResourceId& rId) const
+{
+ sal_Int16 nResult (0);
+
+ const sal_uInt32 nLocalURLCount (maResourceURLs.size());
+ const sal_uInt32 nURLCount(rId.maResourceURLs.size());
+
+ // Start comparison with the top most anchors.
+ for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1;
+ nIndex>=0 && nLocalIndex>=0;
+ --nIndex,--nLocalIndex)
+ {
+ const OUString sLocalURL (maResourceURLs[nLocalIndex]);
+ const OUString sURL (rId.maResourceURLs[nIndex]);
+ const sal_Int32 nLocalResult (sURL.compareTo(sLocalURL));
+ if (nLocalResult != 0)
+ {
+ if (nLocalResult < 0)
+ nResult = -1;
+ else
+ nResult = +1;
+ break;
+ }
+ }
+
+ if (nResult == 0)
+ {
+ // No difference found yet. When the lengths are the same then the
+ // two resource ids are equivalent. Otherwise the shorter comes
+ // first.
+ if (nLocalURLCount != nURLCount)
+ {
+ if (nLocalURLCount < nURLCount)
+ nResult = -1;
+ else
+ nResult = +1;
+ }
+ }
+
+ return nResult;
+}
+
+sal_Int16 ResourceId::CompareToExternalImplementation (const Reference<XResourceId>& rxId) const
+{
+ sal_Int16 nResult (0);
+
+ const Sequence<OUString> aAnchorURLs (rxId->getAnchorURLs());
+ const sal_uInt32 nLocalURLCount (maResourceURLs.size());
+ const sal_uInt32 nURLCount(1+aAnchorURLs.getLength());
+
+ // Start comparison with the top most anchors.
+ sal_Int32 nLocalResult (0);
+ for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1;
+ nIndex>=0&&nLocalIndex>=0;
+ --nIndex,--nLocalIndex)
+ {
+ if (nIndex == 0 )
+ nLocalResult = maResourceURLs[nIndex].compareTo(rxId->getResourceURL());
+ else
+ nLocalResult = maResourceURLs[nIndex].compareTo(aAnchorURLs[nIndex-1]);
+ if (nLocalResult != 0)
+ {
+ if (nLocalResult < 0)
+ nResult = -1;
+ else
+ nResult = +1;
+ break;
+ }
+ }
+
+ if (nResult == 0)
+ {
+ // No difference found yet. When the lengths are the same then the
+ // two resource ids are equivalent. Otherwise the shorter comes
+ // first.
+ if (nLocalURLCount != nURLCount)
+ {
+ if (nLocalURLCount < nURLCount)
+ nResult = -1;
+ else
+ nResult = +1;
+ }
+ }
+
+ return nResult;
+}
+
+sal_Bool SAL_CALL
+ ResourceId::isBoundTo (
+ const Reference<XResourceId>& rxResourceId,
+ AnchorBindingMode eMode)
+{
+ if ( ! rxResourceId.is())
+ {
+ // An empty reference is interpreted as empty resource id.
+ return IsBoundToAnchor(nullptr, nullptr, eMode);
+ }
+
+ ResourceId* pId = nullptr;
+#ifdef USE_OPTIMIZATIONS
+ pId = dynamic_cast<ResourceId*>(rxResourceId.get());
+#endif
+ if (pId != nullptr)
+ {
+ return IsBoundToAnchor(pId->maResourceURLs, eMode);
+ }
+ else
+ {
+ const OUString sResourceURL (rxResourceId->getResourceURL());
+ const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs());
+ return IsBoundToAnchor(&sResourceURL, &aAnchorURLs, eMode);
+ }
+}
+
+sal_Bool SAL_CALL
+ ResourceId::isBoundToURL (
+ const OUString& rsAnchorURL,
+ AnchorBindingMode eMode)
+{
+ return IsBoundToAnchor(&rsAnchorURL, nullptr, eMode);
+}
+
+Reference<XResourceId> SAL_CALL
+ ResourceId::clone()
+{
+ return new ResourceId(std::vector(maResourceURLs));
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL ResourceId::initialize (const Sequence<Any>& aArguments)
+{
+ for (const auto& rArgument : aArguments)
+ {
+ OUString sResourceURL;
+ if (rArgument >>= sResourceURL)
+ maResourceURLs.push_back(sResourceURL);
+ else
+ {
+ Reference<XResourceId> xAnchor;
+ if (rArgument >>= xAnchor)
+ {
+ if (xAnchor.is())
+ {
+ maResourceURLs.push_back(xAnchor->getResourceURL());
+ const Sequence<OUString> aAnchorURLs (xAnchor->getAnchorURLs());
+ maResourceURLs.insert( maResourceURLs.end(), aAnchorURLs.begin(), aAnchorURLs.end() );
+ }
+ }
+ }
+ }
+ ParseResourceURL();
+}
+
+OUString ResourceId::getImplementationName()
+{
+ return "com.sun.star.comp.Draw.framework.ResourceId";
+}
+
+sal_Bool ResourceId::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> ResourceId::getSupportedServiceNames()
+{
+ return css::uno::Sequence<OUString>{
+ "com.sun.star.drawing.framework.ResourceId"};
+}
+
+/** When eMode is DIRECTLY then the anchor of the called object and the
+ anchor represented by the given sequence of anchor URLs have to be
+ identical. When eMode is RECURSIVE then the anchor of the called
+ object has to start with the given anchor URLs.
+*/
+bool ResourceId::IsBoundToAnchor (
+ const OUString* psFirstAnchorURL,
+ const Sequence<OUString>* paAnchorURLs,
+ AnchorBindingMode eMode) const
+{
+ const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1);
+ const bool bHasFirstAnchorURL (psFirstAnchorURL!=nullptr);
+ const sal_uInt32 nAnchorURLCount ((bHasFirstAnchorURL?1:0)
+ + (paAnchorURLs!=nullptr ? paAnchorURLs->getLength() : 0));
+
+ // Check the lengths.
+ if (nLocalAnchorURLCount<nAnchorURLCount ||
+ (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount))
+ {
+ return false;
+ }
+
+ // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
+ // id and the given anchor.
+ sal_uInt32 nOffset = 0;
+ if (paAnchorURLs != nullptr)
+ {
+ sal_uInt32 nCount = paAnchorURLs->getLength();
+ while (nOffset < nCount)
+ {
+ if ( maResourceURLs[nLocalAnchorURLCount - nOffset] !=
+ (*paAnchorURLs)[nCount - 1 - nOffset] )
+ {
+ return false;
+ }
+ ++nOffset;
+ }
+ }
+ if (bHasFirstAnchorURL)
+ {
+ if ( *psFirstAnchorURL != maResourceURLs[nLocalAnchorURLCount - nOffset] )
+ return false;
+ }
+
+ return true;
+}
+
+bool ResourceId::IsBoundToAnchor (
+ const ::std::vector<OUString>& rAnchorURLs,
+ AnchorBindingMode eMode) const
+{
+ const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1);
+ const sal_uInt32 nAnchorURLCount (rAnchorURLs.size());
+
+ // Check the lengths.
+ if (nLocalAnchorURLCount<nAnchorURLCount ||
+ (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount))
+ {
+ return false;
+ }
+
+ // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
+ // id and the given anchor.
+ for (sal_uInt32 nOffset=0; nOffset<nAnchorURLCount; ++nOffset)
+ {
+ if ( maResourceURLs[nLocalAnchorURLCount - nOffset] !=
+ rAnchorURLs[nAnchorURLCount - 1 - nOffset] )
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ResourceId::ParseResourceURL()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex());
+ Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak);
+ if ( ! xURLTransformer.is())
+ {
+ // Create the URL transformer.
+ Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ xURLTransformer.set(util::URLTransformer::create(xContext));
+ mxURLTransformerWeak = xURLTransformer;
+ SdGlobalResourceContainer::Instance().AddResource(
+ Reference<XInterface>(xURLTransformer,UNO_QUERY));
+ }
+
+ if (xURLTransformer.is() && !maResourceURLs.empty() )
+ {
+ mpURL.reset(new util::URL);
+ mpURL->Complete = maResourceURLs[0];
+ xURLTransformer->parseStrict(*mpURL);
+ if (mpURL->Main == maResourceURLs[0])
+ mpURL.reset();
+ else
+ maResourceURLs[0] = mpURL->Main;
+ }
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_ResourceID_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::ResourceId());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/UpdateRequest.cxx b/sd/source/ui/framework/configuration/UpdateRequest.cxx
new file mode 100644
index 000000000..b6c5e8c42
--- /dev/null
+++ b/sd/source/ui/framework/configuration/UpdateRequest.cxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "UpdateRequest.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework
+{
+UpdateRequest::UpdateRequest() noexcept {}
+
+UpdateRequest::~UpdateRequest() noexcept {}
+
+void SAL_CALL UpdateRequest::execute(const Reference<XConfiguration>&)
+{
+ // Do nothing here. The configuration is updated when the request queue
+ // becomes empty.
+}
+
+OUString SAL_CALL UpdateRequest::getName() { return "UpdateRequest"; }
+
+void SAL_CALL UpdateRequest::setName(const OUString&)
+{
+ // Ignored.
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/UpdateRequest.hxx b/sd/source/ui/framework/configuration/UpdateRequest.hxx
new file mode 100644
index 000000000..712167154
--- /dev/null
+++ b/sd/source/ui/framework/configuration/UpdateRequest.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeRequest.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::drawing::framework { class XConfiguration; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeRequest,
+ css::container::XNamed
+ > UpdateRequestInterfaceBase;
+
+/** This update request is used to request configuration updates
+ asynchronous when no other requests are being processed. When there are
+ other requests then we can simply wait until the last one is executed:
+ the configuration is updated when the request queue becomes empty. This
+ is use by this implementation as well. The execute() method does not
+ really do anything. This request just triggers the update of the
+ configuration when it is removed as last request from the queue.
+*/
+class UpdateRequest final
+ : public UpdateRequestInterfaceBase
+{
+public:
+ UpdateRequest() noexcept;
+ virtual ~UpdateRequest() noexcept override;
+
+ // XConfigurationChangeOperation
+
+ virtual void SAL_CALL execute (
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration) override;
+
+ // XNamed
+
+ /** Return a human readable string representation. This is used for
+ debugging purposes.
+ */
+ virtual OUString SAL_CALL getName() override;
+
+ /** This call is ignored because the XNamed interface is (mis)used to
+ give access to a human readable name for debugging purposes.
+ */
+ virtual void SAL_CALL setName (const OUString& rName) override;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/debugtrace.hxx b/sd/source/ui/framework/configuration/debugtrace.hxx
new file mode 100644
index 000000000..b520d0ff3
--- /dev/null
+++ b/sd/source/ui/framework/configuration/debugtrace.hxx
@@ -0,0 +1,15 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+/// Centrally define activation of configuration debug traces.
+#define DEBUG_SD_CONFIGURATION_TRACE 0
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicPaneFactory.cxx b/sd/source/ui/framework/factories/BasicPaneFactory.cxx
new file mode 100644
index 000000000..c01d315a3
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicPaneFactory.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 <memory>
+#include <sal/config.h>
+
+#include "BasicPaneFactory.hxx"
+
+#include "ChildWindowPane.hxx"
+#include "FrameWindowPane.hxx"
+#include "FullScreenPane.hxx"
+
+#include <comphelper/servicehelper.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <PaneShells.hxx>
+#include <ViewShellBase.hxx>
+#include <PaneChildWindows.hxx>
+#include <DrawController.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace {
+ enum PaneId {
+ CenterPaneId,
+ FullScreenPaneId,
+ LeftImpressPaneId,
+ LeftDrawPaneId
+ };
+
+ const sal_Int32 gnConfigurationUpdateStartEvent(0);
+ const sal_Int32 gnConfigurationUpdateEndEvent(1);
+}
+
+namespace sd::framework {
+
+/** Store URL, XPane reference and (local) PaneId for every pane factory
+ that is registered at the PaneController.
+*/
+class BasicPaneFactory::PaneDescriptor
+{
+public:
+ OUString msPaneURL;
+ Reference<XResource> mxPane;
+ PaneId mePaneId;
+ /** The mbReleased flag is set when the pane has been released. Some
+ panes are just hidden and destroyed. When the pane is reused this
+ flag is reset.
+ */
+ bool mbIsReleased;
+
+ bool CompareURL(std::u16string_view rsPaneURL) const { return msPaneURL == rsPaneURL; }
+ bool ComparePane(const Reference<XResource>& rxPane) const { return mxPane == rxPane; }
+};
+
+class BasicPaneFactory::PaneContainer
+ : public ::std::vector<PaneDescriptor>
+{
+public:
+ PaneContainer() {}
+};
+
+//===== PaneFactory ===========================================================
+
+BasicPaneFactory::BasicPaneFactory (
+ const Reference<XComponentContext>& rxContext)
+ : mxComponentContext(rxContext),
+ mpViewShellBase(nullptr),
+ mpPaneContainer(new PaneContainer)
+{
+}
+
+BasicPaneFactory::~BasicPaneFactory()
+{
+}
+
+void BasicPaneFactory::disposing(std::unique_lock<std::mutex>&)
+{
+ Reference<XConfigurationController> xCC (mxConfigurationControllerWeak);
+ if (xCC.is())
+ {
+ xCC->removeResourceFactoryForReference(this);
+ xCC->removeConfigurationChangeListener(this);
+ mxConfigurationControllerWeak.clear();
+ }
+
+ for (const auto& rDescriptor : *mpPaneContainer)
+ {
+ if (rDescriptor.mbIsReleased)
+ {
+ Reference<XComponent> xComponent (rDescriptor.mxPane, UNO_QUERY);
+ if (xComponent.is())
+ {
+ xComponent->removeEventListener(this);
+ xComponent->dispose();
+ }
+ }
+ }
+}
+
+void SAL_CALL BasicPaneFactory::initialize (const Sequence<Any>& aArguments)
+{
+ if (!aArguments.hasElements())
+ return;
+
+ try
+ {
+ // Get the XController from the first argument.
+ Reference<frame::XController> xController (aArguments[0], UNO_QUERY_THROW);
+
+ // Tunnel through the controller to obtain access to the ViewShellBase.
+ try
+ {
+ Reference<lang::XUnoTunnel> xTunnel (xController, UNO_QUERY_THROW);
+ if (auto pController = comphelper::getFromUnoTunnel<DrawController>(xTunnel))
+ mpViewShellBase = pController->GetViewShellBase();
+ }
+ catch(RuntimeException&)
+ {}
+
+ Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW);
+ Reference<XConfigurationController> xCC (xCM->getConfigurationController());
+ mxConfigurationControllerWeak = xCC;
+
+ // Add pane factories for the two left panes (one for Impress and one for
+ // Draw) and the center pane.
+ if (xController.is() && xCC.is())
+ {
+ PaneDescriptor aDescriptor;
+ aDescriptor.msPaneURL = FrameworkHelper::msCenterPaneURL;
+ aDescriptor.mePaneId = CenterPaneId;
+ aDescriptor.mbIsReleased = false;
+ mpPaneContainer->push_back(aDescriptor);
+ xCC->addResourceFactory(aDescriptor.msPaneURL, this);
+
+ aDescriptor.msPaneURL = FrameworkHelper::msFullScreenPaneURL;
+ aDescriptor.mePaneId = FullScreenPaneId;
+ mpPaneContainer->push_back(aDescriptor);
+ xCC->addResourceFactory(aDescriptor.msPaneURL, this);
+
+ aDescriptor.msPaneURL = FrameworkHelper::msLeftImpressPaneURL;
+ aDescriptor.mePaneId = LeftImpressPaneId;
+ mpPaneContainer->push_back(aDescriptor);
+ xCC->addResourceFactory(aDescriptor.msPaneURL, this);
+
+ aDescriptor.msPaneURL = FrameworkHelper::msLeftDrawPaneURL;
+ aDescriptor.mePaneId = LeftDrawPaneId;
+ mpPaneContainer->push_back(aDescriptor);
+ xCC->addResourceFactory(aDescriptor.msPaneURL, this);
+ }
+
+ // Register as configuration change listener.
+ if (xCC.is())
+ {
+ xCC->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateStartEvent,
+ Any(gnConfigurationUpdateStartEvent));
+ xCC->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ Any(gnConfigurationUpdateEndEvent));
+ }
+ }
+ catch (RuntimeException&)
+ {
+ Reference<XConfigurationController> xCC (mxConfigurationControllerWeak);
+ if (xCC.is())
+ xCC->removeResourceFactoryForReference(this);
+ }
+}
+
+//===== XPaneFactory ==========================================================
+
+Reference<XResource> SAL_CALL BasicPaneFactory::createResource (
+ const Reference<XResourceId>& rxPaneId)
+{
+ ThrowIfDisposed();
+
+ Reference<XResource> xPane;
+
+ // Based on the ResourceURL of the given ResourceId look up the
+ // corresponding factory descriptor.
+ PaneContainer::iterator iDescriptor (
+ ::std::find_if (
+ mpPaneContainer->begin(),
+ mpPaneContainer->end(),
+ [&] (PaneDescriptor const& rPane) {
+ return rPane.CompareURL(rxPaneId->getResourceURL());
+ } ));
+
+ if (iDescriptor == mpPaneContainer->end())
+ {
+ // The requested pane can not be created by any of the factories
+ // managed by the called BasicPaneFactory object.
+ throw lang::IllegalArgumentException("BasicPaneFactory::createPane() called for unknown resource id",
+ nullptr,
+ 0);
+ }
+
+ if (iDescriptor->mxPane.is())
+ {
+ // The pane has already been created and is still active (has
+ // not yet been released). This should not happen.
+ xPane = iDescriptor->mxPane;
+ }
+ else
+ {
+ // Create a new pane.
+ switch (iDescriptor->mePaneId)
+ {
+ case CenterPaneId:
+ xPane = CreateFrameWindowPane(rxPaneId);
+ break;
+
+ case FullScreenPaneId:
+ xPane = CreateFullScreenPane(mxComponentContext, rxPaneId);
+ break;
+
+ case LeftImpressPaneId:
+ case LeftDrawPaneId:
+ xPane = CreateChildWindowPane(
+ rxPaneId,
+ *iDescriptor);
+ break;
+ }
+ iDescriptor->mxPane = xPane;
+
+ // Listen for the pane being disposed.
+ Reference<lang::XComponent> xComponent (xPane, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(this);
+ }
+ iDescriptor->mbIsReleased = false;
+
+
+ return xPane;
+}
+
+void SAL_CALL BasicPaneFactory::releaseResource (
+ const Reference<XResource>& rxPane)
+{
+ ThrowIfDisposed();
+
+ // Based on the given XPane reference look up the corresponding factory
+ // descriptor.
+ PaneContainer::iterator iDescriptor (
+ ::std::find_if(
+ mpPaneContainer->begin(),
+ mpPaneContainer->end(),
+ [&] (PaneDescriptor const& rPane) { return rPane.ComparePane(rxPane); } ));
+
+ if (iDescriptor == mpPaneContainer->end())
+ {
+ // The given XPane reference is either empty or the pane was not
+ // created by any of the factories managed by the called
+ // BasicPaneFactory object.
+ throw lang::IllegalArgumentException("BasicPaneFactory::releasePane() called for pane that was not created by same factory.",
+ nullptr,
+ 0);
+ }
+
+ // The given pane was created by one of the factories. Child
+ // windows are just hidden and will be reused when requested later.
+ // Other windows are disposed and their reference is reset so that
+ // on the next createPane() call for the same pane type the pane is
+ // created anew.
+ ChildWindowPane* pChildWindowPane = dynamic_cast<ChildWindowPane*>(rxPane.get());
+ if (pChildWindowPane != nullptr)
+ {
+ iDescriptor->mbIsReleased = true;
+ pChildWindowPane->Hide();
+ }
+ else
+ {
+ iDescriptor->mxPane = nullptr;
+ Reference<XComponent> xComponent (rxPane, UNO_QUERY);
+ if (xComponent.is())
+ {
+ // We are disposing the pane and do not have to be informed of
+ // that.
+ xComponent->removeEventListener(this);
+ xComponent->dispose();
+ }
+ }
+
+}
+
+//===== XConfigurationChangeListener ==========================================
+
+void SAL_CALL BasicPaneFactory::notifyConfigurationChange (
+ const ConfigurationChangeEvent& /* rEvent */ )
+{
+ // FIXME: nothing to do
+}
+
+//===== lang::XEventListener ==================================================
+
+void SAL_CALL BasicPaneFactory::disposing (
+ const lang::EventObject& rEventObject)
+{
+ if (mxConfigurationControllerWeak.get() == rEventObject.Source)
+ {
+ mxConfigurationControllerWeak.clear();
+ }
+ else
+ {
+ // Has one of the panes been disposed? If so, then release the
+ // reference to that pane, but not the pane descriptor.
+ Reference<XResource> xPane (rEventObject.Source, UNO_QUERY);
+ PaneContainer::iterator iDescriptor (
+ ::std::find_if (
+ mpPaneContainer->begin(),
+ mpPaneContainer->end(),
+ [&] (PaneDescriptor const& rPane) { return rPane.ComparePane(xPane); } ));
+ if (iDescriptor != mpPaneContainer->end())
+ {
+ iDescriptor->mxPane = nullptr;
+ }
+ }
+}
+
+Reference<XResource> BasicPaneFactory::CreateFrameWindowPane (
+ const Reference<XResourceId>& rxPaneId)
+{
+ Reference<XResource> xPane;
+
+ if (mpViewShellBase != nullptr)
+ {
+ xPane = new FrameWindowPane(rxPaneId, mpViewShellBase->GetViewWindow());
+ }
+
+ return xPane;
+}
+
+Reference<XResource> BasicPaneFactory::CreateFullScreenPane (
+ const Reference<XComponentContext>& rxComponentContext,
+ const Reference<XResourceId>& rxPaneId)
+{
+ Reference<XResource> xPane (
+ new FullScreenPane(
+ rxComponentContext,
+ rxPaneId,
+ mpViewShellBase->GetViewWindow()));
+
+ return xPane;
+}
+
+Reference<XResource> BasicPaneFactory::CreateChildWindowPane (
+ const Reference<XResourceId>& rxPaneId,
+ const PaneDescriptor& rDescriptor)
+{
+ Reference<XResource> xPane;
+
+ if (mpViewShellBase != nullptr)
+ {
+ // Create the corresponding shell and determine the id of the child window.
+ sal_uInt16 nChildWindowId = 0;
+ ::std::unique_ptr<SfxShell> pShell;
+ switch (rDescriptor.mePaneId)
+ {
+ case LeftImpressPaneId:
+ pShell.reset(new LeftImpressPaneShell());
+ nChildWindowId = ::sd::LeftPaneImpressChildWindow::GetChildWindowId();
+ break;
+
+ case LeftDrawPaneId:
+ pShell.reset(new LeftDrawPaneShell());
+ nChildWindowId = ::sd::LeftPaneDrawChildWindow::GetChildWindowId();
+ break;
+
+ default:
+ break;
+ }
+
+ // With shell and child window id create the ChildWindowPane
+ // wrapper.
+ if (pShell != nullptr)
+ {
+ xPane = new ChildWindowPane(
+ rxPaneId,
+ nChildWindowId,
+ *mpViewShellBase,
+ std::move(pShell));
+ }
+ }
+
+ return xPane;
+}
+
+void BasicPaneFactory::ThrowIfDisposed() const
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("BasicPaneFactory object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_BasicPaneFactory_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::BasicPaneFactory(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicPaneFactory.hxx b/sd/source/ui/framework/factories/BasicPaneFactory.hxx
new file mode 100644
index 000000000..317776e48
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicPaneFactory.hxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XResourceFactory.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/compbase.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <memory>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace sd {
+
+class ViewShellBase;
+}
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::lang::XInitialization,
+ css::drawing::framework::XResourceFactory,
+ css::drawing::framework::XConfigurationChangeListener
+ > BasicPaneFactoryInterfaceBase;
+
+/** This factory provides the frequently used standard panes
+ private:resource/pane/CenterPane
+ private:resource/pane/FullScreenPane
+ private:resource/pane/LeftImpressPane
+ private:resource/pane/LeftDrawPane
+ There are two left panes because this is (seems to be) the only way to
+ show different titles for the left pane in Draw and Impress.
+*/
+class BasicPaneFactory
+ : public BasicPaneFactoryInterfaceBase
+{
+public:
+ explicit BasicPaneFactory (
+ const css::uno::Reference<css::uno::XComponentContext>& rxContext);
+ virtual ~BasicPaneFactory() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence<css::uno::Any>& aArguments) override;
+
+ // XResourceFactory
+
+ virtual css::uno::Reference<css::drawing::framework::XResource>
+ SAL_CALL createResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId) override;
+
+ virtual void SAL_CALL
+ releaseResource (
+ const css::uno::Reference<css::drawing::framework::XResource>& rxPane) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // lang::XEventListener
+
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEventObject) override;
+
+private:
+ css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
+ css::uno::WeakReference<css::drawing::framework::XConfigurationController>
+ mxConfigurationControllerWeak;
+ ViewShellBase* mpViewShellBase;
+ class PaneDescriptor;
+ class PaneContainer;
+ std::unique_ptr<PaneContainer> mpPaneContainer;
+
+ /** Create a new instance of FrameWindowPane.
+ @param rPaneId
+ There is only one frame window so this id is just checked to
+ have the correct value.
+ */
+ css::uno::Reference<css::drawing::framework::XResource>
+ CreateFrameWindowPane (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId);
+
+ /** Create a new pane that represents the center pane in full screen
+ mode.
+ */
+ css::uno::Reference<css::drawing::framework::XResource>
+ CreateFullScreenPane (
+ const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId);
+
+ /** Create a new instance of ChildWindowPane.
+ @param rPaneId
+ The ResourceURL member defines which side pane to create.
+ */
+ css::uno::Reference<css::drawing::framework::XResource>
+ CreateChildWindowPane (
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxPaneId,
+ const PaneDescriptor& rDescriptor);
+
+ /// @throws css::lang::DisposedException
+ void ThrowIfDisposed() const;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicToolBarFactory.cxx b/sd/source/ui/framework/factories/BasicToolBarFactory.cxx
new file mode 100644
index 000000000..af79a88ea
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicToolBarFactory.cxx
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "BasicToolBarFactory.hxx"
+
+#include <ViewTabBar.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <unotools/mediadescriptor.hxx>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+//===== BasicToolBarFactory ===================================================
+
+BasicToolBarFactory::BasicToolBarFactory ()
+{
+}
+
+BasicToolBarFactory::~BasicToolBarFactory()
+{
+}
+
+void BasicToolBarFactory::disposing(std::unique_lock<std::mutex>&)
+{
+ Shutdown();
+}
+
+void BasicToolBarFactory::Shutdown()
+{
+ Reference<lang::XComponent> xComponent (mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(static_cast<lang::XEventListener*>(this));
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->removeResourceFactoryForReference(this);
+ mxConfigurationController = nullptr;
+ }
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL BasicToolBarFactory::initialize (const Sequence<Any>& aArguments)
+{
+ if (!aArguments.hasElements())
+ return;
+
+ try
+ {
+ // Get the XController from the first argument.
+ mxController.set(aArguments[0], UNO_QUERY_THROW);
+
+ utl::MediaDescriptor aDescriptor (mxController->getModel()->getArgs());
+ if ( ! aDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_PREVIEW,
+ false))
+ {
+ // Register the factory for its supported tool bars.
+ Reference<XControllerManager> xControllerManager(mxController, UNO_QUERY_THROW);
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->addResourceFactory(
+ FrameworkHelper::msViewTabBarURL, this);
+ }
+
+ Reference<lang::XComponent> xComponent (mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(static_cast<lang::XEventListener*>(this));
+ }
+ else
+ {
+ // The view shell is in preview mode and thus does not need
+ // the view tab bar.
+ mxConfigurationController = nullptr;
+ }
+ }
+ catch (RuntimeException&)
+ {
+ Shutdown();
+ throw;
+ }
+}
+
+//----- lang::XEventListener --------------------------------------------------
+
+void SAL_CALL BasicToolBarFactory::disposing (
+ const lang::EventObject& rEventObject)
+{
+ if (rEventObject.Source == mxConfigurationController)
+ mxConfigurationController = nullptr;
+}
+
+//===== XPaneFactory ==========================================================
+
+Reference<XResource> SAL_CALL BasicToolBarFactory::createResource (
+ const Reference<XResourceId>& rxToolBarId)
+{
+ ThrowIfDisposed();
+
+ if (rxToolBarId->getResourceURL() != FrameworkHelper::msViewTabBarURL)
+ throw lang::IllegalArgumentException();
+
+ Reference<XResource> xToolBar = new ViewTabBar(rxToolBarId, mxController);
+ return xToolBar;
+}
+
+void SAL_CALL BasicToolBarFactory::releaseResource (
+ const Reference<XResource>& rxToolBar)
+{
+ ThrowIfDisposed();
+
+ Reference<XComponent> xComponent (rxToolBar, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+}
+
+void BasicToolBarFactory::ThrowIfDisposed() const
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("BasicToolBarFactory object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+} // end of namespace sd::framework
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_BasicToolBarFactory_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::BasicToolBarFactory);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicToolBarFactory.hxx b/sd/source/ui/framework/factories/BasicToolBarFactory.hxx
new file mode 100644
index 000000000..fdaf92788
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicToolBarFactory.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/drawing/framework/XResourceFactory.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::frame { class XController; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XResourceFactory,
+ css::lang::XInitialization,
+ css::lang::XEventListener
+ > BasicToolBarFactoryInterfaceBase;
+
+/** This factory provides some of the frequently used tool bars:
+ private:resource/toolbar/ViewTabBar
+*/
+class BasicToolBarFactory
+ : public BasicToolBarFactoryInterfaceBase
+{
+public:
+ BasicToolBarFactory ();
+ virtual ~BasicToolBarFactory() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // ToolBarFactory
+
+ virtual css::uno::Reference<css::drawing::framework::XResource> SAL_CALL
+ createResource (
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxToolBarId) override;
+
+ virtual void SAL_CALL
+ releaseResource (
+ const css::uno::Reference<css::drawing::framework::XResource>&
+ rxToolBar) override;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence<css::uno::Any>& aArguments) override;
+
+ // lang::XEventListener
+
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEventObject) override;
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfigurationController> mxConfigurationController;
+ css::uno::Reference<css::frame::XController> mxController;
+
+ void Shutdown();
+
+ /// @throws css::lang::DisposedException
+ void ThrowIfDisposed() const;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicViewFactory.cxx b/sd/source/ui/framework/factories/BasicViewFactory.cxx
new file mode 100644
index 000000000..425cb4446
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicViewFactory.cxx
@@ -0,0 +1,518 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "BasicViewFactory.hxx"
+
+#include <framework/ViewShellWrapper.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <framework/Pane.hxx>
+#include <DrawController.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <GraphicViewShell.hxx>
+#include <OutlineViewShell.hxx>
+#include <PresentationViewShell.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <FrameView.hxx>
+#include <Window.hxx>
+
+#include <comphelper/servicehelper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/wrkwin.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace sd::framework {
+
+//===== ViewDescriptor ========================================================
+
+class BasicViewFactory::ViewDescriptor
+{
+public:
+ Reference<XResource> mxView;
+ std::shared_ptr<sd::ViewShell> mpViewShell;
+ Reference<XResourceId> mxViewId;
+ static bool CompareView (const std::shared_ptr<ViewDescriptor>& rpDescriptor,
+ const Reference<XResource>& rxView)
+ { return rpDescriptor->mxView.get() == rxView.get(); }
+};
+
+//===== BasicViewFactory::ViewShellContainer ==================================
+
+class BasicViewFactory::ViewShellContainer
+ : public ::std::vector<std::shared_ptr<ViewDescriptor> >
+{
+public:
+ ViewShellContainer() {};
+};
+
+class BasicViewFactory::ViewCache
+ : public ::std::vector<std::shared_ptr<ViewDescriptor> >
+{
+public:
+ ViewCache() {};
+};
+
+//===== ViewFactory ===========================================================
+
+BasicViewFactory::BasicViewFactory ()
+ : mpViewShellContainer(new ViewShellContainer()),
+ mpBase(nullptr),
+ mpFrameView(nullptr),
+ mpWindow(VclPtr<WorkWindow>::Create(nullptr,WB_STDWORK)),
+ mpViewCache(std::make_shared<ViewCache>()),
+ mxLocalPane(new Pane(Reference<XResourceId>(), mpWindow.get()))
+{
+}
+
+BasicViewFactory::~BasicViewFactory()
+{
+}
+
+void BasicViewFactory::disposing(std::unique_lock<std::mutex>&)
+{
+ // Disconnect from the frame view.
+ if (mpFrameView != nullptr)
+ {
+ mpFrameView->Disconnect();
+ mpFrameView = nullptr;
+ }
+
+ // Release the view cache.
+ for (const auto& rxView : *mpViewCache)
+ {
+ ReleaseView(rxView, true);
+ }
+
+ // Release the view shell container. At this point no one other than us
+ // should hold references to the view shells (at the moment this is a
+ // trivial requirement, because no one other than us holds a shared
+ // pointer).
+ // ViewShellContainer::const_iterator iView;
+ for (const auto& rxView : *mpViewShellContainer)
+ {
+ OSL_ASSERT(rxView->mpViewShell.use_count() == 1);
+ }
+ mpViewShellContainer.reset();
+}
+
+Reference<XResource> SAL_CALL BasicViewFactory::createResource (
+ const Reference<XResourceId>& rxViewId)
+{
+ Reference<XResource> xView;
+ const bool bIsCenterPane (
+ rxViewId->isBoundToURL(FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT));
+
+ // Get the pane for the anchor URL.
+ Reference<XPane> xPane;
+ if (mxConfigurationController.is())
+ xPane.set(mxConfigurationController->getResource(rxViewId->getAnchor()), UNO_QUERY);
+
+ // For main views use the frame view of the last main view.
+ ::sd::FrameView* pFrameView = nullptr;
+ if (xPane.is() && bIsCenterPane)
+ {
+ pFrameView = mpFrameView;
+ }
+
+ // Get Window pointer for XWindow of the pane.
+ vcl::Window* pWindow = nullptr;
+ if (xPane.is())
+ pWindow = VCLUnoHelper::GetWindow(xPane->getWindow());
+
+ // Get the view frame.
+ SfxViewFrame* pFrame = nullptr;
+ if (mpBase != nullptr)
+ pFrame = mpBase->GetViewFrame();
+
+ if (pFrame != nullptr && mpBase!=nullptr && pWindow!=nullptr)
+ {
+ // Try to get the view from the cache.
+ std::shared_ptr<ViewDescriptor> pDescriptor (GetViewFromCache(rxViewId, xPane));
+
+ // When the requested view is not in the cache then create a new view.
+ if (pDescriptor == nullptr)
+ {
+ pDescriptor = CreateView(rxViewId, *pFrame, *pWindow, xPane, pFrameView, bIsCenterPane);
+ }
+
+ if (pDescriptor != nullptr)
+ xView = pDescriptor->mxView;
+
+ mpViewShellContainer->push_back(pDescriptor);
+
+ if (bIsCenterPane)
+ ActivateCenterView(pDescriptor);
+ else
+ pWindow->Resize();
+ }
+
+ return xView;
+}
+
+void SAL_CALL BasicViewFactory::releaseResource (const Reference<XResource>& rxView)
+{
+ if ( ! rxView.is())
+ throw lang::IllegalArgumentException();
+
+ if (!rxView.is() || !mpBase)
+ return;
+
+ ViewShellContainer::iterator iViewShell (
+ ::std::find_if(
+ mpViewShellContainer->begin(),
+ mpViewShellContainer->end(),
+ [&] (std::shared_ptr<ViewDescriptor> const& pVD) {
+ return ViewDescriptor::CompareView(pVD, rxView);
+ } ));
+ if (iViewShell == mpViewShellContainer->end())
+ {
+ throw lang::IllegalArgumentException();
+ }
+
+ std::shared_ptr<ViewShell> pViewShell ((*iViewShell)->mpViewShell);
+
+ if ((*iViewShell)->mxViewId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
+ {
+ // Obtain a pointer to and connect to the frame view of the
+ // view. The next view, that is created, will be
+ // initialized with this frame view.
+ if (mpFrameView == nullptr)
+ {
+ mpFrameView = pViewShell->GetFrameView();
+ if (mpFrameView)
+ mpFrameView->Connect();
+ }
+
+ // With the view in the center pane the sub controller is
+ // released, too.
+ mpBase->GetDrawController().SetSubController(
+ Reference<drawing::XDrawSubController>());
+
+ SfxViewShell* pSfxViewShell = pViewShell->GetViewShell();
+ if (pSfxViewShell != nullptr)
+ pSfxViewShell->DisconnectAllClients();
+ }
+
+ ReleaseView(*iViewShell, false);
+
+ mpViewShellContainer->erase(iViewShell);
+}
+
+void SAL_CALL BasicViewFactory::initialize (const Sequence<Any>& aArguments)
+{
+ if (!aArguments.hasElements())
+ return;
+
+ try
+ {
+ // Get the XController from the first argument.
+ Reference<frame::XController> xController (aArguments[0], UNO_QUERY_THROW);
+
+ // Tunnel through the controller to obtain a ViewShellBase.
+ Reference<lang::XUnoTunnel> xTunnel (xController, UNO_QUERY_THROW);
+ ::sd::DrawController* pController = comphelper::getFromUnoTunnel<sd::DrawController>(xTunnel);
+ if (pController != nullptr)
+ mpBase = pController->GetViewShellBase();
+
+ // Register the factory for its supported views.
+ Reference<XControllerManager> xCM (xController,UNO_QUERY_THROW);
+ mxConfigurationController = xCM->getConfigurationController();
+ if ( ! mxConfigurationController.is())
+ throw RuntimeException();
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msImpressViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msDrawViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msOutlineViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msNotesViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msHandoutViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msPresentationViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msSlideSorterURL, this);
+ }
+ catch (RuntimeException&)
+ {
+ mpBase = nullptr;
+ if (mxConfigurationController.is())
+ mxConfigurationController->removeResourceFactoryForReference(this);
+ throw;
+ }
+}
+
+std::shared_ptr<BasicViewFactory::ViewDescriptor> BasicViewFactory::CreateView (
+ const Reference<XResourceId>& rxViewId,
+ SfxViewFrame& rFrame,
+ vcl::Window& rWindow,
+ const Reference<XPane>& rxPane,
+ FrameView* pFrameView,
+ const bool bIsCenterPane)
+{
+ auto pDescriptor = std::make_shared<ViewDescriptor>();
+
+ pDescriptor->mpViewShell = CreateViewShell(
+ rxViewId,
+ rFrame,
+ rWindow,
+ pFrameView);
+ pDescriptor->mxViewId = rxViewId;
+
+ if (pDescriptor->mpViewShell != nullptr)
+ {
+ pDescriptor->mpViewShell->Init(bIsCenterPane);
+ mpBase->GetViewShellManager()->ActivateViewShell(pDescriptor->mpViewShell.get());
+
+ Reference<awt::XWindow> xWindow(rxPane->getWindow());
+ rtl::Reference<ViewShellWrapper> wrapper(new ViewShellWrapper(
+ pDescriptor->mpViewShell,
+ rxViewId,
+ xWindow));
+
+ // register ViewShellWrapper on pane window
+ if (xWindow.is())
+ {
+ xWindow->addWindowListener(wrapper);
+ if (pDescriptor->mpViewShell != nullptr)
+ {
+ pDescriptor->mpViewShell->Resize();
+ }
+ }
+
+ pDescriptor->mxView = wrapper.get();
+ }
+
+ return pDescriptor;
+}
+
+std::shared_ptr<ViewShell> BasicViewFactory::CreateViewShell (
+ const Reference<XResourceId>& rxViewId,
+ SfxViewFrame& rFrame,
+ vcl::Window& rWindow,
+ FrameView* pFrameView)
+{
+ std::shared_ptr<ViewShell> pViewShell;
+ const OUString& rsViewURL (rxViewId->getResourceURL());
+ if (rsViewURL == FrameworkHelper::msImpressViewURL)
+ {
+ pViewShell =
+ std::make_shared<DrawViewShell>(
+ *mpBase,
+ &rWindow,
+ PageKind::Standard,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("impress_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msDrawViewURL)
+ {
+ pViewShell = std::shared_ptr<GraphicViewShell>(
+ new GraphicViewShell(*mpBase, &rWindow, pFrameView),
+ o3tl::default_delete<GraphicViewShell>());
+ pViewShell->GetContentWindow()->set_id("draw_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msOutlineViewURL)
+ {
+ pViewShell =
+ std::make_shared<OutlineViewShell>(
+ &rFrame,
+ *mpBase,
+ &rWindow,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("outline_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msNotesViewURL)
+ {
+ pViewShell =
+ std::make_shared<DrawViewShell>(
+ *mpBase,
+ &rWindow,
+ PageKind::Notes,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("notes_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msHandoutViewURL)
+ {
+ pViewShell =
+ std::make_shared<DrawViewShell>(
+ *mpBase,
+ &rWindow,
+ PageKind::Handout,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("handout_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msPresentationViewURL)
+ {
+ pViewShell =
+ std::make_shared<PresentationViewShell>(
+ *mpBase,
+ &rWindow,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("presentation_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msSlideSorterURL)
+ {
+ pViewShell = ::sd::slidesorter::SlideSorterViewShell::Create (
+ &rFrame,
+ *mpBase,
+ &rWindow,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("slidesorter");
+ }
+
+ return pViewShell;
+}
+
+void BasicViewFactory::ReleaseView (
+ const std::shared_ptr<ViewDescriptor>& rpDescriptor,
+ bool bDoNotCache)
+{
+ bool bIsCacheable (!bDoNotCache && IsCacheable(rpDescriptor));
+
+ if (bIsCacheable)
+ {
+ Reference<XRelocatableResource> xResource (rpDescriptor->mxView, UNO_QUERY);
+ if (xResource.is())
+ {
+ if (mxLocalPane.is())
+ if (xResource->relocateToAnchor(mxLocalPane))
+ mpViewCache->push_back(rpDescriptor);
+ else
+ bIsCacheable = false;
+ else
+ bIsCacheable = false;
+ }
+ else
+ {
+ bIsCacheable = false;
+ }
+ }
+
+ if ( ! bIsCacheable)
+ {
+ // Shut down the current view shell.
+ rpDescriptor->mpViewShell->Shutdown ();
+ mpBase->GetDocShell()->Disconnect(rpDescriptor->mpViewShell.get());
+ mpBase->GetViewShellManager()->DeactivateViewShell(rpDescriptor->mpViewShell.get());
+
+ Reference<XComponent> xComponent (rpDescriptor->mxView, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+ }
+}
+
+bool BasicViewFactory::IsCacheable (const std::shared_ptr<ViewDescriptor>& rpDescriptor)
+{
+ bool bIsCacheable (false);
+
+ Reference<XRelocatableResource> xResource (rpDescriptor->mxView, UNO_QUERY);
+ if (xResource.is())
+ {
+ static ::std::vector<Reference<XResourceId> > s_aCacheableResources = [&]()
+ {
+ ::std::vector<Reference<XResourceId> > tmp;
+ FrameworkHelper::Instance(*mpBase);
+
+ // The slide sorter and the task panel are cacheable and relocatable.
+ tmp.push_back(FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msSlideSorterURL, FrameworkHelper::msLeftDrawPaneURL));
+ tmp.push_back(FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msSlideSorterURL, FrameworkHelper::msLeftImpressPaneURL));
+ return tmp;
+ }();
+
+ bIsCacheable = std::any_of(s_aCacheableResources.begin(), s_aCacheableResources.end(),
+ [&rpDescriptor](const Reference<XResourceId>& rxId) { return rxId->compareTo(rpDescriptor->mxViewId) == 0; });
+ }
+
+ return bIsCacheable;
+}
+
+std::shared_ptr<BasicViewFactory::ViewDescriptor> BasicViewFactory::GetViewFromCache (
+ const Reference<XResourceId>& rxViewId,
+ const Reference<XPane>& rxPane)
+{
+ std::shared_ptr<ViewDescriptor> pDescriptor;
+
+ // Search for the requested view in the cache.
+ ViewCache::iterator iEntry = std::find_if(mpViewCache->begin(), mpViewCache->end(),
+ [&rxViewId](const ViewCache::value_type& rxEntry) { return rxEntry->mxViewId->compareTo(rxViewId) == 0; });
+ if (iEntry != mpViewCache->end())
+ {
+ pDescriptor = *iEntry;
+ mpViewCache->erase(iEntry);
+ }
+
+ // When the view has been found then relocate it to the given pane and
+ // remove it from the cache.
+ if (pDescriptor != nullptr)
+ {
+ bool bRelocationSuccessful (false);
+ Reference<XRelocatableResource> xResource (pDescriptor->mxView, UNO_QUERY);
+ if (xResource.is() && rxPane.is())
+ {
+ if (xResource->relocateToAnchor(rxPane))
+ bRelocationSuccessful = true;
+ }
+
+ if ( ! bRelocationSuccessful)
+ {
+ ReleaseView(pDescriptor, true);
+ pDescriptor.reset();
+ }
+ }
+
+ return pDescriptor;
+}
+
+void BasicViewFactory::ActivateCenterView (
+ const std::shared_ptr<ViewDescriptor>& rpDescriptor)
+{
+ mpBase->GetDocShell()->Connect(rpDescriptor->mpViewShell.get());
+
+ // During the creation of the new sub-shell, resize requests were not
+ // forwarded to it because it was not yet registered. Therefore, we
+ // have to request a resize now.
+ rpDescriptor->mpViewShell->UIFeatureChanged();
+ if (mpBase->GetDocShell()->IsInPlaceActive())
+ mpBase->GetViewFrame()->Resize(true);
+
+ mpBase->GetDrawController().SetSubController(
+ rpDescriptor->mpViewShell->CreateSubController());
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_BasicViewFactory_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::BasicViewFactory);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicViewFactory.hxx b/sd/source/ui/framework/factories/BasicViewFactory.hxx
new file mode 100644
index 000000000..ccd5cbbda
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicViewFactory.hxx
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XResourceFactory.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+
+#include <comphelper/compbase.hxx>
+
+#include <vcl/vclptr.hxx>
+#include <memory>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XPane; }
+
+namespace sd {
+class ViewShell;
+class ViewShellBase;
+class FrameView;
+}
+class SfxViewFrame;
+namespace vcl { class Window; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XResourceFactory,
+ css::lang::XInitialization
+ > BasicViewFactoryInterfaceBase;
+
+/** Factory for the frequently used standard views of the drawing framework:
+ private:resource/view/
+ private:resource/view/ImpressView
+ private:resource/view/GraphicView
+ private:resource/view/OutlineView
+ private:resource/view/NotesView
+ private:resource/view/HandoutView
+ private:resource/view/SlideSorter
+ private:resource/view/PresentationView
+ private:resource/view/TaskPane
+ For some views in some panes this class also acts as a cache.
+*/
+class BasicViewFactory
+ : public BasicViewFactoryInterfaceBase
+{
+public:
+ BasicViewFactory ();
+ virtual ~BasicViewFactory() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XViewFactory
+
+ virtual css::uno::Reference<css::drawing::framework::XResource>
+ SAL_CALL createResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId) override;
+
+ virtual void SAL_CALL releaseResource (
+ const css::uno::Reference<css::drawing::framework::XResource>& xView) override;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence<css::uno::Any>& aArguments) override;
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+ class ViewDescriptor;
+ class ViewShellContainer;
+ std::unique_ptr<ViewShellContainer> mpViewShellContainer;
+ ViewShellBase* mpBase;
+ FrameView* mpFrameView;
+
+ class ViewCache;
+ ScopedVclPtr<vcl::Window> mpWindow;
+ std::shared_ptr<ViewCache> mpViewCache;
+
+ css::uno::Reference<css::drawing::framework::XPane> mxLocalPane;
+
+ std::shared_ptr<ViewDescriptor> CreateView (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId,
+ SfxViewFrame& rFrame,
+ vcl::Window& rWindow,
+ const css::uno::Reference<css::drawing::framework::XPane>& rxPane,
+ FrameView* pFrameView,
+ const bool bIsCenterView);
+
+ std::shared_ptr<ViewShell> CreateViewShell (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId,
+ SfxViewFrame& rFrame,
+ vcl::Window& rWindow,
+ FrameView* pFrameView);
+
+ void ActivateCenterView (
+ const std::shared_ptr<ViewDescriptor>& rpDescriptor);
+
+ void ReleaseView (
+ const std::shared_ptr<ViewDescriptor>& rpDescriptor,
+ bool bDoNotCache);
+
+ bool IsCacheable (
+ const std::shared_ptr<ViewDescriptor>& rpDescriptor);
+
+ std::shared_ptr<ViewDescriptor> GetViewFromCache (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId,
+ const css::uno::Reference<css::drawing::framework::XPane>& rxPane);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/ChildWindowPane.cxx b/sd/source/ui/framework/factories/ChildWindowPane.cxx
new file mode 100644
index 000000000..136f6fcb7
--- /dev/null
+++ b/sd/source/ui/framework/factories/ChildWindowPane.cxx
@@ -0,0 +1,219 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <utility>
+
+#include "ChildWindowPane.hxx"
+
+#include <PaneDockingWindow.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <sfx2/viewfrm.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+ChildWindowPane::ChildWindowPane (
+ const Reference<XResourceId>& rxPaneId,
+ sal_uInt16 nChildWindowId,
+ ViewShellBase& rViewShellBase,
+ ::std::unique_ptr<SfxShell> && pShell)
+ : ChildWindowPaneInterfaceBase(rxPaneId,nullptr),
+ mnChildWindowId(nChildWindowId),
+ mrViewShellBase(rViewShellBase),
+ mpShell(std::move(pShell)),
+ mbHasBeenActivated(false)
+{
+ mrViewShellBase.GetViewShellManager()->ActivateShell(mpShell.get());
+
+ SfxViewFrame* pViewFrame = mrViewShellBase.GetViewFrame();
+ if (pViewFrame == nullptr)
+ return;
+
+ if (mrViewShellBase.IsActive())
+ {
+ if (pViewFrame->KnowsChildWindow(mnChildWindowId))
+ {
+ if (pViewFrame->HasChildWindow(mnChildWindowId))
+ {
+ // The ViewShellBase has already been activated. Make
+ // the child window visible as soon as possible.
+ pViewFrame->SetChildWindow(mnChildWindowId, true);
+ }
+ else
+ {
+ // The window is created asynchronously. Rely on the
+ // ConfigurationUpdater to try another update, and with
+ // that another request for this window, in a short
+ // time.
+ }
+ }
+ else
+ {
+ SAL_WARN("sd", "ChildWindowPane:not known");
+ }
+ }
+ else
+ {
+ // The ViewShellBase has not yet been activated. Hide the
+ // window and wait a little before it is made visible. See
+ // comments in the GetWindow() method for an explanation.
+ pViewFrame->SetChildWindow(mnChildWindowId, false);
+ }
+}
+
+ChildWindowPane::~ChildWindowPane()
+{
+}
+
+void ChildWindowPane::Hide()
+{
+ SfxViewFrame* pViewFrame = mrViewShellBase.GetViewFrame();
+ if (pViewFrame != nullptr)
+ if (pViewFrame->KnowsChildWindow(mnChildWindowId))
+ if (pViewFrame->HasChildWindow(mnChildWindowId))
+ pViewFrame->SetChildWindow(mnChildWindowId, false);
+
+ // Release the window because when the child window is shown again it
+ // may use a different window.
+ mxWindow = nullptr;
+}
+
+void SAL_CALL ChildWindowPane::disposing()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ mrViewShellBase.GetViewShellManager()->DeactivateShell(mpShell.get());
+ mpShell.reset();
+
+ if (mxWindow.is())
+ {
+ mxWindow->removeEventListener(this);
+ }
+
+ Pane::disposing();
+}
+
+vcl::Window* ChildWindowPane::GetWindow()
+{
+ do
+ {
+ if (mxWindow.is())
+ // Window already exists => nothing to do.
+ break;
+
+ // When the window is not yet present then obtain it only when the
+ // shell has already been activated. The activation is not
+ // necessary for the code to work properly but is used to optimize
+ // the layouting and displaying of the window. When it is made
+ // visible too early then some layouting seems to be made twice or at
+ // an inconvenient time and the overall process of initializing the
+ // Impress takes longer.
+ if (!mbHasBeenActivated && mpShell != nullptr && !mpShell->IsActive())
+ break;
+
+ mbHasBeenActivated = true;
+ SfxViewFrame* pViewFrame = mrViewShellBase.GetViewFrame();
+ if (pViewFrame == nullptr)
+ break;
+ // The view frame has to know the child window. This can be the
+ // case, when for example the document is in read-only mode: the
+ // task pane is then not available.
+ if ( ! pViewFrame->KnowsChildWindow(mnChildWindowId))
+ break;
+
+ pViewFrame->SetChildWindow(mnChildWindowId, true);
+ SfxChildWindow* pChildWindow = pViewFrame->GetChildWindow(mnChildWindowId);
+ if (pChildWindow == nullptr)
+ if (pViewFrame->HasChildWindow(mnChildWindowId))
+ {
+ // The child window is not yet visible. Ask the view frame
+ // to show it and try again to get access to the child
+ // window.
+ pViewFrame->ShowChildWindow(mnChildWindowId);
+ pChildWindow = pViewFrame->GetChildWindow(mnChildWindowId);
+ }
+
+ // When the child window is still not visible then we have to try later.
+ if (pChildWindow == nullptr)
+ break;
+
+ // From the child window get the docking window and from that the
+ // content window that is the container for the actual content.
+ PaneDockingWindow* pDockingWindow = dynamic_cast<PaneDockingWindow*>(
+ pChildWindow->GetWindow());
+ if (pDockingWindow == nullptr)
+ break;
+
+ // At last, we have access to the window and its UNO wrapper.
+ mpWindow = &pDockingWindow->GetContentWindow();
+ mxWindow = VCLUnoHelper::GetInterface(mpWindow);
+
+ // Register as window listener to be informed when the child window
+ // is hidden.
+ if (mxWindow.is())
+ mxWindow->addEventListener(this);
+ }
+ while (false);
+
+ return mpWindow;
+}
+
+Reference<awt::XWindow> SAL_CALL ChildWindowPane::getWindow()
+{
+ if (mpWindow == nullptr || ! mxWindow.is())
+ GetWindow();
+ return Pane::getWindow();
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2(
+ ChildWindowPane,
+ ChildWindowPaneInterfaceBase,
+ Pane);
+IMPLEMENT_FORWARD_XTYPEPROVIDER2(
+ ChildWindowPane,
+ ChildWindowPaneInterfaceBase,
+ Pane);
+
+//----- XEventListener --------------------------------------------------------
+
+void SAL_CALL ChildWindowPane::disposing (const lang::EventObject& rEvent)
+{
+ ThrowIfDisposed();
+
+ if (rEvent.Source == mxWindow)
+ {
+ // The window is gone but the pane remains alive. The next call to
+ // GetWindow() may create the window anew.
+ mxWindow = nullptr;
+ mpWindow = nullptr;
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/ChildWindowPane.hxx b/sd/source/ui/framework/factories/ChildWindowPane.hxx
new file mode 100644
index 000000000..082177757
--- /dev/null
+++ b/sd/source/ui/framework/factories/ChildWindowPane.hxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <framework/Pane.hxx>
+
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/uno3.hxx>
+#include <memory>
+
+class SfxShell;
+
+namespace sd { class ViewShellBase; }
+namespace com::sun::star::awt { class XWindow; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+
+namespace sd::framework {
+
+typedef ::cppu::ImplInheritanceHelper <
+ ::sd::framework::Pane,
+ css::lang::XEventListener
+ > ChildWindowPaneInterfaceBase;
+
+/** The ChildWindowPane listens to the child window and disposes itself when
+ the child window becomes inaccessible. This happens for instance when a
+ document is made read-only and the task pane is turned off.
+*/
+class ChildWindowPane
+ : public ChildWindowPaneInterfaceBase
+{
+public:
+ ChildWindowPane (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId,
+ sal_uInt16 nChildWindowId,
+ ViewShellBase& rViewShellBase,
+ ::std::unique_ptr<SfxShell> && pShell);
+ virtual ~ChildWindowPane() override;
+
+ /** Hide the pane. To make the pane visible again, call GetWindow().
+ */
+ void Hide();
+
+ virtual void SAL_CALL disposing() override;
+
+ /** This returns the content window when the child window is already
+ visible. Otherwise <NULL/> is returned. In that case a later call
+ may return the requested window (making a child window visible is an
+ asynchronous process.)
+ Note that GetWindow() may return different Window pointers when
+ Hide() is called in between.
+ */
+ virtual vcl::Window* GetWindow() override;
+
+ /** The local getWindow() first calls GetWindow() to provide a valid
+ window pointer before forwarding the call to the base class.
+ */
+ virtual css::uno::Reference<css::awt::XWindow>
+ SAL_CALL getWindow() override;
+
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing(
+ const css::lang::EventObject& rEvent) override;
+
+private:
+ sal_uInt16 mnChildWindowId;
+ ViewShellBase& mrViewShellBase;
+ ::std::unique_ptr<SfxShell> mpShell;
+
+ /** This flag is set when the pane shell has been activated at least
+ once. It is used to optimize the start-up performance (by not
+ showing the window too early) and by not delaying its creation at
+ later times.
+ */
+ bool mbHasBeenActivated;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/FrameWindowPane.cxx b/sd/source/ui/framework/factories/FrameWindowPane.cxx
new file mode 100644
index 000000000..1f4b387d8
--- /dev/null
+++ b/sd/source/ui/framework/factories/FrameWindowPane.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 "FrameWindowPane.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework
+{
+FrameWindowPane::FrameWindowPane(const Reference<XResourceId>& rxPaneId, vcl::Window* pWindow)
+ : Pane(rxPaneId, pWindow)
+{
+}
+
+FrameWindowPane::~FrameWindowPane() noexcept {}
+
+sal_Bool SAL_CALL FrameWindowPane::isAnchorOnly() { return false; }
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/FrameWindowPane.hxx b/sd/source/ui/framework/factories/FrameWindowPane.hxx
new file mode 100644
index 000000000..67da37fdf
--- /dev/null
+++ b/sd/source/ui/framework/factories/FrameWindowPane.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <framework/Pane.hxx>
+
+namespace com::sun::star::drawing::framework
+{
+class XResourceId;
+}
+
+namespace sd::framework
+{
+/** This subclass is not necessary anymore. We can remove it if that
+ remains so.
+*/
+class FrameWindowPane : public Pane
+{
+public:
+ FrameWindowPane(const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId,
+ vcl::Window* pWindow);
+ virtual ~FrameWindowPane() noexcept override;
+
+ /** A frame window typically can (and should) exists on its own without
+ children, if only to visualize that something (a view) is missing.
+ Therefore this method always returns <FALSE/>.
+ */
+ virtual sal_Bool SAL_CALL isAnchorOnly() override;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/FullScreenPane.cxx b/sd/source/ui/framework/factories/FullScreenPane.cxx
new file mode 100644
index 000000000..dbf34213f
--- /dev/null
+++ b/sd/source/ui/framework/factories/FullScreenPane.cxx
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "FullScreenPane.hxx"
+#include <vcl/vclevent.hxx>
+#include <vcl/wrkwin.hxx>
+#include <o3tl/string_view.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+FullScreenPane::FullScreenPane (
+ const Reference<XComponentContext>& rxComponentContext,
+ const Reference<XResourceId>& rxPaneId,
+ const vcl::Window* pViewShellWindow)
+ : FrameWindowPane(rxPaneId,nullptr),
+ mxComponentContext(rxComponentContext)
+{
+ vcl::Window* pParent = nullptr;
+ mpWorkWindow.reset(VclPtr<WorkWindow>::Create(
+
+ pParent,
+ 0)); // For debugging (non-fullscreen) use WB_BORDER | WB_MOVEABLE | WB_SIZEABLE));
+
+ if ( ! rxPaneId.is())
+ throw lang::IllegalArgumentException();
+
+ sal_Int32 nScreenNumber = 1;
+ ExtractArguments(rxPaneId, nScreenNumber);
+
+ if (!mpWorkWindow)
+ return;
+
+ // Create a new top-level window that is displayed full screen.
+ mpWorkWindow->ShowFullScreenMode(true, nScreenNumber);
+ // For debugging (non-fullscreen) use mpWorkWindow->SetScreenNumber(nScreenNumber);
+ mpWorkWindow->SetMenuBarMode(MenuBarMode::Hide);
+ mpWorkWindow->SetBorderStyle(WindowBorderStyle::REMOVEBORDER);
+ mpWorkWindow->SetBackground(Wallpaper());
+ // Don't show the window right now in order to allow the setting of an
+ // accessibility object: accessibility objects are typically
+ // requested by AT-tools when the window is shown. Chaining it
+ // afterwards may or may not work.
+
+ // Add resize listener at the work window.
+ Link<VclWindowEvent&,void> aWindowEventHandler (LINK(this, FullScreenPane, WindowEventHandler));
+ mpWorkWindow->AddEventListener(aWindowEventHandler);
+
+ // Set title and icon of the new window to those of the current window
+ // of the view shell.
+ if (pViewShellWindow != nullptr)
+ {
+ const SystemWindow* pSystemWindow = pViewShellWindow->GetSystemWindow();
+ mpWorkWindow->SetText(pSystemWindow->GetText());
+ mpWorkWindow->SetIcon(pSystemWindow->GetIcon());
+ }
+
+ // For some reason the VCL canvas can not paint into a WorkWindow.
+ // Therefore a child window is created that covers the WorkWindow
+ // completely.
+ mpWindow = VclPtr<vcl::Window>::Create(mpWorkWindow.get());
+ mpWindow->SetPosSizePixel(Point(0,0), mpWorkWindow->GetSizePixel());
+ mpWindow->SetBackground(Wallpaper());
+ mxWindow = VCLUnoHelper::GetInterface(mpWindow);
+
+ // Create the canvas.
+ mxCanvas = CreateCanvas();
+
+ mpWindow->GrabFocus();
+}
+
+FullScreenPane::~FullScreenPane() noexcept
+{
+}
+
+void SAL_CALL FullScreenPane::disposing()
+{
+ mpWindow.disposeAndClear();
+
+ if (mpWorkWindow)
+ {
+ Link<VclWindowEvent&,void> aWindowEventHandler (LINK(this, FullScreenPane, WindowEventHandler));
+ mpWorkWindow->RemoveEventListener(aWindowEventHandler);
+ mpWorkWindow.disposeAndClear();
+ }
+
+ FrameWindowPane::disposing();
+}
+
+//----- XPane -----------------------------------------------------------------
+
+sal_Bool SAL_CALL FullScreenPane::isVisible()
+{
+ ThrowIfDisposed();
+
+ if (mpWindow != nullptr)
+ return mpWindow->IsReallyVisible();
+ else
+ return false;
+}
+
+void SAL_CALL FullScreenPane::setVisible (const sal_Bool bIsVisible)
+{
+ ThrowIfDisposed();
+
+ if (mpWindow != nullptr)
+ mpWindow->Show(bIsVisible);
+ if (mpWorkWindow != nullptr)
+ mpWorkWindow->Show(bIsVisible);
+}
+
+Reference<css::accessibility::XAccessible> SAL_CALL FullScreenPane::getAccessible()
+{
+ ThrowIfDisposed();
+
+ if (mpWorkWindow != nullptr)
+ return mpWorkWindow->GetAccessible(false);
+ else
+ return nullptr;
+}
+
+void SAL_CALL FullScreenPane::setAccessible (
+ const Reference<css::accessibility::XAccessible>& rxAccessible)
+{
+ ThrowIfDisposed();
+
+ if (mpWindow == nullptr)
+ return;
+
+ Reference<lang::XInitialization> xInitializable (rxAccessible, UNO_QUERY);
+ if (xInitializable.is())
+ {
+ vcl::Window* pParentWindow = mpWindow->GetParent();
+ Reference<css::accessibility::XAccessible> xAccessibleParent;
+ if (pParentWindow != nullptr)
+ xAccessibleParent = pParentWindow->GetAccessible();
+ Sequence<Any> aArguments{ Any(xAccessibleParent) };
+ xInitializable->initialize(aArguments);
+ }
+ GetWindow()->SetAccessible(rxAccessible);
+}
+
+IMPL_LINK(FullScreenPane, WindowEventHandler, VclWindowEvent&, rEvent, void)
+{
+ switch (rEvent.GetId())
+ {
+ case VclEventId::WindowResize:
+ GetWindow()->SetPosPixel(Point(0,0));
+ GetWindow()->SetSizePixel(Size(
+ mpWorkWindow->GetSizePixel().Width(),
+ mpWorkWindow->GetSizePixel().Height()));
+ break;
+
+ case VclEventId::ObjectDying:
+ mpWorkWindow.disposeAndClear();
+ break;
+
+ default: break;
+ }
+}
+
+Reference<rendering::XCanvas> FullScreenPane::CreateCanvas()
+{
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(mxWindow);
+ if (!pWindow)
+ throw RuntimeException();
+
+ Sequence<Any> aArg{ // common: first any is VCL pointer to window (for VCL canvas)
+ Any(reinterpret_cast<sal_Int64>(pWindow.get())),
+ Any(css::awt::Rectangle()),
+ Any(false),
+ Any(mxWindow)
+ };
+
+ Reference<lang::XMultiServiceFactory> xFactory (
+ mxComponentContext->getServiceManager(), UNO_QUERY_THROW);
+ return Reference<rendering::XCanvas>(
+ xFactory->createInstanceWithArguments("com.sun.star.rendering.SpriteCanvas.VCL",
+ aArg),
+ UNO_QUERY);
+}
+
+void FullScreenPane::ExtractArguments (
+ const Reference<XResourceId>& rxPaneId,
+ sal_Int32& rnScreenNumberReturnValue)
+{
+ // Extract arguments from the resource URL.
+ const util::URL aURL = rxPaneId->getFullResourceURL();
+ for (sal_Int32 nIndex{ 0 }; nIndex >= 0; )
+ {
+ const std::u16string_view aToken = o3tl::getToken(aURL.Arguments, 0, '&', nIndex);
+ std::u16string_view sValue;
+ if (o3tl::starts_with(aToken, u"ScreenNumber=", &sValue))
+ {
+ rnScreenNumberReturnValue = o3tl::toInt32(sValue);
+ }
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/FullScreenPane.hxx b/sd/source/ui/framework/factories/FullScreenPane.hxx
new file mode 100644
index 000000000..b33804ee5
--- /dev/null
+++ b/sd/source/ui/framework/factories/FullScreenPane.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "FrameWindowPane.hxx"
+#include <tools/link.hxx>
+#include <vcl/wrkwin.hxx>
+
+class VclWindowEvent;
+
+namespace vcl { class Window; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace sd::framework {
+
+/** The full screen pane creates a pane that covers the complete application
+ window, i.e. that hides menu bar, tool bars, status bars.
+*/
+class FullScreenPane
+ : public FrameWindowPane
+{
+public:
+ /** Create a new full screen pane.
+ @param rxComponentContext
+ Used for creating a new canvas.
+ @param rxPaneId
+ The resource id of the new pane.
+ @param pViewShellWindow
+ The top-level parent of this window is used to obtain title and
+ icon for the new top-level window.
+ */
+ FullScreenPane (
+ const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId,
+ const vcl::Window* pViewShellWindow);
+ virtual ~FullScreenPane() noexcept override;
+
+ virtual void SAL_CALL disposing() override;
+
+ //----- XPane -------------------------------------------------------------
+
+ virtual sal_Bool SAL_CALL isVisible() override;
+
+ virtual void SAL_CALL setVisible (sal_Bool bIsVisible) override;
+
+ virtual css::uno::Reference<css::accessibility::XAccessible> SAL_CALL getAccessible() override;
+
+ virtual void SAL_CALL setAccessible (
+ const css::uno::Reference<css::accessibility::XAccessible>& rxAccessible) override;
+
+ DECL_LINK(WindowEventHandler, VclWindowEvent&, void);
+
+protected:
+ virtual css::uno::Reference<css::rendering::XCanvas>
+ CreateCanvas() override;
+
+private:
+ css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
+ VclPtr<WorkWindow> mpWorkWindow;
+
+ static void ExtractArguments (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId,
+ sal_Int32& rnScreenNumberReturnValue);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/Pane.cxx b/sd/source/ui/framework/factories/Pane.cxx
new file mode 100644
index 000000000..a188f0e11
--- /dev/null
+++ b/sd/source/ui/framework/factories/Pane.cxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <framework/Pane.hxx>
+
+#include <osl/mutex.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/window.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <com/sun/star/rendering/XSpriteCanvas.hpp>
+#include <comphelper/servicehelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+Pane::Pane (
+ const Reference<XResourceId>& rxPaneId,
+ vcl::Window* pWindow)
+ noexcept
+ : PaneInterfaceBase(m_aMutex),
+ mxPaneId(rxPaneId),
+ mpWindow(pWindow),
+ mxWindow(VCLUnoHelper::GetInterface(pWindow))
+{
+}
+
+Pane::~Pane()
+{
+}
+
+void Pane::disposing()
+{
+ mxWindow = nullptr;
+ mpWindow = nullptr;
+}
+
+vcl::Window* Pane::GetWindow()
+{
+ if (mxWindow.is())
+ return mpWindow;
+ else
+ return nullptr;
+}
+
+//----- XPane -----------------------------------------------------------------
+
+Reference<awt::XWindow> SAL_CALL Pane::getWindow()
+{
+ ThrowIfDisposed();
+
+ return mxWindow;
+}
+
+Reference<rendering::XCanvas> SAL_CALL Pane::getCanvas()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ if ( ! mxCanvas.is())
+ mxCanvas = CreateCanvas();
+
+ return mxCanvas;
+}
+
+//----- XPane2 ----------------------------------------------------------------
+
+sal_Bool SAL_CALL Pane::isVisible()
+{
+ ThrowIfDisposed();
+
+ const vcl::Window* pWindow = GetWindow();
+ if (pWindow != nullptr)
+ return pWindow->IsVisible();
+ else
+ return false;
+}
+
+void SAL_CALL Pane::setVisible (sal_Bool bIsVisible)
+{
+ ThrowIfDisposed();
+
+ vcl::Window* pWindow = GetWindow();
+ if (pWindow != nullptr)
+ pWindow->Show(bIsVisible);
+}
+
+Reference<css::accessibility::XAccessible> SAL_CALL Pane::getAccessible()
+{
+ ThrowIfDisposed();
+ vcl::Window* pWindow = GetWindow();
+ if (pWindow != nullptr)
+ return pWindow->GetAccessible(false);
+ else
+ return nullptr;
+}
+
+void SAL_CALL Pane::setAccessible (
+ const Reference<css::accessibility::XAccessible>& rxAccessible)
+{
+ ThrowIfDisposed();
+ vcl::Window* pWindow = GetWindow();
+ if (pWindow != nullptr)
+ pWindow->SetAccessible(rxAccessible);
+}
+
+//----- XResource -------------------------------------------------------------
+
+Reference<XResourceId> SAL_CALL Pane::getResourceId()
+{
+ ThrowIfDisposed();
+
+ return mxPaneId;
+}
+
+sal_Bool SAL_CALL Pane::isAnchorOnly()
+{
+ return true;
+}
+
+//----- XUnoTunnel ------------------------------------------------------------
+
+const Sequence<sal_Int8>& Pane::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit thePaneUnoTunnelId;
+ return thePaneUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL Pane::getSomething (const Sequence<sal_Int8>& rId)
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+Reference<rendering::XCanvas> Pane::CreateCanvas()
+{
+ Reference<rendering::XCanvas> xCanvas;
+
+ if (mpWindow != nullptr)
+ {
+ ::cppcanvas::SpriteCanvasSharedPtr pCanvas (
+ cppcanvas::VCLFactory::createSpriteCanvas(*mpWindow));
+ if (pCanvas)
+ xCanvas.set(pCanvas->getUNOSpriteCanvas());
+ }
+
+ return xCanvas;
+}
+
+void Pane::ThrowIfDisposed() const
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ {
+ throw lang::DisposedException ("Pane object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/PresentationFactory.cxx b/sd/source/ui/framework/factories/PresentationFactory.cxx
new file mode 100644
index 000000000..8cf603809
--- /dev/null
+++ b/sd/source/ui/framework/factories/PresentationFactory.cxx
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <framework/PresentationFactory.hxx>
+
+#include <DrawController.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XView.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/compbase.hxx>
+#include <tools/diagnose_ex.h>
+#include <slideshow.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing::framework;
+
+
+namespace sd::framework {
+
+namespace {
+
+typedef comphelper::WeakComponentImplHelper<lang::XInitialization> PresentationFactoryProviderInterfaceBase;
+
+class PresentationFactoryProvider
+ : public PresentationFactoryProviderInterfaceBase
+{
+public:
+ PresentationFactoryProvider ();
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence<css::uno::Any>& aArguments) override;
+};
+
+typedef comphelper::WeakComponentImplHelper<XView> PresentationViewInterfaceBase;
+
+/** The PresentationView is not an actual view, it is a marker whose
+ existence in a configuration indicates that a slideshow is running
+ (in another application window).
+*/
+class PresentationView
+ : public PresentationViewInterfaceBase
+{
+public:
+ explicit PresentationView (const Reference<XResourceId>& rxViewId)
+ : mxResourceId(rxViewId) {};
+
+ // XView
+
+ virtual Reference<XResourceId> SAL_CALL getResourceId() override
+ { return mxResourceId; };
+
+ virtual sal_Bool SAL_CALL isAnchorOnly() override
+ { return false; }
+
+private:
+ Reference<XResourceId> mxResourceId;
+};
+
+} // end of anonymous namespace.
+
+//===== PresentationFactory ===================================================
+
+constexpr OUStringLiteral gsPresentationViewURL = u"private:resource/view/Presentation";
+
+PresentationFactory::PresentationFactory (
+ const Reference<frame::XController>& rxController)
+ : mxController(rxController)
+{
+}
+
+PresentationFactory::~PresentationFactory()
+{
+}
+
+//----- XViewFactory ----------------------------------------------------------
+
+Reference<XResource> SAL_CALL PresentationFactory::createResource (
+ const Reference<XResourceId>& rxViewId)
+{
+ ThrowIfDisposed();
+
+ if (rxViewId.is())
+ if ( ! rxViewId->hasAnchor() && rxViewId->getResourceURL() == gsPresentationViewURL)
+ return new PresentationView(rxViewId);
+
+ return Reference<XResource>();
+}
+
+void SAL_CALL PresentationFactory::releaseResource (
+ const Reference<XResource>&)
+{
+ ThrowIfDisposed();
+
+ auto pController = comphelper::getFromUnoTunnel<sd::DrawController>(mxController);
+ if (pController != nullptr)
+ {
+ ViewShellBase* pBase = pController->GetViewShellBase();
+ if (pBase != nullptr)
+ SlideShow::Stop( *pBase );
+ }
+}
+
+//===== XConfigurationChangeListener ==========================================
+
+void SAL_CALL PresentationFactory::notifyConfigurationChange (
+ const ConfigurationChangeEvent&)
+{}
+
+//===== lang::XEventListener ==================================================
+
+void SAL_CALL PresentationFactory::disposing (
+ const lang::EventObject&)
+{}
+
+void PresentationFactory::ThrowIfDisposed() const
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("PresentationFactory object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+namespace {
+
+//===== PresentationFactoryProvider ===========================================
+
+PresentationFactoryProvider::PresentationFactoryProvider ()
+{
+}
+
+// XInitialization
+
+void SAL_CALL PresentationFactoryProvider::initialize(
+ const Sequence<Any>& aArguments)
+{
+ if (!aArguments.hasElements())
+ return;
+
+ try
+ {
+ // Get the XController from the first argument.
+ Reference<frame::XController> xController (aArguments[0], UNO_QUERY_THROW);
+ Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW);
+ Reference<XConfigurationController> xCC (xCM->getConfigurationController());
+ if (xCC.is())
+ xCC->addResourceFactory(
+ gsPresentationViewURL,
+ new PresentationFactory(xController));
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+} // end of anonymous namespace.
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_PresentationFactoryProvider_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::PresentationFactoryProvider);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/ViewShellWrapper.cxx b/sd/source/ui/framework/factories/ViewShellWrapper.cxx
new file mode 100644
index 000000000..8f0fcd976
--- /dev/null
+++ b/sd/source/ui/framework/factories/ViewShellWrapper.cxx
@@ -0,0 +1,252 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <framework/ViewShellWrapper.hxx>
+#include <sdpage.hxx>
+#include <ViewShell.hxx>
+
+#include <SlideSorter.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <model/SlsPageDescriptor.hxx>
+
+#include <com/sun/star/drawing/framework/XPane.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::com::sun::star::awt::XWindow;
+
+namespace sd::framework {
+
+ViewShellWrapper::ViewShellWrapper (
+ const std::shared_ptr<ViewShell>& pViewShell,
+ const Reference<XResourceId>& rxViewId,
+ const Reference<awt::XWindow>& rxWindow)
+ : mpViewShell(pViewShell),
+ mpSlideSorterViewShell(
+ std::dynamic_pointer_cast< ::sd::slidesorter::SlideSorterViewShell >( pViewShell )),
+ mxViewId(rxViewId),
+ mxWindow(rxWindow)
+{
+}
+
+ViewShellWrapper::~ViewShellWrapper()
+{
+}
+
+void ViewShellWrapper::disposing(std::unique_lock<std::mutex>&)
+{
+ SAL_INFO("sd.ui", "disposing ViewShellWrapper " << this);
+ Reference<awt::XWindow> xWindow (mxWindow);
+ if (xWindow.is())
+ {
+ SAL_INFO(
+ "sd.ui",
+ "removing ViewShellWrapper " << this << " from window listener at "
+ << mxWindow.get());
+ xWindow->removeWindowListener(this);
+ }
+
+ mpSlideSorterViewShell.reset();
+ mpViewShell.reset();
+}
+
+uno::Any SAL_CALL ViewShellWrapper::queryInterface( const uno::Type & rType )
+{
+ if( mpSlideSorterViewShell &&
+ rType == cppu::UnoType<view::XSelectionSupplier>::get() )
+ {
+ uno::Reference<view::XSelectionSupplier> xSupplier( this );
+ return Any(xSupplier);
+ }
+ else
+ return ViewShellWrapperInterfaceBase::queryInterface( rType );
+}
+
+//----- XResource -------------------------------------------------------------
+
+Reference<XResourceId> SAL_CALL ViewShellWrapper::getResourceId()
+{
+ return mxViewId;
+}
+
+sal_Bool SAL_CALL ViewShellWrapper::isAnchorOnly()
+{
+ return false;
+}
+
+//----- XSelectionSupplier --------------------------------------------------
+
+sal_Bool SAL_CALL ViewShellWrapper::select( const css::uno::Any& aSelection )
+{
+ if (!mpSlideSorterViewShell)
+ return false;
+
+ ::sd::slidesorter::controller::SlideSorterController& rSlideSorterController
+ = mpSlideSorterViewShell->GetSlideSorter().GetController();
+ ::sd::slidesorter::controller::PageSelector& rSelector (rSlideSorterController.GetPageSelector());
+ rSelector.DeselectAllPages();
+ Sequence<Reference<drawing::XDrawPage> > xPages;
+ aSelection >>= xPages;
+ for (const auto& rPage : std::as_const(xPages))
+ {
+ Reference<beans::XPropertySet> xSet (rPage, UNO_QUERY);
+ if (xSet.is())
+ {
+ try
+ {
+ Any aNumber = xSet->getPropertyValue("Number");
+ sal_Int32 nPageNumber = 0;
+ aNumber >>= nPageNumber;
+ nPageNumber -=1; // Transform 1-based page numbers to 0-based ones.
+ rSelector.SelectPage(nPageNumber);
+ }
+ catch (const RuntimeException&)
+ {
+ }
+ }
+ }
+
+ return true;
+}
+
+uno::Any SAL_CALL ViewShellWrapper::getSelection()
+{
+ Any aResult;
+
+ if (!mpSlideSorterViewShell)
+ return aResult;
+
+ slidesorter::model::PageEnumeration aSelectedPages (
+ slidesorter::model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mpSlideSorterViewShell->GetSlideSorter().GetModel()));
+ int nSelectedPageCount (
+ mpSlideSorterViewShell->GetSlideSorter().GetController().GetPageSelector().GetSelectedPageCount());
+
+ Sequence<Reference<XInterface> > aPages(nSelectedPageCount);
+ auto aPagesRange = asNonConstRange(aPages);
+ int nIndex = 0;
+ while (aSelectedPages.HasMoreElements() && nIndex<nSelectedPageCount)
+ {
+ slidesorter::model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ aPagesRange[nIndex++] = pDescriptor->GetPage()->getUnoPage();
+ }
+ aResult <<= aPages;
+
+ return aResult;
+}
+
+void SAL_CALL ViewShellWrapper::addSelectionChangeListener( const uno::Reference< view::XSelectionChangeListener >& )
+{
+}
+
+void SAL_CALL ViewShellWrapper::removeSelectionChangeListener( const uno::Reference< view::XSelectionChangeListener >& )
+{
+}
+
+//----- XRelocatableResource --------------------------------------------------
+
+sal_Bool SAL_CALL ViewShellWrapper::relocateToAnchor (
+ const Reference<XResource>& xResource)
+{
+ bool bResult (false);
+
+ Reference<XPane> xPane (xResource, UNO_QUERY);
+ if (xPane.is())
+ {
+ // Detach from the window of the old pane.
+ Reference<awt::XWindow> xWindow (mxWindow);
+ if (xWindow.is())
+ xWindow->removeWindowListener(this);
+ mxWindow = nullptr;
+
+ if (mpViewShell != nullptr)
+ {
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xPane->getWindow());
+ if (pWindow && mpViewShell->RelocateToParentWindow(pWindow))
+ {
+ bResult = true;
+
+ // Attach to the window of the new pane.
+ xWindow = xPane->getWindow();
+ if (xWindow.is())
+ {
+ xWindow->addWindowListener(this);
+ mpViewShell->Resize();
+ }
+ }
+ }
+ }
+
+ return bResult;
+}
+
+//----- XUnoTunnel ------------------------------------------------------------
+
+const Sequence<sal_Int8>& ViewShellWrapper::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theViewShellWrapperUnoTunnelId;
+ return theViewShellWrapperUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL ViewShellWrapper::getSomething (const Sequence<sal_Int8>& rId)
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+//===== awt::XWindowListener ==================================================
+
+void SAL_CALL ViewShellWrapper::windowResized (const awt::WindowEvent&)
+{
+ ViewShell* pViewShell (mpViewShell.get());
+ if (pViewShell != nullptr)
+ pViewShell->Resize();
+}
+
+void SAL_CALL ViewShellWrapper::windowMoved (const awt::WindowEvent&) {}
+
+void SAL_CALL ViewShellWrapper::windowShown (const lang::EventObject&)
+{
+ ViewShell* pViewShell (mpViewShell.get());
+ if (pViewShell != nullptr)
+ pViewShell->Resize();
+}
+
+void SAL_CALL ViewShellWrapper::windowHidden (const lang::EventObject&) {}
+
+//===== XEventListener ========================================================
+
+void SAL_CALL ViewShellWrapper::disposing (const lang::EventObject& rEvent)
+{
+ if (rEvent.Source == mxWindow)
+ mxWindow = nullptr;
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/CenterViewFocusModule.cxx b/sd/source/ui/framework/module/CenterViewFocusModule.cxx
new file mode 100644
index 000000000..e36f95e33
--- /dev/null
+++ b/sd/source/ui/framework/module/CenterViewFocusModule.cxx
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "CenterViewFocusModule.hxx"
+
+#include <framework/FrameworkHelper.hxx>
+#include <framework/ViewShellWrapper.hxx>
+
+#include <DrawController.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <comphelper/servicehelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace sd::framework {
+
+//===== CenterViewFocusModule ====================================================
+
+CenterViewFocusModule::CenterViewFocusModule (Reference<frame::XController> const & rxController)
+ : mbValid(false),
+ mpBase(nullptr),
+ mbNewViewCreated(false)
+{
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ mxConfigurationController = xControllerManager->getConfigurationController();
+
+ // Tunnel through the controller to obtain a ViewShellBase.
+ auto pController = comphelper::getFromUnoTunnel<sd::DrawController>(rxController);
+ if (pController != nullptr)
+ mpBase = pController->GetViewShellBase();
+
+ // Check, if all required objects do exist.
+ if (mxConfigurationController.is() && mpBase!=nullptr)
+ {
+ mbValid = true;
+ }
+ }
+
+ if (mbValid)
+ {
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ Any());
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationEvent,
+ Any());
+ }
+}
+
+CenterViewFocusModule::~CenterViewFocusModule()
+{
+}
+
+void CenterViewFocusModule::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxConfigurationController.is())
+ mxConfigurationController->removeConfigurationChangeListener(this);
+
+ mbValid = false;
+ mxConfigurationController = nullptr;
+ mpBase = nullptr;
+}
+
+void SAL_CALL CenterViewFocusModule::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (mbValid)
+ {
+ if (rEvent.Type == FrameworkHelper::msConfigurationUpdateEndEvent)
+ {
+ HandleNewView(rEvent.Configuration);
+ }
+ else if (rEvent.Type == FrameworkHelper::msResourceActivationEvent)
+ {
+ if (rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix))
+ mbNewViewCreated = true;
+ }
+ }
+}
+
+void CenterViewFocusModule::HandleNewView (
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ if (!mbNewViewCreated)
+ return;
+
+ mbNewViewCreated = false;
+ // Make the center pane the active one. Tunnel through the
+ // controller to obtain a ViewShell pointer.
+
+ Sequence<Reference<XResourceId> > xViewIds (rxConfiguration->getResources(
+ FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL),
+ FrameworkHelper::msViewURLPrefix,
+ AnchorBindingMode_DIRECT));
+ Reference<XView> xView;
+ if (xViewIds.hasElements())
+ xView.set( mxConfigurationController->getResource(xViewIds[0]),UNO_QUERY);
+ if (mpBase!=nullptr)
+ {
+ auto pViewShellWrapper = comphelper::getFromUnoTunnel<ViewShellWrapper>(xView);
+ if (pViewShellWrapper != nullptr)
+ {
+ std::shared_ptr<ViewShell> pViewShell = pViewShellWrapper->GetViewShell();
+ if (pViewShell != nullptr)
+ mpBase->GetViewShellManager()->MoveToTop(*pViewShell);
+ }
+ }
+}
+
+void SAL_CALL CenterViewFocusModule::disposing (
+ const lang::EventObject& rEvent)
+{
+ if (mxConfigurationController.is())
+ if (rEvent.Source == mxConfigurationController)
+ {
+ mbValid = false;
+ mxConfigurationController = nullptr;
+ mpBase = nullptr;
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/CenterViewFocusModule.hxx b/sd/source/ui/framework/module/CenterViewFocusModule.hxx
new file mode 100644
index 000000000..c6d5d348e
--- /dev/null
+++ b/sd/source/ui/framework/module/CenterViewFocusModule.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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfigurationController;
+}
+namespace com::sun::star::frame
+{
+class XController;
+}
+
+namespace sd
+{
+class ViewShellBase;
+}
+
+namespace sd::framework
+{
+typedef comphelper::WeakComponentImplHelper<css::drawing::framework::XConfigurationChangeListener>
+ CenterViewFocusModuleInterfaceBase;
+
+/** This module waits for new views to be created for the center pane and
+ then moves the center view to the top most place on the shell stack. As
+ we are moving away from the shell stack this module may become obsolete
+ or has to be modified.
+*/
+class CenterViewFocusModule final : public CenterViewFocusModuleInterfaceBase
+{
+public:
+ explicit CenterViewFocusModule(
+ css::uno::Reference<css::frame::XController> const& rxController);
+ virtual ~CenterViewFocusModule() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange(
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override;
+
+private:
+ class ViewShellContainer;
+
+ bool mbValid;
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+ ViewShellBase* mpBase;
+ /** This flag indicates whether in the last configuration change cycle a
+ new view has been created and thus the center view has to be moved
+ to the top of the shell stack.
+ */
+ bool mbNewViewCreated;
+
+ /** At the end of an update of the current configuration this method
+ handles a new view in the center pane by moving the associated view
+ shell to the top of the shell stack.
+ */
+ void HandleNewView(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/DrawModule.cxx b/sd/source/ui/framework/module/DrawModule.cxx
new file mode 100644
index 000000000..17f4671fc
--- /dev/null
+++ b/sd/source/ui/framework/module/DrawModule.cxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <framework/DrawModule.hxx>
+
+#include <framework/FrameworkHelper.hxx>
+#include "CenterViewFocusModule.hxx"
+#include "SlideSorterModule.hxx"
+#include "ToolBarModule.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::framework
+{
+void DrawModule::Initialize(Reference<frame::XController> const& rxController)
+{
+ new sd::framework::CenterViewFocusModule(rxController);
+ new sd::framework::SlideSorterModule(rxController, FrameworkHelper::msLeftDrawPaneURL);
+ new ToolBarModule(rxController);
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ImpressModule.cxx b/sd/source/ui/framework/module/ImpressModule.cxx
new file mode 100644
index 000000000..139b250fd
--- /dev/null
+++ b/sd/source/ui/framework/module/ImpressModule.cxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <framework/ImpressModule.hxx>
+
+#include <framework/FrameworkHelper.hxx>
+#include "ViewTabBarModule.hxx"
+#include "CenterViewFocusModule.hxx"
+#include "SlideSorterModule.hxx"
+#include "ToolBarModule.hxx"
+#include "ShellStackGuard.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::framework {
+
+void ImpressModule::Initialize (Reference<frame::XController> const & rxController)
+{
+ new CenterViewFocusModule(rxController);
+ new ViewTabBarModule(
+ rxController,
+ FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msViewTabBarURL,
+ FrameworkHelper::msCenterPaneURL));
+ new SlideSorterModule(
+ rxController,
+ FrameworkHelper::msLeftImpressPaneURL);
+ new ToolBarModule(rxController);
+ new ShellStackGuard(rxController);
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ModuleController.cxx b/sd/source/ui/framework/module/ModuleController.cxx
new file mode 100644
index 000000000..acd12ec8a
--- /dev/null
+++ b/sd/source/ui/framework/module/ModuleController.cxx
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <framework/ModuleController.hxx>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+
+#include <tools/ConfigurationAccess.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::tools::ConfigurationAccess;
+
+namespace sd::framework {
+
+const sal_uInt32 snFactoryPropertyCount (2);
+const sal_uInt32 snStartupPropertyCount (1);
+
+//===== ModuleController ======================================================
+Reference<XModuleController> ModuleController::CreateInstance (
+ const Reference<XComponentContext>& rxContext)
+{
+ return new ModuleController(rxContext);
+}
+
+ModuleController::ModuleController (const Reference<XComponentContext>& rxContext)
+{
+ /** Load a list of URL to service mappings from the
+ /org.openoffice.Office.Impress/MultiPaneGUI/Framework/ResourceFactories
+ configuration entry. The mappings are stored in the
+ mpResourceToFactoryMap member.
+ */
+ try
+ {
+ ConfigurationAccess aConfiguration (
+ rxContext,
+ "/org.openoffice.Office.Impress/",
+ ConfigurationAccess::READ_ONLY);
+ Reference<container::XNameAccess> xFactories (
+ aConfiguration.GetConfigurationNode("MultiPaneGUI/Framework/ResourceFactories"),
+ UNO_QUERY);
+ ::std::vector<OUString> aProperties (snFactoryPropertyCount);
+ aProperties[0] = "ServiceName";
+ aProperties[1] = "ResourceList";
+ ConfigurationAccess::ForAll(
+ xFactories,
+ aProperties,
+ [this] (OUString const&, ::std::vector<Any> const& xs) {
+ return this->ProcessFactory(xs);
+ } );
+ }
+ catch (Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+ModuleController::~ModuleController() noexcept
+{
+}
+
+void ModuleController::disposing(std::unique_lock<std::mutex>&)
+{
+ // Break the cyclic reference back to DrawController object
+ maLoadedFactories.clear();
+ maResourceToFactoryMap.clear();
+ mxController.clear();
+}
+
+void ModuleController::ProcessFactory (const ::std::vector<Any>& rValues)
+{
+ OSL_ASSERT(rValues.size() == snFactoryPropertyCount);
+
+ // Get the service name of the factory.
+ OUString sServiceName;
+ rValues[0] >>= sServiceName;
+
+ // Get all resource URLs that are created by the factory.
+ Reference<container::XNameAccess> xResources (rValues[1], UNO_QUERY);
+ ::std::vector<OUString> aURLs;
+ tools::ConfigurationAccess::FillList(
+ xResources,
+ "URL",
+ aURLs);
+
+ SAL_INFO("sd.fwk", __func__ << ": ModuleController::adding factory " << sServiceName);
+
+ // Add the resource URLs to the map.
+ for (const auto& rResource : aURLs)
+ {
+ maResourceToFactoryMap[rResource] = sServiceName;
+ SAL_INFO("sd.fwk", __func__ << ": " << rResource);
+ }
+}
+
+void ModuleController::InstantiateStartupServices()
+{
+ try
+ {
+ tools::ConfigurationAccess aConfiguration (
+ "/org.openoffice.Office.Impress/",
+ tools::ConfigurationAccess::READ_ONLY);
+ Reference<container::XNameAccess> xFactories (
+ aConfiguration.GetConfigurationNode("MultiPaneGUI/Framework/StartupServices"),
+ UNO_QUERY);
+ ::std::vector<OUString> aProperties (snStartupPropertyCount);
+ aProperties[0] = "ServiceName";
+ tools::ConfigurationAccess::ForAll(
+ xFactories,
+ aProperties,
+ [this] (OUString const&, ::std::vector<Any> const& xs) {
+ return this->ProcessStartupService(xs);
+ } );
+ }
+ catch (Exception&)
+ {
+ SAL_WARN("sd.fwk", "ERROR in ModuleController::InstantiateStartupServices");
+ }
+}
+
+void ModuleController::ProcessStartupService (const ::std::vector<Any>& rValues)
+{
+ OSL_ASSERT(rValues.size() == snStartupPropertyCount);
+
+ try
+ {
+ // Get the service name of the startup service.
+ OUString sServiceName;
+ rValues[0] >>= sServiceName;
+
+ // Instantiate service.
+ Reference<uno::XComponentContext> xContext =
+ ::comphelper::getProcessComponentContext();
+
+ // Create the startup service.
+ Sequence<Any> aArguments{ Any(mxController) };
+ // Note that when the new object will be destroyed at the end of
+ // this scope when it does not register itself anywhere.
+ // Typically it will add itself as ConfigurationChangeListener
+ // at the configuration controller.
+ xContext->getServiceManager()->createInstanceWithArgumentsAndContext(sServiceName, aArguments, xContext);
+
+ SAL_INFO("sd.fwk", __func__ << ": ModuleController::created startup service " << sServiceName);
+ }
+ catch (Exception&)
+ {
+ SAL_WARN("sd.fwk", "ERROR in ModuleController::ProcessStartupServices");
+ }
+}
+
+//----- XModuleController -----------------------------------------------------
+
+void SAL_CALL ModuleController::requestResource (const OUString& rsResourceURL)
+{
+ auto iFactory = maResourceToFactoryMap.find(rsResourceURL);
+ if (iFactory == maResourceToFactoryMap.end())
+ return;
+
+ // Check that the factory has already been loaded and not been
+ // destroyed in the meantime.
+ Reference<XInterface> xFactory;
+ auto iLoadedFactory = maLoadedFactories.find(iFactory->second);
+ if (iLoadedFactory != maLoadedFactories.end())
+ xFactory.set(iLoadedFactory->second, UNO_QUERY);
+ if ( xFactory.is())
+ return;
+
+ // Create a new instance of the factory.
+ Reference<uno::XComponentContext> xContext =
+ ::comphelper::getProcessComponentContext();
+
+ // Create the factory service.
+ Sequence<Any> aArguments{ Any(mxController) };
+ try
+ {
+ xFactory = xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ iFactory->second,
+ aArguments,
+ xContext);
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sd.fwk", "caught exception while creating factory");
+ }
+
+ // Remember that this factory has been instanced.
+ maLoadedFactories[iFactory->second] = xFactory;
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL ModuleController::initialize (const Sequence<Any>& aArguments)
+{
+ if (aArguments.hasElements())
+ {
+ try
+ {
+ // Get the XController from the first argument.
+ mxController.set(aArguments[0], UNO_QUERY_THROW);
+
+ InstantiateStartupServices();
+ }
+ catch (RuntimeException&)
+ {}
+ }
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_module_ModuleController_get_implementation(
+ css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ css::uno::Reference< css::uno::XInterface > xModCont ( sd::framework::ModuleController::CreateInstance(context) );
+ xModCont->acquire();
+ return xModCont.get();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/PresentationModule.cxx b/sd/source/ui/framework/module/PresentationModule.cxx
new file mode 100644
index 000000000..fb0ac0558
--- /dev/null
+++ b/sd/source/ui/framework/module/PresentationModule.cxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <framework/PresentationModule.hxx>
+
+#include "CenterViewFocusModule.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::framework
+{
+void PresentationModule::Initialize(Reference<frame::XController> const& rxController)
+{
+ new sd::framework::CenterViewFocusModule(rxController);
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ShellStackGuard.cxx b/sd/source/ui/framework/module/ShellStackGuard.cxx
new file mode 100644
index 000000000..83d73b055
--- /dev/null
+++ b/sd/source/ui/framework/module/ShellStackGuard.cxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ShellStackGuard.hxx"
+
+#include <framework/ConfigurationController.hxx>
+#include <framework/FrameworkHelper.hxx>
+
+#include <DrawController.hxx>
+#include <ViewShellBase.hxx>
+#include <sfx2/printer.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <comphelper/servicehelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace sd::framework {
+
+//===== CenterViewFocusModule ====================================================
+
+ShellStackGuard::ShellStackGuard (Reference<frame::XController> const & rxController)
+ : mpBase(nullptr),
+ maPrinterPollingIdle("sd ShellStackGuard PrinterPollingIdle")
+{
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ mxConfigurationController = xControllerManager->getConfigurationController();
+
+ // Tunnel through the controller to obtain a ViewShellBase.
+ auto pController = comphelper::getFromUnoTunnel<sd::DrawController>(rxController);
+ if (pController != nullptr)
+ mpBase = pController->GetViewShellBase();
+ }
+
+ if (mxConfigurationController.is())
+ {
+ // Listen for update starts so that the following update can be
+ // prevented in case of a printing printer.
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateStartEvent,
+ Any());
+
+ // Prepare the printer polling.
+ maPrinterPollingIdle.SetInvokeHandler(LINK(this,ShellStackGuard,TimeoutHandler));
+ }
+}
+
+ShellStackGuard::~ShellStackGuard()
+{
+}
+
+void ShellStackGuard::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxConfigurationController)
+ {
+ mxConfigurationController->removeConfigurationChangeListener(this);
+ mxConfigurationController = nullptr;
+ }
+ mpBase = nullptr;
+}
+
+void SAL_CALL ShellStackGuard::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (rEvent.Type == FrameworkHelper::msConfigurationUpdateStartEvent)
+ {
+ if (mpUpdateLock == nullptr && IsPrinting())
+ {
+ // Prevent configuration updates while the printer is printing.
+ mpUpdateLock.reset(new ConfigurationController::Lock(mxConfigurationController));
+
+ // Start polling for the printer having finished printing.
+ maPrinterPollingIdle.Start();
+ }
+ }
+}
+
+void SAL_CALL ShellStackGuard::disposing (
+ const lang::EventObject& rEvent)
+{
+ if (mxConfigurationController.is())
+ if (rEvent.Source == mxConfigurationController)
+ {
+ mxConfigurationController = nullptr;
+ mpBase = nullptr;
+ }
+}
+
+IMPL_LINK(ShellStackGuard, TimeoutHandler, Timer*, pIdle, void)
+{
+#ifdef DEBUG
+ OSL_ASSERT(pIdle==&maPrinterPollingIdle);
+#else
+ (void)pIdle;
+#endif
+ if (mpUpdateLock == nullptr)
+ return;
+
+ if ( ! IsPrinting())
+ {
+ // Printing finished. Release the update lock.
+ mpUpdateLock.reset();
+ }
+ else
+ {
+ // Wait long for the printing to finish.
+ maPrinterPollingIdle.Start();
+ }
+}
+
+bool ShellStackGuard::IsPrinting() const
+{
+ if (mpBase != nullptr)
+ {
+ SfxPrinter* pPrinter = mpBase->GetPrinter();
+ if (pPrinter != nullptr
+ && pPrinter->IsPrinting())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ShellStackGuard.hxx b/sd/source/ui/framework/module/ShellStackGuard.hxx
new file mode 100644
index 000000000..72b7ed2c6
--- /dev/null
+++ b/sd/source/ui/framework/module/ShellStackGuard.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <framework/ConfigurationController.hxx>
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+
+#include <vcl/idle.hxx>
+#include <comphelper/compbase.hxx>
+#include <memory>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfigurationController;
+}
+namespace com::sun::star::frame
+{
+class XController;
+}
+
+namespace sd
+{
+class ViewShellBase;
+}
+
+namespace sd::framework
+{
+typedef comphelper::WeakComponentImplHelper<css::drawing::framework::XConfigurationChangeListener>
+ ShellStackGuardInterfaceBase;
+
+/** This module locks updates of the current configuration in situations
+ when the shell stack must not be modified.
+
+ On every start of a configuration update the ShellStackGuard checks the
+ printer. If it is printing the configuration update is locked. It then
+ polls the printer and unlocks updates when printing finishes.
+
+ When in the future there are no resources left that use shells then this
+ module can be removed.
+*/
+class ShellStackGuard : public ShellStackGuardInterfaceBase
+{
+public:
+ explicit ShellStackGuard(css::uno::Reference<css::frame::XController> const& rxController);
+ virtual ~ShellStackGuard() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange(
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override;
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+ ViewShellBase* mpBase;
+ std::unique_ptr<ConfigurationController::Lock> mpUpdateLock;
+ Idle maPrinterPollingIdle;
+
+ DECL_LINK(TimeoutHandler, Timer*, void);
+
+ /** Return <TRUE/> when the printer is printing. Return <FALSE/> when
+ the printer is not printing, or there is no printer, or something
+ else went wrong.
+ */
+ bool IsPrinting() const;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/SlideSorterModule.cxx b/sd/source/ui/framework/module/SlideSorterModule.cxx
new file mode 100644
index 000000000..dbe30f0d3
--- /dev/null
+++ b/sd/source/ui/framework/module/SlideSorterModule.cxx
@@ -0,0 +1,313 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlideSorterModule.hxx"
+
+#include <framework/FrameworkHelper.hxx>
+#include <framework/ConfigurationController.hxx>
+#include <com/sun/star/drawing/framework/XTabBar.hpp>
+#include <com/sun/star/drawing/framework/TabBarButton.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/frame/XController.hpp>
+
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <svtools/slidesorterbaropt.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace {
+ const sal_Int32 ResourceActivationRequestEvent = 0;
+ const sal_Int32 ResourceDeactivationRequestEvent = 1;
+}
+
+namespace sd::framework {
+
+//===== SlideSorterModule ==================================================
+
+SlideSorterModule::SlideSorterModule (
+ const Reference<frame::XController>& rxController,
+ const OUString& rsLeftPaneURL)
+ : mxResourceId(FrameworkHelper::CreateResourceId(FrameworkHelper::msSlideSorterURL, rsLeftPaneURL)),
+ mxMainViewAnchorId(FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL)),
+ mxViewTabBarId(FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msViewTabBarURL,
+ FrameworkHelper::msCenterPaneURL)),
+ mxControllerManager(rxController,UNO_QUERY)
+{
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ mxConfigurationController = xControllerManager->getConfigurationController();
+
+ if (mxConfigurationController.is())
+ {
+ uno::Reference<lang::XComponent> const xComppnent(
+ mxConfigurationController, UNO_QUERY_THROW);
+ xComppnent->addEventListener(this);
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationRequestEvent,
+ Any(ResourceActivationRequestEvent));
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceDeactivationRequestEvent,
+ Any(ResourceDeactivationRequestEvent));
+ }
+ }
+ if (!mxConfigurationController.is())
+ return;
+
+ UpdateViewTabBar(nullptr);
+
+ if (SvtSlideSorterBarOptions().GetVisibleImpressView())
+ AddActiveMainView(FrameworkHelper::msImpressViewURL);
+ if (SvtSlideSorterBarOptions().GetVisibleOutlineView())
+ AddActiveMainView(FrameworkHelper::msOutlineViewURL);
+ if (SvtSlideSorterBarOptions().GetVisibleNotesView())
+ AddActiveMainView(FrameworkHelper::msNotesViewURL);
+ if (SvtSlideSorterBarOptions().GetVisibleHandoutView())
+ AddActiveMainView(FrameworkHelper::msHandoutViewURL);
+ if (SvtSlideSorterBarOptions().GetVisibleSlideSorterView())
+ AddActiveMainView(FrameworkHelper::msSlideSorterURL);
+ if (SvtSlideSorterBarOptions().GetVisibleDrawView())
+ AddActiveMainView(FrameworkHelper::msDrawViewURL);
+
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationEvent,
+ Any());
+}
+
+SlideSorterModule::~SlideSorterModule()
+{
+}
+
+void SlideSorterModule::SaveResourceState()
+{
+ SvtSlideSorterBarOptions().SetVisibleImpressView(IsResourceActive(FrameworkHelper::msImpressViewURL));
+ SvtSlideSorterBarOptions().SetVisibleOutlineView(IsResourceActive(FrameworkHelper::msOutlineViewURL));
+ SvtSlideSorterBarOptions().SetVisibleNotesView(IsResourceActive(FrameworkHelper::msNotesViewURL));
+ SvtSlideSorterBarOptions().SetVisibleHandoutView(IsResourceActive(FrameworkHelper::msHandoutViewURL));
+ SvtSlideSorterBarOptions().SetVisibleSlideSorterView(IsResourceActive(FrameworkHelper::msSlideSorterURL));
+ SvtSlideSorterBarOptions().SetVisibleDrawView(IsResourceActive(FrameworkHelper::msDrawViewURL));
+}
+
+void SAL_CALL SlideSorterModule::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (rEvent.Type == FrameworkHelper::msResourceActivationEvent)
+ {
+ if (rEvent.ResourceId->compareTo(mxViewTabBarId) == 0)
+ {
+ // Update the view tab bar because the view tab bar has just
+ // become active.
+ UpdateViewTabBar(Reference<XTabBar>(rEvent.ResourceObject,UNO_QUERY));
+ }
+ else if (rEvent.ResourceId->getResourceTypePrefix() ==
+ FrameworkHelper::msViewURLPrefix
+ && rEvent.ResourceId->isBoundTo(
+ FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL),
+ AnchorBindingMode_DIRECT))
+ {
+ // Update the view tab bar because the view in the center pane
+ // has changed.
+ UpdateViewTabBar(nullptr);
+ }
+ return;
+ }
+
+ OSL_ASSERT(rEvent.ResourceId.is());
+ sal_Int32 nEventType = 0;
+ rEvent.UserData >>= nEventType;
+ switch (nEventType)
+ {
+ case ResourceActivationRequestEvent:
+ if (rEvent.ResourceId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL,
+ AnchorBindingMode_DIRECT))
+ {
+ // A resource directly bound to the center pane has been
+ // requested.
+ if (rEvent.ResourceId->getResourceTypePrefix() ==
+ FrameworkHelper::msViewURLPrefix)
+ {
+ // The requested resource is a view. Show or hide the
+ // resource managed by this ResourceManager accordingly.
+ HandleMainViewSwitch(
+ rEvent.ResourceId->getResourceURL(),
+ true);
+ }
+ }
+ else if (rEvent.ResourceId->compareTo(mxResourceId) == 0)
+ {
+ // The resource managed by this ResourceManager has been
+ // explicitly been requested (maybe by us). Remember this
+ // setting.
+ HandleResourceRequest(true, rEvent.Configuration);
+ }
+ break;
+
+ case ResourceDeactivationRequestEvent:
+ if (rEvent.ResourceId->compareTo(mxMainViewAnchorId) == 0)
+ {
+ HandleMainViewSwitch(
+ OUString(),
+ false);
+ }
+ else if (rEvent.ResourceId->compareTo(mxResourceId) == 0)
+ {
+ // The resource managed by this ResourceManager has been
+ // explicitly been requested to be hidden (maybe by us).
+ // Remember this setting.
+ HandleResourceRequest(false, rEvent.Configuration);
+ }
+ break;
+ }
+}
+
+void SlideSorterModule::UpdateViewTabBar (const Reference<XTabBar>& rxTabBar)
+{
+ if ( ! mxControllerManager.is())
+ return;
+
+ Reference<XTabBar> xBar (rxTabBar);
+ if ( ! xBar.is())
+ {
+ Reference<XConfigurationController> xCC (
+ mxControllerManager->getConfigurationController());
+ if (xCC.is())
+ xBar.set(xCC->getResource(mxViewTabBarId), UNO_QUERY);
+ }
+
+ if (!xBar.is())
+ return;
+
+ TabBarButton aButtonA;
+ aButtonA.ResourceId = FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msSlideSorterURL,
+ FrameworkHelper::msCenterPaneURL);
+ aButtonA.ButtonLabel = SdResId(STR_SLIDE_SORTER_MODE);
+
+ TabBarButton aButtonB;
+ aButtonB.ResourceId = FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msHandoutViewURL,
+ FrameworkHelper::msCenterPaneURL);
+
+ if ( ! xBar->hasTabBarButton(aButtonA))
+ xBar->addTabBarButtonAfter(aButtonA, aButtonB);
+}
+
+void SlideSorterModule::AddActiveMainView (
+ const OUString& rsMainViewURL)
+{
+ maActiveMainViewContainer.insert(rsMainViewURL);
+}
+
+bool SlideSorterModule::IsResourceActive (
+ const OUString& rsMainViewURL)
+{
+ return (maActiveMainViewContainer.find(rsMainViewURL) != maActiveMainViewContainer.end());
+}
+
+void SlideSorterModule::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxConfigurationController.is())
+ {
+ uno::Reference<lang::XComponent> const xComponent(mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(this);
+
+ mxConfigurationController->removeConfigurationChangeListener(this);
+ mxConfigurationController = nullptr;
+ }
+}
+
+void SlideSorterModule::HandleMainViewSwitch (
+ const OUString& rsViewURL,
+ const bool bIsActivated)
+{
+ if (bIsActivated)
+ msCurrentMainViewURL = rsViewURL;
+ else
+ msCurrentMainViewURL.clear();
+
+ if (!mxConfigurationController.is())
+ return;
+
+ ConfigurationController::Lock aLock (mxConfigurationController);
+
+ if (maActiveMainViewContainer.find(msCurrentMainViewURL)
+ != maActiveMainViewContainer.end())
+ {
+ // Activate resource.
+ mxConfigurationController->requestResourceActivation(
+ mxResourceId->getAnchor(),
+ ResourceActivationMode_ADD);
+ mxConfigurationController->requestResourceActivation(
+ mxResourceId,
+ ResourceActivationMode_REPLACE);
+ }
+ else
+ {
+ mxConfigurationController->requestResourceDeactivation(mxResourceId);
+ }
+}
+
+void SlideSorterModule::HandleResourceRequest(
+ bool bActivation,
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ Sequence<Reference<XResourceId> > aCenterViews = rxConfiguration->getResources(
+ FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL),
+ FrameworkHelper::msViewURLPrefix,
+ AnchorBindingMode_DIRECT);
+ if (aCenterViews.getLength() == 1)
+ {
+ if (bActivation)
+ {
+ maActiveMainViewContainer.insert(aCenterViews[0]->getResourceURL());
+ }
+ else
+ {
+ maActiveMainViewContainer.erase(aCenterViews[0]->getResourceURL());
+ }
+ }
+}
+
+void SAL_CALL SlideSorterModule::disposing (
+ const lang::EventObject& rEvent)
+{
+ if (mxConfigurationController.is()
+ && rEvent.Source == mxConfigurationController)
+ {
+ SaveResourceState();
+ // Without the configuration controller this class can do nothing.
+ mxConfigurationController = nullptr;
+ dispose();
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/SlideSorterModule.hxx b/sd/source/ui/framework/module/SlideSorterModule.hxx
new file mode 100644
index 000000000..bec9f5c3c
--- /dev/null
+++ b/sd/source/ui/framework/module/SlideSorterModule.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <comphelper/compbase.hxx>
+#include <memory>
+#include <set>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XControllerManager; }
+namespace com::sun::star::drawing::framework { class XTabBar; }
+namespace com::sun::star::frame { class XController; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeListener
+ > SlideSorterModuleBase;
+
+/** This module is responsible for showing the slide sorter bar and the
+ slide sorter view in the center pane.
+
+ Manage the activation state of one resource depending on the view in the
+ center pane. The ResourceManager remembers in which configuration to
+ activate and in which to deactivate the resource. When the resource is
+ deactivated or activated manually by the user then the ResourceManager
+ detects this and remembers it for the future.
+*/
+class SlideSorterModule final
+ : public SlideSorterModuleBase
+{
+public:
+ SlideSorterModule (
+ const css::uno::Reference<css::frame::XController>& rxController,
+ const OUString& rsLeftPaneURL);
+ virtual ~SlideSorterModule() override;
+
+ /** Remember the given URL as one of a center pane view for which to
+ activate the resource managed by the called object.
+ */
+ void AddActiveMainView (const OUString& rsMainViewURL);
+ bool IsResourceActive (const OUString& rsMainViewURL);
+ void SaveResourceState();
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfigurationChangeListener
+ virtual void SAL_CALL notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEvent) override;
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+ ::std::set<OUString> maActiveMainViewContainer;
+ /// The resource managed by this class.
+ css::uno::Reference<css::drawing::framework::XResourceId> mxResourceId;
+ /// The anchor of the main view.
+ css::uno::Reference<css::drawing::framework::XResourceId> mxMainViewAnchorId;
+ OUString msCurrentMainViewURL;
+ css::uno::Reference<css::drawing::framework::XResourceId> mxViewTabBarId;
+ css::uno::Reference<css::drawing::framework::XControllerManager> mxControllerManager;
+
+ void HandleMainViewSwitch (
+ const OUString& rsViewURL,
+ const bool bIsActivated);
+ void HandleResourceRequest(
+ bool bActivation,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+ void UpdateViewTabBar (
+ const css::uno::Reference<css::drawing::framework::XTabBar>& rxViewTabBar);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ToolBarModule.cxx b/sd/source/ui/framework/module/ToolBarModule.cxx
new file mode 100644
index 000000000..3cecf7b03
--- /dev/null
+++ b/sd/source/ui/framework/module/ToolBarModule.cxx
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ToolBarModule.hxx"
+#include <ViewShellBase.hxx>
+#include <DrawController.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <framework/FrameworkHelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace {
+ const sal_Int32 gnConfigurationUpdateStartEvent(0);
+ const sal_Int32 gnConfigurationUpdateEndEvent(1);
+ const sal_Int32 gnResourceActivationRequestEvent(2);
+ const sal_Int32 gnResourceDeactivationRequestEvent(3);
+}
+
+namespace sd::framework {
+
+//===== ToolBarModule =========================================================
+
+ToolBarModule::ToolBarModule (
+ const Reference<frame::XController>& rxController)
+ : mpBase(nullptr),
+ mbMainViewSwitchUpdatePending(false)
+{
+ // Tunnel through the controller to obtain a ViewShellBase.
+ auto pController = comphelper::getFromUnoTunnel<sd::DrawController>(rxController);
+ if (pController != nullptr)
+ mpBase = pController->GetViewShellBase();
+
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY);
+ if (!xControllerManager.is())
+ return;
+
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (!mxConfigurationController.is())
+ return;
+
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateStartEvent,
+ Any(gnConfigurationUpdateStartEvent));
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ Any(gnConfigurationUpdateEndEvent));
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationRequestEvent,
+ Any(gnResourceActivationRequestEvent));
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceDeactivationRequestEvent,
+ Any(gnResourceDeactivationRequestEvent));
+}
+
+ToolBarModule::~ToolBarModule()
+{
+}
+
+void ToolBarModule::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->removeConfigurationChangeListener(this);
+ mxConfigurationController = nullptr;
+ }
+}
+
+void SAL_CALL ToolBarModule::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (!mxConfigurationController.is())
+ return;
+
+ sal_Int32 nEventType = 0;
+ rEvent.UserData >>= nEventType;
+ switch (nEventType)
+ {
+ case gnConfigurationUpdateStartEvent:
+ HandleUpdateStart();
+ break;
+
+ case gnConfigurationUpdateEndEvent:
+ HandleUpdateEnd();
+ break;
+
+ case gnResourceActivationRequestEvent:
+ case gnResourceDeactivationRequestEvent:
+ // Remember the request for the activation or deactivation
+ // of the center pane view. When that happens then on end
+ // of the next configuration update the set of visible tool
+ // bars will be updated.
+ if ( ! mbMainViewSwitchUpdatePending)
+ if (rEvent.ResourceId->getResourceURL().match(
+ FrameworkHelper::msViewURLPrefix)
+ && rEvent.ResourceId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
+ {
+ mbMainViewSwitchUpdatePending = true;
+ }
+ break;
+ }
+}
+
+void ToolBarModule::HandleUpdateStart()
+{
+ // Lock the ToolBarManager and tell it to lock the ViewShellManager as
+ // well. This way the ToolBarManager can optimize the releasing of
+ // locks and arranging of updates of both tool bars and the view shell
+ // stack.
+ if (mpBase != nullptr)
+ {
+ std::shared_ptr<ToolBarManager> pToolBarManager (mpBase->GetToolBarManager());
+ mpToolBarManagerLock.reset(new ToolBarManager::UpdateLock(pToolBarManager));
+ pToolBarManager->LockViewShellManager();
+ }
+}
+
+void ToolBarModule::HandleUpdateEnd()
+{
+ if (mbMainViewSwitchUpdatePending)
+ {
+ mbMainViewSwitchUpdatePending = false;
+ // Update the set of visible tool bars and deactivate those that are
+ // no longer visible. This is done before the old view shell is
+ // destroyed in order to avoid unnecessary updates of those tool
+ // bars.
+ std::shared_ptr<ToolBarManager> pToolBarManager (mpBase->GetToolBarManager());
+ std::shared_ptr<FrameworkHelper> pFrameworkHelper (
+ FrameworkHelper::Instance(*mpBase));
+ ViewShell* pViewShell
+ = pFrameworkHelper->GetViewShell(FrameworkHelper::msCenterPaneURL).get();
+ if (pViewShell != nullptr)
+ {
+ pToolBarManager->MainViewShellChanged(*pViewShell);
+ pToolBarManager->SelectionHasChanged(
+ *pViewShell,
+ *pViewShell->GetView());
+ pToolBarManager->PreUpdate();
+ }
+ else
+ {
+ pToolBarManager->MainViewShellChanged();
+ pToolBarManager->PreUpdate();
+ }
+ }
+
+ // Releasing the update lock of the ToolBarManager will let the
+ // ToolBarManager with the help of the ViewShellManager take care of
+ // updating tool bars and view shell with the minimal amount of
+ // shell stack modifications and tool bar updates.
+ mpToolBarManagerLock.reset();
+}
+
+void SAL_CALL ToolBarModule::disposing (const lang::EventObject& rEvent)
+{
+ if (mxConfigurationController.is()
+ && rEvent.Source == mxConfigurationController)
+ {
+ // Without the configuration controller this class can do nothing.
+ mxConfigurationController = nullptr;
+ dispose();
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ToolBarModule.hxx b/sd/source/ui/framework/module/ToolBarModule.hxx
new file mode 100644
index 000000000..f9189657d
--- /dev/null
+++ b/sd/source/ui/framework/module/ToolBarModule.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ToolBarManager.hxx>
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <comphelper/compbase.hxx>
+#include <o3tl/deleter.hxx>
+#include <memory>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::frame { class XController; }
+
+namespace sd {
+class ViewShellBase;
+}
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeListener
+ > ToolBarModuleInterfaceBase;
+
+/** This module is responsible for locking the ToolBarManager during
+ configuration updates and for triggering ToolBarManager updates.
+*/
+class ToolBarModule final
+ : public ToolBarModuleInterfaceBase
+{
+public:
+ /** Create a new module.
+ @param rxController
+ This is the access point to the drawing framework.
+ */
+ explicit ToolBarModule (
+ const css::uno::Reference<css::frame::XController>& rxController);
+ virtual ~ToolBarModule() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEvent) override;
+
+private:
+ css::uno::Reference<
+ css::drawing::framework::XConfigurationController> mxConfigurationController;
+ ViewShellBase* mpBase;
+ std::unique_ptr<ToolBarManager::UpdateLock, o3tl::default_delete<ToolBarManager::UpdateLock>> mpToolBarManagerLock;
+ bool mbMainViewSwitchUpdatePending;
+
+ void HandleUpdateStart();
+ void HandleUpdateEnd();
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ViewTabBarModule.cxx b/sd/source/ui/framework/module/ViewTabBarModule.cxx
new file mode 100644
index 000000000..4f5dd4828
--- /dev/null
+++ b/sd/source/ui/framework/module/ViewTabBarModule.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 "ViewTabBarModule.hxx"
+
+#include <framework/FrameworkHelper.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XTabBar.hpp>
+#include <com/sun/star/frame/XController.hpp>
+
+#include <strings.hrc>
+#include <sdresid.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace {
+
+const sal_Int32 ResourceActivationRequestEvent = 0;
+const sal_Int32 ResourceDeactivationRequestEvent = 1;
+const sal_Int32 ResourceActivationEvent = 2;
+
+}
+
+namespace sd::framework {
+
+//===== ViewTabBarModule ==================================================
+
+ViewTabBarModule::ViewTabBarModule (
+ const Reference<frame::XController>& rxController,
+ const Reference<XResourceId>& rxViewTabBarId)
+ : mxViewTabBarId(rxViewTabBarId)
+{
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY);
+
+ if (!xControllerManager.is())
+ return;
+
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (!mxConfigurationController.is())
+ return;
+
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationRequestEvent,
+ Any(ResourceActivationRequestEvent));
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceDeactivationRequestEvent,
+ Any(ResourceDeactivationRequestEvent));
+
+ UpdateViewTabBar(nullptr);
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationEvent,
+ Any(ResourceActivationEvent));
+}
+
+ViewTabBarModule::~ViewTabBarModule()
+{
+}
+
+void ViewTabBarModule::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->removeConfigurationChangeListener(this);
+ mxConfigurationController = nullptr;
+ }
+}
+
+void SAL_CALL ViewTabBarModule::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (!mxConfigurationController.is())
+ return;
+
+ sal_Int32 nEventType = 0;
+ rEvent.UserData >>= nEventType;
+ switch (nEventType)
+ {
+ case ResourceActivationRequestEvent:
+ if (mxViewTabBarId->isBoundTo(rEvent.ResourceId, AnchorBindingMode_DIRECT))
+ {
+ mxConfigurationController->requestResourceActivation(
+ mxViewTabBarId,
+ ResourceActivationMode_ADD);
+ }
+ break;
+
+ case ResourceDeactivationRequestEvent:
+ if (mxViewTabBarId->isBoundTo(rEvent.ResourceId, AnchorBindingMode_DIRECT))
+ {
+ mxConfigurationController->requestResourceDeactivation(mxViewTabBarId);
+ }
+ break;
+
+ case ResourceActivationEvent:
+ if (rEvent.ResourceId->compareTo(mxViewTabBarId) == 0)
+ {
+ UpdateViewTabBar(Reference<XTabBar>(rEvent.ResourceObject,UNO_QUERY));
+ }
+ }
+}
+
+void SAL_CALL ViewTabBarModule::disposing (
+ const lang::EventObject& rEvent)
+{
+ if (mxConfigurationController.is()
+ && rEvent.Source == mxConfigurationController)
+ {
+ // Without the configuration controller this class can do nothing.
+ mxConfigurationController = nullptr;
+ dispose();
+ }
+}
+
+void ViewTabBarModule::UpdateViewTabBar (const Reference<XTabBar>& rxTabBar)
+{
+ if (!mxConfigurationController.is())
+ return;
+
+ Reference<XTabBar> xBar (rxTabBar);
+ if ( ! xBar.is())
+ xBar.set( mxConfigurationController->getResource(mxViewTabBarId), UNO_QUERY);
+
+ if (!xBar.is())
+ return;
+
+ TabBarButton aEmptyButton;
+
+ Reference<XResourceId> xAnchor (mxViewTabBarId->getAnchor());
+
+ TabBarButton aImpressViewButton;
+ aImpressViewButton.ResourceId = FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msImpressViewURL,
+ xAnchor);
+ aImpressViewButton.ButtonLabel = SdResId(STR_NORMAL_MODE);
+ if ( ! xBar->hasTabBarButton(aImpressViewButton))
+ xBar->addTabBarButtonAfter(aImpressViewButton, aEmptyButton);
+
+ TabBarButton aOutlineViewButton;
+ aOutlineViewButton.ResourceId = FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msOutlineViewURL,
+ xAnchor);
+ aOutlineViewButton.ButtonLabel = SdResId(STR_OUTLINE_MODE);
+ if ( ! xBar->hasTabBarButton(aOutlineViewButton))
+ xBar->addTabBarButtonAfter(aOutlineViewButton, aImpressViewButton);
+
+ TabBarButton aNotesViewButton;
+ aNotesViewButton.ResourceId = FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msNotesViewURL,
+ xAnchor);
+ aNotesViewButton.ButtonLabel = SdResId(STR_NOTES_MODE);
+ if ( ! xBar->hasTabBarButton(aNotesViewButton))
+ xBar->addTabBarButtonAfter(aNotesViewButton, aOutlineViewButton);
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ViewTabBarModule.hxx b/sd/source/ui/framework/module/ViewTabBarModule.hxx
new file mode 100644
index 000000000..bfb252b8d
--- /dev/null
+++ b/sd/source/ui/framework/module/ViewTabBarModule.hxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XTabBar; }
+namespace com::sun::star::frame { class XController; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeListener
+ > ViewTabBarModuleInterfaceBase;
+
+/** This module is responsible for showing the ViewTabBar above the view in
+ the center pane.
+*/
+class ViewTabBarModule
+ : public ViewTabBarModuleInterfaceBase
+{
+public:
+ /** Create a new module that controls the view tab bar above the view
+ in the specified pane.
+ @param rxController
+ This is the access point to the drawing framework.
+ @param rxViewTabBarId
+ This ResourceId specifies which tab bar is to be managed by the
+ new module.
+ */
+ ViewTabBarModule (
+ const css::uno::Reference<css::frame::XController>& rxController,
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxViewTabBarId);
+ virtual ~ViewTabBarModule() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEvent) override;
+
+private:
+ css::uno::Reference<
+ css::drawing::framework::XConfigurationController> mxConfigurationController;
+ css::uno::Reference<css::drawing::framework::XResourceId> mxViewTabBarId;
+
+ /** This is the place where the view tab bar is filled. Only missing
+ buttons are added, so it is safe to call this method multiple
+ times.
+ */
+ void UpdateViewTabBar (
+ const css::uno::Reference<css::drawing::framework::XTabBar>& rxTabBar);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/tools/FrameworkHelper.cxx b/sd/source/ui/framework/tools/FrameworkHelper.cxx
new file mode 100644
index 000000000..dceecd510
--- /dev/null
+++ b/sd/source/ui/framework/tools/FrameworkHelper.cxx
@@ -0,0 +1,952 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/time.h>
+
+#include <framework/FrameworkHelper.hxx>
+
+#include <framework/ConfigurationController.hxx>
+#include <framework/ResourceId.hxx>
+#include <framework/ViewShellWrapper.hxx>
+#include <ViewShellBase.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShellHint.hxx>
+#include <app.hrc>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/compbase.hxx>
+#include <svl/lstner.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <sfx2/request.hxx>
+
+#include <vcl/svapp.hxx>
+#include <osl/doublecheckedlocking.h>
+#include <osl/getglobalmutex.hxx>
+#include <tools/diagnose_ex.h>
+#include <memory>
+#include <unordered_map>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace {
+
+//----- CallbackCaller --------------------------------------------------------
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeListener
+ > CallbackCallerInterfaceBase;
+
+/** A CallbackCaller registers as listener at an XConfigurationController
+ object and waits for the notification of one type of event. When that
+ event is received, or when the CallbackCaller detects at its
+ construction that the event will not be sent in the near future, the
+ actual callback object is called and the CallbackCaller destroys itself.
+*/
+class CallbackCaller
+ : public CallbackCallerInterfaceBase
+{
+public:
+ /** Create a new CallbackCaller object. This object controls its own
+ lifetime by acquiring a reference to itself in the constructor.
+ When it detects that the event will not be notified in the near
+ future (because the queue of pending configuration change operations
+ is empty and therefore no event will be sent int the near future, it
+ does not acquires a reference and thus initiates its destruction in
+ the constructor.)
+ @param rBase
+ This ViewShellBase object is used to determine the
+ XConfigurationController at which to register.
+ @param rsEventType
+ The event type which the callback is waiting for.
+ @param pCallback
+ The callback object which is to be notified. The caller will
+ typically release his reference to the caller so that when the
+ CallbackCaller dies (after having called the callback) the
+ callback is destroyed.
+ */
+ CallbackCaller (
+ const ::sd::ViewShellBase& rBase,
+ const OUString& rsEventType,
+ const ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter& rFilter,
+ const ::sd::framework::FrameworkHelper::Callback& rCallback);
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+ // XEventListener
+ virtual void SAL_CALL disposing (const lang::EventObject& rEvent) override;
+ // XConfigurationChangeListener
+ virtual void SAL_CALL notifyConfigurationChange (const ConfigurationChangeEvent& rEvent) override;
+
+private:
+ OUString msEventType;
+ Reference<XConfigurationController> mxConfigurationController;
+ ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter maFilter;
+ ::sd::framework::FrameworkHelper::Callback maCallback;
+};
+
+//----- LifetimeController ----------------------------------------------------
+
+typedef comphelper::WeakComponentImplHelper <
+ css::lang::XEventListener
+ > LifetimeControllerInterfaceBase;
+
+/** This class helps controlling the lifetime of the
+ FrameworkHelper. Register at a ViewShellBase object and an XController
+ object and call Dispose() at the associated FrameworkHelper object when
+ one of them and Release() when both of them are destroyed.
+*/
+class LifetimeController
+ : public LifetimeControllerInterfaceBase,
+ public SfxListener
+{
+public:
+ explicit LifetimeController (::sd::ViewShellBase& rBase);
+ virtual ~LifetimeController() override;
+
+ /** XEventListener. This method is called when the frame::XController
+ is being destroyed.
+ */
+ using WeakComponentImplHelperBase::disposing;
+ virtual void SAL_CALL disposing (const lang::EventObject& rEvent) override;
+
+ /** This method is called when the ViewShellBase is being destroyed.
+ */
+ virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override;
+
+private:
+ ::sd::ViewShellBase& mrBase;
+ bool mbListeningToViewShellBase;
+ bool mbListeningToController;
+
+ /** When one or both of the mbListeningToViewShellBase and
+ mbListeningToController members were modified then call this method
+ to either dispose or release the associated FrameworkHelper.
+ */
+ void Update();
+};
+
+} // end of anonymous namespace
+
+namespace sd::framework {
+
+namespace {
+
+ class FrameworkHelperAllPassFilter
+ {
+ public:
+ bool operator() (const css::drawing::framework::ConfigurationChangeEvent&) { return true; }
+ };
+
+ class FrameworkHelperResourceIdFilter
+ {
+ public:
+ explicit FrameworkHelperResourceIdFilter (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId);
+ bool operator() (const css::drawing::framework::ConfigurationChangeEvent& rEvent)
+ { return mxResourceId.is() && rEvent.ResourceId.is()
+ && mxResourceId->compareTo(rEvent.ResourceId) == 0; }
+ private:
+ css::uno::Reference<css::drawing::framework::XResourceId> mxResourceId;
+ };
+
+} // end of anonymous namespace
+
+// Pane URLS.
+
+const OUString FrameworkHelper::msCenterPaneURL( msPaneURLPrefix + "CenterPane");
+const OUString FrameworkHelper::msFullScreenPaneURL( msPaneURLPrefix + "FullScreenPane");
+const OUString FrameworkHelper::msLeftImpressPaneURL( msPaneURLPrefix + "LeftImpressPane");
+const OUString FrameworkHelper::msLeftDrawPaneURL( msPaneURLPrefix + "LeftDrawPane");
+
+// View URLs.
+
+const OUString FrameworkHelper::msImpressViewURL( msViewURLPrefix + "ImpressView");
+const OUString FrameworkHelper::msDrawViewURL( msViewURLPrefix + "GraphicView");
+const OUString FrameworkHelper::msOutlineViewURL( msViewURLPrefix + "OutlineView");
+const OUString FrameworkHelper::msNotesViewURL( msViewURLPrefix + "NotesView");
+const OUString FrameworkHelper::msHandoutViewURL( msViewURLPrefix + "HandoutView");
+const OUString FrameworkHelper::msSlideSorterURL( msViewURLPrefix + "SlideSorter");
+const OUString FrameworkHelper::msPresentationViewURL( msViewURLPrefix + "PresentationView");
+const OUString FrameworkHelper::msSidebarViewURL( msViewURLPrefix + "SidebarView");
+
+// Tool bar URLs.
+
+const OUString FrameworkHelper::msViewTabBarURL( msToolBarURLPrefix + "ViewTabBar");
+
+//----- helper ----------------------------------------------------------------
+namespace
+{
+ ::std::shared_ptr< ViewShell > lcl_getViewShell( const Reference< XResource >& i_rViewShellWrapper )
+ {
+ ::std::shared_ptr< ViewShell > pViewShell;
+ try
+ {
+ Reference<lang::XUnoTunnel> xViewTunnel( i_rViewShellWrapper, UNO_QUERY_THROW );
+ if (auto pWrapper = comphelper::getFromUnoTunnel<ViewShellWrapper>(xViewTunnel))
+ pViewShell = pWrapper->GetViewShell();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ return pViewShell;
+ }
+ Reference< XResource > lcl_getFirstViewInPane( const Reference< XConfigurationController >& i_rConfigController,
+ const Reference< XResourceId >& i_rPaneId )
+ {
+ try
+ {
+ Reference< XConfiguration > xConfiguration( i_rConfigController->getRequestedConfiguration(), UNO_SET_THROW );
+ Sequence< Reference< XResourceId > > aViewIds( xConfiguration->getResources(
+ i_rPaneId, FrameworkHelper::msViewURLPrefix, AnchorBindingMode_DIRECT ) );
+ if ( aViewIds.hasElements() )
+ return i_rConfigController->getResource( aViewIds[0] );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ return nullptr;
+ }
+}
+
+//----- FrameworkHelper::ViewURLMap -------------------------------------------
+
+/** The ViewURLMap is used to translate between the view URLs used by the
+ drawing framework and the enums defined in the ViewShell class.
+*/
+class FrameworkHelper::ViewURLMap
+ : public std::unordered_map<
+ OUString,
+ ViewShell::ShellType>
+{
+public:
+ ViewURLMap() {}
+};
+
+//----- Framework::DisposeListener ---------------------------------------------
+
+namespace {
+ typedef comphelper::WeakComponentImplHelper <
+ css::lang::XEventListener
+ > FrameworkHelperDisposeListenerInterfaceBase;
+}
+
+class FrameworkHelper::DisposeListener
+ : public FrameworkHelperDisposeListenerInterfaceBase
+{
+public:
+ explicit DisposeListener (const ::std::shared_ptr<FrameworkHelper>& rpHelper);
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ virtual void SAL_CALL disposing (const lang::EventObject& rEventObject) override;
+
+private:
+ ::std::shared_ptr<FrameworkHelper> mpHelper;
+};
+
+//----- FrameworkHelper::Deleter ----------------------------------------------
+
+class FrameworkHelper::Deleter
+{
+public:
+ void operator()(FrameworkHelper* pObject)
+ {
+ delete pObject;
+ }
+};
+
+//----- FrameworkHelper -------------------------------------------------------
+
+FrameworkHelper::ViewURLMap FrameworkHelper::maViewURLMap;
+
+FrameworkHelper::InstanceMap FrameworkHelper::maInstanceMap;
+
+::std::shared_ptr<FrameworkHelper> FrameworkHelper::Instance (ViewShellBase& rBase)
+{
+
+ ::std::shared_ptr<FrameworkHelper> pHelper;
+
+ InstanceMap::const_iterator iHelper (maInstanceMap.find(&rBase));
+ if (iHelper == maInstanceMap.end())
+ {
+ ::osl::GetGlobalMutex aMutexFunctor;
+ ::osl::MutexGuard aGuard (aMutexFunctor());
+ if (iHelper == maInstanceMap.end())
+ {
+ pHelper = ::std::shared_ptr<FrameworkHelper>(
+ new FrameworkHelper(rBase),
+ FrameworkHelper::Deleter());
+ pHelper->Initialize();
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ maInstanceMap[&rBase] = pHelper;
+ }
+ }
+ else
+ {
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ pHelper = iHelper->second;
+ }
+
+ return pHelper;
+}
+
+void FrameworkHelper::DisposeInstance (const ViewShellBase& rBase)
+{
+ InstanceMap::iterator iHelper (maInstanceMap.find(&rBase));
+ if (iHelper != maInstanceMap.end())
+ {
+ iHelper->second->Dispose();
+ }
+}
+
+void FrameworkHelper::ReleaseInstance (const ViewShellBase& rBase)
+{
+ InstanceMap::iterator iHelper (maInstanceMap.find(&rBase));
+ if (iHelper != maInstanceMap.end())
+ maInstanceMap.erase(iHelper);
+}
+
+FrameworkHelper::FrameworkHelper (ViewShellBase& rBase)
+ : mrBase(rBase)
+{
+ Reference<XControllerManager> xControllerManager (rBase.GetController(), UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ }
+
+ new LifetimeController(mrBase);
+}
+
+void FrameworkHelper::Initialize()
+{
+ mxDisposeListener = new DisposeListener(shared_from_this());
+}
+
+FrameworkHelper::~FrameworkHelper()
+{
+}
+
+void FrameworkHelper::Dispose()
+{
+ if (mxDisposeListener.is())
+ mxDisposeListener->dispose();
+ mxConfigurationController = nullptr;
+}
+
+bool FrameworkHelper::IsValid() const
+{
+ return mxConfigurationController.is();
+}
+
+::std::shared_ptr<ViewShell> FrameworkHelper::GetViewShell (const OUString& rsPaneURL)
+{
+ if ( !mxConfigurationController.is() )
+ return ::std::shared_ptr<ViewShell>();
+
+ Reference<XResourceId> xPaneId( CreateResourceId( rsPaneURL ) );
+ return lcl_getViewShell( lcl_getFirstViewInPane( mxConfigurationController, xPaneId ) );
+}
+
+::std::shared_ptr<ViewShell> FrameworkHelper::GetViewShell (const Reference<XView>& rxView)
+{
+ return lcl_getViewShell( rxView );
+}
+
+Reference<XView> FrameworkHelper::GetView (const Reference<XResourceId>& rxPaneOrViewId)
+{
+ Reference<XView> xView;
+
+ if ( ! rxPaneOrViewId.is() || ! mxConfigurationController.is())
+ return nullptr;
+
+ try
+ {
+ if (rxPaneOrViewId->getResourceURL().match(msViewURLPrefix))
+ {
+ xView.set( mxConfigurationController->getResource( rxPaneOrViewId ), UNO_QUERY );
+ }
+ else
+ {
+ xView.set( lcl_getFirstViewInPane( mxConfigurationController, rxPaneOrViewId ), UNO_QUERY );
+ }
+ }
+ catch (lang::DisposedException&)
+ {
+ Dispose();
+ }
+ catch (RuntimeException&)
+ {
+ }
+
+ return xView;
+}
+
+Reference<XResourceId> FrameworkHelper::RequestView (
+ const OUString& rsResourceURL,
+ const OUString& rsAnchorURL)
+{
+ Reference<XResourceId> xViewId;
+
+ try
+ {
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->requestResourceActivation(
+ CreateResourceId(rsAnchorURL),
+ ResourceActivationMode_ADD);
+ xViewId = CreateResourceId(rsResourceURL, rsAnchorURL);
+ mxConfigurationController->requestResourceActivation(
+ xViewId,
+ ResourceActivationMode_REPLACE);
+ }
+ }
+ catch (lang::DisposedException&)
+ {
+ Dispose();
+ xViewId = nullptr;
+ }
+ catch (RuntimeException&)
+ {
+ xViewId = nullptr;
+ }
+
+ return xViewId;
+}
+
+ViewShell::ShellType FrameworkHelper::GetViewId (const OUString& rsViewURL)
+{
+ if (maViewURLMap.empty())
+ {
+ maViewURLMap[msImpressViewURL] = ViewShell::ST_IMPRESS;
+ maViewURLMap[msDrawViewURL] = ViewShell::ST_DRAW;
+ maViewURLMap[msOutlineViewURL] = ViewShell::ST_OUTLINE;
+ maViewURLMap[msNotesViewURL] = ViewShell::ST_NOTES;
+ maViewURLMap[msHandoutViewURL] = ViewShell::ST_HANDOUT;
+ maViewURLMap[msSlideSorterURL] = ViewShell::ST_SLIDE_SORTER;
+ maViewURLMap[msPresentationViewURL] = ViewShell::ST_PRESENTATION;
+ maViewURLMap[msSidebarViewURL] = ViewShell::ST_SIDEBAR;
+ }
+ ViewURLMap::const_iterator iView (maViewURLMap.find(rsViewURL));
+ if (iView != maViewURLMap.end())
+ return iView->second;
+ else
+ return ViewShell::ST_NONE;
+}
+
+OUString FrameworkHelper::GetViewURL (ViewShell::ShellType eType)
+{
+ switch (eType)
+ {
+ case ViewShell::ST_IMPRESS : return msImpressViewURL;
+ case ViewShell::ST_DRAW : return msDrawViewURL;
+ case ViewShell::ST_OUTLINE : return msOutlineViewURL;
+ case ViewShell::ST_NOTES : return msNotesViewURL;
+ case ViewShell::ST_HANDOUT : return msHandoutViewURL;
+ case ViewShell::ST_SLIDE_SORTER : return msSlideSorterURL;
+ case ViewShell::ST_PRESENTATION : return msPresentationViewURL;
+ case ViewShell::ST_SIDEBAR : return msSidebarViewURL;
+ default:
+ return OUString();
+ }
+}
+
+namespace
+{
+
+void updateEditMode(const Reference<XView> &xView, const EditMode eEMode, bool updateFrameView)
+{
+ // Ensure we have the expected edit mode
+ // The check is only for DrawViewShell as OutlineViewShell
+ // and SlideSorterViewShell have no master mode
+ const ::std::shared_ptr<ViewShell> pCenterViewShell (FrameworkHelper::GetViewShell(xView));
+ DrawViewShell* pDrawViewShell
+ = dynamic_cast<DrawViewShell*>(pCenterViewShell.get());
+ if (pDrawViewShell != nullptr)
+ {
+ pCenterViewShell->Broadcast (
+ ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_START));
+
+ pDrawViewShell->ChangeEditMode(eEMode, pDrawViewShell->IsLayerModeActive());
+ if (updateFrameView)
+ pDrawViewShell->WriteFrameViewData();
+
+ pCenterViewShell->Broadcast (
+ ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_END));
+ }
+}
+
+void asyncUpdateEditMode(FrameworkHelper* const pHelper, const EditMode eEMode)
+{
+ Reference<XResourceId> xPaneId (
+ FrameworkHelper::CreateResourceId(framework::FrameworkHelper::msCenterPaneURL));
+ Reference<XView> xView (pHelper->GetView(xPaneId));
+ updateEditMode(xView, eEMode, true);
+}
+
+}
+
+void FrameworkHelper::HandleModeChangeSlot (
+ sal_uInt16 nSlotId,
+ SfxRequest const & rRequest)
+{
+ if ( ! mxConfigurationController.is())
+ return;
+
+ // Parameters are allowed for NotesMasterPage and SlideMasterPage
+ // for these command, transfor xxxxMasterPage with param = false
+ // to ActivatexxxxxMode
+ if (nSlotId == SID_NOTES_MASTER_MODE || nSlotId == SID_SLIDE_MASTER_MODE)
+ {
+ const SfxItemSet* pRequestArguments = rRequest.GetArgs();
+ if (pRequestArguments)
+ {
+ const SfxBoolItem* pIsActive = rRequest.GetArg<SfxBoolItem>(nSlotId);
+ if (!pIsActive->GetValue ())
+ {
+ if (nSlotId == SID_NOTES_MASTER_MODE)
+ nSlotId = SID_NOTES_MODE;
+ else
+ nSlotId = SID_NORMAL_MULTI_PANE_GUI;
+ }
+ }
+ }
+
+ try
+ {
+ if ( ! mxConfigurationController.is())
+ throw RuntimeException();
+
+ Reference<XResourceId> xPaneId (
+ CreateResourceId(framework::FrameworkHelper::msCenterPaneURL));
+ Reference<XView> xView (GetView(xPaneId));
+
+ // Compute requested view
+ OUString sRequestedView;
+ switch (nSlotId)
+ {
+ // draw
+ case SID_DRAWINGMODE:
+ // impress
+ case SID_NORMAL_MULTI_PANE_GUI:
+ case SID_SLIDE_MASTER_MODE:
+ sRequestedView = FrameworkHelper::msImpressViewURL;
+ break;
+
+ case SID_NOTES_MODE:
+ case SID_NOTES_MASTER_MODE:
+ sRequestedView = FrameworkHelper::msNotesViewURL;
+ break;
+
+ case SID_HANDOUT_MASTER_MODE:
+ sRequestedView = FrameworkHelper::msHandoutViewURL;
+ break;
+
+ case SID_SLIDE_SORTER_MULTI_PANE_GUI:
+ case SID_SLIDE_SORTER_MODE:
+ sRequestedView = FrameworkHelper::msSlideSorterURL;
+ break;
+
+ case SID_OUTLINE_MODE:
+ sRequestedView = FrameworkHelper::msOutlineViewURL;
+ break;
+ }
+
+ // Compute requested mode
+ EditMode eEMode = EditMode::Page;
+ if (nSlotId == SID_SLIDE_MASTER_MODE
+ || nSlotId == SID_NOTES_MASTER_MODE
+ || nSlotId == SID_HANDOUT_MASTER_MODE)
+ eEMode = EditMode::MasterPage;
+ // Ensure we have the expected view shell
+ if (!(xView.is() && xView->getResourceId()->getResourceURL() == sRequestedView))
+
+ {
+ const auto xId = CreateResourceId(sRequestedView, msCenterPaneURL);
+ mxConfigurationController->requestResourceActivation(
+ xId,
+ ResourceActivationMode_REPLACE);
+ RunOnResourceActivation(xId, std::bind(&asyncUpdateEditMode, this, eEMode));
+ }
+ else
+ {
+ updateEditMode(xView, eEMode, false);
+ }
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+void FrameworkHelper::RunOnConfigurationEvent(
+ const OUString& rsEventType,
+ const Callback& rCallback)
+{
+ RunOnEvent(
+ rsEventType,
+ FrameworkHelperAllPassFilter(),
+ rCallback);
+}
+
+void FrameworkHelper::RunOnResourceActivation(
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const Callback& rCallback)
+{
+ if (mxConfigurationController.is()
+ && mxConfigurationController->getResource(rxResourceId).is())
+ {
+ rCallback(false);
+ }
+ else
+ {
+ RunOnEvent(
+ msResourceActivationEvent,
+ FrameworkHelperResourceIdFilter(rxResourceId),
+ rCallback);
+ }
+}
+
+namespace {
+
+/** A callback that sets a flag to a specified value when the callback is
+ called.
+*/
+class FlagUpdater
+{
+public:
+ explicit FlagUpdater (bool& rFlag) : mrFlag(rFlag) {}
+ void operator() (bool) const {mrFlag = true;}
+private:
+ bool& mrFlag;
+};
+
+}
+
+void FrameworkHelper::RequestSynchronousUpdate()
+{
+ rtl::Reference<ConfigurationController> pCC (
+ dynamic_cast<ConfigurationController*>(mxConfigurationController.get()));
+ if (pCC.is())
+ pCC->RequestSynchronousUpdate();
+}
+
+void FrameworkHelper::WaitForEvent (const OUString& rsEventType) const
+{
+ bool bConfigurationUpdateSeen (false);
+
+ RunOnEvent(
+ rsEventType,
+ FrameworkHelperAllPassFilter(),
+ FlagUpdater(bConfigurationUpdateSeen));
+
+ sal_uInt32 nStartTime = osl_getGlobalTimer();
+ while ( ! bConfigurationUpdateSeen)
+ {
+ Application::Reschedule();
+
+ if( (osl_getGlobalTimer() - nStartTime) > 60000 )
+ {
+ OSL_FAIL("FrameworkHelper::WaitForEvent(), no event for a minute? giving up!");
+ break;
+ }
+ }
+}
+
+void FrameworkHelper::WaitForUpdate() const
+{
+ WaitForEvent(msConfigurationUpdateEndEvent);
+}
+
+void FrameworkHelper::RunOnEvent(
+ const OUString& rsEventType,
+ const ConfigurationChangeEventFilter& rFilter,
+ const Callback& rCallback) const
+{
+ new CallbackCaller(mrBase,rsEventType,rFilter,rCallback);
+}
+
+void FrameworkHelper::disposing (const lang::EventObject& rEventObject)
+{
+ if (rEventObject.Source == mxConfigurationController)
+ mxConfigurationController = nullptr;
+}
+
+void FrameworkHelper::UpdateConfiguration()
+{
+ if (!mxConfigurationController.is())
+ return;
+
+ try
+ {
+ if (mxConfigurationController.is())
+ mxConfigurationController->update();
+ }
+ catch (lang::DisposedException&)
+ {
+ Dispose();
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+OUString FrameworkHelper::ResourceIdToString (const Reference<XResourceId>& rxResourceId)
+{
+ OUStringBuffer sString;
+ if (rxResourceId.is())
+ {
+ sString.append(rxResourceId->getResourceURL());
+ if (rxResourceId->hasAnchor())
+ {
+ const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs());
+ for (const auto& rAnchorURL : aAnchorURLs)
+ {
+ sString.append(" | ");
+ sString.append(rAnchorURL);
+ }
+ }
+ }
+ return sString.makeStringAndClear();
+}
+
+Reference<XResourceId> FrameworkHelper::CreateResourceId (const OUString& rsResourceURL)
+{
+ return new ::sd::framework::ResourceId(rsResourceURL);
+}
+
+Reference<XResourceId> FrameworkHelper::CreateResourceId (
+ const OUString& rsResourceURL,
+ const OUString& rsAnchorURL)
+{
+ return new ::sd::framework::ResourceId(rsResourceURL, rsAnchorURL);
+}
+
+Reference<XResourceId> FrameworkHelper::CreateResourceId (
+ const OUString& rsResourceURL,
+ const Reference<XResourceId>& rxAnchorId)
+{
+ if (rxAnchorId.is())
+ return new ::sd::framework::ResourceId(
+ rsResourceURL,
+ rxAnchorId->getResourceURL(),
+ rxAnchorId->getAnchorURLs());
+ else
+ return new ::sd::framework::ResourceId(rsResourceURL);
+}
+
+//----- FrameworkHelper::DisposeListener --------------------------------------
+
+FrameworkHelper::DisposeListener::DisposeListener (
+ const ::std::shared_ptr<FrameworkHelper>& rpHelper)
+ : mpHelper(rpHelper)
+{
+ Reference<XComponent> xComponent (mpHelper->mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(this);
+}
+
+void FrameworkHelper::DisposeListener::disposing(std::unique_lock<std::mutex>&)
+{
+ Reference<XComponent> xComponent (mpHelper->mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(this);
+
+ mpHelper.reset();
+}
+
+void SAL_CALL FrameworkHelper::DisposeListener::disposing (const lang::EventObject& rEventObject)
+{
+ if (mpHelper != nullptr)
+ mpHelper->disposing(rEventObject);
+}
+
+//===== FrameworkHelperResourceIdFilter =======================================
+
+FrameworkHelperResourceIdFilter::FrameworkHelperResourceIdFilter (
+ const Reference<XResourceId>& rxResourceId)
+ : mxResourceId(rxResourceId)
+{
+}
+
+} // end of namespace sd::framework
+
+namespace {
+
+//===== CallbackCaller ========================================================
+
+CallbackCaller::CallbackCaller (
+ const ::sd::ViewShellBase& rBase,
+ const OUString& rsEventType,
+ const ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter& rFilter,
+ const ::sd::framework::FrameworkHelper::Callback& rCallback)
+ : msEventType(rsEventType),
+ maFilter(rFilter),
+ maCallback(rCallback)
+{
+ try
+ {
+ Reference<XControllerManager> xControllerManager (rBase.GetController(), UNO_QUERY_THROW);
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (mxConfigurationController.is())
+ {
+ if (mxConfigurationController->hasPendingRequests())
+ mxConfigurationController->addConfigurationChangeListener(this,msEventType,Any());
+ else
+ {
+ // There are no requests waiting to be processed. Therefore
+ // no event, especially not the one we are waiting for, will
+ // be sent in the near future and the callback would never be
+ // called.
+ // Call the callback now and tell him that the event it is
+ // waiting for was not sent.
+ mxConfigurationController = nullptr;
+ maCallback(false);
+ }
+ }
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+void CallbackCaller::disposing(std::unique_lock<std::mutex>&)
+{
+ try
+ {
+ if (mxConfigurationController.is())
+ {
+ Reference<XConfigurationController> xCC (mxConfigurationController);
+ mxConfigurationController = nullptr;
+ xCC->removeConfigurationChangeListener(this);
+ }
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+void SAL_CALL CallbackCaller::disposing (const lang::EventObject& rEvent)
+{
+ if (rEvent.Source == mxConfigurationController)
+ {
+ mxConfigurationController = nullptr;
+ maCallback(false);
+ }
+}
+
+void SAL_CALL CallbackCaller::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (!(rEvent.Type == msEventType && maFilter(rEvent)))
+ return;
+
+ maCallback(true);
+ if (mxConfigurationController.is())
+ {
+ // Reset the reference to the configuration controller so that
+ // dispose() will not try to remove the listener a second time.
+ Reference<XConfigurationController> xCC (mxConfigurationController);
+ mxConfigurationController = nullptr;
+
+ // Removing this object from the controller may very likely lead
+ // to its destruction, so no calls after that.
+ xCC->removeConfigurationChangeListener(this);
+ }
+}
+
+//----- LifetimeController -------------------------------------------------
+
+LifetimeController::LifetimeController (::sd::ViewShellBase& rBase)
+ : mrBase(rBase),
+ mbListeningToViewShellBase(false),
+ mbListeningToController(false)
+{
+ // Register as listener at the ViewShellBase. Because that is not done
+ // via a reference we have to increase the reference count manually.
+ // This is necessary even though listening to the XController did
+ // increase the reference count because the controller may release its
+ // reference to us before the ViewShellBase is destroyed.
+ StartListening(mrBase);
+ acquire();
+ mbListeningToViewShellBase = true;
+
+ Reference<XComponent> xComponent = rBase.GetController();
+ if (xComponent.is())
+ {
+ xComponent->addEventListener(this);
+ mbListeningToController = true;
+ }
+}
+
+LifetimeController::~LifetimeController()
+{
+ OSL_ASSERT(!mbListeningToController && !mbListeningToViewShellBase);
+}
+
+void SAL_CALL LifetimeController::disposing (const lang::EventObject&)
+{
+ mbListeningToController = false;
+ Update();
+}
+
+void LifetimeController::Notify (SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ mbListeningToViewShellBase = false;
+ Update();
+ release();
+ }
+}
+
+void LifetimeController::Update()
+{
+ if (mbListeningToViewShellBase && mbListeningToController)
+ {
+ // Both the controller and the ViewShellBase are alive. Keep
+ // waiting for their destruction.
+ }
+ else if (mbListeningToViewShellBase)
+ {
+ // The controller has been destroyed but the ViewShellBase is still
+ // alive. Dispose the associated FrameworkHelper but keep it around
+ // so that no new instance is created for the dying framework.
+ ::sd::framework::FrameworkHelper::DisposeInstance(mrBase);
+ }
+ else
+ {
+ // Both the controller and the ViewShellBase have been destroyed.
+ // Remove the FrameworkHelper so that the next call its Instance()
+ // method can create a new instance.
+ ::sd::framework::FrameworkHelper::ReleaseInstance(mrBase);
+ }
+}
+
+} // end of anonymous namespace.
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/bulmaper.cxx b/sd/source/ui/func/bulmaper.cxx
new file mode 100644
index 000000000..67a667891
--- /dev/null
+++ b/sd/source/ui/func/bulmaper.cxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/editids.hrc>
+
+//-> Fonts & Items
+#include <vcl/font.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/shdditem.hxx>
+
+//<- Fonts & Items
+#include <svl/itemset.hxx>
+#include <svl/itempool.hxx>
+#include <editeng/numitem.hxx>
+
+#include <bulmaper.hxx>
+
+#define GetWhich(nSlot) rSet.GetPool()->GetWhich( nSlot )
+
+void SdBulletMapper::MapFontsInNumRule( SvxNumRule& aNumRule, const SfxItemSet& rSet )
+{
+ const sal_uInt16 nCount = aNumRule.GetLevelCount();
+ for( sal_uInt16 nLevel = 0; nLevel < nCount; nLevel++ )
+ {
+ const SvxNumberFormat& rSrcLevel = aNumRule.GetLevel(nLevel);
+ SvxNumberFormat aNewLevel( rSrcLevel );
+
+ if(rSrcLevel.GetNumberingType() != css::style::NumberingType::CHAR_SPECIAL &&
+ rSrcLevel.GetNumberingType() != css::style::NumberingType::NUMBER_NONE )
+ {
+ // if enumeration instead bullet is chosen, adjust bullet font to template font
+
+ // to be implemented if module supports CJK
+
+ vcl::Font aMyFont;
+ const SvxFontItem& rFItem =
+ static_cast<const SvxFontItem&>(rSet.Get(GetWhich( sal_uInt16(SID_ATTR_CHAR_FONT) )));
+ aMyFont.SetFamily(rFItem.GetFamily());
+ aMyFont.SetFamilyName(rFItem.GetFamilyName());
+ aMyFont.SetCharSet(rFItem.GetCharSet());
+ aMyFont.SetPitch(rFItem.GetPitch());
+
+ const SvxFontHeightItem& rFHItem =
+ static_cast<const SvxFontHeightItem&>(rSet.Get(GetWhich( sal_uInt16(SID_ATTR_CHAR_FONTHEIGHT) )));
+ aMyFont.SetFontSize(Size(0, rFHItem.GetHeight()));
+
+ const SvxWeightItem& rWItem =
+ static_cast<const SvxWeightItem&>(rSet.Get(GetWhich( sal_uInt16(SID_ATTR_CHAR_WEIGHT) )));
+ aMyFont.SetWeight(rWItem.GetWeight());
+
+ const SvxPostureItem& rPItem =
+ static_cast<const SvxPostureItem&>(rSet.Get(GetWhich( sal_uInt16(SID_ATTR_CHAR_POSTURE) )));
+ aMyFont.SetItalic(rPItem.GetPosture());
+
+ const SvxUnderlineItem& rUItem = rSet.Get(GetWhich(SID_ATTR_CHAR_UNDERLINE));
+ aMyFont.SetUnderline(rUItem.GetLineStyle());
+
+ const SvxOverlineItem& rOItem = static_cast<const SvxOverlineItem&>(rSet.Get(GetWhich(SID_ATTR_CHAR_OVERLINE)));
+ aMyFont.SetOverline(rOItem.GetLineStyle());
+
+ const SvxCrossedOutItem& rCOItem = static_cast<const SvxCrossedOutItem&>(rSet.Get(GetWhich(SID_ATTR_CHAR_STRIKEOUT)));
+ aMyFont.SetStrikeout(rCOItem.GetStrikeout());
+
+ const SvxContourItem& rCItem = static_cast<const SvxContourItem&>(rSet.Get(GetWhich(SID_ATTR_CHAR_CONTOUR)));
+ aMyFont.SetOutline(rCItem.GetValue());
+
+ const SvxShadowedItem& rSItem = static_cast<const SvxShadowedItem&>(rSet.Get(GetWhich(SID_ATTR_CHAR_SHADOWED)));
+ aMyFont.SetShadow(rSItem.GetValue());
+
+ aNewLevel.SetBulletFont(&aMyFont);
+ aNumRule.SetLevel(nLevel, aNewLevel );
+ }
+ else if( rSrcLevel.GetNumberingType() == css::style::NumberingType::CHAR_SPECIAL )
+ {
+ aNewLevel.SetPrefix("");
+ aNewLevel.SetSuffix("");
+ aNumRule.SetLevel(nLevel, aNewLevel );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuarea.cxx b/sd/source/ui/func/fuarea.cxx
new file mode 100644
index 000000000..8dd7543e3
--- /dev/null
+++ b/sd/source/ui/func/fuarea.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuarea.hxx>
+
+#include <svx/svxids.hrc>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <ViewShell.hxx>
+
+#include <drawdoc.hxx>
+#include <View.hxx>
+#include <svx/svxdlg.hxx>
+
+namespace sd {
+
+FuArea::FuArea( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* _pView, SdDrawDocument* pDoc, SfxRequest& rReq)
+: FuPoor(pViewSh, pWin, _pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuArea::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* _pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuArea( pViewSh, pWin, _pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuArea::DoExecute( SfxRequest& rReq )
+{
+ rReq.Ignore ();
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if (pArgs)
+ return;
+
+ SfxItemSet aNewAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aNewAttr );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ bool bHasSlideBackground = mpViewShell->GetDoc()->GetDocumentType() == DocumentType::Impress;
+ VclPtr<AbstractSvxAreaTabDialog> pDlg(
+ pFact->CreateSvxAreaTabDialog(mpViewShell->GetFrameWeld(), &aNewAttr, mpDoc, true, bHasSlideBackground));
+
+ pDlg->StartExecuteAsync([pDlg, pView = this->mpView, pViewShell = this->mpViewShell](sal_Int32 nResult){
+ if (nResult == RET_OK)
+ {
+ pView->SetAttributes (*(pDlg->GetOutputItemSet ()));
+
+ // attributes changed, update Listboxes in Objectbars
+ static const sal_uInt16 SidArray[] = {
+ SID_ATTR_FILL_STYLE,
+ SID_ATTR_FILL_COLOR,
+ SID_ATTR_FILL_GRADIENT,
+ SID_ATTR_FILL_HATCH,
+ SID_ATTR_FILL_BITMAP,
+ SID_ATTR_FILL_TRANSPARENCE,
+ SID_ATTR_FILL_FLOATTRANSPARENCE,
+ SID_ATTR_FILL_USE_SLIDE_BACKGROUND,
+ 0 };
+
+ pViewShell->GetViewFrame()->GetBindings().Invalidate( SidArray );
+ }
+
+ // deferred until the dialog ends
+ pViewShell->Cancel();
+
+ pDlg->disposeOnce();
+ });
+}
+
+void FuArea::Activate()
+{
+}
+
+void FuArea::Deactivate()
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fubullet.cxx b/sd/source/ui/func/fubullet.cxx
new file mode 100644
index 000000000..ab0cf7de8
--- /dev/null
+++ b/sd/source/ui/func/fubullet.cxx
@@ -0,0 +1,330 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fubullet.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <editeng/eeitem.hxx>
+#include <svl/poolitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <OutlineView.hxx>
+#include <OutlineViewShell.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <svx/svdoutl.hxx>
+#include <sfx2/request.hxx>
+#include <svl/ctloptions.hxx>
+#include <svl/stritem.hxx>
+#include <tools/debug.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <svx/svxids.hrc>
+
+namespace sd {
+
+const sal_Unicode CHAR_HARDBLANK = u'\x00A0';
+const sal_Unicode CHAR_HARDHYPHEN = u'\x2011';
+const sal_Unicode CHAR_SOFTHYPHEN = u'\x00AD';
+const sal_Unicode CHAR_RLM = u'\x200F';
+const sal_Unicode CHAR_LRM = u'\x200E';
+const sal_Unicode CHAR_ZWSP = u'\x200B';
+const sal_Unicode CHAR_WJ = u'\x2060';
+const sal_Unicode CHAR_NNBSP = u'\x202F'; //NARROW NO-BREAK SPACE
+
+
+FuBullet::FuBullet (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* _pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, _pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuBullet::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuBullet( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuBullet::DoExecute( SfxRequest& rReq )
+{
+ if( rReq.GetSlot() == SID_CHARMAP )
+ InsertSpecialCharacter(rReq);
+ else
+ {
+ sal_Unicode cMark = 0;
+ switch( rReq.GetSlot() )
+ {
+ case FN_INSERT_SOFT_HYPHEN: cMark = CHAR_SOFTHYPHEN ; break;
+ case FN_INSERT_HARDHYPHEN: cMark = CHAR_HARDHYPHEN ; break;
+ case FN_INSERT_HARD_SPACE: cMark = CHAR_HARDBLANK ; break;
+ case FN_INSERT_NNBSP: cMark = CHAR_NNBSP ; break;
+ case SID_INSERT_RLM : cMark = CHAR_RLM ; break;
+ case SID_INSERT_LRM : cMark = CHAR_LRM ; break;
+ case SID_INSERT_ZWSP : cMark = CHAR_ZWSP ; break;
+ case SID_INSERT_WJ: cMark = CHAR_WJ; break;
+ }
+
+ DBG_ASSERT( cMark != 0, "FuBullet::FuBullet(), illegal slot used!" );
+
+ if( cMark )
+ InsertFormattingMark( cMark );
+ }
+
+}
+
+void FuBullet::InsertFormattingMark( sal_Unicode cMark )
+{
+ OutlinerView* pOV = nullptr;
+ ::Outliner* pOL = nullptr;
+
+ // depending on ViewShell set Outliner and OutlinerView
+ if( dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr)
+ {
+ pOV = mpView->GetTextEditOutlinerView();
+ if (pOV)
+ pOL = mpView->GetTextEditOutliner();
+ }
+ else if( dynamic_cast< const OutlineViewShell *>( mpViewShell ) != nullptr)
+ {
+ pOL = &static_cast<OutlineView*>(mpView)->GetOutliner();
+ pOV = static_cast<OutlineView*>(mpView)->GetViewByWindow(
+ mpViewShell->GetActiveWindow());
+ }
+
+ // insert string
+ if(!(pOV && pOL))
+ return;
+
+ // prevent flickering
+ pOV->HideCursor();
+ pOL->SetUpdateLayout(false);
+
+ // remove old selected text
+ pOV->InsertText( "" );
+
+ // prepare undo
+ SfxUndoManager& rUndoMgr = pOL->GetUndoManager();
+ rUndoMgr.EnterListAction(SdResId(STR_UNDO_INSERT_SPECCHAR),
+ "", 0, mpViewShell->GetViewShellBase().GetViewShellId() );
+
+ // insert given text
+ OUString aStr( cMark );
+ pOV->InsertText( aStr, true);
+
+ ESelection aSel = pOV->GetSelection();
+ aSel.nStartPara = aSel.nEndPara;
+ aSel.nStartPos = aSel.nEndPos;
+ pOV->SetSelection(aSel);
+
+ rUndoMgr.LeaveListAction();
+
+ // restart repainting
+ pOL->SetUpdateLayout(true);
+ pOV->ShowCursor();
+}
+
+void FuBullet::InsertSpecialCharacter( SfxRequest const & rReq )
+{
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ const SfxStringItem* pItem = nullptr;
+ if( pArgs )
+ pItem = pArgs->GetItemIfSet(SID_CHARMAP, false);
+
+ OUString aChars;
+ vcl::Font aFont;
+ if ( pItem )
+ {
+ aChars = pItem->GetValue();
+ const SfxStringItem* pFontItem = pArgs->GetItemIfSet( SID_ATTR_SPECIALCHAR, false );
+ if ( pFontItem )
+ {
+ const OUString& aFontName = pFontItem->GetValue();
+ aFont = vcl::Font( aFontName, Size(1,1) );
+ }
+ else
+ {
+ SfxItemSet aFontAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aFontAttr );
+ const SvxFontItem* pFItem = aFontAttr.GetItem( SID_ATTR_CHAR_FONT );
+ if( pFItem )
+ aFont = vcl::Font( pFItem->GetFamilyName(), pFItem->GetStyleName(), Size( 1, 1 ) );
+ }
+ }
+
+ if (aChars.isEmpty())
+ {
+ SfxAllItemSet aSet( mpDoc->GetPool() );
+ aSet.Put( SfxBoolItem( FN_PARAM_1, false ) );
+
+ SfxItemSet aFontAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aFontAttr );
+ const SvxFontItem* pFontItem = aFontAttr.GetItem( SID_ATTR_CHAR_FONT );
+ if( pFontItem )
+ aSet.Put( *pFontItem );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ auto xFrame = mpViewShell ? mpViewShell->GetFrame()->GetFrame().GetFrameInterface() : nullptr;
+ ScopedVclPtr<SfxAbstractDialog> pDlg( pFact->CreateCharMapDialog(mpView->GetViewShell()->GetFrameWeld(), aSet,
+ xFrame) );
+
+ // If a character is selected, it can be shown
+ // pDLg->SetFont( );
+ // pDlg->SetChar( );
+ pDlg->Execute();
+ return;
+ }
+
+ if (aChars.isEmpty())
+ return;
+
+ OutlinerView* pOV = nullptr;
+ ::Outliner* pOL = nullptr;
+
+ // determine depending on ViewShell Outliner and OutlinerView
+ if(dynamic_cast< const DrawViewShell *>( mpViewShell ))
+ {
+ pOV = mpView->GetTextEditOutlinerView();
+ if (pOV)
+ {
+ pOL = mpView->GetTextEditOutliner();
+ }
+ }
+ else if(dynamic_cast< const OutlineViewShell *>( mpViewShell ))
+ {
+ pOL = &static_cast<OutlineView*>(mpView)->GetOutliner();
+ pOV = static_cast<OutlineView*>(mpView)->GetViewByWindow(
+ mpViewShell->GetActiveWindow());
+ }
+
+ // insert special character
+ if (!pOV)
+ return;
+
+ // prevent flicker
+ pOV->HideCursor();
+ pOL->SetUpdateLayout(false);
+
+ /* remember old attributes:
+ To do that, remove selected area before (it has to go anyway).
+ With that, we get unique attributes (and since there is no
+ DeleteSelected() in OutlinerView, it is deleted by inserting an
+ empty string). */
+ pOV->InsertText( "" );
+
+ SfxItemSetFixed<EE_CHAR_FONTINFO, EE_CHAR_FONTINFO> aOldSet( mpDoc->GetPool() );
+ aOldSet.Put( pOV->GetAttribs() );
+
+ SfxUndoManager& rUndoMgr = pOL->GetUndoManager();
+ ViewShellId nViewShellId = mpViewShell ? mpViewShell->GetViewShellBase().GetViewShellId() : ViewShellId(-1);
+ rUndoMgr.EnterListAction(SdResId(STR_UNDO_INSERT_SPECCHAR),
+ "", 0, nViewShellId );
+ pOV->InsertText(aChars, true);
+
+ // set attributes (set font)
+ SfxItemSet aSet(pOL->GetEmptyItemSet());
+ SvxFontItem aFontItem (aFont.GetFamilyType(), aFont.GetFamilyName(),
+ aFont.GetStyleName(), aFont.GetPitch(),
+ aFont.GetCharSet(),
+ EE_CHAR_FONTINFO);
+ aSet.Put(aFontItem);
+ aFontItem.SetWhich(EE_CHAR_FONTINFO_CJK);
+ aSet.Put(aFontItem);
+ aFontItem.SetWhich(EE_CHAR_FONTINFO_CTL);
+ aSet.Put(aFontItem);
+ pOV->SetAttribs(aSet);
+
+ ESelection aSel = pOV->GetSelection();
+ aSel.nStartPara = aSel.nEndPara;
+ aSel.nStartPos = aSel.nEndPos;
+ pOV->SetSelection(aSel);
+
+ // do not go ahead with setting attributes of special characters
+ pOV->GetOutliner()->QuickSetAttribs(aOldSet, aSel);
+
+ rUndoMgr.LeaveListAction();
+
+ // show it again
+ pOL->SetUpdateLayout(true);
+ pOV->ShowCursor();
+}
+
+void FuBullet::GetSlotState( SfxItemSet& rSet, ViewShell const * pViewShell, SfxViewFrame* pViewFrame )
+{
+ if( !(SfxItemState::DEFAULT == rSet.GetItemState( SID_CHARMAP ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_CHARMAP_CONTROL ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( FN_INSERT_SOFT_HYPHEN ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( FN_INSERT_HARDHYPHEN ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( FN_INSERT_HARD_SPACE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( FN_INSERT_NNBSP ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_INSERT_RLM ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_INSERT_LRM ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_INSERT_WJ ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_INSERT_ZWSP )))
+ return;
+
+ ::sd::View* pView = pViewShell ? pViewShell->GetView() : nullptr;
+ OutlinerView* pOLV = pView ? pView->GetTextEditOutlinerView() : nullptr;
+
+ const bool bTextEdit = pOLV;
+
+ SvtCTLOptions aCTLOptions;
+ const bool bCtlEnabled = aCTLOptions.IsCTLFontEnabled();
+
+ if(!bTextEdit )
+ {
+ rSet.DisableItem(FN_INSERT_SOFT_HYPHEN);
+ rSet.DisableItem(FN_INSERT_HARDHYPHEN);
+ rSet.DisableItem(FN_INSERT_HARD_SPACE);
+ rSet.DisableItem(FN_INSERT_NNBSP);
+ rSet.DisableItem(SID_INSERT_WJ);
+ rSet.DisableItem(SID_INSERT_ZWSP);
+ }
+
+ if( !bTextEdit && (dynamic_cast<OutlineViewShell const *>( pViewShell ) == nullptr) )
+ {
+ rSet.DisableItem(SID_CHARMAP);
+ rSet.DisableItem(SID_CHARMAP_CONTROL);
+ }
+
+ if(!bTextEdit || !bCtlEnabled )
+ {
+ rSet.DisableItem(SID_INSERT_RLM);
+ rSet.DisableItem(SID_INSERT_LRM);
+ }
+
+ if( pViewFrame )
+ {
+ SfxBindings& rBindings = pViewFrame->GetBindings();
+
+ rBindings.SetVisibleState( SID_INSERT_RLM, bCtlEnabled );
+ rBindings.SetVisibleState( SID_INSERT_LRM, bCtlEnabled );
+ }
+}
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuchar.cxx b/sd/source/ui/func/fuchar.cxx
new file mode 100644
index 000000000..3935f64a1
--- /dev/null
+++ b/sd/source/ui/func/fuchar.cxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuchar.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sfxdlg.hxx>
+
+#include <svx/svxids.hrc>
+#include <editeng/eeitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/brushitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <ViewShell.hxx>
+#include <DrawDocShell.hxx>
+#include <sdabstdlg.hxx>
+
+namespace sd {
+
+
+FuChar::FuChar (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuChar::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuChar( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuChar::DoExecute( SfxRequest& rReq )
+{
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if( !pArgs )
+ {
+ SfxItemSet aEditAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aEditAttr );
+
+ SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLCOLOR, EE_ITEMS_START, EE_ITEMS_END> aNewAttr(mpViewShell->GetPool());
+ aNewAttr.Put( aEditAttr, false );
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg( pFact->CreateSdTabCharDialog(mpViewShell->GetFrameWeld(), &aNewAttr, mpDoc->GetDocSh() ) );
+ if (rReq.GetSlot() == SID_CHAR_DLG_EFFECT)
+ {
+ pDlg->SetCurPageId("RID_SVXPAGE_CHAR_EFFECTS");
+ }
+
+ sal_uInt16 nResult = pDlg->Execute();
+
+ if( nResult != RET_OK )
+ return;
+
+ const SfxItemSet* pOutputSet = pDlg->GetOutputItemSet();
+ SfxItemSet aOtherSet( *pOutputSet );
+
+ // and now the reverse process
+ const SvxBrushItem* pBrushItem = aOtherSet.GetItem<SvxBrushItem>( SID_ATTR_BRUSH_CHAR );
+
+ if ( pBrushItem )
+ {
+ SvxColorItem aBackColorItem( pBrushItem->GetColor(), EE_CHAR_BKGCOLOR );
+ aOtherSet.ClearItem( SID_ATTR_BRUSH_CHAR );
+ aOtherSet.Put( aBackColorItem );
+ }
+
+ rReq.Done( aOtherSet );
+ pArgs = rReq.GetArgs();
+ }
+ mpView->SetAttributes(*pArgs);
+
+ // invalidate the Slots which are in DrTxtObjBar
+ static const sal_uInt16 SidArray[] = {
+ SID_ATTR_CHAR_FONT,
+ SID_ATTR_CHAR_POSTURE,
+ SID_ATTR_CHAR_WEIGHT,
+ SID_ATTR_CHAR_SHADOWED,
+ SID_ATTR_CHAR_STRIKEOUT,
+ SID_ATTR_CHAR_UNDERLINE,
+ SID_ATTR_CHAR_FONTHEIGHT,
+ SID_ATTR_CHAR_COLOR,
+ SID_ATTR_CHAR_KERNING,
+ SID_ATTR_CHAR_CASEMAP,
+ SID_SET_SUPER_SCRIPT,
+ SID_SET_SUB_SCRIPT,
+ SID_ATTR_CHAR_BACK_COLOR,
+ 0 };
+
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArray );
+
+ if( mpDoc->GetOnlineSpell() )
+ {
+ if( SfxItemState::SET == pArgs->GetItemState(EE_CHAR_LANGUAGE, false ) ||
+ SfxItemState::SET == pArgs->GetItemState(EE_CHAR_LANGUAGE_CJK, false ) ||
+ SfxItemState::SET == pArgs->GetItemState(EE_CHAR_LANGUAGE_CTL, false ) )
+ {
+ mpDoc->StopOnlineSpelling();
+ mpDoc->StartOnlineSpelling();
+ }
+ }
+}
+
+void FuChar::Activate()
+{
+}
+
+void FuChar::Deactivate()
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fucon3d.cxx b/sd/source/ui/func/fucon3d.cxx
new file mode 100644
index 000000000..fb844548f
--- /dev/null
+++ b/sd/source/ui/func/fucon3d.cxx
@@ -0,0 +1,474 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fucon3d.hxx>
+
+#include <svx/svxids.hrc>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <tools/poly.hxx>
+
+#include <svx/xlineit0.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/sphere3d.hxx>
+#include <svx/cube3d.hxx>
+#include <svx/lathe3d.hxx>
+#include <svx/camera3d.hxx>
+
+#include <vcl/weld.hxx>
+
+#include <app.hrc>
+
+#include <View.hxx>
+#include <Window.hxx>
+#include <ViewShell.hxx>
+#include <drawdoc.hxx>
+#include <ViewShellBase.hxx>
+#include <ToolBarManager.hxx>
+#include <svx/svx3ditems.hxx>
+
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+
+FuConstruct3dObject::FuConstruct3dObject (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuConstruct(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuConstruct3dObject::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent )
+{
+ FuConstruct3dObject* pFunc;
+ rtl::Reference<FuPoor> xFunc( pFunc = new FuConstruct3dObject( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ pFunc->SetPermanent(bPermanent);
+ return xFunc;
+}
+
+void FuConstruct3dObject::DoExecute( SfxRequest& rReq )
+{
+ FuConstruct::DoExecute( rReq );
+ mpViewShell->GetViewShellBase().GetToolBarManager()->SetToolBar(
+ ToolBarManager::ToolBarGroup::Function,
+ ToolBarManager::msDrawingObjectToolBar);
+}
+
+E3dCompoundObject* FuConstruct3dObject::ImpCreateBasic3DShape()
+{
+ E3dCompoundObject* p3DObj = nullptr;
+
+ switch (nSlotId)
+ {
+ default:
+ case SID_3D_CUBE:
+ {
+ p3DObj = new E3dCubeObj(
+ mpView->getSdrModelFromSdrView(),
+ mpView->Get3DDefaultAttributes(),
+ ::basegfx::B3DPoint(-2500, -2500, -2500),
+ ::basegfx::B3DVector(5000, 5000, 5000));
+ break;
+ }
+
+ case SID_3D_SPHERE:
+ {
+ p3DObj = new E3dSphereObj(
+ mpView->getSdrModelFromSdrView(),
+ mpView->Get3DDefaultAttributes(),
+ ::basegfx::B3DPoint(0, 0, 0),
+ ::basegfx::B3DVector(5000, 5000, 5000));
+ break;
+ }
+
+ case SID_3D_SHELL:
+ {
+ XPolygon aXPoly(Point (0, 1250), 2500, 2500, 0_deg100, 9000_deg100, false);
+ aXPoly.Scale(5.0, 5.0);
+
+ ::basegfx::B2DPolygon aB2DPolygon(aXPoly.getB2DPolygon());
+ if(aB2DPolygon.areControlPointsUsed())
+ {
+ aB2DPolygon = ::basegfx::utils::adaptiveSubdivideByAngle(aB2DPolygon);
+ }
+ p3DObj = new E3dLatheObj(
+ mpView->getSdrModelFromSdrView(),
+ mpView->Get3DDefaultAttributes(),
+ ::basegfx::B2DPolyPolygon(aB2DPolygon));
+
+ /* this is an open object, therefore it has to be handled double-
+ sided by default */
+ p3DObj->SetMergedItem(makeSvx3DDoubleSidedItem(true));
+ break;
+ }
+
+ case SID_3D_HALF_SPHERE:
+ {
+ XPolygon aXPoly(Point (0, 1250), 2500, 2500, 0_deg100, 9000_deg100, false);
+ aXPoly.Scale(5.0, 5.0);
+
+ aXPoly.Insert(0, Point (2400*5, 1250*5), PolyFlags::Normal);
+ aXPoly.Insert(0, Point (2000*5, 1250*5), PolyFlags::Normal);
+ aXPoly.Insert(0, Point (1500*5, 1250*5), PolyFlags::Normal);
+ aXPoly.Insert(0, Point (1000*5, 1250*5), PolyFlags::Normal);
+ aXPoly.Insert(0, Point (500*5, 1250*5), PolyFlags::Normal);
+ aXPoly.Insert(0, Point (250*5, 1250*5), PolyFlags::Normal);
+ aXPoly.Insert(0, Point (50*5, 1250*5), PolyFlags::Normal);
+ aXPoly.Insert(0, Point (0, 1250*5), PolyFlags::Normal);
+
+ ::basegfx::B2DPolygon aB2DPolygon(aXPoly.getB2DPolygon());
+ if(aB2DPolygon.areControlPointsUsed())
+ {
+ aB2DPolygon = ::basegfx::utils::adaptiveSubdivideByAngle(aB2DPolygon);
+ }
+ p3DObj = new E3dLatheObj(
+ mpView->getSdrModelFromSdrView(),
+ mpView->Get3DDefaultAttributes(),
+ ::basegfx::B2DPolyPolygon(aB2DPolygon));
+ break;
+ }
+
+ case SID_3D_TORUS:
+ {
+ ::basegfx::B2DPolygon aB2DPolygon(::basegfx::utils::createPolygonFromCircle(::basegfx::B2DPoint(1000.0, 0.0), 500.0));
+ if(aB2DPolygon.areControlPointsUsed())
+ {
+ aB2DPolygon = ::basegfx::utils::adaptiveSubdivideByAngle(aB2DPolygon);
+ }
+ p3DObj = new E3dLatheObj(
+ mpView->getSdrModelFromSdrView(),
+ mpView->Get3DDefaultAttributes(),
+ ::basegfx::B2DPolyPolygon(aB2DPolygon));
+ break;
+ }
+
+ case SID_3D_CYLINDER:
+ {
+ ::basegfx::B2DPolygon aInnerPoly;
+
+ aInnerPoly.append(::basegfx::B2DPoint(0, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(50*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(100*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(200*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(300*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(400*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(450*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(500*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(500*5, -1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(450*5, -1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(400*5, -1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(300*5, -1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(200*5, -1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(100*5, -1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(50*5, -1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(0, -1000*5));
+ aInnerPoly.setClosed(true);
+
+ p3DObj = new E3dLatheObj(
+ mpView->getSdrModelFromSdrView(),
+ mpView->Get3DDefaultAttributes(),
+ ::basegfx::B2DPolyPolygon(aInnerPoly));
+ break;
+ }
+
+ case SID_3D_CONE:
+ {
+ ::basegfx::B2DPolygon aInnerPoly;
+
+ aInnerPoly.append(::basegfx::B2DPoint(0, -1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(25*5, -900*5));
+ aInnerPoly.append(::basegfx::B2DPoint(50*5, -800*5));
+ aInnerPoly.append(::basegfx::B2DPoint(100*5, -600*5));
+ aInnerPoly.append(::basegfx::B2DPoint(200*5, -200*5));
+ aInnerPoly.append(::basegfx::B2DPoint(300*5, 200*5));
+ aInnerPoly.append(::basegfx::B2DPoint(400*5, 600*5));
+ aInnerPoly.append(::basegfx::B2DPoint(500*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(400*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(300*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(200*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(100*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(50*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(0, 1000*5));
+ aInnerPoly.setClosed(true);
+
+ p3DObj = new E3dLatheObj(
+ mpView->getSdrModelFromSdrView(),
+ mpView->Get3DDefaultAttributes(),
+ ::basegfx::B2DPolyPolygon(aInnerPoly));
+ break;
+ }
+
+ case SID_3D_PYRAMID:
+ {
+ ::basegfx::B2DPolygon aInnerPoly;
+
+ aInnerPoly.append(::basegfx::B2DPoint(0, -1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(25*5, -900*5));
+ aInnerPoly.append(::basegfx::B2DPoint(50*5, -800*5));
+ aInnerPoly.append(::basegfx::B2DPoint(100*5, -600*5));
+ aInnerPoly.append(::basegfx::B2DPoint(200*5, -200*5));
+ aInnerPoly.append(::basegfx::B2DPoint(300*5, 200*5));
+ aInnerPoly.append(::basegfx::B2DPoint(400*5, 600*5));
+ aInnerPoly.append(::basegfx::B2DPoint(500*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(400*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(300*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(200*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(100*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(50*5, 1000*5));
+ aInnerPoly.append(::basegfx::B2DPoint(0, 1000*5));
+ aInnerPoly.setClosed(true);
+
+ p3DObj = new E3dLatheObj(
+ mpView->getSdrModelFromSdrView(),
+ mpView->Get3DDefaultAttributes(),
+ ::basegfx::B2DPolyPolygon(aInnerPoly));
+ p3DObj->SetMergedItem(makeSvx3DHorizontalSegmentsItem(4));
+ break;
+ }
+ }
+
+ return p3DObj;
+}
+
+void FuConstruct3dObject::ImpPrepareBasic3DShape(E3dCompoundObject const * p3DObj, E3dScene *pScene)
+{
+ Camera3D aCamera = pScene->GetCamera ();
+
+ // get transformed BoundVolume of the new object
+ basegfx::B3DRange aBoundVol;
+ basegfx::B3DRange aObjVol(p3DObj->GetBoundVolume());
+ aObjVol.transform(p3DObj->GetTransform());
+ aBoundVol.expand(aObjVol);
+ double fDeepth(aBoundVol.getDepth());
+
+ aCamera.SetPRP(::basegfx::B3DPoint(0.0, 0.0, 1000.0));
+ aCamera.SetPosition(::basegfx::B3DPoint(0.0, 0.0, mpView->GetDefaultCamPosZ() + fDeepth / 2));
+ aCamera.SetFocalLength(mpView->GetDefaultCamFocal());
+ pScene->SetCamera(aCamera);
+ basegfx::B3DHomMatrix aTransformation;
+
+ switch (nSlotId)
+ {
+ case SID_3D_CUBE:
+ {
+ aTransformation.rotate(basegfx::deg2rad(20), 0.0, 0.0);
+ }
+ break;
+
+ case SID_3D_SPHERE:
+ {
+ }
+ break;
+
+ case SID_3D_SHELL:
+ case SID_3D_HALF_SPHERE:
+ {
+ aTransformation.rotate(basegfx::deg2rad(200), 0.0, 0.0);
+ }
+ break;
+
+ case SID_3D_CYLINDER:
+ case SID_3D_CONE:
+ case SID_3D_PYRAMID:
+ {
+ }
+ break;
+
+ case SID_3D_TORUS:
+ {
+ aTransformation.rotate(basegfx::deg2rad(90), 0.0, 0.0);
+ }
+ break;
+
+ default:
+ {
+ }
+ break;
+ }
+
+ pScene->SetTransform(aTransformation * pScene->GetTransform());
+
+ SfxItemSet aAttr (mpViewShell->GetPool());
+ pScene->SetMergedItemSetAndBroadcast(aAttr);
+}
+
+bool FuConstruct3dObject::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bReturn = FuConstruct::MouseButtonDown(rMEvt);
+
+ if ( rMEvt.IsLeft() && !mpView->IsAction() )
+ {
+ Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ mpWindow->CaptureMouse();
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+
+ weld::WaitObject aWait(mpViewShell->GetFrameWeld());
+
+ E3dCompoundObject* p3DObj = ImpCreateBasic3DShape();
+ E3dScene* pScene = mpView->SetCurrent3DObj(p3DObj);
+
+ ImpPrepareBasic3DShape(p3DObj, pScene);
+ bReturn = mpView->BegCreatePreparedObject(aPnt, nDrgLog, pScene);
+
+ SdrObject* pObj = mpView->GetCreateObj();
+
+ if (pObj)
+ {
+ SfxItemSet aAttr(mpDoc->GetPool());
+ SetStyleSheet(aAttr, pObj);
+
+ // extract LineStyle
+ aAttr.Put(XLineStyleItem (drawing::LineStyle_NONE));
+
+ pObj->SetMergedItemSet(aAttr);
+ }
+ }
+
+ return bReturn;
+}
+
+bool FuConstruct3dObject::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bReturn = false;
+
+ if ( mpView->IsCreateObj() && rMEvt.IsLeft() )
+ {
+ if( mpView->EndCreateObj( SdrCreateCmd::ForceEnd ) )
+ {
+ bReturn = true;
+ }
+ else
+ {
+ //Drag was too small to create object, so insert default object at click pos
+ Point aClickPos(mpWindow->PixelToLogic(rMEvt.GetPosPixel()));
+ sal_uInt32 nDefaultObjectSize(1000);
+ sal_Int32 nCenterOffset(-sal_Int32(nDefaultObjectSize / 2));
+ aClickPos.AdjustX(nCenterOffset);
+ aClickPos.AdjustY(nCenterOffset);
+
+ SdrPageView *pPV = mpView->GetSdrPageView();
+
+ if(mpView->IsSnapEnabled())
+ aClickPos = mpView->GetSnapPos(aClickPos, pPV);
+
+ ::tools::Rectangle aNewObjectRectangle(aClickPos, Size(nDefaultObjectSize, nDefaultObjectSize));
+ SdrObjectUniquePtr pObjDefault = CreateDefaultObject(nSlotId, aNewObjectRectangle);
+
+ bReturn = mpView->InsertObjectAtView(pObjDefault.release(), *pPV);
+ }
+ }
+ bReturn = FuConstruct::MouseButtonUp(rMEvt) || bReturn;
+
+ if (!bPermanent)
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+
+ return bReturn;
+}
+
+void FuConstruct3dObject::Activate()
+{
+ mpView->SetCurrentObj(SdrObjKind::NONE);
+
+ FuConstruct::Activate();
+}
+
+SdrObjectUniquePtr FuConstruct3dObject::CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle)
+{
+
+ E3dCompoundObject* p3DObj = ImpCreateBasic3DShape();
+
+ // E3dView::SetCurrent3DObj part
+ // get transformed BoundVolume of the object
+ basegfx::B3DRange aObjVol(p3DObj->GetBoundVolume());
+ aObjVol.transform(p3DObj->GetTransform());
+ basegfx::B3DRange aVolume(aObjVol);
+ double fW(aVolume.getWidth());
+ double fH(aVolume.getHeight());
+ ::tools::Rectangle a3DRect(0, 0, static_cast<::tools::Long>(fW), static_cast<::tools::Long>(fH));
+ std::unique_ptr< E3dScene, SdrObjectFreeOp > pScene(new E3dScene(*mpDoc));
+
+ // copied code from E3dView::InitScene
+ double fCamZ(aVolume.getMaxZ() + ((fW + fH) / 4.0));
+ Camera3D aCam(pScene->GetCamera());
+ aCam.SetAutoAdjustProjection(false);
+ aCam.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
+ ::basegfx::B3DPoint aLookAt;
+ double fDefaultCamPosZ = mpView->GetDefaultCamPosZ();
+ ::basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
+ aCam.SetPosAndLookAt(aCamPos, aLookAt);
+ aCam.SetFocalLength(mpView->GetDefaultCamFocal());
+ pScene->SetCamera(aCam);
+ pScene->InsertObject(p3DObj);
+ pScene->NbcSetSnapRect(a3DRect);
+ ImpPrepareBasic3DShape(p3DObj, pScene.get());
+ SfxItemSet aAttr(mpDoc->GetPool());
+ SetStyleSheet(aAttr, p3DObj);
+ aAttr.Put(XLineStyleItem (drawing::LineStyle_NONE));
+ p3DObj->SetMergedItemSet(aAttr);
+
+ // make object interactive at once
+ pScene->SetBoundAndSnapRectsDirty();
+
+ // Take care of restrictions for the rectangle
+ ::tools::Rectangle aRect(rRectangle);
+
+ switch(nID)
+ {
+ case SID_3D_CUBE:
+ case SID_3D_SPHERE:
+ case SID_3D_TORUS:
+ {
+ // force quadratic
+ ImpForceQuadratic(aRect);
+ break;
+ }
+
+ case SID_3D_SHELL:
+ case SID_3D_HALF_SPHERE:
+ {
+ // force horizontal layout
+ break;
+ }
+
+ case SID_3D_CYLINDER:
+ case SID_3D_CONE:
+ case SID_3D_PYRAMID:
+ {
+ // force vertical layout
+ break;
+ }
+ }
+
+ // use changed rectangle, not original one
+ pScene->SetLogicRect(aRect);
+
+ return SdrObjectUniquePtr(pScene.release());
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuconarc.cxx b/sd/source/ui/func/fuconarc.cxx
new file mode 100644
index 000000000..b5be93f9b
--- /dev/null
+++ b/sd/source/ui/func/fuconarc.cxx
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuconarc.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdocirc.hxx>
+#include <sfx2/request.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svdobj.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <osl/diagnose.h>
+
+#include <svx/svxids.hrc>
+
+#include <Window.hxx>
+#include <drawdoc.hxx>
+
+#include <View.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <ToolBarManager.hxx>
+
+#include <svx/sxciaitm.hxx>
+#include <svx/xfillit0.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+
+FuConstructArc::FuConstructArc (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq )
+ : FuConstruct( pViewSh, pWin, pView, pDoc, rReq )
+{
+}
+
+rtl::Reference<FuPoor> FuConstructArc::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent )
+{
+ FuConstructArc* pFunc;
+ rtl::Reference<FuPoor> xFunc( pFunc = new FuConstructArc( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ pFunc->SetPermanent(bPermanent);
+ return xFunc;
+}
+
+void FuConstructArc::DoExecute( SfxRequest& rReq )
+{
+ FuConstruct::DoExecute( rReq );
+
+ mpViewShell->GetViewShellBase().GetToolBarManager()->SetToolBar(
+ ToolBarManager::ToolBarGroup::Function,
+ ToolBarManager::msDrawingObjectToolBar);
+
+ const SfxItemSet *pArgs = rReq.GetArgs ();
+
+ if (!pArgs)
+ return;
+
+ const SfxUInt32Item* pCenterX = rReq.GetArg<SfxUInt32Item>(ID_VAL_CENTER_X);
+ const SfxUInt32Item* pCenterY = rReq.GetArg<SfxUInt32Item>(ID_VAL_CENTER_Y);
+ const SfxUInt32Item* pAxisX = rReq.GetArg<SfxUInt32Item>(ID_VAL_AXIS_X);
+ const SfxUInt32Item* pAxisY = rReq.GetArg<SfxUInt32Item>(ID_VAL_AXIS_Y);
+ const SfxUInt32Item* pPhiStart = rReq.GetArg<SfxUInt32Item>(ID_VAL_ANGLESTART);
+ const SfxUInt32Item* pPhiEnd = rReq.GetArg<SfxUInt32Item>(ID_VAL_ANGLEEND);
+
+ ::tools::Rectangle aNewRectangle (pCenterX->GetValue () - pAxisX->GetValue () / 2,
+ pCenterY->GetValue () - pAxisY->GetValue () / 2,
+ pCenterX->GetValue () + pAxisX->GetValue () / 2,
+ pCenterY->GetValue () + pAxisY->GetValue () / 2);
+
+ Activate(); // sets aObjKind
+ SdrCircObj* pNewCircle =
+ new SdrCircObj(
+ mpView->getSdrModelFromSdrView(),
+ ToSdrCircKind(mpView->GetCurrentObjIdentifier()),
+ aNewRectangle,
+ Degree100(pPhiStart->GetValue() * 10),
+ Degree100(pPhiEnd->GetValue() * 10));
+ SdrPageView *pPV = mpView->GetSdrPageView();
+
+ mpView->InsertObjectAtView(pNewCircle, *pPV, SdrInsertFlags::SETDEFLAYER);
+}
+
+bool FuConstructArc::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ bool bReturn = FuConstruct::MouseButtonDown( rMEvt );
+
+ if ( rMEvt.IsLeft() && !mpView->IsAction() )
+ {
+ Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+ mpWindow->CaptureMouse();
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+ mpView->BegCreateObj(aPnt, nullptr, nDrgLog);
+
+ SdrObject* pObj = mpView->GetCreateObj();
+
+ if (pObj)
+ {
+ SfxItemSet aAttr(mpDoc->GetPool());
+ SetStyleSheet(aAttr, pObj);
+
+ pObj->SetMergedItemSet(aAttr);
+ }
+
+ bReturn = true;
+ }
+ return bReturn;
+}
+
+bool FuConstructArc::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ bool bReturn = false;
+ bool bCreated = false;
+
+ if ( mpView->IsCreateObj() && rMEvt.IsLeft() )
+ {
+ const size_t nCount = mpView->GetSdrPageView()->GetObjList()->GetObjCount();
+
+ if (mpView->EndCreateObj(SdrCreateCmd::NextPoint) )
+ {
+ if (nCount != mpView->GetSdrPageView()->GetObjList()->GetObjCount())
+ {
+ bCreated = true;
+ }
+ }
+
+ bReturn = true;
+ }
+
+ bReturn = FuConstruct::MouseButtonUp (rMEvt) || bReturn;
+
+ if (!bPermanent && bCreated)
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+
+ return bReturn;
+}
+
+void FuConstructArc::Activate()
+{
+ SdrObjKind aObjKind;
+
+ switch( nSlotId )
+ {
+ case SID_DRAW_ARC :
+ case SID_DRAW_CIRCLEARC:
+ {
+ aObjKind = SdrObjKind::CircleArc;
+ }
+ break;
+
+ case SID_DRAW_PIE :
+ case SID_DRAW_PIE_NOFILL :
+ case SID_DRAW_CIRCLEPIE :
+ case SID_DRAW_CIRCLEPIE_NOFILL:
+ {
+ aObjKind = SdrObjKind::CircleSection;
+ }
+ break;
+
+ case SID_DRAW_ELLIPSECUT :
+ case SID_DRAW_ELLIPSECUT_NOFILL:
+ case SID_DRAW_CIRCLECUT :
+ case SID_DRAW_CIRCLECUT_NOFILL :
+ {
+ aObjKind = SdrObjKind::CircleCut;
+ }
+ break;
+
+ default:
+ {
+ aObjKind = SdrObjKind::CircleArc;
+ }
+ break;
+ }
+
+ mpView->SetCurrentObj(aObjKind);
+
+ FuConstruct::Activate();
+}
+
+SdrObjectUniquePtr FuConstructArc::CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle)
+{
+
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ mpView->getSdrModelFromSdrView(),
+ mpView->GetCurrentObjInventor(),
+ mpView->GetCurrentObjIdentifier()));
+
+ if(pObj)
+ {
+ if( dynamic_cast< const SdrCircObj *>( pObj.get() ) != nullptr)
+ {
+ ::tools::Rectangle aRect(rRectangle);
+
+ if(SID_DRAW_ARC == nID ||
+ SID_DRAW_CIRCLEARC == nID ||
+ SID_DRAW_CIRCLEPIE == nID ||
+ SID_DRAW_CIRCLEPIE_NOFILL == nID ||
+ SID_DRAW_CIRCLECUT == nID ||
+ SID_DRAW_CIRCLECUT_NOFILL == nID)
+ {
+ // force quadratic
+ ImpForceQuadratic(aRect);
+ }
+
+ pObj->SetLogicRect(aRect);
+
+ SfxItemSet aAttr(mpDoc->GetPool());
+ aAttr.Put(makeSdrCircStartAngleItem(9000_deg100));
+ aAttr.Put(makeSdrCircEndAngleItem(0_deg100));
+
+ if(SID_DRAW_PIE_NOFILL == nID ||
+ SID_DRAW_CIRCLEPIE_NOFILL == nID ||
+ SID_DRAW_ELLIPSECUT_NOFILL == nID ||
+ SID_DRAW_CIRCLECUT_NOFILL == nID)
+ {
+ aAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+
+ pObj->SetMergedItemSet(aAttr);
+ }
+ else
+ {
+ OSL_FAIL("Object is NO circle object");
+ }
+ }
+
+ return pObj;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuconbez.cxx b/sd/source/ui/func/fuconbez.cxx
new file mode 100644
index 000000000..b123e9c2d
--- /dev/null
+++ b/sd/source/ui/func/fuconbez.cxx
@@ -0,0 +1,556 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+
+#include <fuconbez.hxx>
+#include <svx/svdopath.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svdobj.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <osl/diagnose.h>
+
+#include <svx/svxids.hrc>
+#include <svx/svdpagv.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xlnwtit.hxx>
+
+#include <app.hrc>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <View.hxx>
+#include <Window.hxx>
+#include <ToolBarManager.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+#include <CustomAnimationEffect.hxx>
+
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+/*//Extra attributes coming from parameters
+ sal_uInt16 mnTransparence; // Default: 0
+ OUString msColor; // Default: ""
+ sal_uInt16 mnWidth; // Default: 0
+ OUString msShapeName; // Default: ""*/
+FuConstructBezierPolygon::FuConstructBezierPolygon (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuConstruct(pViewSh, pWin, pView, pDoc, rReq),
+ nEditMode(SID_BEZIER_MOVE),
+ mnTransparence(0),
+ mnWidth(0)
+{
+}
+
+namespace{
+
+/// Checks to see if the request has a parameter of IsSticky:bool=true
+/// It means that the selected command/button will stay selected after use
+bool isSticky(const SfxRequest& rReq)
+{
+ const SfxItemSet *pArgs = rReq.GetArgs ();
+ if (pArgs)
+ {
+ const SfxBoolItem* pIsSticky = rReq.GetArg<SfxBoolItem>(FN_PARAM_4);
+ if (pIsSticky && pIsSticky->GetValue())
+ return true;
+ }
+
+ return false;
+}
+
+}
+
+rtl::Reference<FuPoor> FuConstructBezierPolygon::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent )
+{
+ FuConstructBezierPolygon* pFunc;
+ rtl::Reference<FuPoor> xFunc( pFunc = new FuConstructBezierPolygon( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ pFunc->SetPermanent(bPermanent || isSticky(rReq));
+ return xFunc;
+}
+
+void FuConstructBezierPolygon::DoExecute( SfxRequest& rReq )
+{
+ FuConstruct::DoExecute( rReq );
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if( !pArgs )
+ return;
+
+ const SfxUnoAnyItem* pPoolItem = pArgs->GetItemIfSet( SID_ADD_MOTION_PATH );
+ if( pPoolItem )
+ maTargets = pPoolItem->GetValue();
+
+ if (nSlotId != SID_DRAW_FREELINE_NOFILL)
+ return;
+
+ const SfxUInt16Item* pTransparence = rReq.GetArg<SfxUInt16Item>(FN_PARAM_1);
+ const SfxStringItem* pColor = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ const SfxUInt16Item* pWidth = rReq.GetArg<SfxUInt16Item>(FN_PARAM_3);
+ const SfxStringItem* pShapeName = rReq.GetArg<SfxStringItem>(SID_SHAPE_NAME);
+
+ if (pTransparence && pTransparence->GetValue() > 0)
+ {
+ mnTransparence = pTransparence->GetValue();
+ }
+ if (pColor && !pColor->GetValue().isEmpty())
+ {
+ msColor = pColor->GetValue();
+ }
+ if (pWidth && pWidth->GetValue() > 0)
+ {
+ mnWidth = pWidth->GetValue();
+ }
+ if (pShapeName && !pShapeName->GetValue().isEmpty())
+ {
+ msShapeName = pShapeName->GetValue();
+ }
+}
+
+bool FuConstructBezierPolygon::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bReturn = FuConstruct::MouseButtonDown(rMEvt);
+
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+
+ if (eHit == SdrHitKind::Handle || rMEvt.IsMod1())
+ {
+ mpView->SetEditMode(SdrViewEditMode::Edit);
+ }
+ else
+ {
+ mpView->SetEditMode(SdrViewEditMode::Create);
+ }
+
+ if (aVEvt.meEvent == SdrEventKind::BeginTextEdit)
+ {
+ // here, we do not allow text input
+ aVEvt.meEvent = SdrEventKind::BeginDragObj;
+ mpView->EnableExtendedMouseEventDispatcher(false);
+ }
+ else
+ {
+ mpView->EnableExtendedMouseEventDispatcher(true);
+ }
+
+ if (eHit == SdrHitKind::MarkedObject && nEditMode == SID_BEZIER_INSERT)
+ {
+ // insert gluepoint
+ mpView->BegInsObjPoint(aMDPos, rMEvt.IsMod1());
+ }
+ else
+ {
+ mpView->MouseButtonDown(rMEvt, mpWindow->GetOutDev());
+
+ SdrObject* pObj = mpView->GetCreateObj();
+
+ if (pObj)
+ {
+ SfxItemSet aAttr(mpDoc->GetPool());
+ SetStyleSheet(aAttr, pObj);
+ SetAttributes(aAttr, pObj);
+ pObj->SetMergedItemSet(aAttr);
+ }
+ }
+
+ return bReturn;
+}
+
+bool FuConstructBezierPolygon::MouseButtonUp(const MouseEvent& rMEvt )
+{
+ bool bReturn = false;
+ bool bCreated = false;
+
+ SdrViewEvent aVEvt;
+ mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONUP, aVEvt);
+
+ const size_t nCount = mpView->GetSdrPageView()->GetObjList()->GetObjCount();
+
+ if (mpView->IsInsObjPoint())
+ {
+ mpView->EndInsObjPoint(SdrCreateCmd::ForceEnd);
+ }
+ else
+ {
+ mpView->MouseButtonUp(rMEvt, mpWindow->GetOutDev());
+ }
+
+ if (aVEvt.meEvent == SdrEventKind::EndCreate)
+ {
+ bReturn = true;
+
+ if (nCount+1 == mpView->GetSdrPageView()->GetObjList()->GetObjCount())
+ {
+ bCreated = true;
+ }
+
+ // trick to suppress FuDraw::DoubleClick
+ bMBDown = false;
+
+ }
+
+ bReturn = FuConstruct::MouseButtonUp(rMEvt) || bReturn;
+
+ bool bDeleted = false;
+ if( bCreated && maTargets.hasValue() )
+ {
+ SdrPathObj* pPathObj = dynamic_cast< SdrPathObj* >( mpView->GetSdrPageView()->GetObjList()->GetObj( nCount ) );
+ SdPage* pPage = dynamic_cast< SdPage* >( pPathObj ? pPathObj->getSdrPageFromSdrObject() : nullptr );
+ if( pPage )
+ {
+ std::shared_ptr< sd::MainSequence > pMainSequence( pPage->getMainSequence() );
+ if( pMainSequence )
+ {
+ Sequence< Any > aTargets;
+ maTargets >>= aTargets;
+
+ sal_Int32 nTCount = aTargets.getLength();
+ if( nTCount > 1 )
+ {
+ const Any* pTarget = aTargets.getConstArray();
+ double fDuration = 0.0;
+ *pTarget++ >>= fDuration;
+ bool bFirst = true;
+
+ OUString sPresetId;
+ switch(nSlotId)
+ {
+ case SID_DRAW_BEZIER_NOFILL:
+ sPresetId = "libo-motionpath-curve";
+ break;
+ case SID_DRAW_POLYGON_NOFILL:
+ sPresetId = "libo-motionpath-polygon";
+ break;
+ case SID_DRAW_FREELINE_NOFILL:
+ sPresetId = "libo-motionpath-freeform-line";
+ break;
+ }
+
+ while( --nTCount )
+ {
+ CustomAnimationEffectPtr pCreated( pMainSequence->append( *pPathObj, *pTarget++, fDuration, sPresetId) );
+ if( bFirst )
+ bFirst = false;
+ else
+ pCreated->setNodeType( css::presentation::EffectNodeType::WITH_PREVIOUS );
+ }
+ }
+ }
+ }
+ mpView->DeleteMarked();
+ bDeleted = true;
+ }
+
+ if ((!bPermanent && bCreated) || bDeleted)
+ {
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ }
+
+ return bReturn;
+}
+
+void FuConstructBezierPolygon::Activate()
+{
+ mpView->EnableExtendedMouseEventDispatcher(true);
+
+ SdrObjKind eKind;
+
+ switch (nSlotId)
+ {
+ case SID_DRAW_POLYGON_NOFILL:
+ case SID_DRAW_XPOLYGON_NOFILL:
+ {
+ eKind = SdrObjKind::PolyLine;
+ }
+ break;
+
+ case SID_DRAW_POLYGON:
+ case SID_DRAW_XPOLYGON:
+ {
+ eKind = SdrObjKind::Polygon;
+ }
+ break;
+
+ case SID_DRAW_BEZIER_NOFILL:
+ {
+ eKind = SdrObjKind::PathLine;
+ }
+ break;
+
+ case SID_DRAW_BEZIER_FILL:
+ {
+ eKind = SdrObjKind::PathFill;
+ }
+ break;
+
+ case SID_DRAW_FREELINE_NOFILL:
+ {
+ eKind = SdrObjKind::FreehandLine;
+ }
+ break;
+
+ case SID_DRAW_FREELINE:
+ {
+ eKind = SdrObjKind::FreehandFill;
+ }
+ break;
+
+ default:
+ {
+ eKind = SdrObjKind::PathLine;
+ }
+ break;
+ }
+
+ mpView->SetCurrentObj(eKind);
+
+ FuConstruct::Activate();
+}
+
+void FuConstructBezierPolygon::Deactivate()
+{
+ mpView->EnableExtendedMouseEventDispatcher(false);
+
+ FuConstruct::Deactivate();
+}
+
+void FuConstructBezierPolygon::SelectionHasChanged()
+{
+ FuDraw::SelectionHasChanged();
+
+ mpViewShell->GetViewShellBase().GetToolBarManager()->SelectionHasChanged(
+ *mpViewShell,
+ *mpView);
+}
+
+namespace {
+/// Returns the color based on the color names listed in core/include/tools/color.hxx
+/// Feel free to extend with more color names from color.hxx
+Color strToColor(std::u16string_view sColor)
+{
+ Color aColor = COL_AUTO;
+
+ if (sColor == u"COL_GRAY")
+ aColor = COL_GRAY;
+ else if (sColor == u"COL_GRAY3")
+ aColor = COL_GRAY3;
+ else if (sColor == u"COL_GRAY7")
+ aColor = COL_GRAY7;
+
+ return aColor;
+}
+}
+
+void FuConstructBezierPolygon::SetAttributes(SfxItemSet& rAttr, SdrObject *pObj)
+{
+ if (nSlotId == SID_DRAW_FREELINE_NOFILL)
+ {
+ if (mnTransparence > 0 && mnTransparence <= 100)
+ rAttr.Put(XLineTransparenceItem(mnTransparence));
+ if (!msColor.isEmpty())
+ rAttr.Put(XLineColorItem(OUString(), strToColor(msColor)));
+ if (mnWidth > 0)
+ rAttr.Put(XLineWidthItem(mnWidth));
+ if (!msShapeName.isEmpty())
+ pObj->SetName(msShapeName);
+ }
+}
+
+/**
+ * Set current bezier edit mode
+ */
+void FuConstructBezierPolygon::SetEditMode(sal_uInt16 nMode)
+{
+ nEditMode = nMode;
+ ForcePointer();
+
+ SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_BEZIER_MOVE);
+ rBindings.Invalidate(SID_BEZIER_INSERT);
+}
+
+SdrObjectUniquePtr FuConstructBezierPolygon::CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle)
+{
+ // case SID_DRAW_POLYGON:
+ // case SID_DRAW_POLYGON_NOFILL:
+ // case SID_DRAW_XPOLYGON:
+ // case SID_DRAW_XPOLYGON_NOFILL:
+ // case SID_DRAW_FREELINE:
+ // case SID_DRAW_FREELINE_NOFILL:
+ // case SID_DRAW_BEZIER_FILL: // BASIC
+ // case SID_DRAW_BEZIER_NOFILL: // BASIC
+
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ mpView->getSdrModelFromSdrView(),
+ mpView->GetCurrentObjInventor(),
+ mpView->GetCurrentObjIdentifier()));
+
+ if(pObj)
+ {
+ if( auto pPathObj = dynamic_cast< SdrPathObj *>( pObj.get() ) )
+ {
+ basegfx::B2DPolyPolygon aPoly;
+
+ switch(nID)
+ {
+ case SID_DRAW_BEZIER_FILL:
+ {
+ const sal_Int32 nWdt(rRectangle.GetWidth() / 2);
+ const sal_Int32 nHgt(rRectangle.GetHeight() / 2);
+ const basegfx::B2DPolygon aInnerPoly(basegfx::utils::createPolygonFromEllipse(basegfx::B2DPoint(rRectangle.Center().X(), rRectangle.Center().Y()), nWdt, nHgt));
+
+ aPoly.append(aInnerPoly);
+ break;
+ }
+ case SID_DRAW_BEZIER_NOFILL:
+ {
+ basegfx::B2DPolygon aInnerPoly;
+
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left(), rRectangle.Bottom()));
+
+ const basegfx::B2DPoint aCenterBottom(rRectangle.Center().X(), rRectangle.Bottom());
+ aInnerPoly.appendBezierSegment(
+ aCenterBottom,
+ aCenterBottom,
+ basegfx::B2DPoint(rRectangle.Center().X(), rRectangle.Center().Y()));
+
+ const basegfx::B2DPoint aCenterTop(rRectangle.Center().X(), rRectangle.Top());
+ aInnerPoly.appendBezierSegment(
+ aCenterTop,
+ aCenterTop,
+ basegfx::B2DPoint(rRectangle.Right(), rRectangle.Top()));
+
+ aPoly.append(aInnerPoly);
+ break;
+ }
+ case SID_DRAW_FREELINE:
+ case SID_DRAW_FREELINE_NOFILL:
+ {
+ basegfx::B2DPolygon aInnerPoly;
+
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left(), rRectangle.Bottom()));
+
+ aInnerPoly.appendBezierSegment(
+ basegfx::B2DPoint(rRectangle.Left(), rRectangle.Top()),
+ basegfx::B2DPoint(rRectangle.Center().X(), rRectangle.Top()),
+ basegfx::B2DPoint(rRectangle.Center().X(), rRectangle.Center().Y()));
+
+ aInnerPoly.appendBezierSegment(
+ basegfx::B2DPoint(rRectangle.Center().X(), rRectangle.Bottom()),
+ basegfx::B2DPoint(rRectangle.Right(), rRectangle.Bottom()),
+ basegfx::B2DPoint(rRectangle.Right(), rRectangle.Top()));
+
+ if(SID_DRAW_FREELINE == nID)
+ {
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Right(), rRectangle.Bottom()));
+ }
+ else
+ {
+ aInnerPoly.setClosed(true);
+ }
+
+ aPoly.append(aInnerPoly);
+ break;
+ }
+ case SID_DRAW_XPOLYGON:
+ case SID_DRAW_XPOLYGON_NOFILL:
+ {
+ basegfx::B2DPolygon aInnerPoly;
+
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left(), rRectangle.Bottom()));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left(), rRectangle.Top()));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Center().X(), rRectangle.Top()));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Center().X(), rRectangle.Center().Y()));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Right(), rRectangle.Center().Y()));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Right(), rRectangle.Bottom()));
+
+ if(SID_DRAW_XPOLYGON_NOFILL == nID)
+ {
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Center().X(), rRectangle.Bottom()));
+ }
+ else
+ {
+ aInnerPoly.setClosed(true);
+ }
+
+ aPoly.append(aInnerPoly);
+ break;
+ }
+ case SID_DRAW_POLYGON:
+ case SID_DRAW_POLYGON_NOFILL:
+ {
+ basegfx::B2DPolygon aInnerPoly;
+ const sal_Int32 nWdt(rRectangle.GetWidth());
+ const sal_Int32 nHgt(rRectangle.GetHeight());
+
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left(), rRectangle.Bottom()));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left() + (nWdt * 30) / 100, rRectangle.Top() + (nHgt * 70) / 100));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left(), rRectangle.Top() + (nHgt * 15) / 100));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left() + (nWdt * 65) / 100, rRectangle.Top()));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left() + nWdt, rRectangle.Top() + (nHgt * 30) / 100));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left() + (nWdt * 80) / 100, rRectangle.Top() + (nHgt * 50) / 100));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Left() + (nWdt * 80) / 100, rRectangle.Top() + (nHgt * 75) / 100));
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Bottom(), rRectangle.Right()));
+
+ if(SID_DRAW_POLYGON_NOFILL == nID)
+ {
+ aInnerPoly.append(basegfx::B2DPoint(rRectangle.Center().X(), rRectangle.Bottom()));
+ }
+ else
+ {
+ aInnerPoly.setClosed(true);
+ }
+
+ aPoly.append(aInnerPoly);
+ break;
+ }
+ }
+
+ pPathObj->SetPathPoly(aPoly);
+ }
+ else
+ {
+ OSL_FAIL("Object is NO path object");
+ }
+
+ pObj->SetLogicRect(rRectangle);
+ }
+
+ return pObj;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuconcs.cxx b/sd/source/ui/func/fuconcs.cxx
new file mode 100644
index 000000000..806960dd2
--- /dev/null
+++ b/sd/source/ui/func/fuconcs.cxx
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuconcs.hxx>
+#include <rtl/ustring.hxx>
+
+#include <svx/svxids.hrc>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/sdtagitm.hxx>
+
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <ToolBarManager.hxx>
+#include <svx/gallery.hxx>
+#include <svx/sdooitm.hxx>
+#include <svl/itempool.hxx>
+#include <svl/stritem.hxx>
+
+#include <View.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+
+namespace sd {
+
+
+FuConstructCustomShape::FuConstructCustomShape (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq ) :
+ FuConstruct(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuConstructCustomShape::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent )
+{
+ FuConstructCustomShape* pFunc;
+ rtl::Reference<FuPoor> xFunc( pFunc = new FuConstructCustomShape( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ pFunc->SetPermanent( bPermanent );
+ return xFunc;
+}
+
+void FuConstructCustomShape::DoExecute( SfxRequest& rReq )
+{
+ FuConstruct::DoExecute( rReq );
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if ( pArgs )
+ {
+ const SfxStringItem& rItm = static_cast<const SfxStringItem&>(pArgs->Get( rReq.GetSlot() ));
+ aCustomShape = rItm.GetValue();
+ }
+
+ mpViewShell->GetViewShellBase().GetToolBarManager()->SetToolBar(
+ ToolBarManager::ToolBarGroup::Function,
+ ToolBarManager::msDrawingObjectToolBar);
+}
+
+bool FuConstructCustomShape::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bReturn = FuConstruct::MouseButtonDown(rMEvt);
+
+ if ( rMEvt.IsLeft() && !mpView->IsAction() )
+ {
+ Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ mpWindow->CaptureMouse();
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+
+ mpView->BegCreateObj(aPnt, nullptr, nDrgLog);
+
+ SdrObject* pObj = mpView->GetCreateObj();
+ if ( pObj )
+ {
+ SetAttributes( pObj );
+ bool bForceFillStyle = true;
+ bool bForceNoFillStyle = false;
+ if ( static_cast<SdrObjCustomShape*>(pObj)->UseNoFillStyle() )
+ {
+ bForceFillStyle = false;
+ bForceNoFillStyle = true;
+ }
+ SfxItemSet aAttr(mpDoc->GetPool());
+ SetStyleSheet( aAttr, pObj, bForceFillStyle, bForceNoFillStyle );
+ pObj->SetMergedItemSet(aAttr);
+ }
+ }
+
+ return bReturn;
+}
+
+bool FuConstructCustomShape::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bReturn(false);
+
+ if(mpView->IsCreateObj() && rMEvt.IsLeft())
+ {
+ SdrObject* pObj = mpView->GetCreateObj();
+ if( pObj && mpView->EndCreateObj( SdrCreateCmd::ForceEnd ) )
+ {
+ bReturn = true;
+ }
+ else
+ {
+ //Drag was too small to create object, so insert default object at click pos
+ Point aClickPos(mpWindow->PixelToLogic(rMEvt.GetPosPixel()));
+ sal_uInt32 nDefaultObjectSize(1000);
+ sal_Int32 nCenterOffset(-sal_Int32(nDefaultObjectSize / 2));
+ aClickPos.AdjustX(nCenterOffset);
+ aClickPos.AdjustY(nCenterOffset);
+
+ SdrPageView *pPV = mpView->GetSdrPageView();
+ if(mpView->IsSnapEnabled())
+ aClickPos = mpView->GetSnapPos(aClickPos, pPV);
+
+ ::tools::Rectangle aNewObjectRectangle(aClickPos, Size(nDefaultObjectSize, nDefaultObjectSize));
+ SdrObjectUniquePtr pObjDefault = CreateDefaultObject(nSlotId, aNewObjectRectangle);
+
+ bReturn = mpView->InsertObjectAtView(pObjDefault.release(), *pPV);
+ }
+ }
+ bReturn = FuConstruct::MouseButtonUp (rMEvt) || bReturn;
+
+ if (!bPermanent)
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+
+ return bReturn;
+}
+
+void FuConstructCustomShape::Activate()
+{
+ mpView->SetCurrentObj( SdrObjKind::CustomShape );
+ FuConstruct::Activate();
+}
+
+/**
+ * set attribute for the object to be created
+ */
+void FuConstructCustomShape::SetAttributes( SdrObject* pObj )
+{
+ bool bAttributesAppliedFromGallery = false;
+
+ if ( GalleryExplorer::GetSdrObjCount( GALLERY_THEME_POWERPOINT ) )
+ {
+ std::vector< OUString > aObjList;
+ if ( GalleryExplorer::FillObjListTitle( GALLERY_THEME_POWERPOINT, aObjList ) )
+ {
+ for ( std::vector<OUString>::size_type i = 0; i < aObjList.size(); i++ )
+ {
+ if ( aObjList[ i ].equalsIgnoreAsciiCase( aCustomShape ) )
+ {
+ FmFormModel aFormModel;
+ SfxItemPool& rPool(aFormModel.GetItemPool());
+ rPool.FreezeIdRanges();
+
+ if ( GalleryExplorer::GetSdrObj( GALLERY_THEME_POWERPOINT, i, &aFormModel ) )
+ {
+ const SdrPage* pPage = aFormModel.GetPage( 0 );
+ if ( pPage )
+ {
+ const SdrObject* pSourceObj = pPage->GetObj( 0 );
+ if( pSourceObj )
+ {
+ const SfxItemSet& rSource = pSourceObj->GetMergedItemSet();
+ SfxItemSetFixed<
+ // Ranges from SdrAttrObj:
+ SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTDIRECTION,
+ // Graphic attributes, 3D properties,
+ // CustomShape properties:
+ SDRATTR_GRAF_FIRST,
+ SDRATTR_CUSTOMSHAPE_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END> aDest(pObj->getSdrModelFromSdrObject().GetItemPool());
+ aDest.Set( rSource );
+ pObj->SetMergedItemSet( aDest );
+ // Enables Word-wrap by default (tdf#134369)
+ pObj->SetMergedItem( SdrOnOffItem( SDRATTR_TEXT_WORDWRAP, true ) );
+ Degree100 nAngle = pSourceObj->GetRotateAngle();
+ if ( nAngle )
+ pObj->NbcRotate( pObj->GetSnapRect().Center(), nAngle );
+ bAttributesAppliedFromGallery = true;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ if ( !bAttributesAppliedFromGallery )
+ {
+ pObj->SetMergedItem( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
+ pObj->SetMergedItem( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) );
+ pObj->SetMergedItem( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_BLOCK ) );
+ pObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( false ) );
+ static_cast<SdrObjCustomShape*>(pObj)->MergeDefaultAttributes( &aCustomShape );
+ }
+}
+
+const OUString& FuConstructCustomShape::GetShapeType() const
+{
+ return aCustomShape;
+}
+
+SdrObjectUniquePtr FuConstructCustomShape::CreateDefaultObject(const sal_uInt16, const ::tools::Rectangle& rRectangle)
+{
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ mpView->getSdrModelFromSdrView(),
+ mpView->GetCurrentObjInventor(),
+ mpView->GetCurrentObjIdentifier()));
+
+ if( pObj )
+ {
+ ::tools::Rectangle aRect( rRectangle );
+ if ( doConstructOrthogonal() )
+ ImpForceQuadratic( aRect );
+ pObj->SetLogicRect( aRect );
+ SetAttributes( pObj.get() );
+ SfxItemSet aAttr(mpDoc->GetPool());
+ SetStyleSheet(aAttr, pObj.get());
+ pObj->SetMergedItemSet(aAttr);
+ }
+ return pObj;
+}
+
+// #i33136#
+bool FuConstructCustomShape::doConstructOrthogonal() const
+{
+ return SdrObjCustomShape::doConstructOrthogonal(aCustomShape);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuconnct.cxx b/sd/source/ui/func/fuconnct.cxx
new file mode 100644
index 000000000..fc95b4907
--- /dev/null
+++ b/sd/source/ui/func/fuconnct.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 <fuconnct.hxx>
+#include <sfx2/request.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/dialogs.hrc>
+
+namespace sd {
+
+
+FuConnectionDlg::FuConnectionDlg (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuConnectionDlg::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuConnectionDlg( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuConnectionDlg::DoExecute( SfxRequest& rReq )
+{
+ SfxItemSet aNewAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aNewAttr );
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if( !pArgs )
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateSfxDialog(rReq.GetFrameWeld(), aNewAttr, mpView, RID_SVXPAGE_CONNECTION));
+
+ if( pDlg->Execute() == RET_OK )
+ {
+ rReq.Done( *pDlg->GetOutputItemSet() );
+ pArgs = rReq.GetArgs();
+ }
+ }
+ if( pArgs )
+ mpView->SetAttributes( *pArgs );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuconrec.cxx b/sd/source/ui/func/fuconrec.cxx
new file mode 100644
index 000000000..d93ef2849
--- /dev/null
+++ b/sd/source/ui/func/fuconrec.cxx
@@ -0,0 +1,1096 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuconrec.hxx>
+#include <svx/svdpagv.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+#include <app.hrc>
+#include <svl/itemset.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/sdtmfitm.hxx>
+#include <svx/sxekitm.hxx>
+#include <svx/sderitm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdocirc.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/request.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/xtable.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/sdtditm.hxx>
+
+#include <svx/svdocapt.hxx>
+
+#include <svx/svdomeas.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <ToolBarManager.hxx>
+#include <editeng/writingmodeitem.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/signaturelinehelper.hxx>
+#include <osl/diagnose.h>
+
+#include <sdresid.hxx>
+#include <View.hxx>
+#include <sdpage.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <unokywds.hxx>
+
+#include <strings.hrc>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+
+FuConstructRectangle::FuConstructRectangle (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuConstruct(pViewSh, pWin, pView, pDoc, rReq)
+ , mnFillTransparence(0)
+ , mnLineStyle(SAL_MAX_UINT16)
+{
+}
+
+namespace{
+
+/// Checks to see if the request has a parameter of IsSticky:bool=true
+/// It means that the selected command/button will stay selected after use
+bool isSticky(const SfxRequest& rReq)
+{
+ const SfxItemSet *pArgs = rReq.GetArgs ();
+ if (pArgs)
+ {
+ const SfxBoolItem* pIsSticky = rReq.GetArg<SfxBoolItem>(FN_PARAM_4);
+ if (pIsSticky && pIsSticky->GetValue())
+ return true;
+ }
+
+ return false;
+}
+
+}
+
+rtl::Reference<FuPoor> FuConstructRectangle::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent )
+{
+ FuConstructRectangle* pFunc;
+ rtl::Reference<FuPoor> xFunc( pFunc = new FuConstructRectangle( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ pFunc->SetPermanent(bPermanent || isSticky(rReq));
+ return xFunc;
+}
+
+void FuConstructRectangle::DoExecute( SfxRequest& rReq )
+{
+ FuConstruct::DoExecute( rReq );
+
+ mpViewShell->GetViewShellBase().GetToolBarManager()->SetToolBar(
+ ToolBarManager::ToolBarGroup::Function,
+ ToolBarManager::msDrawingObjectToolBar);
+
+ const SfxItemSet *pArgs = rReq.GetArgs ();
+
+ if (pArgs)
+ {
+ switch (nSlotId)
+ {
+ case SID_DRAW_ELLIPSE :
+ {
+ const SfxUInt32Item* pCenterX = rReq.GetArg<SfxUInt32Item>(ID_VAL_CENTER_X);
+ const SfxUInt32Item* pCenterY = rReq.GetArg<SfxUInt32Item>(ID_VAL_CENTER_Y);
+ const SfxUInt32Item* pAxisX = rReq.GetArg<SfxUInt32Item>(ID_VAL_AXIS_X);
+ const SfxUInt32Item* pAxisY = rReq.GetArg<SfxUInt32Item>(ID_VAL_AXIS_Y);
+
+ if (!pCenterX || !pCenterY || !pAxisX || !pAxisY)
+ break;
+
+ ::tools::Rectangle aNewRectangle (pCenterX->GetValue () - pAxisX->GetValue () / 2,
+ pCenterY->GetValue () - pAxisY->GetValue () / 2,
+ pCenterX->GetValue () + pAxisX->GetValue () / 2,
+ pCenterY->GetValue () + pAxisY->GetValue () / 2);
+ SdrCircObj *pNewCircle = new SdrCircObj(
+ mpView->getSdrModelFromSdrView(),
+ SdrCircKind::Full,
+ aNewRectangle);
+ SdrPageView *pPV = mpView->GetSdrPageView();
+
+ mpView->InsertObjectAtView(pNewCircle, *pPV, SdrInsertFlags::SETDEFLAYER | SdrInsertFlags::SETDEFATTR);
+ }
+ break;
+
+ case SID_DRAW_RECT :
+ {
+ const SfxUInt32Item* pMouseStartX = rReq.GetArg<SfxUInt32Item>(ID_VAL_MOUSESTART_X);
+ const SfxUInt32Item* pMouseStartY = rReq.GetArg<SfxUInt32Item>(ID_VAL_MOUSESTART_Y);
+ const SfxUInt32Item* pMouseEndX = rReq.GetArg<SfxUInt32Item>(ID_VAL_MOUSEEND_X);
+ const SfxUInt32Item* pMouseEndY = rReq.GetArg<SfxUInt32Item>(ID_VAL_MOUSEEND_Y);
+ const SfxUInt16Item* pFillTransparence = rReq.GetArg<SfxUInt16Item>(FN_PARAM_1);
+ const SfxStringItem* pFillColor = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ const SfxUInt16Item* pLineStyle = rReq.GetArg<SfxUInt16Item>(FN_PARAM_3);
+ const SfxStringItem* pShapeName = rReq.GetArg<SfxStringItem>(SID_SHAPE_NAME);
+
+ if (pFillTransparence && pFillTransparence->GetValue() > 0)
+ {
+ mnFillTransparence = pFillTransparence->GetValue();
+ }
+ if (pFillColor && !pFillColor->GetValue().isEmpty())
+ {
+ msFillColor = pFillColor->GetValue();
+ }
+ if (pLineStyle)
+ {
+ mnLineStyle = pLineStyle->GetValue();
+ }
+ if (pShapeName && !pShapeName->GetValue().isEmpty())
+ {
+ msShapeName = pShapeName->GetValue();
+ }
+
+ if (!pMouseStartX || !pMouseStartY || !pMouseEndX || !pMouseEndY)
+ break;
+
+ ::tools::Rectangle aNewRectangle (pMouseStartX->GetValue (),
+ pMouseStartY->GetValue (),
+ pMouseEndX->GetValue (),
+ pMouseEndY->GetValue ());
+ SdrRectObj *pNewRect = new SdrRectObj(
+ mpView->getSdrModelFromSdrView(),
+ aNewRectangle);
+ SdrPageView *pPV = mpView->GetSdrPageView();
+
+ mpView->InsertObjectAtView(pNewRect, *pPV, SdrInsertFlags::SETDEFLAYER | SdrInsertFlags::SETDEFATTR);
+ }
+ break;
+ }
+ }
+
+ if (nSlotId == SID_TOOL_CONNECTOR ||
+ nSlotId == SID_CONNECTOR_ARROW_START ||
+ nSlotId == SID_CONNECTOR_ARROW_END ||
+ nSlotId == SID_CONNECTOR_ARROWS ||
+ nSlotId == SID_CONNECTOR_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_CIRCLES ||
+ nSlotId == SID_CONNECTOR_LINE ||
+ nSlotId == SID_CONNECTOR_LINE_ARROW_START ||
+ nSlotId == SID_CONNECTOR_LINE_ARROW_END ||
+ nSlotId == SID_CONNECTOR_LINE_ARROWS ||
+ nSlotId == SID_CONNECTOR_LINE_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_LINE_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_LINE_CIRCLES ||
+ nSlotId == SID_CONNECTOR_CURVE ||
+ nSlotId == SID_CONNECTOR_CURVE_ARROW_START ||
+ nSlotId == SID_CONNECTOR_CURVE_ARROW_END ||
+ nSlotId == SID_CONNECTOR_CURVE_ARROWS ||
+ nSlotId == SID_CONNECTOR_CURVE_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_CURVE_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_CURVE_CIRCLES ||
+ nSlotId == SID_CONNECTOR_LINES ||
+ nSlotId == SID_CONNECTOR_LINES_ARROW_START ||
+ nSlotId == SID_CONNECTOR_LINES_ARROW_END ||
+ nSlotId == SID_CONNECTOR_LINES_ARROWS ||
+ nSlotId == SID_CONNECTOR_LINES_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_LINES_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_LINES_CIRCLES ||
+ nSlotId == SID_LINE_ARROW_START ||
+ nSlotId == SID_LINE_ARROW_END ||
+ nSlotId == SID_LINE_ARROWS ||
+ nSlotId == SID_LINE_ARROW_CIRCLE ||
+ nSlotId == SID_LINE_CIRCLE_ARROW ||
+ nSlotId == SID_LINE_ARROW_SQUARE ||
+ nSlotId == SID_LINE_SQUARE_ARROW )
+ {
+ mpView->UnmarkAll();
+ }
+}
+
+bool FuConstructRectangle::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bReturn = FuConstruct::MouseButtonDown(rMEvt);
+
+ if ( rMEvt.IsLeft() && !mpView->IsAction() )
+ {
+ Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ mpWindow->CaptureMouse();
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+
+ if (mpView->GetCurrentObjIdentifier() == SdrObjKind::Caption)
+ {
+ Size aCaptionSize(846, 846); // (4x2)cm
+ bReturn = mpView->BegCreateCaptionObj(aPnt, aCaptionSize,
+ nullptr, nDrgLog);
+ }
+ else
+ {
+ mpView->BegCreateObj(aPnt, nullptr, nDrgLog);
+ }
+
+ SdrObject* pObj = mpView->GetCreateObj();
+
+ if (pObj)
+ {
+ SfxItemSet aAttr(mpDoc->GetPool());
+ SetStyleSheet(aAttr, pObj);
+ SetAttributes(aAttr, pObj);
+ SetLineEnds(aAttr, *pObj);
+ pObj->SetMergedItemSet(aAttr);
+
+ if( nSlotId == SID_DRAW_CAPTION_VERTICAL )
+ static_cast<SdrTextObj*>(pObj)->SetVerticalWriting( true );
+ }
+ }
+ return bReturn;
+}
+
+bool FuConstructRectangle::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bReturn(false);
+
+ if(mpView->IsCreateObj() && rMEvt.IsLeft())
+ {
+ SdrObject* pObj = mpView->GetCreateObj();
+
+ if(pObj && mpView->EndCreateObj(SdrCreateCmd::ForceEnd))
+ {
+ if(SID_DRAW_MEASURELINE == nSlotId)
+ {
+ SdrLayerAdmin& rAdmin = mpDoc->GetLayerAdmin();
+ pObj->SetLayer(rAdmin.GetLayerID(sUNO_LayerName_measurelines));
+ }
+
+ // init text position when vertical caption object is created
+ if( dynamic_cast< const SdrCaptionObj *>( pObj ) != nullptr && SID_DRAW_CAPTION_VERTICAL == nSlotId)
+ {
+ // draw text object, needs to be initialized when vertical text is used
+ SfxItemSet aSet(pObj->GetMergedItemSet());
+
+ aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER));
+ aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
+
+ // Correct the value of SDRATTR_TEXTDIRECTION to avoid SetItemSet
+ // calling SetVerticalWriting() again since this item may not yet
+ // be set at the object and thus may differ from vertical state of
+ // the object.
+ aSet.Put(SvxWritingModeItem(css::text::WritingMode_TB_RL, SDRATTR_TEXTDIRECTION));
+ pObj->SetMergedItemSet(aSet);
+ }
+
+ bReturn = true;
+ }
+ else
+ {
+ //Drag was too small to create object, so insert default object at click pos
+ Point aClickPos(mpWindow->PixelToLogic(rMEvt.GetPosPixel()));
+ sal_uInt32 nDefaultObjectSize(1500);
+ sal_Int32 nCenterOffset(-sal_Int32(nDefaultObjectSize / 2));
+ aClickPos.AdjustX(nCenterOffset);
+ aClickPos.AdjustY(nCenterOffset);
+
+ SdrPageView *pPV = mpView->GetSdrPageView();
+ if(mpView->IsSnapEnabled())
+ aClickPos = mpView->GetSnapPos(aClickPos, pPV);
+
+ ::tools::Rectangle aNewObjectRectangle(aClickPos, Size(nDefaultObjectSize, nDefaultObjectSize));
+ SdrObjectUniquePtr pObjDefault = CreateDefaultObject(nSlotId, aNewObjectRectangle);
+
+ bReturn = mpView->InsertObjectAtView(pObjDefault.release(), *pPV);
+ }
+ }
+
+ bReturn = FuConstruct::MouseButtonUp (rMEvt) || bReturn;
+
+ if (!bPermanent)
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+
+ return bReturn;
+}
+
+void FuConstructRectangle::Activate()
+{
+ SdrObjKind aObjKind;
+
+ switch (nSlotId)
+ {
+ case SID_LINE_ARROW_START:
+ case SID_LINE_ARROW_END:
+ case SID_LINE_ARROWS:
+ case SID_LINE_ARROW_CIRCLE:
+ case SID_LINE_CIRCLE_ARROW:
+ case SID_LINE_ARROW_SQUARE:
+ case SID_LINE_SQUARE_ARROW:
+ mpView->SetGlueVisible();
+ [[fallthrough]];
+ case SID_DRAW_LINE :
+ case SID_DRAW_XLINE:
+ aObjKind = SdrObjKind::Line;
+ break;
+
+ case SID_DRAW_MEASURELINE:
+ {
+ aObjKind = SdrObjKind::Measure;
+ }
+ break;
+
+ case SID_DRAW_RECT :
+ case SID_DRAW_RECT_NOFILL :
+ case SID_DRAW_RECT_ROUND :
+ case SID_DRAW_RECT_ROUND_NOFILL:
+ case SID_DRAW_SQUARE :
+ case SID_DRAW_SQUARE_NOFILL :
+ case SID_DRAW_SQUARE_ROUND :
+ case SID_DRAW_SQUARE_ROUND_NOFILL:
+ {
+ aObjKind = SdrObjKind::Rectangle;
+ }
+ break;
+
+ case SID_DRAW_ELLIPSE :
+ case SID_DRAW_ELLIPSE_NOFILL:
+ case SID_DRAW_CIRCLE :
+ case SID_DRAW_CIRCLE_NOFILL :
+ {
+ aObjKind = SdrObjKind::CircleOrEllipse;
+ }
+ break;
+
+ case SID_DRAW_CAPTION:
+ case SID_DRAW_CAPTION_VERTICAL:
+ {
+ aObjKind = SdrObjKind::Caption;
+ }
+ break;
+
+ case SID_TOOL_CONNECTOR:
+ case SID_CONNECTOR_ARROW_START:
+ case SID_CONNECTOR_ARROW_END:
+ case SID_CONNECTOR_ARROWS:
+ case SID_CONNECTOR_CIRCLE_START:
+ case SID_CONNECTOR_CIRCLE_END:
+ case SID_CONNECTOR_CIRCLES:
+ case SID_CONNECTOR_LINE:
+ case SID_CONNECTOR_LINE_ARROW_START:
+ case SID_CONNECTOR_LINE_ARROW_END:
+ case SID_CONNECTOR_LINE_ARROWS:
+ case SID_CONNECTOR_LINE_CIRCLE_START:
+ case SID_CONNECTOR_LINE_CIRCLE_END:
+ case SID_CONNECTOR_LINE_CIRCLES:
+ case SID_CONNECTOR_CURVE:
+ case SID_CONNECTOR_CURVE_ARROW_START:
+ case SID_CONNECTOR_CURVE_ARROW_END:
+ case SID_CONNECTOR_CURVE_ARROWS:
+ case SID_CONNECTOR_CURVE_CIRCLE_START:
+ case SID_CONNECTOR_CURVE_CIRCLE_END:
+ case SID_CONNECTOR_CURVE_CIRCLES:
+ case SID_CONNECTOR_LINES:
+ case SID_CONNECTOR_LINES_ARROW_START:
+ case SID_CONNECTOR_LINES_ARROW_END:
+ case SID_CONNECTOR_LINES_ARROWS:
+ case SID_CONNECTOR_LINES_CIRCLE_START:
+ case SID_CONNECTOR_LINES_CIRCLE_END:
+ case SID_CONNECTOR_LINES_CIRCLES:
+ {
+ aObjKind = SdrObjKind::Edge;
+ mpView->SetGlueVisible();
+ }
+ break;
+ case SID_INSERT_SIGNATURELINE:
+ {
+ aObjKind = SdrObjKind::Graphic;
+ }
+ break;
+
+ default:
+ {
+ aObjKind = SdrObjKind::Rectangle;
+ }
+ break;
+ }
+
+ mpView->SetCurrentObj(aObjKind);
+
+ FuConstruct::Activate();
+}
+
+void FuConstructRectangle::Deactivate()
+{
+ if( nSlotId == SID_TOOL_CONNECTOR ||
+ nSlotId == SID_CONNECTOR_ARROW_START ||
+ nSlotId == SID_CONNECTOR_ARROW_END ||
+ nSlotId == SID_CONNECTOR_ARROWS ||
+ nSlotId == SID_CONNECTOR_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_CIRCLES ||
+ nSlotId == SID_CONNECTOR_LINE ||
+ nSlotId == SID_CONNECTOR_LINE_ARROW_START ||
+ nSlotId == SID_CONNECTOR_LINE_ARROW_END ||
+ nSlotId == SID_CONNECTOR_LINE_ARROWS ||
+ nSlotId == SID_CONNECTOR_LINE_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_LINE_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_LINE_CIRCLES ||
+ nSlotId == SID_CONNECTOR_CURVE ||
+ nSlotId == SID_CONNECTOR_CURVE_ARROW_START ||
+ nSlotId == SID_CONNECTOR_CURVE_ARROW_END ||
+ nSlotId == SID_CONNECTOR_CURVE_ARROWS ||
+ nSlotId == SID_CONNECTOR_CURVE_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_CURVE_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_CURVE_CIRCLES ||
+ nSlotId == SID_CONNECTOR_LINES ||
+ nSlotId == SID_CONNECTOR_LINES_ARROW_START ||
+ nSlotId == SID_CONNECTOR_LINES_ARROW_END ||
+ nSlotId == SID_CONNECTOR_LINES_ARROWS ||
+ nSlotId == SID_CONNECTOR_LINES_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_LINES_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_LINES_CIRCLES ||
+ nSlotId == SID_LINE_ARROW_START ||
+ nSlotId == SID_LINE_ARROW_END ||
+ nSlotId == SID_LINE_ARROWS ||
+ nSlotId == SID_LINE_ARROW_CIRCLE ||
+ nSlotId == SID_LINE_CIRCLE_ARROW ||
+ nSlotId == SID_LINE_ARROW_SQUARE ||
+ nSlotId == SID_LINE_SQUARE_ARROW )
+ {
+ mpView->SetGlueVisible( false );
+ }
+ FuConstruct::Deactivate();
+
+ if (nSlotId != SID_INSERT_SIGNATURELINE)
+ {
+ return;
+ }
+
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() < 1)
+ {
+ // Just switching pages, no signature rectangle yet.
+ return;
+ }
+
+ // Finished drawing a signature rectangle, now set it up.
+ if (!mpViewShell)
+ {
+ return;
+ }
+
+ uno::Reference<security::XCertificate> xCertificate
+ = svx::SignatureLineHelper::getSignatureCertificate(mpViewShell->GetObjectShell(),
+ mpViewShell->GetFrameWeld());
+ if (!xCertificate.is())
+ {
+ return;
+ }
+
+ svx::SignatureLineHelper::setShapeCertificate(mpView, xCertificate);
+
+ // Update infobar to offer "finish signing".
+ SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
+ if (pFrame && pFrame->HasInfoBarWithID(u"readonly"))
+ {
+ pFrame->RemoveInfoBar(u"readonly");
+ pFrame->AppendReadOnlyInfobar();
+ }
+}
+
+namespace {
+/// Returns the color based on the color names listed in core/include/tools/color.hxx
+/// Feel free to extend with more color names from color.hxx
+Color strToColor(std::u16string_view sColor)
+{
+ Color aColor = COL_AUTO;
+
+ if (sColor == u"COL_GRAY")
+ aColor = COL_GRAY;
+ else if (sColor == u"COL_GRAY3")
+ aColor = COL_GRAY3;
+ else if (sColor == u"COL_GRAY7")
+ aColor = COL_GRAY7;
+
+ return aColor;
+}
+}
+
+/**
+ * set attribute for the object to be created
+ */
+void FuConstructRectangle::SetAttributes(SfxItemSet& rAttr, SdrObject* pObj)
+{
+ if (nSlotId == SID_DRAW_RECT_ROUND ||
+ nSlotId == SID_DRAW_RECT_ROUND_NOFILL ||
+ nSlotId == SID_DRAW_SQUARE_ROUND ||
+ nSlotId == SID_DRAW_SQUARE_ROUND_NOFILL)
+ {
+ // round corner
+ rAttr.Put(makeSdrEckenradiusItem(500));
+ }
+ else if (nSlotId == SID_CONNECTOR_LINE ||
+ nSlotId == SID_CONNECTOR_LINE_ARROW_START ||
+ nSlotId == SID_CONNECTOR_LINE_ARROW_END ||
+ nSlotId == SID_CONNECTOR_LINE_ARROWS ||
+ nSlotId == SID_CONNECTOR_LINE_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_LINE_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_LINE_CIRCLES)
+ {
+ // direct connector
+ rAttr.Put(SdrEdgeKindItem(SdrEdgeKind::OneLine));
+ }
+ else if (nSlotId == SID_CONNECTOR_LINES ||
+ nSlotId == SID_CONNECTOR_LINES_ARROW_START ||
+ nSlotId == SID_CONNECTOR_LINES_ARROW_END ||
+ nSlotId == SID_CONNECTOR_LINES_ARROWS ||
+ nSlotId == SID_CONNECTOR_LINES_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_LINES_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_LINES_CIRCLES)
+ {
+ // line connector
+ rAttr.Put(SdrEdgeKindItem(SdrEdgeKind::ThreeLines));
+ }
+ else if (nSlotId == SID_CONNECTOR_CURVE ||
+ nSlotId == SID_CONNECTOR_CURVE_ARROW_START ||
+ nSlotId == SID_CONNECTOR_CURVE_ARROW_END ||
+ nSlotId == SID_CONNECTOR_CURVE_ARROWS ||
+ nSlotId == SID_CONNECTOR_CURVE_CIRCLE_START ||
+ nSlotId == SID_CONNECTOR_CURVE_CIRCLE_END ||
+ nSlotId == SID_CONNECTOR_CURVE_CIRCLES)
+ {
+ // curve connector
+ rAttr.Put(SdrEdgeKindItem(SdrEdgeKind::Bezier));
+ }
+ else if ( nSlotId == SID_DRAW_CAPTION || nSlotId == SID_DRAW_CAPTION_VERTICAL )
+ {
+ // legend object
+ Size aSize(pObj->GetLogicRect().GetSize());
+ rAttr.Put( makeSdrTextMinFrameHeightItem( aSize.Height() ) );
+ rAttr.Put( makeSdrTextMinFrameWidthItem( aSize.Width() ) );
+ rAttr.Put( makeSdrTextAutoGrowHeightItem( true ) );
+ rAttr.Put( makeSdrTextAutoGrowWidthItem( true ) );
+
+ // Support full with for vertical caption objects, too
+ if(SID_DRAW_CAPTION == nSlotId)
+ rAttr.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_BLOCK ) );
+ else
+ rAttr.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_BLOCK ) );
+
+ rAttr.Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
+ rAttr.Put( makeSdrTextLeftDistItem( 100 ) );
+ rAttr.Put( makeSdrTextRightDistItem( 100 ) );
+ rAttr.Put( makeSdrTextUpperDistItem( 100 ) );
+ rAttr.Put( makeSdrTextLowerDistItem( 100 ) );
+ }
+ else if (nSlotId == SID_DRAW_MEASURELINE)
+ {
+ // dimension line
+ SdPage* pPage = static_cast<SdPage*>( mpView->GetSdrPageView()->GetPage() );
+ OUString aName(SdResId(STR_POOLSHEET_MEASURE));
+ SfxStyleSheet* pSheet(
+ static_cast< SfxStyleSheet* >(
+ pPage->getSdrModelFromSdrPage().GetStyleSheetPool()->Find(aName, SfxStyleFamily::Para)));
+ DBG_ASSERT(pSheet, "StyleSheet missing");
+
+ if (pSheet)
+ {
+ pObj->SetStyleSheet(pSheet, false);
+ }
+
+ SdrLayerAdmin& rAdmin = mpDoc->GetLayerAdmin();
+ pObj->SetLayer(rAdmin.GetLayerID(sUNO_LayerName_measurelines));
+ }
+ else if (nSlotId == SID_DRAW_RECT)
+ {
+ if (mnFillTransparence > 0 && mnFillTransparence <= 100)
+ rAttr.Put(XFillTransparenceItem(mnFillTransparence));
+ if (!msFillColor.isEmpty())
+ rAttr.Put(XFillColorItem(OUString(), strToColor(msFillColor)));
+ if (!msShapeName.isEmpty())
+ pObj->SetName(msShapeName);
+
+ switch(mnLineStyle)
+ {
+ case 0:
+ rAttr.Put( XLineStyleItem(css::drawing::LineStyle_NONE ) );
+ break;
+ case 1:
+ rAttr.Put( XLineStyleItem(css::drawing::LineStyle_SOLID ) );
+ break;
+ case 2:
+ rAttr.Put( XLineStyleItem(css::drawing::LineStyle_DASH ) );
+ break;
+ default:
+ // Leave it to the defaults
+ break;
+ }
+ }
+ else if (nSlotId == SID_INSERT_SIGNATURELINE)
+ {
+ // Avoid the default solid fill and line, we'll set a graphic instead.
+ rAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ rAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ }
+}
+
+/**
+ * set line starts and ends for the object to be created
+ */
+static ::basegfx::B2DPolyPolygon getPolygon(TranslateId pResId, const SdrModel& rModel)
+{
+ ::basegfx::B2DPolyPolygon aRetval;
+ XLineEndListRef pLineEndList(rModel.GetLineEndList());
+
+ if( pLineEndList.is() )
+ {
+ OUString aArrowName(SvxResId(pResId));
+ ::tools::Long nCount = pLineEndList->Count();
+ ::tools::Long nIndex;
+ for( nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ const XLineEndEntry* pEntry = pLineEndList->GetLineEnd(nIndex);
+ if( pEntry->GetName() == aArrowName )
+ {
+ aRetval = pEntry->GetLineEnd();
+ break;
+ }
+ }
+ }
+
+ return aRetval;
+}
+
+void FuConstructRectangle::SetLineEnds(SfxItemSet& rAttr, SdrObject const & rObj)
+{
+ if ( !((rObj.GetObjIdentifier() == SdrObjKind::Edge &&
+ nSlotId != SID_TOOL_CONNECTOR &&
+ nSlotId != SID_CONNECTOR_LINE &&
+ nSlotId != SID_CONNECTOR_LINES &&
+ nSlotId != SID_CONNECTOR_CURVE) ||
+ nSlotId == SID_LINE_ARROW_START ||
+ nSlotId == SID_LINE_ARROW_END ||
+ nSlotId == SID_LINE_ARROWS ||
+ nSlotId == SID_LINE_ARROW_CIRCLE ||
+ nSlotId == SID_LINE_CIRCLE_ARROW ||
+ nSlotId == SID_LINE_ARROW_SQUARE ||
+ nSlotId == SID_LINE_SQUARE_ARROW) )
+ return;
+
+ // set attributes of line start and ends
+ SdrModel& rModel(rObj.getSdrModelFromSdrObject());
+
+ // arrowhead
+ ::basegfx::B2DPolyPolygon aArrow( getPolygon( RID_SVXSTR_ARROW, rModel ) );
+ if( !aArrow.count() )
+ {
+ ::basegfx::B2DPolygon aNewArrow;
+ aNewArrow.append(::basegfx::B2DPoint(10.0, 0.0));
+ aNewArrow.append(::basegfx::B2DPoint(0.0, 30.0));
+ aNewArrow.append(::basegfx::B2DPoint(20.0, 30.0));
+ aNewArrow.setClosed(true);
+ aArrow.append(aNewArrow);
+ }
+
+ // Circles
+ ::basegfx::B2DPolyPolygon aCircle( getPolygon( RID_SVXSTR_CIRCLE, rModel ) );
+ if( !aCircle.count() )
+ {
+ ::basegfx::B2DPolygon aNewCircle = ::basegfx::utils::createPolygonFromEllipse(::basegfx::B2DPoint(0.0, 0.0), 250.0, 250.0);
+ aNewCircle.setClosed(true);
+ aCircle.append(aNewCircle);
+ }
+
+ // Square
+ ::basegfx::B2DPolyPolygon aSquare( getPolygon( RID_SVXSTR_SQUARE, rModel ) );
+ if( !aSquare.count() )
+ {
+ ::basegfx::B2DPolygon aNewSquare;
+ aNewSquare.append(::basegfx::B2DPoint(0.0, 0.0));
+ aNewSquare.append(::basegfx::B2DPoint(10.0, 0.0));
+ aNewSquare.append(::basegfx::B2DPoint(10.0, 10.0));
+ aNewSquare.append(::basegfx::B2DPoint(0.0, 10.0));
+ aNewSquare.setClosed(true);
+ aSquare.append(aNewSquare);
+ }
+
+ SfxItemSet aSet( mpDoc->GetPool() );
+ mpView->GetAttributes( aSet );
+
+ // #i3908# Here, the default Line Start/End width for arrow construction is
+ // set. To have the same value in all situations (construction) in i3908
+ // it was decided to change the default to 0.03 cm for all situations.
+ ::tools::Long nWidth = 300; // (1/100th mm)
+
+ // determine line width and calculate with it the line end width
+ if( aSet.GetItemState( XATTR_LINEWIDTH ) != SfxItemState::DONTCARE )
+ {
+ ::tools::Long nValue = aSet.Get( XATTR_LINEWIDTH ).GetValue();
+ if( nValue > 0 )
+ nWidth = nValue * 3;
+ }
+
+ switch (nSlotId)
+ {
+ case SID_CONNECTOR_ARROWS:
+ case SID_CONNECTOR_LINE_ARROWS:
+ case SID_CONNECTOR_LINES_ARROWS:
+ case SID_CONNECTOR_CURVE_ARROWS:
+ case SID_LINE_ARROWS:
+ {
+ // connector with arrow ends
+ rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
+ rAttr.Put(XLineStartWidthItem(nWidth));
+ rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
+ rAttr.Put(XLineEndWidthItem(nWidth));
+ }
+ break;
+
+ case SID_CONNECTOR_ARROW_START:
+ case SID_CONNECTOR_LINE_ARROW_START:
+ case SID_CONNECTOR_LINES_ARROW_START:
+ case SID_CONNECTOR_CURVE_ARROW_START:
+ case SID_LINE_ARROW_START:
+ case SID_LINE_ARROW_CIRCLE:
+ case SID_LINE_ARROW_SQUARE:
+ {
+ // connector with arrow start
+ rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
+ rAttr.Put(XLineStartWidthItem(nWidth));
+ }
+ break;
+
+ case SID_CONNECTOR_ARROW_END:
+ case SID_CONNECTOR_LINE_ARROW_END:
+ case SID_CONNECTOR_LINES_ARROW_END:
+ case SID_CONNECTOR_CURVE_ARROW_END:
+ case SID_LINE_ARROW_END:
+ case SID_LINE_CIRCLE_ARROW:
+ case SID_LINE_SQUARE_ARROW:
+ {
+ // connector with arrow end
+ rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_ARROW), aArrow));
+ rAttr.Put(XLineEndWidthItem(nWidth));
+ }
+ break;
+
+ case SID_CONNECTOR_CIRCLES:
+ case SID_CONNECTOR_LINE_CIRCLES:
+ case SID_CONNECTOR_LINES_CIRCLES:
+ case SID_CONNECTOR_CURVE_CIRCLES:
+ {
+ // connector with circle ends
+ rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_CIRCLE), aCircle));
+ rAttr.Put(XLineStartWidthItem(nWidth));
+ rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_CIRCLE), aCircle));
+ rAttr.Put(XLineEndWidthItem(nWidth));
+ }
+ break;
+
+ case SID_CONNECTOR_CIRCLE_START:
+ case SID_CONNECTOR_LINE_CIRCLE_START:
+ case SID_CONNECTOR_LINES_CIRCLE_START:
+ case SID_CONNECTOR_CURVE_CIRCLE_START:
+ {
+ // connector with circle start
+ rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_CIRCLE), aCircle));
+ rAttr.Put(XLineStartWidthItem(nWidth));
+ }
+ break;
+
+ case SID_CONNECTOR_CIRCLE_END:
+ case SID_CONNECTOR_LINE_CIRCLE_END:
+ case SID_CONNECTOR_LINES_CIRCLE_END:
+ case SID_CONNECTOR_CURVE_CIRCLE_END:
+ {
+ // connector with circle ends
+ rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_CIRCLE), aCircle));
+ rAttr.Put(XLineEndWidthItem(nWidth));
+ }
+ break;
+ }
+
+ // and again, for the still missing ends
+ switch (nSlotId)
+ {
+ case SID_LINE_ARROW_CIRCLE:
+ {
+ // circle end
+ rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_CIRCLE), aCircle));
+ rAttr.Put(XLineEndWidthItem(nWidth));
+ }
+ break;
+
+ case SID_LINE_CIRCLE_ARROW:
+ {
+ // circle start
+ rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_CIRCLE), aCircle));
+ rAttr.Put(XLineStartWidthItem(nWidth));
+ }
+ break;
+
+ case SID_LINE_ARROW_SQUARE:
+ {
+ // square end
+ rAttr.Put(XLineEndItem(SvxResId(RID_SVXSTR_SQUARE), aSquare));
+ rAttr.Put(XLineEndWidthItem(nWidth));
+ }
+ break;
+
+ case SID_LINE_SQUARE_ARROW:
+ {
+ // square start
+ rAttr.Put(XLineStartItem(SvxResId(RID_SVXSTR_SQUARE), aSquare));
+ rAttr.Put(XLineStartWidthItem(nWidth));
+ }
+ break;
+ }
+}
+
+SdrObjectUniquePtr FuConstructRectangle::CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle)
+{
+ DBG_ASSERT( (nID != SID_DRAW_FONTWORK) && (nID != SID_DRAW_FONTWORK_VERTICAL ), "FuConstRectangle::CreateDefaultObject can not create Fontwork shapes!" );
+
+ // case SID_DRAW_LINE:
+ // case SID_DRAW_XLINE:
+ // case SID_DRAW_MEASURELINE:
+ // case SID_LINE_ARROW_START:
+ // case SID_LINE_ARROW_END:
+ // case SID_LINE_ARROWS:
+ // case SID_LINE_ARROW_CIRCLE:
+ // case SID_LINE_CIRCLE_ARROW:
+ // case SID_LINE_ARROW_SQUARE:
+ // case SID_LINE_SQUARE_ARROW:
+ // case SID_DRAW_RECT:
+ // case SID_DRAW_RECT_NOFILL:
+ // case SID_DRAW_RECT_ROUND:
+ // case SID_DRAW_RECT_ROUND_NOFILL:
+ // case SID_DRAW_SQUARE:
+ // case SID_DRAW_SQUARE_NOFILL:
+ // case SID_DRAW_SQUARE_ROUND:
+ // case SID_DRAW_SQUARE_ROUND_NOFILL:
+ // case SID_DRAW_ELLIPSE:
+ // case SID_DRAW_ELLIPSE_NOFILL:
+ // case SID_DRAW_CIRCLE:
+ // case SID_DRAW_CIRCLE_NOFILL:
+ // case SID_DRAW_CAPTION:
+ // case SID_DRAW_CAPTION_VERTICAL:
+ // case SID_TOOL_CONNECTOR:
+ // case SID_CONNECTOR_ARROW_START:
+ // case SID_CONNECTOR_ARROW_END:
+ // case SID_CONNECTOR_ARROWS:
+ // case SID_CONNECTOR_CIRCLE_START:
+ // case SID_CONNECTOR_CIRCLE_END:
+ // case SID_CONNECTOR_CIRCLES:
+ // case SID_CONNECTOR_LINE:
+ // case SID_CONNECTOR_LINE_ARROW_START:
+ // case SID_CONNECTOR_LINE_ARROW_END:
+ // case SID_CONNECTOR_LINE_ARROWS:
+ // case SID_CONNECTOR_LINE_CIRCLE_START:
+ // case SID_CONNECTOR_LINE_CIRCLE_END:
+ // case SID_CONNECTOR_LINE_CIRCLES:
+ // case SID_CONNECTOR_CURVE:
+ // case SID_CONNECTOR_CURVE_ARROW_START:
+ // case SID_CONNECTOR_CURVE_ARROW_END:
+ // case SID_CONNECTOR_CURVE_ARROWS:
+ // case SID_CONNECTOR_CURVE_CIRCLE_START:
+ // case SID_CONNECTOR_CURVE_CIRCLE_END:
+ // case SID_CONNECTOR_CURVE_CIRCLES:
+ // case SID_CONNECTOR_LINES:
+ // case SID_CONNECTOR_LINES_ARROW_START:
+ // case SID_CONNECTOR_LINES_ARROW_END:
+ // case SID_CONNECTOR_LINES_ARROWS:
+ // case SID_CONNECTOR_LINES_CIRCLE_START:
+ // case SID_CONNECTOR_LINES_CIRCLE_END:
+ // case SID_CONNECTOR_LINES_CIRCLES:
+
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ mpView->getSdrModelFromSdrView(),
+ mpView->GetCurrentObjInventor(),
+ mpView->GetCurrentObjIdentifier()));
+
+ if(pObj)
+ {
+ ::tools::Rectangle aRect(rRectangle);
+
+ if(SID_DRAW_SQUARE == nID ||
+ SID_DRAW_SQUARE_NOFILL == nID ||
+ SID_DRAW_SQUARE_ROUND == nID ||
+ SID_DRAW_SQUARE_ROUND_NOFILL == nID ||
+ SID_DRAW_CIRCLE == nID ||
+ SID_DRAW_CIRCLE_NOFILL == nID)
+ {
+ // force quadratic
+ ImpForceQuadratic(aRect);
+ }
+
+ Point aStart = aRect.TopLeft();
+ Point aEnd = aRect.BottomRight();
+
+ switch(nID)
+ {
+ case SID_DRAW_LINE:
+ case SID_DRAW_XLINE:
+ case SID_LINE_ARROW_START:
+ case SID_LINE_ARROW_END:
+ case SID_LINE_ARROWS:
+ case SID_LINE_ARROW_CIRCLE:
+ case SID_LINE_CIRCLE_ARROW:
+ case SID_LINE_ARROW_SQUARE:
+ case SID_LINE_SQUARE_ARROW:
+ {
+ if( auto pPathObj = dynamic_cast<SdrPathObj *>( pObj.get() ) )
+ {
+ sal_Int32 nYMiddle((aRect.Top() + aRect.Bottom()) / 2);
+
+ ::basegfx::B2DPolygon aB2DPolygon;
+ aB2DPolygon.append(::basegfx::B2DPoint(aStart.X(), nYMiddle));
+ aB2DPolygon.append(::basegfx::B2DPoint(aEnd.X(), nYMiddle));
+ pPathObj->SetPathPoly(::basegfx::B2DPolyPolygon(aB2DPolygon));
+ }
+ else
+ {
+ OSL_FAIL("Object is NO line object");
+ }
+
+ break;
+ }
+
+ case SID_DRAW_MEASURELINE:
+ {
+ if( auto pMeasureObj = dynamic_cast< SdrMeasureObj *>( pObj.get() ) )
+ {
+ sal_Int32 nYMiddle((aRect.Top() + aRect.Bottom()) / 2);
+ pMeasureObj->SetPoint(Point(aStart.X(), nYMiddle), 0);
+ pMeasureObj->SetPoint(Point(aEnd.X(), nYMiddle), 1);
+ }
+ else
+ {
+ OSL_FAIL("Object is NO measure object");
+ }
+
+ break;
+ }
+
+ case SID_TOOL_CONNECTOR:
+ case SID_CONNECTOR_ARROW_START:
+ case SID_CONNECTOR_ARROW_END:
+ case SID_CONNECTOR_ARROWS:
+ case SID_CONNECTOR_CIRCLE_START:
+ case SID_CONNECTOR_CIRCLE_END:
+ case SID_CONNECTOR_CIRCLES:
+ case SID_CONNECTOR_LINE:
+ case SID_CONNECTOR_LINE_ARROW_START:
+ case SID_CONNECTOR_LINE_ARROW_END:
+ case SID_CONNECTOR_LINE_ARROWS:
+ case SID_CONNECTOR_LINE_CIRCLE_START:
+ case SID_CONNECTOR_LINE_CIRCLE_END:
+ case SID_CONNECTOR_LINE_CIRCLES:
+ case SID_CONNECTOR_CURVE:
+ case SID_CONNECTOR_CURVE_ARROW_START:
+ case SID_CONNECTOR_CURVE_ARROW_END:
+ case SID_CONNECTOR_CURVE_ARROWS:
+ case SID_CONNECTOR_CURVE_CIRCLE_START:
+ case SID_CONNECTOR_CURVE_CIRCLE_END:
+ case SID_CONNECTOR_CURVE_CIRCLES:
+ case SID_CONNECTOR_LINES:
+ case SID_CONNECTOR_LINES_ARROW_START:
+ case SID_CONNECTOR_LINES_ARROW_END:
+ case SID_CONNECTOR_LINES_ARROWS:
+ case SID_CONNECTOR_LINES_CIRCLE_START:
+ case SID_CONNECTOR_LINES_CIRCLE_END:
+ case SID_CONNECTOR_LINES_CIRCLES:
+ {
+ if( auto pEdgeObj = dynamic_cast< SdrEdgeObj *>( pObj.get() ) )
+ {
+ pEdgeObj->SetTailPoint(false, aStart);
+ pEdgeObj->SetTailPoint(true, aEnd);
+ }
+ else
+ {
+ OSL_FAIL("Object is NO connector object");
+ }
+
+ break;
+ }
+ case SID_DRAW_CAPTION:
+ case SID_DRAW_CAPTION_VERTICAL:
+ {
+ if( auto pCaptionObj = dynamic_cast< SdrCaptionObj *>( pObj.get() ) )
+ {
+ bool bIsVertical(SID_DRAW_CAPTION_VERTICAL == nID);
+
+ pCaptionObj->SetVerticalWriting(bIsVertical);
+
+ if(bIsVertical)
+ {
+ SfxItemSet aSet(pObj->GetMergedItemSet());
+ aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER));
+ aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
+ pObj->SetMergedItemSet(aSet);
+ }
+
+ // The default text is not inserted anymore.
+
+ pCaptionObj->SetLogicRect(aRect);
+ pCaptionObj->SetTailPos(
+ aRect.TopLeft() - Point(aRect.GetWidth() / 2, aRect.GetHeight() / 2));
+ }
+ else
+ {
+ OSL_FAIL("Object is NO caption object");
+ }
+
+ break;
+ }
+
+ default:
+ {
+ pObj->SetLogicRect(aRect);
+
+ break;
+ }
+ }
+
+ SfxItemSet aAttr(mpDoc->GetPool());
+ SetStyleSheet(aAttr, pObj.get());
+ SetAttributes(aAttr, pObj.get());
+ SetLineEnds(aAttr, *pObj);
+ pObj->SetMergedItemSet(aAttr);
+ }
+
+ return pObj;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuconstr.cxx b/sd/source/ui/func/fuconstr.cxx
new file mode 100644
index 000000000..9d6f36320
--- /dev/null
+++ b/sd/source/ui/func/fuconstr.cxx
@@ -0,0 +1,414 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuconstr.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/svdpagv.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <tools/debug.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+
+#include <app.hrc>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <fudraw.hxx>
+#include <View.hxx>
+#include <Window.hxx>
+#include <ViewShell.hxx>
+#include <drawdoc.hxx>
+#include <FrameView.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <glob.hxx>
+#include <comphelper/lok.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+
+FuConstruct::FuConstruct (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuDraw(pViewSh, pWin, pView, pDoc, rReq),
+ bSelectionChanged(false)
+{
+}
+
+bool FuConstruct::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bReturn = FuDraw::MouseButtonDown(rMEvt);
+
+ bMBDown = true;
+ bSelectionChanged = false;
+
+ if ( mpView->IsAction() )
+ {
+ return true;
+ }
+
+ bFirstMouseMove = true;
+ aDragTimer.Start();
+
+ aMDPos = mpWindow->PixelToLogic( rMEvt.GetPosPixel() );
+ sal_uInt16 nHitLog = sal_uInt16 (mpWindow->PixelToLogic(Size(HITPIX,0)).Width());
+
+ if (rMEvt.IsLeft() && mpView->IsExtendedMouseEventDispatcherEnabled())
+ {
+ mpWindow->CaptureMouse();
+
+ SdrHdl* pHdl = mpView->PickHandle(aMDPos);
+
+ if ( pHdl != nullptr || mpView->IsMarkedHit(aMDPos, nHitLog) )
+ {
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+ mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
+ bReturn = true;
+ }
+ else if ( mpView->AreObjectsMarked() )
+ {
+ mpView->UnmarkAll();
+ bReturn = true;
+ }
+ }
+
+ return bReturn;
+}
+
+bool FuConstruct::MouseMove(const MouseEvent& rMEvt)
+{
+ FuDraw::MouseMove(rMEvt);
+
+ if (aDragTimer.IsActive() )
+ {
+ if( bFirstMouseMove )
+ bFirstMouseMove = false;
+ else
+ aDragTimer.Stop();
+ }
+
+ Point aPix(rMEvt.GetPosPixel());
+ Point aPnt( mpWindow->PixelToLogic(aPix) );
+
+ if ( mpView->IsAction() )
+ {
+ ForceScroll(aPix);
+ mpView->MovAction(aPnt);
+ }
+
+ return true;
+}
+
+bool FuConstruct::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bReturn = true;
+
+ if (aDragTimer.IsActive() )
+ {
+ aDragTimer.Stop();
+ bIsInDragMode = false;
+ }
+
+ FuDraw::MouseButtonUp(rMEvt);
+
+ Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ if ( mpView && mpView->IsDragObj() )
+ {
+ FrameView* pFrameView = mpViewShell->GetFrameView();
+ bool bDragWithCopy = (rMEvt.IsMod1() && pFrameView->IsDragWithCopy());
+
+ if (bDragWithCopy)
+ {
+ bDragWithCopy = !mpView->IsPresObjSelected(false);
+ }
+
+ mpView->SetDragWithCopy(bDragWithCopy);
+ mpView->EndDragObj( mpView->IsDragWithCopy() );
+ }
+ else if ( mpView && mpView->IsMarkObj() )
+ {
+ mpView->EndMarkObj();
+ }
+ else
+ {
+ bReturn = false;
+ }
+
+ if ( mpView && !mpView->IsAction() )
+ {
+ mpWindow->ReleaseMouse();
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+
+ if ( !mpView->AreObjectsMarked() )
+ {
+ SdrPageView* pPV;
+ sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
+
+ SdrObject* pObj = mpView->PickObj(aPnt, mpView->getHitTolLog(), pPV);
+ if (!pObj)
+ {
+ mpView->MarkObj(aPnt, nHitLog);
+ }
+
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ }
+ else if (rMEvt.IsLeft() && !rMEvt.IsShift() && !rMEvt.IsMod1() && !rMEvt.IsMod2() &&
+ !bSelectionChanged &&
+ std::abs(aPnt.X() - aMDPos.X()) < nDrgLog &&
+ std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
+ {
+ // toggle between selection and rotation
+ SdrObject* pSingleObj = nullptr;
+
+ if (mpView->GetMarkedObjectList().GetMarkCount()==1)
+ {
+ pSingleObj = mpView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
+ }
+
+ const bool bTiledRendering = comphelper::LibreOfficeKit::isActive();
+ if (!bTiledRendering && (mpView->GetDragMode() == SdrDragMode::Move && mpView->IsRotateAllowed() &&
+ (mpViewShell->GetFrameView()->IsClickChangeRotation() ||
+ (pSingleObj && pSingleObj->GetObjInventor()==SdrInventor::E3d))))
+ {
+ mpView->SetDragMode(SdrDragMode::Rotate);
+ }
+ else
+ {
+ mpView->SetDragMode(SdrDragMode::Move);
+ }
+ }
+ }
+
+ sal_uInt16 nClicks = rMEvt.GetClicks();
+
+ if (nClicks == 2 && rMEvt.IsLeft() && bMBDown &&
+ !rMEvt.IsMod1() && !rMEvt.IsMod2() && !rMEvt.IsShift() )
+ {
+ DoubleClick(rMEvt);
+ }
+ bMBDown = false;
+
+ return bReturn;
+}
+
+void FuConstruct::Activate()
+{
+ mpView->SetEditMode(SdrViewEditMode::Create);
+ FuDraw::Activate();
+}
+
+void FuConstruct::Deactivate()
+{
+ FuDraw::Deactivate();
+ mpView->SetEditMode(SdrViewEditMode::Edit);
+}
+
+/**
+ * set style sheet for the object to be created
+ */
+void FuConstruct::SetStyleSheet(SfxItemSet& rAttr, SdrObject* pObj)
+{
+ bool bUseFillStyle, bUseNoFillStyle;
+ bUseFillStyle = bUseNoFillStyle = false;
+
+ switch( nSlotId )
+ {
+ case SID_DRAW_RECT:
+ case SID_DRAW_RECT_ROUND:
+ case SID_DRAW_SQUARE:
+ case SID_DRAW_SQUARE_ROUND:
+ case SID_DRAW_ELLIPSE:
+ case SID_DRAW_PIE:
+ case SID_DRAW_ELLIPSECUT:
+ case SID_DRAW_CIRCLE:
+ case SID_DRAW_CIRCLEPIE:
+ case SID_DRAW_CIRCLECUT:
+ case SID_DRAW_POLYGON:
+ case SID_DRAW_XPOLYGON:
+ case SID_DRAW_FREELINE:
+ case SID_DRAW_BEZIER_FILL:
+ {
+ bUseFillStyle = true;
+ break;
+ }
+ case SID_DRAW_RECT_NOFILL:
+ case SID_DRAW_RECT_ROUND_NOFILL:
+ case SID_DRAW_SQUARE_NOFILL:
+ case SID_DRAW_SQUARE_ROUND_NOFILL:
+ case SID_DRAW_ELLIPSE_NOFILL:
+ case SID_DRAW_PIE_NOFILL:
+ case SID_DRAW_ELLIPSECUT_NOFILL:
+ case SID_DRAW_CIRCLE_NOFILL:
+ case SID_DRAW_CIRCLEPIE_NOFILL:
+ case SID_DRAW_CIRCLECUT_NOFILL:
+ case SID_DRAW_POLYGON_NOFILL:
+ case SID_DRAW_XPOLYGON_NOFILL:
+ case SID_DRAW_FREELINE_NOFILL:
+ case SID_DRAW_LINE:
+ case SID_DRAW_XLINE:
+ case SID_CONNECTOR_ARROW_START:
+ case SID_CONNECTOR_ARROW_END:
+ case SID_CONNECTOR_ARROWS:
+ case SID_CONNECTOR_CIRCLE_START:
+ case SID_CONNECTOR_CIRCLE_END:
+ case SID_CONNECTOR_CIRCLES:
+ case SID_CONNECTOR_LINE:
+ case SID_CONNECTOR_LINE_ARROW_START:
+ case SID_CONNECTOR_LINE_ARROW_END:
+ case SID_CONNECTOR_LINE_ARROWS:
+ case SID_CONNECTOR_LINE_CIRCLE_START:
+ case SID_CONNECTOR_LINE_CIRCLE_END:
+ case SID_CONNECTOR_LINE_CIRCLES:
+ case SID_CONNECTOR_CURVE:
+ case SID_CONNECTOR_CURVE_ARROW_START:
+ case SID_CONNECTOR_CURVE_ARROW_END:
+ case SID_CONNECTOR_CURVE_ARROWS:
+ case SID_CONNECTOR_CURVE_CIRCLE_START:
+ case SID_CONNECTOR_CURVE_CIRCLE_END:
+ case SID_CONNECTOR_CURVE_CIRCLES:
+ case SID_CONNECTOR_LINES:
+ case SID_CONNECTOR_LINES_ARROW_START:
+ case SID_CONNECTOR_LINES_ARROW_END:
+ case SID_CONNECTOR_LINES_ARROWS:
+ case SID_CONNECTOR_LINES_CIRCLE_START:
+ case SID_CONNECTOR_LINES_CIRCLE_END:
+ case SID_CONNECTOR_LINES_CIRCLES:
+ case SID_DRAW_BEZIER_NOFILL:
+ case SID_LINE_ARROW_END:
+ {
+ bUseNoFillStyle = true;
+ break;
+ }
+ }
+ SetStyleSheet( rAttr, pObj, bUseFillStyle, bUseNoFillStyle );
+}
+
+void FuConstruct::SetStyleSheet( SfxItemSet& rAttr, SdrObject* pObj,
+ const bool bForceFillStyle, const bool bForceNoFillStyle )
+{
+ SdPage* pPage = static_cast<SdPage*>(mpView->GetSdrPageView()->GetPage());
+ if ( pPage->IsMasterPage() && pPage->GetPageKind() == PageKind::Standard &&
+ mpDoc->GetDocumentType() == DocumentType::Impress )
+ {
+ /**********************************************
+ * Objects was created on the slide master page
+ ***********************************************/
+ OUString aName( pPage->GetLayoutName() );
+ sal_Int32 n = aName.indexOf(SD_LT_SEPARATOR) + SD_LT_SEPARATOR.getLength();
+ aName = OUString::Concat(aName.subView(0, n)) + STR_LAYOUT_BACKGROUNDOBJECTS;
+ SfxStyleSheet* pSheet(
+ static_cast< SfxStyleSheet* >(
+ pPage->getSdrModelFromSdrPage().GetStyleSheetPool()->Find(aName, SfxStyleFamily::Page)));
+ DBG_ASSERT(pSheet, "StyleSheet missing");
+ if (pSheet)
+ {
+ // applying style sheet for background objects
+ pObj->SetStyleSheet(pSheet, false);
+ SfxItemSet& rSet = pSheet->GetItemSet();
+ const XFillStyleItem& rFillStyle = rSet.Get(XATTR_FILLSTYLE);
+ if ( bForceFillStyle )
+ {
+ if (rFillStyle.GetValue() == drawing::FillStyle_NONE)
+ rAttr.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ }
+ else if ( bForceNoFillStyle )
+ {
+ if (rFillStyle.GetValue() != drawing::FillStyle_NONE)
+ rAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ }
+ }
+ else
+ {
+ /***********************************
+ * object was created on normal page
+ ************************************/
+ if ( bForceNoFillStyle )
+ {
+ OUString aName(SdResId(STR_POOLSHEET_OBJWITHOUTFILL));
+ SfxStyleSheet* pSheet(
+ static_cast< SfxStyleSheet* >(
+ pPage->getSdrModelFromSdrPage().GetStyleSheetPool()->Find(aName, SfxStyleFamily::Para)));
+ DBG_ASSERT(pSheet, "Stylesheet missing");
+ if (pSheet)
+ {
+ pObj->SetStyleSheet(pSheet, false);
+ SfxItemSet aAttr(mpView->GetDefaultAttr());
+ aAttr.Put(pSheet->GetItemSet().Get(XATTR_FILLSTYLE));
+ pObj->SetMergedItemSet(aAttr);
+ }
+ else
+ {
+ SfxItemSet aAttr(mpView->GetDefaultAttr());
+ rAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ pObj->SetMergedItemSet(aAttr);
+ }
+ }
+ else
+ {
+ // Creating an object with fill.
+ SdrPage* pThemePage = pPage;
+ if (pThemePage->TRG_HasMasterPage())
+ {
+ pThemePage = &pThemePage->TRG_GetMasterPage();
+ }
+
+ svx::Theme* pTheme = pThemePage->getSdrPageProperties().GetTheme();
+ if (pTheme)
+ {
+ // We construct an object on a page where the master page has a theme. Take the
+ // accent1 color from that theme, make sure it has priority over the shape's
+ // document-global style.
+ SfxItemSet aAttr(mpView->GetDefaultAttr());
+
+ aAttr.Put(XFillStyleItem(css::drawing::FillStyle_SOLID));
+
+ svx::ThemeColorType eColorType = svx::ThemeColorType::ACCENT1;
+ Color aColor = pTheme->GetColor(eColorType);
+ XFillColorItem aFillColorItem("", aColor);
+ aFillColorItem.GetThemeColor().SetThemeIndex(static_cast<sal_Int16>(eColorType));
+ aAttr.Put(aFillColorItem);
+
+ aAttr.Put(XLineStyleItem(css::drawing::LineStyle_SOLID));
+
+ // Line color is 50% darker than the fill color.
+ aColor.ApplyTintOrShade(-5000);
+ XLineColorItem aLineColorItem("", aColor);
+ // TODO no theme or theme effect for line colors yet.
+ aAttr.Put(aLineColorItem);
+
+ pObj->SetMergedItemSet(aAttr);
+ }
+ }
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuconuno.cxx b/sd/source/ui/func/fuconuno.cxx
new file mode 100644
index 000000000..afa4523c6
--- /dev/null
+++ b/sd/source/ui/func/fuconuno.cxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuconuno.hxx>
+#include <rtl/ustring.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/request.hxx>
+#include <svl/intitem.hxx>
+#include <svx/svxids.hrc>
+#include <vcl/ptrstyle.hxx>
+
+#include <ViewShell.hxx>
+#include <View.hxx>
+#include <Window.hxx>
+#include <ViewShellBase.hxx>
+#include <ToolBarManager.hxx>
+#include <unokywds.hxx>
+
+
+namespace sd {
+
+
+FuConstructUnoControl::FuConstructUnoControl (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuConstruct(pViewSh, pWin, pView, pDoc, rReq)
+ , nInventor(SdrInventor::Unknown)
+ , nIdentifier(SdrObjKind::NONE)
+{
+}
+
+rtl::Reference<FuPoor> FuConstructUnoControl::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent )
+{
+ FuConstructUnoControl* pFunc;
+ rtl::Reference<FuPoor> xFunc( pFunc = new FuConstructUnoControl( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ pFunc->SetPermanent(bPermanent);
+ return xFunc;
+}
+
+void FuConstructUnoControl::DoExecute( SfxRequest& rReq )
+{
+ FuConstruct::DoExecute( rReq );
+
+ const SfxUInt32Item* pInventorItem = rReq.GetArg<SfxUInt32Item>(SID_FM_CONTROL_INVENTOR);
+ const SfxUInt16Item* pIdentifierItem = rReq.GetArg<SfxUInt16Item>(SID_FM_CONTROL_IDENTIFIER);
+ if( pInventorItem )
+ nInventor = static_cast<SdrInventor>(pInventorItem->GetValue());
+ if( pIdentifierItem )
+ nIdentifier = static_cast<SdrObjKind>(pIdentifierItem->GetValue());
+
+ mpViewShell->GetViewShellBase().GetToolBarManager()->SetToolBar(
+ ToolBarManager::ToolBarGroup::Function,
+ ToolBarManager::msDrawingObjectToolBar);
+}
+
+bool FuConstructUnoControl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bReturn = FuConstruct::MouseButtonDown(rMEvt);
+
+ if ( rMEvt.IsLeft() && !mpView->IsAction() )
+ {
+ Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+ mpWindow->CaptureMouse();
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+ mpView->BegCreateObj(aPnt, nullptr, nDrgLog);
+ bReturn = true;
+ }
+ return bReturn;
+}
+
+bool FuConstructUnoControl::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bReturn = false;
+
+ if ( mpView->IsCreateObj() && rMEvt.IsLeft() )
+ {
+ mpView->EndCreateObj(SdrCreateCmd::ForceEnd);
+ bReturn = true;
+ }
+
+ bReturn = (FuConstruct::MouseButtonUp(rMEvt) || bReturn);
+
+ if (!bPermanent)
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+
+ return bReturn;
+}
+
+void FuConstructUnoControl::Activate()
+{
+ mpView->SetCurrentObj( nIdentifier, nInventor );
+
+ aNewPointer = PointerStyle::DrawRect;
+ aOldPointer = mpWindow->GetPointer();
+ mpWindow->SetPointer( aNewPointer );
+
+ aOldLayer = mpView->GetActiveLayer();
+ mpView->SetActiveLayer(sUNO_LayerName_controls);
+
+ FuConstruct::Activate();
+}
+
+void FuConstructUnoControl::Deactivate()
+{
+ FuConstruct::Deactivate();
+ mpView->SetActiveLayer( aOldLayer );
+ mpWindow->SetPointer( aOldPointer );
+}
+
+SdrObjectUniquePtr FuConstructUnoControl::CreateDefaultObject(const sal_uInt16, const ::tools::Rectangle& rRectangle)
+{
+ // case SID_FM_CREATE_CONTROL:
+
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ mpView->getSdrModelFromSdrView(),
+ mpView->GetCurrentObjInventor(),
+ mpView->GetCurrentObjIdentifier()));
+
+ if(pObj)
+ {
+ pObj->SetLogicRect(rRectangle);
+ }
+
+ return pObj;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fucopy.cxx b/sd/source/ui/func/fucopy.cxx
new file mode 100644
index 000000000..99e5f7b87
--- /dev/null
+++ b/sd/source/ui/func/fucopy.cxx
@@ -0,0 +1,288 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fucopy.hxx>
+#include <sfx2/progress.hxx>
+#include <svl/intitem.hxx>
+
+#include <sdattr.hrc>
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <ViewShell.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/xcolit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/sdangitm.hxx>
+#include <sfx2/request.hxx>
+#include <sdabstdlg.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+
+FuCopy::FuCopy (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuCopy::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuCopy( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuCopy::DoExecute( SfxRequest& rReq )
+{
+ if( !mpView->AreObjectsMarked() )
+ return;
+
+ // Undo
+ OUString aString = mpView->GetDescriptionOfMarkedObjects() +
+ " " + SdResId( STR_UNDO_COPYOBJECTS );
+ mpView->BegUndo( aString );
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if( !pArgs )
+ {
+ SfxItemSetFixed<ATTR_COPY_START, ATTR_COPY_END> aSet( mpViewShell->GetPool() );
+
+ // indicate color attribute
+ SfxItemSet aAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aAttr );
+
+ if( const XFillStyleItem* pFillStyleItem = aAttr.GetItemIfSet( XATTR_FILLSTYLE ) )
+ {
+ drawing::FillStyle eStyle = pFillStyleItem->GetValue();
+
+ const XFillColorItem* pFillColorItem;
+ if( eStyle == drawing::FillStyle_SOLID &&
+ (pFillColorItem = aAttr.GetItemIfSet( XATTR_FILLCOLOR )) )
+ {
+ XColorItem aXColorItem( ATTR_COPY_START_COLOR, pFillColorItem->GetName(),
+ pFillColorItem->GetColorValue() );
+ aSet.Put( aXColorItem );
+
+ }
+ }
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractCopyDlg> pDlg(pFact->CreateCopyDlg(mpViewShell->GetFrameWeld(), aSet, mpView ));
+
+ sal_uInt16 nResult = pDlg->Execute();
+
+ switch( nResult )
+ {
+ case RET_OK:
+ pDlg->GetAttr( aSet );
+ rReq.Done( aSet );
+ pArgs = rReq.GetArgs();
+ break;
+
+ default:
+ {
+ pDlg.disposeAndClear();
+ mpView->EndUndo();
+ return; // Cancel
+ }
+ }
+ }
+
+ ::tools::Rectangle aRect;
+ sal_Int32 lWidth = 0, lHeight = 0, lSizeX = 0, lSizeY = 0;
+ Degree100 lAngle(0);
+ sal_uInt16 nNumber = 0;
+ Color aStartColor, aEndColor;
+ bool bColor = false;
+
+ if (pArgs)
+ {
+ // Count
+ if( const SfxUInt16Item* pPoolItem = pArgs->GetItemIfSet( ATTR_COPY_NUMBER ) )
+ nNumber = pPoolItem->GetValue();
+
+ // translation
+ if( const SfxInt32Item* pPoolItem = pArgs->GetItemIfSet( ATTR_COPY_MOVE_X ) )
+ lSizeX = pPoolItem->GetValue();
+ if( const SfxInt32Item* pPoolItem = pArgs->GetItemIfSet( ATTR_COPY_MOVE_Y ) )
+ lSizeY = pPoolItem->GetValue();
+ if( const SdrAngleItem* pPoolItem = pArgs->GetItemIfSet( ATTR_COPY_ANGLE ) )
+ lAngle = pPoolItem->GetValue();
+
+ // scale
+ if( const SfxInt32Item* pPoolItem = pArgs->GetItemIfSet( ATTR_COPY_WIDTH ) )
+ lWidth = pPoolItem->GetValue();
+ if( const SfxInt32Item* pPoolItem = pArgs->GetItemIfSet( ATTR_COPY_HEIGHT ) )
+ lHeight = pPoolItem->GetValue();
+
+ // start/end color
+ if( const XColorItem* pPoolItem = pArgs->GetItemIfSet( ATTR_COPY_START_COLOR ) )
+ {
+ aStartColor = pPoolItem->GetColorValue();
+ bColor = true;
+ }
+ if( const XColorItem* pPoolItem = pArgs->GetItemIfSet( ATTR_COPY_END_COLOR ) )
+ {
+ aEndColor = pPoolItem->GetColorValue();
+ if( aStartColor == aEndColor )
+ bColor = false;
+ }
+ }
+
+ // remove handles
+ //HMHmpView->HideMarkHdl();
+
+ std::unique_ptr<SfxProgress> pProgress;
+ bool bWaiting = false;
+
+ if( nNumber > 1 )
+ {
+ OUString aStr = SdResId( STR_OBJECTS ) +
+ " " + SdResId( STR_UNDO_COPYOBJECTS );
+
+ pProgress.reset(new SfxProgress( mpDocSh, aStr, nNumber ));
+ mpDocSh->SetWaitCursor( true );
+ bWaiting = true;
+ }
+
+ const SdrMarkList aMarkList( mpView->GetMarkedObjectList() );
+ const size_t nMarkCount = aMarkList.GetMarkCount();
+ SdrObject* pObj = nullptr;
+
+ // calculate number of possible copies
+ aRect = mpView->GetAllMarkedRect();
+
+ if( lWidth < 0 )
+ {
+ ::tools::Long nTmp = ( aRect.Right() - aRect.Left() ) / -lWidth;
+ nNumber = static_cast<sal_uInt16>(std::min( nTmp, static_cast<::tools::Long>(nNumber) ));
+ }
+
+ if( lHeight < 0 )
+ {
+ ::tools::Long nTmp = ( aRect.Bottom() - aRect.Top() ) / -lHeight;
+ nNumber = static_cast<sal_uInt16>(std::min( nTmp, static_cast<::tools::Long>(nNumber) ));
+ }
+
+ for( sal_uInt16 i = 1; i <= nNumber; i++ )
+ {
+ if( pProgress )
+ pProgress->SetState( i );
+
+ aRect = mpView->GetAllMarkedRect();
+
+ if( ( 1 == i ) && bColor )
+ {
+ SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLCOLOR> aNewSet( mpViewShell->GetPool() );
+ aNewSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ aNewSet.Put( XFillColorItem( OUString(), aStartColor ) );
+ mpView->SetAttributes( aNewSet );
+ }
+
+ // make a copy of selected objects
+ mpView->CopyMarked();
+
+ // get newly selected objects
+ SdrMarkList aCopyMarkList( mpView->GetMarkedObjectList() );
+ const size_t nCopyMarkCount = aMarkList.GetMarkCount();
+
+ // set protection flags at marked copies to null
+ for( size_t j = 0; j < nCopyMarkCount; ++j )
+ {
+ pObj = aCopyMarkList.GetMark( j )->GetMarkedSdrObj();
+
+ if( pObj )
+ {
+ pObj->SetMoveProtect( false );
+ pObj->SetResizeProtect( false );
+ }
+ }
+
+ Fraction aWidth( aRect.Right() - aRect.Left() + lWidth, aRect.Right() - aRect.Left() );
+ Fraction aHeight( aRect.Bottom() - aRect.Top() + lHeight, aRect.Bottom() - aRect.Top() );
+
+ if( mpView->IsResizeAllowed() )
+ mpView->ResizeAllMarked( aRect.TopLeft(), aWidth, aHeight );
+
+ if( mpView->IsRotateAllowed() )
+ mpView->RotateAllMarked( aRect.Center(), lAngle );
+
+ if( mpView->IsMoveAllowed() )
+ mpView->MoveAllMarked( Size( lSizeX, lSizeY ) );
+
+ // set protection flags at marked copies to original values
+ if( nMarkCount == nCopyMarkCount )
+ {
+ for( size_t j = 0; j < nMarkCount; ++j )
+ {
+ SdrObject* pSrcObj = aMarkList.GetMark( j )->GetMarkedSdrObj();
+ SdrObject* pDstObj = aCopyMarkList.GetMark( j )->GetMarkedSdrObj();
+
+ if( pSrcObj && pDstObj &&
+ ( pSrcObj->GetObjInventor() == pDstObj->GetObjInventor() ) &&
+ ( pSrcObj->GetObjIdentifier() == pDstObj->GetObjIdentifier() ) )
+ {
+ pDstObj->SetMoveProtect( pSrcObj->IsMoveProtect() );
+ pDstObj->SetResizeProtect( pSrcObj->IsResizeProtect() );
+ }
+ }
+ }
+
+ if( bColor )
+ {
+ // probably room for optimizations, but may can lead to rounding errors
+ sal_uInt8 nRed = aStartColor.GetRed() + static_cast<sal_uInt8>( ( static_cast<::tools::Long>(aEndColor.GetRed()) - static_cast<::tools::Long>(aStartColor.GetRed()) ) * static_cast<::tools::Long>(i) / static_cast<::tools::Long>(nNumber) );
+ sal_uInt8 nGreen = aStartColor.GetGreen() + static_cast<sal_uInt8>( ( static_cast<::tools::Long>(aEndColor.GetGreen()) - static_cast<::tools::Long>(aStartColor.GetGreen()) ) * static_cast<::tools::Long>(i) / static_cast<::tools::Long>(nNumber) );
+ sal_uInt8 nBlue = aStartColor.GetBlue() + static_cast<sal_uInt8>( ( static_cast<::tools::Long>(aEndColor.GetBlue()) - static_cast<::tools::Long>(aStartColor.GetBlue()) ) * static_cast<::tools::Long>(i) / static_cast<::tools::Long>(nNumber) );
+ Color aNewColor( nRed, nGreen, nBlue );
+ SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLCOLOR> aNewSet( mpViewShell->GetPool() );
+ aNewSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ aNewSet.Put( XFillColorItem( OUString(), aNewColor ) );
+ mpView->SetAttributes( aNewSet );
+ }
+ }
+
+ pProgress.reset();
+
+ if ( bWaiting )
+ mpDocSh->SetWaitCursor( false );
+
+ // show handles
+ mpView->AdjustMarkHdl(); //HMH sal_True );
+ //HMHpView->ShowMarkHdl();
+
+ mpView->EndUndo();
+}
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fucushow.cxx b/sd/source/ui/func/fucushow.cxx
new file mode 100644
index 000000000..eb3b12211
--- /dev/null
+++ b/sd/source/ui/func/fucushow.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 <fucushow.hxx>
+
+#include <svx/svxids.hrc>
+
+#include <ViewShell.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <sdabstdlg.hxx>
+
+namespace sd {
+
+
+FuCustomShowDlg::FuCustomShowDlg (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor( pViewSh, pWin, pView, pDoc, rReq )
+{
+}
+
+rtl::Reference<FuPoor> FuCustomShowDlg::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuCustomShowDlg( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuCustomShowDlg::DoExecute( SfxRequest& )
+{
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = mpViewShell->GetActiveWindow();
+ ScopedVclPtr<AbstractSdCustomShowDlg> pDlg( pFact->CreateSdCustomShowDlg(pWin ? pWin->GetFrameWeld() : nullptr, *mpDoc) );
+ sal_uInt16 nRet = pDlg->Execute();
+ mpDoc->SetChanged();
+ sd::PresentationSettings& rSettings = mpDoc->getPresentationSettings();
+
+ if( nRet == RET_YES )
+ {
+ // If the custom show is not set by default
+ if (!rSettings.mbCustomShow)
+ {
+ rSettings.mbStartCustomShow = true;
+ rSettings.mbCustomShow = pDlg->IsCustomShow();
+ }
+
+ mpViewShell->SetStartShowWithDialog(true);
+
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_PRESENTATION,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+ if (nRet == RET_OK)
+ {
+ if (mpDoc->GetCustomShowList())
+ {
+ if (!pDlg->IsCustomShow())
+ {
+ rSettings.mbCustomShow = false;
+ rSettings.mbAll = true;
+ }
+ }
+ }
+ pDlg.disposeAndClear();
+}
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fudraw.cxx b/sd/source/ui/func/fudraw.cxx
new file mode 100644
index 000000000..8beb753f6
--- /dev/null
+++ b/sd/source/ui/func/fudraw.cxx
@@ -0,0 +1,820 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <vcl/svapp.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/svdogrp.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/help.hxx>
+#include <svx/bmpmask.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/sfxhelp.hxx>
+#include <svx/svdpagv.hxx>
+#include <vcl/imapobj.hxx>
+#include <svx/svxids.hrc>
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <strings.hrc>
+
+
+#include <sdmod.hxx>
+#include <fudraw.hxx>
+#include <ViewShell.hxx>
+#include <FrameView.hxx>
+#include <View.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <sdresid.hxx>
+#include <fusel.hxx>
+#include <vcl/weld.hxx>
+#include <svx/sdrhittesthelper.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd {
+
+
+/**
+ * Base-class for all drawmodul-specific functions
+ */
+FuDraw::FuDraw(ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView,
+ SdDrawDocument* pDoc, SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+ , aNewPointer(PointerStyle::Arrow)
+ , aOldPointer(PointerStyle::Arrow)
+ , bMBDown(false)
+ , bDragHelpLine(false)
+ , nHelpLine(0)
+ , bPermanent(false)
+{
+}
+
+FuDraw::~FuDraw()
+{
+ mpView->BrkAction();
+}
+
+
+/**
+ * Code shared by MouseButtonDown and MouseMove
+ */
+void FuDraw::DoModifiers(const MouseEvent& rMEvt, bool bSnapModPressed)
+{
+ FrameView* pFrameView = mpViewShell->GetFrameView();
+ bool bGridSnap = pFrameView->IsGridSnap();
+ bGridSnap = (bSnapModPressed != bGridSnap);
+
+ if (mpView->IsGridSnap() != bGridSnap)
+ mpView->SetGridSnap(bGridSnap);
+
+ bool bBordSnap = pFrameView->IsBordSnap();
+ bBordSnap = (bSnapModPressed != bBordSnap);
+
+ if (mpView->IsBordSnap() != bBordSnap)
+ mpView->SetBordSnap(bBordSnap);
+
+ bool bHlplSnap = pFrameView->IsHlplSnap();
+ bHlplSnap = (bSnapModPressed != bHlplSnap);
+
+ if (mpView->IsHlplSnap() != bHlplSnap)
+ mpView->SetHlplSnap(bHlplSnap);
+
+ bool bOFrmSnap = pFrameView->IsOFrmSnap();
+ bOFrmSnap = (bSnapModPressed != bOFrmSnap);
+
+ if (mpView->IsOFrmSnap() != bOFrmSnap)
+ mpView->SetOFrmSnap(bOFrmSnap);
+
+ bool bOPntSnap = pFrameView->IsOPntSnap();
+ bOPntSnap = (bSnapModPressed != bOPntSnap);
+
+ if (mpView->IsOPntSnap() != bOPntSnap)
+ mpView->SetOPntSnap(bOPntSnap);
+
+ bool bOConSnap = pFrameView->IsOConSnap();
+ bOConSnap = (bSnapModPressed != bOConSnap);
+
+ if (mpView->IsOConSnap() != bOConSnap)
+ mpView->SetOConSnap(bOConSnap);
+
+ bool bAngleSnap = rMEvt.IsShift() == !pFrameView->IsAngleSnapEnabled();
+
+ if (mpView->IsAngleSnapEnabled() != bAngleSnap)
+ mpView->SetAngleSnapEnabled(bAngleSnap);
+
+ bool bCenter = rMEvt.IsMod2();
+
+ if ( mpView->IsCreate1stPointAsCenter() != bCenter ||
+ mpView->IsResizeAtCenter() != bCenter )
+ {
+ mpView->SetCreate1stPointAsCenter(bCenter);
+ mpView->SetResizeAtCenter(bCenter);
+ }
+}
+
+
+bool FuDraw::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = false;
+ bDragHelpLine = false;
+ aMDPos = mpWindow->PixelToLogic( rMEvt.GetPosPixel() );
+
+ if ( rMEvt.IsLeft() )
+ {
+ FrameView* pFrameView = mpViewShell->GetFrameView();
+
+ bool bOrtho = false;
+
+ bool bRestricted = true;
+
+ if (mpView->IsDragObj())
+ {
+ // object is dragged (move, resize,...)
+ const SdrHdl* pHdl = mpView->GetDragStat().GetHdl();
+
+ if (!pHdl || (!pHdl->IsCornerHdl() && !pHdl->IsVertexHdl()))
+ {
+ // Move
+ bRestricted = false;
+ }
+ }
+
+ // #i33136#
+ if(bRestricted && doConstructOrthogonal())
+ {
+ // Restrict movement:
+ // rectangle->square, ellipse->circle, etc.
+ bOrtho = !rMEvt.IsShift();
+ }
+ else
+ {
+ bOrtho = rMEvt.IsShift() != pFrameView->IsOrtho();
+ }
+ if (!mpView->IsSnapEnabled())
+ mpView->SetSnapEnabled(true);
+
+ bool bSnapModPressed = rMEvt.IsMod1();
+ if (mpView->IsOrtho() != bOrtho)
+ mpView->SetOrtho(bOrtho);
+
+ DoModifiers(rMEvt, bSnapModPressed);
+
+ SdrPageView* pPV = nullptr;
+ sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
+
+ // look only for HelpLines when they are visible (!)
+ bool bHelpLine(false);
+ if(mpView->IsHlplVisible())
+ bHelpLine = mpView->PickHelpLine(aMDPos, nHitLog, *mpWindow->GetOutDev(), nHelpLine, pPV);
+ bool bHitHdl = (mpView->PickHandle(aMDPos) != nullptr);
+
+ if ( bHelpLine
+ && !mpView->IsCreateObj()
+ && ((mpView->GetEditMode() == SdrViewEditMode::Edit && !bHitHdl) || (rMEvt.IsShift() && bSnapModPressed)) )
+ {
+ mpWindow->CaptureMouse();
+ mpView->BegDragHelpLine(nHelpLine, pPV);
+ bDragHelpLine = mpView->IsDragHelpLine();
+ bReturn = true;
+ }
+ }
+ ForcePointer(&rMEvt);
+
+ return bReturn;
+}
+
+bool FuDraw::MouseMove(const MouseEvent& rMEvt)
+{
+ FrameView* pFrameView = mpViewShell->GetFrameView();
+ Point aPos = mpWindow->PixelToLogic( rMEvt.GetPosPixel() );
+
+ bool bOrtho = false;
+ bool bRestricted = true;
+
+ if (mpView->IsDragObj())
+ {
+ // object is dragged (move, resize, ...)
+ const SdrHdl* pHdl = mpView->GetDragStat().GetHdl();
+
+ if (!pHdl || (!pHdl->IsCornerHdl() && !pHdl->IsVertexHdl()))
+ {
+ // Move
+ bRestricted = false;
+ }
+ }
+
+ if (mpView->IsAction())
+ {
+ // #i33136# and fdo#88339
+ if(bRestricted && doConstructOrthogonal())
+ {
+ // Scale proportionally by default:
+ // rectangle->square, ellipse->circle, images, etc.
+ bOrtho = !rMEvt.IsShift();
+ }
+ else
+ {
+ bOrtho = rMEvt.IsShift() != pFrameView->IsOrtho();
+ }
+
+ bool bSnapModPressed = rMEvt.IsMod2();
+ mpView->SetDragWithCopy(rMEvt.IsMod1() && pFrameView->IsDragWithCopy());
+
+ if (mpView->IsOrtho() != bOrtho)
+ mpView->SetOrtho(bOrtho);
+ DoModifiers(rMEvt, bSnapModPressed);
+
+
+ if ( mpView->IsDragHelpLine() )
+ mpView->MovDragHelpLine(aPos);
+ }
+
+ bool bReturn = mpView->MouseMove(rMEvt, mpWindow->GetOutDev());
+
+ if (mpView->IsAction())
+ {
+ // Because the flag set back if necessary in MouseMove
+ if (mpView->IsOrtho() != bOrtho)
+ mpView->SetOrtho(bOrtho);
+ }
+
+ ForcePointer(&rMEvt);
+
+ return bReturn;
+}
+
+bool FuDraw::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if (mpView && mpView->IsDragHelpLine())
+ mpView->EndDragHelpLine();
+
+ if ( bDragHelpLine )
+ {
+ ::tools::Rectangle aOutputArea(Point(0,0), mpWindow->GetOutputSizePixel());
+
+ if (mpView && !aOutputArea.Contains(rMEvt.GetPosPixel()))
+ mpView->GetSdrPageView()->DeleteHelpLine(nHelpLine);
+
+ mpWindow->ReleaseMouse();
+ }
+
+ if (mpView)
+ {
+ FrameView* pFrameView = mpViewShell->GetFrameView();
+ mpView->SetOrtho( pFrameView->IsOrtho() );
+ mpView->SetAngleSnapEnabled( pFrameView->IsAngleSnapEnabled() );
+ mpView->SetSnapEnabled(true);
+ mpView->SetCreate1stPointAsCenter(false);
+ mpView->SetResizeAtCenter(false);
+ mpView->SetDragWithCopy(pFrameView->IsDragWithCopy());
+ mpView->SetGridSnap(pFrameView->IsGridSnap());
+ mpView->SetBordSnap(pFrameView->IsBordSnap());
+ mpView->SetHlplSnap(pFrameView->IsHlplSnap());
+ mpView->SetOFrmSnap(pFrameView->IsOFrmSnap());
+ mpView->SetOPntSnap(pFrameView->IsOPntSnap());
+ mpView->SetOConSnap(pFrameView->IsOConSnap());
+ }
+
+ bIsInDragMode = false;
+ ForcePointer(&rMEvt);
+ FuPoor::MouseButtonUp(rMEvt);
+
+ return false;
+}
+
+/**
+ * Process keyboard input
+ * @returns sal_True if a KeyEvent is being processed, sal_False otherwise
+ */
+bool FuDraw::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bReturn = false;
+
+ switch ( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_ESCAPE:
+ {
+ bReturn = FuDraw::cancel();
+ }
+ break;
+
+ case KEY_DELETE:
+ case KEY_BACKSPACE:
+ {
+ if (!mpDocSh->IsReadOnly())
+ {
+ if (mpView->IsPresObjSelected(false, true, false, true))
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(mpWindow->GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ // wait-mousepointer while deleting object
+ weld::WaitObject aWait(mpViewShell->GetFrameWeld());
+ // delete object
+ mpView->DeleteMarked();
+ }
+ }
+ bReturn = true;
+ }
+ break;
+
+ case KEY_TAB:
+ {
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ if ( !aCode.IsMod1() && !aCode.IsMod2() )
+ {
+ // Moved next line which was a bugfix itself into
+ // the scope which really does the object selection travel
+ // and thus is allowed to call SelectionHasChanged().
+
+ // Switch to FuSelect.
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(
+ SID_OBJECT_SELECT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+
+ // changeover to the next object
+ if(!mpView->MarkNextObj( !aCode.IsShift() ))
+ {
+ //If there is only one object, don't do the UnmarkAllObj() & MarkNextObj().
+ if ( mpView->HasMultipleMarkableObjects() && mpView->AreObjectsMarked() )
+ {
+ // No next object: go over open end and get first from
+ // the other side
+ mpView->UnmarkAllObj();
+ mpView->MarkNextObj(!aCode.IsShift());
+ }
+ }
+
+ if(mpView->AreObjectsMarked())
+ mpView->MakeVisible(mpView->GetAllMarkedRect(), *mpWindow);
+
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_END:
+ {
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ if ( aCode.IsMod1() )
+ {
+ // mark last object
+ mpView->UnmarkAllObj();
+ mpView->MarkNextObj();
+
+ if(mpView->AreObjectsMarked())
+ mpView->MakeVisible(mpView->GetAllMarkedRect(), *mpWindow);
+
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_HOME:
+ {
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ if ( aCode.IsMod1() )
+ {
+ // mark first object
+ mpView->UnmarkAllObj();
+ mpView->MarkNextObj(true);
+
+ if(mpView->AreObjectsMarked())
+ mpView->MakeVisible(mpView->GetAllMarkedRect(), *mpWindow);
+
+ bReturn = true;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!bReturn)
+ {
+ bReturn = FuPoor::KeyInput(rKEvt);
+ }
+ else
+ {
+ mpWindow->ReleaseMouse();
+ }
+
+ return bReturn;
+}
+
+void FuDraw::Activate()
+{
+ FuPoor::Activate();
+ ForcePointer();
+}
+
+/**
+ * Toggle mouse-pointer
+ */
+void FuDraw::ForcePointer(const MouseEvent* pMEvt)
+{
+ Point aPnt;
+ sal_uInt16 nModifier = 0;
+ bool bLeftDown = false;
+ bool bDefPointer = true;
+
+ if (pMEvt)
+ {
+ aPnt = mpWindow->PixelToLogic(pMEvt->GetPosPixel());
+ nModifier = pMEvt->GetModifier();
+ bLeftDown = pMEvt->IsLeft();
+ }
+ else
+ {
+ aPnt = mpWindow->PixelToLogic(mpWindow->GetPointerPosPixel());
+ }
+
+ if (mpView->IsDragObj())
+ {
+ if (SD_MOD()->GetWaterCan() && !mpView->PickHandle(aPnt))
+ {
+ // water can mode
+ bDefPointer = false;
+ mpWindow->SetPointer(PointerStyle::Fill);
+ }
+ }
+ else
+ {
+ SdrHdl* pHdl = mpView->PickHandle(aPnt);
+
+ if (SD_MOD()->GetWaterCan() && !pHdl)
+ {
+ // water can mode
+ bDefPointer = false;
+ mpWindow->SetPointer(PointerStyle::Fill);
+ }
+ else if (!pHdl &&
+ mpViewShell->GetViewFrame()->HasChildWindow(SvxBmpMaskChildWindow::GetChildWindowId()))
+ {
+ // pipette mode
+ SfxChildWindow* pWnd = mpViewShell->GetViewFrame()->GetChildWindow(SvxBmpMaskChildWindow::GetChildWindowId());
+ SvxBmpMask* pMask = pWnd ? static_cast<SvxBmpMask*>(pWnd->GetWindow()) : nullptr;
+ if (pMask && pMask->IsEyedropping())
+ {
+ bDefPointer = false;
+ mpWindow->SetPointer(PointerStyle::RefHand);
+ }
+ }
+ else if (!mpView->IsAction())
+ {
+ SdrObject* pObj = nullptr;
+ SdrPageView* pPV = nullptr;
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = SdrHitKind::NONE;
+ SdrDragMode eDragMode = mpView->GetDragMode();
+
+ if (pMEvt)
+ {
+ eHit = mpView->PickAnything(*pMEvt, SdrMouseEventKind::MOVE, aVEvt);
+ }
+
+ if ((eDragMode == SdrDragMode::Rotate) && (eHit == SdrHitKind::MarkedObject))
+ {
+ // The goal of this request is show always the rotation arrow for 3D-objects at rotation mode
+ // Independent of the settings at Tools->Options->Draw "Objects always moveable"
+ // 2D-objects acquit in another way. Otherwise, the rotation of 3d-objects around any axes
+ // wouldn't be possible per default.
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ SdrObject* pObject = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if ((dynamic_cast<const E3dObject* >(pObject) != nullptr) && (rMarkList.GetMarkCount() == 1))
+ {
+ mpWindow->SetPointer(PointerStyle::Rotate);
+ bDefPointer = false; // Otherwise it'll be called Joe's routine and the mousepointer will reconfigurate again
+ }
+ }
+
+ if (eHit == SdrHitKind::NONE)
+ {
+ // found nothing -> look after at the masterpage
+ pObj = mpView->PickObj(aPnt, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
+ }
+ else if (eHit == SdrHitKind::UnmarkedObject)
+ {
+ pObj = aVEvt.mpObj;
+ }
+ else if (eHit == SdrHitKind::TextEditObj && dynamic_cast< const FuSelection *>( this ) != nullptr)
+ {
+ SdrObjKind nSdrObjKind = aVEvt.mpObj->GetObjIdentifier();
+
+ if ( nSdrObjKind != SdrObjKind::Text &&
+ nSdrObjKind != SdrObjKind::TitleText &&
+ nSdrObjKind != SdrObjKind::OutlineText &&
+ aVEvt.mpObj->IsEmptyPresObj() )
+ {
+ pObj = nullptr;
+ bDefPointer = false;
+ mpWindow->SetPointer(PointerStyle::Arrow);
+ }
+ }
+
+ if (pObj && pMEvt && !pMEvt->IsMod2()
+ && dynamic_cast<const FuSelection*>(this) != nullptr)
+ {
+ // test for ImageMap
+ bDefPointer = !SetPointer(pObj, aPnt);
+
+ if (bDefPointer
+ && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr
+ || dynamic_cast<const E3dScene*>(pObj) != nullptr))
+ {
+ // take a glance into the group
+ pObj = mpView->PickObj(aPnt, mpView->getHitTolLog(), pPV,
+ SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::DEEP);
+ if (pObj)
+ bDefPointer = !SetPointer(pObj, aPnt);
+ }
+ }
+ }
+ }
+
+ if (bDefPointer)
+ {
+ mpWindow->SetPointer(mpView->GetPreferredPointer(
+ aPnt, mpWindow->GetOutDev(), nModifier, bLeftDown));
+ }
+}
+
+/**
+ * Set cursor to pointer when in clickable area of an ImageMap
+ *
+ * @return True when pointer was set
+ */
+bool FuDraw::SetPointer(const SdrObject* pObj, const Point& rPos)
+{
+ bool bImageMapInfo = SvxIMapInfo::GetIMapInfo(pObj) != nullptr;
+
+ if (!bImageMapInfo)
+ return false;
+
+ const SdrLayerIDSet* pVisiLayer = &mpView->GetSdrPageView()->GetVisibleLayers();
+ sal_uInt16 nHitLog(sal_uInt16(mpWindow->PixelToLogic(Size(HITPIX, 0)).Width()));
+ ::tools::Long n2HitLog(nHitLog * 2);
+ Point aHitPosR(rPos);
+ Point aHitPosL(rPos);
+ Point aHitPosT(rPos);
+ Point aHitPosB(rPos);
+
+ aHitPosR.AdjustX(n2HitLog);
+ aHitPosL.AdjustX(-n2HitLog);
+ aHitPosT.AdjustY(n2HitLog);
+ aHitPosB.AdjustY(-n2HitLog);
+
+ if (!pObj->IsClosedObj()
+ || (SdrObjectPrimitiveHit(*pObj, aHitPosR, nHitLog, *mpView->GetSdrPageView(), pVisiLayer,
+ false)
+ && SdrObjectPrimitiveHit(*pObj, aHitPosL, nHitLog, *mpView->GetSdrPageView(),
+ pVisiLayer, false)
+ && SdrObjectPrimitiveHit(*pObj, aHitPosT, nHitLog, *mpView->GetSdrPageView(),
+ pVisiLayer, false)
+ && SdrObjectPrimitiveHit(*pObj, aHitPosB, nHitLog, *mpView->GetSdrPageView(),
+ pVisiLayer, false)))
+ {
+ // hit inside the object (without margin) or open object
+ if (SvxIMapInfo::GetHitIMapObject(pObj, rPos))
+ {
+ mpWindow->SetPointer(PointerStyle::RefHand);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Response of doubleclick
+ */
+void FuDraw::DoubleClick(const MouseEvent& rMEvt)
+{
+ sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
+
+ if ( mpView->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+
+ if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::OLE2)
+ {
+ // activate OLE-object
+ SfxInt16Item aItem(SID_OBJECT, 0);
+ mpViewShell->GetViewFrame()->
+ GetDispatcher()->ExecuteList(SID_OBJECT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aItem });
+ }
+ else if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::Graphic && pObj->IsEmptyPresObj() )
+ {
+ mpViewShell->GetViewFrame()->
+ GetDispatcher()->Execute( SID_INSERT_GRAPHIC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+ else if ( ( dynamic_cast< const SdrTextObj *>( pObj ) != nullptr || dynamic_cast< const SdrObjGroup *>( pObj ) != nullptr ) &&
+ !SD_MOD()->GetWaterCan() &&
+ mpViewShell->GetFrameView()->IsDoubleClickTextEdit() &&
+ !mpDocSh->IsReadOnly())
+ {
+ SfxUInt16Item aItem(SID_TEXTEDIT, 2);
+ mpViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_TEXTEDIT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aItem });
+ }
+ else if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::Group)
+ {
+ // hit group -> select subobject
+ mpView->UnMarkAll();
+ mpView->MarkObj(aMDPos, nHitLog, rMEvt.IsShift(), true);
+ }
+ }
+ }
+ else
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+}
+
+bool FuDraw::RequestHelp(const HelpEvent& rHEvt)
+{
+ bool bReturn = false;
+
+ if (Help::IsBalloonHelpEnabled() || Help::IsQuickHelpEnabled())
+ {
+ SdrViewEvent aVEvt;
+
+ MouseEvent aMEvt(mpWindow->GetPointerPosPixel(), 1, MouseEventModifiers::NONE, MOUSE_LEFT);
+
+ SdrHitKind eHit = mpView->PickAnything(aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+
+ SdrObject* pObj = aVEvt.mpObj;
+
+ if (eHit != SdrHitKind::NONE && pObj != nullptr)
+ {
+ Point aPosPixel = rHEvt.GetMousePosPixel();
+
+ bReturn = SetHelpText(pObj, aPosPixel, aVEvt);
+
+ if (!bReturn && (dynamic_cast< const SdrObjGroup *>( pObj ) != nullptr || dynamic_cast< const E3dScene* >(pObj) != nullptr))
+ {
+ // take a glance into the group
+ SdrPageView* pPV = nullptr;
+
+ Point aPos(mpWindow->PixelToLogic(mpWindow->ScreenToOutputPixel(aPosPixel)));
+
+ pObj = mpView->PickObj(aPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::DEEP);
+ if (pObj)
+ bReturn = SetHelpText(pObj, aPosPixel, aVEvt);
+ }
+ }
+ }
+
+ if (!bReturn)
+ {
+ bReturn = FuPoor::RequestHelp(rHEvt);
+ }
+
+ if (!bReturn)
+ bReturn = mpView->RequestHelp(rHEvt);
+
+ return bReturn;
+}
+
+bool FuDraw::SetHelpText(const SdrObject* pObj, const Point& rPosPixel, const SdrViewEvent& rVEvt)
+{
+ OUString aHelpText;
+ Point aPos(mpWindow->PixelToLogic(mpWindow->ScreenToOutputPixel(rPosPixel)));
+ IMapObject* pIMapObj = SvxIMapInfo::GetHitIMapObject(pObj, aPos);
+
+ if (!rVEvt.mpURLField && !pIMapObj)
+ return false;
+
+ OUString aURL;
+ if (rVEvt.mpURLField)
+ aURL = INetURLObject::decode(rVEvt.mpURLField->GetURL(),
+ INetURLObject::DecodeMechanism::WithCharset);
+ else if (pIMapObj)
+ {
+ aURL = pIMapObj->GetAltText() +
+ " (" +
+ INetURLObject::decode(pIMapObj->GetURL(),
+ INetURLObject::DecodeMechanism::WithCharset) +
+ ")";
+ }
+ else
+ return false;
+
+ aHelpText = SfxHelp::GetURLHelpText(aURL);
+
+ if (aHelpText.isEmpty())
+ return false;
+
+ ::tools::Rectangle aLogicPix = mpWindow->LogicToPixel(pObj->GetLogicRect());
+ ::tools::Rectangle aScreenRect(mpWindow->OutputToScreenPixel(aLogicPix.TopLeft()),
+ mpWindow->OutputToScreenPixel(aLogicPix.BottomRight()));
+
+ if (Help::IsBalloonHelpEnabled())
+ Help::ShowBalloon( static_cast<vcl::Window*>(mpWindow), rPosPixel, aScreenRect, aHelpText);
+ else if (Help::IsQuickHelpEnabled())
+ Help::ShowQuickHelp( static_cast<vcl::Window*>(mpWindow), aScreenRect, aHelpText);
+
+ return true;
+}
+
+/** is called when the current function should be aborted. <p>
+ This is used when a function gets a KEY_ESCAPE but can also
+ be called directly.
+
+ @returns true if an active function was aborted
+*/
+bool FuDraw::cancel()
+{
+ bool bReturn = false;
+
+ if ( mpView->IsAction() )
+ {
+ mpView->BrkAction();
+ bReturn = true;
+ }
+ else if ( mpView->IsTextEdit() )
+ {
+ mpView->SdrEndTextEdit();
+ bReturn = true;
+
+ SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_DEC_INDENT );
+ rBindings.Invalidate( SID_INC_INDENT );
+ rBindings.Invalidate( SID_PARASPACE_INCREASE );
+ rBindings.Invalidate( SID_PARASPACE_DECREASE );
+ }
+ else if ( mpView->AreObjectsMarked() )
+ {
+ const SdrHdlList& rHdlList = mpView->GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(pHdl)
+ {
+ const_cast<SdrHdlList&>(rHdlList).ResetFocusHdl();
+ }
+ else
+ {
+ mpView->UnmarkAll();
+ }
+
+ // Switch to FuSelect.
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(
+ SID_OBJECT_SELECT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+
+ bReturn = true;
+ }
+
+ return bReturn;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fudspord.cxx b/sd/source/ui/func/fudspord.cxx
new file mode 100644
index 000000000..f129c523c
--- /dev/null
+++ b/sd/source/ui/func/fudspord.cxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fudspord.hxx>
+
+#include <vcl/ptrstyle.hxx>
+
+#include <app.hrc>
+#include <fupoor.hxx>
+#include <ViewShell.hxx>
+#include <View.hxx>
+#include <Window.hxx>
+
+namespace sd {
+
+
+FuDisplayOrder::FuDisplayOrder( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq)
+: FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+, maPtr(PointerStyle::Arrow)
+, mpRefObj(nullptr)
+{
+}
+
+FuDisplayOrder::~FuDisplayOrder()
+{
+}
+
+void FuDisplayOrder::implClearOverlay()
+{
+ mpOverlay.reset();
+}
+
+rtl::Reference<FuPoor> FuDisplayOrder::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuDisplayOrder( pViewSh, pWin, pView, pDoc, rReq ) );
+ return xFunc;
+}
+
+bool FuDisplayOrder::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ return true;
+}
+
+bool FuDisplayOrder::MouseMove(const MouseEvent& rMEvt)
+{
+ SdrPageView* pPV;
+ Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ SdrObject* pPickObj = mpView->PickObj(aPnt, mpView->getHitTolLog(), pPV);
+ if (pPickObj)
+ {
+ if (mpRefObj != pPickObj)
+ {
+ // delete current overlay
+ implClearOverlay();
+
+ // create new one
+ mpOverlay.reset( new SdrDropMarkerOverlay(*mpView, *pPickObj) );
+
+ // remember referenced object
+ mpRefObj = pPickObj;
+ }
+ }
+ else
+ {
+ mpRefObj = nullptr;
+ implClearOverlay();
+ }
+
+ return true;
+}
+
+bool FuDisplayOrder::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ SdrPageView* pPV = nullptr;
+ Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ mpRefObj = mpView->PickObj(aPnt, mpView->getHitTolLog(), pPV);
+ if (mpRefObj)
+ {
+ if (nSlotId == SID_BEFORE_OBJ)
+ {
+ mpView->PutMarkedInFrontOfObj(mpRefObj);
+ }
+ else
+ {
+ mpView->PutMarkedBehindObj(mpRefObj);
+ }
+ }
+
+ mpViewShell->Cancel();
+
+ return true;
+}
+
+void FuDisplayOrder::Activate()
+{
+ maPtr = mpWindow->GetPointer();
+ mpWindow->SetPointer( PointerStyle::RefHand );
+}
+
+void FuDisplayOrder::Deactivate()
+{
+ mpWindow->SetPointer( maPtr );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuediglu.cxx b/sd/source/ui/func/fuediglu.cxx
new file mode 100644
index 000000000..5d9d61447
--- /dev/null
+++ b/sd/source/ui/func/fuediglu.cxx
@@ -0,0 +1,471 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuediglu.hxx>
+#include <svl/eitem.hxx>
+#include <svx/svdglue.hxx>
+#include <sfx2/request.hxx>
+
+#include <app.hrc>
+
+#include <Window.hxx>
+#include <View.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <ToolBarManager.hxx>
+
+namespace sd {
+
+
+FuEditGluePoints::FuEditGluePoints (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuDraw(pViewSh, pWin, pView, pDoc, rReq)
+ //Add Shift+UP/DOWN/LEFT/RIGHT key to move the position of insert point,
+ //and SHIFT+ENTER key to decide the position and draw the new insert point
+ ,bBeginInsertPoint(false),
+ oldPoint(0,0)
+{
+}
+
+rtl::Reference<FuPoor> FuEditGluePoints::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent )
+{
+ FuEditGluePoints* pFunc;
+ rtl::Reference<FuPoor> xFunc( pFunc = new FuEditGluePoints( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ pFunc->SetPermanent( bPermanent );
+ return xFunc;
+}
+
+void FuEditGluePoints::DoExecute( SfxRequest& rReq )
+{
+ FuDraw::DoExecute( rReq );
+ mpView->SetInsGluePointMode(false);
+ mpViewShell->GetViewShellBase().GetToolBarManager()->AddToolBar(
+ ToolBarManager::ToolBarGroup::Function,
+ ToolBarManager::msGluePointsToolBar);
+}
+
+FuEditGluePoints::~FuEditGluePoints()
+{
+ mpView->BrkAction();
+ mpView->UnmarkAllGluePoints();
+ mpView->SetInsGluePointMode(false);
+}
+
+bool FuEditGluePoints::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ mpView->SetActualWin( mpWindow->GetOutDev() );
+
+ bool bReturn = FuDraw::MouseButtonDown(rMEvt);
+
+ if (mpView->IsAction())
+ {
+ if (rMEvt.IsRight())
+ mpView->BckAction();
+
+ return true;
+ }
+
+ if (rMEvt.IsLeft())
+ {
+ bReturn = true;
+ sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+ mpWindow->CaptureMouse();
+
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+
+ if (eHit == SdrHitKind::Handle)
+ {
+ // drag handle
+ SdrHdl* pHdl = aVEvt.mpHdl;
+
+ if (mpView->IsGluePointMarked(aVEvt.mpObj, aVEvt.mnGlueId) && rMEvt.IsShift())
+ {
+ mpView->UnmarkGluePoint(aVEvt.mpObj, aVEvt.mnGlueId);
+ pHdl = nullptr;
+ }
+
+ if (pHdl)
+ {
+ // drag handle
+ mpView->BegDragObj(aMDPos, nullptr, aVEvt.mpHdl, nDrgLog);
+ }
+ }
+ else if (eHit == SdrHitKind::MarkedObject && mpView->IsInsGluePointMode())
+ {
+ // insert gluepoints
+ mpView->BegInsGluePoint(aMDPos);
+ }
+ else if (eHit == SdrHitKind::MarkedObject && rMEvt.IsMod1())
+ {
+ // select gluepoints
+ if (!rMEvt.IsShift())
+ mpView->UnmarkAllGluePoints();
+
+ mpView->BegMarkGluePoints(aMDPos);
+ }
+ else if (eHit == SdrHitKind::MarkedObject && !rMEvt.IsShift() && !rMEvt.IsMod2())
+ {
+ // move object
+ mpView->BegDragObj(aMDPos, nullptr, nullptr, nDrgLog);
+ }
+ else if (eHit == SdrHitKind::Gluepoint)
+ {
+ // select gluepoints
+ if (!rMEvt.IsShift())
+ mpView->UnmarkAllGluePoints();
+
+ mpView->MarkGluePoint(aVEvt.mpObj, aVEvt.mnGlueId, false);
+ SdrHdl* pHdl = mpView->GetGluePointHdl(aVEvt.mpObj, aVEvt.mnGlueId);
+
+ if (pHdl)
+ {
+ mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
+ }
+ }
+ else
+ {
+ // select or drag object
+ if (!rMEvt.IsShift() && !rMEvt.IsMod2() && eHit == SdrHitKind::UnmarkedObject)
+ {
+ mpView->UnmarkAllObj();
+ }
+
+ bool bMarked = false;
+
+ if (!rMEvt.IsMod1())
+ {
+ if (rMEvt.IsMod2())
+ {
+ bMarked = mpView->MarkNextObj(aMDPos, nHitLog, rMEvt.IsShift());
+ }
+ else
+ {
+ bMarked = mpView->MarkObj(aMDPos, nHitLog, rMEvt.IsShift());
+ }
+ }
+
+ if (bMarked &&
+ (!rMEvt.IsShift() || eHit == SdrHitKind::MarkedObject))
+ {
+ // move object
+ mpView->BegDragObj(aMDPos, nullptr, aVEvt.mpHdl, nDrgLog);
+ }
+ else if (mpView->AreObjectsMarked())
+ {
+ // select gluepoint
+ if (!rMEvt.IsShift())
+ mpView->UnmarkAllGluePoints();
+
+ mpView->BegMarkGluePoints(aMDPos);
+ }
+ else
+ {
+ // select object
+ mpView->BegMarkObj(aMDPos);
+ }
+ }
+
+ ForcePointer(&rMEvt);
+ }
+
+ return bReturn;
+}
+
+bool FuEditGluePoints::MouseMove(const MouseEvent& rMEvt)
+{
+ mpView->SetActualWin( mpWindow->GetOutDev() );
+
+ FuDraw::MouseMove(rMEvt);
+
+ if (mpView->IsAction())
+ {
+ Point aPix(rMEvt.GetPosPixel());
+ Point aPnt( mpWindow->PixelToLogic(aPix) );
+ ForceScroll(aPix);
+ mpView->MovAction(aPnt);
+ }
+
+ ForcePointer(&rMEvt);
+
+ return true;
+}
+
+bool FuEditGluePoints::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ mpView->SetActualWin( mpWindow->GetOutDev() );
+
+ bool bReturn = false;
+
+ if (mpView->IsAction())
+ {
+ bReturn = true;
+ mpView->EndAction();
+ }
+
+ FuDraw::MouseButtonUp(rMEvt);
+
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+ Point aPos = mpWindow->PixelToLogic( rMEvt.GetPosPixel() );
+
+ if (std::abs(aMDPos.X() - aPos.X()) < nDrgLog &&
+ std::abs(aMDPos.Y() - aPos.Y()) < nDrgLog &&
+ !rMEvt.IsShift() && !rMEvt.IsMod2())
+ {
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+
+ if (eHit == SdrHitKind::NONE)
+ {
+ // click on position: deselect
+ mpView->UnmarkAllObj();
+ }
+ }
+
+ mpWindow->ReleaseMouse();
+
+ return bReturn;
+}
+
+/**
+ * Process keyboard input
+ * @returns sal_True if a KeyEvent is being processed, sal_False otherwise
+ */
+bool FuEditGluePoints::KeyInput(const KeyEvent& rKEvt)
+{
+ mpView->SetActualWin( mpWindow->GetOutDev() );
+
+ //Add Shift+UP/DOWN/LEFT/RIGHT key to move the position of insert point,
+ //and SHIFT+ENTER key to decide the position and draw the new insert point
+
+ bool bReturn = false;
+
+ switch (rKEvt.GetKeyCode().GetCode())
+ {
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ {
+ if(rKEvt.GetKeyCode().IsShift()&& mpView->IsInsGluePointMode() ){
+ ::tools::Long nX = 0;
+ ::tools::Long nY = 0;
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+ if (nCode == KEY_UP)
+ {
+ // scroll up
+ nX = 0;
+ nY =-1;
+ }
+ else if (nCode == KEY_DOWN)
+ {
+ // scroll down
+ nX = 0;
+ nY = 1;
+ }
+ else if (nCode == KEY_LEFT)
+ {
+ // scroll left
+ nX =-1;
+ nY = 0;
+ }
+ else if (nCode == KEY_RIGHT)
+ {
+ // scroll right
+ nX = 1;
+ nY = 0;
+ }
+ Point centerPoint;
+ ::tools::Rectangle rect = mpView->GetMarkedObjRect();
+ centerPoint = mpWindow->LogicToPixel(rect.Center());
+ Point aPoint = bBeginInsertPoint? oldPoint:centerPoint;
+ Point ePoint = aPoint + Point(nX,nY);
+ mpWindow->SetPointerPosPixel(ePoint);
+ //simulate mouse move action
+ MouseEvent eMevt(ePoint, 1, MouseEventModifiers::DRAGMOVE, MOUSE_LEFT, 0);
+ MouseMove(eMevt);
+ oldPoint = ePoint;
+ bBeginInsertPoint = true;
+ bReturn = true;
+ }
+ }
+ break;
+ case KEY_RETURN:
+ if(rKEvt.GetKeyCode().IsShift() && mpView->IsInsGluePointMode() )
+ {
+ if(bBeginInsertPoint)
+ {
+ mpWindow->SetPointerPosPixel(oldPoint);
+ //simulate mouse button down action
+ MouseEvent aMevt(oldPoint, 1,
+ MouseEventModifiers::SIMPLEMOVE | MouseEventModifiers::DRAGMOVE,
+ MOUSE_LEFT, KEY_SHIFT);
+ // MT IA2: Not used?
+ // sal_uInt16 ubuttons = aMevt.GetButtons();
+ // sal_uInt16 uMod = aMevt.GetModifier();
+ MouseButtonDown(aMevt);
+ mpWindow->CaptureMouse();
+ //simulate mouse button up action
+ MouseEvent rMEvt(oldPoint+Point(0,0), 1,
+ MouseEventModifiers::SIMPLEMOVE | MouseEventModifiers::ENTERWINDOW,
+ MOUSE_LEFT, KEY_SHIFT);
+ MouseButtonUp(rMEvt);
+ bReturn= true;
+ }
+ }
+ break;
+ }
+
+ if(!bReturn)
+ bReturn = FuDraw::KeyInput(rKEvt);
+
+ return bReturn;
+}
+
+//Add Shift+UP/DOWN/LEFT/RIGHT key to move the position of insert point, and
+//SHIFT+ENTER key to decide the position and draw the new insert point
+void FuEditGluePoints::ForcePointer(const MouseEvent* pMEvt)
+{
+ if(bBeginInsertPoint && pMEvt)
+ {
+ MouseEvent aMEvt(pMEvt->GetPosPixel(), pMEvt->GetClicks(),
+ pMEvt->GetMode(), pMEvt->GetButtons(), pMEvt->GetModifier() & ~KEY_SHIFT);
+ FuDraw::ForcePointer(&aMEvt);
+ }
+ else
+ {
+ FuDraw::ForcePointer(pMEvt);
+ }
+}
+
+bool FuEditGluePoints::Command(const CommandEvent& rCEvt)
+{
+ mpView->SetActualWin( mpWindow->GetOutDev() );
+ return FuPoor::Command( rCEvt );
+}
+
+void FuEditGluePoints::Activate()
+{
+ mpView->SetGluePointEditMode();
+ FuDraw::Activate();
+}
+
+void FuEditGluePoints::Deactivate()
+{
+ mpView->SetGluePointEditMode( false );
+ FuDraw::Deactivate();
+}
+
+void FuEditGluePoints::ReceiveRequest(SfxRequest& rReq)
+{
+ switch (rReq.GetSlot())
+ {
+ case SID_GLUE_INSERT_POINT:
+ {
+ mpView->SetInsGluePointMode(!mpView->IsInsGluePointMode());
+ }
+ break;
+
+ case SID_GLUE_ESCDIR_LEFT:
+ {
+ mpView->SetMarkedGluePointsEscDir( SdrEscapeDirection::LEFT,
+ !mpView->IsMarkedGluePointsEscDir( SdrEscapeDirection::LEFT ) );
+ }
+ break;
+
+ case SID_GLUE_ESCDIR_RIGHT:
+ {
+ mpView->SetMarkedGluePointsEscDir( SdrEscapeDirection::RIGHT,
+ !mpView->IsMarkedGluePointsEscDir( SdrEscapeDirection::RIGHT ) );
+ }
+ break;
+
+ case SID_GLUE_ESCDIR_TOP:
+ {
+ mpView->SetMarkedGluePointsEscDir( SdrEscapeDirection::TOP,
+ !mpView->IsMarkedGluePointsEscDir( SdrEscapeDirection::TOP ) );
+ }
+ break;
+
+ case SID_GLUE_ESCDIR_BOTTOM:
+ {
+ mpView->SetMarkedGluePointsEscDir( SdrEscapeDirection::BOTTOM,
+ !mpView->IsMarkedGluePointsEscDir( SdrEscapeDirection::BOTTOM ) );
+ }
+ break;
+
+ case SID_GLUE_PERCENT:
+ {
+ const SfxItemSet* pSet = rReq.GetArgs();
+ const SfxPoolItem& rItem = pSet->Get(SID_GLUE_PERCENT);
+ bool bPercent = static_cast<const SfxBoolItem&>(rItem).GetValue();
+ mpView->SetMarkedGluePointsPercent(bPercent);
+ }
+ break;
+
+ case SID_GLUE_HORZALIGN_CENTER:
+ {
+ mpView->SetMarkedGluePointsAlign(false, SdrAlign::HORZ_CENTER);
+ }
+ break;
+
+ case SID_GLUE_HORZALIGN_LEFT:
+ {
+ mpView->SetMarkedGluePointsAlign(false, SdrAlign::HORZ_LEFT);
+ }
+ break;
+
+ case SID_GLUE_HORZALIGN_RIGHT:
+ {
+ mpView->SetMarkedGluePointsAlign(false, SdrAlign::HORZ_RIGHT);
+ }
+ break;
+
+ case SID_GLUE_VERTALIGN_CENTER:
+ {
+ mpView->SetMarkedGluePointsAlign(true, SdrAlign::VERT_CENTER);
+ }
+ break;
+
+ case SID_GLUE_VERTALIGN_TOP:
+ {
+ mpView->SetMarkedGluePointsAlign(true, SdrAlign::VERT_TOP);
+ }
+ break;
+
+ case SID_GLUE_VERTALIGN_BOTTOM:
+ {
+ mpView->SetMarkedGluePointsAlign(true, SdrAlign::VERT_BOTTOM);
+ }
+ break;
+ }
+
+ // at the end, call base class
+ FuPoor::ReceiveRequest(rReq);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuexecuteinteraction.cxx b/sd/source/ui/func/fuexecuteinteraction.cxx
new file mode 100644
index 000000000..d1956fcf5
--- /dev/null
+++ b/sd/source/ui/func/fuexecuteinteraction.cxx
@@ -0,0 +1,237 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuexecuteinteraction.hxx>
+
+#include <app.hrc>
+#include <config_features.h>
+#include <avmedia/mediawindow.hxx>
+#include <basic/sbstar.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/urihelper.hxx>
+#include <tools/urlobj.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <DrawViewShell.hxx>
+#include <GraphicDocShell.hxx>
+#include <ViewShell.hxx>
+#include <anminfo.hxx>
+#include <drawdoc.hxx>
+#include <drawview.hxx>
+#include <pgjump.hxx>
+
+#include <com/sun/star/media/XPlayer.hpp>
+
+using namespace css;
+
+namespace sd
+{
+FuExecuteInteraction::FuExecuteInteraction(ViewShell* pViewSh, ::sd::Window* pWin,
+ ::sd::View* pView, SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuExecuteInteraction::Create(ViewShell* pViewSh, ::sd::Window* pWin,
+ ::sd::View* pView, SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+{
+ rtl::Reference<FuPoor> xFunc(new FuExecuteInteraction(pViewSh, pWin, pView, pDoc, rReq));
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuExecuteInteraction::DoExecute(SfxRequest&)
+{
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() != 1)
+ return;
+
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ if (dynamic_cast<const GraphicDocShell*>(mpDocSh) != nullptr
+ || dynamic_cast<const DrawView*>(mpView) == nullptr)
+ return;
+
+ SdAnimationInfo* pInfo = SdDrawDocument::GetAnimationInfo(pObj);
+ if (!pInfo)
+ return;
+
+ switch (pInfo->meClickAction)
+ {
+ case presentation::ClickAction_BOOKMARK:
+ {
+ // Jump to Bookmark (Page or Object)
+ SfxStringItem aItem(SID_NAVIGATOR_OBJECT, pInfo->GetBookmark());
+ mpViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_NAVIGATOR_OBJECT, SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+
+ case presentation::ClickAction_DOCUMENT:
+ {
+ OUString sBookmark(pInfo->GetBookmark());
+ // Jump to document
+ if (!sBookmark.isEmpty())
+ {
+ SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName());
+ SfxStringItem aStrItem(SID_FILE_NAME, sBookmark);
+ SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
+ SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
+ SfxBoolItem aBrowseItem(SID_BROWSE, true);
+ pFrame->GetDispatcher()->ExecuteList(
+ SID_OPENDOC, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
+ }
+ }
+ break;
+
+ case presentation::ClickAction_PREVPAGE:
+ {
+ // Jump to the previous page
+ SfxUInt16Item aItem(SID_NAVIGATOR_PAGE, PAGE_PREVIOUS);
+ mpViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_NAVIGATOR_PAGE, SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+
+ case presentation::ClickAction_NEXTPAGE:
+ {
+ // Jump to the next page
+ SfxUInt16Item aItem(SID_NAVIGATOR_PAGE, PAGE_NEXT);
+ mpViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_NAVIGATOR_PAGE, SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+
+ case presentation::ClickAction_FIRSTPAGE:
+ {
+ // Jump to the first page
+ SfxUInt16Item aItem(SID_NAVIGATOR_PAGE, PAGE_FIRST);
+ mpViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_NAVIGATOR_PAGE, SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+
+ case presentation::ClickAction_LASTPAGE:
+ {
+ // Jump to the last page
+ SfxUInt16Item aItem(SID_NAVIGATOR_PAGE, PAGE_LAST);
+ mpViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_NAVIGATOR_PAGE, SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+
+ case presentation::ClickAction_SOUND:
+ {
+#if HAVE_FEATURE_AVMEDIA
+ try
+ {
+ mxPlayer.set(avmedia::MediaWindow::createPlayer(pInfo->GetBookmark(), "" /*TODO?*/),
+ uno::UNO_SET_THROW);
+ mxPlayer->start();
+ }
+ catch (uno::Exception&)
+ {
+ }
+#endif
+ }
+ break;
+
+ case presentation::ClickAction_VERB:
+ {
+ // Assign verb
+ mpView->UnmarkAll();
+ mpView->MarkObj(pObj, mpView->GetSdrPageView());
+ DrawViewShell* pDrViewSh = static_cast<DrawViewShell*>(mpViewShell);
+ pDrViewSh->DoVerb(static_cast<sal_Int16>(pInfo->mnVerb));
+ }
+ break;
+
+ case presentation::ClickAction_PROGRAM:
+ {
+ OUString aBaseURL = GetDocSh()->GetMedium()->GetBaseURL();
+ INetURLObject aURL(::URIHelper::SmartRel2Abs(
+ INetURLObject(aBaseURL), pInfo->GetBookmark(), URIHelper::GetMaybeFileHdl(), true,
+ false, INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::Unambiguous));
+
+ if (INetProtocol::File == aURL.GetProtocol())
+ {
+ SfxStringItem aUrl(SID_FILE_NAME,
+ aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
+ SfxBoolItem aBrowsing(SID_BROWSE, true);
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ pViewFrm->GetDispatcher()->ExecuteList(
+ SID_OPENDOC, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aUrl, &aBrowsing });
+ }
+ }
+ break;
+
+#if HAVE_FEATURE_SCRIPTING
+ case presentation::ClickAction_MACRO:
+ {
+ // Execute macro
+ OUString aMacro = pInfo->GetBookmark();
+
+ if (SfxApplication::IsXScriptURL(aMacro))
+ {
+ uno::Any aRet;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aParams;
+ uno::Sequence<uno::Any> aOutArgs;
+
+ mpDocSh->CallXScript(aMacro, aParams, aRet, aOutArgsIndex, aOutArgs);
+ }
+ else
+ {
+ // aMacro has got following format:
+ // "Macroname.Modulname.Libname.Documentname" or
+ // "Macroname.Modulname.Libname.Applicationname"
+ sal_Int32 nIdx{ 0 };
+ const std::u16string_view aMacroName = o3tl::getToken(aMacro, 0, '.', nIdx);
+ const std::u16string_view aModulName = o3tl::getToken(aMacro, 0, '.', nIdx);
+
+ // Currently the "Call" method only resolves modulename+macroname
+ mpDocSh->GetBasic()->Call(OUString::Concat(aModulName) + "." + aMacroName);
+ }
+ }
+ break;
+#endif
+
+ default:
+ break;
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuexpand.cxx b/sd/source/ui/func/fuexpand.cxx
new file mode 100644
index 000000000..822174ed9
--- /dev/null
+++ b/sd/source/ui/func/fuexpand.cxx
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuexpand.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/svdundo.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/svdetc.hxx>
+#include <xmloff/autolayout.hxx>
+#include <sal/log.hxx>
+
+#include <app.hrc>
+#include <strings.hrc>
+#include <pres.hxx>
+#include <View.hxx>
+#include <sdpage.hxx>
+#include <Outliner.hxx>
+#include <drawdoc.hxx>
+#include <ViewShell.hxx>
+#include <sdresid.hxx>
+#include <sdmod.hxx>
+#include <sfx2/dispatch.hxx>
+#include <editeng/eeitem.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+
+FuExpandPage::FuExpandPage (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuExpandPage::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuExpandPage( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuExpandPage::DoExecute( SfxRequest& )
+{
+ if ( mpView && mpView->IsTextEdit() )
+ mpView->SdrEndTextEdit();
+
+ // find selected page (only standard pages)
+ SdPage* pActualPage = nullptr;
+ sal_uInt16 i = 0;
+ sal_uInt16 nCount = mpDoc->GetSdPageCount(PageKind::Standard);
+
+ while (!pActualPage && i < nCount)
+ {
+ if (mpDoc->GetSdPage(i, PageKind::Standard)->IsSelected())
+ {
+ pActualPage = mpDoc->GetSdPage(i, PageKind::Standard);
+ }
+
+ i++;
+ }
+
+ if (!pActualPage)
+ return;
+
+ SdOutliner aOutliner( mpDoc, OutlinerMode::OutlineObject );
+ aOutliner.SetUpdateLayout(false);
+ aOutliner.EnableUndo(false);
+
+ if (mpDocSh)
+ aOutliner.SetRefDevice( SD_MOD()->GetVirtualRefDevice() );
+
+ aOutliner.SetDefTab( mpDoc->GetDefaultTabulator() );
+ aOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(mpDoc->GetStyleSheetPool()));
+
+ SdrLayerIDSet aVisibleLayers = pActualPage->TRG_GetMasterPageVisibleLayers();
+ sal_uInt16 nActualPageNum = pActualPage->GetPageNum();
+ SdPage* pActualNotesPage = static_cast<SdPage*>(mpDoc->GetPage(nActualPageNum + 1));
+ SdrTextObj* pActualOutline = static_cast<SdrTextObj*>(pActualPage->GetPresObj(PresObjKind::Outline));
+
+ if (pActualOutline)
+ {
+ const bool bUndo = mpView->IsUndoEnabled();
+
+ if( bUndo )
+ mpView->BegUndo(SdResId(STR_UNDO_EXPAND_PAGE));
+
+ // set current structuring-object into outliner
+ OutlinerParaObject* pParaObj = pActualOutline->GetOutlinerParaObject();
+ aOutliner.SetText(*pParaObj);
+
+ // remove hard paragraph- and character attributes
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aEmptyEEAttr(mpDoc->GetPool());
+ sal_Int32 nParaCount1 = aOutliner.GetParagraphCount();
+
+ for (sal_Int32 nPara = 0; nPara < nParaCount1; nPara++)
+ {
+ aOutliner.RemoveCharAttribs(nPara);
+ aOutliner.SetParaAttribs(nPara, aEmptyEEAttr);
+ }
+
+ sal_uInt16 nPos = 2;
+ Paragraph* pPara = aOutliner.GetParagraph( 0 );
+
+ while (pPara)
+ {
+ sal_Int32 nParaPos = aOutliner.GetAbsPos( pPara );
+ sal_Int16 nDepth = aOutliner.GetDepth( nParaPos );
+ if ( nDepth == 0 )
+ {
+ // page with title & structuring!
+ rtl::Reference<SdPage> pPage = mpDoc->AllocSdPage(false);
+ pPage->SetSize(pActualPage->GetSize() );
+ pPage->SetBorder(pActualPage->GetLeftBorder(),
+ pActualPage->GetUpperBorder(),
+ pActualPage->GetRightBorder(),
+ pActualPage->GetLowerBorder() );
+ pPage->SetName(OUString());
+
+ // insert page after current page
+ mpDoc->InsertPage(pPage.get(), nActualPageNum + nPos);
+ nPos++;
+
+ if( bUndo )
+ mpView->AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoNewPage(*pPage));
+
+ // use MasterPage of the current page
+ pPage->TRG_SetMasterPage(pActualPage->TRG_GetMasterPage());
+ pPage->SetLayoutName(pActualPage->GetLayoutName());
+ pPage->SetAutoLayout(AUTOLAYOUT_TITLE_CONTENT, true);
+ pPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+
+ // notes-page
+ rtl::Reference<SdPage> pNotesPage = mpDoc->AllocSdPage(false);
+ pNotesPage->SetSize(pActualNotesPage->GetSize());
+ pNotesPage->SetBorder(pActualNotesPage->GetLeftBorder(),
+ pActualNotesPage->GetUpperBorder(),
+ pActualNotesPage->GetRightBorder(),
+ pActualNotesPage->GetLowerBorder() );
+ pNotesPage->SetPageKind(PageKind::Notes);
+ pNotesPage->SetName(OUString());
+
+ // insert page after current page
+ mpDoc->InsertPage(pNotesPage.get(), nActualPageNum + nPos);
+ nPos++;
+
+ if( bUndo )
+ mpView->AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoNewPage(*pNotesPage));
+
+ // use MasterPage of the current page
+ pNotesPage->TRG_SetMasterPage(pActualNotesPage->TRG_GetMasterPage());
+ pNotesPage->SetLayoutName(pActualNotesPage->GetLayoutName());
+ pNotesPage->SetAutoLayout(pActualNotesPage->GetAutoLayout(), true);
+ pNotesPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+
+ // create title text objects
+ SdrTextObj* pTextObj = static_cast<SdrTextObj*>(pPage->GetPresObj(PresObjKind::Title));
+ SAL_WARN_IF(!pTextObj, "sd.core", "worrying lack of PresObjKind::Title object");
+ if (!pTextObj)
+ continue;
+
+ std::optional<OutlinerParaObject> pOutlinerParaObject = aOutliner.CreateParaObject( nParaPos, 1);
+ pOutlinerParaObject->SetOutlinerMode(OutlinerMode::TitleObject);
+
+ if( pOutlinerParaObject->GetDepth(0) != -1 )
+ {
+ std::unique_ptr<SdrOutliner> pTempOutl = SdrMakeOutliner(OutlinerMode::TitleObject, *mpDoc);
+
+ pTempOutl->SetText( *pOutlinerParaObject );
+
+ pOutlinerParaObject.reset();
+
+ pTempOutl->SetDepth( pTempOutl->GetParagraph( 0 ), -1 );
+
+ pOutlinerParaObject = pTempOutl->CreateParaObject();
+ }
+
+ pTextObj->SetOutlinerParaObject(std::move(pOutlinerParaObject));
+
+ pTextObj->SetEmptyPresObj(false);
+
+ SfxStyleSheet* pSheet = pPage->GetStyleSheetForPresObj(PresObjKind::Title);
+ pTextObj->NbcSetStyleSheet(pSheet, false);
+
+ SdrTextObj* pOutlineObj = nullptr;
+ sal_Int32 nChildCount = aOutliner.GetChildCount(pPara);
+ if (nChildCount > 0)
+ pOutlineObj = static_cast<SdrTextObj*>( pPage->GetPresObj(PresObjKind::Outline) );
+ if (pOutlineObj)
+ {
+ // create structuring text objects
+ std::optional<OutlinerParaObject> pOPO = aOutliner.CreateParaObject(++nParaPos, nChildCount);
+
+ std::unique_ptr<SdrOutliner> pTempOutl = SdrMakeOutliner(OutlinerMode::OutlineObject, *mpDoc);
+ pTempOutl->SetText( *pOPO );
+
+ sal_Int32 nParaCount2 = pTempOutl->GetParagraphCount();
+ sal_Int32 nPara;
+ for( nPara = 0; nPara < nParaCount2; nPara++ )
+ {
+ pTempOutl->SetDepth (
+ pTempOutl->GetParagraph( nPara ),
+ pTempOutl->GetDepth( nPara ) - 1);
+ }
+
+ pOPO = pTempOutl->CreateParaObject();
+ pTempOutl.reset();
+
+ pOutlineObj->SetOutlinerParaObject( std::move(pOPO) );
+ pOutlineObj->SetEmptyPresObj(false);
+
+ // remove hard attributes (Flag to sal_True)
+ SfxItemSet aAttr(mpDoc->GetPool());
+ aAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ aAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ pOutlineObj->SetMergedItemSet(aAttr);
+ }
+ }
+
+ pPara = aOutliner.GetParagraph( ++nParaPos );
+ }
+
+ if( bUndo )
+ mpView->EndUndo();
+ }
+
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_DELETE_PAGE, SfxCallMode::SYNCHRON | SfxCallMode::RECORD);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuformatpaintbrush.cxx b/sd/source/ui/func/fuformatpaintbrush.cxx
new file mode 100644
index 000000000..40bde764f
--- /dev/null
+++ b/sd/source/ui/func/fuformatpaintbrush.cxx
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/request.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/svdotable.hxx>
+#include <svx/svdundo.hxx>
+#include <editeng/outliner.hxx>
+#include <vcl/ptrstyle.hxx>
+
+#include <fuformatpaintbrush.hxx>
+#include <drawview.hxx>
+#include <DrawViewShell.hxx>
+#include <FrameView.hxx>
+#include <drawdoc.hxx>
+#include <ViewShellBase.hxx>
+
+#include <Window.hxx>
+
+namespace sd {
+
+
+FuFormatPaintBrush::FuFormatPaintBrush( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+: FuText(pViewSh, pWin, pView, pDoc, rReq)
+, mbPermanent( false )
+, mbOldIsQuickTextEditMode( true )
+{
+}
+
+rtl::Reference<FuPoor> FuFormatPaintBrush::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuFormatPaintBrush( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute( rReq );
+ return xFunc;
+}
+
+void FuFormatPaintBrush::DoExecute( SfxRequest& rReq )
+{
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ if( pArgs && pArgs->Count() >= 1 )
+ {
+ mbPermanent = pArgs->Get(SID_FORMATPAINTBRUSH).GetValue();
+ }
+
+ if( mpView )
+ {
+ mpView->TakeFormatPaintBrush( mxItemSet );
+ }
+}
+
+void FuFormatPaintBrush::implcancel()
+{
+ if( mpViewShell && mpViewShell->GetViewFrame() )
+ {
+ SfxViewFrame* pViewFrame = mpViewShell->GetViewFrame();
+ pViewFrame->GetBindings().Invalidate(SID_FORMATPAINTBRUSH);
+ pViewFrame->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ }
+}
+
+static void unmarkimpl( SdrView* pView )
+{
+ pView->SdrEndTextEdit();
+ pView->UnMarkAll();
+}
+
+bool FuFormatPaintBrush::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if(mpView&&mpWindow)
+ {
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+
+ if( (eHit == SdrHitKind::TextEdit) || (eHit == SdrHitKind::TextEditObj && ( mpViewShell->GetFrameView()->IsQuickEdit() || dynamic_cast<sdr::table::SdrTableObj*>(aVEvt.mpObj) != nullptr ) ))
+ {
+ SdrPageView* pPV=nullptr;
+ sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
+ SdrObject* pPickObj = mpView->PickObj(mpWindow->PixelToLogic(rMEvt.GetPosPixel()),nHitLog, pPV, SdrSearchOptions::PICKMARKABLE);
+ if( (pPickObj != nullptr) && !pPickObj->IsEmptyPresObj() )
+ {
+ // if we text hit another shape than the one currently selected, unselect the old one now
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() > 0 )
+ {
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ if( rMarkList.GetMark(0)->GetMarkedSdrObj() != pPickObj )
+ {
+
+ // if current selected shape is not that of the hit text edit, deselect it
+ unmarkimpl( mpView );
+ }
+ }
+ else
+ {
+ // more than one shape selected, deselect all of them
+ unmarkimpl( mpView );
+ }
+ }
+ MouseEvent aMEvt( rMEvt.GetPosPixel(), rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), 0 );
+ return FuText::MouseButtonDown(aMEvt);
+ }
+
+ if (aVEvt.mpObj == nullptr)
+ aVEvt.mpObj = pPickObj;
+ }
+
+ unmarkimpl( mpView );
+
+ if (aVEvt.mpObj)
+ {
+ sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
+ mpView->MarkObj(mpWindow->PixelToLogic( rMEvt.GetPosPixel() ), nHitLog, false/*bToggle*/);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool FuFormatPaintBrush::MouseMove(const MouseEvent& rMEvt)
+{
+ bool bReturn = false;
+ if( mpWindow && mpView )
+ {
+ if ( mpView->IsTextEdit() )
+ {
+ bReturn = FuText::MouseMove( rMEvt );
+ mpWindow->SetPointer(PointerStyle::Fill);
+ }
+ else
+ {
+ sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
+ SdrPageView* pPV=nullptr;
+ SdrObject* pObj = mpView->PickObj(mpWindow->PixelToLogic( rMEvt.GetPosPixel() ),nHitLog, pPV, SdrSearchOptions::PICKMARKABLE);
+ if (pObj && HasContentForThisType(pObj->GetObjInventor(),pObj->GetObjIdentifier()) )
+ mpWindow->SetPointer(PointerStyle::Fill);
+ else
+ mpWindow->SetPointer(PointerStyle::Arrow);
+ }
+ }
+ return bReturn;
+}
+
+bool FuFormatPaintBrush::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if( mxItemSet && mpView && mpView->AreObjectsMarked() )
+ {
+ bool bNoCharacterFormats = false;
+ bool bNoParagraphFormats = false;
+ {
+ if( (rMEvt.GetModifier()&KEY_MOD1) && (rMEvt.GetModifier()&KEY_SHIFT) )
+ bNoCharacterFormats = true;
+ else if( rMEvt.GetModifier() & KEY_MOD1 )
+ bNoParagraphFormats = true;
+ }
+
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+ if( pOLV )
+ pOLV->MouseButtonUp(rMEvt);
+
+ Paste( bNoCharacterFormats, bNoParagraphFormats );
+ if(mpViewShell)
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate(SID_FORMATPAINTBRUSH);
+
+ if( mbPermanent )
+ return true;
+ }
+
+ implcancel();
+ return true;
+}
+
+bool FuFormatPaintBrush::KeyInput(const KeyEvent& rKEvt)
+{
+ if (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)
+ {
+ implcancel();
+ return true;
+ }
+ return FuPoor::KeyInput(rKEvt);
+}
+
+void FuFormatPaintBrush::Activate()
+{
+ mbOldIsQuickTextEditMode = mpViewShell->GetFrameView()->IsQuickEdit();
+ if( !mbOldIsQuickTextEditMode )
+ {
+ mpViewShell->GetFrameView()->SetQuickEdit(true);
+ mpView->SetQuickTextEditMode(true);
+ }
+}
+
+void FuFormatPaintBrush::Deactivate()
+{
+ if( !mbOldIsQuickTextEditMode )
+ {
+ mpViewShell->GetFrameView()->SetQuickEdit(false);
+ mpView->SetQuickTextEditMode(false);
+ }
+}
+
+bool FuFormatPaintBrush::HasContentForThisType( SdrInventor nObjectInventor, SdrObjKind nObjectIdentifier ) const
+{
+ if (mxItemSet == nullptr)
+ return false;
+ if( !mpView || (!SdrObjEditView::SupportsFormatPaintbrush( nObjectInventor, nObjectIdentifier) ) )
+ return false;
+ return true;
+}
+
+void FuFormatPaintBrush::Paste( bool bNoCharacterFormats, bool bNoParagraphFormats )
+{
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ if( !(mxItemSet && ( rMarkList.GetMarkCount() == 1 )) )
+ return;
+
+ SdrObject* pObj( nullptr );
+ bool bUndo = mpDoc->IsUndoEnabled();
+
+ if( bUndo && !mpView->GetTextEditOutlinerView() )
+ pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ // n685123: ApplyFormatPaintBrush itself would store undo information
+ // except in a few cases (?)
+ if( pObj )
+ {
+ OUString sLabel( mpViewShell->GetViewShellBase().RetrieveLabelFromCommand(".uno:FormatPaintbrush" ) );
+ mpDoc->BegUndo( sLabel );
+ if (dynamic_cast< sdr::table::SdrTableObj* >( pObj ) == nullptr)
+ mpDoc->AddUndo( mpDoc->GetSdrUndoFactory().CreateUndoAttrObject( *pObj, false, true ) );
+ }
+
+ mpView->ApplyFormatPaintBrush( *mxItemSet, bNoCharacterFormats, bNoParagraphFormats );
+
+ if( pObj )
+ {
+ mpDoc->EndUndo();
+ }
+}
+
+/* static */ void FuFormatPaintBrush::GetMenuState( DrawViewShell const & rDrawViewShell, SfxItemSet &rSet )
+{
+ const SdrMarkList& rMarkList = rDrawViewShell.GetDrawView()->GetMarkedObjectList();
+
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if( pObj && SdrObjEditView::SupportsFormatPaintbrush(pObj->GetObjInventor(),pObj->GetObjIdentifier()) )
+ return;
+ }
+ rSet.DisableItem( SID_FORMATPAINTBRUSH );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuhhconv.cxx b/sd/source/ui/func/fuhhconv.cxx
new file mode 100644
index 000000000..a312439bb
--- /dev/null
+++ b/sd/source/ui/func/fuhhconv.cxx
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/i18n/TextConversionOption.hpp>
+
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/bootstrap.hxx>
+#include <svl/style.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/fontitem.hxx>
+
+#include <fuhhconv.hxx>
+#include <drawdoc.hxx>
+#include <Outliner.hxx>
+#include <DrawViewShell.hxx>
+#include <OutlineViewShell.hxx>
+#include <Window.hxx>
+#include <ViewShellBase.hxx>
+
+#include <sdresid.hxx>
+#include <strings.hrc>
+
+class SfxRequest;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+
+FuHangulHanjaConversion::FuHangulHanjaConversion (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDocument,
+ SfxRequest& rReq )
+ : FuPoor(pViewSh, pWin, pView, pDocument, rReq),
+ pSdOutliner(nullptr),
+ bOwnOutliner(false)
+{
+ if ( dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr )
+ {
+ bOwnOutliner = true;
+ pSdOutliner = new SdOutliner( mpDoc, OutlinerMode::TextObject );
+ }
+ else if ( dynamic_cast< const OutlineViewShell *>( mpViewShell ) != nullptr )
+ {
+ bOwnOutliner = false;
+ pSdOutliner = mpDoc->GetOutliner();
+ }
+
+ if (pSdOutliner)
+ pSdOutliner->PrepareSpelling();
+}
+
+FuHangulHanjaConversion::~FuHangulHanjaConversion()
+{
+ if (pSdOutliner)
+ pSdOutliner->EndConversion();
+
+ if (bOwnOutliner)
+ delete pSdOutliner;
+}
+
+rtl::Reference<FuPoor> FuHangulHanjaConversion::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuHangulHanjaConversion( pViewSh, pWin, pView, pDoc, rReq ) );
+ return xFunc;
+}
+
+/**
+ * Search and replace
+ */
+void FuHangulHanjaConversion::StartConversion( LanguageType nSourceLanguage, LanguageType nTargetLanguage,
+ const vcl::Font *pTargetFont, sal_Int32 nOptions, bool bIsInteractive )
+{
+
+ mpView->BegUndo(SdResId(STR_UNDO_HANGULHANJACONVERSION));
+
+ ViewShellBase* pBase = dynamic_cast<ViewShellBase*>( SfxViewShell::Current() );
+ if (pBase != nullptr)
+ mpViewShell = pBase->GetMainViewShell().get();
+
+ if( mpViewShell )
+ {
+ if ( pSdOutliner && dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr && !bOwnOutliner )
+ {
+ pSdOutliner->EndConversion();
+
+ bOwnOutliner = true;
+ pSdOutliner = new SdOutliner( mpDoc, OutlinerMode::TextObject );
+ pSdOutliner->BeginConversion();
+ }
+ else if ( pSdOutliner && dynamic_cast< const OutlineViewShell *>( mpViewShell ) != nullptr && bOwnOutliner )
+ {
+ pSdOutliner->EndConversion();
+ delete pSdOutliner;
+
+ bOwnOutliner = false;
+ pSdOutliner = mpDoc->GetOutliner();
+ pSdOutliner->BeginConversion();
+ }
+
+ if (pSdOutliner)
+ pSdOutliner->StartConversion(nSourceLanguage, nTargetLanguage, pTargetFont, nOptions, bIsInteractive );
+ }
+
+ // Due to changing between edit mode, notes mode, and handout mode the
+ // view has most likely changed. Get the new one.
+ mpViewShell = pBase ? pBase->GetMainViewShell().get() : nullptr;
+ if (mpViewShell != nullptr)
+ {
+ mpView = mpViewShell->GetView();
+ mpWindow = mpViewShell->GetActiveWindow();
+ }
+ else
+ {
+ mpView = nullptr;
+ mpWindow = nullptr;
+ }
+
+ if (mpView != nullptr)
+ mpView->EndUndo();
+}
+
+void FuHangulHanjaConversion::ConvertStyles( LanguageType nTargetLanguage, const vcl::Font *pTargetFont )
+{
+ if( !mpDoc )
+ return;
+
+ SfxStyleSheetBasePool* pStyleSheetPool = mpDoc->GetStyleSheetPool();
+ if( !pStyleSheetPool )
+ return;
+
+ SfxStyleSheetBase* pStyle = pStyleSheetPool->First(SfxStyleFamily::All);
+ while( pStyle )
+ {
+ SfxItemSet& rSet = pStyle->GetItemSet();
+
+ const bool bHasParent = !pStyle->GetParent().isEmpty();
+
+ if( !bHasParent || rSet.GetItemState( EE_CHAR_LANGUAGE_CJK, false ) == SfxItemState::SET )
+ rSet.Put( SvxLanguageItem( nTargetLanguage, EE_CHAR_LANGUAGE_CJK ) );
+
+ if( pTargetFont &&
+ ( !bHasParent || rSet.GetItemState( EE_CHAR_FONTINFO_CJK, false ) == SfxItemState::SET ) )
+ {
+ // set new font attribute
+ SvxFontItem aFontItem( rSet.Get( EE_CHAR_FONTINFO_CJK ) );
+ aFontItem.SetFamilyName( pTargetFont->GetFamilyName());
+ aFontItem.SetFamily( pTargetFont->GetFamilyType());
+ aFontItem.SetStyleName( pTargetFont->GetStyleName());
+ aFontItem.SetPitch( pTargetFont->GetPitch());
+ aFontItem.SetCharSet( pTargetFont->GetCharSet());
+ rSet.Put( aFontItem );
+ }
+
+ pStyle = pStyleSheetPool->Next();
+ }
+
+ mpDoc->SetLanguage( nTargetLanguage, EE_CHAR_LANGUAGE_CJK );
+}
+
+void FuHangulHanjaConversion::StartChineseConversion()
+{
+ //open ChineseTranslationDialog
+ Reference< XComponentContext > xContext(
+ ::cppu::defaultBootstrap_InitialComponentContext() ); //@todo get context from calc if that has one
+ if(!xContext.is())
+ return;
+
+ Reference< lang::XMultiComponentFactory > xMCF( xContext->getServiceManager() );
+ if(!xMCF.is())
+ return;
+
+ Reference< ui::dialogs::XExecutableDialog > xDialog(
+ xMCF->createInstanceWithContext("com.sun.star.linguistic2.ChineseTranslationDialog"
+ , xContext), UNO_QUERY);
+ Reference< lang::XInitialization > xInit( xDialog, UNO_QUERY );
+ if( xInit.is() )
+ {
+ // initialize dialog
+ Reference< awt::XWindow > xDialogParentWindow;
+ Sequence<Any> aSeq(comphelper::InitAnyPropertySequence(
+ {
+ {"ParentWindow", uno::Any(xDialogParentWindow)}
+ }));
+ xInit->initialize( aSeq );
+
+ //execute dialog
+ sal_Int16 nDialogRet = xDialog->execute();
+ if( RET_OK == nDialogRet )
+ {
+ //get some parameters from the dialog
+ bool bToSimplified = true;
+ bool bUseVariants = true;
+ bool bCommonTerms = true;
+ Reference< beans::XPropertySet > xProp( xDialog, UNO_QUERY );
+ if( xProp.is() )
+ {
+ try
+ {
+ xProp->getPropertyValue( "IsDirectionToSimplified" ) >>= bToSimplified;
+ xProp->getPropertyValue( "IsUseCharacterVariants" ) >>= bUseVariants;
+ xProp->getPropertyValue( "IsTranslateCommonTerms" ) >>= bCommonTerms;
+ }
+ catch( Exception& )
+ {
+ }
+ }
+
+ //execute translation
+ LanguageType nSourceLang = bToSimplified ? LANGUAGE_CHINESE_TRADITIONAL : LANGUAGE_CHINESE_SIMPLIFIED;
+ LanguageType nTargetLang = bToSimplified ? LANGUAGE_CHINESE_SIMPLIFIED : LANGUAGE_CHINESE_TRADITIONAL;
+ sal_Int32 nOptions = bUseVariants ? i18n::TextConversionOption::USE_CHARACTER_VARIANTS : 0;
+ if( !bCommonTerms )
+ nOptions = nOptions | i18n::TextConversionOption::CHARACTER_BY_CHARACTER;
+
+ vcl::Font aTargetFont = OutputDevice::GetDefaultFont(
+ DefaultFontType::CJK_PRESENTATION,
+ nTargetLang, GetDefaultFontFlags::OnlyOne );
+
+ StartConversion( nSourceLang, nTargetLang, &aTargetFont, nOptions, false );
+ ConvertStyles( nTargetLang, &aTargetFont );
+ }
+ }
+ Reference< lang::XComponent > xComponent( xDialog, UNO_QUERY );
+ if( xComponent.is() )
+ xComponent->dispose();
+}
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuinsert.cxx b/sd/source/ui/func/fuinsert.cxx
new file mode 100644
index 000000000..919814d56
--- /dev/null
+++ b/sd/source/ui/func/fuinsert.cxx
@@ -0,0 +1,767 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <fuinsert.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <editeng/sizeitem.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <svx/svxdlg.hxx>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+
+#include <svl/stritem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/msgpool.hxx>
+#include <sfx2/msg.hxx>
+#include <svtools/insdlg.hxx>
+#include <sfx2/request.hxx>
+#include <svl/globalnameitem.hxx>
+#include <svtools/embedhlp.hxx>
+#include <svx/linkwarn.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <comphelper/classids.hxx>
+#include <svtools/sfxecode.hxx>
+#include <vcl/transfer.hxx>
+#include <svl/urlbmk.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <sot/formats.hxx>
+#include <svx/svdpagv.hxx>
+#include <sfx2/opengrf.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/charthelper.hxx>
+#include <svx/svxids.hrc>
+
+#include <sdresid.hxx>
+#include <View.hxx>
+#include <sdmod.hxx>
+#include <Window.hxx>
+#include <DrawViewShell.hxx>
+#include <DrawDocShell.hxx>
+#include <GraphicDocShell.hxx>
+#include <strings.hrc>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <sdgrffilter.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/errinf.hxx>
+#include <vcl/graphicfilter.hxx>
+
+#include <vcl/GraphicNativeTransform.hxx>
+#include <vcl/GraphicNativeMetadata.hxx>
+
+#include <comphelper/lok.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+
+FuInsertGraphic::FuInsertGraphic (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq,
+ bool replaceExistingImage)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq),
+ mbReplaceExistingImage(replaceExistingImage)
+{
+}
+
+rtl::Reference<FuPoor> FuInsertGraphic::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView,
+ SdDrawDocument* pDoc, SfxRequest& rReq, bool replaceExistingImage )
+{
+ rtl::Reference<FuPoor> xFunc( new FuInsertGraphic( pViewSh, pWin, pView, pDoc, rReq, replaceExistingImage ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuInsertGraphic::DoExecute( SfxRequest& rReq )
+{
+ OUString aFileName;
+ Graphic aGraphic;
+
+ bool bAsLink = false;
+ ErrCode nError = ERRCODE_GRFILTER_OPENERROR;
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ const SfxPoolItem* pItem;
+
+ if ( pArgs &&
+ pArgs->GetItemState( SID_INSERT_GRAPHIC, true, &pItem ) == SfxItemState::SET )
+ {
+ aFileName = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ OUString aFilterName;
+ if ( const SfxStringItem* pFilterItem = pArgs->GetItemIfSet( FN_PARAM_FILTER ) )
+ aFilterName = pFilterItem->GetValue();
+
+ if ( pArgs->GetItemState( FN_PARAM_1, true, &pItem ) == SfxItemState::SET )
+ bAsLink = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ nError = GraphicFilter::LoadGraphic( aFileName, aFilterName, aGraphic, &GraphicFilter::GetGraphicFilter() );
+ }
+ else
+ {
+ SvxOpenGraphicDialog aDlg(SdResId(STR_INSERTGRAPHIC), mpWindow ? mpWindow->GetFrameWeld() : nullptr);
+
+ if( aDlg.Execute() != ERRCODE_NONE )
+ return; // cancel dialog
+
+ nError = aDlg.GetGraphic(aGraphic);
+ bAsLink = aDlg.IsAsLink();
+ aFileName = aDlg.GetPath();
+ }
+
+ if( nError == ERRCODE_NONE )
+ {
+ GraphicNativeMetadata aMetadata;
+ if ( aMetadata.read(aGraphic) )
+ {
+ const Degree10 aRotation = aMetadata.getRotation();
+ if (aRotation)
+ {
+ GraphicNativeTransform aTransform( aGraphic );
+ aTransform.rotate( aRotation );
+ }
+ }
+ if( dynamic_cast< DrawViewShell *>( mpViewShell ) )
+ {
+ sal_Int8 nAction = DND_ACTION_COPY;
+ SdrObject* pPickObj = nullptr;
+ if (mbReplaceExistingImage)
+ pPickObj = mpView->GetSelectedSingleObject( mpView->GetPage() );
+ if (pPickObj)
+ nAction = DND_ACTION_LINK;
+ else
+ {
+ pPickObj = mpView->GetEmptyPresentationObject( PresObjKind::Graphic );
+ if (pPickObj)
+ nAction = DND_ACTION_LINK;
+ }
+
+ Point aPos = mpWindow->GetVisibleCenter();
+ SdrGrafObj* pGrafObj = mpView->InsertGraphic(aGraphic, nAction, aPos, pPickObj, nullptr);
+
+ if(pGrafObj && bAsLink )
+ {
+ // really store as link only?
+ if( officecfg::Office::Common::Misc::ShowLinkWarningDialog::get() )
+ {
+ SvxLinkWarningDialog aWarnDlg(mpWindow->GetFrameWeld(), aFileName);
+ if (aWarnDlg.run() != RET_OK)
+ return; // don't store as link
+ }
+
+ // store as link
+ pGrafObj->SetGraphicLink(aFileName);
+ }
+ }
+ }
+ else
+ {
+ SdGRFFilter::HandleGraphicFilterError( nError, GraphicFilter::GetGraphicFilter().GetLastError() );
+ }
+}
+
+FuInsertClipboard::FuInsertClipboard (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuInsertClipboard::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuInsertClipboard( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuInsertClipboard::DoExecute( SfxRequest& )
+{
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( mpWindow ) );
+ SotClipboardFormatId nFormatId;
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractPasteDialog> pDlg(pFact->CreatePasteDialog(mpViewShell->GetFrameWeld()));
+ pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, OUString() );
+ pDlg->Insert( SotClipboardFormatId::LINK_SOURCE, OUString() );
+ pDlg->Insert( SotClipboardFormatId::DRAWING, OUString() );
+ pDlg->Insert( SotClipboardFormatId::SVXB, OUString() );
+ pDlg->Insert( SotClipboardFormatId::GDIMETAFILE, OUString() );
+ pDlg->Insert( SotClipboardFormatId::BITMAP, OUString() );
+ pDlg->Insert( SotClipboardFormatId::NETSCAPE_BOOKMARK, OUString() );
+ pDlg->Insert( SotClipboardFormatId::STRING, OUString() );
+ pDlg->Insert( SotClipboardFormatId::HTML, OUString() );
+ pDlg->Insert( SotClipboardFormatId::RTF, OUString() );
+ pDlg->Insert( SotClipboardFormatId::RICHTEXT, OUString() );
+ pDlg->Insert( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT, OUString() );
+
+ //TODO/MBA: testing
+ nFormatId = pDlg->GetFormat( aDataHelper );
+ if( nFormatId == SotClipboardFormatId::NONE || !aDataHelper.GetTransferable().is() )
+ return;
+
+ sal_Int8 nAction = DND_ACTION_COPY;
+ DrawViewShell* pDrViewSh = nullptr;
+
+ if (!mpView->InsertData( aDataHelper,
+ mpWindow->PixelToLogic( ::tools::Rectangle( Point(), mpWindow->GetOutputSizePixel() ).Center() ),
+ nAction, false, nFormatId ))
+ {
+ pDrViewSh = dynamic_cast<DrawViewShell*>(mpViewShell);
+ }
+
+ if (!pDrViewSh)
+ return;
+
+ INetBookmark aINetBookmark( "", "" );
+
+ if( ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) ) ||
+ ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::FILEGRPDESCRIPTOR, aINetBookmark ) ) ||
+ ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::UNIFORMRESOURCELOCATOR, aINetBookmark ) ) )
+ {
+ pDrViewSh->InsertURLField( aINetBookmark.GetURL(), aINetBookmark.GetDescription(), "" );
+ }
+}
+
+FuInsertOLE::FuInsertOLE (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuInsertOLE::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuInsertOLE( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuInsertOLE::DoExecute( SfxRequest& rReq )
+{
+ if ( nSlotId == SID_ATTR_TABLE ||
+ nSlotId == SID_INSERT_DIAGRAM ||
+ nSlotId == SID_INSERT_MATH )
+ {
+ PresObjKind ePresObjKind = (nSlotId == SID_INSERT_DIAGRAM) ? PresObjKind::Chart : PresObjKind::Object;
+
+ SdrObject* pPickObj = mpView->GetEmptyPresentationObject( ePresObjKind );
+
+ // insert diagram or Calc table
+ OUString aObjName;
+ SvGlobalName aName;
+ if (nSlotId == SID_INSERT_DIAGRAM)
+ aName = SvGlobalName( SO3_SCH_CLASSID);
+ else if (nSlotId == SID_ATTR_TABLE)
+ aName = SvGlobalName(SO3_SC_CLASSID);
+ else if (nSlotId == SID_INSERT_MATH)
+ aName = SvGlobalName(SO3_SM_CLASSID);
+
+ uno::Reference < embed::XEmbeddedObject > xObj = mpViewShell->GetViewFrame()->GetObjectShell()->
+ GetEmbeddedObjectContainer().CreateEmbeddedObject( aName.GetByteSequence(), aObjName );
+ if ( xObj.is() )
+ {
+ // Create default chart type.
+ uno::Reference<chart2::XChartDocument> xChartDoc(xObj->getComponent(), uno::UNO_QUERY);
+ if (xChartDoc.is())
+ xChartDoc->createDefaultChart();
+
+ sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
+
+ MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
+
+ ::tools::Rectangle aRect;
+ if( pPickObj )
+ {
+ aRect = pPickObj->GetLogicRect();
+
+ awt::Size aSz;
+ aSz.Width = aRect.GetWidth();
+ aSz.Height = aRect.GetHeight();
+ xObj->setVisualAreaSize( nAspect, aSz );
+ }
+ else
+ {
+ awt::Size aSz;
+ try
+ {
+ aSz = xObj->getVisualAreaSize( nAspect );
+ }
+ catch ( embed::NoVisualAreaSizeException& )
+ {
+ // the default size will be set later
+ }
+
+ Size aSize( aSz.Width, aSz.Height );
+
+ if (aSize.IsEmpty())
+ {
+ // rectangle with balanced edge ratio
+ aSize.setWidth( 14100 );
+ aSize.setHeight( 10000 );
+ Size aTmp = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aUnit));
+ aSz.Width = aTmp.Width();
+ aSz.Height = aTmp.Height();
+ xObj->setVisualAreaSize( nAspect, aSz );
+ }
+ else
+ {
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(aUnit), MapMode(MapUnit::Map100thMM));
+ }
+
+ Point aPos = mpWindow->GetVisibleCenter();
+ aPos.AdjustX( -(aSize.Width() / 2) );
+ aPos.AdjustY( -(aSize.Height() / 2) );
+ aRect = ::tools::Rectangle(aPos, aSize);
+ }
+
+ SdrOle2Obj* pOleObj = new SdrOle2Obj(
+ mpView->getSdrModelFromSdrView(),
+ svt::EmbeddedObjectRef( xObj, nAspect ),
+ aObjName,
+ aRect);
+ SdrPageView* pPV = mpView->GetSdrPageView();
+
+ // if we have a pick obj we need to make this new ole a pres obj replacing the current pick obj
+ if( pPickObj )
+ {
+ SdPage* pPage = static_cast< SdPage* >(pPickObj->getSdrPageFromSdrObject());
+ if(pPage && pPage->IsPresObj(pPickObj))
+ {
+ pPage->InsertPresObj( pOleObj, ePresObjKind );
+ pOleObj->SetUserCall(pPickObj->GetUserCall());
+ }
+
+ // #i123468# we need to end text edit before replacing the object. There cannot yet
+ // being text typed (else it would not be an EmptyPresObj anymore), but it may be
+ // in text edit mode
+ if (mpView->IsTextEdit())
+ {
+ mpView->SdrEndTextEdit();
+ }
+ }
+
+ bool bRet = true;
+ if( pPickObj )
+ mpView->ReplaceObjectAtView(pPickObj, *pPV, pOleObj );
+ else
+ bRet = mpView->InsertObjectAtView(pOleObj, *pPV, SdrInsertFlags::SETDEFLAYER);
+
+ if (bRet && !comphelper::LibreOfficeKit::isActive())
+ {
+ // Let the chart be activated after the inserting (unless
+ // via LibreOfficeKit)
+ if (nSlotId == SID_INSERT_DIAGRAM)
+ {
+ pOleObj->SetProgName( "StarChart");
+ }
+ else if (nSlotId == SID_ATTR_TABLE)
+ {
+ pOleObj->SetProgName( "StarCalc" );
+ }
+ else if (nSlotId == SID_INSERT_MATH)
+ {
+ pOleObj->SetProgName( "StarMath" );
+ }
+
+ pOleObj->SetLogicRect(aRect);
+ Size aTmp( OutputDevice::LogicToLogic(aRect.GetSize(), MapMode(MapUnit::Map100thMM), MapMode(aUnit)) );
+ awt::Size aVisualSize;
+ aVisualSize.Width = aTmp.Width();
+ aVisualSize.Height = aTmp.Height();
+ xObj->setVisualAreaSize( nAspect, aVisualSize );
+ mpViewShell->ActivateObject(pOleObj, embed::EmbedVerbs::MS_OLEVERB_SHOW);
+
+ if (nSlotId == SID_INSERT_DIAGRAM)
+ {
+ // note, that this call modified the chart model which
+ // results in a change notification. So call this after
+ // everything else is finished.
+ ChartHelper::AdaptDefaultsForChart( xObj );
+ }
+ }
+ }
+ else
+ {
+ ErrorHandler::HandleError(* new StringErrorInfo(ERRCODE_SFX_OLEGENERAL,
+ "" ) );
+ }
+ }
+ else
+ {
+ // insert object
+ sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
+ bool bCreateNew = false;
+ uno::Reference < embed::XEmbeddedObject > xObj;
+ uno::Reference < embed::XStorage > xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
+ SvObjectServerList aServerLst;
+ OUString aName;
+
+ OUString aIconMediaType;
+ uno::Reference< io::XInputStream > xIconMetaFile;
+
+ const SfxGlobalNameItem* pNameItem = rReq.GetArg<SfxGlobalNameItem>(SID_INSERT_OBJECT);
+ if ( nSlotId == SID_INSERT_OBJECT && pNameItem )
+ {
+ const SvGlobalName& aClassName = pNameItem->GetValue();
+ xObj = mpViewShell->GetViewFrame()->GetObjectShell()->
+ GetEmbeddedObjectContainer().CreateEmbeddedObject( aClassName.GetByteSequence(), aName );
+ }
+ else
+ {
+ switch ( nSlotId )
+ {
+ case SID_INSERT_OBJECT :
+ {
+ aServerLst.FillInsertObjects();
+ if (mpDoc->GetDocumentType() == DocumentType::Draw)
+ {
+ aServerLst.Remove( GraphicDocShell::Factory().GetClassId() );
+ }
+ else
+ {
+ aServerLst.Remove( DrawDocShell::Factory().GetClassId() );
+ }
+
+ [[fallthrough]];
+ }
+ case SID_INSERT_FLOATINGFRAME :
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractInsertObjectDialog> pDlg(
+ pFact->CreateInsertObjectDialog( mpViewShell->GetFrameWeld(), SD_MOD()->GetSlotPool()->GetSlot(nSlotId)->GetCommandString(),
+ xStorage, &aServerLst ));
+ pDlg->Execute();
+ bCreateNew = pDlg->IsCreateNew();
+ xObj = pDlg->GetObject();
+
+ xIconMetaFile = pDlg->GetIconIfIconified( &aIconMediaType );
+ if ( xIconMetaFile.is() )
+ nAspect = embed::Aspects::MSOLE_ICON;
+
+ if ( xObj.is() )
+ mpViewShell->GetObjectShell()->GetEmbeddedObjectContainer().InsertEmbeddedObject( xObj, aName );
+
+ break;
+ }
+ }
+ }
+
+ try
+ {
+ if (xObj.is())
+ {
+ bool bInsertNewObject = true;
+
+ Size aSize;
+ MapUnit aMapUnit = MapUnit::Map100thMM;
+ if ( nAspect != embed::Aspects::MSOLE_ICON )
+ {
+ awt::Size aSz;
+ try
+ {
+ aSz = xObj->getVisualAreaSize( nAspect );
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {
+ // the default size will be set later
+ }
+
+ aSize =Size( aSz.Width, aSz.Height );
+
+ aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
+ if (aSize.IsEmpty())
+ {
+ // rectangle with balanced edge ratio
+ aSize.setWidth( 14100 );
+ aSize.setHeight( 10000 );
+ Size aTmp = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aMapUnit));
+ aSz.Width = aTmp.Width();
+ aSz.Height = aTmp.Height();
+ xObj->setVisualAreaSize( nAspect, aSz );
+ }
+ else
+ {
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapUnit), MapMode(MapUnit::Map100thMM));
+ }
+ }
+
+ if ( mpView->AreObjectsMarked() )
+ {
+ // as an empty OLE object available?
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ if (pObj->GetObjInventor() == SdrInventor::Default &&
+ pObj->GetObjIdentifier() == SdrObjKind::OLE2)
+ {
+ if ( !static_cast<SdrOle2Obj*>(pObj)->GetObjRef().is() )
+ {
+ // the empty OLE object gets a new IPObj
+ bInsertNewObject = false;
+ pObj->SetEmptyPresObj(false);
+ static_cast<SdrOle2Obj*>(pObj)->SetOutlinerParaObject(std::nullopt);
+ static_cast<SdrOle2Obj*>(pObj)->SetObjRef(xObj);
+ static_cast<SdrOle2Obj*>(pObj)->SetPersistName(aName);
+ static_cast<SdrOle2Obj*>(pObj)->SetName(aName);
+ static_cast<SdrOle2Obj*>(pObj)->SetAspect(nAspect);
+ ::tools::Rectangle aRect = static_cast<SdrOle2Obj*>(pObj)->GetLogicRect();
+
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ {
+ if( xIconMetaFile.is() )
+ static_cast<SdrOle2Obj*>(pObj)->SetGraphicToObj( xIconMetaFile, aIconMediaType );
+ }
+ else
+ {
+ Size aTmp = OutputDevice::LogicToLogic(aRect.GetSize(), MapMode(MapUnit::Map100thMM), MapMode(aMapUnit));
+ awt::Size aSz( aTmp.Width(), aTmp.Height() );
+ xObj->setVisualAreaSize( nAspect, aSz );
+ }
+ }
+ }
+ }
+ }
+
+ if (bInsertNewObject)
+ {
+ // we create a new OLE object
+ SdrPageView* pPV = mpView->GetSdrPageView();
+ Size aPageSize = pPV->GetPage()->GetSize();
+
+ // get the size from the iconified object
+ ::svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ {
+ aObjRef.SetGraphicStream( xIconMetaFile, aIconMediaType );
+ MapMode aMapMode( MapUnit::Map100thMM );
+ aSize = aObjRef.GetSize( &aMapMode );
+ }
+
+ Point aPnt ((aPageSize.Width() - aSize.Width()) / 2,
+ (aPageSize.Height() - aSize.Height()) / 2);
+ ::tools::Rectangle aRect (aPnt, aSize);
+ SdrOle2Obj* pObj = new SdrOle2Obj(
+ mpView->getSdrModelFromSdrView(),
+ aObjRef,
+ aName,
+ aRect);
+
+ if( mpView->InsertObjectAtView(pObj, *pPV, SdrInsertFlags::SETDEFLAYER) )
+ {
+ // Math objects change their object size during InsertObject.
+ // New size must be set in SdrObject, or a wrong scale will be set at
+ // ActivateObject.
+
+ if ( nAspect != embed::Aspects::MSOLE_ICON )
+ {
+ try
+ {
+ awt::Size aSz = xObj->getVisualAreaSize( nAspect );
+
+ Size aNewSize = OutputDevice::LogicToLogic( Size( aSz.Width, aSz.Height ),
+ MapMode( aMapUnit ), MapMode( MapUnit::Map100thMM ) );
+ if ( aNewSize != aSize )
+ {
+ aRect.SetSize( aNewSize );
+ pObj->SetLogicRect( aRect );
+ }
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {}
+ }
+
+ if (bCreateNew)
+ {
+ pObj->SetLogicRect(aRect);
+
+ if ( nAspect != embed::Aspects::MSOLE_ICON )
+ {
+ Size aTmp = OutputDevice::LogicToLogic(aRect.GetSize(), MapMode(MapUnit::Map100thMM), MapMode(aMapUnit));
+ awt::Size aSz( aTmp.Width(), aTmp.Height() );
+ xObj->setVisualAreaSize( nAspect, aSz );
+ }
+
+ mpViewShell->ActivateObject(pObj, embed::EmbedVerbs::MS_OLEVERB_SHOW);
+ }
+
+ Size aVisSizePixel = mpWindow->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = mpWindow->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ mpViewShell->VisAreaChanged(aVisAreaWin);
+ mpDocSh->SetVisArea(aVisAreaWin);
+ }
+ }
+ }
+ }
+ catch (uno::Exception&)
+ {
+ // For some reason the object can not be inserted. For example
+ // because it is password protected and is not properly unlocked.
+ }
+ }
+}
+
+FuInsertAVMedia::FuInsertAVMedia(
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuInsertAVMedia::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuInsertAVMedia( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuInsertAVMedia::DoExecute( SfxRequest& rReq )
+{
+#if HAVE_FEATURE_AVMEDIA
+ OUString aURL;
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ bool bAPI = false;
+
+ const SvxSizeItem* pSizeItem = rReq.GetArg<SvxSizeItem>(FN_PARAM_1);
+ const SfxBoolItem* pLinkItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_2);
+ const bool bSizeUnknown = !pSizeItem;
+ Size aPrefSize;
+
+ if( pReqArgs )
+ {
+ const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>( &pReqArgs->Get( rReq.GetSlot() ) );
+
+ if( pStringItem )
+ {
+ aURL = pStringItem->GetValue();
+ bAPI = !aURL.isEmpty();
+ }
+ }
+
+ bool bLink(pLinkItem ? pLinkItem->GetValue() : true);
+ if (!(bAPI
+ || ::avmedia::MediaWindow::executeMediaURLDialog(mpWindow ? mpWindow->GetFrameWeld() : nullptr, aURL, & bLink)
+ ))
+ return;
+
+ if (!bSizeUnknown)
+ {
+ aPrefSize = pSizeItem->GetSize();
+ }
+ else
+ {
+ // If we don't have a size then try and find that out, the resulted might be deliver async, so dispatch a follow up
+ // effort to insert the video, this time with a size.
+ if( mpWindow )
+ mpWindow->EnterWait();
+
+ css::uno::Reference<css::frame::XDispatchProvider> xDispatchProvider(mpViewShell->GetViewFrame()->GetFrame().GetFrameInterface(), css::uno::UNO_QUERY);
+
+ rtl::Reference<avmedia::PlayerListener> xPlayerListener(new avmedia::PlayerListener(
+ [xDispatchProvider, aURL, bLink](const css::uno::Reference<css::media::XPlayer>& rPlayer){
+ css::awt::Size aSize = rPlayer->getPreferredPlayerWindowSize();
+ avmedia::MediaWindow::dispatchInsertAVMedia(xDispatchProvider, aSize, aURL, bLink);
+ }));
+
+ const bool bIsMediaURL = ::avmedia::MediaWindow::isMediaURL(aURL, "", true, xPlayerListener);
+
+ if( mpWindow )
+ mpWindow->LeaveWait();
+
+ if (!bIsMediaURL && !bAPI)
+ ::avmedia::MediaWindow::executeFormatErrorBox(mpWindow->GetFrameWeld());
+
+ return;
+ }
+
+ InsertMediaURL(aURL, aPrefSize, bLink);
+
+#else
+ (void)rReq;
+#endif
+}
+
+#if HAVE_FEATURE_AVMEDIA
+void FuInsertAVMedia::InsertMediaURL(const OUString& rURL, const Size& rPrefSize, bool bLink)
+{
+ if( mpWindow )
+ mpWindow->EnterWait();
+
+ Point aPos;
+ Size aSize;
+ sal_Int8 nAction = DND_ACTION_COPY;
+
+ if (rPrefSize.Width() && rPrefSize.Height())
+ {
+ if( mpWindow )
+ aSize = mpWindow->PixelToLogic(rPrefSize, MapMode(MapUnit::Map100thMM));
+ else
+ aSize = Application::GetDefaultDevice()->PixelToLogic(rPrefSize, MapMode(MapUnit::Map100thMM));
+ }
+ else
+ aSize = Size( 5000, 5000 );
+
+ if( mpWindow )
+ {
+ aPos = mpWindow->PixelToLogic( ::tools::Rectangle( aPos, mpWindow->GetOutputSizePixel() ).Center() );
+ aPos.AdjustX( -(aSize.Width() >> 1) );
+ aPos.AdjustY( -(aSize.Height() >> 1) );
+ }
+
+ mpView->InsertMediaURL(rURL, nAction, aPos, aSize, bLink);
+
+ if( mpWindow )
+ mpWindow->LeaveWait();
+}
+#endif
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuinsfil.cxx b/sd/source/ui/func/fuinsfil.cxx
new file mode 100644
index 000000000..6569514cf
--- /dev/null
+++ b/sd/source/ui/func/fuinsfil.cxx
@@ -0,0 +1,725 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuinsfil.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/progress.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editeng.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/app.hxx>
+#include <vcl/weld.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdoutl.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sot/formats.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svxids.hrc>
+#include <tools/debug.hxx>
+#include <com/sun/star/ui/dialogs/XFilterManager.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <Window.hxx>
+#include <View.hxx>
+#include <strings.hrc>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+#include <ViewShellBase.hxx>
+#include <DrawViewShell.hxx>
+#include <OutlineView.hxx>
+#include <DrawDocShell.hxx>
+#include <GraphicDocShell.hxx>
+#include <app.hrc>
+#include <Outliner.hxx>
+#include <sdabstdlg.hxx>
+#include <memory>
+
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star;
+
+typedef ::std::pair< OUString, OUString > FilterDesc;
+
+namespace
+{
+
+OUString lcl_GetExtensionsList ( ::std::vector< FilterDesc > const& rFilterDescList )
+{
+ OUStringBuffer aExtensions;
+
+ for (const auto& rFilterDesc : rFilterDescList)
+ {
+ OUString sWildcard = rFilterDesc.second;
+
+ if ( aExtensions.indexOf( sWildcard ) == -1 )
+ {
+ if ( !aExtensions.isEmpty() )
+ aExtensions.append(";");
+ aExtensions.append(sWildcard);
+ }
+
+ }
+
+ return aExtensions.makeStringAndClear();
+}
+
+void lcl_AddFilter ( ::std::vector< FilterDesc >& rFilterDescList,
+ const std::shared_ptr<const SfxFilter>& pFilter )
+{
+ if (pFilter)
+ rFilterDescList.emplace_back( pFilter->GetUIName(), pFilter->GetDefaultExtension() );
+}
+
+}
+
+namespace sd {
+
+
+FuInsertFile::FuInsertFile (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuInsertFile::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuInsertFile( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuInsertFile::DoExecute( SfxRequest& rReq )
+{
+ SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
+ ::std::vector< FilterDesc > aFilterVector;
+ ::std::vector< OUString > aOtherFilterVector;
+ const SfxItemSet* pArgs = rReq.GetArgs ();
+
+ FuInsertFile::GetSupportedFilterVector( aOtherFilterVector );
+
+ if (!pArgs)
+ {
+ sfx2::FileDialogHelper aFileDialog(
+ ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::Insert, mpWindow ? mpWindow->GetFrameWeld() : nullptr);
+ aFileDialog.SetContext(sfx2::FileDialogHelper::DrawImpressInsertFile);
+ Reference< XFilePicker > xFilePicker( aFileDialog.GetFilePicker() );
+ Reference< XFilterManager > xFilterManager( xFilePicker, UNO_QUERY );
+ OUString aOwnCont;
+ OUString aOtherCont;
+
+ aFileDialog.SetTitle( SdResId(STR_DLG_INSERT_PAGES_FROM_FILE) );
+
+ if( mpDoc->GetDocumentType() == DocumentType::Impress )
+ {
+ aOwnCont = "simpress";
+ aOtherCont = "sdraw";
+ }
+ else
+ {
+ aOtherCont = "simpress";
+ aOwnCont = "sdraw" ;
+ }
+
+ SfxFilterMatcher aMatch( aOwnCont );
+
+ if( xFilterManager.is() )
+ {
+ // Get filter for current format
+ try
+ {
+ // Get main filter
+ std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetDefaultFilterFromFactory( aOwnCont );
+ lcl_AddFilter( aFilterVector, pFilter );
+
+ // get template filter
+ if( mpDoc->GetDocumentType() == DocumentType::Impress )
+ pFilter = DrawDocShell::Factory().GetTemplateFilter();
+ else
+ pFilter = GraphicDocShell::Factory().GetTemplateFilter();
+ lcl_AddFilter( aFilterVector, pFilter );
+
+ // get cross filter
+ pFilter = SfxFilter::GetDefaultFilterFromFactory( aOtherCont );
+ lcl_AddFilter( aFilterVector, pFilter );
+
+ // get Powerpoint filter
+ pFilter = aMatch.GetFilter4Extension( ".ppt" );
+ lcl_AddFilter( aFilterVector, pFilter );
+
+ // Get other draw/impress filters
+ pFilter = aMatch.GetFilter4ClipBoardId( SotClipboardFormatId::STARIMPRESS_60, SfxFilterFlags::IMPORT, SfxFilterFlags::TEMPLATEPATH );
+ lcl_AddFilter( aFilterVector, pFilter );
+
+ pFilter = aMatch.GetFilter4ClipBoardId( SotClipboardFormatId::STARIMPRESS_60, SfxFilterFlags::TEMPLATEPATH );
+ lcl_AddFilter( aFilterVector, pFilter );
+
+ pFilter = aMatch.GetFilter4ClipBoardId( SotClipboardFormatId::STARDRAW_60, SfxFilterFlags::IMPORT, SfxFilterFlags::TEMPLATEPATH );
+ lcl_AddFilter( aFilterVector, pFilter );
+
+ pFilter = aMatch.GetFilter4ClipBoardId( SotClipboardFormatId::STARDRAW_60, SfxFilterFlags::TEMPLATEPATH );
+ lcl_AddFilter( aFilterVector, pFilter );
+
+ pFilter = aMatch.GetFilter4ClipBoardId( SotClipboardFormatId::STARDRAW, SfxFilterFlags::IMPORT, SfxFilterFlags::TEMPLATEPATH );
+ lcl_AddFilter( aFilterVector, pFilter );
+
+ pFilter = aMatch.GetFilter4ClipBoardId( SotClipboardFormatId::STARDRAW, SfxFilterFlags::TEMPLATEPATH );
+ lcl_AddFilter( aFilterVector, pFilter );
+
+ // add additional supported filters
+ for( const auto& rOtherFilter : aOtherFilterVector )
+ {
+ if( ( pFilter = rMatcher.GetFilter4Mime( rOtherFilter ) ) != nullptr )
+ lcl_AddFilter( aFilterVector, pFilter );
+ }
+
+ // set "All supported formats" as the default filter
+ OUString aAllSpec( SdResId( STR_ALL_SUPPORTED_FORMATS ) );
+ OUString aExtensions = lcl_GetExtensionsList( aFilterVector );
+ OUString aGUIName = aAllSpec + " (" + aExtensions + ")";
+
+ xFilterManager->appendFilter( aGUIName, aExtensions );
+ xFilterManager->setCurrentFilter( aAllSpec );
+
+ // append individual filters
+ for( const auto& rFilter : aFilterVector )
+ {
+ xFilterManager->appendFilter( rFilter.first, rFilter.second );
+ }
+
+ // end with "All files" as fallback
+ xFilterManager->appendFilter( SdResId( STR_ALL_FILES ), "*.*" );
+ }
+ catch (const IllegalArgumentException&)
+ {
+ }
+ }
+
+ if( aFileDialog.Execute() != ERRCODE_NONE )
+ return;
+ else
+ {
+ aFilterName = aFileDialog.GetCurrentFilter();
+ aFile = aFileDialog.GetPath();
+ }
+ }
+ else
+ {
+ const SfxStringItem* pFileName = rReq.GetArg<SfxStringItem>(ID_VAL_DUMMY0);
+ const SfxStringItem* pFilterName = rReq.GetArg<SfxStringItem>(ID_VAL_DUMMY1);
+
+ aFile = pFileName->GetValue ();
+
+ if( pFilterName )
+ aFilterName = pFilterName->GetValue ();
+ }
+
+ mpDocSh->SetWaitCursor( true );
+
+ std::unique_ptr<SfxMedium> xMedium(new SfxMedium(aFile, StreamMode::READ | StreamMode::NOCREATE));
+ std::shared_ptr<const SfxFilter> pFilter;
+
+ SfxGetpApp()->GetFilterMatcher().GuessFilter(*xMedium, pFilter);
+
+ bool bDrawMode = dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr;
+ bool bInserted = false;
+
+ if( pFilter )
+ {
+ xMedium->SetFilter( pFilter );
+ aFilterName = pFilter->GetFilterName();
+
+ if( xMedium->IsStorage() || ( xMedium->GetInStream() && SotStorage::IsStorageFile( xMedium->GetInStream() ) ) )
+ {
+ if ( pFilter->GetServiceName() == "com.sun.star.presentation.PresentationDocument" ||
+ pFilter->GetServiceName() == "com.sun.star.drawing.DrawingDocument" )
+ {
+ // Draw, Impress or PowerPoint document
+ // the ownership of the Medium is transferred
+ if( bDrawMode )
+ InsSDDinDrMode(xMedium.release());
+ else
+ InsSDDinOlMode(xMedium.release());
+
+ // ownership of pMedium has changed in this case
+ bInserted = true;
+ }
+ }
+ else
+ {
+ bool bFound = ( ::std::find( aOtherFilterVector.begin(), aOtherFilterVector.end(), pFilter->GetMimeType() ) != aOtherFilterVector.end() );
+ if( !bFound &&
+ ( aFilterName.indexOf( "Text" ) != -1 ||
+ aFilterName.indexOf( "Rich" ) != -1 ||
+ aFilterName.indexOf( "RTF" ) != -1 ||
+ aFilterName.indexOf( "HTML" ) != -1 ) )
+ {
+ bFound = true;
+ }
+
+ if( bFound )
+ {
+ if( bDrawMode )
+ InsTextOrRTFinDrMode(xMedium.get());
+ else
+ InsTextOrRTFinOlMode(xMedium.get());
+
+ bInserted = true;
+ xMedium.reset();
+ }
+ }
+ }
+
+ mpDocSh->SetWaitCursor( false );
+
+ if( !bInserted )
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(mpWindow->GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok, SdResId(STR_READ_DATA_ERROR)));
+ xErrorBox->run();
+ }
+}
+
+bool FuInsertFile::InsSDDinDrMode(SfxMedium* pMedium)
+{
+ bool bOK = false;
+
+ mpDocSh->SetWaitCursor( false );
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ weld::Window* pParent = mpViewShell ? mpViewShell->GetFrameWeld() : nullptr;
+ ScopedVclPtr<AbstractSdInsertPagesObjsDlg> pDlg( pFact->CreateSdInsertPagesObjsDlg(pParent, mpDoc, pMedium, aFile) );
+
+ sal_uInt16 nRet = pDlg->Execute();
+
+ mpDocSh->SetWaitCursor( true );
+
+ if( nRet == RET_OK )
+ {
+ /* list with page names (if NULL, then all pages)
+ First, insert pages */
+ std::vector<OUString> aBookmarkList = pDlg->GetList( 1 ); // pages
+ bool bLink = pDlg->IsLink();
+ SdPage* pPage = nullptr;
+ ::sd::View* pView = mpViewShell ? mpViewShell->GetView() : nullptr;
+
+ if (pView)
+ {
+ if( auto pOutlineView = dynamic_cast<OutlineView *>( pView ))
+ {
+ pPage = pOutlineView->GetActualPage();
+ }
+ else
+ {
+ pPage = static_cast<SdPage*>(pView->GetSdrPageView()->GetPage());
+ }
+ }
+
+ sal_uInt16 nPos = 0xFFFF;
+
+ if (pPage && !pPage->IsMasterPage())
+ {
+ if (pPage->GetPageKind() == PageKind::Standard)
+ {
+ nPos = pPage->GetPageNum() + 2;
+ }
+ else if (pPage->GetPageKind() == PageKind::Notes)
+ {
+ nPos = pPage->GetPageNum() + 1;
+ }
+ }
+
+ bool bNameOK;
+ std::vector<OUString> aExchangeList;
+ std::vector<OUString> aObjectBookmarkList = pDlg->GetList( 2 ); // objects
+
+ /* if pBookmarkList is NULL, we insert selected pages, and/or selected
+ objects or everything. */
+ if( !aBookmarkList.empty() || aObjectBookmarkList.empty() )
+ {
+ /* To ensure that all page names are unique, we check the ones we
+ want to insert and insert them into a substitution list if
+ necessary.
+ bNameOK is sal_False if the user has canceled. */
+ bNameOK = mpView->GetExchangeList( aExchangeList, aBookmarkList, 0 );
+
+ if( bNameOK )
+ bOK = mpDoc->InsertBookmarkAsPage( aBookmarkList, &aExchangeList,
+ bLink, false/*bReplace*/, nPos,
+ false, nullptr, true, true, false );
+
+ aBookmarkList.clear();
+ aExchangeList.clear();
+ }
+
+ // to ensure ... (see above)
+ bNameOK = mpView->GetExchangeList( aExchangeList, aObjectBookmarkList, 1 );
+
+ if( bNameOK )
+ bOK = mpDoc->InsertBookmarkAsObject( aObjectBookmarkList, aExchangeList,
+ nullptr, nullptr, false );
+
+ if( pDlg->IsRemoveUnnecessaryMasterPages() )
+ mpDoc->RemoveUnnecessaryMasterPages();
+ }
+
+ return bOK;
+}
+
+void FuInsertFile::InsTextOrRTFinDrMode(SfxMedium* pMedium)
+{
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSdInsertPagesObjsDlg> pDlg( pFact->CreateSdInsertPagesObjsDlg(mpViewShell->GetFrameWeld(), mpDoc, nullptr, aFile) );
+
+ mpDocSh->SetWaitCursor( false );
+
+ sal_uInt16 nRet = pDlg->Execute();
+ mpDocSh->SetWaitCursor( true );
+
+ if( nRet != RET_OK )
+ return;
+
+ // selected file format: text, RTF or HTML (default is text)
+ EETextFormat nFormat = EETextFormat::Text;
+
+ if( aFilterName.indexOf( "Rich") != -1 )
+ nFormat = EETextFormat::Rtf;
+ else if( aFilterName.indexOf( "HTML" ) != -1 )
+ nFormat = EETextFormat::Html;
+
+ /* create our own outline since:
+ - it is possible that the document outliner is actually used in the
+ structuring mode
+ - the draw outliner of the drawing engine has to draw something in
+ between
+ - the global outliner could be used in SdPage::CreatePresObj */
+ SdOutliner aOutliner( mpDoc, OutlinerMode::TextObject );
+
+ // set reference device
+ aOutliner.SetRefDevice( SD_MOD()->GetVirtualRefDevice() );
+
+ SdPage* pPage = static_cast<DrawViewShell*>(mpViewShell)->GetActualPage();
+ aLayoutName = pPage->GetLayoutName();
+ sal_Int32 nIndex = aLayoutName.indexOf(SD_LT_SEPARATOR);
+ if( nIndex != -1 )
+ aLayoutName = aLayoutName.copy(0, nIndex);
+
+ aOutliner.SetPaperSize(pPage->GetSize());
+
+ SvStream* pStream = pMedium->GetInStream();
+ assert(pStream && "No InStream!");
+ pStream->Seek( 0 );
+
+ ErrCode nErr = aOutliner.Read( *pStream, pMedium->GetBaseURL(), nFormat, mpDocSh->GetHeaderAttributes() );
+
+ if (nErr || aOutliner.GetEditEngine().GetText().isEmpty())
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(mpWindow->GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok, SdResId(STR_READ_DATA_ERROR)));
+ xErrorBox->run();
+ }
+ else
+ {
+ // is it a master page?
+ if (static_cast<DrawViewShell*>(mpViewShell)->GetEditMode() == EditMode::MasterPage &&
+ !pPage->IsMasterPage())
+ {
+ pPage = static_cast<SdPage*>(&(pPage->TRG_GetMasterPage()));
+ }
+
+ assert(pPage && "page not found");
+
+ // if editing is going on right now, let it flow into this text object
+ OutlinerView* pOutlinerView = mpView->GetTextEditOutlinerView();
+ if( pOutlinerView )
+ {
+ SdrObject* pObj = mpView->GetTextEditObject();
+ if( pObj &&
+ pObj->GetObjInventor() == SdrInventor::Default &&
+ pObj->GetObjIdentifier() == SdrObjKind::TitleText &&
+ aOutliner.GetParagraphCount() > 1 )
+ {
+ // in title objects, only one paragraph is allowed
+ while ( aOutliner.GetParagraphCount() > 1 )
+ {
+ Paragraph* pPara = aOutliner.GetParagraph( 0 );
+ sal_uLong nLen = aOutliner.GetText( pPara ).getLength();
+ aOutliner.QuickDelete( ESelection( 0, nLen, 1, 0 ) );
+ aOutliner.QuickInsertLineBreak( ESelection( 0, nLen, 0, nLen ) );
+ }
+ }
+ }
+
+ std::optional<OutlinerParaObject> pOPO = aOutliner.CreateParaObject();
+
+ if (pOutlinerView)
+ {
+ pOutlinerView->InsertText(*pOPO);
+ }
+ else
+ {
+ SdrRectObj* pTO = new SdrRectObj(
+ mpView->getSdrModelFromSdrView(),
+ SdrObjKind::Text);
+ pTO->SetOutlinerParaObject(std::move(pOPO));
+
+ const bool bUndo = mpView->IsUndoEnabled();
+ if( bUndo )
+ mpView->BegUndo(SdResId(STR_UNDO_INSERT_TEXTFRAME));
+ pPage->InsertObject(pTO);
+
+ /* can be bigger as the maximal allowed size:
+ limit object size if necessary */
+ Size aSize(aOutliner.CalcTextSize());
+ Size aMaxSize = mpDoc->GetMaxObjSize();
+ aSize.setHeight( std::min(aSize.Height(), aMaxSize.Height()) );
+ aSize.setWidth( std::min(aSize.Width(), aMaxSize.Width()) );
+ aSize = mpWindow->LogicToPixel(aSize);
+
+ // put it at the center of the window
+ Size aTemp(mpWindow->GetOutputSizePixel());
+ Point aPos(aTemp.Width() / 2, aTemp.Height() / 2);
+ aPos.AdjustX( -(aSize.Width() / 2) );
+ aPos.AdjustY( -(aSize.Height() / 2) );
+ aSize = mpWindow->PixelToLogic(aSize);
+ aPos = mpWindow->PixelToLogic(aPos);
+ pTO->SetLogicRect(::tools::Rectangle(aPos, aSize));
+
+ if (pDlg->IsLink())
+ {
+ pTO->SetTextLink(aFile, aFilterName );
+ }
+
+ if( bUndo )
+ {
+ mpView->AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoInsertObject(*pTO));
+ mpView->EndUndo();
+ }
+ }
+ }
+}
+
+void FuInsertFile::InsTextOrRTFinOlMode(SfxMedium* pMedium)
+{
+ // selected file format: text, RTF or HTML (default is text)
+ EETextFormat nFormat = EETextFormat::Text;
+
+ if( aFilterName.indexOf( "Rich") != -1 )
+ nFormat = EETextFormat::Rtf;
+ else if( aFilterName.indexOf( "HTML" ) != -1 )
+ nFormat = EETextFormat::Html;
+
+ ::Outliner& rDocliner = static_cast<OutlineView*>(mpView)->GetOutliner();
+
+ std::vector<Paragraph*> aSelList;
+ rDocliner.GetView(0)->CreateSelectionList(aSelList);
+
+ Paragraph* pPara = aSelList.empty() ? nullptr : *(aSelList.begin());
+
+ // what should we insert?
+ while (pPara && !Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE))
+ pPara = rDocliner.GetParent(pPara);
+
+ sal_Int32 nTargetPos = rDocliner.GetAbsPos(pPara) + 1;
+
+ // apply layout of predecessor page
+ sal_uInt16 nPage = 0;
+ pPara = rDocliner.GetParagraph( rDocliner.GetAbsPos( pPara ) - 1 );
+ while (pPara)
+ {
+ sal_Int32 nPos = rDocliner.GetAbsPos( pPara );
+ if ( Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) )
+ nPage++;
+ pPara = rDocliner.GetParagraph( nPos - 1 );
+ }
+ SdPage* pPage = mpDoc->GetSdPage(nPage, PageKind::Standard);
+ aLayoutName = pPage->GetLayoutName();
+ sal_Int32 nIndex = aLayoutName.indexOf(SD_LT_SEPARATOR);
+ if( nIndex != -1 )
+ aLayoutName = aLayoutName.copy(0, nIndex);
+
+ /* create our own outline since:
+ - it is possible that the document outliner is actually used in the
+ structuring mode
+ - the draw outliner of the drawing engine has to draw something in
+ between
+ - the global outliner could be used in SdPage::CreatePresObj */
+ ::Outliner aOutliner( &mpDoc->GetItemPool(), OutlinerMode::OutlineObject );
+ aOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(mpDoc->GetStyleSheetPool()));
+
+ // set reference device
+ aOutliner.SetRefDevice(SD_MOD()->GetVirtualRefDevice());
+ aOutliner.SetPaperSize(Size(0x7fffffff, 0x7fffffff));
+
+ SvStream* pStream = pMedium->GetInStream();
+ DBG_ASSERT( pStream, "No InStream!" );
+ pStream->Seek( 0 );
+
+ ErrCode nErr = aOutliner.Read(*pStream, pMedium->GetBaseURL(), nFormat, mpDocSh->GetHeaderAttributes());
+
+ if (nErr || aOutliner.GetEditEngine().GetText().isEmpty())
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(mpWindow->GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok, SdResId(STR_READ_DATA_ERROR)));
+ xErrorBox->run();
+ }
+ else
+ {
+ sal_Int32 nParaCount = aOutliner.GetParagraphCount();
+
+ // for progress bar: number of level-0-paragraphs
+ sal_uInt16 nNewPages = 0;
+ pPara = aOutliner.GetParagraph( 0 );
+ while (pPara)
+ {
+ sal_Int32 nPos = aOutliner.GetAbsPos( pPara );
+ if( Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) )
+ nNewPages++;
+ pPara = aOutliner.GetParagraph( ++nPos );
+ }
+
+ mpDocSh->SetWaitCursor( false );
+
+ std::optional<SfxProgress> pProgress( std::in_place, mpDocSh, SdResId(STR_CREATE_PAGES), nNewPages);
+ pProgress->SetState( 0, 100 );
+
+ nNewPages = 0;
+
+ ViewShellId nViewShellId = mpViewShell ? mpViewShell->GetViewShellBase().GetViewShellId() : ViewShellId(-1);
+ rDocliner.GetUndoManager().EnterListAction(
+ SdResId(STR_UNDO_INSERT_FILE), OUString(), 0, nViewShellId );
+
+ sal_Int32 nSourcePos = 0;
+ SfxStyleSheet* pStyleSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Outline );
+ Paragraph* pSourcePara = aOutliner.GetParagraph( 0 );
+ while (pSourcePara)
+ {
+ sal_Int32 nPos = aOutliner.GetAbsPos( pSourcePara );
+ sal_Int16 nDepth = aOutliner.GetDepth( nPos );
+
+ // only take the last paragraph if it is filled
+ if (nSourcePos < nParaCount - 1 ||
+ !aOutliner.GetText(pSourcePara).isEmpty())
+ {
+ rDocliner.Insert( aOutliner.GetText(pSourcePara), nTargetPos, nDepth );
+ OUString aStyleSheetName( pStyleSheet->GetName() );
+ aStyleSheetName = aStyleSheetName.subView( 0, aStyleSheetName.getLength()-1 ) +
+ OUString::number( nDepth <= 0 ? 1 : nDepth+1 );
+ SfxStyleSheetBasePool* pStylePool = mpDoc->GetStyleSheetPool();
+ SfxStyleSheet* pOutlStyle = static_cast<SfxStyleSheet*>( pStylePool->Find( aStyleSheetName, pStyleSheet->GetFamily() ) );
+ rDocliner.SetStyleSheet( nTargetPos, pOutlStyle );
+ }
+
+ if( Outliner::HasParaFlag( pSourcePara, ParaFlag::ISPAGE ) )
+ {
+ nNewPages++;
+ pProgress->SetState( nNewPages );
+ }
+
+ pSourcePara = aOutliner.GetParagraph( ++nPos );
+ nTargetPos++;
+ nSourcePos++;
+ }
+
+ rDocliner.GetUndoManager().LeaveListAction();
+
+ pProgress.reset();
+
+ mpDocSh->SetWaitCursor( true );
+ }
+}
+
+bool FuInsertFile::InsSDDinOlMode(SfxMedium* pMedium)
+{
+ OutlineView* pOlView = static_cast<OutlineView*>(mpView);
+
+ // transfer Outliner content to SdDrawDocument
+ pOlView->PrepareClose();
+
+ // read in like in the character mode
+ if (InsSDDinDrMode(pMedium))
+ {
+ ::Outliner* pOutliner = pOlView->GetViewByWindow(mpWindow)->GetOutliner();
+
+ // cut notification links temporarily
+ Link<Outliner::ParagraphHdlParam,void> aOldParagraphInsertedHdl = pOutliner->GetParaInsertedHdl();
+ pOutliner->SetParaInsertedHdl( Link<Outliner::ParagraphHdlParam,void>());
+ Link<Outliner::ParagraphHdlParam,void> aOldParagraphRemovingHdl = pOutliner->GetParaRemovingHdl();
+ pOutliner->SetParaRemovingHdl( Link<Outliner::ParagraphHdlParam,void>());
+ Link<Outliner::DepthChangeHdlParam,void> aOldDepthChangedHdl = pOutliner->GetDepthChangedHdl();
+ pOutliner->SetDepthChangedHdl( Link<::Outliner::DepthChangeHdlParam,void>());
+ Link<::Outliner*,void> aOldBeginMovingHdl = pOutliner->GetBeginMovingHdl();
+ pOutliner->SetBeginMovingHdl( Link<::Outliner*,void>());
+ Link<::Outliner*,void> aOldEndMovingHdl = pOutliner->GetEndMovingHdl();
+ pOutliner->SetEndMovingHdl( Link<::Outliner*,void>());
+
+ Link<EditStatus&,void> aOldStatusEventHdl = pOutliner->GetStatusEventHdl();
+ pOutliner->SetStatusEventHdl(Link<EditStatus&,void>());
+
+ pOutliner->Clear();
+ pOlView->FillOutliner();
+
+ // set links again
+ pOutliner->SetParaInsertedHdl(aOldParagraphInsertedHdl);
+ pOutliner->SetParaRemovingHdl(aOldParagraphRemovingHdl);
+ pOutliner->SetDepthChangedHdl(aOldDepthChangedHdl);
+ pOutliner->SetBeginMovingHdl(aOldBeginMovingHdl);
+ pOutliner->SetEndMovingHdl(aOldEndMovingHdl);
+ pOutliner->SetStatusEventHdl(aOldStatusEventHdl);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+void FuInsertFile::GetSupportedFilterVector( ::std::vector< OUString >& rFilterVector )
+{
+ SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
+ std::shared_ptr<const SfxFilter> pSearchFilter;
+
+ rFilterVector.clear();
+
+ if( ( pSearchFilter = rMatcher.GetFilter4Mime( "text/plain" )) != nullptr )
+ rFilterVector.push_back( pSearchFilter->GetMimeType() );
+
+ if( ( pSearchFilter = rMatcher.GetFilter4Mime( "application/rtf" ) ) != nullptr )
+ rFilterVector.push_back( pSearchFilter->GetMimeType() );
+
+ if( ( pSearchFilter = rMatcher.GetFilter4Mime( "text/html" ) ) != nullptr )
+ rFilterVector.push_back( pSearchFilter->GetMimeType() );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuline.cxx b/sd/source/ui/func/fuline.cxx
new file mode 100644
index 000000000..da9cc795f
--- /dev/null
+++ b/sd/source/ui/func/fuline.cxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuline.hxx>
+
+#include <svx/svxids.hrc>
+#include <sfx2/request.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <ViewShell.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <svx/svxdlg.hxx>
+
+namespace sd {
+
+
+FuLine::FuLine (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuLine::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuLine( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuLine::DoExecute( SfxRequest& rReq )
+{
+ rReq.Ignore();
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if (pArgs)
+ return;
+
+ const SdrObject* pObj = nullptr;
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ SfxItemSet aNewAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aNewAttr );
+
+ bool bHasMarked = mpView->AreObjectsMarked();
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ VclPtr<SfxAbstractTabDialog> pDlg( pFact->CreateSvxLineTabDialog(mpViewShell->GetFrameWeld(), &aNewAttr, mpDoc, pObj, bHasMarked) );
+
+ pDlg->StartExecuteAsync([pDlg, this](sal_Int32 nResult){
+ if (nResult == RET_OK)
+ {
+ mpView->SetAttributes (*(pDlg->GetOutputItemSet ()));
+
+ // some attributes are changed, we have to update the listboxes in the objectbars
+ static const sal_uInt16 SidArray[] = {
+ SID_ATTR_LINE_STYLE, // ( SID_SVX_START + 169 )
+ SID_ATTR_LINE_DASH, // ( SID_SVX_START + 170 )
+ SID_ATTR_LINE_WIDTH, // ( SID_SVX_START + 171 )
+ SID_ATTR_LINE_COLOR, // ( SID_SVX_START + 172 )
+ SID_ATTR_LINE_START, // ( SID_SVX_START + 173 )
+ SID_ATTR_LINE_END, // ( SID_SVX_START + 174 )
+ SID_ATTR_LINE_TRANSPARENCE, // (SID_SVX_START+1107)
+ SID_ATTR_LINE_JOINT, // (SID_SVX_START+1110)
+ SID_ATTR_LINE_CAP, // (SID_SVX_START+1111)
+ 0 };
+
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArray );
+ }
+
+ // deferred until the dialog ends
+ mpViewShell->Cancel();
+
+ pDlg->disposeOnce();
+ });
+}
+
+void FuLine::Activate()
+{
+}
+
+void FuLine::Deactivate()
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fulinend.cxx b/sd/source/ui/func/fulinend.cxx
new file mode 100644
index 000000000..34fe63161
--- /dev/null
+++ b/sd/source/ui/func/fulinend.cxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fulinend.hxx>
+#include <svx/xtable.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdopath.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <strings.hrc>
+#include <helpids.h>
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <View.hxx>
+#include <Window.hxx>
+#include <memory>
+
+namespace sd {
+
+
+FuLineEnd::FuLineEnd(ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView,
+ SdDrawDocument* pDoc, SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuLineEnd::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuLineEnd( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuLineEnd::DoExecute( SfxRequest& )
+{
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if( rMarkList.GetMarkCount() != 1 )
+ return;
+
+ const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ const SdrObject* pNewObj;
+ SdrObjectUniquePtr pConvPolyObj;
+
+ if( dynamic_cast< const SdrPathObj *>( pObj ) != nullptr )
+ {
+ pNewObj = pObj;
+ }
+ else
+ {
+ SdrObjTransformInfoRec aInfoRec;
+ pObj->TakeObjInfo( aInfoRec );
+
+ if( aInfoRec.bCanConvToPath &&
+ pObj->GetObjInventor() == SdrInventor::Default &&
+ pObj->GetObjIdentifier() != SdrObjKind::Group )
+ // bCanConvToPath is sal_True for group objects,
+ // but it crashes on ConvertToPathObj()!
+ {
+ pConvPolyObj = pObj->ConvertToPolyObj( true, false );
+ pNewObj = pConvPolyObj.get();
+
+ if( !pNewObj || dynamic_cast< const SdrPathObj *>( pNewObj ) == nullptr )
+ return; // Cancel, additional security, but it does not help
+ // for group objects
+ }
+ else return; // Cancel
+ }
+
+ const ::basegfx::B2DPolyPolygon aPolyPolygon = static_cast<const SdrPathObj*>(pNewObj)->GetPathPoly();
+
+ // Delete the created poly-object
+ pConvPolyObj.reset();
+
+ XLineEndListRef pLineEndList = mpDoc->GetLineEndList();
+
+ OUString aNewName( SdResId( STR_LINEEND ) );
+ OUString aDesc( SdResId( STR_DESC_LINEEND ) );
+ OUString aName;
+
+ ::tools::Long nCount = pLineEndList->Count();
+ ::tools::Long j = 1;
+ bool bDifferent = false;
+
+ while( !bDifferent )
+ {
+ aName = aNewName + " " + OUString::number(j++);
+ bDifferent = true;
+ for( ::tools::Long i = 0; i < nCount && bDifferent; i++ )
+ {
+ if( aName == pLineEndList->GetLineEnd( i )->GetName() )
+ bDifferent = false;
+ }
+ }
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxNameDialog> pDlg( pFact->CreateSvxNameDialog( nullptr, aName, aDesc ) );
+
+ pDlg->SetEditHelpId( HID_SD_NAMEDIALOG_LINEEND );
+
+ if( pDlg->Execute() != RET_OK )
+ return;
+
+ pDlg->GetName( aName );
+ bDifferent = true;
+
+ for( ::tools::Long i = 0; i < nCount && bDifferent; i++ )
+ {
+ if( aName == pLineEndList->GetLineEnd( i )->GetName() )
+ bDifferent = false;
+ }
+
+ if( bDifferent )
+ {
+ pLineEndList->Insert(std::make_unique<XLineEndEntry>(aPolyPolygon, aName));
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(mpWindow ? mpWindow->GetFrameWeld() : nullptr,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SdResId(STR_WARN_NAME_DUPLICATE)));
+ xWarn->run();
+ }
+}
+
+void FuLineEnd::Activate()
+{
+}
+
+void FuLineEnd::Deactivate()
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fulink.cxx b/sd/source/ui/func/fulink.cxx
new file mode 100644
index 000000000..8a6d726de
--- /dev/null
+++ b/sd/source/ui/func/fulink.cxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fulink.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <svx/svxdlg.hxx>
+
+#include <drawdoc.hxx>
+#include <ViewShell.hxx>
+#include <app.hrc>
+
+class SfxRequest;
+
+namespace sd {
+
+
+FuLink::FuLink (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq )
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuLink::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuLink( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuLink::DoExecute( SfxRequest& )
+{
+ sfx2::LinkManager* pLinkManager = mpDoc->GetLinkManager();
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractLinksDialog> pDlg(pFact->CreateLinksDialog(mpViewShell->GetFrameWeld(), pLinkManager));
+ pDlg->Execute();
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_MANAGE_LINKS );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fumeasur.cxx b/sd/source/ui/func/fumeasur.cxx
new file mode 100644
index 000000000..27afd0f7a
--- /dev/null
+++ b/sd/source/ui/func/fumeasur.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fumeasur.hxx>
+#include <sfx2/request.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/dialogs.hrc>
+
+namespace sd {
+
+
+FuMeasureDlg::FuMeasureDlg (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuMeasureDlg::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuMeasureDlg( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuMeasureDlg::DoExecute( SfxRequest& rReq )
+{
+ SfxItemSet aNewAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aNewAttr );
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if( !pArgs )
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateSfxDialog(rReq.GetFrameWeld(), aNewAttr, mpView, RID_SVXPAGE_MEASURE));
+
+ if( pDlg->Execute() == RET_OK )
+ {
+ rReq.Done( *pDlg->GetOutputItemSet() );
+ pArgs = rReq.GetArgs();
+ }
+ }
+
+ if( pArgs )
+ mpView->SetAttributes( *pArgs );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fumorph.cxx b/sd/source/ui/func/fumorph.cxx
new file mode 100644
index 000000000..c2f94b440
--- /dev/null
+++ b/sd/source/ui/func/fumorph.cxx
@@ -0,0 +1,508 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fumorph.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdogrp.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <View.hxx>
+#include <Window.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <strings.hrc>
+#include <sdresid.hxx>
+
+#include <sdabstdlg.hxx>
+
+#include <svx/svditer.hxx>
+
+#include <basegfx/color/bcolor.hxx>
+#include <com/sun/star/drawing/LineStyle.hpp>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+FuMorph::FuMorph (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq )
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuMorph::Create(
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq
+)
+{
+ rtl::Reference<FuPoor> xFunc( new FuMorph( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuMorph::DoExecute( SfxRequest& )
+{
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if(rMarkList.GetMarkCount() != 2)
+ return;
+
+ // create clones
+ SdrObject* pObj1 = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ SdrObject* pObj2 = rMarkList.GetMark(1)->GetMarkedSdrObj();
+ SdrObject* pCloneObj1(pObj1->CloneSdrObject(pObj1->getSdrModelFromSdrObject()));
+ SdrObject* pCloneObj2(pObj2->CloneSdrObject(pObj2->getSdrModelFromSdrObject()));
+
+ // delete text at clone, otherwise we do not get a correct PathObj
+ pCloneObj1->SetOutlinerParaObject(std::nullopt);
+ pCloneObj2->SetOutlinerParaObject(std::nullopt);
+
+ // create path objects
+ SdrObjectUniquePtr pPolyObj1 = pCloneObj1->ConvertToPolyObj(false, false);
+ SdrObjectUniquePtr pPolyObj2 = pCloneObj2->ConvertToPolyObj(false, false);
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractMorphDlg> pDlg( pFact->CreateMorphDlg(mpWindow ? mpWindow->GetFrameWeld() : nullptr, pObj1, pObj2) );
+ if(pPolyObj1 && pPolyObj2 && (pDlg->Execute() == RET_OK))
+ {
+ B2DPolyPolygonList_impl aPolyPolyList;
+ ::basegfx::B2DPolyPolygon aPolyPoly1;
+ ::basegfx::B2DPolyPolygon aPolyPoly2;
+
+ pDlg->SaveSettings();
+
+ // #i48168# Not always is the pPolyObj1/pPolyObj2 a SdrPathObj, it may also be a group object
+ // containing SdrPathObjs. To get the polygons, I add two iters here
+ SdrObjListIter aIter1(*pPolyObj1);
+ SdrObjListIter aIter2(*pPolyObj2);
+
+ while(aIter1.IsMore())
+ {
+ SdrObject* pObj = aIter1.Next();
+ if(auto pPathObj = dynamic_cast< SdrPathObj *>( pObj ))
+ aPolyPoly1.append(pPathObj->GetPathPoly());
+ }
+
+ while(aIter2.IsMore())
+ {
+ SdrObject* pObj = aIter2.Next();
+ if(auto pPathObj = dynamic_cast< SdrPathObj *>( pObj ))
+ aPolyPoly2.append(pPathObj->GetPathPoly());
+ }
+
+ // perform morphing
+ if(aPolyPoly1.count() && aPolyPoly2.count())
+ {
+ aPolyPoly1 = ::basegfx::utils::correctOrientations(aPolyPoly1);
+ aPolyPoly1.removeDoublePoints();
+ ::basegfx::B2VectorOrientation eIsClockwise1(::basegfx::utils::getOrientation(aPolyPoly1.getB2DPolygon(0)));
+
+ aPolyPoly2 = ::basegfx::utils::correctOrientations(aPolyPoly2);
+ aPolyPoly2.removeDoublePoints();
+ ::basegfx::B2VectorOrientation eIsClockwise2(::basegfx::utils::getOrientation(aPolyPoly2.getB2DPolygon(0)));
+
+ // set same orientation
+ if(eIsClockwise1 != eIsClockwise2)
+ aPolyPoly2.flip();
+
+ // force same poly count
+ if(aPolyPoly1.count() < aPolyPoly2.count())
+ ImpAddPolys(aPolyPoly1, aPolyPoly2);
+ else if(aPolyPoly2.count() < aPolyPoly1.count())
+ ImpAddPolys(aPolyPoly2, aPolyPoly1);
+
+ // use orientation flag from dialog
+ if(!pDlg->IsOrientationFade())
+ aPolyPoly2.flip();
+
+ // force same point counts
+ for( sal_uInt32 a(0); a < aPolyPoly1.count(); a++ )
+ {
+ ::basegfx::B2DPolygon aSub1(aPolyPoly1.getB2DPolygon(a));
+ ::basegfx::B2DPolygon aSub2(aPolyPoly2.getB2DPolygon(a));
+
+ if(aSub1.count() < aSub2.count())
+ ImpEqualizePolyPointCount(aSub1, aSub2);
+ else if(aSub2.count() < aSub1.count())
+ ImpEqualizePolyPointCount(aSub2, aSub1);
+
+ aPolyPoly1.setB2DPolygon(a, aSub1);
+ aPolyPoly2.setB2DPolygon(a, aSub2);
+ }
+
+ ImpMorphPolygons(aPolyPoly1, aPolyPoly2, pDlg->GetFadeSteps(), aPolyPolyList);
+
+ OUString aString = mpView->GetDescriptionOfMarkedObjects() +
+ " " + SdResId(STR_UNDO_MORPHING);
+
+ mpView->BegUndo(aString);
+ ImpInsertPolygons(aPolyPolyList, pDlg->IsAttributeFade(), pObj1, pObj2);
+ mpView->EndUndo();
+ }
+ }
+ SdrObject::Free( pCloneObj1 );
+ SdrObject::Free( pCloneObj2 );
+}
+
+static ::basegfx::B2DPolygon ImpGetExpandedPolygon(
+ const ::basegfx::B2DPolygon& rCandidate,
+ sal_uInt32 nNum
+)
+{
+ if(rCandidate.count() && nNum && rCandidate.count() != nNum)
+ {
+ // length of step in dest poly
+ ::basegfx::B2DPolygon aRetval;
+ const double fStep(::basegfx::utils::getLength(rCandidate) / static_cast<double>(rCandidate.isClosed() ? nNum : nNum - 1));
+ double fDestPos(0.0);
+ double fSrcPos(0.0);
+ sal_uInt32 nSrcPos(0);
+ sal_uInt32 nSrcPosNext((nSrcPos + 1 == rCandidate.count()) ? 0 : nSrcPos + 1);
+ double fNextSrcLen(::basegfx::B2DVector(rCandidate.getB2DPoint(nSrcPos) - rCandidate.getB2DPoint(nSrcPosNext)).getLength());
+
+ for(sal_uInt32 b(0); b < nNum; b++)
+ {
+ // calc fDestPos in source
+ while(fSrcPos + fNextSrcLen < fDestPos)
+ {
+ fSrcPos += fNextSrcLen;
+ nSrcPos++;
+ nSrcPosNext = (nSrcPos + 1 == rCandidate.count()) ? 0 : nSrcPos + 1;
+ fNextSrcLen = ::basegfx::B2DVector(rCandidate.getB2DPoint(nSrcPos) - rCandidate.getB2DPoint(nSrcPosNext)).getLength();
+ }
+
+ // fDestPos is between fSrcPos and (fSrcPos + fNextSrcLen)
+ const double fLenA((fDestPos - fSrcPos) / fNextSrcLen);
+ const ::basegfx::B2DPoint aOld1(rCandidate.getB2DPoint(nSrcPos));
+ const ::basegfx::B2DPoint aOld2(rCandidate.getB2DPoint(nSrcPosNext));
+ ::basegfx::B2DPoint aNewPoint(basegfx::interpolate(aOld1, aOld2, fLenA));
+ aRetval.append(aNewPoint);
+
+ // next step
+ fDestPos += fStep;
+ }
+
+ if(aRetval.count() >= 3)
+ {
+ aRetval.setClosed(rCandidate.isClosed());
+ }
+
+ return aRetval;
+ }
+ else
+ {
+ return rCandidate;
+ }
+}
+
+/**
+ * make the point count of the polygons equal in adding points
+ */
+void FuMorph::ImpEqualizePolyPointCount(
+ ::basegfx::B2DPolygon& rSmall,
+ const ::basegfx::B2DPolygon& rBig
+)
+{
+ // create poly with equal point count
+ const sal_uInt32 nCnt(rBig.count());
+ ::basegfx::B2DPolygon aPoly1(ImpGetExpandedPolygon(rSmall, nCnt));
+
+ // create transformation for rBig to do the compare
+ const ::basegfx::B2DRange aSrcSize(::basegfx::utils::getRange(rBig));
+ const ::basegfx::B2DPoint aSrcPos(aSrcSize.getCenter());
+ const ::basegfx::B2DRange aDstSize(::basegfx::utils::getRange(rSmall));
+ const ::basegfx::B2DPoint aDstPos(aDstSize.getCenter());
+
+ basegfx::B2DHomMatrix aTrans(basegfx::utils::createTranslateB2DHomMatrix(-aSrcPos.getX(), -aSrcPos.getY()));
+ aTrans.scale(aDstSize.getWidth() / aSrcSize.getWidth(), aDstSize.getHeight() / aSrcSize.getHeight());
+ aTrans.translate(aDstPos.getX(), aDstPos.getY());
+
+ // transpose points to have smooth linear blending
+ ::basegfx::B2DPolygon aPoly2;
+ aPoly2.append(::basegfx::B2DPoint(), nCnt);
+ sal_uInt32 nInd(ImpGetNearestIndex(aPoly1, aTrans * rBig.getB2DPoint(0)));
+
+ for(sal_uInt32 a(0); a < nCnt; a++)
+ {
+ aPoly2.setB2DPoint((a + nCnt - nInd) % nCnt, aPoly1.getB2DPoint(a));
+ }
+
+ aPoly2.setClosed(rBig.isClosed());
+ rSmall = aPoly2;
+}
+
+sal_uInt32 FuMorph::ImpGetNearestIndex(
+ const ::basegfx::B2DPolygon& rPoly,
+ const ::basegfx::B2DPoint& rPos
+)
+{
+ double fMinDist = 0.0;
+ sal_uInt32 nActInd = 0;
+
+ for(sal_uInt32 a(0); a < rPoly.count(); a++)
+ {
+ double fNewDist(::basegfx::B2DVector(rPoly.getB2DPoint(a) - rPos).getLength());
+
+ if(!a || fNewDist < fMinDist)
+ {
+ fMinDist = fNewDist;
+ nActInd = a;
+ }
+ }
+
+ return nActInd;
+}
+
+/**
+ * add to a point reduced polys until count is same
+ */
+void FuMorph::ImpAddPolys(
+ ::basegfx::B2DPolyPolygon& rSmaller,
+ const ::basegfx::B2DPolyPolygon& rBigger
+)
+{
+ while(rSmaller.count() < rBigger.count())
+ {
+ const ::basegfx::B2DPolygon& aToBeCopied(rBigger.getB2DPolygon(rSmaller.count()));
+ const ::basegfx::B2DRange aToBeCopiedPolySize(::basegfx::utils::getRange(aToBeCopied));
+ ::basegfx::B2DPoint aNewPoint(aToBeCopiedPolySize.getCenter());
+ ::basegfx::B2DPolygon aNewPoly;
+
+ const ::basegfx::B2DRange aSrcSize(::basegfx::utils::getRange(rBigger.getB2DPolygon(0)));
+ const ::basegfx::B2DPoint aSrcPos(aSrcSize.getCenter());
+ const ::basegfx::B2DRange aDstSize(::basegfx::utils::getRange(rSmaller.getB2DPolygon(0)));
+ const ::basegfx::B2DPoint aDstPos(aDstSize.getCenter());
+ aNewPoint = aNewPoint - aSrcPos + aDstPos;
+
+ for(sal_uInt32 a(0); a < aToBeCopied.count(); a++)
+ {
+ aNewPoly.append(aNewPoint);
+ }
+
+ rSmaller.append(aNewPoly);
+ }
+}
+
+/**
+ * create group object with morphed polygons
+ */
+void FuMorph::ImpInsertPolygons(
+ B2DPolyPolygonList_impl& rPolyPolyList3D,
+ bool bAttributeFade,
+ const SdrObject* pObj1,
+ const SdrObject* pObj2
+)
+{
+ Color aStartFillCol;
+ Color aEndFillCol;
+ Color aStartLineCol;
+ Color aEndLineCol;
+ ::tools::Long nStartLineWidth = 0;
+ ::tools::Long nEndLineWidth = 0;
+ SdrPageView* pPageView = mpView->GetSdrPageView();
+ SfxItemPool & rPool = pObj1->GetObjectItemPool();
+ SfxItemSetFixed<SDRATTR_START,SDRATTR_NOTPERSIST_FIRST-1,EE_ITEMS_START,EE_ITEMS_END> aSet1( rPool );
+ SfxItemSet aSet2( aSet1 );
+ bool bLineColor = false;
+ bool bFillColor = false;
+ bool bLineWidth = false;
+ bool bIgnoreLine = false;
+ bool bIgnoreFill = false;
+
+ aSet1.Put(pObj1->GetMergedItemSet());
+ aSet2.Put(pObj2->GetMergedItemSet());
+
+ const drawing::LineStyle eLineStyle1 = aSet1.Get(XATTR_LINESTYLE).GetValue();
+ const drawing::LineStyle eLineStyle2 = aSet2.Get(XATTR_LINESTYLE).GetValue();
+ const drawing::FillStyle eFillStyle1 = aSet1.Get(XATTR_FILLSTYLE).GetValue();
+ const drawing::FillStyle eFillStyle2 = aSet2.Get(XATTR_FILLSTYLE).GetValue();
+
+ if ( bAttributeFade )
+ {
+ if ( ( eLineStyle1 != drawing::LineStyle_NONE ) && ( eLineStyle2 != drawing::LineStyle_NONE ) )
+ {
+ bLineWidth = bLineColor = true;
+
+ aStartLineCol = aSet1.Get(XATTR_LINECOLOR).GetColorValue();
+ aEndLineCol = aSet2.Get(XATTR_LINECOLOR).GetColorValue();
+
+ nStartLineWidth = aSet1.Get(XATTR_LINEWIDTH).GetValue();
+ nEndLineWidth = aSet2.Get(XATTR_LINEWIDTH).GetValue();
+ }
+ else if ( ( eLineStyle1 == drawing::LineStyle_NONE ) && ( eLineStyle2 == drawing::LineStyle_NONE ) )
+ bIgnoreLine = true;
+
+ if ( ( eFillStyle1 == drawing::FillStyle_SOLID ) && ( eFillStyle2 == drawing::FillStyle_SOLID ) )
+ {
+ bFillColor = true;
+ aStartFillCol = aSet1.Get(XATTR_FILLCOLOR).GetColorValue();
+ aEndFillCol = aSet2.Get(XATTR_FILLCOLOR).GetColorValue();
+ }
+ else if ( ( eFillStyle1 == drawing::FillStyle_NONE ) && ( eFillStyle2 == drawing::FillStyle_NONE ) )
+ bIgnoreFill = true;
+ }
+
+ if ( !pPageView )
+ return;
+
+ SfxItemSet aSet( aSet1 );
+ std::unique_ptr<SdrObjGroup, SdrObjectFreeOp> xObjGroup(new SdrObjGroup(mpView->getSdrModelFromSdrView()));
+ SdrObjList* pObjList = xObjGroup->GetSubList();
+ const size_t nCount = rPolyPolyList3D.size();
+ const double fStep = 1. / ( nCount + 1 );
+ const double fDelta = nEndLineWidth - nStartLineWidth;
+ double fFactor = fStep;
+
+ aSet.Put( XLineStyleItem( drawing::LineStyle_SOLID ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
+
+ for ( size_t i = 0; i < nCount; i++, fFactor += fStep )
+ {
+ const ::basegfx::B2DPolyPolygon& rPolyPoly3D = rPolyPolyList3D[ i ];
+ SdrPathObj* pNewObj = new SdrPathObj(
+ mpView->getSdrModelFromSdrView(),
+ SdrObjKind::Polygon,
+ rPolyPoly3D);
+
+ // line color
+ if ( bLineColor )
+ {
+ const basegfx::BColor aLineColor(basegfx::interpolate(aStartLineCol.getBColor(), aEndLineCol.getBColor(), fFactor));
+ aSet.Put( XLineColorItem( "", Color(aLineColor)));
+ }
+ else if ( bIgnoreLine )
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+
+ // fill color
+ if ( bFillColor )
+ {
+ const basegfx::BColor aFillColor(basegfx::interpolate(aStartFillCol.getBColor(), aEndFillCol.getBColor(), fFactor));
+ aSet.Put( XFillColorItem( "", Color(aFillColor)));
+ }
+ else if ( bIgnoreFill )
+ aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+
+ // line width
+ if ( bLineWidth )
+ aSet.Put( XLineWidthItem( nStartLineWidth + static_cast<::tools::Long>( fFactor * fDelta + 0.5 ) ) );
+
+ pNewObj->SetMergedItemSetAndBroadcast(aSet);
+
+ pObjList->InsertObject( pNewObj );
+ }
+
+ if ( nCount )
+ {
+ pObjList->InsertObject(
+ pObj1->CloneSdrObject(pObj1->getSdrModelFromSdrObject()),
+ 0 );
+ pObjList->InsertObject(
+ pObj2->CloneSdrObject(pObj2->getSdrModelFromSdrObject()) );
+
+ mpView->DeleteMarked();
+ mpView->InsertObjectAtView(xObjGroup.release(), *pPageView, SdrInsertFlags:: SETDEFLAYER);
+ }
+}
+
+/**
+ * create single morphed PolyPolygon
+ */
+::basegfx::B2DPolyPolygon FuMorph::ImpCreateMorphedPolygon(
+ const ::basegfx::B2DPolyPolygon& rPolyPolyStart,
+ const ::basegfx::B2DPolyPolygon& rPolyPolyEnd,
+ double fMorphingFactor
+)
+{
+ ::basegfx::B2DPolyPolygon aNewPolyPolygon;
+ const double fFactor = 1.0 - fMorphingFactor;
+
+ for(sal_uInt32 a(0); a < rPolyPolyStart.count(); a++)
+ {
+ const ::basegfx::B2DPolygon& aPolyStart(rPolyPolyStart.getB2DPolygon(a));
+ const ::basegfx::B2DPolygon& aPolyEnd(rPolyPolyEnd.getB2DPolygon(a));
+ const sal_uInt32 nCount(aPolyStart.count());
+ ::basegfx::B2DPolygon aNewPolygon;
+
+ for(sal_uInt32 b(0); b < nCount; b++)
+ {
+ const ::basegfx::B2DPoint& aPtStart(aPolyStart.getB2DPoint(b));
+ const ::basegfx::B2DPoint& aPtEnd(aPolyEnd.getB2DPoint(b));
+ aNewPolygon.append(aPtEnd + ((aPtStart - aPtEnd) * fFactor));
+ }
+
+ aNewPolygon.setClosed(aPolyStart.isClosed() && aPolyEnd.isClosed());
+ aNewPolyPolygon.append(aNewPolygon);
+ }
+
+ return aNewPolyPolygon;
+}
+
+/**
+ * create morphed PolyPolygons
+ */
+void FuMorph::ImpMorphPolygons(
+ const ::basegfx::B2DPolyPolygon& rPolyPoly1,
+ const ::basegfx::B2DPolyPolygon& rPolyPoly2,
+ const sal_uInt16 nSteps,
+ B2DPolyPolygonList_impl& rPolyPolyList3D
+)
+{
+ if(!nSteps)
+ return;
+
+ const ::basegfx::B2DRange aStartPolySize(::basegfx::utils::getRange(rPolyPoly1));
+ const ::basegfx::B2DPoint aStartCenter(aStartPolySize.getCenter());
+ const ::basegfx::B2DRange aEndPolySize(::basegfx::utils::getRange(rPolyPoly2));
+ const ::basegfx::B2DPoint aEndCenter(aEndPolySize.getCenter());
+ const ::basegfx::B2DPoint aDelta(aEndCenter - aStartCenter);
+ const double fFactor(1.0 / (nSteps + 1));
+ double fValue(0.0);
+
+ for(sal_uInt16 i(0); i < nSteps; i++)
+ {
+ fValue += fFactor;
+ ::basegfx::B2DPolyPolygon aNewPolyPoly2D = ImpCreateMorphedPolygon(rPolyPoly1, rPolyPoly2, fValue);
+
+ const ::basegfx::B2DRange aNewPolySize(::basegfx::utils::getRange(aNewPolyPoly2D));
+ const ::basegfx::B2DPoint aNewS(aNewPolySize.getCenter());
+ const ::basegfx::B2DPoint aRealS(aStartCenter + (aDelta * fValue));
+ const ::basegfx::B2DPoint aDiff(aRealS - aNewS);
+
+ aNewPolyPoly2D.transform(basegfx::utils::createTranslateB2DHomMatrix(aDiff));
+ rPolyPolyList3D.push_back( std::move(aNewPolyPoly2D) );
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/funavig.cxx b/sd/source/ui/func/funavig.cxx
new file mode 100644
index 000000000..bd0cdb7c3
--- /dev/null
+++ b/sd/source/ui/func/funavig.cxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <funavig.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <app.hrc>
+#include <sdpage.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <drawdoc.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShell.hxx>
+#include <slideshow.hxx>
+
+namespace sd {
+
+
+FuNavigation::FuNavigation (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuNavigation::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuNavigation( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuNavigation::DoExecute( SfxRequest& rReq )
+{
+ bool bSlideShow = SlideShow::IsRunning( mpViewShell->GetViewShellBase() );
+
+ switch ( rReq.GetSlot() )
+ {
+ case SID_GO_TO_FIRST_PAGE:
+ {
+ if (!mpView->IsTextEdit()
+ && dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr
+ && !bSlideShow)
+ {
+ // jump to first page
+ static_cast<DrawViewShell*>(mpViewShell)->SwitchPage(0);
+ }
+ }
+ break;
+
+ case SID_GO_TO_PREVIOUS_PAGE:
+ {
+ if( !bSlideShow)
+ if( auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell ) )
+ {
+ // With no modifier pressed we move to the previous
+ // slide.
+ mpView->SdrEndTextEdit();
+
+ // Previous page.
+ SdPage* pPage = pDrawViewShell->GetActualPage();
+ sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2;
+
+ if (nSdPage > 0)
+ {
+ // Switch the page and send events regarding
+ // deactivation the old page and activating the new
+ // one.
+ TabControl& rPageTabControl =
+ static_cast<DrawViewShell*>(mpViewShell)
+ ->GetPageTabControl();
+ if (rPageTabControl.IsReallyShown())
+ rPageTabControl.SendDeactivatePageEvent ();
+ static_cast<DrawViewShell*>(mpViewShell)->SwitchPage(nSdPage - 1);
+ if (rPageTabControl.IsReallyShown())
+ rPageTabControl.SendActivatePageEvent ();
+ }
+ }
+ }
+ break;
+
+ case SID_GO_TO_NEXT_PAGE:
+ {
+ if( !bSlideShow)
+ if( auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell ))
+ {
+ // With no modifier pressed we move to the next slide.
+ mpView->SdrEndTextEdit();
+
+ // Next page.
+ SdPage* pPage = pDrawViewShell->GetActualPage();
+ sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2;
+
+ if (nSdPage < mpDoc->GetSdPageCount(pPage->GetPageKind()) - 1)
+ {
+ // Switch the page and send events regarding
+ // deactivation the old page and activating the new
+ // one.
+ TabControl& rPageTabControl =
+ static_cast<DrawViewShell*>(mpViewShell)->GetPageTabControl();
+ if (rPageTabControl.IsReallyShown())
+ rPageTabControl.SendDeactivatePageEvent ();
+ static_cast<DrawViewShell*>(mpViewShell)->SwitchPage(nSdPage + 1);
+ if (rPageTabControl.IsReallyShown())
+ rPageTabControl.SendActivatePageEvent ();
+ }
+ }
+ }
+ break;
+
+ case SID_GO_TO_LAST_PAGE:
+ {
+ if (!mpView->IsTextEdit() && !bSlideShow)
+ if (auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell ))
+ {
+ // jump to last page
+ SdPage* pPage = pDrawViewShell->GetActualPage();
+ pDrawViewShell->SwitchPage(mpDoc->GetSdPageCount(
+ pPage->GetPageKind()) - 1);
+ }
+ }
+ break;
+ }
+ // Refresh toolbar icons
+ SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_GO_TO_FIRST_PAGE);
+ rBindings.Invalidate(SID_GO_TO_PREVIOUS_PAGE);
+ rBindings.Invalidate(SID_GO_TO_NEXT_PAGE);
+ rBindings.Invalidate(SID_GO_TO_LAST_PAGE);
+}
+
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuoaprms.cxx b/sd/source/ui/func/fuoaprms.cxx
new file mode 100644
index 000000000..0feaabfb4
--- /dev/null
+++ b/sd/source/ui/func/fuoaprms.cxx
@@ -0,0 +1,800 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuoaprms.hxx>
+#include <sdattr.hrc>
+
+#include <editeng/colritem.hxx>
+#include <svx/svdundo.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <svx/svdopath.hxx>
+#include <tools/debug.hxx>
+
+#include <strings.hrc>
+#include <drawdoc.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <anminfo.hxx>
+#include <unoaprms.hxx>
+#include <sdundogr.hxx>
+#include <View.hxx>
+#include <sdabstdlg.hxx>
+#include <sdresid.hxx>
+#include <tools/helpers.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+
+namespace sd {
+
+
+#define ATTR_MISSING 0 ///< Attribute missing
+#define ATTR_MIXED 1 ///< Attribute ambiguous (on multi-selection)
+#define ATTR_SET 2 ///< Attribute unique
+
+FuObjectAnimationParameters::FuObjectAnimationParameters (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuObjectAnimationParameters::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuObjectAnimationParameters( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuObjectAnimationParameters::DoExecute( SfxRequest& rReq )
+{
+ SfxUndoManager* pUndoMgr = mpViewShell->GetViewFrame()->GetObjectShell()->GetUndoManager();
+
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ short nAnimationSet = ATTR_MISSING;
+ short nEffectSet = ATTR_MISSING;
+ short nTextEffectSet = ATTR_MISSING;
+ short nSpeedSet = ATTR_MISSING;
+ short nFadeColorSet = ATTR_MISSING;
+ short nFadeOutSet = ATTR_MISSING;
+ short nInvisibleSet = ATTR_MISSING;
+ short nSoundOnSet = ATTR_MISSING;
+ short nSoundFileSet = ATTR_MISSING;
+ short nPlayFullSet = ATTR_MISSING;
+ short nClickActionSet = ATTR_MISSING;
+ short nBookmarkSet = ATTR_MISSING;
+
+ short nSecondEffectSet = ATTR_MISSING;
+ short nSecondSpeedSet = ATTR_MISSING;
+ short nSecondSoundOnSet = ATTR_MISSING;
+ short nSecondPlayFullSet = ATTR_MISSING;
+
+ // defaults (for Undo-Action)
+ presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE;
+ presentation::AnimationEffect eTextEffect = presentation::AnimationEffect_NONE;
+ presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_MEDIUM;
+ bool bActive = false;
+ bool bFadeOut = false;
+ Color aFadeColor = COL_LIGHTGRAY;
+ bool bInvisible = false;
+ bool bSoundOn = false;
+ OUString aSound;
+ bool bPlayFull = false;
+ presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
+ OUString aBookmark;
+
+ presentation::AnimationEffect eSecondEffect = presentation::AnimationEffect_NONE;
+ presentation::AnimationSpeed eSecondSpeed = presentation::AnimationSpeed_MEDIUM;
+ bool bSecondSoundOn = false;
+ bool bSecondPlayFull = false;
+
+ SdAnimationInfo* pInfo;
+ SdrMark* pMark;
+
+ // inspect first object
+ pMark = rMarkList.GetMark(0);
+ pInfo = SdDrawDocument::GetAnimationInfo(pMark->GetMarkedSdrObj());
+ if( pInfo )
+ {
+ bActive = pInfo->mbActive;
+ nAnimationSet = ATTR_SET;
+
+ eEffect = pInfo->meEffect;
+ nEffectSet = ATTR_SET;
+
+ eTextEffect = pInfo->meTextEffect;
+ nTextEffectSet = ATTR_SET;
+
+ eSpeed = pInfo->meSpeed;
+ nSpeedSet = ATTR_SET;
+
+ bFadeOut = pInfo->mbDimPrevious;
+ nFadeOutSet = ATTR_SET;
+
+ aFadeColor = pInfo->maDimColor;
+ nFadeColorSet = ATTR_SET;
+
+ bInvisible = pInfo->mbDimHide;
+ nInvisibleSet = ATTR_SET;
+
+ bSoundOn = pInfo->mbSoundOn;
+ nSoundOnSet = ATTR_SET;
+
+ aSound = pInfo->maSoundFile;
+ nSoundFileSet = ATTR_SET;
+
+ bPlayFull = pInfo->mbPlayFull;
+ nPlayFullSet = ATTR_SET;
+
+ eClickAction = pInfo->meClickAction;
+ nClickActionSet = ATTR_SET;
+
+ aBookmark = pInfo->GetBookmark();
+ nBookmarkSet = ATTR_SET;
+
+ eSecondEffect = pInfo->meSecondEffect;
+ nSecondEffectSet = ATTR_SET;
+
+ eSecondSpeed = pInfo->meSecondSpeed;
+ nSecondSpeedSet = ATTR_SET;
+
+ bSecondSoundOn = pInfo->mbSecondSoundOn;
+ nSecondSoundOnSet = ATTR_SET;
+
+ bSecondPlayFull = pInfo->mbSecondPlayFull;
+ nSecondPlayFullSet = ATTR_SET;
+ }
+
+ // if necessary, inspect more objects
+ for( size_t nObject = 1; nObject < nCount; ++nObject )
+ {
+ pMark = rMarkList.GetMark( nObject );
+ SdrObject* pObject = pMark->GetMarkedSdrObj();
+ pInfo = SdDrawDocument::GetAnimationInfo(pObject);
+ if( pInfo )
+ {
+ if( bActive != pInfo->mbActive )
+ nAnimationSet = ATTR_MIXED;
+
+ if( eEffect != pInfo->meEffect )
+ nEffectSet = ATTR_MIXED;
+
+ if( eTextEffect != pInfo->meTextEffect )
+ nTextEffectSet = ATTR_MIXED;
+
+ if( eSpeed != pInfo->meSpeed )
+ nSpeedSet = ATTR_MIXED;
+
+ if( bFadeOut != pInfo->mbDimPrevious )
+ nFadeOutSet = ATTR_MIXED;
+
+ if( aFadeColor != pInfo->maDimColor )
+ nFadeColorSet = ATTR_MIXED;
+
+ if( bInvisible != pInfo->mbDimHide )
+ nInvisibleSet = ATTR_MIXED;
+
+ if( bSoundOn != pInfo->mbSoundOn )
+ nSoundOnSet = ATTR_MIXED;
+
+ if( aSound != pInfo->maSoundFile )
+ nSoundFileSet = ATTR_MIXED;
+
+ if( bPlayFull != pInfo->mbPlayFull )
+ nPlayFullSet = ATTR_MIXED;
+
+ if( eClickAction != pInfo->meClickAction )
+ nClickActionSet = ATTR_MIXED;
+
+ if( aBookmark != pInfo->GetBookmark() )
+ nBookmarkSet = ATTR_MIXED;
+
+ if( eSecondEffect != pInfo->meSecondEffect )
+ nSecondEffectSet = ATTR_MIXED;
+
+ if( eSecondSpeed != pInfo->meSecondSpeed )
+ nSecondSpeedSet = ATTR_MIXED;
+
+ if( bSecondSoundOn != pInfo->mbSecondSoundOn )
+ nSecondSoundOnSet = ATTR_MIXED;
+
+ if( bSecondPlayFull != pInfo->mbSecondPlayFull )
+ nSecondPlayFullSet = ATTR_MIXED;
+ }
+ else
+ {
+ if (nAnimationSet == ATTR_SET && bActive)
+ nAnimationSet = ATTR_MIXED;
+
+ if (nEffectSet == ATTR_SET && eEffect != presentation::AnimationEffect_NONE)
+ nEffectSet = ATTR_MIXED;
+
+ if (nTextEffectSet == ATTR_SET && eTextEffect != presentation::AnimationEffect_NONE)
+ nTextEffectSet = ATTR_MIXED;
+
+ if (nSpeedSet == ATTR_SET)
+ nSpeedSet = ATTR_MIXED;
+
+ if (nFadeOutSet == ATTR_SET && bFadeOut)
+ nFadeOutSet = ATTR_MIXED;
+
+ if (nFadeColorSet == ATTR_SET)
+ nFadeColorSet = ATTR_MIXED;
+
+ if (nInvisibleSet == ATTR_SET && bInvisible)
+ nInvisibleSet = ATTR_MIXED;
+
+ if (nSoundOnSet == ATTR_SET && bSoundOn)
+ nSoundOnSet = ATTR_MIXED;
+
+ if (nSoundFileSet == ATTR_SET)
+ nSoundFileSet = ATTR_MIXED;
+
+ if (nPlayFullSet == ATTR_SET && bPlayFull)
+ nPlayFullSet = ATTR_MIXED;
+
+ if (nClickActionSet == ATTR_SET && eClickAction != presentation::ClickAction_NONE)
+ nClickActionSet = ATTR_MIXED;
+
+ if (nBookmarkSet == ATTR_SET)
+ nBookmarkSet = ATTR_MIXED;
+
+ if (nSecondEffectSet == ATTR_SET && eSecondEffect != presentation::AnimationEffect_NONE)
+ nSecondEffectSet = ATTR_MIXED;
+
+ if (nSecondSpeedSet == ATTR_SET)
+ nSecondSpeedSet = ATTR_MIXED;
+
+ if (nSecondSoundOnSet == ATTR_SET && bSecondSoundOn)
+ nSecondSoundOnSet = ATTR_MIXED;
+
+ if (nSecondPlayFullSet == ATTR_SET && bSecondPlayFull)
+ nSecondPlayFullSet = ATTR_MIXED;
+ }
+ }
+
+ /* Exactly two objects with path effect?
+ Then, only the animation info at the moved object is valid. */
+ if (nCount == 2)
+ {
+ SdrObject* pObject1 = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ SdrObject* pObject2 = rMarkList.GetMark(1)->GetMarkedSdrObj();
+ SdrObjKind eKind1 = pObject1->GetObjIdentifier();
+ SdrObjKind eKind2 = pObject2->GetObjIdentifier();
+ SdAnimationInfo* pInfo1 = SdDrawDocument::GetAnimationInfo(pObject1);
+ SdAnimationInfo* pInfo2 = SdDrawDocument::GetAnimationInfo(pObject2);
+ pInfo = nullptr;
+
+ if (pObject1->GetObjInventor() == SdrInventor::Default &&
+ ((eKind1 == SdrObjKind::Line) || // 2 point line
+ (eKind1 == SdrObjKind::PolyLine) || // Polygon
+ (eKind1 == SdrObjKind::PathLine)) && // Bezier curve
+ (pInfo2 && pInfo2->meEffect == presentation::AnimationEffect_PATH))
+ {
+ pInfo = pInfo2;
+ }
+
+ if (pObject2->GetObjInventor() == SdrInventor::Default &&
+ ((eKind2 == SdrObjKind::Line) || // 2 point line
+ (eKind2 == SdrObjKind::PolyLine) || // Polygon
+ (eKind2 == SdrObjKind::PathLine)) && // Bezier curve
+ (pInfo1 && pInfo1->meEffect == presentation::AnimationEffect_PATH))
+ {
+ pInfo = pInfo1;
+ }
+
+ if (pInfo)
+ {
+ bActive = pInfo->mbActive; nAnimationSet = ATTR_SET;
+ eEffect = pInfo->meEffect; nEffectSet = ATTR_SET;
+ eTextEffect = pInfo->meTextEffect; nTextEffectSet = ATTR_SET;
+ eSpeed = pInfo->meSpeed; nSpeedSet = ATTR_SET;
+ bFadeOut = pInfo->mbDimPrevious; nFadeOutSet = ATTR_SET;
+ aFadeColor = pInfo->maDimColor; nFadeColorSet = ATTR_SET;
+ bInvisible = pInfo->mbDimHide; nInvisibleSet = ATTR_SET;
+ bSoundOn = pInfo->mbSoundOn; nSoundOnSet = ATTR_SET;
+ aSound = pInfo->maSoundFile; nSoundFileSet = ATTR_SET;
+ bPlayFull = pInfo->mbPlayFull; nPlayFullSet = ATTR_SET;
+ eClickAction = pInfo->meClickAction; nClickActionSet = ATTR_SET;
+ aBookmark = pInfo->GetBookmark(); nBookmarkSet = ATTR_SET;
+ eSecondEffect = pInfo->meSecondEffect; nSecondEffectSet = ATTR_SET;
+ eSecondSpeed = pInfo->meSecondSpeed; nSecondSpeedSet = ATTR_SET;
+ bSecondSoundOn = pInfo->mbSecondSoundOn; nSecondSoundOnSet = ATTR_SET;
+ bSecondPlayFull = pInfo->mbSecondPlayFull; nSecondPlayFullSet = ATTR_SET;
+ }
+ }
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if(!pArgs)
+ {
+ // fill ItemSet for dialog
+ SfxItemSetFixed<ATTR_ANIMATION_START, ATTR_ACTION_END> aSet(mpDoc->GetPool());
+
+ // fill the set
+ if (nAnimationSet == ATTR_SET)
+ aSet.Put( SfxBoolItem( ATTR_ANIMATION_ACTIVE, bActive));
+ else if (nAnimationSet == ATTR_MIXED)
+ aSet.InvalidateItem(ATTR_ANIMATION_ACTIVE);
+ else
+ aSet.Put(SfxBoolItem(ATTR_ANIMATION_ACTIVE, false));
+
+ if (nEffectSet == ATTR_SET)
+ aSet.Put(SfxUInt16Item(ATTR_ANIMATION_EFFECT, static_cast<sal_uInt16>(eEffect)));
+ else if (nEffectSet == ATTR_MIXED)
+ aSet.InvalidateItem( ATTR_ANIMATION_EFFECT );
+ else
+ aSet.Put(SfxUInt16Item(ATTR_ANIMATION_EFFECT, sal_uInt16(presentation::AnimationEffect_NONE)));
+
+ if (nTextEffectSet == ATTR_SET)
+ aSet.Put(SfxUInt16Item(ATTR_ANIMATION_TEXTEFFECT, static_cast<sal_uInt16>(eTextEffect)));
+ else if (nTextEffectSet == ATTR_MIXED)
+ aSet.InvalidateItem( ATTR_ANIMATION_TEXTEFFECT );
+ else
+ aSet.Put(SfxUInt16Item(ATTR_ANIMATION_TEXTEFFECT, sal_uInt16(presentation::AnimationEffect_NONE)));
+
+ if (nSpeedSet == ATTR_SET)
+ aSet.Put(SfxUInt16Item(ATTR_ANIMATION_SPEED, static_cast<sal_uInt16>(eSpeed)));
+ else
+ aSet.InvalidateItem(ATTR_ANIMATION_SPEED);
+
+ if (nFadeOutSet == ATTR_SET)
+ aSet.Put(SfxBoolItem(ATTR_ANIMATION_FADEOUT, bFadeOut));
+ else if (nFadeOutSet == ATTR_MIXED)
+ aSet.InvalidateItem(ATTR_ANIMATION_FADEOUT);
+ else
+ aSet.Put(SfxBoolItem(ATTR_ANIMATION_FADEOUT, false));
+
+ if (nFadeColorSet == ATTR_SET)
+ aSet.Put(SvxColorItem(aFadeColor, ATTR_ANIMATION_COLOR));
+ else if (nFadeColorSet == ATTR_MIXED)
+ aSet.InvalidateItem(ATTR_ANIMATION_COLOR);
+ else
+ aSet.Put(SvxColorItem(COL_LIGHTGRAY, ATTR_ANIMATION_COLOR));
+
+ if (nInvisibleSet == ATTR_SET)
+ aSet.Put(SfxBoolItem(ATTR_ANIMATION_INVISIBLE, bInvisible));
+ else if (nInvisibleSet == ATTR_MIXED)
+ aSet.InvalidateItem(ATTR_ANIMATION_INVISIBLE);
+ else
+ aSet.Put(SfxBoolItem(ATTR_ANIMATION_INVISIBLE, false));
+
+ if (nSoundOnSet == ATTR_SET)
+ aSet.Put(SfxBoolItem(ATTR_ANIMATION_SOUNDON, bSoundOn));
+ else if (nSoundOnSet == ATTR_MIXED)
+ aSet.InvalidateItem(ATTR_ANIMATION_SOUNDON);
+ else
+ aSet.Put(SfxBoolItem(ATTR_ANIMATION_SOUNDON, false));
+
+ if (nSoundFileSet == ATTR_SET)
+ aSet.Put(SfxStringItem(ATTR_ANIMATION_SOUNDFILE, aSound));
+ else
+ aSet.InvalidateItem(ATTR_ANIMATION_SOUNDFILE);
+
+ if (nPlayFullSet == ATTR_SET)
+ aSet.Put(SfxBoolItem(ATTR_ANIMATION_PLAYFULL, bPlayFull));
+ else if (nPlayFullSet == ATTR_MIXED)
+ aSet.InvalidateItem(ATTR_ANIMATION_PLAYFULL);
+ else
+ aSet.Put(SfxBoolItem(ATTR_ANIMATION_PLAYFULL, false));
+
+ if (nClickActionSet == ATTR_SET)
+ aSet.Put(SfxUInt16Item(ATTR_ACTION, static_cast<sal_uInt16>(eClickAction)));
+ else if (nClickActionSet == ATTR_MIXED)
+ aSet.InvalidateItem(ATTR_ACTION);
+ else
+ aSet.Put(SfxUInt16Item(ATTR_ACTION, sal_uInt16(presentation::ClickAction_NONE)));
+
+ if (nBookmarkSet == ATTR_SET)
+ aSet.Put(SfxStringItem(ATTR_ACTION_FILENAME, aBookmark));
+ else
+ aSet.InvalidateItem(ATTR_ACTION_FILENAME);
+
+ if (nSecondEffectSet == ATTR_SET)
+ aSet.Put(SfxUInt16Item(ATTR_ACTION_EFFECT, static_cast<sal_uInt16>(eSecondEffect)));
+ else if (nSecondEffectSet == ATTR_MIXED)
+ aSet.InvalidateItem( ATTR_ACTION_EFFECT );
+ else
+ aSet.Put(SfxUInt16Item(ATTR_ACTION_EFFECT, sal_uInt16(presentation::AnimationEffect_NONE)));
+
+ if (nSecondSpeedSet == ATTR_SET)
+ aSet.Put(SfxUInt16Item(ATTR_ACTION_EFFECTSPEED, static_cast<sal_uInt16>(eSecondSpeed)));
+ else
+ aSet.InvalidateItem(ATTR_ACTION_EFFECTSPEED);
+
+ if (nSecondSoundOnSet == ATTR_SET)
+ aSet.Put(SfxBoolItem(ATTR_ACTION_SOUNDON, bSecondSoundOn));
+ else if (nSecondSoundOnSet == ATTR_MIXED)
+ aSet.InvalidateItem(ATTR_ACTION_SOUNDON);
+ else
+ aSet.Put(SfxBoolItem(ATTR_ACTION_SOUNDON, false));
+
+ if (nSecondPlayFullSet == ATTR_SET)
+ aSet.Put(SfxBoolItem(ATTR_ACTION_PLAYFULL, bSecondPlayFull));
+ else if (nSecondPlayFullSet == ATTR_MIXED)
+ aSet.InvalidateItem(ATTR_ACTION_PLAYFULL);
+ else
+ aSet.Put(SfxBoolItem(ATTR_ACTION_PLAYFULL, false));
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractDialog> pDlg( pFact->CreatSdActionDialog(mpViewShell->GetFrameWeld(), &aSet, mpView) );
+
+ short nResult = pDlg->Execute();
+
+ if( nResult != RET_OK )
+ return;
+
+ rReq.Done( *( pDlg->GetOutputItemSet() ) );
+ pArgs = rReq.GetArgs();
+ }
+
+ // evaluation of the ItemSets
+ if (pArgs->GetItemState(ATTR_ANIMATION_ACTIVE) == SfxItemState::SET)
+ {
+ bActive = static_cast<const SfxBoolItem&>(pArgs->Get(ATTR_ANIMATION_ACTIVE)).GetValue();
+ nAnimationSet = ATTR_SET;
+ }
+ else
+ nAnimationSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ANIMATION_EFFECT) == SfxItemState::SET)
+ {
+ eEffect = static_cast<presentation::AnimationEffect>(static_cast<const SfxUInt16Item&>( pArgs->
+ Get(ATTR_ANIMATION_EFFECT)).GetValue());
+ nEffectSet = ATTR_SET;
+ }
+ else
+ nEffectSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ANIMATION_TEXTEFFECT) == SfxItemState::SET)
+ {
+ eTextEffect = static_cast<presentation::AnimationEffect>(static_cast<const SfxUInt16Item&>( pArgs->
+ Get(ATTR_ANIMATION_TEXTEFFECT)).GetValue());
+ nTextEffectSet = ATTR_SET;
+ }
+ else
+ nTextEffectSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ANIMATION_SPEED) == SfxItemState::SET)
+ {
+ eSpeed = static_cast<presentation::AnimationSpeed>(static_cast<const SfxUInt16Item&>( pArgs->
+ Get(ATTR_ANIMATION_SPEED)).GetValue());
+ nSpeedSet = ATTR_SET;
+ }
+ else
+ nSpeedSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ANIMATION_FADEOUT) == SfxItemState::SET)
+ {
+ bFadeOut = static_cast<const SfxBoolItem&>(pArgs->Get(ATTR_ANIMATION_FADEOUT)).GetValue();
+ nFadeOutSet = ATTR_SET;
+ }
+ else
+ nFadeOutSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ANIMATION_INVISIBLE) == SfxItemState::SET)
+ {
+ bInvisible = static_cast<const SfxBoolItem&>(pArgs->Get(ATTR_ANIMATION_INVISIBLE)).GetValue();
+ nInvisibleSet = ATTR_SET;
+ }
+ else
+ nInvisibleSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ANIMATION_SOUNDON) == SfxItemState::SET)
+ {
+ bSoundOn = static_cast<const SfxBoolItem&>(pArgs->Get(ATTR_ANIMATION_SOUNDON)).GetValue();
+ nSoundOnSet = ATTR_SET;
+ }
+ else
+ nSoundOnSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ANIMATION_SOUNDFILE) == SfxItemState::SET)
+ {
+ aSound = static_cast<const SfxStringItem&>(pArgs->Get(ATTR_ANIMATION_SOUNDFILE)).GetValue();
+ nSoundFileSet = ATTR_SET;
+ }
+ else
+ nSoundFileSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ANIMATION_COLOR) == SfxItemState::SET)
+ {
+ aFadeColor = static_cast<const SvxColorItem&>(pArgs->Get(ATTR_ANIMATION_COLOR)).GetValue();
+ nFadeColorSet = ATTR_SET;
+ }
+ else
+ nFadeColorSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ANIMATION_PLAYFULL) == SfxItemState::SET)
+ {
+ bPlayFull = static_cast<const SfxBoolItem&>(pArgs->Get(ATTR_ANIMATION_PLAYFULL)).GetValue();
+ nPlayFullSet = ATTR_SET;
+ }
+ else
+ nPlayFullSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ACTION) == SfxItemState::SET)
+ {
+ eClickAction = static_cast<presentation::ClickAction>(static_cast<const SfxUInt16Item&>(pArgs->
+ Get(ATTR_ACTION)).GetValue());
+ nClickActionSet = ATTR_SET;
+ }
+ else
+ nClickActionSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ACTION_FILENAME) == SfxItemState::SET)
+ {
+ aBookmark = static_cast<const SfxStringItem&>(pArgs->
+ Get(ATTR_ACTION_FILENAME)).GetValue();
+ nBookmarkSet = ATTR_SET;
+ }
+ else
+ nBookmarkSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ACTION_EFFECT) == SfxItemState::SET)
+ {
+ eSecondEffect = static_cast<presentation::AnimationEffect>(static_cast<const SfxUInt16Item&>( pArgs->
+ Get(ATTR_ACTION_EFFECT)).GetValue());
+ nSecondEffectSet = ATTR_SET;
+ }
+ else
+ nSecondEffectSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ACTION_EFFECTSPEED) == SfxItemState::SET)
+ {
+ eSecondSpeed = static_cast<presentation::AnimationSpeed>(static_cast<const SfxUInt16Item&>( pArgs->
+ Get(ATTR_ACTION_EFFECTSPEED)).GetValue());
+ nSecondSpeedSet = ATTR_SET;
+ }
+ else
+ nSecondSpeedSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ACTION_SOUNDON) == SfxItemState::SET)
+ {
+ bSecondSoundOn = static_cast<const SfxBoolItem&>(pArgs->Get(ATTR_ACTION_SOUNDON)).GetValue();
+ nSecondSoundOnSet = ATTR_SET;
+ }
+ else
+ nSecondSoundOnSet = ATTR_MISSING;
+
+ if (pArgs->GetItemState(ATTR_ACTION_PLAYFULL) == SfxItemState::SET)
+ {
+ bSecondPlayFull = static_cast<const SfxBoolItem&>(pArgs->Get(ATTR_ACTION_PLAYFULL)).GetValue();
+ nSecondPlayFullSet = ATTR_SET;
+ }
+ else
+ nSecondPlayFullSet = ATTR_MISSING;
+
+ // if any attribute is chosen
+ if (!(nEffectSet == ATTR_SET ||
+ nTextEffectSet == ATTR_SET ||
+ nSpeedSet == ATTR_SET ||
+ nAnimationSet == ATTR_SET ||
+ nFadeOutSet == ATTR_SET ||
+ nFadeColorSet == ATTR_SET ||
+ nInvisibleSet == ATTR_SET ||
+ nSoundOnSet == ATTR_SET ||
+ nSoundFileSet == ATTR_SET ||
+ nPlayFullSet == ATTR_SET ||
+ nClickActionSet == ATTR_SET ||
+ nBookmarkSet == ATTR_SET ||
+ nSecondEffectSet == ATTR_SET ||
+ nSecondSpeedSet == ATTR_SET ||
+ nSecondSoundOnSet == ATTR_SET ||
+ nSecondPlayFullSet == ATTR_SET))
+ return;
+
+ // String for undo-group and list-action
+ OUString aComment(SdResId(STR_UNDO_ANIMATION));
+
+ // with 'following curves', we have an additional UndoAction
+ // therefore cling? here
+ pUndoMgr->EnterListAction(aComment, aComment, 0, mpViewShell->GetViewShellBase().GetViewShellId());
+
+ // create undo group
+ std::unique_ptr<SdUndoGroup> pUndoGroup(new SdUndoGroup(mpDoc));
+ pUndoGroup->SetComment(aComment);
+
+ // for the path effect, remember some stuff
+ SdrPathObj* pPath = nullptr;
+ if (eEffect == presentation::AnimationEffect_PATH && nEffectSet == ATTR_SET)
+ {
+ DBG_ASSERT(nCount == 2, "This effect expects two selected objects");
+ SdrObject* pObject1 = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ SdrObject* pObject2 = rMarkList.GetMark(1)->GetMarkedSdrObj();
+ SdrObjKind eKind1 = pObject1->GetObjIdentifier();
+ SdrObjKind eKind2 = pObject2->GetObjIdentifier();
+ SdrObject* pRunningObj = nullptr;
+
+ if (pObject1->GetObjInventor() == SdrInventor::Default &&
+ ((eKind1 == SdrObjKind::Line) || // 2 point line
+ (eKind1 == SdrObjKind::PolyLine) || // Polygon
+ (eKind1 == SdrObjKind::PathLine))) // Bezier curve
+ {
+ pPath = static_cast<SdrPathObj*>(pObject1);
+ pRunningObj = pObject2;
+ }
+
+ if (pObject2->GetObjInventor() == SdrInventor::Default &&
+ ((eKind2 == SdrObjKind::Line) || // 2 point line
+ (eKind2 == SdrObjKind::PolyLine) || // Polygon
+ (eKind2 == SdrObjKind::PathLine))) // Bezier curve
+ {
+ pPath = static_cast<SdrPathObj*>(pObject2);
+ pRunningObj = pObject1;
+ }
+
+ assert(pRunningObj && pPath && "no curve found");
+
+ // push the running object to the end of the curve
+ if (pRunningObj)
+ {
+ ::tools::Rectangle aCurRect(pRunningObj->GetLogicRect());
+ Point aCurCenter(aCurRect.Center());
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon = pPath->GetPathPoly();
+ sal_uInt32 nNoOfPolygons(rPolyPolygon.count());
+ const ::basegfx::B2DPolygon& aPolygon(rPolyPolygon.getB2DPolygon(nNoOfPolygons - 1));
+ sal_uInt32 nPoints(aPolygon.count());
+ const ::basegfx::B2DPoint aNewB2DCenter(aPolygon.getB2DPoint(nPoints - 1));
+ const Point aNewCenter(FRound(aNewB2DCenter.getX()), FRound(aNewB2DCenter.getY()));
+ Size aDistance(aNewCenter.X() - aCurCenter.X(), aNewCenter.Y() - aCurCenter.Y());
+ pRunningObj->Move(aDistance);
+
+ pUndoMgr->AddUndoAction(mpDoc->GetSdrUndoFactory().CreateUndoMoveObject( *pRunningObj, aDistance));
+ }
+ }
+
+ for (size_t nObject = 0; nObject < nCount; ++nObject)
+ {
+ SdrObject* pObject = rMarkList.GetMark(nObject)->GetMarkedSdrObj();
+
+ pInfo = SdDrawDocument::GetAnimationInfo(pObject);
+
+ bool bCreated = false;
+ if( !pInfo )
+ {
+ pInfo = SdDrawDocument::GetShapeUserData(*pObject,true);
+ bCreated = true;
+ }
+
+ // path object for 'following curves'?
+ if (eEffect == presentation::AnimationEffect_PATH && pObject == pPath)
+ {
+ SdAnimationPrmsUndoAction* pAction = new SdAnimationPrmsUndoAction
+ (mpDoc, pObject, bCreated);
+ pAction->SetActive(pInfo->mbActive, pInfo->mbActive);
+ pAction->SetEffect(pInfo->meEffect, pInfo->meEffect);
+ pAction->SetTextEffect(pInfo->meTextEffect, pInfo->meTextEffect);
+ pAction->SetSpeed(pInfo->meSpeed, pInfo->meSpeed);
+ pAction->SetDim(pInfo->mbDimPrevious, pInfo->mbDimPrevious);
+ pAction->SetDimColor(pInfo->maDimColor, pInfo->maDimColor);
+ pAction->SetDimHide(pInfo->mbDimHide, pInfo->mbDimHide);
+ pAction->SetSoundOn(pInfo->mbSoundOn, pInfo->mbSoundOn);
+ pAction->SetSound(pInfo->maSoundFile, pInfo->maSoundFile);
+ pAction->SetPlayFull(pInfo->mbPlayFull, pInfo->mbPlayFull);
+ pAction->SetClickAction(pInfo->meClickAction, pInfo->meClickAction);
+ pAction->SetBookmark(pInfo->GetBookmark(), pInfo->GetBookmark());
+ pAction->SetVerb(pInfo->mnVerb, pInfo->mnVerb);
+ pAction->SetSecondEffect(pInfo->meSecondEffect, pInfo->meSecondEffect);
+ pAction->SetSecondSpeed(pInfo->meSecondSpeed, pInfo->meSecondSpeed);
+ pAction->SetSecondSoundOn(pInfo->mbSecondSoundOn, pInfo->mbSecondSoundOn);
+ pAction->SetSecondPlayFull(pInfo->mbSecondPlayFull, pInfo->mbSecondPlayFull);
+ pUndoGroup->AddAction(pAction);
+
+ }
+ else
+ {
+
+ // create undo action with old and new sizes
+ SdAnimationPrmsUndoAction* pAction = new SdAnimationPrmsUndoAction
+ (mpDoc, pObject, bCreated);
+ pAction->SetActive(pInfo->mbActive, bActive);
+ pAction->SetEffect(pInfo->meEffect, eEffect);
+ pAction->SetTextEffect(pInfo->meTextEffect, eTextEffect);
+ pAction->SetSpeed(pInfo->meSpeed, eSpeed);
+ pAction->SetDim(pInfo->mbDimPrevious, bFadeOut);
+ pAction->SetDimColor(pInfo->maDimColor, aFadeColor);
+ pAction->SetDimHide(pInfo->mbDimHide, bInvisible);
+ pAction->SetSoundOn(pInfo->mbSoundOn, bSoundOn);
+ pAction->SetSound(pInfo->maSoundFile, aSound);
+ pAction->SetPlayFull(pInfo->mbPlayFull, bPlayFull);
+ pAction->SetClickAction(pInfo->meClickAction, eClickAction);
+ pAction->SetBookmark(pInfo->GetBookmark(), aBookmark);
+ pAction->SetVerb(pInfo->mnVerb, static_cast<sal_uInt16>(pInfo->GetBookmark().toInt32()) );
+ pAction->SetSecondEffect(pInfo->meSecondEffect, eSecondEffect);
+ pAction->SetSecondSpeed(pInfo->meSecondSpeed, eSecondSpeed);
+ pAction->SetSecondSoundOn(pInfo->mbSecondSoundOn, bSecondSoundOn);
+ pAction->SetSecondPlayFull(pInfo->mbSecondPlayFull,bSecondPlayFull);
+ pUndoGroup->AddAction(pAction);
+
+ // insert new values at info block of the object
+ if (nAnimationSet == ATTR_SET)
+ pInfo->mbActive = bActive;
+
+ if (nEffectSet == ATTR_SET)
+ pInfo->meEffect = eEffect;
+
+ if (nTextEffectSet == ATTR_SET)
+ pInfo->meTextEffect = eTextEffect;
+
+ if (nSpeedSet == ATTR_SET)
+ pInfo->meSpeed = eSpeed;
+
+ if (nFadeOutSet == ATTR_SET)
+ pInfo->mbDimPrevious = bFadeOut;
+
+ if (nFadeColorSet == ATTR_SET)
+ pInfo->maDimColor = aFadeColor;
+
+ if (nInvisibleSet == ATTR_SET)
+ pInfo->mbDimHide = bInvisible;
+
+ if (nSoundOnSet == ATTR_SET)
+ pInfo->mbSoundOn = bSoundOn;
+
+ if (nSoundFileSet == ATTR_SET)
+ pInfo->maSoundFile = aSound;
+
+ if (nPlayFullSet == ATTR_SET)
+ pInfo->mbPlayFull = bPlayFull;
+
+ if (nClickActionSet == ATTR_SET)
+ pInfo->meClickAction = eClickAction;
+
+ if (nBookmarkSet == ATTR_SET)
+ pInfo->SetBookmark( aBookmark );
+
+ if (nSecondEffectSet == ATTR_SET)
+ pInfo->meSecondEffect = eSecondEffect;
+
+ if (nSecondSpeedSet == ATTR_SET)
+ pInfo->meSecondSpeed = eSecondSpeed;
+
+ if (nSecondSoundOnSet == ATTR_SET)
+ pInfo->mbSecondSoundOn = bSecondSoundOn;
+
+ if (nSecondPlayFullSet == ATTR_SET)
+ pInfo->mbSecondPlayFull = bSecondPlayFull;
+
+ if (eClickAction == presentation::ClickAction_VERB)
+ pInfo->mnVerb = static_cast<sal_uInt16>(aBookmark.toInt32());
+ }
+ }
+ // Set the Undo Group in of the Undo Manager
+ pUndoMgr->AddUndoAction(std::move(pUndoGroup));
+ pUndoMgr->LeaveListAction();
+
+ // Model changed
+ mpDoc->SetChanged();
+ // not seen, therefore we do not need to invalidate at the bindings
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuolbull.cxx b/sd/source/ui/func/fuolbull.cxx
new file mode 100644
index 000000000..beb57db5b
--- /dev/null
+++ b/sd/source/ui/func/fuolbull.cxx
@@ -0,0 +1,340 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuolbull.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/eeitem.hxx>
+#include <sfx2/request.hxx>
+#include <editeng/numitem.hxx>
+#include <strings.hxx>
+
+#include <svx/svxids.hrc>
+#include <OutlineView.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <sdabstdlg.hxx>
+#include <svx/nbdtmg.hxx>
+#include <svx/nbdtmgfact.hxx>
+#include <svx/svdoutl.hxx>
+#include <memory>
+
+using namespace svx::sidebar;
+namespace sd {
+
+FuBulletAndPosition::FuBulletAndPosition(ViewShell* pViewShell, ::sd::Window* pWindow,
+ ::sd::View* pView, SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewShell, pWindow, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuBulletAndPosition::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuBulletAndPosition( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuBulletAndPosition::DoExecute( SfxRequest& rReq )
+{
+ const sal_uInt16 nSId = rReq.GetSlot();
+ if ( nSId == FN_SVX_SET_BULLET || nSId == FN_SVX_SET_NUMBER )
+ {
+ SetCurrentBulletsNumbering(rReq);
+ return;
+ }
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ const SfxStringItem* pPageItem = SfxItemSet::GetItem<SfxStringItem>(pArgs, FN_PARAM_1, false);
+
+ if ( pArgs && !pPageItem )
+ {
+ /* not direct to pOlView; therefore, SdDrawView::SetAttributes can catch
+ changes to master page and redirect to a template */
+ mpView->SetAttributes(*pArgs);
+ return;
+ }
+
+ // fill ItemSet for Dialog
+ SfxItemSet aEditAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aEditAttr );
+
+ SfxItemSetFixed<EE_PARA_NUMBULLET, EE_PARA_BULLET> aNewAttr( mpViewShell->GetPool() );
+ aNewAttr.Put( aEditAttr, false );
+
+ auto pView = mpView;
+
+ // create and execute dialog
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxBulletAndPositionDlg> pDlg(pFact->CreateSvxBulletAndPositionDlg(mpViewShell->GetFrameWeld(), &aNewAttr, mpView));
+ sal_uInt16 nResult = pDlg->Execute();
+
+ if( nResult == RET_OK )
+ {
+ OutlinerView* pOLV = pView->GetTextEditOutlinerView();
+
+ std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard;
+
+ if (OutlineView* pOutlineView = dynamic_cast<OutlineView*>(pView))
+ {
+ pOLV = pOutlineView->GetViewByWindow(mpViewShell->GetActiveWindow());
+ aGuard.reset(new OutlineViewModelChangeGuard(*pOutlineView));
+ }
+
+ if( pOLV )
+ pOLV->EnsureNumberingIsOn();
+
+ const SfxItemSet pOutputSet( *pDlg->GetOutputItemSet( &aNewAttr ) );
+ pView->SetAttributes(pOutputSet, /*bReplaceAll=*/false, /*bSlide*/ pDlg->IsSlideScope(), /*bMaster=*/pDlg->IsApplyToMaster());
+ }
+
+ rReq.Done();
+}
+
+void FuBulletAndPosition::SetCurrentBulletsNumbering(SfxRequest& rReq)
+{
+ if (!mpDoc || !mpView)
+ return;
+
+ const sal_uInt16 nSId = rReq.GetSlot();
+ if ( nSId != FN_SVX_SET_BULLET && nSId != FN_SVX_SET_NUMBER )
+ {
+ // unexpected SfxRequest
+ return;
+ }
+
+ const SfxUInt16Item* pItem = rReq.GetArg<SfxUInt16Item>(nSId);
+ if ( !pItem )
+ {
+ rReq.Done();
+ return;
+ }
+
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aNewAttr( mpViewShell->GetPool() );
+ {
+ SfxItemSet aEditAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aEditAttr );
+ aNewAttr.Put( aEditAttr, false );
+ }
+
+ const DrawViewShell* pDrawViewShell = dynamic_cast< DrawViewShell* >(mpViewShell);
+ //Init bullet level in "Customize" tab page in bullet dialog in master page view
+ const bool bInMasterView = pDrawViewShell && pDrawViewShell->GetEditMode() == EditMode::MasterPage;
+ if ( bInMasterView )
+ {
+ SdrObject* pObj = mpView->GetTextEditObject();
+ if( pObj && pObj->GetObjIdentifier() == SdrObjKind::OutlineText )
+ {
+ const sal_uInt16 nLevel = mpView->GetSelectionLevel();
+ if( nLevel != 0xFFFF )
+ {
+ //save the itemset value
+ SfxItemSet aStoreSet( aNewAttr );
+ aNewAttr.ClearItem();
+ //extend range
+ aNewAttr.MergeRange( SID_PARAM_NUM_PRESET, SID_PARAM_CUR_NUM_LEVEL );
+ aNewAttr.Put( aStoreSet );
+ //put current level user selected
+ aNewAttr.Put( SfxUInt16Item( SID_PARAM_CUR_NUM_LEVEL, nLevel ) );
+ }
+ }
+ }
+
+ sal_uInt16 nIdx = pItem->GetValue();
+ bool bToggle = false;
+ if( nIdx == sal_uInt16(0xFFFF) )
+ {
+ // If the nIdx is (sal_uInt16)0xFFFF, means set bullet status to on/off
+ nIdx = 1;
+ bToggle = true;
+ }
+ nIdx--;
+
+ TypedWhichId<SvxNumBulletItem> nNumItemId = SID_ATTR_NUMBERING_RULE;
+ const SfxPoolItem* pTmpItem = GetNumBulletItem( aNewAttr, nNumItemId );
+ std::unique_ptr<SvxNumRule> pNumRule;
+ if ( pTmpItem )
+ {
+ pNumRule.reset(new SvxNumRule(static_cast<const SvxNumBulletItem*>(pTmpItem)->GetNumRule()));
+
+ // get numbering rule corresponding to <nIdx> and apply the needed number formats to <pNumRule>
+ NBOTypeMgrBase* pNumRuleMgr =
+ NBOutlineTypeMgrFact::CreateInstance(
+ nSId == FN_SVX_SET_BULLET ? NBOType::Bullets : NBOType::Numbering );
+ if ( pNumRuleMgr )
+ {
+ sal_uInt16 nActNumLvl = sal_uInt16(0xFFFF);
+ if(const SfxUInt16Item* pNumLevelItem = aNewAttr.GetItemIfSet(SID_PARAM_CUR_NUM_LEVEL, false))
+ nActNumLvl = pNumLevelItem->GetValue();
+
+ pNumRuleMgr->SetItems(&aNewAttr);
+ SvxNumRule aTmpRule( *pNumRule );
+ if ( nSId == FN_SVX_SET_BULLET && bToggle && nIdx==0 )
+ {
+ // for toggling bullets get default numbering rule
+ pNumRuleMgr->ApplyNumRule( aTmpRule, nIdx, nActNumLvl, true );
+ }
+ else
+ {
+ pNumRuleMgr->ApplyNumRule( aTmpRule, nIdx, nActNumLvl );
+ }
+
+ sal_uInt16 nMask = 1;
+ for(sal_uInt16 i = 0; i < pNumRule->GetLevelCount(); i++)
+ {
+ if(nActNumLvl & nMask)
+ {
+ const SvxNumberFormat& aFmt(aTmpRule.GetLevel(i));
+ pNumRule->SetLevel(i, aFmt);
+ }
+ nMask <<= 1;
+ }
+ }
+ }
+
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+ std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard;
+ if (OutlineView* pView = dynamic_cast<OutlineView*>(mpView))
+ {
+ pOLV = pView->GetViewByWindow(mpViewShell->GetActiveWindow());
+ aGuard.reset(new OutlineViewModelChangeGuard(*pView));
+ }
+
+ SdrOutliner* pOwner = bInMasterView ? mpView->GetTextEditOutliner() : nullptr;
+ const bool bOutlinerUndoEnabled = pOwner && !pOwner->IsInUndo() && pOwner->IsUndoEnabled();
+ SdrModel* pSdrModel = bInMasterView ? mpView->GetModel() : nullptr;
+ const bool bModelUndoEnabled = pSdrModel && pSdrModel->IsUndoEnabled();
+
+ if ( bOutlinerUndoEnabled )
+ {
+ pOwner->UndoActionStart( OLUNDO_ATTR );
+ }
+ else if ( bModelUndoEnabled )
+ {
+ pSdrModel->BegUndo();
+ }
+
+ if ( pOLV )
+ {
+ pOLV->ToggleBulletsNumbering( bToggle, nSId == FN_SVX_SET_BULLET, bInMasterView ? nullptr : pNumRule.get() );
+ }
+ else
+ {
+ mpView->ChangeMarkedObjectsBulletsNumbering( bToggle, nSId == FN_SVX_SET_BULLET, bInMasterView ? nullptr : pNumRule.get() );
+ }
+
+ if (bInMasterView && pNumRule)
+ {
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aSetAttr( mpViewShell->GetPool() );
+ aSetAttr.Put(SvxNumBulletItem( *pNumRule, nNumItemId ));
+ mpView->SetAttributes(aSetAttr);
+ }
+
+ if( bOutlinerUndoEnabled )
+ {
+ pOwner->UndoActionEnd();
+ }
+ else if ( bModelUndoEnabled )
+ {
+ pSdrModel->EndUndo();
+ }
+
+ pNumRule.reset();
+ rReq.Done();
+}
+
+const SvxNumBulletItem* FuBulletAndPosition::GetNumBulletItem(SfxItemSet& aNewAttr, TypedWhichId<SvxNumBulletItem>& nNumItemId)
+{
+ const SvxNumBulletItem* pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false);
+
+ if(pTmpItem)
+ return pTmpItem;
+
+ nNumItemId = aNewAttr.GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE);
+ pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false);
+ if (pTmpItem)
+ return pTmpItem;
+
+ bool bOutliner = false;
+ bool bTitle = false;
+
+ if( mpView )
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ for(size_t nNum = 0; nNum < nCount; ++nNum)
+ {
+ SdrObject* pObj = rMarkList.GetMark(nNum)->GetMarkedSdrObj();
+ if( pObj->GetObjInventor() == SdrInventor::Default )
+ {
+ switch(pObj->GetObjIdentifier())
+ {
+ case SdrObjKind::TitleText:
+ bTitle = true;
+ break;
+ case SdrObjKind::OutlineText:
+ bOutliner = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ const SvxNumBulletItem *pItem = nullptr;
+ if(bOutliner)
+ {
+ SfxStyleSheetBasePool* pSSPool = mpView->GetDocSh()->GetStyleSheetPool();
+ SfxStyleSheetBase* pFirstStyleSheet = pSSPool->Find( STR_LAYOUT_OUTLINE + " 1", SfxStyleFamily::Pseudo);
+ if( pFirstStyleSheet )
+ pItem = pFirstStyleSheet->GetItemSet().GetItemIfSet(EE_PARA_NUMBULLET, false);
+ }
+
+ if( pItem == nullptr )
+ pItem = aNewAttr.GetPool()->GetSecondaryPool()->GetPoolDefaultItem(EE_PARA_NUMBULLET);
+
+ //DBG_ASSERT( pItem, "No EE_PARA_NUMBULLET in the Pool!" );
+
+ aNewAttr.Put(pItem->CloneSetWhich(EE_PARA_NUMBULLET));
+
+ if(bTitle && aNewAttr.GetItemState(EE_PARA_NUMBULLET) == SfxItemState::SET )
+ {
+ const SvxNumBulletItem* pBulletItem = aNewAttr.GetItem(EE_PARA_NUMBULLET);
+ const SvxNumRule& rLclRule = pBulletItem->GetNumRule();
+ SvxNumRule aNewRule( rLclRule );
+ aNewRule.SetFeatureFlag( SvxNumRuleFlags::NO_NUMBERS );
+
+ SvxNumBulletItem aNewItem( std::move(aNewRule), EE_PARA_NUMBULLET );
+ aNewAttr.Put(aNewItem);
+ }
+
+ pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false);
+ return pTmpItem;
+}
+
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuoltext.cxx b/sd/source/ui/func/fuoltext.cxx
new file mode 100644
index 000000000..fe64cac47
--- /dev/null
+++ b/sd/source/ui/func/fuoltext.cxx
@@ -0,0 +1,305 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuoltext.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/flditem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/dispatch.hxx>
+#include <tools/debug.hxx>
+#include <svl/stritem.hxx>
+
+#include <svx/svxids.hrc>
+#include <app.hrc>
+#include <OutlineView.hxx>
+#include <Window.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <OutlineViewShell.hxx>
+
+#include <memory>
+
+namespace sd {
+
+const sal_uInt16 SidArray[] = {
+ SID_STYLE_FAMILY2,
+ SID_STYLE_FAMILY3,
+ SID_STYLE_FAMILY5,
+ SID_STYLE_UPDATE_BY_EXAMPLE,
+ SID_CUT,
+ SID_COPY,
+ SID_PASTE,
+ SID_SELECTALL,
+ SID_ATTR_CHAR_FONT,
+ SID_ATTR_CHAR_POSTURE,
+ SID_ATTR_CHAR_WEIGHT,
+ SID_ATTR_CHAR_SHADOWED,
+ SID_ATTR_CHAR_STRIKEOUT,
+ SID_ATTR_CHAR_UNDERLINE,
+ SID_ATTR_CHAR_FONTHEIGHT,
+ SID_ATTR_CHAR_COLOR,
+ SID_ATTR_CHAR_KERNING,
+ SID_OUTLINE_UP,
+ SID_OUTLINE_DOWN,
+ SID_OUTLINE_LEFT,
+ SID_OUTLINE_RIGHT,
+ //SID_OUTLINE_FORMAT,
+ SID_OUTLINE_COLLAPSE_ALL,
+ //SID_OUTLINE_BULLET,
+ SID_OUTLINE_COLLAPSE,
+ SID_OUTLINE_EXPAND_ALL,
+ SID_OUTLINE_EXPAND,
+ SID_SET_SUPER_SCRIPT,
+ SID_SET_SUB_SCRIPT,
+ SID_HYPERLINK_GETLINK,
+ SID_DEC_INDENT,
+ SID_INC_INDENT,
+ SID_PARASPACE_INCREASE,
+ SID_PARASPACE_DECREASE,
+ SID_SCALE,
+ SID_STATUS_PAGE,
+ SID_STATUS_LAYOUT,
+ SID_EXPAND_PAGE,
+ SID_SUMMARY_PAGE,
+ 0 };
+
+
+FuOutlineText::FuOutlineText(ViewShell* pViewShell, ::sd::Window* pWindow,
+ ::sd::View* pView, SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewShell, pWindow, pView, pDoc, rReq),
+ pOutlineViewShell (static_cast<OutlineViewShell*>(pViewShell)),
+ pOutlineView (static_cast<OutlineView*>(pView))
+{
+}
+
+/**
+ * forward to OutlinerView
+ */
+bool FuOutlineText::Command(const CommandEvent& rCEvt)
+{
+ bool bResult = false;
+
+ OutlinerView* pOlView =
+ static_cast<OutlineView*>(mpView)->GetViewByWindow(mpWindow);
+ DBG_ASSERT (pOlView, "no OutlineView found");
+
+ if (pOlView)
+ {
+ pOlView->Command(rCEvt); // unfortunately, we do not get a return value
+ bResult = true;
+ }
+ return bResult;
+}
+
+
+rtl::Reference<FuPoor> FuOutlineText::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuOutlineText( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute( rReq );
+ return xFunc;
+}
+
+bool FuOutlineText::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ mpWindow->GrabFocus();
+
+ bool bReturn = pOutlineView->GetViewByWindow(mpWindow)->MouseButtonDown(rMEvt);
+
+ if (bReturn)
+ {
+ // Now the attributes of the current text position can be different
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArray );
+ }
+ else
+ {
+ bReturn = FuPoor::MouseButtonDown(rMEvt);
+ }
+
+ return bReturn;
+}
+
+bool FuOutlineText::MouseMove(const MouseEvent& rMEvt)
+{
+ bool bReturn = pOutlineView->GetViewByWindow(mpWindow)->MouseMove(rMEvt);
+
+ if (!bReturn)
+ {
+ bReturn = FuPoor::MouseMove(rMEvt);
+ }
+
+ return bReturn;
+}
+
+bool FuOutlineText::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bReturn = pOutlineView->GetViewByWindow(mpWindow)->MouseButtonUp(rMEvt);
+
+ if (bReturn)
+ {
+ // Now the attributes of the current text position can be different
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArray );
+ }
+ else
+ {
+ const SvxFieldItem* pFieldItem = pOutlineView->GetViewByWindow( mpWindow )->GetFieldUnderMousePointer();
+ if( pFieldItem )
+ {
+ const SvxFieldData* pField = pFieldItem->GetField();
+
+ if( auto pURLField = dynamic_cast< const SvxURLField *>( pField ) )
+ {
+ bReturn = true;
+ mpWindow->ReleaseMouse();
+ SfxStringItem aStrItem( SID_FILE_NAME, pURLField->GetURL() );
+ SfxStringItem aReferer( SID_REFERER, mpDocSh->GetMedium()->GetName() );
+ SfxBoolItem aBrowseItem( SID_BROWSE, true );
+ SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
+
+ if ( rMEvt.IsMod1() )
+ {
+ // open in new frame
+ pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aStrItem, &aBrowseItem, &aReferer });
+ }
+ else
+ {
+ // open in current frame
+ SfxFrameItem aFrameItem( SID_DOCFRAME, pFrame );
+ pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
+ }
+ }
+ }
+ }
+
+ if( !bReturn )
+ bReturn = FuPoor::MouseButtonUp(rMEvt);
+
+ return bReturn;
+}
+
+/**
+ * Process keyboard input
+ * @returns sal_True if a KeyEvent is being processed, sal_False otherwise
+ */
+bool FuOutlineText::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bReturn = false;
+
+ sal_uInt16 nKeyGroup = rKEvt.GetKeyCode().GetGroup();
+ if( !mpDocSh->IsReadOnly() || nKeyGroup == KEYGROUP_CURSOR )
+ {
+ mpWindow->GrabFocus();
+
+ std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard;
+ if( (nKeyGroup != KEYGROUP_CURSOR) && (nKeyGroup != KEYGROUP_FKEYS) )
+ aGuard.reset( new OutlineViewModelChangeGuard( *pOutlineView ) );
+
+ bReturn = pOutlineView->GetViewByWindow(mpWindow)->PostKeyEvent(rKEvt);
+
+ if (bReturn)
+ {
+ UpdateForKeyPress (rKEvt);
+ }
+ else
+ {
+ bReturn = FuPoor::KeyInput(rKEvt);
+ }
+ }
+
+ return bReturn;
+}
+
+void FuOutlineText::UpdateForKeyPress (const KeyEvent& rEvent)
+{
+ // Attributes at the current text position may have changed.
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate(SidArray);
+
+ bool bUpdatePreview = true;
+ switch (rEvent.GetKeyCode().GetCode())
+ {
+ // When just the cursor has been moved the preview only changes when
+ // it moved to entries of another page. To prevent unnecessary
+ // updates we check this here. This is an early rejection test, so
+ // missing a key is not a problem.
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ case KEY_HOME:
+ case KEY_END:
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN:
+ {
+ SdPage* pCurrentPage = pOutlineViewShell->GetActualPage();
+ bUpdatePreview = (pCurrentPage != pOutlineViewShell->GetActualPage());
+ }
+ break;
+ }
+ if (bUpdatePreview)
+ pOutlineViewShell->UpdatePreview (pOutlineViewShell->GetActualPage());
+}
+
+/**
+ * Cut object to clipboard
+ */
+void FuOutlineText::DoCut()
+{
+ pOutlineView->GetViewByWindow(mpWindow)->Cut();
+}
+
+/**
+ * Copy object to clipboard
+ */
+void FuOutlineText::DoCopy()
+{
+ pOutlineView->GetViewByWindow(mpWindow)->Copy();
+}
+
+/**
+ * Paste object from clipboard
+ */
+void FuOutlineText::DoPaste()
+{
+ pOutlineView->GetViewByWindow(mpWindow)->PasteSpecial();
+}
+
+/**
+ * Paste object as unformatted text from clipboard
+ */
+void FuOutlineText::DoPasteUnformatted()
+{
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( mpViewShell->GetActiveWindow() ) );
+ if (aDataHelper.GetTransferable().is())
+ {
+ OUString aText;
+ if (aDataHelper.GetString(SotClipboardFormatId::STRING, aText))
+ pOutlineView->GetViewByWindow(mpWindow)->InsertText(aText);
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fupage.cxx b/sd/source/ui/func/fupage.cxx
new file mode 100644
index 000000000..5427e6b7d
--- /dev/null
+++ b/sd/source/ui/func/fupage.cxx
@@ -0,0 +1,648 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fupage.hxx>
+
+// arrange Tab-Page
+
+#include <sfx2/sfxdlg.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/svxids.hrc>
+#include <svl/itempool.hxx>
+#include <svl/grabbagitem.hxx>
+#include <sfx2/request.hxx>
+#include <vcl/prntypes.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <stlsheet.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <svx/graphichelper.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <svx/sdr/properties/properties.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/pbinitem.hxx>
+#include <sfx2/opengrf.hxx>
+#include <sal/log.hxx>
+
+#include <strings.hrc>
+#include <sdpage.hxx>
+#include <View.hxx>
+#include <Window.hxx>
+#include <pres.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <DrawViewShell.hxx>
+#include <app.hrc>
+#include <unchss.hxx>
+#include <undoback.hxx>
+#include <sdabstdlg.hxx>
+#include <sdresid.hxx>
+
+#include <memory>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+// 50 cm 28350
+// adapted from writer
+#define MAXHEIGHT 28350
+#define MAXWIDTH 28350
+
+
+static void mergeItemSetsImpl( SfxItemSet& rTarget, const SfxItemSet& rSource )
+{
+ const WhichRangesContainer& rRanges = rSource.GetRanges();
+ sal_uInt16 p1, p2;
+ for (sal_Int32 i = 0; i < rRanges.size(); ++i)
+ {
+ p1 = rRanges[i].first;
+ p2 = rRanges[i].second;
+
+ // make ranges discrete
+ while(i < rRanges.size()-1 && (rRanges[i+1].first - p2 == 1))
+ {
+ p2 = rRanges[i+1].second;
+ ++i;
+ }
+ rTarget.MergeRange( p1, p2 );
+ }
+
+ rTarget.Put(rSource);
+}
+
+FuPage::FuPage( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView,
+ SdDrawDocument* pDoc, SfxRequest& rReq )
+: FuPoor(pViewSh, pWin, pView, pDoc, rReq),
+ mrReq(rReq),
+ mpArgs( rReq.GetArgs() ),
+ mbPageBckgrdDeleted( false ),
+ mbMasterPage( false ),
+ mbDisplayBackgroundTabPage( true ),
+ mpPage(nullptr),
+ mpDrawViewShell(nullptr)
+{
+}
+
+rtl::Reference<FuPoor> FuPage::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuPage( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuPage::DoExecute(SfxRequest& rReq)
+{
+ mpDrawViewShell = dynamic_cast<DrawViewShell*>(mpViewShell);
+ DBG_ASSERT( mpDrawViewShell, "sd::FuPage::FuPage(), called without a current DrawViewShell!" );
+
+ if( mpDrawViewShell )
+ {
+ mbMasterPage = mpDrawViewShell->GetEditMode() == EditMode::MasterPage;
+ // we don't really want to format page background with SID_ATTR_PAGE[_SIZE] slots
+ mbDisplayBackgroundTabPage = ( mpDrawViewShell->GetPageKind() == PageKind::Standard) &&
+ ( nSlotId != SID_ATTR_PAGE_SIZE) && ( nSlotId != SID_ATTR_PAGE );
+ mpPage = mpDrawViewShell->getCurrentPage();
+ }
+
+ if( !mpPage )
+ return;
+
+ // if there are no arguments given, open the dialog
+ if (!mpArgs || mpArgs->GetItemState(SID_SELECT_BACKGROUND) == SfxItemState::SET)
+ {
+ mpView->SdrEndTextEdit();
+ mpArgs = ExecuteDialog(mpWindow ? mpWindow->GetFrameWeld() : nullptr, rReq);
+ }
+
+ // if we now have arguments, apply them to current page
+ if( mpArgs )
+ {
+ ApplyItemSet( mpArgs );
+ }
+}
+
+FuPage::~FuPage()
+{
+}
+
+void FuPage::Activate()
+{
+}
+
+void FuPage::Deactivate()
+{
+}
+
+void MergePageBackgroundFilling(SdPage *pPage, SdStyleSheet *pStyleSheet, bool bMasterPage, SfxItemSet& rMergedAttr)
+{
+ if (bMasterPage)
+ {
+ if (pStyleSheet)
+ mergeItemSetsImpl(rMergedAttr, pStyleSheet->GetItemSet());
+ }
+ else
+ {
+ // Only this page, get attributes for background fill
+ const SfxItemSet& rBackgroundAttributes = pPage->getSdrPageProperties().GetItemSet();
+
+ if(drawing::FillStyle_NONE != rBackgroundAttributes.Get(XATTR_FILLSTYLE).GetValue())
+ {
+ // page attributes are used, take them
+ rMergedAttr.Put(rBackgroundAttributes);
+ }
+ else
+ {
+ if(pStyleSheet
+ && drawing::FillStyle_NONE != pStyleSheet->GetItemSet().Get(XATTR_FILLSTYLE).GetValue())
+ {
+ // if the page has no fill style, use the settings from the
+ // background stylesheet (if used)
+ mergeItemSetsImpl(rMergedAttr, pStyleSheet->GetItemSet());
+ }
+ else
+ {
+ // no fill style from page, start with no fill style
+ rMergedAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ }
+ }
+}
+
+const SfxItemSet* FuPage::ExecuteDialog(weld::Window* pParent, const SfxRequest& rReq)
+{
+ if (!mpDrawViewShell)
+ return nullptr;
+
+ SfxItemSetFixed<
+ XATTR_FILL_FIRST, XATTR_FILL_LAST,
+ EE_PARA_WRITINGDIR, EE_PARA_WRITINGDIR,
+ SID_ATTR_BORDER_OUTER, SID_ATTR_BORDER_OUTER,
+ SID_ATTR_BORDER_SHADOW, SID_ATTR_BORDER_SHADOW,
+ SID_ATTR_PAGE, SID_ATTR_PAGE_SHARED,
+ SID_ATTR_CHAR_GRABBAG, SID_ATTR_CHAR_GRABBAG,
+ SID_ATTR_PAGE_COLOR, SID_ATTR_PAGE_FILLSTYLE
+ > aNewAttr(mpDoc->GetPool());
+ // Keep it sorted
+ aNewAttr.MergeRange(mpDoc->GetPool().GetWhich(SID_ATTR_LRSPACE),
+ mpDoc->GetPool().GetWhich(SID_ATTR_ULSPACE));
+
+ // Retrieve additional data for dialog
+
+ SvxShadowItem aShadowItem(SID_ATTR_BORDER_SHADOW);
+ aNewAttr.Put( aShadowItem );
+ SvxBoxItem aBoxItem( SID_ATTR_BORDER_OUTER );
+ aNewAttr.Put( aBoxItem );
+
+ aNewAttr.Put( SvxFrameDirectionItem(
+ mpDoc->GetDefaultWritingMode() == css::text::WritingMode_RL_TB ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB,
+ EE_PARA_WRITINGDIR ) );
+
+ // Retrieve page-data for dialog
+
+ SvxPageItem aPageItem( SID_ATTR_PAGE );
+ aPageItem.SetDescName( mpPage->GetName() );
+ aPageItem.SetPageUsage( SvxPageUsage::All );
+ aPageItem.SetLandscape( mpPage->GetOrientation() == Orientation::Landscape );
+ aPageItem.SetNumType( mpDoc->GetPageNumType() );
+ aNewAttr.Put( aPageItem );
+
+ // size
+ maSize = mpPage->GetSize();
+ SvxSizeItem aSizeItem( SID_ATTR_PAGE_SIZE, maSize );
+ aNewAttr.Put( aSizeItem );
+
+ // Max size
+ SvxSizeItem aMaxSizeItem( SID_ATTR_PAGE_MAXSIZE, Size( MAXWIDTH, MAXHEIGHT ) );
+ aNewAttr.Put( aMaxSizeItem );
+
+ // paperbin
+ SvxPaperBinItem aPaperBinItem( SID_ATTR_PAGE_PAPERBIN, static_cast<sal_uInt8>(mpPage->GetPaperBin()) );
+ aNewAttr.Put( aPaperBinItem );
+
+ SvxLRSpaceItem aLRSpaceItem( static_cast<sal_uInt16>(mpPage->GetLeftBorder()), static_cast<sal_uInt16>(mpPage->GetRightBorder()), 0, 0, mpDoc->GetPool().GetWhich(SID_ATTR_LRSPACE));
+ aNewAttr.Put( aLRSpaceItem );
+
+ SvxULSpaceItem aULSpaceItem( static_cast<sal_uInt16>(mpPage->GetUpperBorder()), static_cast<sal_uInt16>(mpPage->GetLowerBorder()), mpDoc->GetPool().GetWhich(SID_ATTR_ULSPACE));
+ aNewAttr.Put( aULSpaceItem );
+
+ // Application
+ bool bScale = mpDoc->GetDocumentType() != DocumentType::Draw;
+ aNewAttr.Put( SfxBoolItem( SID_ATTR_PAGE_EXT1, bScale ) );
+
+ bool bFullSize = mpPage->IsMasterPage() ?
+ mpPage->IsBackgroundFullSize() : static_cast<SdPage&>(mpPage->TRG_GetMasterPage()).IsBackgroundFullSize();
+
+ SfxGrabBagItem grabBag(SID_ATTR_CHAR_GRABBAG);
+ grabBag.GetGrabBag()["BackgroundFullSize"] <<= bFullSize;
+
+ if (mpDoc->GetDocumentType() == DocumentType::Impress && mpPage->IsMasterPage())
+ {
+ // A master slide may have a theme.
+ svx::Theme* pTheme = mpPage->getSdrPageProperties().GetTheme();
+ if (pTheme)
+ {
+ uno::Any aTheme;
+ pTheme->ToAny(aTheme);
+ grabBag.GetGrabBag()["Theme"] = aTheme;
+ }
+ }
+
+ aNewAttr.Put(grabBag);
+
+ // Merge ItemSet for dialog
+
+ const WhichRangesContainer& rRanges = aNewAttr.GetRanges();
+ sal_uInt16 p1 = rRanges[0].first, p2 = rRanges[0].second;
+ sal_Int32 idx = 1;
+ while(idx < rRanges.size() && (rRanges[idx].first - p2 == 1))
+ {
+ p2 = rRanges[idx].second;
+ ++idx;
+ }
+ SfxItemSet aMergedAttr( *aNewAttr.GetPool(), p1, p2 );
+
+ mergeItemSetsImpl( aMergedAttr, aNewAttr );
+
+ SdStyleSheet* pStyleSheet = mpPage->getPresentationStyle(HID_PSEUDOSHEET_BACKGROUND);
+
+ // merge page background filling to the dialogs input set
+ if( mbDisplayBackgroundTabPage )
+ {
+ MergePageBackgroundFilling(mpPage, pStyleSheet, mbMasterPage, aMergedAttr);
+ }
+
+ std::optional< SfxItemSet > pTempSet;
+
+ const sal_uInt16 nId = GetSlotID();
+ if (nId == SID_SAVE_BACKGROUND)
+ {
+ const XFillStyleItem& rStyleItem = aMergedAttr.Get(XATTR_FILLSTYLE);
+ if (drawing::FillStyle_BITMAP == rStyleItem.GetValue())
+ {
+ const XFillBitmapItem& rBitmap = aMergedAttr.Get(XATTR_FILLBITMAP);
+ const GraphicObject& rGraphicObj = rBitmap.GetGraphicObject();
+ GraphicHelper::ExportGraphic(pParent, rGraphicObj.GetGraphic(), "");
+ }
+ }
+ else if (nId == SID_SELECT_BACKGROUND)
+ {
+ Graphic aGraphic;
+ ErrCode nError = ERRCODE_GRFILTER_OPENERROR;
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ const SfxPoolItem* pItem;
+
+ if (pArgs && pArgs->GetItemState(SID_SELECT_BACKGROUND, true, &pItem) == SfxItemState::SET)
+ {
+ OUString aFileName(static_cast<const SfxStringItem*>(pItem)->GetValue());
+ OUString aFilterName;
+
+ if (const SfxStringItem* pFilterItem = pArgs->GetItemIfSet(FN_PARAM_FILTER))
+ aFilterName = pFilterItem->GetValue();
+
+ nError = GraphicFilter::LoadGraphic(aFileName, aFilterName, aGraphic,
+ &GraphicFilter::GetGraphicFilter());
+ }
+ else
+ {
+ SvxOpenGraphicDialog aDlg(SdResId(STR_SET_BACKGROUND_PICTURE), pParent);
+
+ nError = aDlg.Execute();
+ if (nError == ERRCODE_NONE)
+ {
+ nError = aDlg.GetGraphic(aGraphic);
+ }
+ }
+
+ if (nError == ERRCODE_NONE)
+ {
+ pTempSet.emplace( mpDoc->GetPool(), svl::Items<XATTR_FILL_FIRST, XATTR_FILL_LAST> );
+
+ pTempSet->Put( XFillStyleItem( drawing::FillStyle_BITMAP ) );
+
+ // MigrateItemSet makes sure the XFillBitmapItem will have a unique name
+ SfxItemSetFixed<XATTR_FILLBITMAP, XATTR_FILLBITMAP> aMigrateSet( mpDoc->GetPool() );
+ aMigrateSet.Put(XFillBitmapItem("background", aGraphic));
+ SdrModel::MigrateItemSet( &aMigrateSet, &*pTempSet, mpDoc );
+
+ pTempSet->Put( XFillBmpStretchItem( true ));
+ pTempSet->Put( XFillBmpTileItem( false ));
+ }
+ }
+
+ else
+ {
+ bool bIsImpressDoc = mpDrawViewShell->GetDoc()->GetDocumentType() == DocumentType::Impress;
+
+ // create the dialog
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg( pFact->CreateSdTabPageDialog(mpViewShell->GetFrameWeld(), &aMergedAttr, mpDocSh, mbDisplayBackgroundTabPage, bIsImpressDoc, mbMasterPage) );
+ if( pDlg->Execute() == RET_OK )
+ pTempSet.emplace( *pDlg->GetOutputItemSet() );
+ }
+
+ if (pTempSet && pStyleSheet)
+ {
+ pStyleSheet->AdjustToFontHeight(*pTempSet);
+
+ if( mbDisplayBackgroundTabPage )
+ {
+ // if some fillstyle-items are not set in the dialog, then
+ // try to use the items before
+ bool bChanges = false;
+ for( sal_uInt16 i=XATTR_FILL_FIRST; i<XATTR_FILL_LAST; i++ )
+ {
+ if( aMergedAttr.GetItemState( i ) != SfxItemState::DEFAULT )
+ {
+ if( pTempSet->GetItemState( i ) == SfxItemState::DEFAULT )
+ pTempSet->Put( aMergedAttr.Get( i ) );
+ else
+ if( aMergedAttr.GetItem( i ) != pTempSet->GetItem( i ) )
+ bChanges = true;
+ }
+ }
+
+ // if the background for this page was set to invisible, the background-object has to be deleted, too.
+ const XFillStyleItem* pTempFillStyleItem = pTempSet->GetItem<XFillStyleItem>(XATTR_FILLSTYLE);
+ assert(pTempFillStyleItem);
+ if (pTempFillStyleItem->GetValue() == drawing::FillStyle_NONE)
+ mbPageBckgrdDeleted = true;
+ else
+ {
+ if (pTempSet->GetItemState(XATTR_FILLSTYLE) == SfxItemState::DEFAULT)
+ {
+ const XFillStyleItem* pMergedFillStyleItem = aMergedAttr.GetItem<XFillStyleItem>(XATTR_FILLSTYLE);
+ assert(pMergedFillStyleItem);
+ if (pMergedFillStyleItem->GetValue() == drawing::FillStyle_NONE)
+ mbPageBckgrdDeleted = true;
+ }
+ }
+
+ const XFillGradientItem* pTempGradItem = pTempSet->GetItem<XFillGradientItem>(XATTR_FILLGRADIENT);
+ if (pTempGradItem && pTempGradItem->GetName().isEmpty())
+ {
+ // MigrateItemSet guarantees unique gradient names
+ SfxItemSetFixed<XATTR_FILLGRADIENT, XATTR_FILLGRADIENT> aMigrateSet( mpDoc->GetPool() );
+ aMigrateSet.Put( XFillGradientItem("gradient", pTempGradItem->GetGradientValue()) );
+ SdrModel::MigrateItemSet( &aMigrateSet, &*pTempSet, mpDoc);
+ }
+
+ const XFillHatchItem* pTempHatchItem = pTempSet->GetItem<XFillHatchItem>(XATTR_FILLHATCH);
+ if (pTempHatchItem && pTempHatchItem->GetName().isEmpty())
+ {
+ // MigrateItemSet guarantees unique hatch names
+ SfxItemSetFixed<XATTR_FILLHATCH, XATTR_FILLHATCH> aMigrateSet( mpDoc->GetPool() );
+ aMigrateSet.Put( XFillHatchItem("hatch", pTempHatchItem->GetHatchValue()) );
+ SdrModel::MigrateItemSet( &aMigrateSet, &*pTempSet, mpDoc);
+ }
+
+ if( !mbMasterPage && bChanges && mbPageBckgrdDeleted )
+ {
+ mpBackgroundObjUndoAction.reset( new SdBackgroundObjUndoAction(
+ *mpDoc, *mpPage, mpPage->getSdrPageProperties().GetItemSet()) );
+
+ if(!mpPage->IsMasterPage())
+ {
+ // on normal pages, switch off fill attribute usage
+ SdrPageProperties& rPageProperties = mpPage->getSdrPageProperties();
+ rPageProperties.ClearItem( XATTR_FILLBITMAP );
+ rPageProperties.ClearItem( XATTR_FILLGRADIENT );
+ rPageProperties.ClearItem( XATTR_FILLHATCH );
+ rPageProperties.PutItem(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ }
+
+
+ /* Special treatment: reset the INVALIDS to
+ NULL-Pointer (otherwise INVALIDs or pointer point
+ to DefaultItems in the template; both would
+ prevent the attribute inheritance) */
+ pTempSet->ClearInvalidItems();
+
+ if( mbMasterPage )
+ {
+ mpDocSh->GetUndoManager()->AddUndoAction(std::make_unique<StyleSheetUndoAction>(
+ mpDoc, static_cast<SfxStyleSheet*>(pStyleSheet), &(*pTempSet)));
+ pStyleSheet->GetItemSet().Put( *pTempSet );
+ sdr::properties::CleanupFillProperties( pStyleSheet->GetItemSet() );
+ pStyleSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ }
+
+ // if background filling is set to master pages then clear from page set
+ if( mbMasterPage )
+ {
+ for( sal_uInt16 nWhich = XATTR_FILL_FIRST; nWhich <= XATTR_FILL_LAST; nWhich++ )
+ {
+ pTempSet->ClearItem( nWhich );
+ }
+ pTempSet->Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+
+ if( const SvxFrameDirectionItem* pItem = pTempSet->GetItemIfSet( EE_PARA_WRITINGDIR, false ) )
+ {
+ SvxFrameDirection nVal = pItem->GetValue();
+ mpDoc->SetDefaultWritingMode( nVal == SvxFrameDirection::Horizontal_RL_TB ? css::text::WritingMode_RL_TB : css::text::WritingMode_LR_TB );
+ }
+
+ mpDoc->SetChanged();
+
+ // BackgroundFill of Masterpage: no hard attributes allowed
+ SdrPage& rUsedMasterPage = mpPage->IsMasterPage() ? *mpPage : mpPage->TRG_GetMasterPage();
+ OSL_ENSURE(rUsedMasterPage.IsMasterPage(), "No MasterPage (!)");
+ rUsedMasterPage.getSdrPageProperties().ClearItem();
+ OSL_ENSURE(nullptr != rUsedMasterPage.getSdrPageProperties().GetStyleSheet(),
+ "MasterPage without StyleSheet detected (!)");
+ }
+
+ aNewAttr.Put(*pTempSet);
+ mrReq.Done( aNewAttr );
+
+ return mrReq.GetArgs();
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+void FuPage::ApplyItemSet( const SfxItemSet* pArgs )
+{
+ if (!pArgs || !mpDrawViewShell)
+ return;
+
+ // Set new page-attributes
+ PageKind ePageKind = mpDrawViewShell->GetPageKind();
+ const SfxPoolItem* pPoolItem;
+ bool bSetPageSizeAndBorder = false;
+ Size aNewSize(maSize);
+ sal_Int32 nLeft = -1, nRight = -1, nUpper = -1, nLower = -1;
+ bool bScaleAll = true;
+ Orientation eOrientation = mpPage->GetOrientation();
+ SdPage* pMasterPage = mpPage->IsMasterPage() ? mpPage : &static_cast<SdPage&>(mpPage->TRG_GetMasterPage());
+ bool bFullSize = pMasterPage->IsBackgroundFullSize();
+ sal_uInt16 nPaperBin = mpPage->GetPaperBin();
+
+ if( pArgs->GetItemState(SID_ATTR_PAGE, true, &pPoolItem) == SfxItemState::SET )
+ {
+ mpDoc->SetPageNumType(static_cast<const SvxPageItem*>(pPoolItem)->GetNumType());
+
+ eOrientation = static_cast<const SvxPageItem*>(pPoolItem)->IsLandscape() ?
+ Orientation::Landscape : Orientation::Portrait;
+
+ if( mpPage->GetOrientation() != eOrientation )
+ bSetPageSizeAndBorder = true;
+
+ mpDrawViewShell->ResetActualPage();
+ }
+
+ if( pArgs->GetItemState(SID_ATTR_PAGE_SIZE, true, &pPoolItem) == SfxItemState::SET )
+ {
+ aNewSize = static_cast<const SvxSizeItem*>(pPoolItem)->GetSize();
+
+ if( mpPage->GetSize() != aNewSize )
+ bSetPageSizeAndBorder = true;
+ }
+
+ if( pArgs->GetItemState(mpDoc->GetPool().GetWhich(SID_ATTR_LRSPACE),
+ true, &pPoolItem) == SfxItemState::SET )
+ {
+ nLeft = static_cast<const SvxLRSpaceItem*>(pPoolItem)->GetLeft();
+ nRight = static_cast<const SvxLRSpaceItem*>(pPoolItem)->GetRight();
+
+ if( mpPage->GetLeftBorder() != nLeft || mpPage->GetRightBorder() != nRight )
+ bSetPageSizeAndBorder = true;
+
+ }
+
+ if( pArgs->GetItemState(mpDoc->GetPool().GetWhich(SID_ATTR_ULSPACE),
+ true, &pPoolItem) == SfxItemState::SET )
+ {
+ nUpper = static_cast<const SvxULSpaceItem*>(pPoolItem)->GetUpper();
+ nLower = static_cast<const SvxULSpaceItem*>(pPoolItem)->GetLower();
+
+ if( mpPage->GetUpperBorder() != nUpper || mpPage->GetLowerBorder() != nLower )
+ bSetPageSizeAndBorder = true;
+ }
+
+ if( pArgs->GetItemState(mpDoc->GetPool().GetWhich(SID_ATTR_PAGE_EXT1), true, &pPoolItem) == SfxItemState::SET )
+ {
+ bScaleAll = static_cast<const SfxBoolItem*>(pPoolItem)->GetValue();
+ }
+
+ if (SfxItemState::SET == pArgs->GetItemState(SID_ATTR_CHAR_GRABBAG, true, &pPoolItem))
+ {
+ SfxGrabBagItem const*const pGrabBag(static_cast<SfxGrabBagItem const*>(pPoolItem));
+ if (pGrabBag->GetGrabBag().find("BackgroundFullSize")->second >>= bFullSize)
+ {
+ if (pMasterPage->IsBackgroundFullSize() != bFullSize)
+ {
+ bSetPageSizeAndBorder = true;
+ }
+ }
+
+ if (mpDoc->GetDocumentType() == DocumentType::Impress && mpPage->IsMasterPage())
+ {
+ // The item set may have a theme.
+ auto it = pGrabBag->GetGrabBag().find("Theme");
+ if (it != pGrabBag->GetGrabBag().end())
+ {
+ std::unique_ptr<svx::Theme> pTheme = svx::Theme::FromAny(it->second);
+ pMasterPage->getSdrPageProperties().SetTheme(std::move(pTheme));
+ }
+ else
+ {
+ SAL_WARN("sd.ui", "FuPage::ApplyItemSet: got no theme");
+ }
+ }
+ }
+
+ // Paper Bin
+ if( pArgs->GetItemState(mpDoc->GetPool().GetWhich(SID_ATTR_PAGE_PAPERBIN), true, &pPoolItem) == SfxItemState::SET )
+ {
+ nPaperBin = static_cast<const SvxPaperBinItem*>(pPoolItem)->GetValue();
+
+ if( mpPage->GetPaperBin() != nPaperBin )
+ bSetPageSizeAndBorder = true;
+ }
+
+ if (nLeft == -1 && nUpper != -1)
+ {
+ bSetPageSizeAndBorder = true;
+ nLeft = mpPage->GetLeftBorder();
+ nRight = mpPage->GetRightBorder();
+ }
+ else if (nLeft != -1 && nUpper == -1)
+ {
+ bSetPageSizeAndBorder = true;
+ nUpper = mpPage->GetUpperBorder();
+ nLower = mpPage->GetLowerBorder();
+ }
+
+ if( bSetPageSizeAndBorder || !mbMasterPage )
+ mpDrawViewShell->SetPageSizeAndBorder(ePageKind, aNewSize, nLeft, nRight, nUpper, nLower, bScaleAll, eOrientation, nPaperBin, bFullSize );
+
+ // if bMasterPage==sal_False then create a background-object for this page with the
+ // properties set in the dialog before, but if mbPageBckgrdDeleted==sal_True then
+ // the background of this page was set to invisible, so it would be a mistake
+ // to create a new background-object for this page !
+
+ if( mbDisplayBackgroundTabPage )
+ {
+ if( !mbMasterPage && !mbPageBckgrdDeleted )
+ {
+ // Only this page
+ mpBackgroundObjUndoAction.reset( new SdBackgroundObjUndoAction(
+ *mpDoc, *mpPage, mpPage->getSdrPageProperties().GetItemSet()) );
+ SfxItemSet aSet( *pArgs );
+ sdr::properties::CleanupFillProperties(aSet);
+ mpPage->getSdrPageProperties().ClearItem();
+ mpPage->getSdrPageProperties().PutItemSet(aSet);
+ }
+ }
+
+ // add undo action for background object
+ if( mpBackgroundObjUndoAction )
+ {
+ // set merge flag, because a SdUndoGroupAction could have been inserted before
+ mpDocSh->GetUndoManager()->AddUndoAction( std::move(mpBackgroundObjUndoAction), true );
+ }
+
+ // Objects can not be bigger than ViewSize
+ Size aPageSize = mpDoc->GetSdPage(0, ePageKind)->GetSize();
+ Size aViewSize(aPageSize.Width() * 3, aPageSize.Height() * 2);
+ mpDoc->SetMaxObjSize(aViewSize);
+
+ // if necessary, we tell Preview the new context
+ mpDrawViewShell->UpdatePreview( mpDrawViewShell->GetActualPage() );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuparagr.cxx b/sd/source/ui/func/fuparagr.cxx
new file mode 100644
index 000000000..ac5d87636
--- /dev/null
+++ b/sd/source/ui/func/fuparagr.cxx
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuparagr.hxx>
+#include <editeng/eeitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/editdata.hxx>
+#include <editeng/lrspitem.hxx>
+#include <svx/svdoutl.hxx>
+#include <svl/intitem.hxx>
+
+#include <View.hxx>
+#include <ViewShell.hxx>
+#include <drawdoc.hxx>
+#include <sdabstdlg.hxx>
+#include <sdattr.hrc>
+
+namespace sd {
+
+
+FuParagraph::FuParagraph (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuParagraph::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuParagraph( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuParagraph::DoExecute( SfxRequest& rReq )
+{
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ OutlinerView* pOutlView = mpView->GetTextEditOutlinerView();
+ ::Outliner* pOutliner = mpView->GetTextEditOutliner();
+
+ if( !pArgs )
+ {
+ SfxItemSet aEditAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aEditAttr );
+ SfxItemPool *pPool = aEditAttr.GetPool();
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END,
+ SID_ATTR_TABSTOP_OFFSET, SID_ATTR_TABSTOP_OFFSET,
+ ATTR_PARANUMBERING_START, ATTR_PARANUMBERING_END> aNewAttr( *pPool );
+
+ aNewAttr.Put( aEditAttr );
+
+ // left border is offset
+ const ::tools::Long nOff = aNewAttr.Get( EE_PARA_LRSPACE ).GetTextLeft();
+ // conversion since TabulatorTabPage always uses Twips!
+ SfxInt32Item aOff( SID_ATTR_TABSTOP_OFFSET, nOff );
+ aNewAttr.Put( aOff );
+
+ if( pOutlView && pOutliner )
+ {
+ ESelection eSelection = pOutlView->GetSelection();
+ aNewAttr.Put( SfxInt16Item( ATTR_NUMBER_NEWSTART_AT, pOutliner->GetNumberingStartValue( eSelection.nStartPara ) ) );
+ aNewAttr.Put( SfxBoolItem( ATTR_NUMBER_NEWSTART, pOutliner->IsParaIsNumberingRestart( eSelection.nStartPara ) ) );
+ }
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSdParagraphTabDlg(mpViewShell->GetFrameWeld(), &aNewAttr));
+
+ sal_uInt16 nResult = pDlg->Execute();
+
+ switch( nResult )
+ {
+ case RET_OK:
+ {
+ rReq.Done( *( pDlg->GetOutputItemSet() ) );
+
+ pArgs = rReq.GetArgs();
+ }
+ break;
+
+ default:
+ return; // Cancel
+ }
+ }
+ mpView->SetAttributes( *pArgs );
+
+ if( pOutlView && pOutliner )
+ {
+ ESelection eSelection = pOutlView->GetSelection();
+
+ if( const SfxBoolItem* pItem = pArgs->GetItemIfSet( ATTR_NUMBER_NEWSTART, false ) )
+ {
+ const bool bNewStart = pItem->GetValue();
+ pOutliner->SetParaIsNumberingRestart( eSelection.nStartPara, bNewStart );
+ }
+
+ if( const SfxInt16Item* pItem = pArgs->GetItemIfSet( ATTR_NUMBER_NEWSTART_AT, false ) )
+ {
+ const sal_Int16 nStartAt = pItem->GetValue();
+ pOutliner->SetNumberingStartValue( eSelection.nStartPara, nStartAt );
+ }
+ }
+
+ // invalidate slots
+ static const sal_uInt16 SidArray[] = {
+ SID_ATTR_TABSTOP,
+ SID_ATTR_PARA_ADJUST_LEFT,
+ SID_ATTR_PARA_ADJUST_RIGHT,
+ SID_ATTR_PARA_ADJUST_CENTER,
+ SID_ATTR_PARA_ADJUST_BLOCK,
+ SID_ATTR_PARA_LINESPACE,
+ SID_ATTR_PARA_LINESPACE_10,
+ SID_ATTR_PARA_LINESPACE_15,
+ SID_ATTR_PARA_LINESPACE_20,
+ SID_ATTR_PARA_ULSPACE,
+ SID_ATTR_PARA_LRSPACE,
+ SID_DEC_INDENT,
+ SID_INC_INDENT,
+ SID_ATTR_PARA_LEFT_TO_RIGHT,
+ SID_ATTR_PARA_RIGHT_TO_LEFT,
+ SID_RULER_TEXT_RIGHT_TO_LEFT,
+ SID_PARASPACE_INCREASE,
+ SID_PARASPACE_DECREASE,
+ 0 };
+
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArray );
+}
+
+void FuParagraph::Activate()
+{
+}
+
+void FuParagraph::Deactivate()
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fupoor.cxx b/sd/source/ui/func/fupoor.cxx
new file mode 100644
index 000000000..e901d07a6
--- /dev/null
+++ b/sd/source/ui/func/fupoor.cxx
@@ -0,0 +1,1135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fupoor.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/svdpagv.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdograf.hxx>
+#include <vcl/seleng.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <svl/stritem.hxx>
+
+#include <app.hrc>
+#include <fusel.hxx>
+#include <sdpage.hxx>
+#include <DrawViewShell.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <zoomlist.hxx>
+#include <slideshow.hxx>
+#include <LayerTabBar.hxx>
+
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+
+#include <sfx2/viewfrm.hxx>
+
+#include <svx/svditer.hxx>
+
+#include <editeng/editeng.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd {
+
+
+FuPoor::FuPoor (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDrDoc,
+ SfxRequest& rReq)
+ : mpView(pView),
+ mpViewShell(pViewSh),
+ mpWindow(pWin),
+ mpDocSh( pDrDoc->GetDocSh() ),
+ mpDoc(pDrDoc),
+ nSlotId( rReq.GetSlot() ),
+ aScrollTimer("sd FuPoor aScrollTimer"),
+ aDragTimer("sd FuPoor aDragTimer"),
+ bIsInDragMode(false),
+ bNoScrollUntilInside (true),
+ aDelayToScrollTimer("sd FuPoor aDelayToScrollTimer"),
+ bScrollable (false),
+ bDelayActive (false),
+ bFirstMouseMove (false),
+ // remember MouseButton state
+ mnCode(0)
+{
+ ReceiveRequest(rReq);
+
+ aScrollTimer.SetInvokeHandler( LINK(this, FuPoor, ScrollHdl) );
+ aScrollTimer.SetTimeout(SELENG_AUTOREPEAT_INTERVAL);
+
+ aDragTimer.SetInvokeHandler( LINK(this, FuPoor, DragHdl) );
+ aDragTimer.SetTimeout(SELENG_DRAGDROP_TIMEOUT);
+
+ aDelayToScrollTimer.SetInvokeHandler( LINK(this, FuPoor, DelayHdl) );
+ aDelayToScrollTimer.SetTimeout(2000);
+}
+
+FuPoor::~FuPoor()
+{
+ aDragTimer.Stop();
+ aScrollTimer.Stop();
+ aDelayToScrollTimer.Stop();
+}
+
+void FuPoor::Activate()
+{
+}
+
+void FuPoor::Deactivate()
+{
+ aDragTimer.Stop();
+ aScrollTimer.Stop();
+ aDelayToScrollTimer.Stop ();
+ bScrollable = bDelayActive = false;
+
+ if (mpWindow && mpWindow->IsMouseCaptured())
+ mpWindow->ReleaseMouse();
+}
+
+void FuPoor::SetWindow(::sd::Window* pWin)
+{
+ mpWindow = pWin;
+}
+
+/**
+ * scroll when approached the border of the window; is called by MouseMove
+ */
+void FuPoor::ForceScroll(const Point& aPixPos)
+{
+ aScrollTimer.Stop();
+
+ if ( mpView->IsDragHelpLine() || mpView->IsSetPageOrg() ||
+ SlideShow::IsRunning( mpViewShell->GetViewShellBase() ) )
+ return;
+
+ Point aPos = mpWindow->OutputToScreenPixel(aPixPos);
+ const ::tools::Rectangle& rRect = mpViewShell->GetAllWindowRect();
+
+ if ( bNoScrollUntilInside )
+ {
+ if ( rRect.Contains(aPos) )
+ bNoScrollUntilInside = false;
+ }
+ else
+ {
+ short dx = 0, dy = 0;
+
+ if ( aPos.X() <= rRect.Left() ) dx = -1;
+ if ( aPos.X() >= rRect.Right() ) dx = 1;
+ if ( aPos.Y() <= rRect.Top() ) dy = -1;
+ if ( aPos.Y() >= rRect.Bottom() ) dy = 1;
+
+ if ( dx != 0 || dy != 0 )
+ {
+ if (bScrollable)
+ {
+ // scroll action in derived class
+ mpViewShell->ScrollLines(dx, dy);
+ aScrollTimer.Start();
+ }
+ else if (! bDelayActive) StartDelayToScrollTimer ();
+ }
+ }
+}
+
+/**
+ * timer handler for window scrolling
+ */
+IMPL_LINK_NOARG(FuPoor, ScrollHdl, Timer *, void)
+{
+ Point aPnt(mpWindow->GetPointerPosPixel());
+
+ // use remembered MouseButton state to create correct
+ // MouseEvents for this artificial MouseMove.
+ MouseMove(MouseEvent(aPnt, 1, MouseEventModifiers::NONE, GetMouseButtonCode()));
+}
+
+/**
+ * handle keyboard events
+ * @returns sal_True if the event was handled, sal_False otherwise
+ */
+bool FuPoor::KeyInput(const KeyEvent& rKEvt)
+{
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+ bool bReturn = false;
+ bool bSlideShow = SlideShow::IsRunning( mpViewShell->GetViewShellBase() );
+
+ switch (nCode)
+ {
+ case KEY_RETURN:
+ {
+ if(rKEvt.GetKeyCode().IsMod1())
+ {
+ if( auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell ))
+ {
+ SdPage* pActualPage = pDrawViewShell->GetActualPage();
+ SdrTextObj* pCandidate = nullptr;
+
+ if(pActualPage)
+ {
+ SdrObjListIter aIter(pActualPage, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore() && !pCandidate)
+ {
+ SdrObject* pObj = aIter.Next();
+
+ if(auto pTextObj = dynamic_cast<SdrTextObj *>( pObj ))
+ {
+ SdrInventor nInv(pObj->GetObjInventor());
+ SdrObjKind nKnd(pObj->GetObjIdentifier());
+
+ if(SdrInventor::Default == nInv &&
+ (SdrObjKind::TitleText == nKnd || SdrObjKind::OutlineText == nKnd || SdrObjKind::Text == nKnd))
+ {
+ pCandidate = pTextObj;
+ }
+ }
+ }
+ }
+
+ if(pCandidate)
+ {
+ mpView->UnMarkAll();
+ mpView->MarkObj(pCandidate, mpView->GetSdrPageView());
+
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(
+ SID_ATTR_CHAR, SfxCallMode::ASYNCHRON);
+ }
+ else
+ {
+ // insert a new page with the same page layout
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(
+ SID_INSERTPAGE_QUICK, SfxCallMode::ASYNCHRON);
+ }
+
+ // consumed
+ bReturn = true;
+ }
+ }
+ else
+ {
+ // activate OLE object on RETURN for selected object
+ // activate text edit on RETURN for selected object
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if( !mpView->IsTextEdit() && 1 == rMarkList.GetMarkCount() )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( dynamic_cast< const SdrOle2Obj* >( pObj ) && !mpDocSh->IsUIActive() )
+ {
+ //HMHmpView->HideMarkHdl();
+ mpViewShell->ActivateObject(static_cast<SdrOle2Obj*>(pObj), css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY);
+ }
+ else if( pObj && pObj->IsEmptyPresObj() && dynamic_cast< const SdrGrafObj *>( pObj ) != nullptr )
+ {
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_INSERT_GRAPHIC, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+ else
+ {
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_ATTR_CHAR, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+
+ // consumed
+ bReturn = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_TAB:
+ {
+ // handle Mod1 and Mod2 to get travelling running on different systems
+ if(rKEvt.GetKeyCode().IsMod1() || rKEvt.GetKeyCode().IsMod2())
+ {
+ // do something with a selected handle?
+ const SdrHdlList& rHdlList = mpView->GetHdlList();
+ bool bForward(!rKEvt.GetKeyCode().IsShift());
+
+ const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward);
+
+ // guarantee visibility of focused handle
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(pHdl)
+ {
+ Point aHdlPosition(pHdl->GetPos());
+ ::tools::Rectangle aVisRect(aHdlPosition - Point(100, 100), Size(200, 200));
+ mpView->MakeVisible(aVisRect, *mpWindow);
+ }
+
+ // consumed
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_ESCAPE:
+ {
+ bReturn = FuPoor::cancel();
+ }
+ break;
+
+ case KEY_ADD:
+ {
+ if (!mpView->IsTextEdit() && !bSlideShow && !mpDocSh->IsUIActive())
+ {
+ // increase zoom
+ mpViewShell->SetZoom(mpWindow->GetZoom() * 3 / 2);
+
+ if( auto pViewShell = dynamic_cast<DrawViewShell *>( mpViewShell ))
+ pViewShell->SetZoomOnPage(false);
+
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_SUBTRACT:
+ {
+ if (!mpView->IsTextEdit() && !bSlideShow && !mpDocSh->IsUIActive())
+ {
+ // decrease zoom
+ mpViewShell->SetZoom(mpWindow->GetZoom() * 2 / 3);
+
+ if( auto pViewShell = dynamic_cast<DrawViewShell *>( mpViewShell ))
+ pViewShell->SetZoomOnPage(false);
+
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_MULTIPLY:
+ {
+ if (!mpView->IsTextEdit() && !bSlideShow)
+ {
+ // zoom to page
+ mpViewShell->GetViewFrame()->GetDispatcher()->
+ Execute(SID_SIZE_PAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_DIVIDE:
+ {
+ if (!mpView->IsTextEdit() && !bSlideShow)
+ {
+ // zoom to selected objects
+ mpViewShell->GetViewFrame()->GetDispatcher()->
+ Execute(SID_SIZE_OPTIMAL, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_POINT:
+ {
+ ZoomList* pZoomList = mpViewShell->GetZoomList();
+
+ if (!mpView->IsTextEdit() && pZoomList->IsNextPossible() && !bSlideShow && !mpDocSh->IsUIActive())
+ {
+ // use next ZoomRect
+ mpViewShell->SetZoomRect(pZoomList->GetNextZoomRect());
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_COMMA:
+ {
+ ZoomList* pZoomList = mpViewShell->GetZoomList();
+
+ if (!mpView->IsTextEdit() && pZoomList->IsPreviousPossible() && !bSlideShow && !mpDocSh->IsUIActive())
+ {
+ // use previous ZoomRect
+ mpViewShell->SetZoomRect(pZoomList->GetPreviousZoomRect());
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_HOME:
+ {
+ if (!mpView->IsTextEdit() && !bSlideShow)
+ if (auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell ))
+ {
+ // jump to first page
+ pDrawViewShell->SwitchPage(0);
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_END:
+ {
+ if (!mpView->IsTextEdit() && !bSlideShow)
+ if (auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell ))
+ {
+ // jump to last page
+ SdPage* pPage = pDrawViewShell->GetActualPage();
+ pDrawViewShell->SwitchPage(mpDoc->GetSdPageCount(
+ pPage->GetPageKind()) - 1);
+ bReturn = true;
+ }
+ }
+ break;
+
+ case KEY_PAGEUP:
+ {
+ if( rKEvt.GetKeyCode().IsMod1() && rKEvt.GetKeyCode().IsMod2() )
+ break;
+ if( bSlideShow)
+ break;
+
+ if( auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell ) )
+ {
+ // The page-up key switches layers or pages depending on the
+ // modifier key.
+ if ( ! rKEvt.GetKeyCode().GetModifier())
+ {
+ // With no modifier pressed we move to the previous
+ // slide.
+ mpView->SdrEndTextEdit();
+
+ // Previous page.
+ bReturn = true;
+ SdPage* pPage = pDrawViewShell->GetActualPage();
+ sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2;
+
+ if (nSdPage > 0)
+ {
+ // Switch the page and send events regarding
+ // deactivation the old page and activating the new
+ // one.
+ TabControl& rPageTabControl =
+ pDrawViewShell->GetPageTabControl();
+ if (rPageTabControl.IsReallyShown())
+ rPageTabControl.SendDeactivatePageEvent ();
+ pDrawViewShell->SwitchPage(nSdPage - 1);
+ if (rPageTabControl.IsReallyShown())
+ rPageTabControl.SendActivatePageEvent ();
+ }
+ }
+ else if (rKEvt.GetKeyCode().IsMod1())
+ {
+ // With the CONTROL modifier we switch layers.
+ if (pDrawViewShell->IsLayerModeActive())
+ {
+ // Moves to the previous layer.
+ SwitchLayer (-1);
+ }
+ }
+ }
+ }
+ break;
+
+ case KEY_PAGEDOWN:
+ {
+ if( rKEvt.GetKeyCode().IsMod1() && rKEvt.GetKeyCode().IsMod2() )
+ break;
+ if(dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr && !bSlideShow)
+ {
+ // The page-down key switches layers or pages depending on the
+ // modifier key.
+ if ( ! rKEvt.GetKeyCode().GetModifier())
+ {
+ // With no modifier pressed we move to the next slide.
+ mpView->SdrEndTextEdit();
+
+ // Next page.
+ bReturn = true;
+ SdPage* pPage = static_cast<DrawViewShell*>(mpViewShell)->GetActualPage();
+ sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2;
+
+ if (nSdPage < mpDoc->GetSdPageCount(pPage->GetPageKind()) - 1)
+ {
+ // Switch the page and send events regarding
+ // deactivation the old page and activating the new
+ // one.
+ TabControl& rPageTabControl =
+ static_cast<DrawViewShell*>(mpViewShell)->GetPageTabControl();
+ if (rPageTabControl.IsReallyShown())
+ rPageTabControl.SendDeactivatePageEvent ();
+ static_cast<DrawViewShell*>(mpViewShell)->SwitchPage(nSdPage + 1);
+ if (rPageTabControl.IsReallyShown())
+ rPageTabControl.SendActivatePageEvent ();
+ }
+ }
+ else if (rKEvt.GetKeyCode().IsMod1())
+ {
+ // With the CONTROL modifier we switch layers.
+ if (static_cast<DrawViewShell*>(mpViewShell)->IsLayerModeActive())
+ {
+ // With the layer mode active pressing page-down
+ // moves to the next layer.
+ SwitchLayer (+1);
+ }
+ }
+ }
+ }
+ break;
+
+ // change select state when focus is on poly point
+ case KEY_SPACE:
+ {
+ const SdrHdlList& rHdlList = mpView->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(mpView->IsPointMarked(*pHdl))
+ {
+ if(rKEvt.GetKeyCode().IsShift())
+ {
+ mpView->UnmarkPoint(*pHdl);
+ }
+ }
+ else
+ {
+ if(!rKEvt.GetKeyCode().IsShift())
+ {
+ mpView->UnmarkAllPoints();
+ }
+
+ mpView->MarkPoint(*pHdl);
+ }
+
+ if(nullptr == rHdlList.GetFocusHdl())
+ {
+ // restore point with focus
+ SdrHdl* pNewOne = nullptr;
+
+ for(size_t a = 0; !pNewOne && a < rHdlList.GetHdlCount(); ++a)
+ {
+ SdrHdl* pAct = rHdlList.GetHdl(a);
+
+ if(pAct
+ && pAct->GetKind() == SdrHdlKind::Poly
+ && pAct->GetPolyNum() == nPol
+ && pAct->GetPointNum() == nPnt)
+ {
+ pNewOne = pAct;
+ }
+ }
+
+ if(pNewOne)
+ {
+ const_cast<SdrHdlList&>(rHdlList).SetFocusHdl(pNewOne);
+ }
+ }
+
+ bReturn = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ {
+ if (!mpView->IsTextEdit() && !bSlideShow)
+ {
+ ::tools::Long nX = 0;
+ ::tools::Long nY = 0;
+
+ if (nCode == KEY_UP)
+ {
+ // scroll up
+ nX = 0;
+ nY =-1;
+ }
+ else if (nCode == KEY_DOWN)
+ {
+ // scroll down
+ nX = 0;
+ nY = 1;
+ }
+ else if (nCode == KEY_LEFT)
+ {
+ // scroll left
+ nX =-1;
+ nY = 0;
+ }
+ else if (nCode == KEY_RIGHT)
+ {
+ // scroll right
+ nX = 1;
+ nY = 0;
+ }
+
+ if (mpView->AreObjectsMarked() && !rKEvt.GetKeyCode().IsMod1() &&
+ !mpDocSh->IsReadOnly())
+ {
+ const SdrHdlList& rHdlList = mpView->GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ bool bIsMoveOfConnectedHandle(false);
+ bool bOldSuppress = false;
+ SdrEdgeObj* pEdgeObj = nullptr;
+ if(pHdl)
+ pEdgeObj = dynamic_cast<SdrEdgeObj *>( pHdl->GetObj() );
+
+ if(pEdgeObj && 0 == pHdl->GetPolyNum())
+ {
+ if(0 == pHdl->GetPointNum())
+ {
+ if(pEdgeObj->GetConnection(true).GetObject())
+ {
+ bIsMoveOfConnectedHandle = true;
+ }
+ }
+ if(1 == pHdl->GetPointNum())
+ {
+ if(pEdgeObj->GetConnection(false).GetObject())
+ {
+ bIsMoveOfConnectedHandle = true;
+ }
+ }
+ }
+
+ if(pEdgeObj)
+ {
+ // Suppress default connects to inside object and object center
+ bOldSuppress = pEdgeObj->GetSuppressDefaultConnect();
+ pEdgeObj->SetSuppressDefaultConnect(true);
+ }
+
+ if(bIsMoveOfConnectedHandle)
+ {
+ sal_uInt16 nMarkHdSiz(mpView->GetMarkHdlSizePixel());
+ Size aHalfConSiz(nMarkHdSiz + 1, nMarkHdSiz + 1);
+ aHalfConSiz = mpWindow->PixelToLogic(aHalfConSiz);
+
+ if(100 < aHalfConSiz.Width())
+ nX *= aHalfConSiz.Width();
+ else
+ nX *= 100;
+
+ if(100 < aHalfConSiz.Height())
+ nY *= aHalfConSiz.Height();
+ else
+ nY *= 100;
+ }
+ else if(rKEvt.GetKeyCode().IsMod2())
+ {
+ // move in 1 pixel distance
+ Size aLogicSizeOnePixel = mpWindow->PixelToLogic(Size(1,1));
+ nX *= aLogicSizeOnePixel.Width();
+ nY *= aLogicSizeOnePixel.Height();
+ }
+ else if(rKEvt.GetKeyCode().IsShift())
+ {
+ nX *= 1000;
+ nY *= 1000;
+ }
+ else
+ {
+ // old, fixed move distance
+ nX *= 100;
+ nY *= 100;
+ }
+
+ if(nullptr == pHdl)
+ {
+ // only take action when move is allowed
+ if(mpView->IsMoveAllowed())
+ {
+ // restrict movement to WorkArea
+ const ::tools::Rectangle& rWorkArea = mpView->GetWorkArea();
+
+ if(!rWorkArea.IsEmpty())
+ {
+ ::tools::Rectangle aMarkRect(mpView->GetMarkedObjRect());
+ aMarkRect.Move(nX, nY);
+
+ if(!aMarkRect.Contains(rWorkArea))
+ {
+ if(aMarkRect.Left() < rWorkArea.Left())
+ {
+ nX += rWorkArea.Left() - aMarkRect.Left();
+ }
+
+ if(aMarkRect.Right() > rWorkArea.Right())
+ {
+ nX -= aMarkRect.Right() - rWorkArea.Right();
+ }
+
+ if(aMarkRect.Top() < rWorkArea.Top())
+ {
+ nY += rWorkArea.Top() - aMarkRect.Top();
+ }
+
+ if(aMarkRect.Bottom() > rWorkArea.Bottom())
+ {
+ nY -= aMarkRect.Bottom() - rWorkArea.Bottom();
+ }
+ }
+ }
+
+ // no handle selected
+ if(0 != nX || 0 != nY)
+ {
+ mpView->MoveAllMarked(Size(nX, nY));
+
+ mpView->MakeVisible(mpView->GetAllMarkedRect(), *mpWindow);
+ }
+ }
+ }
+ 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 = mpView->GetDragStat();
+
+ // start dragging
+ mpView->BegDragObj(aStartPoint, nullptr, pHdl, 0);
+
+ if(mpView->IsDragObj())
+ {
+ bool bWasNoSnap = rDragStat.IsNoSnap();
+ bool bWasSnapEnabled = mpView->IsSnapEnabled();
+
+ // switch snapping off
+ if(!bWasNoSnap)
+ const_cast<SdrDragStat&>(rDragStat).SetNoSnap();
+ if(bWasSnapEnabled)
+ mpView->SetSnapEnabled(false);
+
+ mpView->MovAction(aEndPoint);
+ mpView->EndDragObj();
+
+ // restore snap
+ if(!bWasNoSnap)
+ const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap);
+ if(bWasSnapEnabled)
+ mpView->SetSnapEnabled(bWasSnapEnabled);
+ }
+
+ // make moved handle visible
+ ::tools::Rectangle aVisRect(aEndPoint - Point(100, 100), Size(200, 200));
+ mpView->MakeVisible(aVisRect, *mpWindow);
+ }
+ }
+
+ if(pEdgeObj)
+ {
+ // Restore original suppress value
+ pEdgeObj->SetSuppressDefaultConnect(bOldSuppress);
+ }
+ }
+ else
+ {
+ // scroll page
+ mpViewShell->ScrollLines(nX, nY);
+ }
+
+ bReturn = true;
+ }
+ }
+ break;
+ }
+
+ if (bReturn)
+ {
+ mpWindow->ReleaseMouse();
+ }
+
+ // when a text-editable object is selected and the
+ // input character is printable, activate text edit on that object
+ // and feed character to object
+ if(!bReturn && !mpDocSh->IsReadOnly())
+ {
+ if (!mpView->IsTextEdit())
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if(1 == rMarkList.GetMarkCount())
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ // #i118485# allow TextInput for OLEs, too
+ if( dynamic_cast< const SdrTextObj *>( pObj ) != nullptr && pObj->HasTextEdit())
+ {
+ // use common IsSimpleCharInput from the EditEngine.
+ bool bPrintable(EditEngine::IsSimpleCharInput(rKEvt));
+
+ if(bPrintable)
+ {
+ // try to activate textedit mode for the selected object
+ SfxStringItem aInputString(SID_ATTR_CHAR, OUString(rKEvt.GetCharCode()));
+
+ mpViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_ATTR_CHAR,
+ SfxCallMode::ASYNCHRON,
+ { &aInputString });
+
+ // consumed
+ bReturn = true;
+ }
+ }
+ }
+ else
+ {
+ // test if there is a title object there. If yes, try to
+ // set it to edit mode and start typing...
+ DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(mpViewShell);
+ if (pDrawViewShell && EditEngine::IsSimpleCharInput(rKEvt))
+ {
+ SdPage* pActualPage = pDrawViewShell->GetActualPage();
+ SdrTextObj* pCandidate = nullptr;
+
+ if(pActualPage)
+ {
+ SdrObjListIter aIter(pActualPage, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore() && !pCandidate)
+ {
+ SdrObject* pObj = aIter.Next();
+
+ if(auto pTextObj = dynamic_cast< SdrTextObj *>( pObj ))
+ {
+ SdrInventor nInv(pObj->GetObjInventor());
+ SdrObjKind nKnd(pObj->GetObjIdentifier());
+
+ if(SdrInventor::Default == nInv && SdrObjKind::TitleText == nKnd)
+ {
+ pCandidate = pTextObj;
+ }
+ }
+ }
+ }
+
+ // when candidate found and candidate is untouched, start editing text...
+ if(pCandidate && pCandidate->IsEmptyPresObj())
+ {
+ mpView->UnMarkAll();
+ mpView->MarkObj(pCandidate, mpView->GetSdrPageView());
+ SfxStringItem aInputString(SID_ATTR_CHAR, OUString(rKEvt.GetCharCode()));
+
+ mpViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_ATTR_CHAR,
+ SfxCallMode::ASYNCHRON,
+ { &aInputString });
+
+ // consumed
+ bReturn = true;
+ }
+ }
+ }
+ }
+ }
+
+ return bReturn;
+}
+
+bool FuPoor::MouseMove(const MouseEvent& )
+{
+ return false;
+}
+
+void FuPoor::SelectionHasChanged()
+{
+ const SdrHdlList& rHdlList = mpView->GetHdlList();
+ const_cast<SdrHdlList&>(rHdlList).ResetFocusHdl();
+}
+
+/**
+ * Cut object to clipboard
+ */
+void FuPoor::DoCut()
+{
+ if (mpView)
+ {
+ mpView->DoCut();
+ }
+}
+
+/**
+ * Copy object to clipboard
+ */
+void FuPoor::DoCopy()
+{
+ if (mpView)
+ {
+ mpView->DoCopy();
+ }
+}
+
+/**
+ * Paste object from clipboard
+ */
+void FuPoor::DoPaste()
+{
+ if (mpView)
+ {
+ mpView->DoPaste(mpWindow);
+ }
+}
+
+/**
+ * Paste unformatted text from clipboard
+ */
+void FuPoor::DoPasteUnformatted()
+{
+ if (mpView)
+ {
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( mpViewShell->GetActiveWindow() ) );
+ if (aDataHelper.GetTransferable().is())
+ {
+ sal_Int8 nAction = DND_ACTION_COPY;
+ mpView->InsertData( aDataHelper,
+ mpWindow->PixelToLogic( ::tools::Rectangle( Point(), mpWindow->GetOutputSizePixel() ).Center() ),
+ nAction, false, SotClipboardFormatId::STRING);
+ }
+ }
+}
+
+/**
+ * Timer handler for Drag&Drop
+ */
+IMPL_LINK_NOARG(FuPoor, DragHdl, Timer *, void)
+{
+ if( !mpView )
+ return;
+
+ sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
+ SdrHdl* pHdl = mpView->PickHandle(aMDPos);
+
+ if ( pHdl==nullptr && mpView->IsMarkedHit(aMDPos, nHitLog)
+ && !mpView->IsPresObjSelected(false) )
+ {
+ mpWindow->ReleaseMouse();
+ bIsInDragMode = true;
+ mpView->StartDrag( aMDPos, mpWindow );
+ }
+}
+
+bool FuPoor::Command(const CommandEvent& rCEvt)
+{
+ return mpView->Command(rCEvt,mpWindow);
+}
+
+/**
+ * Timer handler for window scrolling
+ */
+IMPL_LINK_NOARG(FuPoor, DelayHdl, Timer *, void)
+{
+ aDelayToScrollTimer.Stop ();
+ bScrollable = true;
+
+ Point aPnt(mpWindow->GetPointerPosPixel());
+
+ // use remembered MouseButton state to create correct
+ // MouseEvents for this artificial MouseMove.
+ MouseMove(MouseEvent(aPnt, 1, MouseEventModifiers::NONE, GetMouseButtonCode()));
+}
+
+bool FuPoor::MouseButtonUp (const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ aDelayToScrollTimer.Stop ();
+ bScrollable = bDelayActive = false;
+ return bScrollable;
+}
+
+bool FuPoor::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ return false;
+}
+
+void FuPoor::StartDelayToScrollTimer ()
+{
+ bDelayActive = true;
+ aDelayToScrollTimer.Start ();
+}
+
+bool FuPoor::RequestHelp(const HelpEvent& rHEvt)
+{
+ bool bReturn = false;
+
+ SdrPageView* pPV = mpView->GetSdrPageView();
+
+ if (pPV)
+ {
+ SdPage* pPage = static_cast<SdPage*>( pPV->GetPage() );
+
+ if (pPage)
+ {
+ bReturn = FmFormPage::RequestHelp(mpWindow, mpView, rHEvt);
+ }
+ }
+
+ return bReturn;
+}
+
+void FuPoor::ReceiveRequest(SfxRequest& /*rReq*/)
+{
+}
+
+SdrObjectUniquePtr FuPoor::CreateDefaultObject(const sal_uInt16, const ::tools::Rectangle& )
+{
+ // empty base implementation
+ return nullptr;
+}
+
+void FuPoor::ImpForceQuadratic(::tools::Rectangle& rRect)
+{
+ if(rRect.GetWidth() > rRect.GetHeight())
+ {
+ rRect = ::tools::Rectangle(
+ Point(rRect.Left() + ((rRect.GetWidth() - rRect.GetHeight()) / 2), rRect.Top()),
+ Size(rRect.GetHeight(), rRect.GetHeight()));
+ }
+ else
+ {
+ rRect = ::tools::Rectangle(
+ Point(rRect.Left(), rRect.Top() + ((rRect.GetHeight() - rRect.GetWidth()) / 2)),
+ Size(rRect.GetWidth(), rRect.GetWidth()));
+ }
+}
+
+void FuPoor::SwitchLayer (sal_Int32 nOffset)
+{
+ auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell );
+ if(!pDrawViewShell)
+ return;
+
+ // Calculate the new index.
+ sal_Int32 nIndex = pDrawViewShell->GetActiveTabLayerIndex() + nOffset;
+
+ // Make sure the new index lies inside the range of valid indices.
+ if (nIndex < 0)
+ nIndex = 0;
+ else if (nIndex >= pDrawViewShell->GetTabLayerCount ())
+ nIndex = pDrawViewShell->GetTabLayerCount() - 1;
+
+ // Set the new active layer.
+ if (nIndex != pDrawViewShell->GetActiveTabLayerIndex ())
+ {
+ LayerTabBar* pLayerTabControl =
+ static_cast<DrawViewShell*>(mpViewShell)->GetLayerTabControl();
+ if (pLayerTabControl != nullptr)
+ pLayerTabControl->SendDeactivatePageEvent ();
+
+ pDrawViewShell->SetActiveTabLayerIndex (nIndex);
+
+ if (pLayerTabControl != nullptr)
+ pLayerTabControl->SendActivatePageEvent ();
+ }
+}
+
+/** is called when the current function should be aborted. <p>
+ This is used when a function gets a KEY_ESCAPE but can also
+ be called directly.
+
+ @returns true if an active function was aborted
+*/
+bool FuPoor::cancel()
+{
+ if ( dynamic_cast< const FuSelection *>( this ) == nullptr )
+ {
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ return true;
+ }
+
+ return false;
+}
+
+// #i33136#
+bool FuPoor::doConstructOrthogonal() const
+{
+ // Check whether a media object is selected
+ bool bResizeKeepRatio = false;
+ // tdf#89758 Avoid interactive crop preview from being proportionally scaled by default.
+ if (mpView->AreObjectsMarked() && mpView->GetDragMode() != SdrDragMode::Crop)
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrObjKind aObjIdentifier = rMarkList.GetMark(0)->GetMarkedSdrObj()->GetObjIdentifier();
+ bResizeKeepRatio = aObjIdentifier == SdrObjKind::Graphic ||
+ aObjIdentifier == SdrObjKind::Media ||
+ aObjIdentifier == SdrObjKind::OLE2;
+ }
+ }
+ SdrHdl* pHdl = mpView->PickHandle(aMDPos);
+ // Resize proportionally when media is selected and the user drags on a corner
+ if (pHdl)
+ bResizeKeepRatio = bResizeKeepRatio && pHdl->IsCornerHdl();
+
+ return (
+ bResizeKeepRatio ||
+ SID_DRAW_XLINE == nSlotId ||
+ SID_DRAW_CIRCLEARC == nSlotId ||
+ SID_DRAW_SQUARE == nSlotId ||
+ SID_DRAW_SQUARE_NOFILL == nSlotId ||
+ SID_DRAW_SQUARE_ROUND == nSlotId ||
+ SID_DRAW_SQUARE_ROUND_NOFILL == nSlotId ||
+ SID_DRAW_CIRCLE == nSlotId ||
+ SID_DRAW_CIRCLE_NOFILL == nSlotId ||
+ SID_DRAW_CIRCLEPIE == nSlotId ||
+ SID_DRAW_CIRCLEPIE_NOFILL == nSlotId ||
+ SID_DRAW_CIRCLECUT == nSlotId ||
+ SID_DRAW_CIRCLECUT_NOFILL == nSlotId ||
+ SID_DRAW_XPOLYGON == nSlotId ||
+ SID_DRAW_XPOLYGON_NOFILL == nSlotId ||
+ SID_3D_CUBE == nSlotId ||
+ SID_3D_SPHERE == nSlotId ||
+ SID_3D_SHELL == nSlotId ||
+ SID_3D_HALF_SPHERE == nSlotId ||
+ SID_3D_TORUS == nSlotId ||
+ SID_3D_CYLINDER == nSlotId ||
+ SID_3D_CONE == nSlotId ||
+ SID_3D_PYRAMID == nSlotId);
+}
+
+void FuPoor::DoExecute( SfxRequest& )
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuprlout.cxx b/sd/source/ui/func/fuprlout.cxx
new file mode 100644
index 000000000..c436b78f0
--- /dev/null
+++ b/sd/source/ui/func/fuprlout.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 <fuprlout.hxx>
+#include <sfx2/dispatch.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/request.hxx>
+#include <svl/stritem.hxx>
+
+#include <sdattr.hrc>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <pres.hxx>
+#include <DrawViewShell.hxx>
+#include <View.hxx>
+#include <glob.hxx>
+#include <app.hrc>
+#include <DrawDocShell.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <Window.hxx>
+#include <drawview.hxx>
+#include <sdabstdlg.hxx>
+#include <memory>
+
+namespace sd
+{
+
+
+#define DOCUMENT_TOKEN '#'
+
+FuPresentationLayout::FuPresentationLayout (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuPresentationLayout::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuPresentationLayout( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuPresentationLayout::DoExecute( SfxRequest& rReq )
+{
+ // prevent selected objects or objects which are under editing from disappearing
+ mpView->SdrEndTextEdit();
+
+ if(mpView->GetSdrPageView())
+ {
+ mpView->UnmarkAll();
+ }
+
+ bool bError = false;
+
+ /* if we are on a master page, the changes apply for all pages and notes-
+ pages who are using the relevant layout */
+ bool bOnMaster = false;
+ if (DrawViewShell *pShell = dynamic_cast<DrawViewShell*>(mpViewShell))
+ {
+ EditMode eEditMode = pShell->GetEditMode();
+ if (eEditMode == EditMode::MasterPage)
+ bOnMaster = true;
+ }
+
+ std::vector<SdPage*> aUnselect;
+ if (!bOnMaster)
+ {
+ //We later rely on IsSelected, so transfer the selection here
+ //into the document
+ slidesorter::SlideSorterViewShell* pSlideSorterViewShell
+ = slidesorter::SlideSorterViewShell::GetSlideSorter(mpViewShell->GetViewShellBase());
+ if (pSlideSorterViewShell)
+ {
+ std::shared_ptr<slidesorter::SlideSorterViewShell::PageSelection> xSelection(
+ pSlideSorterViewShell->GetPageSelection());
+ if (xSelection)
+ {
+ for (SdPage *pPage : *xSelection)
+ {
+ if (pPage->IsSelected() || pPage->GetPageKind() != PageKind::Standard)
+ continue;
+ mpDoc->SetSelected(pPage, true);
+ aUnselect.push_back(pPage);
+ }
+ }
+ }
+ }
+
+ std::vector<SdPage*> aSelectedPages;
+ std::vector<sal_uInt16> aSelectedPageNums;
+ // determine the active pages
+ for (sal_uInt16 nPage = 0; nPage < mpDoc->GetSdPageCount(PageKind::Standard); nPage++)
+ {
+ SdPage* pPage = mpDoc->GetSdPage(nPage, PageKind::Standard);
+ if (pPage->IsSelected())
+ {
+ aSelectedPages.push_back(pPage);
+ aSelectedPageNums.push_back(nPage);
+ }
+ }
+
+ bool bMasterPage = bOnMaster;
+ bool bCheckMasters = false;
+
+ // call dialog
+ bool bLoad = false; // appear the new master pages?
+ OUString aFile;
+
+ SfxItemSetFixed<ATTR_PRESLAYOUT_START, ATTR_PRESLAYOUT_END> aSet(mpDoc->GetPool() );
+
+ aSet.Put( SfxBoolItem( ATTR_PRESLAYOUT_LOAD, bLoad));
+ aSet.Put( SfxBoolItem( ATTR_PRESLAYOUT_MASTER_PAGE, bMasterPage ) );
+ aSet.Put( SfxBoolItem( ATTR_PRESLAYOUT_CHECK_MASTERS, bCheckMasters ) );
+
+ if (!aSelectedPages.empty())
+ {
+ OUString aOldLayoutName(aSelectedPages.back()->GetLayoutName());
+ sal_Int32 nPos = aOldLayoutName.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ aOldLayoutName = aOldLayoutName.copy(0, nPos);
+ aSet.Put(SfxStringItem(ATTR_PRESLAYOUT_NAME, aOldLayoutName));
+ }
+
+ const SfxItemSet *pArgs = rReq.GetArgs ();
+
+ if (pArgs)
+ {
+ if (pArgs->GetItemState(ATTR_PRESLAYOUT_LOAD) == SfxItemState::SET)
+ bLoad = static_cast<const SfxBoolItem&>(pArgs->Get(ATTR_PRESLAYOUT_LOAD)).GetValue();
+ if( pArgs->GetItemState( ATTR_PRESLAYOUT_MASTER_PAGE ) == SfxItemState::SET )
+ bMasterPage = pArgs->Get( ATTR_PRESLAYOUT_MASTER_PAGE ).GetValue();
+ if( pArgs->GetItemState( ATTR_PRESLAYOUT_CHECK_MASTERS ) == SfxItemState::SET )
+ bCheckMasters = static_cast<const SfxBoolItem&>( pArgs->Get( ATTR_PRESLAYOUT_CHECK_MASTERS ) ).GetValue();
+ if (pArgs->GetItemState(ATTR_PRESLAYOUT_NAME) == SfxItemState::SET)
+ aFile = pArgs->Get(ATTR_PRESLAYOUT_NAME).GetValue();
+ }
+ else
+ {
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSdPresLayoutDlg> pDlg(pFact->CreateSdPresLayoutDlg(mpWindow ? mpWindow->GetFrameWeld() : nullptr, mpDocSh, aSet));
+
+ sal_uInt16 nResult = pDlg->Execute();
+
+ switch (nResult)
+ {
+ case RET_OK:
+ {
+ pDlg->GetAttr(aSet);
+ if (aSet.GetItemState(ATTR_PRESLAYOUT_LOAD) == SfxItemState::SET)
+ bLoad = static_cast<const SfxBoolItem&>(aSet.Get(ATTR_PRESLAYOUT_LOAD)).GetValue();
+ if( aSet.GetItemState( ATTR_PRESLAYOUT_MASTER_PAGE ) == SfxItemState::SET )
+ bMasterPage = aSet.Get( ATTR_PRESLAYOUT_MASTER_PAGE ).GetValue();
+ if( aSet.GetItemState( ATTR_PRESLAYOUT_CHECK_MASTERS ) == SfxItemState::SET )
+ bCheckMasters = static_cast<const SfxBoolItem&>(aSet.Get( ATTR_PRESLAYOUT_CHECK_MASTERS ) ).GetValue();
+ if (aSet.GetItemState(ATTR_PRESLAYOUT_NAME) == SfxItemState::SET)
+ aFile = aSet.Get(ATTR_PRESLAYOUT_NAME).GetValue();
+ }
+ break;
+
+ default:
+ bError = true;
+ }
+ }
+
+ if (bError)
+ return;
+
+ mpDocSh->SetWaitCursor( true );
+
+ /* Here, we only exchange masterpages, therefore the current page
+ remains the current page. To prevent calling PageOrderChangedHint
+ during insertion and extraction of the masterpages, we block. */
+ /* That isn't quite right. If the masterpageview is active and you are
+ removing a masterpage, it's possible that you are removing the
+ current masterpage. So you have to call ResetActualPage ! */
+ if( dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr && !bCheckMasters )
+ static_cast<DrawView*>(mpView)->BlockPageOrderChangedHint(true);
+
+ if (bLoad)
+ {
+ sal_Int32 nIdx{ 0 };
+ OUString aFileName = aFile.getToken(0, DOCUMENT_TOKEN, nIdx);
+ SdDrawDocument* pTempDoc = mpDoc->OpenBookmarkDoc( aFileName );
+
+ // #69581: If I chose the standard-template I got no filename and so I get no
+ // SdDrawDocument-Pointer. But the method SetMasterPage is able to handle
+ // a NULL-pointer as a Standard-template ( look at SdDrawDocument::SetMasterPage )
+ OUString aLayoutName;
+ if( pTempDoc )
+ aLayoutName = aFile.getToken(0, DOCUMENT_TOKEN, nIdx);
+ for (auto nSelectedPage : aSelectedPageNums)
+ mpDoc->SetMasterPage(nSelectedPage, aLayoutName, pTempDoc, bMasterPage, bCheckMasters);
+ mpDoc->CloseBookmarkDoc();
+ }
+ else
+ {
+ // use master page with the layout name aFile from current Doc
+ for (auto nSelectedPage : aSelectedPageNums)
+ mpDoc->SetMasterPage(nSelectedPage, aFile, mpDoc, bMasterPage, bCheckMasters);
+ }
+
+ // remove blocking
+ if( dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr && !bCheckMasters )
+ static_cast<DrawView*>(mpView)->BlockPageOrderChangedHint(false);
+
+ // if the master page was visible, show it again
+ if (!aSelectedPages.empty())
+ {
+ if (bOnMaster)
+ {
+ if( auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell ))
+ {
+ ::sd::View* pView = pDrawViewShell->GetView();
+ for (auto pSelectedPage : aSelectedPages)
+ {
+ sal_uInt16 nPgNum = pSelectedPage->TRG_GetMasterPage().GetPageNum();
+
+ if (static_cast<DrawViewShell*>(mpViewShell)->GetPageKind() == PageKind::Notes)
+ nPgNum++;
+
+ pView->HideSdrPage();
+ pView->ShowSdrPage(pView->GetModel()->GetMasterPage(nPgNum));
+ }
+ }
+
+ // force update of TabBar
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_MASTERPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+ else
+ {
+ for (auto pSelectedPage : aSelectedPages)
+ pSelectedPage->SetAutoLayout(pSelectedPage->GetAutoLayout());
+ }
+ }
+
+ //Undo transfer to document selection
+ for (auto pPage : aUnselect)
+ mpDoc->SetSelected(pPage, false);
+
+
+ // fake a mode change to repaint the page tab bar
+ if( auto pDrawViewSh = dynamic_cast<DrawViewShell *>( mpViewShell ) )
+ {
+ EditMode eMode = pDrawViewSh->GetEditMode();
+ bool bLayer = pDrawViewSh->IsLayerModeActive();
+ pDrawViewSh->ChangeEditMode( eMode, !bLayer );
+ pDrawViewSh->ChangeEditMode( eMode, bLayer );
+ }
+
+ mpDocSh->SetWaitCursor( false );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuprobjs.cxx b/sd/source/ui/func/fuprobjs.cxx
new file mode 100644
index 000000000..6042d1fbc
--- /dev/null
+++ b/sd/source/ui/func/fuprobjs.cxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuprobjs.hxx>
+
+#include <svl/stritem.hxx>
+#include <svl/style.hxx>
+#include <editeng/outliner.hxx>
+#include <svl/hint.hxx>
+#include <tools/debug.hxx>
+
+#include <app.hrc>
+
+#include <strings.hxx>
+
+#include <drawdoc.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <DrawDocShell.hxx>
+#include <OutlineView.hxx>
+#include <OutlineViewShell.hxx>
+#include <ViewShell.hxx>
+#include <Window.hxx>
+#include <glob.hxx>
+#include <prlayout.hxx>
+#include <unchss.hxx>
+#include <sdabstdlg.hxx>
+#include <memory>
+
+namespace sd {
+
+
+FuPresentationObjects::FuPresentationObjects (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuPresentationObjects::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuPresentationObjects( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuPresentationObjects::DoExecute( SfxRequest& )
+{
+ OutlineViewShell* pOutlineViewShell = dynamic_cast< OutlineViewShell* >( mpViewShell );
+ DBG_ASSERT( pOutlineViewShell, "sd::FuPresentationObjects::DoExecute(), does not work without an OutlineViewShell!");
+ if( !pOutlineViewShell )
+ return;
+
+ /* does the selections end in a unique presentation layout?
+ if not, it is not allowed to edit the templates */
+ SfxItemSetFixed<SID_STATUS_LAYOUT, SID_STATUS_LAYOUT> aSet(mpDoc->GetItemPool() );
+ pOutlineViewShell->GetStatusBarState( aSet );
+ OUString aLayoutName = static_cast<const SfxStringItem&>(aSet.Get(SID_STATUS_LAYOUT)).GetValue();
+ DBG_ASSERT(!aLayoutName.isEmpty(), "Layout not defined");
+
+ bool bUnique = false;
+ sal_Int16 nDepth, nTmp;
+ OutlineView* pOlView = static_cast<OutlineView*>(pOutlineViewShell->GetView());
+ OutlinerView* pOutlinerView = pOlView->GetViewByWindow( static_cast<Window*>(mpWindow) );
+ ::Outliner* pOutl = pOutlinerView->GetOutliner();
+
+ std::vector<Paragraph*> aSelList;
+ pOutlinerView->CreateSelectionList(aSelList);
+
+ Paragraph* pPara = aSelList.empty() ? nullptr : aSelList.front();
+
+ nDepth = pOutl->GetDepth(pOutl->GetAbsPos( pPara ) );
+ bool bPage = ::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE );
+
+ for( const auto& rpPara : aSelList )
+ {
+ nTmp = pOutl->GetDepth( pOutl->GetAbsPos( rpPara ) );
+
+ if( nDepth != nTmp )
+ {
+ bUnique = false;
+ break;
+ }
+
+ if( ::Outliner::HasParaFlag( rpPara, ParaFlag::ISPAGE ) != bPage )
+ {
+ bUnique = false;
+ break;
+ }
+ bUnique = true;
+ }
+
+ if( !bUnique )
+ return;
+
+ OUString aStyleName = aLayoutName + SD_LT_SEPARATOR;
+ PresentationObjects ePO;
+
+ if( bPage )
+ {
+ ePO = PresentationObjects::Title;
+ aStyleName += STR_LAYOUT_TITLE;
+ }
+ else
+ {
+ ePO = static_cast<PresentationObjects>( static_cast<int>(PresentationObjects::Outline_1) + nDepth - 1 );
+ aStyleName += STR_LAYOUT_OUTLINE + " " + OUString::number(nDepth);
+ }
+
+ SfxStyleSheetBasePool* pStyleSheetPool = mpDocSh->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStyleSheetPool->Find( aStyleName, SfxStyleFamily::Page );
+ DBG_ASSERT(pStyleSheet, "StyleSheet missing");
+
+ if( !pStyleSheet )
+ return;
+
+ SfxStyleSheetBase& rStyleSheet = *pStyleSheet;
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSdPresLayoutTemplateDlg(mpDocSh, mpViewShell->GetFrameWeld(),
+ false, rStyleSheet, ePO, pStyleSheetPool));
+ if( pDlg->Execute() == RET_OK )
+ {
+ const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
+ // Undo-Action
+ mpDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<StyleSheetUndoAction>(mpDoc, static_cast<SfxStyleSheet*>(pStyleSheet), pOutSet));
+
+ pStyleSheet->GetItemSet().Put( *pOutSet );
+ static_cast<SfxStyleSheet*>( pStyleSheet )->Broadcast( SfxHint( SfxHintId::DataChanged ) );
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuscale.cxx b/sd/source/ui/func/fuscale.cxx
new file mode 100644
index 000000000..d4730b243
--- /dev/null
+++ b/sd/source/ui/func/fuscale.cxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuscale.hxx>
+
+#include <svx/svxids.hrc>
+
+#include <app.hrc>
+#include <View.hxx>
+#include <Window.hxx>
+#include <OutlineViewShell.hxx>
+#include <drawdoc.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShell.hxx>
+#include <fuzoom.hxx>
+
+#include <svx/svdpagv.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <sfx2/request.hxx>
+#include <svx/svxdlg.hxx>
+#include <memory>
+
+namespace sd {
+
+
+FuScale::FuScale (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuScale::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuScale( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuScale::DoExecute( SfxRequest& rReq )
+{
+ sal_Int16 nValue;
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if( !pArgs )
+ {
+ SfxItemSetFixed<SID_ATTR_ZOOM, SID_ATTR_ZOOM> aNewAttr( mpDoc->GetPool() );
+ std::unique_ptr<SvxZoomItem> pZoomItem;
+ SvxZoomEnableFlags nZoomValues = SvxZoomEnableFlags::ALL;
+
+ nValue = static_cast<sal_Int16>(mpWindow->GetZoom());
+
+ // zoom on page size?
+ if( dynamic_cast< DrawViewShell *>( mpViewShell ) &&
+ static_cast<DrawViewShell*>(mpViewShell)->IsZoomOnPage() )
+ {
+ pZoomItem.reset(new SvxZoomItem( SvxZoomType::WHOLEPAGE, nValue ));
+ }
+ else
+ {
+ pZoomItem.reset(new SvxZoomItem( SvxZoomType::PERCENT, nValue ));
+ }
+
+ // limit range
+ if( mpViewShell )
+ {
+ if( dynamic_cast< DrawViewShell *>( mpViewShell ) != nullptr )
+ {
+ SdrPageView* pPageView = mpView->GetSdrPageView();
+ if( pPageView && pPageView->GetObjList()->GetObjCount() == 0 )
+ {
+ nZoomValues &= ~SvxZoomEnableFlags::OPTIMAL;
+ }
+ }
+ else if( dynamic_cast< OutlineViewShell *>( mpViewShell ) != nullptr )
+ {
+ nZoomValues &= ~SvxZoomEnableFlags::OPTIMAL;
+ nZoomValues &= ~SvxZoomEnableFlags::WHOLEPAGE;
+ nZoomValues &= ~SvxZoomEnableFlags::PAGEWIDTH;
+ }
+ }
+
+ pZoomItem->SetValueSet( nZoomValues );
+ aNewAttr.Put( std::move(pZoomItem) );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxZoomDialog> pDlg(pFact->CreateSvxZoomDialog(rReq.GetFrameWeld(), aNewAttr));
+ pDlg->SetLimits( static_cast<sal_uInt16>(mpWindow->GetMinZoom()), static_cast<sal_uInt16>(mpWindow->GetMaxZoom()) );
+ sal_uInt16 nResult = pDlg->Execute();
+ switch( nResult )
+ {
+ case RET_CANCEL:
+ {
+ rReq.Ignore ();
+ return; // Cancel
+ }
+ default:
+ {
+ rReq.Ignore ();
+ }
+ break;
+ }
+
+ const SfxItemSet aArgs (*(pDlg->GetOutputItemSet ()));
+
+ pDlg.disposeAndClear();
+
+ if (!mpViewShell)
+ return;
+
+ switch ( aArgs.Get (SID_ATTR_ZOOM).GetType ())
+ {
+ case SvxZoomType::PERCENT:
+ {
+ nValue = aArgs.Get (SID_ATTR_ZOOM).GetValue ();
+
+ mpViewShell->SetZoom( nValue );
+
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArrayZoom );
+ }
+ break;
+
+ case SvxZoomType::OPTIMAL:
+ {
+ if( dynamic_cast< DrawViewShell *>( mpViewShell ) != nullptr )
+ {
+ // name confusion: SID_SIZE_ALL -> zoom onto all objects
+ // --> the program offers it as optimal
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_SIZE_ALL, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+ }
+ break;
+
+ case SvxZoomType::PAGEWIDTH:
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_SIZE_PAGE_WIDTH, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ break;
+
+ case SvxZoomType::WHOLEPAGE:
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_SIZE_PAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ break;
+ default:
+ break;
+ }
+ }
+ else if(mpViewShell && (pArgs->Count () == 1))
+ {
+ const SfxUInt32Item* pScale = rReq.GetArg<SfxUInt32Item>(ID_VAL_ZOOM);
+ mpViewShell->SetZoom (pScale->GetValue ());
+
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArrayZoom );
+ }
+
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fusearch.cxx b/sd/source/ui/func/fusearch.cxx
new file mode 100644
index 000000000..73a112bf4
--- /dev/null
+++ b/sd/source/ui/func/fusearch.cxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fusearch.hxx>
+
+#include <sfx2/viewfrm.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <fupoor.hxx>
+#include <drawdoc.hxx>
+#include <app.hrc>
+#include <Outliner.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <OutlineViewShell.hxx>
+#include <ViewShellBase.hxx>
+
+class SfxRequest;
+
+namespace sd {
+
+const sal_uInt16 SidArraySpell[] = {
+ SID_DRAWINGMODE,
+ SID_OUTLINE_MODE,
+ SID_SLIDE_SORTER_MODE,
+ SID_NOTES_MODE,
+ SID_HANDOUT_MASTER_MODE,
+ SID_SLIDE_MASTER_MODE,
+ SID_NOTES_MASTER_MODE,
+ 0 };
+
+FuSearch::FuSearch (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq )
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq),
+ m_pSdOutliner(nullptr),
+ m_bOwnOutliner(false)
+{
+}
+
+FuSearch* FuSearch::createPtr(ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq)
+{
+ FuSearch* xFunc( new FuSearch( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuSearch::DoExecute( SfxRequest& )
+{
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArraySpell );
+
+ if ( dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr )
+ {
+ m_bOwnOutliner = true;
+ m_pSdOutliner = new SdOutliner( mpDoc, OutlinerMode::TextObject );
+ }
+ else if ( dynamic_cast< const OutlineViewShell *>( mpViewShell ) != nullptr )
+ {
+ m_bOwnOutliner = false;
+ m_pSdOutliner = mpDoc->GetOutliner();
+ }
+
+ if (m_pSdOutliner)
+ m_pSdOutliner->PrepareSpelling();
+}
+
+FuSearch::~FuSearch()
+{
+ if ( ! mpDocSh->IsInDestruction() && mpDocSh->GetViewShell()!=nullptr)
+ mpDocSh->GetViewShell()->GetViewFrame()->GetBindings().Invalidate( SidArraySpell );
+
+ if (m_pSdOutliner)
+ m_pSdOutliner->EndSpelling();
+
+ if (m_bOwnOutliner)
+ delete m_pSdOutliner;
+}
+
+void FuSearch::SearchAndReplace( const SvxSearchItem* pSearchItem )
+{
+ ViewShellBase* pBase = dynamic_cast<ViewShellBase*>( SfxViewShell::Current() );
+ ViewShell* pViewShell = nullptr;
+ if (pBase != nullptr)
+ pViewShell = pBase->GetMainViewShell().get();
+
+ if (pViewShell == nullptr)
+ return;
+
+ if (m_pSdOutliner && dynamic_cast<const DrawViewShell*>(pViewShell) && !m_bOwnOutliner)
+ {
+ m_pSdOutliner->EndSpelling();
+
+ m_bOwnOutliner = true;
+ m_pSdOutliner = new SdOutliner(mpDoc, OutlinerMode::TextObject);
+ m_pSdOutliner->PrepareSpelling();
+ }
+ else if (m_pSdOutliner && dynamic_cast<const OutlineViewShell*>(pViewShell) && m_bOwnOutliner)
+ {
+ m_pSdOutliner->EndSpelling();
+ delete m_pSdOutliner;
+
+ m_bOwnOutliner = false;
+ m_pSdOutliner = mpDoc->GetOutliner();
+ m_pSdOutliner->PrepareSpelling();
+ }
+
+ if (m_pSdOutliner)
+ {
+ bool bEndSpelling = m_pSdOutliner->StartSearchAndReplace(pSearchItem);
+
+ if (bEndSpelling)
+ {
+ m_pSdOutliner->EndSpelling();
+ m_pSdOutliner->PrepareSpelling();
+ }
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fusel.cxx b/sd/source/ui/func/fusel.cxx
new file mode 100644
index 000000000..a525f3bfc
--- /dev/null
+++ b/sd/source/ui/func/fusel.cxx
@@ -0,0 +1,1328 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fusel.hxx>
+#include <svx/svddrgmt.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/scene3d.hxx>
+#include <vcl/imapobj.hxx>
+#include <unotools/securityoptions.hxx>
+#include <svx/svxids.hrc>
+#include <svx/xfillit0.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/stritem.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <editeng/flditem.hxx>
+
+#include <svx/svdotable.hxx>
+
+#include <app.hrc>
+
+#include <sdmod.hxx>
+#include <DrawDocShell.hxx>
+#include <stlpool.hxx>
+#include <fudraw.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <FrameView.hxx>
+#include <View.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <DrawViewShell.hxx>
+#include <ToolBarManager.hxx>
+#include <Client.hxx>
+
+#include <svx/svdundo.hxx>
+
+#include <svx/sdrhittesthelper.hxx>
+#include <svx/diagram/IDiagramHelper.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd {
+
+FuSelection::FuSelection (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuDraw(pViewSh, pWin, pView, pDoc, rReq),
+ bTempRotation(false),
+ bSelectionChanged(false),
+ pHdl(nullptr),
+ bSuppressChangesOfSelection(false),
+ bMirrorSide0(false),
+ nEditMode(SID_BEZIER_MOVE),
+ pWaterCanCandidate(nullptr)
+ //Add Shift+UP/DOWN/LEFT/RIGHT key to move the position of insert point,
+ //and SHIFT+ENTER key to decide the position and draw the new insert point
+ ,bBeginInsertPoint(false),
+ oldPoint(0,0)
+ ,bMovedToCenterPoint(false)
+{
+}
+
+rtl::Reference<FuPoor> FuSelection::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuSelection( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuSelection::DoExecute( SfxRequest& rReq )
+{
+ FuDraw::DoExecute( rReq );
+
+ // Select object bar
+ SelectionHasChanged();
+}
+
+FuSelection::~FuSelection()
+{
+ mpView->UnmarkAllPoints();
+ mpView->ResetCreationActive();
+
+ if ( mpView->GetDragMode() != SdrDragMode::Move )
+ {
+ mpView->SetDragMode(SdrDragMode::Move);
+ }
+}
+
+namespace {
+ bool lcl_followHyperlinkAllowed(const MouseEvent& rMEvt) {
+ if (!rMEvt.IsMod1() && SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
+ return false;
+ if (rMEvt.IsMod1() && !SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
+ return false;
+ return true;
+ }
+}
+
+bool FuSelection::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ pHdl = nullptr;
+ bool bReturn = FuDraw::MouseButtonDown(rMEvt);
+ bool bWaterCan = SD_MOD()->GetWaterCan();
+ const bool bReadOnly = mpDocSh->IsReadOnly();
+ // When the right mouse button is pressed then only select objects
+ // (and deselect others) as a preparation for showing the context
+ // menu.
+ const bool bSelectionOnly = rMEvt.IsRight();
+
+ bMBDown = true;
+ bSelectionChanged = false;
+
+ if ( mpView->IsAction() )
+ {
+ if ( rMEvt.IsRight() )
+ mpView->BckAction();
+ return true;
+ }
+
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+ sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // When tiled rendering, we always work in logic units, use the non-pixel constants.
+ nDrgLog = DRGLOG;
+ nHitLog = HITLOG;
+ }
+
+ // The following code is executed for right clicks as well as for left
+ // clicks in order to modify the selection for the right button as a
+ // preparation for the context menu. The functions BegMarkObject() and
+ // BegDragObject(), however, are not called for right clicks because a)
+ // it makes no sense and b) to have IsAction() return sal_False when called
+ // from Command() which is a prerequisite for the context menu.
+ if ((rMEvt.IsLeft() || rMEvt.IsRight())
+ && !mpView->IsAction()
+ && (mpView->IsFrameDragSingles() || !mpView->HasMarkablePoints()))
+ {
+ /******************************************************************
+ * NO BEZIER_EDITOR
+ ******************************************************************/
+ mpWindow->CaptureMouse();
+ pHdl = mpView->PickHandle(aMDPos);
+
+ Degree100 nAngle0 = GetAngle(aMDPos - mpView->GetRef1());
+ nAngle0 -= 27000_deg100;
+ nAngle0 = NormAngle36000(nAngle0);
+ bMirrorSide0 = nAngle0 < 18000_deg100;
+
+ if (!pHdl && mpView->Is3DRotationCreationActive())
+ {
+ /******************************************************************
+ * If 3D-rotation bodies are about to be created,
+ * end creation now.
+ ******************************************************************/
+ bSuppressChangesOfSelection = true;
+ mpWindow->EnterWait();
+ mpView->End3DCreation();
+ bSuppressChangesOfSelection = false;
+ mpView->ResetCreationActive();
+ mpWindow->LeaveWait();
+ }
+
+ bool bTextEdit = false;
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+
+ if (eHit == SdrHitKind::TextEditObj && (mpViewShell->GetFrameView()->IsQuickEdit() || dynamic_cast< sdr::table::SdrTableObj* >(aVEvt.mpObj) != nullptr))
+ {
+ bTextEdit = true;
+ }
+
+ // When clicking into a URl field, also go to text edit mode (when not following the link)
+ if (!bTextEdit && eHit == SdrHitKind::UrlField && !rMEvt.IsMod2() && !lcl_followHyperlinkAllowed(rMEvt))
+ bTextEdit = true;
+
+ bool bPreventModify = mpDocSh->IsReadOnly();
+ if (bPreventModify && mpDocSh->GetSignPDFCertificate().is())
+ {
+ // If the just added signature line shape is selected, allow moving / resizing it.
+ bPreventModify = false;
+ }
+
+ if(!bTextEdit
+ && !bPreventModify
+ && ((mpView->IsMarkedHit(aMDPos, nHitLog) && !rMEvt.IsShift() && !rMEvt.IsMod2()) || pHdl != nullptr)
+ && (rMEvt.GetClicks() != 2)
+ )
+ {
+ if (!pHdl && mpView->Is3DRotationCreationActive())
+ {
+ // Switch between 3D-rotation body -> selection
+ mpView->ResetCreationActive();
+ }
+ else if (bWaterCan)
+ {
+ // Remember the selected object for proper handling in
+ // MouseButtonUp().
+ pWaterCanCandidate = pickObject (aMDPos);
+ }
+ else
+ {
+ // hit handle or marked object
+ bFirstMouseMove = true;
+ aDragTimer.Start();
+ }
+
+ if ( ! rMEvt.IsRight())
+ if (mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog))
+ mpView->GetDragMethod()->SetShiftPressed( rMEvt.IsShift() );
+ bReturn = true;
+ }
+ else
+ {
+ SdrPageView* pPV = nullptr;
+ SdrObject* pObj = !rMEvt.IsMod2() ? mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO) : nullptr;
+ if (pObj)
+ {
+ mpView->BegMacroObj(aMDPos, nHitLog, pObj, pPV, mpWindow);
+ bReturn = true;
+ }
+ else if ( bTextEdit )
+ {
+ SdrObjKind nSdrObjKind = aVEvt.mpObj->GetObjIdentifier();
+
+ if (aVEvt.mpObj->GetObjInventor() == SdrInventor::Default &&
+ (nSdrObjKind == SdrObjKind::Text ||
+ nSdrObjKind == SdrObjKind::TitleText ||
+ nSdrObjKind == SdrObjKind::OutlineText ||
+ !aVEvt.mpObj->IsEmptyPresObj()))
+ {
+ // Seamless Editing: branch to text input
+ if (!rMEvt.IsShift())
+ mpView->UnmarkAll();
+
+ SfxUInt16Item aItem(SID_TEXTEDIT, 1);
+ mpViewShell->GetViewFrame()->GetDispatcher()->
+ ExecuteList(SID_TEXTEDIT,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aItem });
+ return bReturn; // CAUTION, due to the synchronous slot the object is deleted now
+ }
+ }
+ else if ( !rMEvt.IsMod2() && rMEvt.GetClicks() == 1 &&
+ aVEvt.meEvent == SdrEventKind::ExecuteUrl )
+ {
+ mpWindow->ReleaseMouse();
+
+ // If tiled rendering, let client handles URL execution and early returns.
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ SfxViewShell& rSfxViewShell = mpViewShell->GetViewShellBase();
+ rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, aVEvt.mpURLField->GetURL().toUtf8().getStr());
+ return true;
+ }
+
+ if (!lcl_followHyperlinkAllowed(rMEvt))
+ return true;
+
+ SfxStringItem aStrItem(SID_FILE_NAME, aVEvt.mpURLField->GetURL());
+ SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName());
+ SfxBoolItem aBrowseItem( SID_BROWSE, true );
+ SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
+ mpWindow->ReleaseMouse();
+
+ if (rMEvt.IsMod1())
+ {
+ // Open in new frame
+ pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aStrItem, &aBrowseItem, &aReferer });
+ }
+ else
+ {
+ // Open in current frame
+ SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
+ pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
+ }
+
+ bReturn = true;
+ }
+ else if(!rMEvt.IsMod2()
+ && dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr
+ )
+ {
+ pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
+ if (pObj)
+ {
+ // Handle ImageMap click when not just selecting
+ if (!bSelectionOnly)
+ {
+ if (lcl_followHyperlinkAllowed(rMEvt))
+ bReturn = HandleImageMapClick(pObj, aMDPos);
+ }
+
+ if (!bReturn
+ && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr
+ || dynamic_cast<const E3dScene*>(pObj) != nullptr))
+ {
+ if (rMEvt.GetClicks() == 1)
+ {
+ // Look into the group
+ pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV,
+ SdrSearchOptions::ALSOONMASTER
+ | SdrSearchOptions::DEEP);
+ if (pObj && lcl_followHyperlinkAllowed(rMEvt))
+ bReturn = HandleImageMapClick(pObj, aMDPos);
+ }
+ else if (!bReadOnly && rMEvt.GetClicks() == 2)
+ {
+ // New: double click on selected Group object
+ // enter group
+ if (!bSelectionOnly
+ && pObj->getSdrPageFromSdrObject() == pPV->GetPage())
+ bReturn = pPV->EnterGroup(pObj);
+ }
+ }
+ }
+
+ // #i71727# replaced else here with two possibilities, once the original else (!pObj)
+ // and also ignoring the found object when it's on a masterpage
+ if(!pObj || (pObj->getSdrPageFromSdrObject() && pObj->getSdrPageFromSdrObject()->IsMasterPage()))
+ {
+ if(mpView->IsGroupEntered() && 2 == rMEvt.GetClicks())
+ {
+ // New: double click on empty space/on obj on MasterPage, leave group
+ mpView->LeaveOneGroup();
+ bReturn = true;
+ }
+ }
+ }
+
+ if (!bReturn)
+ {
+ if (bWaterCan)
+ {
+ if ( ! (rMEvt.IsShift() || rMEvt.IsMod2()))
+ {
+ // Find the object under the current mouse position
+ // and store it for the MouseButtonUp() method to
+ // evaluate.
+ pWaterCanCandidate = pickObject (aMDPos);
+ }
+ }
+ else
+ {
+ bReturn = true;
+ bool bDeactivateOLE = false;
+
+ if ( !rMEvt.IsShift() && !rMEvt.IsMod2() )
+ {
+ OSL_ASSERT (mpViewShell->GetViewShell()!=nullptr);
+ Client* pIPClient = static_cast<Client*>(
+ mpViewShell->GetViewShell()->GetIPClient());
+
+ if (pIPClient && pIPClient->IsObjectInPlaceActive())
+ {
+ // OLE-object gets deactivated in subsequent UnmarkAll()
+ bDeactivateOLE = true;
+ }
+
+ mpView->UnmarkAll();
+ }
+
+ bool bMarked = false;
+
+ if ( !rMEvt.IsMod1() && !bDeactivateOLE)
+ {
+ if ( rMEvt.IsMod2() )
+ {
+ bMarked = mpView->MarkNextObj(aMDPos, nHitLog, rMEvt.IsShift() );
+ }
+ else
+ {
+ bool bToggle = false;
+
+ if (rMEvt.IsShift() && mpView->GetMarkedObjectList().GetMarkCount() > 1)
+ {
+ // No Toggle on single selection
+ bToggle = true;
+ }
+
+ bMarked = mpView->MarkObj(aMDPos, nHitLog, bToggle);
+ }
+ }
+
+ if( !bDeactivateOLE )
+ {
+ if ( !bReadOnly &&
+ bMarked &&
+ (!rMEvt.IsShift() || mpView->IsMarkedHit(aMDPos, nHitLog)))
+ {
+ /**********************************************************
+ * Move object
+ **********************************************************/
+ aDragTimer.Start();
+
+ pHdl=mpView->PickHandle(aMDPos);
+ if ( ! rMEvt.IsRight())
+ mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
+ }
+ else
+ {
+ /**********************************************************
+ * Select object
+ **********************************************************/
+ if ( ! rMEvt.IsRight())
+ mpView->BegMarkObj(aMDPos);
+ }
+ }
+
+ if( bMarked && bTempRotation && (nSlotId == SID_OBJECT_ROTATE) && !rMEvt.IsShift() && (rMEvt.GetClicks() != 2) )
+ {
+ nSlotId = SID_OBJECT_SELECT;
+ Activate();
+ }
+ }
+ }
+ }
+ }
+ else if ( !bReadOnly
+ && (rMEvt.IsLeft() || rMEvt.IsRight())
+ && !mpView->IsAction())
+ {
+ /**********************************************************************
+ * BEZIER-EDITOR
+ **********************************************************************/
+ mpWindow->CaptureMouse();
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+
+ if (eHit == SdrHitKind::Handle && aVEvt.mpHdl->GetKind() == SdrHdlKind::BezierWeight)
+ {
+ /******************************************************************
+ * Drag Handle
+ ******************************************************************/
+ if ( ! rMEvt.IsRight())
+ mpView->BegDragObj(aMDPos, nullptr, aVEvt.mpHdl, nDrgLog);
+ }
+ else if (eHit == SdrHitKind::MarkedObject && nEditMode == SID_BEZIER_INSERT)
+ {
+ /******************************************************************
+ * Insert gluepoint
+ ******************************************************************/
+ mpView->BegInsObjPoint(aMDPos, rMEvt.IsMod1());
+ }
+ else if (eHit == SdrHitKind::MarkedObject && rMEvt.IsMod1())
+ {
+ /******************************************************************
+ * Select gluepoint
+ ******************************************************************/
+ if (!rMEvt.IsShift())
+ mpView->UnmarkAllPoints();
+
+ if ( ! rMEvt.IsRight())
+ mpView->BegMarkPoints(aMDPos);
+ }
+ else if (eHit == SdrHitKind::MarkedObject && !rMEvt.IsShift() && !rMEvt.IsMod2())
+ {
+ /******************************************************************
+ * Move object
+ ******************************************************************/
+ if ( ! rMEvt.IsRight())
+ mpView->BegDragObj(aMDPos, nullptr, nullptr, nDrgLog);
+ }
+ else if (eHit == SdrHitKind::Handle)
+ {
+ /******************************************************************
+ * Select gluepoint
+ ******************************************************************/
+ if (!mpView->IsPointMarked(*aVEvt.mpHdl) || rMEvt.IsShift())
+ {
+ if (!rMEvt.IsShift())
+ {
+ mpView->UnmarkAllPoints();
+ pHdl = mpView->PickHandle(aMDPos);
+ }
+ else
+ {
+ if (mpView->IsPointMarked(*aVEvt.mpHdl))
+ {
+ mpView->UnmarkPoint(*aVEvt.mpHdl);
+ pHdl = nullptr;
+ }
+ else
+ {
+ pHdl = mpView->PickHandle(aMDPos);
+ }
+ }
+
+ if (pHdl)
+ {
+ mpView->MarkPoint(*pHdl);
+ if ( ! rMEvt.IsRight())
+ mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
+
+ }
+ }
+ else
+ {
+ // Point IS marked and NO shift is pressed. Start
+ // dragging of selected point(s)
+ pHdl = mpView->PickHandle(aMDPos);
+ if(pHdl && ! rMEvt.IsRight())
+ mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
+ }
+ }
+ else
+ {
+ /******************************************************************
+ * Select or drag object
+ ******************************************************************/
+ if (!rMEvt.IsShift() && !rMEvt.IsMod2() && eHit == SdrHitKind::UnmarkedObject)
+ {
+ mpView->UnmarkAllObj();
+ }
+
+ bool bMarked = false;
+
+ if (!rMEvt.IsMod1())
+ {
+ if (rMEvt.IsMod2())
+ {
+ bMarked = mpView->MarkNextObj(aMDPos, nHitLog, rMEvt.IsShift());
+ }
+ else
+ {
+ bMarked = mpView->MarkObj(aMDPos, nHitLog, rMEvt.IsShift());
+ }
+ }
+
+ if (bMarked &&
+ (!rMEvt.IsShift() || eHit == SdrHitKind::MarkedObject))
+ {
+ // Move object
+ if ( ! rMEvt.IsRight())
+ mpView->BegDragObj(aMDPos, nullptr, aVEvt.mpHdl, nDrgLog);
+ }
+ else if (mpView->AreObjectsMarked())
+ {
+ /**************************************************************
+ * Select gluepoint
+ **************************************************************/
+ if (!rMEvt.IsShift())
+ mpView->UnmarkAllPoints();
+
+ if ( ! rMEvt.IsRight())
+ mpView->BegMarkPoints(aMDPos);
+ }
+ else
+ {
+ /**************************************************************
+ * Select object
+ **************************************************************/
+ if ( ! rMEvt.IsRight())
+ mpView->BegMarkObj(aMDPos);
+ }
+
+ ForcePointer(&rMEvt);
+ }
+ }
+
+ if (!bIsInDragMode)
+ {
+ ForcePointer(&rMEvt);
+ }
+
+ return bReturn;
+}
+
+bool FuSelection::MouseMove(const MouseEvent& rMEvt)
+{
+ bool bReturn = FuDraw::MouseMove(rMEvt);
+
+ if (aDragTimer.IsActive())
+ {
+ if(bFirstMouseMove)
+ {
+ bFirstMouseMove = false;
+ }
+ else
+ {
+ aDragTimer.Stop();
+ }
+ }
+
+ if (mpView->IsAction())
+ {
+ Point aPix(rMEvt.GetPosPixel());
+ Point aPnt(mpWindow->PixelToLogic(aPix));
+
+ ForceScroll(aPix);
+
+ if (mpView->IsInsObjPoint())
+ {
+ mpView->MovInsObjPoint(aPnt);
+ }
+ else
+ {
+ mpView->MovAction(aPnt);
+ }
+ }
+
+ ForcePointer(&rMEvt);
+
+ return bReturn;
+}
+
+bool FuSelection::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bReturn = false;
+ // When the right mouse button is pressed then only select objects
+ // (and deselect others) as a preparation for showing the context
+ // menu.
+ const bool bSelectionOnly = rMEvt.IsRight();
+
+ if (aDragTimer.IsActive() )
+ {
+ aDragTimer.Stop();
+ bIsInDragMode = false;
+ }
+
+ if( !mpView )
+ return false;
+
+ Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+ sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+
+ if (mpView->IsFrameDragSingles() || !mpView->HasMarkablePoints())
+ {
+ /**********************************************************************
+ * NO BEZIER_EDITOR
+ **********************************************************************/
+ if ( mpView->IsDragObj() )
+ {
+ /******************************************************************
+ * Object was moved
+ ******************************************************************/
+ FrameView* pFrameView = mpViewShell->GetFrameView();
+ bool bDragWithCopy = (rMEvt.IsMod1() && pFrameView->IsDragWithCopy());
+
+ if (bDragWithCopy)
+ {
+ bDragWithCopy = !mpView->IsPresObjSelected(false);
+ }
+
+ mpView->SetDragWithCopy(bDragWithCopy);
+ bool bWasDragged(mpView->EndDragObj( mpView->IsDragWithCopy() ));
+
+ mpView->ForceMarkedToAnotherPage();
+
+ if (!rMEvt.IsShift() && !rMEvt.IsMod1() && !rMEvt.IsMod2() &&
+ !bSelectionChanged &&
+ std::abs(aPnt.X() - aMDPos.X()) < nDrgLog &&
+ std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
+ {
+ /*************************************************************
+ * If a user wants to click on an object in front of a marked
+ * one, he releases the mouse button immediately
+ **************************************************************/
+ SdrPageView* pPV;
+ SdrObject* pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::BEFOREMARK);
+ if (pObj && pPV->IsObjMarkable(pObj))
+ {
+ mpView->UnmarkAllObj();
+ mpView->MarkObj(pObj,pPV);
+ return true;
+ }
+
+ // check for single object selected
+ SdrObject* pSingleObj = nullptr;
+
+ if (mpView->GetMarkedObjectList().GetMarkCount()==1)
+ {
+ pSingleObj = mpView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
+ }
+
+ // Check for click on svx::diagram::DiagramFrameHdl
+ // - if we hit a SdrHdl
+ // - if it was not moved
+ // - if single object is selected
+ // - and it is a Diagram
+ if(pHdl && !bWasDragged && nullptr != pSingleObj && pSingleObj->isDiagram())
+ {
+ svx::diagram::DiagramFrameHdl* pDiagramFrameHdl(dynamic_cast<svx::diagram::DiagramFrameHdl*>(pHdl));
+ if(nullptr != pDiagramFrameHdl)
+ {
+ // let the DiagramFrameHdl decide what to do
+ svx::diagram::DiagramFrameHdl::clicked(aPnt);
+ }
+ }
+
+ /**************************************************************
+ * Toggle between selection and rotation
+ **************************************************************/
+ if (nSlotId == SID_OBJECT_SELECT
+ && !comphelper::LibreOfficeKit::isActive()
+ && mpView->IsRotateAllowed()
+
+ && (rMEvt.GetClicks() != 2)
+ && (mpViewShell->GetFrameView()->IsClickChangeRotation()
+ || (pSingleObj
+ && pSingleObj->GetObjInventor()==SdrInventor::E3d))
+ && ! bSelectionOnly)
+
+ {
+ bTempRotation = true;
+ nSlotId = SID_OBJECT_ROTATE;
+ Activate();
+ }
+ else if (nSlotId == SID_OBJECT_ROTATE)
+ {
+ nSlotId = SID_OBJECT_SELECT;
+ Activate();
+ }
+ }
+ else if (nSlotId == SID_CONVERT_TO_3D_LATHE)
+ {
+ if (!pHdl)
+ {
+ bSuppressChangesOfSelection = true;
+ mpView->Start3DCreation();
+ bSuppressChangesOfSelection = false;
+ }
+ else if (pHdl->GetKind() != SdrHdlKind::MirrorAxis &&
+ pHdl->GetKind() != SdrHdlKind::Ref1 &&
+ pHdl->GetKind() != SdrHdlKind::Ref2 && mpView->Is3DRotationCreationActive())
+ {
+ /*********************************************************
+ * If 3D-rotation bodies are about to be created,
+ * end creation now
+ **********************************************************/
+ Degree100 nAngle1 = GetAngle(aPnt - mpView->GetRef1());
+ nAngle1 -= 27000_deg100;
+ nAngle1 = NormAngle36000(nAngle1);
+ bool bMirrorSide1 = nAngle1 < 18000_deg100;
+
+ if (bMirrorSide0 != bMirrorSide1)
+ {
+ bSuppressChangesOfSelection = true;
+ mpWindow->EnterWait();
+ mpView->End3DCreation();
+ bSuppressChangesOfSelection = false;
+ nSlotId = SID_OBJECT_SELECT;
+ mpWindow->LeaveWait();
+ Activate();
+ }
+ }
+ }
+ }
+ else if (rMEvt.IsMod1()
+ && !rMEvt.IsMod2()
+ && std::abs(aPnt.X() - aMDPos.X()) < nDrgLog
+ && std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
+ {
+ // Enter group
+ mpView->MarkObj(aPnt, nHitLog, rMEvt.IsShift(), rMEvt.IsMod1());
+ }
+
+ if (mpView->IsAction() )
+ {
+ mpView->EndAction();
+ }
+
+ if( SD_MOD()->GetWaterCan() )
+ {
+ if( rMEvt.IsRight() )
+ {
+ // In watering-can mode, on press onto right mouse button, an undo is executed
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_UNDO, SfxCallMode::ASYNCHRON );
+ }
+ else if (pWaterCanCandidate != nullptr)
+ {
+ // Is the candidate object still under the mouse?
+ if (pickObject (aPnt) == pWaterCanCandidate)
+ {
+ SdStyleSheetPool* pPool = static_cast<SdStyleSheetPool*>(
+ mpDocSh->GetStyleSheetPool());
+ if (pPool != nullptr)
+ {
+ SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(
+ pPool->GetActualStyleSheet());
+ if (pStyleSheet != nullptr && mpView->IsUndoEnabled() )
+ {
+ // Added UNDOs for the WaterCan mode. This was never done in
+ // the past, thus it was missing all the time.
+ std::unique_ptr<SdrUndoAction> pUndoAttr = mpDoc->GetSdrUndoFactory().CreateUndoAttrObject(*pWaterCanCandidate, true, true);
+ mpView->BegUndo(pUndoAttr->GetComment());
+ mpView->AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoGeoObject(*pWaterCanCandidate));
+ mpView->AddUndo(std::move(pUndoAttr));
+
+ pWaterCanCandidate->SetStyleSheet (pStyleSheet, false);
+
+ mpView->EndUndo();
+ }
+ }
+ }
+ }
+ // else when there has been no object under the mouse when the
+ // button was pressed then nothing happens even when there is
+ // one now.
+ }
+
+ sal_uInt16 nClicks = rMEvt.GetClicks();
+
+ if (nClicks == 2 && rMEvt.IsLeft() && bMBDown &&
+ !rMEvt.IsMod1() && !rMEvt.IsShift() )
+ {
+ DoubleClick(rMEvt);
+ }
+
+ bMBDown = false;
+
+ ForcePointer(&rMEvt);
+ pHdl = nullptr;
+ mpWindow->ReleaseMouse();
+ SdrObject* pSingleObj = nullptr;
+ const size_t nMarkCount = mpView->GetMarkedObjectList().GetMarkCount();
+
+ if (nMarkCount==1)
+ {
+ pSingleObj = mpView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
+ }
+
+ if ( (nSlotId != SID_OBJECT_SELECT && nMarkCount==0) ||
+ ( mpView->GetDragMode() == SdrDragMode::Crook &&
+ !mpView->IsCrookAllowed( mpView->IsCrookNoContortion() ) ) ||
+ ( mpView->GetDragMode() == SdrDragMode::Shear &&
+ !mpView->IsShearAllowed() && !mpView->IsDistortAllowed() ) ||
+ ( nSlotId==SID_CONVERT_TO_3D_LATHE && pSingleObj &&
+ (pSingleObj->GetObjInventor() != SdrInventor::Default ||
+ pSingleObj->GetObjIdentifier() == SdrObjKind::Measure) ) )
+ {
+ bReturn = true;
+ ForcePointer(&rMEvt);
+ pHdl = nullptr;
+ mpWindow->ReleaseMouse();
+ FuDraw::MouseButtonUp(rMEvt);
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::SYNCHRON);
+ return bReturn; // CAUTION, due to the synchronous slot, the object is deleted now.
+ }
+
+ FuDraw::MouseButtonUp(rMEvt);
+ }
+ else
+ {
+ /**********************************************************************
+ * BEZIER_EDITOR
+ **********************************************************************/
+ if ( mpView->IsAction() )
+ {
+ if ( mpView->IsInsObjPoint() )
+ {
+ mpView->EndInsObjPoint(SdrCreateCmd::ForceEnd);
+ }
+ else if ( mpView->IsDragObj() )
+ {
+ FrameView* pFrameView = mpViewShell->GetFrameView();
+ bool bDragWithCopy = (rMEvt.IsMod1() && pFrameView->IsDragWithCopy());
+
+ if (bDragWithCopy)
+ {
+ bDragWithCopy = !mpView->IsPresObjSelected(false);
+ }
+
+ mpView->SetDragWithCopy(bDragWithCopy);
+ mpView->EndDragObj( mpView->IsDragWithCopy() );
+ }
+ else
+ {
+ mpView->EndAction();
+
+ sal_uInt16 nDrgLog2 = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+ Point aPos = mpWindow->PixelToLogic( rMEvt.GetPosPixel() );
+
+ if (std::abs(aMDPos.X() - aPos.X()) < nDrgLog2 &&
+ std::abs(aMDPos.Y() - aPos.Y()) < nDrgLog2 &&
+ !rMEvt.IsShift() && !rMEvt.IsMod2())
+ {
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+
+ if (eHit == SdrHitKind::NONE)
+ {
+ // Click on the same place - unselect
+ mpView->UnmarkAllObj();
+ }
+ }
+ }
+ }
+ else if (!rMEvt.IsShift() && rMEvt.IsMod1() && !rMEvt.IsMod2() &&
+ std::abs(aPnt.X() - aMDPos.X()) < nDrgLog &&
+ std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
+ {
+ // Enter group
+ mpView->MarkObj(aPnt, nHitLog, false, rMEvt.IsMod1());
+ }
+
+ ForcePointer(&rMEvt);
+ pHdl = nullptr;
+ mpWindow->ReleaseMouse();
+
+ FuDraw::MouseButtonUp(rMEvt);
+ }
+
+ return bReturn;
+}
+
+/**
+ * Process keyboard input
+ * @returns sal_True if a KeyEvent is being processed, sal_False otherwise
+ */
+bool FuSelection::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bReturn = false;
+
+ switch (rKEvt.GetKeyCode().GetCode())
+ {
+ case KEY_ESCAPE:
+ {
+ bReturn = FuSelection::cancel();
+ }
+ break;
+ //add keyboard operation for insert points in drawing curve
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ {
+ if(rKEvt.GetKeyCode().IsShift()&&(nEditMode == SID_BEZIER_INSERT)){
+ ::tools::Long nX = 0;
+ ::tools::Long nY = 0;
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+ if (nCode == KEY_UP)
+ {
+ // scroll up
+ nX = 0;
+ nY =-1;
+ }
+ else if (nCode == KEY_DOWN)
+ {
+ // scroll down
+ nX = 0;
+ nY = 1;
+ }
+ else if (nCode == KEY_LEFT)
+ {
+ // scroll left
+ nX =-1;
+ nY = 0;
+ }
+ else if (nCode == KEY_RIGHT)
+ {
+ // scroll right
+ nX = 1;
+ nY = 0;
+ }
+
+ Point centerPoint;
+ ::tools::Rectangle rect = mpView->GetMarkedObjRect();
+ centerPoint = mpWindow->LogicToPixel(rect.Center());
+ Point aPoint = bMovedToCenterPoint? oldPoint:centerPoint;
+ Point ePoint = aPoint + Point(nX,nY);
+ mpWindow->SetPointerPosPixel(ePoint);
+ //simulate mouse move action
+ MouseEvent eMevt(ePoint, 1, MouseEventModifiers::DRAGMOVE, MOUSE_LEFT, 0);
+ MouseMove(eMevt);
+ oldPoint = ePoint;
+ bMovedToCenterPoint = true;
+ bReturn = true;
+ }
+ }
+ break;
+ case KEY_RETURN:
+ if(rKEvt.GetKeyCode().IsShift()&&(nEditMode == SID_BEZIER_INSERT))
+ {
+ if(!bBeginInsertPoint)
+ {
+ //simulate mouse button down action
+ MouseEvent aMevt(oldPoint, 1,
+ MouseEventModifiers::SIMPLEMOVE | MouseEventModifiers::DRAGMOVE,
+ MOUSE_LEFT, KEY_SHIFT);
+ MouseButtonDown(aMevt);
+ mpWindow->CaptureMouse();
+ bBeginInsertPoint = true;
+ }
+ else
+ {
+ //simulate mouse button up action
+ MouseEvent rMEvt(oldPoint, 1,
+ MouseEventModifiers::SIMPLEMOVE | MouseEventModifiers::ENTERWINDOW,
+ MOUSE_LEFT, KEY_SHIFT);
+ MouseButtonUp(rMEvt);
+ bBeginInsertPoint = false;
+ }
+ bReturn= true;
+ }
+ break;
+ }
+ if (!bReturn)
+ {
+ bReturn = FuDraw::KeyInput(rKEvt);
+
+ if(mpView->GetMarkedObjectList().GetMarkCount() == 0)
+ {
+ mpView->ResetCreationActive();
+
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+ }
+
+ return bReturn;
+
+}
+
+void FuSelection::Activate()
+{
+ SdrDragMode eMode;
+ mpView->ResetCreationActive();
+ mpView->SetEditMode(SdrViewEditMode::Edit);
+
+ switch( nSlotId )
+ {
+ case SID_OBJECT_ROTATE:
+ {
+ eMode = SdrDragMode::Rotate;
+
+ if ( mpView->GetDragMode() != eMode )
+ mpView->SetDragMode(eMode);
+ }
+ break;
+
+ case SID_OBJECT_MIRROR:
+ {
+ eMode = SdrDragMode::Mirror;
+
+ if ( mpView->GetDragMode() != eMode )
+ mpView->SetDragMode(eMode);
+ }
+ break;
+
+ case SID_OBJECT_CROP:
+ {
+ eMode = SdrDragMode::Crop;
+
+ if ( mpView->GetDragMode() != eMode )
+ mpView->SetDragMode(eMode);
+ }
+ break;
+
+ case SID_OBJECT_TRANSPARENCE:
+ {
+ eMode = SdrDragMode::Transparence;
+
+ if ( mpView->GetDragMode() != eMode )
+ mpView->SetDragMode(eMode);
+ }
+ break;
+
+ case SID_OBJECT_GRADIENT:
+ {
+ eMode = SdrDragMode::Gradient;
+
+ if ( mpView->GetDragMode() != eMode )
+ mpView->SetDragMode(eMode);
+ }
+ break;
+
+ case SID_OBJECT_SHEAR:
+ {
+ eMode = SdrDragMode::Shear;
+
+ if ( mpView->GetDragMode() != eMode )
+ mpView->SetDragMode(eMode);
+ }
+ break;
+
+ case SID_OBJECT_CROOK_ROTATE:
+ {
+ eMode = SdrDragMode::Crook;
+
+ if ( mpView->GetDragMode() != eMode )
+ {
+ mpView->SetDragMode(eMode);
+ mpView->SetCrookMode(SdrCrookMode::Rotate);
+ }
+ }
+ break;
+
+ case SID_OBJECT_CROOK_SLANT:
+ {
+ eMode = SdrDragMode::Crook;
+
+ if ( mpView->GetDragMode() != eMode )
+ {
+ mpView->SetDragMode(eMode);
+ mpView->SetCrookMode(SdrCrookMode::Slant);
+ }
+ }
+ break;
+
+ case SID_OBJECT_CROOK_STRETCH:
+ {
+ eMode = SdrDragMode::Crook;
+
+ if ( mpView->GetDragMode() != eMode )
+ {
+ mpView->SetDragMode(eMode);
+ mpView->SetCrookMode(SdrCrookMode::Stretch);
+ }
+ }
+ break;
+
+ case SID_CONVERT_TO_3D_LATHE:
+ {
+ eMode = SdrDragMode::Mirror;
+ bSuppressChangesOfSelection = true;
+
+ if ( mpView->GetDragMode() != eMode )
+ mpView->SetDragMode(eMode);
+
+ if (!mpView->Is3DRotationCreationActive())
+ mpView->Start3DCreation();
+
+ bSuppressChangesOfSelection = false;
+ }
+ break;
+
+ default:
+ {
+ eMode = SdrDragMode::Move;
+
+ if ( mpView->GetDragMode() != eMode )
+ mpView->SetDragMode(eMode);
+ }
+ break;
+ }
+
+ if (nSlotId != SID_OBJECT_ROTATE)
+ {
+ bTempRotation = false;
+ }
+
+ FuDraw::Activate();
+}
+
+void FuSelection::SelectionHasChanged()
+{
+ bSelectionChanged = true;
+
+ FuDraw::SelectionHasChanged();
+
+ if (mpView->Is3DRotationCreationActive() && !bSuppressChangesOfSelection)
+ {
+ // Switch rotation body -> selection
+ mpView->ResetCreationActive();
+ nSlotId = SID_OBJECT_SELECT;
+ Activate();
+ }
+
+ // Activate the right tool bar for the current context of the view.
+ mpViewShell->GetViewShellBase().GetToolBarManager()->SelectionHasChanged(*mpViewShell, *mpView);
+}
+
+/**
+ * Set current bezier edit mode
+ */
+void FuSelection::SetEditMode(sal_uInt16 nMode)
+{
+ nEditMode = nMode;
+
+ if (nEditMode == SID_BEZIER_INSERT)
+ {
+ mpView->SetInsObjPointMode(true);
+ }
+ else
+ {
+ mpView->SetInsObjPointMode(false);
+ }
+
+ ForcePointer();
+
+ SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_BEZIER_MOVE);
+ rBindings.Invalidate(SID_BEZIER_INSERT);
+}
+
+/**
+ * Execute ImageMap interaction
+ */
+bool FuSelection::HandleImageMapClick(const SdrObject* pObj, const Point& rPos)
+{
+ bool bClosed = pObj->IsClosedObj();
+ bool bFilled = false;
+
+ if (bClosed)
+ {
+ SfxItemSet aSet(mpDoc->GetPool());
+
+ aSet.Put(pObj->GetMergedItemSet());
+
+ const XFillStyleItem& rFillStyle = aSet.Get(XATTR_FILLSTYLE);
+ bFilled = rFillStyle.GetValue() != drawing::FillStyle_NONE;
+ }
+
+ const SdrLayerIDSet* pVisiLayer = &mpView->GetSdrPageView()->GetVisibleLayers();
+ sal_uInt16 nHitLog = sal_uInt16(mpWindow->PixelToLogic(Size(HITPIX, 0)).Width());
+ const ::tools::Long n2HitLog = nHitLog * 2;
+ Point aHitPosR(rPos);
+ Point aHitPosL(rPos);
+ Point aHitPosT(rPos);
+ Point aHitPosB(rPos);
+
+ aHitPosR.AdjustX(n2HitLog);
+ aHitPosL.AdjustX(-n2HitLog);
+ aHitPosT.AdjustY(n2HitLog);
+ aHitPosB.AdjustY(-n2HitLog);
+
+ if (!bClosed || !bFilled
+ || (SdrObjectPrimitiveHit(*pObj, aHitPosR, nHitLog, *mpView->GetSdrPageView(), pVisiLayer,
+ false)
+ && SdrObjectPrimitiveHit(*pObj, aHitPosL, nHitLog, *mpView->GetSdrPageView(),
+ pVisiLayer, false)
+ && SdrObjectPrimitiveHit(*pObj, aHitPosT, nHitLog, *mpView->GetSdrPageView(),
+ pVisiLayer, false)
+ && SdrObjectPrimitiveHit(*pObj, aHitPosB, nHitLog, *mpView->GetSdrPageView(),
+ pVisiLayer, false)))
+ {
+ if (SvxIMapInfo::GetIMapInfo(pObj))
+ {
+ const IMapObject* pIMapObj = SvxIMapInfo::GetHitIMapObject(pObj, rPos);
+
+ if (pIMapObj && !pIMapObj->GetURL().isEmpty())
+ {
+ // Jump to Document
+ mpWindow->ReleaseMouse();
+ SfxStringItem aStrItem(SID_FILE_NAME, pIMapObj->GetURL());
+ SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName());
+ SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
+ SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
+ SfxBoolItem aBrowseItem(SID_BROWSE, true);
+ mpWindow->ReleaseMouse();
+ pFrame->GetDispatcher()->ExecuteList(
+ SID_OPENDOC, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/** is called when the current function should be aborted. <p>
+ This is used when a function gets a KEY_ESCAPE but can also
+ be called directly.
+
+ @returns true if an active function was aborted
+*/
+bool FuSelection::cancel()
+{
+ if (mpView->Is3DRotationCreationActive())
+ {
+ mpView->ResetCreationActive();
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+SdrObject* FuSelection::pickObject (const Point& rTestPoint)
+{
+ SdrPageView* pPageView;
+ sal_uInt16 nHitLog = sal_uInt16 (mpWindow->PixelToLogic(Size(HITPIX,0)).Width());
+ return mpView->PickObj(rTestPoint, nHitLog, pPageView, SdrSearchOptions::PICKMARKABLE);
+}
+
+void FuSelection::ForcePointer(const MouseEvent* pMEvt)
+{
+ if(bMovedToCenterPoint && !bBeginInsertPoint && pMEvt)
+ {
+ MouseEvent aMEvt(pMEvt->GetPosPixel(), pMEvt->GetClicks(),
+ pMEvt->GetMode(), pMEvt->GetButtons(), pMEvt->GetModifier() & ~KEY_SHIFT);
+ FuDraw::ForcePointer(&aMEvt);
+ }
+ else
+ {
+ FuDraw::ForcePointer(pMEvt);
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fusldlg.cxx b/sd/source/ui/func/fusldlg.cxx
new file mode 100644
index 000000000..c0269b08a
--- /dev/null
+++ b/sd/source/ui/func/fusldlg.cxx
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fusldlg.hxx>
+#include <svl/eitem.hxx>
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <svl/intitem.hxx>
+
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <sdattr.hrc>
+#include <sdmod.hxx>
+#include <Window.hxx>
+#include <optsitem.hxx>
+#include <sdabstdlg.hxx>
+
+namespace sd {
+
+#define ITEMVALUE(ItemSet,Id,Cast) static_cast<const Cast&>((ItemSet).Get(Id)).GetValue()
+
+
+FuSlideShowDlg::FuSlideShowDlg (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor( pViewSh, pWin, pView, pDoc, rReq )
+{
+}
+
+rtl::Reference<FuPoor> FuSlideShowDlg::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuSlideShowDlg( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuSlideShowDlg::DoExecute( SfxRequest& )
+{
+ PresentationSettings& rPresentationSettings = mpDoc->getPresentationSettings();
+
+ SfxItemSetFixed<ATTR_PRESENT_START, ATTR_PRESENT_END> aDlgSet( mpDoc->GetPool() );
+ std::vector<OUString> aPageNameList(mpDoc->GetSdPageCount( PageKind::Standard ));
+ const OUString& rPresPage = rPresentationSettings.maPresPage;
+ OUString aFirstPage;
+ SdPage* pPage = nullptr;
+ ::tools::Long nPage;
+
+ for( nPage = mpDoc->GetSdPageCount( PageKind::Standard ) - 1; nPage >= 0; nPage-- )
+ {
+ pPage = mpDoc->GetSdPage( static_cast<sal_uInt16>(nPage), PageKind::Standard );
+ OUString aStr( pPage->GetName() );
+
+ if ( aStr.isEmpty() )
+ {
+ aStr = SdResId( STR_PAGE ) + OUString::number( nPage + 1 );
+ }
+
+ aPageNameList[ nPage ] = aStr;
+
+ // is this our (existing) first page?
+ if ( rPresPage == aStr )
+ aFirstPage = rPresPage;
+ else if ( pPage->IsSelected() && aFirstPage.isEmpty() )
+ aFirstPage = aStr;
+ }
+ SdCustomShowList* pCustomShowList = mpDoc->GetCustomShowList(); // No Create
+
+ if( aFirstPage.isEmpty() && pPage )
+ aFirstPage = pPage->GetName();
+
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_ALL, rPresentationSettings.mbAll ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_CUSTOMSHOW, rPresentationSettings.mbCustomShow ) );
+ aDlgSet.Put( SfxStringItem( ATTR_PRESENT_DIANAME, aFirstPage ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_ENDLESS, rPresentationSettings.mbEndless ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_MANUEL, rPresentationSettings.mbManual ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_MOUSE, rPresentationSettings.mbMouseVisible ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_PEN, rPresentationSettings.mbMouseAsPen ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_ANIMATION_ALLOWED, rPresentationSettings.mbAnimationAllowed ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_CHANGE_PAGE, !rPresentationSettings.mbLockedPages ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_ALWAYS_ON_TOP, rPresentationSettings.mbAlwaysOnTop ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_FULLSCREEN, rPresentationSettings.mbFullScreen ) );
+ aDlgSet.Put( SfxUInt32Item( ATTR_PRESENT_PAUSE_TIMEOUT, rPresentationSettings.mnPauseTimeout ) );
+ aDlgSet.Put( SfxBoolItem( ATTR_PRESENT_SHOW_PAUSELOGO, rPresentationSettings.mbShowPauseLogo ) );
+
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ aDlgSet.Put( SfxInt32Item( ATTR_PRESENT_DISPLAY, pOptions->GetDisplay() ) );
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSdStartPresDlg> pDlg( pFact->CreateSdStartPresentationDlg(mpWindow ? mpWindow->GetFrameWeld() : nullptr, aDlgSet, aPageNameList, pCustomShowList) );
+ if( pDlg->Execute() != RET_OK )
+ return;
+
+ ::tools::Long nValue32;
+ bool bValue;
+ bool bValuesChanged = false;
+
+ pDlg->GetAttr( aDlgSet );
+
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_ALL, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbAll )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbAll = bValue;
+ // remove any previous existing slide
+ rPresentationSettings.maPresPage.clear();
+ }
+
+ if (!rPresentationSettings.mbAll)
+ {
+ OUString aPage = ITEMVALUE( aDlgSet, ATTR_PRESENT_DIANAME, SfxStringItem );
+ if( aPage != rPresentationSettings.maPresPage )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.maPresPage = aPage;
+ }
+ }
+
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_CUSTOMSHOW, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbCustomShow )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbCustomShow = bValue;
+ rPresentationSettings.mbStartCustomShow = false;
+ }
+
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_ENDLESS, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbEndless )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbEndless = bValue;
+ }
+
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_MANUEL, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbManual )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbManual = bValue;
+ }
+
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_MOUSE, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbMouseVisible )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbMouseVisible = bValue;
+ }
+
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_PEN, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbMouseAsPen )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbMouseAsPen = bValue;
+ }
+
+ bValue = !ITEMVALUE( aDlgSet, ATTR_PRESENT_CHANGE_PAGE, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbLockedPages )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbLockedPages = bValue;
+ }
+
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_ANIMATION_ALLOWED, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbAnimationAllowed )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbAnimationAllowed = bValue;
+ }
+
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_ALWAYS_ON_TOP, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbAlwaysOnTop )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbAlwaysOnTop = bValue;
+ }
+
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_FULLSCREEN, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbFullScreen )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbFullScreen = bValue;
+ }
+
+ nValue32 = ITEMVALUE( aDlgSet, ATTR_PRESENT_PAUSE_TIMEOUT, SfxUInt32Item );
+ if( nValue32 != rPresentationSettings.mnPauseTimeout )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mnPauseTimeout = nValue32;
+ }
+
+ bValue = ITEMVALUE( aDlgSet, ATTR_PRESENT_SHOW_PAUSELOGO, SfxBoolItem );
+ if ( bValue != rPresentationSettings.mbShowPauseLogo )
+ {
+ bValuesChanged = true;
+ rPresentationSettings.mbShowPauseLogo = bValue;
+ }
+
+ pOptions->SetDisplay( ITEMVALUE( aDlgSet, ATTR_PRESENT_DISPLAY, SfxInt32Item ) );
+
+ // is something has changed, we set the modified flag
+ if ( bValuesChanged )
+ mpDoc->SetChanged();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fusnapln.cxx b/sd/source/ui/func/fusnapln.cxx
new file mode 100644
index 000000000..ee51d78ce
--- /dev/null
+++ b/sd/source/ui/func/fusnapln.cxx
@@ -0,0 +1,196 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fusnapln.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/request.hxx>
+#include <svx/svxids.hrc>
+
+#include <strings.hrc>
+#include <sdattr.hrc>
+
+#include <View.hxx>
+#include <ViewShell.hxx>
+#include <DrawViewShell.hxx>
+#include <Window.hxx>
+#include <sdenumdef.hxx>
+#include <sdresid.hxx>
+#include <sdabstdlg.hxx>
+#include <svx/svdpagv.hxx>
+
+namespace sd {
+
+
+FuSnapLine::FuSnapLine(ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView,
+ SdDrawDocument* pDoc, SfxRequest& rReq) :
+ FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuSnapLine::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuSnapLine( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuSnapLine::DoExecute( SfxRequest& rReq )
+{
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ sal_uInt16 nHelpLine = 0;
+ bool bCreateNew = true;
+
+ // Get index of snap line or snap point from the request.
+ const SfxUInt32Item* pHelpLineIndex = rReq.GetArg<SfxUInt32Item>(ID_VAL_INDEX);
+ if (pHelpLineIndex != nullptr)
+ {
+ nHelpLine = static_cast<sal_uInt16>(pHelpLineIndex->GetValue());
+ // Reset the argument pointer to trigger the display of the dialog.
+ pArgs = nullptr;
+ }
+
+ SdrPageView* pPV = mpView->GetSdrPageView();
+
+ if (!pArgs)
+ {
+ SfxItemSetFixed<ATTR_SNAPLINE_START, ATTR_SNAPLINE_END> aNewAttr(mpViewShell->GetPool());
+ bool bLineExist (false);
+ Point aLinePos;
+
+ if (pHelpLineIndex == nullptr)
+ {
+ // The index of the snap line is not provided as argument to the
+ // request. Determine it from the mouse position.
+
+ aLinePos = static_cast<DrawViewShell*>(mpViewShell)->GetMousePos();
+
+ if ( aLinePos.X() >= 0 )
+ {
+ aLinePos = mpWindow->PixelToLogic(aLinePos);
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(mpWindow->PixelToLogic(Size(HITPIX,0)).Width());
+ bLineExist = mpView->PickHelpLine(aLinePos, nHitLog, *mpWindow->GetOutDev(), nHelpLine, pPV);
+ if ( bLineExist )
+ aLinePos = (pPV->GetHelpLines())[nHelpLine].GetPos();
+ else
+ pPV = mpView->GetSdrPageView();
+
+ pPV->LogicToPagePos(aLinePos);
+ }
+ else
+ aLinePos = Point(0,0);
+ }
+ else
+ {
+ assert(pPV!=nullptr);
+ aLinePos = (pPV->GetHelpLines())[nHelpLine].GetPos();
+ pPV->LogicToPagePos(aLinePos);
+ bLineExist = true;
+ }
+ aNewAttr.Put(SfxInt32Item(ATTR_SNAPLINE_X, aLinePos.X()));
+ aNewAttr.Put(SfxInt32Item(ATTR_SNAPLINE_Y, aLinePos.Y()));
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = mpViewShell->GetActiveWindow();
+ ScopedVclPtr<AbstractSdSnapLineDlg> pDlg( pFact->CreateSdSnapLineDlg(pWin ? pWin->GetFrameWeld() : nullptr, aNewAttr, mpView) );
+
+ if ( bLineExist )
+ {
+ pDlg->HideRadioGroup();
+
+ const SdrHelpLine& rHelpLine = (pPV->GetHelpLines())[nHelpLine];
+
+ if ( rHelpLine.GetKind() == SdrHelpLineKind::Point )
+ {
+ pDlg->SetText(SdResId(STR_SNAPDLG_SETPOINT));
+ pDlg->SetInputFields(true, true);
+ }
+ else
+ {
+ pDlg->SetText(SdResId(STR_SNAPDLG_SETLINE));
+
+ if ( rHelpLine.GetKind() == SdrHelpLineKind::Vertical )
+ pDlg->SetInputFields(true, false);
+ else
+ pDlg->SetInputFields(false, true);
+ }
+ bCreateNew = false;
+ }
+ else
+ pDlg->HideDeleteBtn();
+
+ sal_uInt16 nResult = pDlg->Execute();
+
+ pDlg->GetAttr(aNewAttr);
+ pDlg.disposeAndClear();
+
+ switch( nResult )
+ {
+ case RET_OK:
+ rReq.Done(aNewAttr);
+ pArgs = rReq.GetArgs();
+ break;
+
+ case RET_SNAP_DELETE:
+ // delete snap object
+ if ( !bCreateNew )
+ pPV->DeleteHelpLine(nHelpLine);
+ [[fallthrough]];
+ default:
+ return;
+ }
+ }
+ Point aHlpPos;
+
+ aHlpPos.setX( static_cast<const SfxInt32Item&>( pArgs->Get(ATTR_SNAPLINE_X)).GetValue() );
+ aHlpPos.setY( static_cast<const SfxInt32Item&>( pArgs->Get(ATTR_SNAPLINE_Y)).GetValue() );
+ pPV->PagePosToLogic(aHlpPos);
+
+ if ( bCreateNew )
+ {
+ SdrHelpLineKind eKind;
+
+ pPV = mpView->GetSdrPageView();
+
+ switch ( static_cast<SnapKind>(static_cast<const SfxUInt16Item&>(
+ pArgs->Get(ATTR_SNAPLINE_KIND)).GetValue()) )
+ {
+ case SnapKind::Horizontal : eKind = SdrHelpLineKind::Horizontal; break;
+ case SnapKind::Vertical : eKind = SdrHelpLineKind::Vertical; break;
+ default : eKind = SdrHelpLineKind::Point; break;
+ }
+ pPV->InsertHelpLine(SdrHelpLine(eKind, aHlpPos));
+ }
+ else
+ {
+ const SdrHelpLine& rHelpLine = (pPV->GetHelpLines())[nHelpLine];
+ pPV->SetHelpLine(nHelpLine, SdrHelpLine(rHelpLine.GetKind(), aHlpPos));
+ }
+}
+
+void FuSnapLine::Activate()
+{
+}
+
+void FuSnapLine::Deactivate()
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fusumry.cxx b/sd/source/ui/func/fusumry.cxx
new file mode 100644
index 000000000..9b160099c
--- /dev/null
+++ b/sd/source/ui/func/fusumry.cxx
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fusumry.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <editeng/outlobj.hxx>
+#include <xmloff/autolayout.hxx>
+
+#include <strings.hrc>
+
+#include <pres.hxx>
+#include <View.hxx>
+#include <sdpage.hxx>
+#include <Outliner.hxx>
+#include <drawdoc.hxx>
+#include <ViewShell.hxx>
+#include <sdmod.hxx>
+#include <sdresid.hxx>
+#include <DrawViewShell.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+
+FuSummaryPage::FuSummaryPage (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuSummaryPage::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuSummaryPage( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuSummaryPage::DoExecute( SfxRequest& )
+{
+ std::unique_ptr<SdOutliner> pOutl;
+ rtl::Reference<SdPage> pSummaryPage;
+ sal_uInt16 i = 0;
+ sal_uInt16 nFirstPage = SDRPAGE_NOTFOUND;
+ sal_uInt16 nSelectedPages = 0;
+ sal_uInt16 nCount = mpDoc->GetSdPageCount(PageKind::Standard);
+
+ while (i < nCount && nSelectedPages <= 1)
+ {
+ /* How many pages are selected?
+ exactly one: pool everything from this page
+ otherwise: only pool the selected pages */
+ SdPage* pActualPage = mpDoc->GetSdPage(i, PageKind::Standard);
+
+ if (pActualPage->IsSelected())
+ {
+ if (nFirstPage == SDRPAGE_NOTFOUND)
+ {
+ nFirstPage = i;
+ }
+
+ nSelectedPages++;
+ }
+
+ i++;
+ }
+
+ bool bBegUndo = false;
+
+ SfxStyleSheet* pStyle = nullptr;
+
+ for (i = nFirstPage; i < nCount; i++)
+ {
+ SdPage* pActualPage = mpDoc->GetSdPage(i, PageKind::Standard);
+
+ if (nSelectedPages <= 1 || pActualPage->IsSelected())
+ {
+ SdPage* pActualNotesPage = mpDoc->GetSdPage(i, PageKind::Notes);
+ SdrTextObj* pTextObj = static_cast<SdrTextObj*>( pActualPage->GetPresObj(PresObjKind::Title) );
+
+ if (pTextObj && !pTextObj->IsEmptyPresObj())
+ {
+ if (!pSummaryPage)
+ {
+ // insert "table of content"-page and create outliner
+ const bool bUndo = mpView->IsUndoEnabled();
+
+ if( bUndo )
+ {
+ mpView->BegUndo(SdResId(STR_UNDO_SUMMARY_PAGE));
+ bBegUndo = true;
+ }
+
+ SdrLayerIDSet aVisibleLayers = pActualPage->TRG_GetMasterPageVisibleLayers();
+
+ // page with title & structuring!
+ pSummaryPage = mpDoc->AllocSdPage(false);
+ pSummaryPage->SetSize(pActualPage->GetSize() );
+ pSummaryPage->SetBorder(pActualPage->GetLeftBorder(),
+ pActualPage->GetUpperBorder(),
+ pActualPage->GetRightBorder(),
+ pActualPage->GetLowerBorder() );
+
+ // insert page at the back
+ mpDoc->InsertPage(pSummaryPage.get(), nCount * 2 + 1);
+ if( bUndo )
+ mpView->AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoNewPage(*pSummaryPage));
+
+ // use MasterPage of the current page
+ pSummaryPage->TRG_SetMasterPage(pActualPage->TRG_GetMasterPage());
+ pSummaryPage->SetLayoutName(pActualPage->GetLayoutName());
+ pSummaryPage->SetAutoLayout(AUTOLAYOUT_TITLE_CONTENT, true);
+ pSummaryPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+ pSummaryPage->setHeaderFooterSettings(pActualPage->getHeaderFooterSettings());
+
+ // notes-page
+ rtl::Reference<SdPage> pNotesPage = mpDoc->AllocSdPage(false);
+ pNotesPage->SetSize(pActualNotesPage->GetSize());
+ pNotesPage->SetBorder(pActualNotesPage->GetLeftBorder(),
+ pActualNotesPage->GetUpperBorder(),
+ pActualNotesPage->GetRightBorder(),
+ pActualNotesPage->GetLowerBorder() );
+ pNotesPage->SetPageKind(PageKind::Notes);
+
+ // insert page at the back
+ mpDoc->InsertPage(pNotesPage.get(), nCount * 2 + 2);
+
+ if( bUndo )
+ mpView->AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoNewPage(*pNotesPage));
+
+ // use MasterPage of the current page
+ pNotesPage->TRG_SetMasterPage(pActualNotesPage->TRG_GetMasterPage());
+ pNotesPage->SetLayoutName(pActualNotesPage->GetLayoutName());
+ pNotesPage->SetAutoLayout(pActualNotesPage->GetAutoLayout(), true);
+ pNotesPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+ pNotesPage->setHeaderFooterSettings(pActualNotesPage->getHeaderFooterSettings());
+
+ pOutl.reset(new SdOutliner( mpDoc, OutlinerMode::OutlineObject ));
+ pOutl->SetUpdateLayout(false);
+ pOutl->EnableUndo(false);
+
+ if (mpDocSh)
+ pOutl->SetRefDevice(SD_MOD()->GetVirtualRefDevice());
+
+ pOutl->SetDefTab( mpDoc->GetDefaultTabulator() );
+ pOutl->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(mpDoc->GetStyleSheetPool()));
+ pStyle = pSummaryPage->GetStyleSheetForPresObj( PresObjKind::Outline );
+ pOutl->SetStyleSheet( 0, pStyle );
+ }
+
+ // add text
+ OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject();
+ // #118876#, check if the OutlinerParaObject is created successfully
+ if( pParaObj )
+ {
+ pParaObj->SetOutlinerMode( OutlinerMode::OutlineObject );
+ pOutl->AddText(*pParaObj);
+ }
+ }
+ }
+ }
+
+ if (!pSummaryPage)
+ return;
+
+ SdrTextObj* pTextObj = static_cast<SdrTextObj*>( pSummaryPage->GetPresObj(PresObjKind::Outline) );
+
+ if (!pTextObj)
+ return;
+
+ // remove hard break- and character attributes
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aEmptyEEAttr(mpDoc->GetPool());
+ sal_Int32 nParaCount = pOutl->GetParagraphCount();
+
+ for (sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
+ {
+ pOutl->SetStyleSheet( nPara, pStyle );
+ pOutl->RemoveCharAttribs(nPara);
+ pOutl->SetParaAttribs(nPara, aEmptyEEAttr);
+ pOutl->SetDepth(pOutl->GetParagraph(nPara), 0);
+ }
+
+ pTextObj->SetOutlinerParaObject( pOutl->CreateParaObject() );
+ pTextObj->SetEmptyPresObj(false);
+
+ // remove hard attributes (Flag to sal_True)
+ SfxItemSet aAttr(mpDoc->GetPool());
+ aAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ aAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ pTextObj->SetMergedItemSet(aAttr);
+
+ if( bBegUndo )
+ mpView->EndUndo();
+ pOutl.reset();
+
+ DrawViewShell* pDrawViewShell= dynamic_cast< DrawViewShell* >( mpViewShell );
+ if(pDrawViewShell)
+ {
+ pDrawViewShell->SwitchPage( (pSummaryPage->GetPageNum() - 1) / 2);
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/futempl.cxx b/sd/source/ui/func/futempl.cxx
new file mode 100644
index 000000000..2c0c22ecd
--- /dev/null
+++ b/sd/source/ui/func/futempl.cxx
@@ -0,0 +1,638 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+
+#include <futempl.hxx>
+
+#include <svx/svxids.hrc>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <editeng/eeitem.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <editeng/numitem.hxx>
+#include <svx/svdopage.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/brushitem.hxx>
+#include <svx/svditer.hxx>
+#include <svx/sdr/properties/properties.hxx>
+#include <svl/intitem.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <o3tl/string_view.hxx>
+#include <app.hrc>
+#include <stlsheet.hxx>
+#include <sdpage.hxx>
+#include <stlpool.hxx>
+#include <sdmod.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShell.hxx>
+
+#include <strings.hrc>
+#include <prlayout.hxx>
+#include <sdresid.hxx>
+#include <OutlineView.hxx>
+#include <sdabstdlg.hxx>
+#include <memory>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::container;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::style;
+
+namespace sd
+{
+
+
+FuTemplate::FuTemplate (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq )
+ : FuPoor( pViewSh, pWin, pView, pDoc, rReq )
+{
+}
+
+rtl::Reference<FuPoor> FuTemplate::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuTemplate( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuTemplate::DoExecute( SfxRequest& rReq )
+{
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ sal_uInt16 nSId = rReq.GetSlot();
+
+ // get StyleSheet parameter
+ SfxStyleSheetBasePool* pSSPool = mpDoc->GetDocSh()->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = nullptr;
+
+ const SfxPoolItem* pItem;
+ SfxStyleFamily nFamily = SfxStyleFamily(USHRT_MAX);
+ if( pArgs && SfxItemState::SET == pArgs->GetItemState( SID_STYLE_FAMILY,
+ false, &pItem ))
+ {
+ nFamily = static_cast<SfxStyleFamily>( pArgs->Get( SID_STYLE_FAMILY ).GetValue());
+ }
+ else if( pArgs && SfxItemState::SET == pArgs->GetItemState( SID_STYLE_FAMILYNAME,
+ false, &pItem ))
+ {
+ OUString sFamily = pArgs->Get( SID_STYLE_FAMILYNAME ).GetValue();
+ if (sFamily == "graphics")
+ nFamily = SfxStyleFamily::Para;
+ else
+ nFamily = SfxStyleFamily::Pseudo;
+ }
+
+ OUString aStyleName;
+ sal_uInt16 nRetMask = static_cast<sal_uInt16>(SfxStyleSearchBits::All);
+
+ switch( nSId )
+ {
+ case SID_STYLE_APPLY:
+ case SID_STYLE_EDIT:
+ case SID_STYLE_DELETE:
+ case SID_STYLE_HIDE:
+ case SID_STYLE_SHOW:
+ case SID_STYLE_FAMILY:
+ case SID_STYLE_NEW_BY_EXAMPLE:
+ {
+ const SfxStringItem* pNameItem = rReq.GetArg<SfxStringItem>(SID_APPLY_STYLE);
+ const SfxStringItem* pFamilyItem = rReq.GetArg<SfxStringItem>(SID_STYLE_FAMILYNAME);
+ if ( pFamilyItem && pNameItem )
+ {
+ try
+ {
+ Reference< XStyleFamiliesSupplier > xModel(mpDoc->GetDocSh()->GetModel(), UNO_QUERY_THROW );
+ Reference< XNameAccess > xCont( xModel->getStyleFamilies() );
+ Reference< XNameAccess > xStyles( xCont->getByName(pFamilyItem->GetValue()), UNO_QUERY_THROW );
+ Reference< XPropertySet > xInfo( xStyles->getByName( pNameItem->GetValue() ), UNO_QUERY_THROW );
+
+ OUString aUIName;
+ xInfo->getPropertyValue( "DisplayName" ) >>= aUIName;
+ if ( !aUIName.isEmpty() )
+ rReq.AppendItem( SfxStringItem( nSId, aUIName ) );
+ }
+ catch( Exception& )
+ {
+ }
+ }
+
+ if (pArgs && pArgs->GetItemState(nSId) == SfxItemState::SET)
+ aStyleName = static_cast<const SfxStringItem &>( pArgs->Get( nSId ) ).GetValue();
+ }
+ }
+
+ switch( nSId )
+ {
+ case SID_STYLE_NEW:
+ {
+ SfxStyleSheetBase *p = pSSPool->Find(aStyleName, nFamily );
+ if(p)
+ {
+ pSSPool->Remove(p);
+ p = nullptr;
+ }
+ pStyleSheet = &pSSPool->Make( aStyleName, nFamily, SfxStyleSearchBits::UserDefined );
+
+ if (pArgs && pArgs->GetItemState(SID_STYLE_REFERENCE) == SfxItemState::SET)
+ {
+ OUString aParentName( pArgs->Get(SID_STYLE_REFERENCE).GetValue());
+ pStyleSheet->SetParent(aParentName);
+ }
+ else
+ {
+ pStyleSheet->SetParent(SdResId(STR_STANDARD_STYLESHEET_NAME));
+ }
+ }
+ break;
+
+ case SID_STYLE_NEW_BY_EXAMPLE:
+ {
+ // at the moment, the dialog to enter the name of the template is still opened
+ SfxStyleSheetBase *p = pSSPool->Find(aStyleName, nFamily );
+ if(p)
+ {
+ pSSPool->Remove(p);
+ p = nullptr;
+ }
+ pStyleSheet = &pSSPool->Make( aStyleName, nFamily, SfxStyleSearchBits::UserDefined );
+ pStyleSheet->SetParent(SdResId(STR_STANDARD_STYLESHEET_NAME));
+ }
+ break;
+
+ case SID_STYLE_EDIT:
+ pStyleSheet = pSSPool->Find( aStyleName, nFamily);
+ break;
+
+ case SID_STYLE_DELETE:
+ pStyleSheet = pSSPool->Find( aStyleName, nFamily);
+ if( pStyleSheet )
+ {
+ pSSPool->Remove( pStyleSheet );
+ nRetMask = sal_uInt16(true);
+ mpDoc->SetChanged();
+ }
+ else
+ {
+ nRetMask = sal_uInt16(false);
+ }
+ break;
+
+ case SID_STYLE_HIDE:
+ case SID_STYLE_SHOW:
+ pStyleSheet = pSSPool->Find( aStyleName, nFamily);
+ pStyleSheet->SetHidden( nSId == SID_STYLE_HIDE );
+ nRetMask = sal_uInt16(true);
+ break;
+
+ case SID_STYLE_APPLY:
+ // apply the template to the document
+ pStyleSheet = pSSPool->Find( aStyleName, nFamily);
+
+ // do not set presentation styles, they will be set implicit
+ if ( pStyleSheet && pStyleSheet->GetFamily() != SfxStyleFamily::Pseudo )
+ {
+ SfxStyleSheet* pOldStyleSheet = mpView->GetStyleSheet();
+ OUString aStr;
+
+ if( // if the object had no style sheet, allow all
+ !pOldStyleSheet ||
+
+ // allow if old and new style sheet has same family
+ pStyleSheet->GetFamily() == pOldStyleSheet->GetFamily() ||
+
+ // allow if old was background objects and new is graphics
+ (pStyleSheet->GetFamily() == SfxStyleFamily::Para && pOldStyleSheet->GetHelpId( aStr ) == HID_PSEUDOSHEET_BACKGROUNDOBJECTS) ||
+
+ // allow if old was presentation and we are a drawing document
+ (pOldStyleSheet->GetFamily() == SfxStyleFamily::Page && mpDoc->GetDocumentType() == DocumentType::Draw) )
+ {
+ mpView->SetStyleSheet( static_cast<SfxStyleSheet*>(pStyleSheet));
+ mpDoc->SetChanged();
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_STYLE_FAMILY2 );
+ }
+ }
+ break;
+
+ case SID_STYLE_WATERCAN:
+ {
+ if( !SD_MOD()->GetWaterCan() )
+ {
+ if (pArgs && pArgs->GetItemState( nSId ) == SfxItemState::SET)
+ {
+ aStyleName = static_cast<const SfxStringItem &>( pArgs->Get( nSId ) ).GetValue();
+ SD_MOD()->SetWaterCan( true );
+ pStyleSheet = pSSPool->Find( aStyleName, nFamily);
+ }
+ // no presentation object templates, they are only allowed implicitly
+ if( pStyleSheet && pStyleSheet->GetFamily() != SfxStyleFamily::Pseudo )
+ {
+ static_cast<SdStyleSheetPool*>( pSSPool )->SetActualStyleSheet( pStyleSheet );
+
+ // we switch explicitly into selection mode
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_OBJECT_SELECT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+
+ }
+ else
+ SD_MOD()->SetWaterCan( false );
+ }
+ else
+ {
+ SD_MOD()->SetWaterCan( false );
+ // we have to re-enable to tools-bar
+ mpViewShell->Invalidate();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch( nSId )
+ {
+ case SID_STYLE_NEW:
+ case SID_STYLE_EDIT:
+ {
+ PresentationObjects ePO = PresentationObjects::Outline_1;
+
+ if( pStyleSheet )
+ {
+ ScopedVclPtr<SfxAbstractTabDialog> pStdDlg;
+ ScopedVclPtr<SfxAbstractTabDialog> pPresDlg;
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+
+ SfxStyleFamily eFamily = pStyleSheet->GetFamily();
+
+ if (eFamily == SfxStyleFamily::Para)
+ {
+ pStdDlg.disposeAndReset(pFact ? pFact->CreateSdTabTemplateDlg(mpViewShell->GetFrameWeld(), mpDoc->GetDocSh(), *pStyleSheet, mpDoc, mpView) : nullptr);
+ }
+ else if (eFamily == SfxStyleFamily::Pseudo)
+ {
+ OUString aName(pStyleSheet->GetName());
+ bool bBackground = false;
+ bool bOldDocInOtherLanguage = false;
+
+ if (aName == SdResId(STR_PSEUDOSHEET_TITLE))
+ {
+ ePO = PresentationObjects::Title;
+ }
+ else if (aName == SdResId(STR_PSEUDOSHEET_SUBTITLE))
+ {
+ ePO = PresentationObjects::Subtitle;
+ }
+ else if (aName ==
+ SdResId(STR_PSEUDOSHEET_BACKGROUND))
+ {
+ bBackground = true;
+ ePO = PresentationObjects::Background;
+ }
+ else if (aName ==
+ SdResId(STR_PSEUDOSHEET_BACKGROUNDOBJECTS))
+ {
+ ePO = PresentationObjects::BackgroundObjects;
+ }
+ else if (aName ==
+ SdResId(STR_PSEUDOSHEET_NOTES))
+ {
+ ePO = PresentationObjects::Notes;
+ }
+ else if(aName.indexOf(SdResId(STR_PSEUDOSHEET_OUTLINE)) != -1)
+ {
+ OUString aOutlineStr(SdResId(STR_PSEUDOSHEET_OUTLINE));
+ // determine number, mind the blank between name and number
+ std::u16string_view aNumStr(aName.subView(aOutlineStr.getLength() + 1));
+ sal_uInt16 nLevel = static_cast<sal_uInt16>(o3tl::toInt32(aNumStr));
+ switch (nLevel)
+ {
+ case 1: ePO = PresentationObjects::Outline_1; break;
+ case 2: ePO = PresentationObjects::Outline_2; break;
+ case 3: ePO = PresentationObjects::Outline_3; break;
+ case 4: ePO = PresentationObjects::Outline_4; break;
+ case 5: ePO = PresentationObjects::Outline_5; break;
+ case 6: ePO = PresentationObjects::Outline_6; break;
+ case 7: ePO = PresentationObjects::Outline_7; break;
+ case 8: ePO = PresentationObjects::Outline_8; break;
+ case 9: ePO = PresentationObjects::Outline_9; break;
+ }
+ }
+ else
+ {
+ OSL_FAIL("StyleSheet from older version with different language");
+ bOldDocInOtherLanguage = true;
+ }
+
+ if( !bOldDocInOtherLanguage )
+ {
+ pPresDlg.disposeAndReset(pFact ? pFact->CreateSdPresLayoutTemplateDlg(mpDocSh, mpViewShell->GetFrameWeld(), bBackground, *pStyleSheet, ePO, pSSPool ) : nullptr);
+ }
+ }
+
+ sal_uInt16 nResult = RET_CANCEL;
+ const SfxItemSet* pOutSet = nullptr;
+ if (pStdDlg)
+ {
+ nResult = pStdDlg->Execute();
+ pOutSet = pStdDlg->GetOutputItemSet();
+ }
+ else if( pPresDlg )
+ {
+ nResult = pPresDlg->Execute();
+ pOutSet = pPresDlg->GetOutputItemSet();
+ }
+
+ switch( nResult )
+ {
+ case RET_OK:
+ {
+ nRetMask = static_cast<sal_uInt16>(pStyleSheet->GetMask());
+
+ if (eFamily == SfxStyleFamily::Pseudo)
+ {
+ SfxItemSet aTempSet(*pOutSet);
+ /* Extract SvxBrushItem out of set and insert SvxColorItem */
+ const SvxBrushItem* pBrushItem = aTempSet.GetItem<SvxBrushItem>( SID_ATTR_BRUSH_CHAR );
+
+ if ( pBrushItem )
+ {
+ SvxColorItem aBackColorItem(pBrushItem->GetColor(), EE_CHAR_BKGCOLOR);
+ aTempSet.ClearItem( EE_CHAR_BKGCOLOR );
+ aTempSet.Put( aBackColorItem );
+ }
+ static_cast<SdStyleSheet*>(pStyleSheet)->AdjustToFontHeight(aTempSet);
+
+ /* Special treatment: reset the INVALIDS to
+ NULL-Pointer (otherwise INVALIDs or pointer point
+ to DefaultItems in the template; both would
+ prevent the attribute inheritance) */
+ aTempSet.ClearInvalidItems();
+
+ // EE_PARA_NUMBULLET item is only valid in first outline template
+ if( (ePO >= PresentationObjects::Outline_2) && (ePO <= PresentationObjects::Outline_9) )
+ {
+ if (aTempSet.GetItemState(EE_PARA_NUMBULLET) == SfxItemState::SET)
+ {
+ SvxNumRule aRule(aTempSet.GetItem<SvxNumBulletItem>(EE_PARA_NUMBULLET)->GetNumRule());
+
+ OUString sStyleName(SdResId(STR_PSEUDOSHEET_OUTLINE) + " 1");
+ SfxStyleSheetBase* pFirstStyleSheet = pSSPool->Find( sStyleName, SfxStyleFamily::Pseudo);
+
+ if(pFirstStyleSheet)
+ {
+ pFirstStyleSheet->GetItemSet().Put( SvxNumBulletItem( aRule, EE_PARA_NUMBULLET ));
+ SdStyleSheet* pRealSheet = static_cast<SdStyleSheet*>(pFirstStyleSheet)->GetRealStyleSheet();
+ pRealSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ }
+
+ aTempSet.ClearItem( EE_PARA_NUMBULLET );
+ }
+ }
+
+ pStyleSheet->GetItemSet().Put(aTempSet);
+ SdStyleSheet::BroadcastSdStyleSheetChange(pStyleSheet, ePO, pSSPool);
+ }
+
+ SfxItemSet& rAttr = pStyleSheet->GetItemSet();
+
+ sdr::properties::CleanupFillProperties( rAttr );
+
+ // check for unique names of named items for xml
+ if( rAttr.GetItemState( XATTR_FILLBITMAP ) == SfxItemState::SET )
+ {
+ const SfxPoolItem* pOldItem = rAttr.GetItem( XATTR_FILLBITMAP );
+ std::unique_ptr<SfxPoolItem> pNewItem = static_cast<const XFillBitmapItem*>(pOldItem)->checkForUniqueItem( mpDoc );
+ if( pNewItem )
+ {
+ rAttr.Put( std::move(pNewItem) );
+ }
+ }
+ if( rAttr.GetItemState( XATTR_LINEDASH ) == SfxItemState::SET )
+ {
+ const SfxPoolItem* pOldItem = rAttr.GetItem( XATTR_LINEDASH );
+ std::unique_ptr<SfxPoolItem> pNewItem = static_cast<const XLineDashItem*>(pOldItem)->checkForUniqueItem( mpDoc );
+ if( pNewItem )
+ {
+ rAttr.Put( std::move(pNewItem) );
+ }
+ }
+ if( rAttr.GetItemState( XATTR_LINESTART ) == SfxItemState::SET )
+ {
+ const SfxPoolItem* pOldItem = rAttr.GetItem( XATTR_LINESTART );
+ std::unique_ptr<SfxPoolItem> pNewItem = static_cast<const XLineStartItem*>(pOldItem)->checkForUniqueItem( mpDoc );
+ if( pNewItem )
+ {
+ rAttr.Put( std::move(pNewItem) );
+ }
+ }
+ if( rAttr.GetItemState( XATTR_LINEEND ) == SfxItemState::SET )
+ {
+ const SfxPoolItem* pOldItem = rAttr.GetItem( XATTR_LINEEND );
+ std::unique_ptr<SfxPoolItem> pNewItem = static_cast<const XLineEndItem*>(pOldItem)->checkForUniqueItem( mpDoc );
+ if( pNewItem )
+ {
+ rAttr.Put( std::move(pNewItem) );
+ }
+ }
+ if( rAttr.GetItemState( XATTR_FILLGRADIENT ) == SfxItemState::SET )
+ {
+ const SfxPoolItem* pOldItem = rAttr.GetItem( XATTR_FILLGRADIENT );
+ std::unique_ptr<SfxPoolItem> pNewItem = static_cast<const XFillGradientItem*>(pOldItem)->checkForUniqueItem( mpDoc );
+ if( pNewItem )
+ {
+ rAttr.Put( std::move(pNewItem) );
+ }
+ }
+ if( rAttr.GetItemState( XATTR_FILLFLOATTRANSPARENCE ) == SfxItemState::SET )
+ {
+ const SfxPoolItem* pOldItem = rAttr.GetItem( XATTR_FILLFLOATTRANSPARENCE );
+ std::unique_ptr<SfxPoolItem> pNewItem = static_cast<const XFillFloatTransparenceItem*>(pOldItem)->checkForUniqueItem( mpDoc );
+ if( pNewItem )
+ {
+ rAttr.Put( std::move(pNewItem) );
+ }
+ }
+ if( rAttr.GetItemState( XATTR_FILLHATCH ) == SfxItemState::SET )
+ {
+ const SfxPoolItem* pOldItem = rAttr.GetItem( XATTR_FILLHATCH );
+ std::unique_ptr<SfxPoolItem> pNewItem = static_cast<const XFillHatchItem*>(pOldItem)->checkForUniqueItem( mpDoc );
+ if( pNewItem )
+ {
+ rAttr.Put( std::move(pNewItem) );
+ }
+ }
+
+ static_cast<SfxStyleSheet*>( pStyleSheet )->Broadcast( SfxHint( SfxHintId::DataChanged ) );
+
+ DrawViewShell* pDrawViewShell = dynamic_cast< DrawViewShell* >( mpViewShell );
+ if( pDrawViewShell )
+ {
+ PageKind ePageKind = pDrawViewShell->GetPageKind();
+ if( ePageKind == PageKind::Notes || ePageKind == PageKind::Handout )
+ {
+ SdPage* pPage = mpViewShell->GetActualPage();
+
+ if(pDrawViewShell->GetEditMode() == EditMode::MasterPage)
+ {
+ pPage = static_cast<SdPage*>((&(pPage->TRG_GetMasterPage())));
+ }
+
+ if( pPage )
+ {
+ SdrObjListIter aIter( pPage );
+ while( aIter.IsMore() )
+ {
+ SdrObject* pObj = aIter.Next();
+ if( dynamic_cast< const SdrPageObj *>( pObj ) != nullptr )
+ {
+ // repaint only
+ pObj->ActionChanged();
+ // pObj->SendRepaintBroadcast();
+ }
+ }
+ }
+ }
+ }
+
+ if( mpDoc->GetOnlineSpell() )
+ {
+ if( SfxItemState::SET == rAttr.GetItemState(EE_CHAR_LANGUAGE, false ) ||
+ SfxItemState::SET == rAttr.GetItemState(EE_CHAR_LANGUAGE_CJK, false ) ||
+ SfxItemState::SET == rAttr.GetItemState(EE_CHAR_LANGUAGE_CTL, false ) )
+ {
+ mpDoc->StopOnlineSpelling();
+ mpDoc->StartOnlineSpelling();
+ }
+ }
+
+ mpDoc->SetChanged();
+ }
+ break;
+
+ default:
+ {
+ if( nSId == SID_STYLE_NEW )
+ pSSPool->Remove( pStyleSheet );
+ }
+ return; // Cancel
+ }
+ }
+ }
+ break;
+
+ case SID_STYLE_NEW_BY_EXAMPLE:
+ {
+ if( pStyleSheet )
+ {
+ nRetMask = static_cast<sal_uInt16>(pStyleSheet->GetMask());
+ SfxItemSet aCoreSet( mpDoc->GetPool() );
+ mpView->GetAttributes( aCoreSet, true );
+
+ // if the object had a template, this becomes parent of the new template
+ SfxStyleSheet* pOldStyle = mpView->GetStyleSheet();
+
+ // if pOldStyle == pStyleSheet -> recursion
+ if( pOldStyle != pStyleSheet )
+ {
+ if (pOldStyle)
+ {
+ pStyleSheet->SetParent(pOldStyle->GetName());
+ }
+
+ SfxItemSet* pStyleSet = &pStyleSheet->GetItemSet();
+ pStyleSet->Put(aCoreSet);
+
+ /* apply template (but not when somebody is editing a text.
+ To do this, the edit engine had to be capable to use
+ templates on a character level. */
+ if (!mpView->GetTextEditObject())
+ {
+ mpView->SetStyleSheet( static_cast<SfxStyleSheet*>(pStyleSheet));
+ }
+
+ static_cast<SfxStyleSheet*>( pStyleSheet )->Broadcast( SfxHint( SfxHintId::DataChanged ) );
+ mpDoc->SetChanged();
+
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_STYLE_FAMILY2 );
+ }
+ }
+ }
+ break;
+
+ case SID_STYLE_UPDATE_BY_EXAMPLE:
+ {
+ if ((mpView->AreObjectsMarked() && mpView->GetMarkedObjectList().GetMarkCount() == 1) ||
+ dynamic_cast< const OutlineView *>( mpView ) != nullptr)
+ {
+ pStyleSheet = mpView->GetStyleSheet();
+
+ if( pStyleSheet )
+ {
+ nRetMask = static_cast<sal_uInt16>(pStyleSheet->GetMask());
+ SfxItemSet aCoreSet( mpDoc->GetPool() );
+ mpView->GetAttributes( aCoreSet );
+
+ SfxItemSet* pStyleSet = &pStyleSheet->GetItemSet();
+ pStyleSet->Put( aCoreSet );
+
+ mpView->SetStyleSheet( static_cast<SfxStyleSheet*>(pStyleSheet));
+
+ static_cast<SfxStyleSheet*>( pStyleSheet )->Broadcast( SfxHint( SfxHintId::DataChanged ) );
+ mpDoc->SetChanged();
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_STYLE_FAMILY2 );
+ }
+ }
+ }
+ break;
+
+ }
+ if( nRetMask != static_cast<sal_uInt16>(SfxStyleSearchBits::All) )
+ rReq.SetReturnValue( SfxUInt16Item( nSId, nRetMask ) );
+}
+
+void FuTemplate::Activate()
+{
+}
+
+void FuTemplate::Deactivate()
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/futext.cxx b/sd/source/ui/func/futext.cxx
new file mode 100644
index 000000000..725bf96e1
--- /dev/null
+++ b/sd/source/ui/func/futext.cxx
@@ -0,0 +1,1464 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <futext.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/help.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <svx/svdotext.hxx>
+#include <editeng/flditem.hxx>
+#include <svl/style.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/sdtmfitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <editeng/editeng.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svxids.hrc>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <sfx2/docfile.hxx>
+#include <editeng/outlobj.hxx>
+#include <osl/diagnose.h>
+
+#include <editeng/frmdiritem.hxx>
+
+#include <svx/svdetc.hxx>
+#include <editeng/editview.hxx>
+
+#include <sdresid.hxx>
+#include <app.hrc>
+
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <View.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <FrameView.hxx>
+#include <ToolBarManager.hxx>
+#include <DrawDocShell.hxx>
+#include <strings.hrc>
+#include <pres.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::linguistic2;
+
+namespace sd {
+
+const sal_uInt16 SidArray[] = {
+ SID_STYLE_FAMILY2, // 5542
+ SID_STYLE_FAMILY5, // 5545
+ SID_REDO, // 5700
+ SID_UNDO, // 5701
+ SID_CUT, // 5710
+ SID_COPY, // 5711
+ SID_ATTR_TABSTOP, // 10002
+ SID_ATTR_CHAR_FONT, // 10007
+ SID_ATTR_CHAR_POSTURE, // 10008
+ SID_ATTR_CHAR_WEIGHT, // 10009
+ SID_ATTR_CHAR_SHADOWED, // 10010
+ SID_ATTR_CHAR_STRIKEOUT, // 10013
+ SID_ATTR_CHAR_UNDERLINE, // 10014
+ SID_ATTR_CHAR_FONTHEIGHT, // 10015
+ SID_ATTR_CHAR_COLOR, // 10017
+ SID_ATTR_CHAR_KERNING, // 10018
+ SID_ATTR_CHAR_CASEMAP, // 10019
+ SID_ATTR_PARA_ADJUST_LEFT, // 10028
+ SID_ATTR_PARA_ADJUST_RIGHT, // 10029
+ SID_ATTR_PARA_ADJUST_CENTER, // 10030
+ SID_ATTR_PARA_ADJUST_BLOCK, // 10031
+ SID_ATTR_PARA_LINESPACE_10, // 10034
+ SID_ATTR_PARA_LINESPACE_15, // 10035
+ SID_ATTR_PARA_LINESPACE_20, // 10036
+ SID_ATTR_PARA_ULSPACE, // 10042
+ SID_ATTR_PARA_LRSPACE, // 10043
+ SID_ATTR_TRANSFORM_POS_X, // 10088
+ SID_ATTR_TRANSFORM_POS_Y, // 10089
+ SID_ATTR_TRANSFORM_WIDTH, // 10090
+ SID_ATTR_TRANSFORM_HEIGHT, // 10091
+ SID_ATTR_TRANSFORM_ROT_X, // 10093
+ SID_ATTR_TRANSFORM_ROT_Y, // 10094
+ SID_ATTR_TRANSFORM_ANGLE, // 10095 //Added
+ SID_OUTLINE_UP, // 10150
+ SID_OUTLINE_DOWN, // 10151
+ SID_OUTLINE_LEFT, // 10152
+ SID_OUTLINE_RIGHT, // 10153
+ SID_ATTR_TRANSFORM_PROTECT_POS, // 10236
+ SID_ATTR_TRANSFORM_PROTECT_SIZE, // 10237 //Added
+ SID_FORMTEXT_STYLE, // 10257
+ SID_SET_SUPER_SCRIPT, // 10294
+ SID_SET_SUB_SCRIPT, // 10295
+ SID_ATTR_TRANSFORM_AUTOWIDTH, // 10310
+ SID_ATTR_TRANSFORM_AUTOHEIGHT, // 10311 //Added
+ SID_HYPERLINK_GETLINK, // 10361
+ SID_DEC_INDENT, // 10461
+ SID_INC_INDENT, // 10462
+ SID_CHARMAP, // 10503
+ SID_TEXTDIRECTION_LEFT_TO_RIGHT, // 10907
+ SID_TEXTDIRECTION_TOP_TO_BOTTOM, // 10908
+ SID_ATTR_PARA_LEFT_TO_RIGHT, // 10950
+ SID_ATTR_PARA_RIGHT_TO_LEFT, // 10951
+ SID_PARASPACE_INCREASE, // 11145
+ SID_PARASPACE_DECREASE, // 11146
+ FN_NUM_BULLET_ON, // 20138
+ 0 };
+
+
+/**
+ * base class for text functions
+ */
+FuText::FuText( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+: FuConstruct(pViewSh, pWin, pView, pDoc, rReq)
+, bFirstObjCreated(false)
+, bJustEndedEdit(false)
+, rRequest (rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuText::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuText( pViewSh, pWin, pView, pDoc, rReq ) );
+ return xFunc;
+}
+
+void FuText::disposing()
+{
+ if(mpView)
+ {
+ if(mpView->SdrEndTextEdit() == SdrEndTextEditKind::Deleted)
+ mxTextObj.reset(nullptr);
+
+ // reset the RequestHandler of the used Outliner to the handler of the document
+ ::Outliner* pOutliner = mpView->GetTextEditOutliner();
+
+ if (pOutliner)
+ pOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(mpDoc->GetStyleSheetPool()));
+ }
+}
+
+/*************************************************************************
+|*
+|* Execute functionality of this class:
+|*
+|* #71422: Start the functionality of this class in this method
+|* and not in the ctor.
+|* If you construct an object of this class and you put the
+|* address of this object to pFuActual you've got a problem,
+|* because some methods inside DoExecute use the pFuActual-Pointer.
+|* If the code inside DoExecute is executed inside the ctor,
+|* the value of pFuActual is not right. And the value will not
+|* be right until the ctor finished !!!
+|*
+\************************************************************************/
+void FuText::DoExecute( SfxRequest& )
+{
+ mpViewShell->GetViewShellBase().GetToolBarManager()->SetToolBarShell(
+ ToolBarManager::ToolBarGroup::Function,
+ ToolbarId::Draw_Text_Toolbox_Sd);
+
+ mpView->SetCurrentObj(SdrObjKind::Text);
+ mpView->SetEditMode(SdrViewEditMode::Edit);
+
+ MouseEvent aMEvt(mpWindow->GetPointerPosPixel());
+
+ if (nSlotId == SID_TEXTEDIT)
+ {
+ // Try to select an object
+ SdrPageView* pPV = mpView->GetSdrPageView();
+ SdrViewEvent aVEvt;
+ mpView->PickAnything(aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+ mpView->MarkObj(aVEvt.mpRootObj, pPV);
+
+ mxTextObj.reset( dynamic_cast< SdrTextObj* >( aVEvt.mpObj ) );
+ }
+ else if (mpView->AreObjectsMarked())
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ mxTextObj.reset( dynamic_cast< SdrTextObj* >( pObj ) );
+ }
+ }
+
+ // check for table
+ if (mpView->AreObjectsMarked())
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if( pObj && (pObj->GetObjInventor() == SdrInventor::Default ) && (pObj->GetObjIdentifier() == SdrObjKind::Table) )
+ {
+ mpViewShell->GetViewShellBase().GetToolBarManager()->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Table_Toolbox);
+ }
+ }
+ }
+
+ bool bQuickDrag = true;
+
+ const SfxItemSet* pArgs = rRequest.GetArgs();
+
+ if (pArgs
+
+ // test for type before using
+ && SID_TEXTEDIT == nSlotId
+ && SfxItemState::SET == pArgs->GetItemState(SID_TEXTEDIT)
+
+ && static_cast<const SfxUInt16Item&>(pArgs->Get(SID_TEXTEDIT)).GetValue() == 2)
+ {
+ // Selection by doubleclick -> don't allow QuickDrag
+ bQuickDrag = false;
+ }
+
+ SetInEditMode(aMEvt, bQuickDrag);
+}
+
+bool FuText::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bMBDown = true;
+ bJustEndedEdit = false;
+
+ bool bReturn = FuDraw::MouseButtonDown(rMEvt);
+
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+
+ // handle URL also during the text editing
+ if (rMEvt.GetClicks() == 1 && rMEvt.IsLeft() && rMEvt.IsMod1())
+ {
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+
+ if (mxTextObj.is() && pOLV && pOLV->GetFieldUnderMousePointer())
+ {
+ const SvxFieldItem* pFieldItem = pOLV->GetFieldUnderMousePointer();
+ if (pFieldItem)
+ {
+ const SvxFieldData* pField = pFieldItem->GetField();
+
+ if (auto pURLField = dynamic_cast< const SvxURLField *>( pField ))
+ {
+ eHit = SdrHitKind::MarkedObject;
+ aVEvt.meEvent = SdrEventKind::ExecuteUrl;
+ aVEvt.mpURLField = pURLField;
+ }
+ }
+ }
+ }
+
+ if (eHit == SdrHitKind::TextEdit)
+ {
+ // hit text -> SdrView handles event
+ if (mpView->MouseButtonDown(rMEvt, mpWindow->GetOutDev()))
+ return true;
+ }
+
+ if (rMEvt.GetClicks() == 1)
+ {
+ if (mpView->IsTextEdit() && eHit != SdrHitKind::MarkedObject && eHit != SdrHitKind::Handle)
+ {
+ // finish text input
+ if(mpView->SdrEndTextEdit() == SdrEndTextEditKind::Deleted)
+ {
+ /* Bugfix from MBA: during a double click onto the unused? area
+ in text mode, we get with the second click eHit =
+ SdrHitKind::TextEditObj since it goes to the TextObject which was
+ created with the first click. But this is removed by
+ SdrEndTextEdit since it is empty. But it is still in the mark
+ list. The call MarkObj further below accesses then the dead
+ object. As a simple fix, we determine eHit after
+ SdrEndTextEdit again, this returns then SdrHitKind::NONE. */
+ mxTextObj.reset(nullptr);
+ eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+ }
+
+ mpView->SetCurrentObj(SdrObjKind::Text);
+ mpView->SetEditMode(SdrViewEditMode::Edit);
+ }
+
+ if (rMEvt.IsLeft() || rMEvt.IsRight())
+ {
+ mpWindow->CaptureMouse();
+ SdrPageView* pPV = mpView->GetSdrPageView();
+
+ if (eHit == SdrHitKind::TextEdit)
+ {
+ SetInEditMode(rMEvt, false);
+ }
+ else
+ {
+ // Don't remark table when clicking in it, mark change triggers a lot of updating
+ bool bMarkChanges = true;
+ rtl::Reference< sdr::SelectionController > xSelectionController(mpView->getSelectionController());
+ if (eHit == SdrHitKind::TextEditObj && xSelectionController.is())
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1 && rMarkList.GetMark(0)->GetMarkedSdrObj() == aVEvt.mpRootObj)
+ bMarkChanges = false;
+ }
+
+ if (eHit != SdrHitKind::Handle)
+ {
+ // deselect selection
+ if (!rMEvt.IsShift() && eHit == SdrHitKind::TextEditObj)
+ {
+ if(bMarkChanges)
+ {
+ mpView->UnmarkAll();
+ mpView->SetDragMode(SdrDragMode::Move);
+ }
+ }
+ }
+
+ if ( aVEvt.meEvent == SdrEventKind::ExecuteUrl ||
+ eHit == SdrHitKind::Handle ||
+ eHit == SdrHitKind::MarkedObject ||
+ eHit == SdrHitKind::TextEditObj ||
+ ( eHit == SdrHitKind::UnmarkedObject && bFirstObjCreated &&
+ !bPermanent ) )
+ {
+ // Handle, hit marked or unmarked object
+ if (eHit == SdrHitKind::TextEditObj)
+ {
+ /* hit text of unmarked object:
+ select object and set to EditMode */
+ if (bMarkChanges)
+ mpView->MarkObj(aVEvt.mpRootObj, pPV);
+
+ if (auto pSdrTextObj = dynamic_cast<SdrTextObj*>(aVEvt.mpObj))
+ {
+ mxTextObj.reset( pSdrTextObj );
+ }
+
+ SetInEditMode(rMEvt, true);
+ }
+ else if (aVEvt.meEvent == SdrEventKind::ExecuteUrl && !rMEvt.IsMod2())
+ {
+ // execute URL
+ mpWindow->ReleaseMouse();
+ SfxStringItem aStrItem(SID_FILE_NAME, aVEvt.mpURLField->GetURL());
+ SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName());
+ SfxBoolItem aBrowseItem( SID_BROWSE, true );
+ SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
+ mpWindow->ReleaseMouse();
+
+ if (rMEvt.IsMod1())
+ {
+ // open in new frame
+ pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aStrItem, &aBrowseItem, &aReferer });
+ }
+ else
+ {
+ // open in current frame
+ SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
+ pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
+ }
+ }
+ else
+ {
+ // drag object or handle
+
+ // #i78748#
+ // do the EndTextEdit first, it will delete the handles and force a
+ // recreation. This will make aVEvt.mpHdl to point to a deleted handle,
+ // thus it is necessary to reset it and to get it again.
+
+ // #i112855#
+ // cl: I'm not sure why we checked here also for mxTextObj->GetOutlinerParaObject
+ // this caused SdrEndTextEdit() to be called also when not in text editing and
+ // this does not make sense and caused troubles. (see issue 112855)
+
+ if( mpView->IsTextEdit() )
+ {
+ mpView->SdrEndTextEdit();
+ bJustEndedEdit = true;
+
+ if(aVEvt.mpHdl)
+ {
+ // force new handle identification, the pointer will be dead here
+ // since SdrEndTextEdit has reset (deleted) the handles.
+ aVEvt.mpHdl = nullptr;
+ mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+ }
+ }
+
+ if (!aVEvt.mpHdl)
+ {
+ if( eHit == SdrHitKind::UnmarkedObject )
+ {
+ if ( !rMEvt.IsShift() )
+ mpView->UnmarkAll();
+
+ mpView->MarkObj(aVEvt.mpRootObj, pPV);
+ }
+
+ // Drag object
+ bFirstMouseMove = true;
+ aDragTimer.Start();
+ }
+
+ if ( ! rMEvt.IsRight())
+ {
+ // we need to pick again since SdrEndTextEdit can rebuild the handles list
+ eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+ if( (eHit == SdrHitKind::Handle) || (eHit == SdrHitKind::MarkedObject) )
+ {
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+ mpView->BegDragObj(aMDPos, nullptr, aVEvt.mpHdl, nDrgLog);
+ }
+ }
+ bReturn = true;
+ }
+ }
+ else if ( nSlotId != SID_TEXTEDIT &&
+ (bPermanent || !bFirstObjCreated) )
+ {
+ // create object
+ mpView->SetCurrentObj(SdrObjKind::Text);
+ mpView->SetEditMode(SdrViewEditMode::Create);
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+ mpView->BegCreateObj(aMDPos, nullptr, nDrgLog);
+ }
+ else
+ {
+ // select
+ if( !rMEvt.IsShift() )
+ mpView->UnmarkAll();
+
+ mpView->BegMarkObj( aMDPos );
+ }
+ }
+ }
+ }
+ else if ( rMEvt.GetClicks() == 2 && !mpView->IsTextEdit() )
+ {
+ MouseEvent aMEvt( mpWindow->GetPointerPosPixel() );
+ SetInEditMode( aMEvt, false );
+ }
+
+ if (!bIsInDragMode)
+ {
+ ForcePointer(&rMEvt);
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate(SidArray);
+ }
+
+ return bReturn;
+}
+
+bool FuText::MouseMove(const MouseEvent& rMEvt)
+{
+ bool bReturn = FuDraw::MouseMove(rMEvt);
+
+ if (aDragTimer.IsActive() )
+ {
+ if( bFirstMouseMove )
+ bFirstMouseMove = false;
+ else
+ aDragTimer.Stop();
+ }
+
+ if (!bReturn && mpView->IsAction() && !mpDocSh->IsReadOnly())
+ {
+ Point aPix(rMEvt.GetPosPixel());
+ Point aPnt(mpWindow->PixelToLogic(aPix));
+
+ ForceScroll(aPix);
+ mpView->MovAction(aPnt);
+ }
+
+ ForcePointer(&rMEvt);
+
+ return bReturn;
+}
+
+void FuText::ImpSetAttributesForNewTextObject(SdrTextObj* pTxtObj)
+{
+ if(mpDoc->GetDocumentType() == DocumentType::Impress)
+ {
+ if( nSlotId == SID_ATTR_CHAR )
+ {
+ /* Create Impress text object (rescales to line height)
+ We get the correct height during the subsequent creation of the
+ object, otherwise we draw too much */
+ SfxItemSet aSet(mpViewShell->GetPool());
+ aSet.Put(makeSdrTextMinFrameHeightItem(0));
+ aSet.Put(makeSdrTextAutoGrowWidthItem(false));
+ aSet.Put(makeSdrTextAutoGrowHeightItem(true));
+ pTxtObj->SetMergedItemSet(aSet);
+ pTxtObj->AdjustTextFrameWidthAndHeight();
+ aSet.Put(makeSdrTextMaxFrameHeightItem(pTxtObj->GetLogicRect().GetSize().Height()));
+ pTxtObj->SetMergedItemSet(aSet);
+ const SfxViewShell* pCurrentViewShell = SfxViewShell::Current();
+ if (pCurrentViewShell && (pCurrentViewShell->isLOKMobilePhone() || pCurrentViewShell->isLOKTablet()))
+ pTxtObj->SetText(SdResId(STR_PRESOBJ_TEXT_EDIT_MOBILE));
+ }
+ else if( nSlotId == SID_ATTR_CHAR_VERTICAL )
+ {
+ SfxItemSet aSet(mpViewShell->GetPool());
+ aSet.Put(makeSdrTextMinFrameWidthItem(0));
+ aSet.Put(makeSdrTextAutoGrowWidthItem(true));
+ aSet.Put(makeSdrTextAutoGrowHeightItem(false));
+
+ // Needs to be set since default is SDRTEXTHORZADJUST_BLOCK
+ aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
+ pTxtObj->SetMergedItemSet(aSet);
+ pTxtObj->AdjustTextFrameWidthAndHeight();
+ aSet.Put(makeSdrTextMaxFrameWidthItem(pTxtObj->GetLogicRect().GetSize().Width()));
+ pTxtObj->SetMergedItemSet(aSet);
+ }
+ }
+ else
+ {
+ if( nSlotId == SID_ATTR_CHAR_VERTICAL )
+ {
+ // draw text object, needs to be initialized when vertical text is used
+ SfxItemSet aSet(mpViewShell->GetPool());
+
+ aSet.Put(makeSdrTextAutoGrowWidthItem(true));
+ aSet.Put(makeSdrTextAutoGrowHeightItem(false));
+
+ // Set defaults for vertical click-n'drag text object, pool defaults are:
+ // SdrTextVertAdjustItem: SDRTEXTVERTADJUST_TOP
+ // SdrTextHorzAdjustItem: SDRTEXTHORZADJUST_BLOCK
+ // Analog to that:
+ aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BLOCK));
+ aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
+
+ pTxtObj->SetMergedItemSet(aSet);
+ }
+ }
+}
+
+void FuText::ImpSetAttributesFitToSize(SdrTextObj* pTxtObj)
+{
+ // FitToSize (fit to frame)
+ SfxItemSetFixed<SDRATTR_TEXT_AUTOGROWHEIGHT, SDRATTR_TEXT_AUTOGROWWIDTH> aSet(mpViewShell->GetPool());
+ aSet.Put(SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_PROPORTIONAL));
+ aSet.Put(makeSdrTextAutoGrowHeightItem(false));
+ aSet.Put(makeSdrTextAutoGrowWidthItem(false));
+ pTxtObj->SetMergedItemSet(aSet);
+ pTxtObj->AdjustTextFrameWidthAndHeight();
+}
+
+void FuText::ImpSetAttributesFitToSizeVertical(SdrTextObj* pTxtObj)
+{
+ SfxItemSetFixed<SDRATTR_TEXT_AUTOGROWHEIGHT, SDRATTR_TEXT_AUTOGROWWIDTH> aSet(mpViewShell->GetPool());
+ aSet.Put(SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_PROPORTIONAL));
+ aSet.Put(makeSdrTextAutoGrowHeightItem(false));
+ aSet.Put(makeSdrTextAutoGrowWidthItem(false));
+ pTxtObj->SetMergedItemSet(aSet);
+ pTxtObj->AdjustTextFrameWidthAndHeight();
+}
+
+void FuText::ImpSetAttributesFitCommon(SdrTextObj* pTxtObj)
+{
+ // Normal Textobject
+ if (mpDoc->GetDocumentType() != DocumentType::Impress)
+ return;
+
+ if( nSlotId == SID_ATTR_CHAR )
+ {
+ // Impress text object (rescales to line height)
+ SfxItemSet aSet(mpViewShell->GetPool());
+ aSet.Put(makeSdrTextMinFrameHeightItem(0));
+ aSet.Put(makeSdrTextMaxFrameHeightItem(0));
+ aSet.Put(makeSdrTextAutoGrowHeightItem(true));
+ aSet.Put(makeSdrTextAutoGrowWidthItem(false));
+ pTxtObj->SetMergedItemSet(aSet);
+ }
+ else if( nSlotId == SID_ATTR_CHAR_VERTICAL )
+ {
+ SfxItemSet aSet(mpViewShell->GetPool());
+ aSet.Put(makeSdrTextMinFrameWidthItem(0));
+ aSet.Put(makeSdrTextMaxFrameWidthItem(0));
+ aSet.Put(makeSdrTextAutoGrowWidthItem(true));
+ aSet.Put(makeSdrTextAutoGrowHeightItem(false));
+ pTxtObj->SetMergedItemSet(aSet);
+ }
+
+ pTxtObj->AdjustTextFrameWidthAndHeight();
+}
+
+bool FuText::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bReturn = false;
+ if (aDragTimer.IsActive())
+ {
+ aDragTimer.Stop();
+ bIsInDragMode = false;
+ }
+
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArray );
+
+ Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ if( (mpView && mpView->MouseButtonUp(rMEvt, mpWindow->GetOutDev())) || rMEvt.GetClicks() == 2 )
+ return true; // handle event from SdrView
+
+ bool bEmptyTextObj = false;
+
+ if (mxTextObj.is())
+ {
+ bool bReset = true;
+
+ if (mpView)
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1
+ && ( rMarkList.GetMark(0)->GetMarkedSdrObj() == mxTextObj.get()) )
+ {
+ if( mxTextObj.is() && !GetTextObj()->GetOutlinerParaObject() )
+ bEmptyTextObj = true;
+ else
+ bFirstObjCreated = true;
+ bReset = false;
+ }
+ }
+
+ if (bReset)
+ {
+ mxTextObj.reset(nullptr);
+ }
+ }
+
+ if( mpView && mpView->IsDragObj())
+ {
+ // object was moved
+ FrameView* pFrameView = mpViewShell->GetFrameView();
+ bool bDragWithCopy = (rMEvt.IsMod1() && pFrameView->IsDragWithCopy());
+
+ if (bDragWithCopy)
+ {
+ bDragWithCopy = !mpView->IsPresObjSelected(false);
+ }
+
+ mpView->SetDragWithCopy(bDragWithCopy);
+ mpView->EndDragObj( mpView->IsDragWithCopy() );
+ mpView->ForceMarkedToAnotherPage();
+ mpView->SetCurrentObj(SdrObjKind::Text);
+
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+
+ if (bJustEndedEdit)
+ {
+ bJustEndedEdit = false;
+ FuPoor::cancel();
+ }
+ if ((rMEvt.GetClicks() != 2) &&
+ !rMEvt.IsShift() && !rMEvt.IsMod1() && !rMEvt.IsMod2() && !rMEvt.IsRight() &&
+ std::abs(aPnt.X() - aMDPos.X()) < nDrgLog &&
+ std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
+ {
+ /*************************************************************
+ * From text mode, you don't want to rotate immediately.
+ **************************************************************/
+ SdrPageView* pPV;
+ SdrObject* pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::BEFOREMARK);
+ if (pObj && pPV->IsObjMarkable(pObj))
+ {
+ mpView->UnmarkAllObj();
+ mpView->MarkObj(pObj,pPV);
+ return bReturn;
+ }
+ }
+ }
+ else if( mpView && mpView->IsCreateObj() && rMEvt.IsLeft())
+ {
+ // object was created
+ mxTextObj.reset( dynamic_cast< SdrTextObj* >( mpView->GetCreateObj() ) );
+
+ if( mxTextObj.is() )
+ {
+ //AW outliner needs to be set to vertical when there is no
+ // outliner object up to now; also it needs to be set back to not
+ // vertical when there was a vertical one used last time.
+ OutlinerParaObject* pOPO = GetTextObj()->GetOutlinerParaObject();
+ SdrOutliner& rOutl(mxTextObj->getSdrModelFromSdrObject().GetDrawOutliner(GetTextObj()));
+ bool bVertical((pOPO && pOPO->IsEffectivelyVertical())
+ || nSlotId == SID_ATTR_CHAR_VERTICAL
+ || nSlotId == SID_TEXT_FITTOSIZE_VERTICAL);
+ rOutl.SetVertical(bVertical);
+
+ // Before ImpSetAttributesForNewTextObject the vertical writing mode
+ // needs to be set at the object. This is done here at the OutlinerParaObject
+ // directly to not mirror the layout text items involved. These items will be set
+ // from ImpSetAttributesForNewTextObject and below.
+ OutlinerParaObject* pPara = GetTextObj()->GetOutlinerParaObject();
+
+ if(!pPara)
+ {
+ GetTextObj()->ForceOutlinerParaObject();
+ pPara = GetTextObj()->GetOutlinerParaObject();
+ }
+
+ if(pPara && bVertical != pPara->IsEffectivelyVertical())
+ {
+ // set ParaObject orientation accordingly
+ pPara->SetVertical(bVertical);
+ }
+
+ ImpSetAttributesForNewTextObject(GetTextObj());
+ }
+
+ if (!mpView->EndCreateObj(SdrCreateCmd::ForceEnd))
+ {
+ // it was not possible to create text object
+ mxTextObj.reset(nullptr);
+ }
+ else if (nSlotId == SID_TEXT_FITTOSIZE)
+ {
+ ImpSetAttributesFitToSize(GetTextObj());
+
+ SetInEditMode(rMEvt, false);
+ }
+ else if ( nSlotId == SID_TEXT_FITTOSIZE_VERTICAL )
+ {
+ ImpSetAttributesFitToSizeVertical(GetTextObj());
+
+ SetInEditMode(rMEvt, false);
+ }
+ else
+ {
+ ImpSetAttributesFitCommon(GetTextObj());
+
+ // thereby the handles and the gray frame are correct
+ mpView->AdjustMarkHdl();
+ mpView->PickHandle(aPnt);
+ SetInEditMode(rMEvt, false);
+ }
+ }
+ else if ( mpView && mpView->IsAction())
+ {
+ mpView->EndAction();
+ }
+
+ ForcePointer(&rMEvt);
+ mpWindow->ReleaseMouse();
+ sal_uInt16 nDrgLog1 = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+
+ if ( mpView && !mpView->AreObjectsMarked() &&
+ std::abs(aMDPos.X() - aPnt.X()) < nDrgLog1 &&
+ std::abs(aMDPos.Y() - aPnt.Y()) < nDrgLog1 &&
+ !rMEvt.IsShift() && !rMEvt.IsMod2() )
+ {
+ SdrPageView* pPV2 = mpView->GetSdrPageView();
+ SdrViewEvent aVEvt;
+ mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+ mpView->MarkObj(aVEvt.mpRootObj, pPV2);
+ }
+
+ if ( !mxTextObj.is() && mpView )
+ {
+ if ( ( (!bEmptyTextObj && bPermanent) ||
+ (!bFirstObjCreated && !bPermanent) ) &&
+ !mpDocSh->IsReadOnly() &&
+ nSlotId != SID_TEXTEDIT )
+ {
+ // text body (left-justified AutoGrow)
+ mpView->SetCurrentObj(SdrObjKind::Text);
+ mpView->SetEditMode(SdrViewEditMode::Create);
+ sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
+ mpView->BegCreateObj(aMDPos, nullptr, nDrgLog);
+
+ bool bSnapEnabled = mpView->IsSnapEnabled();
+
+ if (bSnapEnabled)
+ mpView->SetSnapEnabled(false);
+
+ aPnt.AdjustX(nDrgLog + nDrgLog );
+ aPnt.AdjustY(nDrgLog + nDrgLog );
+ mpView->MovAction(aPnt);
+
+ mxTextObj.reset( dynamic_cast< SdrTextObj* >( mpView->GetCreateObj() ) );
+
+ if(mxTextObj.is())
+ {
+ GetTextObj()->SetDisableAutoWidthOnDragging(true);
+ }
+
+ if(!mpView->EndCreateObj(SdrCreateCmd::ForceEnd))
+ {
+ mxTextObj.reset(nullptr);
+ }
+
+ if(bSnapEnabled)
+ mpView->SetSnapEnabled(bSnapEnabled);
+
+ if(mxTextObj.is())
+ {
+ SfxItemSet aSet(mpViewShell->GetPool());
+ aSet.Put(makeSdrTextMinFrameHeightItem(0));
+ aSet.Put(makeSdrTextMinFrameWidthItem(0));
+ aSet.Put(makeSdrTextAutoGrowHeightItem(true));
+ aSet.Put(makeSdrTextAutoGrowWidthItem(true));
+
+ if(nSlotId == SID_ATTR_CHAR_VERTICAL)
+ {
+ // Here, all items which need to be different from pool default need to be set
+ // again on the newly created text object.
+ // Since this is a simple click text object, it is first created, then SetVertical()
+ // is used, then ImpSetAttributesForNewTextObject is called and then the object is
+ // deleted again since not the minimum drag distance was travelled. Then, a new
+ // click text object is created and thus all that stuff needs to be set again here.
+
+ // Before using the new object the vertical writing mode
+ // needs to be set. This is done here at the OutlinerParaObject
+ // directly to not mirror the layout text items involved. These items will be set
+ // below.
+ OutlinerParaObject* pPara = GetTextObj()->GetOutlinerParaObject();
+
+ if(!pPara)
+ {
+ GetTextObj()->ForceOutlinerParaObject();
+ pPara = GetTextObj()->GetOutlinerParaObject();
+ }
+
+ if(pPara && !pPara->IsEffectivelyVertical())
+ {
+ // set ParaObject orientation accordingly
+ pPara->SetVertical(true);
+ }
+
+ aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
+
+ // Analog to the else case below, for vertical simple click texts
+ // one of the default set items from ImpSetAttributesForNewTextObject
+ // needs to be adapted to non-block mode.
+ const SfxItemSet& rSet = mpView->GetDefaultAttr();
+ SvxFrameDirection eDirection = rSet.Get(EE_PARA_WRITINGDIR).GetValue();
+
+ if(SvxFrameDirection::Horizontal_RL_TB == eDirection || SvxFrameDirection::Vertical_RL_TB == eDirection)
+ {
+ aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM));
+ }
+ else
+ {
+ aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP));
+ }
+ }
+ else
+ {
+ // This is for Format/Page settings. Since this also leads
+ // to the object defaults to be changed, i think this code can be
+ // removed. CL. wanted to take a look before adding this.
+
+ // Look in the object defaults if left-to-right is wanted. If
+ // yes, set text anchoring to right to let the box grow to left.
+ const SfxItemSet& rSet = mpView->GetDefaultAttr();
+ SvxFrameDirection eDirection = rSet.Get(EE_PARA_WRITINGDIR).GetValue();
+
+ if(SvxFrameDirection::Horizontal_RL_TB == eDirection)
+ {
+ aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
+ }
+ else
+ {
+ aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT));
+ }
+ }
+
+ GetTextObj()->SetMergedItemSet(aSet);
+ GetTextObj()->SetDisableAutoWidthOnDragging(true);
+ SetInEditMode(rMEvt, false);
+ }
+
+ bFirstObjCreated = true;
+ }
+ else
+ {
+ // switch to selection
+ if (mpView->SdrEndTextEdit() == SdrEndTextEditKind::Deleted)
+ {
+ mxTextObj.reset(nullptr);
+ }
+
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_OBJECT_SELECT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+ }
+ if (bJustEndedEdit)
+ {
+ bJustEndedEdit = false;
+ FuPoor::cancel();
+ }
+ bMBDown = false;
+ FuConstruct::MouseButtonUp(rMEvt);
+ return bReturn;
+}
+
+/**
+ * handle keyboard events
+ * @returns sal_True if the event was handled, sal_False otherwise
+ */
+bool FuText::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bReturn = false;
+
+ vcl::KeyCode nCode = rKEvt.GetKeyCode();
+ bool bShift = nCode.IsShift();
+
+ if(mxTextObj.is())
+ {
+ // maybe object is deleted, test if it's equal to the selected object
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ SdrObject* pSelectedObj = nullptr;
+
+ if(1 == rMarkList.GetMarkCount())
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ pSelectedObj = pMark->GetMarkedSdrObj();
+ }
+
+ if(mxTextObj.get() != pSelectedObj)
+ {
+ mxTextObj.reset(nullptr);
+ }
+ }
+
+ if ( mxTextObj.is() && mxTextObj->GetObjInventor() == SdrInventor::Default && mxTextObj->GetObjIdentifier() == SdrObjKind::TitleText && rKEvt.GetKeyCode().GetCode() == KEY_RETURN )
+ {
+ // title text object: always soft breaks
+ bShift = true;
+ }
+
+ sal_uInt16 nKey = nCode.GetCode();
+ vcl::KeyCode aKeyCode (nKey, bShift, nCode.IsMod1(), nCode.IsMod2(), nCode.IsMod3() );
+ KeyEvent aKEvt(rKEvt.GetCharCode(), aKeyCode);
+
+ bool bOK = true;
+
+ if (mpDocSh->IsReadOnly())
+ {
+ bOK = !EditEngine::DoesKeyChangeText(aKEvt);
+ }
+ if( aKeyCode.GetCode() == KEY_PAGEUP || aKeyCode.GetCode() == KEY_PAGEDOWN )
+ {
+ bOK = false; // default handling in base class
+ }
+
+ if (bOK && mpView->KeyInput(aKEvt, mpWindow) )
+ {
+ bReturn = true;
+
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArray );
+
+ }
+ else if (aKeyCode == KEY_ESCAPE)
+ {
+ bReturn = cancel();
+ }
+
+ if( bPermanent )
+ {
+ mpView->SetCurrentObj(SdrObjKind::Text);
+ mpView->SetEditMode(SdrViewEditMode::Create);
+ }
+
+ if (!bReturn)
+ {
+ bReturn = FuDraw::KeyInput(aKEvt);
+ }
+
+ return bReturn;
+}
+
+void FuText::Activate()
+{
+ mpView->SetQuickTextEditMode(mpViewShell->GetFrameView()->IsQuickEdit());
+
+ // #i89661# it's no longer necessary to make it so big here, it's fine tuned
+ // for text objects in SdrMarkView::CheckSingleSdrObjectHit
+ mpView->SetHitTolerancePixel( 2 * HITPIX );
+
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+
+ if (pOLV)
+ pOLV->ShowCursor(/*bGotoCursor=*/true, /*bActivate=*/true);
+
+ FuConstruct::Activate();
+
+ if( pOLV )
+ mpView->SetEditMode(SdrViewEditMode::Edit);
+}
+
+void FuText::Deactivate()
+{
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+
+ if (pOLV)
+ pOLV->HideCursor(/*bDeactivate=*/true);
+
+ mpView->SetHitTolerancePixel( HITPIX );
+
+ FuConstruct::Deactivate();
+}
+
+/**
+ * Sets the object into the edit mode.
+ */
+void FuText::SetInEditMode(const MouseEvent& rMEvt, bool bQuickDrag)
+{
+ SdrPageView* pPV = mpView->GetSdrPageView();
+ if( mxTextObj.is() && (mxTextObj->getSdrPageFromSdrObject() == pPV->GetPage()) )
+ {
+ mpView->SetCurrentObj(SdrObjKind::Text);
+
+ if( bPermanent )
+ mpView->SetEditMode(SdrViewEditMode::Create);
+ else
+ mpView->SetEditMode(SdrViewEditMode::Edit);
+
+ bool bEmptyOutliner = false;
+
+ if (!GetTextObj()->GetOutlinerParaObject() && mpView->GetTextEditOutliner())
+ {
+ ::Outliner* pOutl = mpView->GetTextEditOutliner();
+ sal_Int32 nParagraphCnt = pOutl->GetParagraphCount();
+ Paragraph* p1stPara = pOutl->GetParagraph( 0 );
+
+ if (nParagraphCnt==1 && p1stPara)
+ {
+ // with only one paragraph
+ if (pOutl->GetText(p1stPara).isEmpty())
+ {
+ bEmptyOutliner = true;
+ }
+ }
+ }
+
+ if (GetTextObj() != mpView->GetTextEditObject() || bEmptyOutliner)
+ {
+ SdrInventor nInv = mxTextObj->GetObjInventor();
+ SdrObjKind nSdrObjKind = mxTextObj->GetObjIdentifier();
+
+ if (nInv == SdrInventor::Default && GetTextObj()->HasTextEdit() &&
+ (nSdrObjKind == SdrObjKind::Text ||
+ nSdrObjKind == SdrObjKind::TitleText ||
+ nSdrObjKind == SdrObjKind::OutlineText || !mxTextObj->IsEmptyPresObj() ) )
+ {
+ // create new outliner (owned by SdrObjEditView)
+ std::unique_ptr<SdrOutliner> pOutl = SdrMakeOutliner(OutlinerMode::OutlineObject, *mpDoc);
+
+ if (bEmptyOutliner)
+ mpView->SdrEndTextEdit(true);
+
+ SdrTextObj* pTextObj = GetTextObj();
+ if( pTextObj )
+ {
+ OutlinerParaObject* pOPO = pTextObj->GetOutlinerParaObject();
+ if( pOPO && pOPO->IsEffectivelyVertical() )
+ {
+ pOutl->SetVertical(pOPO->GetVertical());
+ pOutl->SetRotation(pOPO->GetRotation());
+ }
+ else if (nSlotId == SID_ATTR_CHAR_VERTICAL || nSlotId == SID_TEXT_FITTOSIZE_VERTICAL)
+ pOutl->SetVertical( true );
+
+ if( pTextObj->getTextCount() > 1 )
+ {
+ Point aPix(rMEvt.GetPosPixel());
+ Point aPnt(mpWindow->PixelToLogic(aPix));
+ pTextObj->setActiveText( pTextObj->CheckTextHit(aPnt ) );
+ }
+
+ if (mpView->SdrBeginTextEdit(pTextObj, pPV, mpWindow, true, pOutl.release()) && mxTextObj->GetObjInventor() == SdrInventor::Default)
+ {
+ //tdf#102293 flush overlay before going on to pass clicks down to
+ //the outline view which will want to paint selections
+ for (sal_uInt32 b = 0; b < pPV->PageWindowCount(); ++b)
+ {
+ const SdrPageWindow& rPageWindow = *pPV->GetPageWindow(b);
+ if (!rPageWindow.GetPaintWindow().OutputToWindow())
+ continue;
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (!xManager.is())
+ continue;
+ xManager->flush();
+ }
+
+ bFirstObjCreated = true;
+ DeleteDefaultText();
+
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+
+ nSdrObjKind = mxTextObj->GetObjIdentifier();
+
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+
+ if (eHit == SdrHitKind::TextEdit)
+ {
+ // hit text
+ if (nSdrObjKind == SdrObjKind::Text ||
+ nSdrObjKind == SdrObjKind::TitleText ||
+ nSdrObjKind == SdrObjKind::OutlineText ||
+ nSdrObjKind == SdrObjKind::Table ||
+ nSlotId == SID_TEXTEDIT ||
+ !bQuickDrag)
+ {
+ pOLV->MouseButtonDown(rMEvt);
+ pOLV->MouseMove(rMEvt);
+ pOLV->MouseButtonUp(rMEvt);
+ }
+
+ if (mpViewShell->GetFrameView()->IsQuickEdit() && bQuickDrag && GetTextObj()->GetOutlinerParaObject())
+ {
+ pOLV->MouseButtonDown(rMEvt);
+ }
+ }
+ else
+ {
+ // Move cursor to end of text
+ ESelection aNewSelection(EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND, EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND);
+ if (pOLV != nullptr)
+ pOLV->SetSelection(aNewSelection);
+ }
+ }
+ else
+ {
+ mpView->RestoreDefaultText( mxTextObj.get() );
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ mxTextObj.reset(nullptr);
+ }
+}
+
+/**
+ * Text entry is started, if necessary delete the default text.
+ */
+void FuText::DeleteDefaultText()
+{
+ if ( !(mxTextObj.is() && mxTextObj->IsEmptyPresObj()) )
+ return;
+
+ SdPage* pPage = static_cast<SdPage*>( mxTextObj->getSdrPageFromSdrObject() );
+
+ if (!pPage)
+ return;
+
+ PresObjKind ePresObjKind = pPage->GetPresObjKind(mxTextObj.get());
+
+ if ( !(ePresObjKind == PresObjKind::Title ||
+ ePresObjKind == PresObjKind::Outline ||
+ ePresObjKind == PresObjKind::Notes ||
+ ePresObjKind == PresObjKind::Text ) ||
+ pPage->IsMasterPage() )
+ return;
+
+ ::Outliner* pOutliner = mpView->GetTextEditOutliner();
+ SfxStyleSheet* pSheet = pOutliner->GetStyleSheet( 0 );
+ bool bIsUndoEnabled = pOutliner->IsUndoEnabled();
+ if( bIsUndoEnabled )
+ pOutliner->EnableUndo(false);
+
+ pOutliner->SetText( OUString(), pOutliner->GetParagraph( 0 ) );
+
+ if( bIsUndoEnabled )
+ pOutliner->EnableUndo(true);
+
+ if (pSheet &&
+ (ePresObjKind == PresObjKind::Notes || ePresObjKind == PresObjKind::Text))
+ pOutliner->SetStyleSheet(0, pSheet);
+
+ mxTextObj->SetEmptyPresObj(true);
+}
+
+bool FuText::RequestHelp(const HelpEvent& rHEvt)
+{
+ bool bReturn = false;
+
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+
+ if ((Help::IsBalloonHelpEnabled() || Help::IsQuickHelpEnabled()) &&
+ mxTextObj.is() && pOLV && pOLV->GetFieldUnderMousePointer())
+ {
+ OUString aHelpText;
+ const SvxFieldItem* pFieldItem = pOLV->GetFieldUnderMousePointer();
+ const SvxFieldData* pField = pFieldItem->GetField();
+
+ if (auto pURLField = dynamic_cast< const SvxURLField *>( pField ))
+ {
+ // URL-Field
+ aHelpText = INetURLObject::decode( pURLField->GetURL(), INetURLObject::DecodeMechanism::WithCharset );
+ }
+ if (!aHelpText.isEmpty())
+ {
+ ::tools::Rectangle aLogicPix = mpWindow->LogicToPixel(mxTextObj->GetLogicRect());
+ ::tools::Rectangle aScreenRect(mpWindow->OutputToScreenPixel(aLogicPix.TopLeft()),
+ mpWindow->OutputToScreenPixel(aLogicPix.BottomRight()));
+
+ if (Help::IsBalloonHelpEnabled())
+ {
+ Help::ShowBalloon( static_cast<vcl::Window*>(mpWindow), rHEvt.GetMousePosPixel(), aScreenRect, aHelpText);
+ bReturn = true;
+ }
+ else if (Help::IsQuickHelpEnabled())
+ {
+ Help::ShowQuickHelp( static_cast<vcl::Window*>(mpWindow), aScreenRect, aHelpText);
+ bReturn = true;
+ }
+ }
+ }
+
+ if (!bReturn)
+ {
+ bReturn = FuConstruct::RequestHelp(rHEvt);
+ }
+
+ return bReturn;
+}
+
+void FuText::ReceiveRequest(SfxRequest& rReq)
+{
+ nSlotId = rReq.GetSlot();
+
+ // then we call the base class (besides others, nSlotId is NOT set there)
+ FuPoor::ReceiveRequest(rReq);
+
+ if (!(nSlotId == SID_TEXTEDIT || mpViewShell->GetFrameView()->IsQuickEdit() || SID_ATTR_CHAR == nSlotId))
+ return;
+
+ MouseEvent aMEvt(mpWindow->GetPointerPosPixel());
+
+ mxTextObj.reset(nullptr);
+
+ if (nSlotId == SID_TEXTEDIT)
+ {
+ // are we currently editing?
+ mxTextObj.reset( mpView->GetTextEditObject() );
+
+ if (!mxTextObj.is())
+ {
+ // Try to select an object
+ SdrPageView* pPV = mpView->GetSdrPageView();
+ SdrViewEvent aVEvt;
+ mpView->PickAnything(aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+ mpView->MarkObj(aVEvt.mpRootObj, pPV);
+
+ if (auto pSdrTextObj = dynamic_cast<SdrTextObj*>(aVEvt.mpObj))
+ {
+ mxTextObj.reset( pSdrTextObj );
+ }
+ }
+ }
+ else if (mpView->AreObjectsMarked())
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ if( auto pTextObj = dynamic_cast<SdrTextObj *>( pObj ))
+ {
+ mxTextObj.reset( pTextObj );
+ }
+ }
+ }
+
+ bool bQuickDrag = true;
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if (pArgs
+
+ // test for type before using
+ && SID_TEXTEDIT == nSlotId
+ && SfxItemState::SET == pArgs->GetItemState(SID_TEXTEDIT)
+
+ && static_cast<const SfxUInt16Item&>( pArgs->Get(SID_TEXTEDIT)).GetValue() == 2)
+ {
+ // selection with double click -> do not allow QuickDrag
+ bQuickDrag = false;
+ }
+
+ SetInEditMode(aMEvt, bQuickDrag);
+}
+
+void FuText::DoubleClick(const MouseEvent& )
+{
+ // Nothing to do
+}
+
+/** Removed the insertion of default text and putting a new text
+ object directly into edit mode.
+*/
+SdrObjectUniquePtr FuText::CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle)
+{
+ SdrObjectUniquePtr pObj( SdrObjFactory::MakeNewObject(
+ mpView->getSdrModelFromSdrView(),
+ mpView->GetCurrentObjInventor(),
+ mpView->GetCurrentObjIdentifier(),
+ nullptr) );
+
+ if(pObj)
+ {
+ if( auto pText = dynamic_cast< SdrTextObj *>( pObj.get() ) )
+ {
+ pText->SetLogicRect(rRectangle);
+
+ bool bVertical = (SID_ATTR_CHAR_VERTICAL == nID || SID_TEXT_FITTOSIZE_VERTICAL == nID);
+ pText->SetVerticalWriting(bVertical);
+
+ ImpSetAttributesForNewTextObject(pText);
+
+ if (nSlotId == SID_TEXT_FITTOSIZE)
+ {
+ ImpSetAttributesFitToSize(pText);
+ }
+ else if ( nSlotId == SID_TEXT_FITTOSIZE_VERTICAL )
+ {
+ ImpSetAttributesFitToSizeVertical(pText);
+ }
+ else
+ {
+ ImpSetAttributesFitCommon(pText);
+ }
+
+ // Put text object into edit mode.
+ SdrPageView* pPV = mpView->GetSdrPageView();
+ mpView->SdrBeginTextEdit(pText, pPV);
+ }
+ else
+ {
+ OSL_FAIL("Object is NO text object");
+ }
+ }
+
+ return pObj;
+}
+
+/** is called when the current function should be aborted. <p>
+ This is used when a function gets a KEY_ESCAPE but can also
+ be called directly.
+
+ @returns true if an active function was aborted
+*/
+bool FuText::cancel()
+{
+ if ( mpView->IsTextEdit() )
+ {
+ if(mpView->SdrEndTextEdit() == SdrEndTextEditKind::Deleted)
+ mxTextObj.reset(nullptr);
+
+ mpView->SetCurrentObj(SdrObjKind::Text);
+ mpView->SetEditMode(SdrViewEditMode::Edit);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void FuText::ChangeFontSize( bool bGrow, OutlinerView* pOLV, const FontList* pFontList, ::sd::View* pView )
+{
+ if( !pFontList || !pView )
+ return;
+
+ if( pOLV )
+ {
+ pOLV->GetEditView().ChangeFontSize( bGrow, pFontList );
+ }
+ else
+ {
+
+ pView->BegUndo(SdResId(bGrow ? STR_GROW_FONT_SIZE : STR_SHRINK_FONT_SIZE));
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ for( size_t nMark = 0; nMark < rMarkList.GetMarkCount(); ++nMark )
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( rMarkList.GetMark(nMark)->GetMarkedSdrObj() );
+ if( pTextObj )
+ {
+ rtl::Reference<sdr::SelectionController> xSelectionController(pView->getSelectionController());
+ if (xSelectionController.is() && xSelectionController->ChangeFontSize(bGrow, pFontList))
+ {
+ continue;
+ }
+ for( sal_Int32 nText = 0; nText < pTextObj->getTextCount(); nText++ )
+ {
+ pTextObj->setActiveText( nText );
+
+ // Put text object into edit mode.
+ SdrPageView* pPV = pView->GetSdrPageView();
+ pView->SdrBeginTextEdit(pTextObj, pPV);
+
+ pOLV = pView->GetTextEditOutlinerView();
+ if( pOLV )
+ {
+ EditEngine* pEditEngine = pOLV->GetEditView().GetEditEngine();
+ if( pEditEngine )
+ {
+ ESelection aSel;
+ aSel.nEndPara = pEditEngine->GetParagraphCount()-1;
+ aSel.nEndPos = pEditEngine->GetTextLen(aSel.nEndPara);
+ pOLV->SetSelection(aSel);
+ }
+
+ ChangeFontSize( bGrow, pOLV, pFontList, pView );
+ }
+
+ pView->SdrEndTextEdit();
+ }
+
+ SfxItemSet aShapeSet( pTextObj->GetMergedItemSet() );
+ if( EditView::ChangeFontSize( bGrow, aShapeSet, pFontList ) )
+ {
+ pTextObj->SetObjectItemNoBroadcast( aShapeSet.Get( EE_CHAR_FONTHEIGHT ) );
+ pTextObj->SetObjectItemNoBroadcast( aShapeSet.Get( EE_CHAR_FONTHEIGHT_CJK ) );
+ pTextObj->SetObjectItemNoBroadcast( aShapeSet.Get( EE_CHAR_FONTHEIGHT_CTL ) );
+ }
+ }
+ }
+ pView->EndUndo();
+ }
+}
+
+void FuText::InvalidateBindings()
+{
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate(SidArray);
+}
+
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/futhes.cxx b/sd/source/ui/func/futhes.cxx
new file mode 100644
index 000000000..78d2ae693
--- /dev/null
+++ b/sd/source/ui/func/futhes.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <futhes.hxx>
+
+#include <editeng/outliner.hxx>
+#include <sfx2/request.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdotext.hxx>
+#include <editeng/eeitem.hxx>
+#include <tools/debug.hxx>
+
+#include <svx/svxerr.hxx>
+#include <svx/dialmgr.hxx>
+#include <editeng/unolingu.hxx>
+#include <vcl/weld.hxx>
+#include <drawdoc.hxx>
+#include <View.hxx>
+#include <Outliner.hxx>
+#include <DrawViewShell.hxx>
+#include <OutlineViewShell.hxx>
+#include <Window.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::linguistic2;
+
+class SfxRequest;
+
+namespace sd {
+
+
+FuThesaurus::FuThesaurus( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView,
+ SdDrawDocument* pDoc, SfxRequest& rReq )
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuThesaurus::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuThesaurus( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuThesaurus::DoExecute(SfxRequest& rReq)
+{
+ SfxErrorContext aContext(ERRCTX_SVX_LINGU_THESAURUS, OUString(),
+ mpWindow->GetFrameWeld(), RID_SVXERRCTX, SvxResLocale());
+
+ if (dynamic_cast< DrawViewShell *>( mpViewShell ))
+ {
+ SdrTextObj* pTextObj = nullptr;
+
+ if ( mpView->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if ( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ pTextObj = dynamic_cast<SdrTextObj *>( pObj );
+ }
+ }
+
+ ::Outliner* pOutliner = mpView->GetTextEditOutliner();
+ const OutlinerView* pOutlView = mpView->GetTextEditOutlinerView();
+
+ if ( pTextObj && pOutliner && pOutlView )
+ {
+ if ( !pOutliner->GetSpeller().is() )
+ {
+ Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() );
+ if ( xSpellChecker.is() )
+ pOutliner->SetSpeller( xSpellChecker );
+
+ Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() );
+ if( xHyphenator.is() )
+ pOutliner->SetHyphenator( xHyphenator );
+
+ pOutliner->SetDefaultLanguage( mpDoc->GetLanguage( EE_CHAR_LANGUAGE ) );
+ }
+
+ EESpellState eState = const_cast<OutlinerView*>(pOutlView)->StartThesaurus(rReq.GetFrameWeld());
+ DBG_ASSERT(eState != EESpellState::NoSpeller, "No SpellChecker");
+ }
+ }
+ else if (dynamic_cast< OutlineViewShell *>( mpViewShell ))
+ {
+ Outliner* pOutliner = mpDoc->GetOutliner();
+ OutlinerView* pOutlView = pOutliner->GetView(0);
+
+ if ( !pOutliner->GetSpeller().is() )
+ {
+ Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() );
+ if ( xSpellChecker.is() )
+ pOutliner->SetSpeller( xSpellChecker );
+
+ Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() );
+ if( xHyphenator.is() )
+ pOutliner->SetHyphenator( xHyphenator );
+
+ pOutliner->SetDefaultLanguage( mpDoc->GetLanguage( EE_CHAR_LANGUAGE ) );
+ }
+
+ EESpellState eState = pOutlView->StartThesaurus(rReq.GetFrameWeld());
+ DBG_ASSERT(eState != EESpellState::NoSpeller, "No SpellChecker");
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/futransf.cxx b/sd/source/ui/func/futransf.cxx
new file mode 100644
index 000000000..8c565a3b8
--- /dev/null
+++ b/sd/source/ui/func/futransf.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <futransf.hxx>
+
+#include <svx/svxids.hrc>
+#include <sfx2/request.hxx>
+
+#include <strings.hrc>
+#include <ViewShell.hxx>
+#include <View.hxx>
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <svx/svxdlg.hxx>
+#include <comphelper/lok.hxx>
+
+#include <memory>
+
+using namespace sd;
+
+FuTransform::FuTransform(ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView,
+ SdDrawDocument* pDoc, SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuTransform::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuTransform( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+namespace {
+
+void setUndo(::sd::View* pView, const SfxItemSet* pArgs, bool addPageMargin)
+{
+ // Undo
+ OUString aString = pView->GetDescriptionOfMarkedObjects() +
+ " " + SdResId(STR_TRANSFORM);
+ pView->BegUndo(aString);
+ pView->SetGeoAttrToMarked(*pArgs, addPageMargin);
+ pView->SetAttributes(*pArgs);
+ pView->EndUndo();
+}
+
+}
+
+void FuTransform::DoExecute( SfxRequest& rReq )
+{
+ if (!mpView->AreObjectsMarked())
+ return;
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if (pArgs)
+ {
+ // If this comes from LOK, that means the shape is moved by mouse
+ // only then pArgs is pre-set.
+ setUndo(mpView, pArgs, comphelper::LibreOfficeKit::isActive());
+ return;
+ }
+
+ // --------- itemset for size and position --------
+ SfxItemSet aSet( mpView->GetGeoAttrFromMarked() );
+ VclPtr<SfxAbstractTabDialog> pDlg;
+
+ bool bWelded = false;
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if( rMarkList.GetMarkCount() == 1 &&
+ pObj->GetObjInventor() == SdrInventor::Default &&
+ pObj->GetObjIdentifier() == SdrObjKind::Caption )
+ {
+ // --------- itemset for caption --------
+ SfxItemSet aNewAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aNewAttr );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ pDlg.reset(pFact->CreateCaptionDialog(mpViewShell->GetFrameWeld(), mpView));
+
+ const WhichRangesContainer& pRange = pDlg->GetInputRanges( *aNewAttr.GetPool() );
+ SfxItemSet aCombSet( *aNewAttr.GetPool(), pRange );
+ aCombSet.Put( aNewAttr );
+ aCombSet.Put( aSet );
+ pDlg->SetInputSet( &aCombSet );
+ }
+ else
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ pDlg.reset(pFact->CreateSvxTransformTabDialog(mpViewShell->GetFrameWeld(), &aSet, mpView));
+ bWelded = true;
+ }
+
+ assert(pDlg && "there must be a dialog at this point");
+
+ auto pRequest = std::make_shared<SfxRequest>(rReq);
+ rReq.Ignore(); // the 'old' request is not relevant any more
+
+ pDlg->StartExecuteAsync([bWelded, pDlg, pRequest, this](sal_Int32 nResult){
+ if (nResult == RET_OK)
+ {
+ pRequest->Done(*(pDlg->GetOutputItemSet()));
+ // Page margin is already calculated at this point.
+ setUndo(mpView, pRequest->GetArgs(), false);
+ }
+
+ // deferred until the dialog ends
+ mpViewShell->Invalidate(SID_RULER_OBJECT);
+ mpViewShell->Cancel();
+ if (bWelded)
+ pDlg->disposeOnce();
+ });
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/futxtatt.cxx b/sd/source/ui/func/futxtatt.cxx
new file mode 100644
index 000000000..56f8c2569
--- /dev/null
+++ b/sd/source/ui/func/futxtatt.cxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <futxtatt.hxx>
+#include <sfx2/request.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <View.hxx>
+#include <drawdoc.hxx>
+
+namespace sd {
+
+
+FuTextAttrDlg::FuTextAttrDlg (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuTextAttrDlg::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuTextAttrDlg( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuTextAttrDlg::DoExecute( SfxRequest& rReq )
+{
+ SfxItemSet aNewAttr( mpDoc->GetPool() );
+ mpView->GetAttributes( aNewAttr );
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if( !pArgs )
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateTextTabDialog(rReq.GetFrameWeld(), &aNewAttr, mpView));
+
+ sal_uInt16 nResult = pDlg->Execute();
+
+ switch( nResult )
+ {
+ case RET_OK:
+ {
+ rReq.Done( *( pDlg->GetOutputItemSet() ) );
+
+ pArgs = rReq.GetArgs();
+ }
+ break;
+
+ default:
+ return; // Cancel
+ }
+ }
+ mpView->SetAttributes( *pArgs );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuvect.cxx b/sd/source/ui/func/fuvect.cxx
new file mode 100644
index 000000000..64840810c
--- /dev/null
+++ b/sd/source/ui/func/fuvect.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuvect.hxx>
+#include <svx/svdograf.hxx>
+
+#include <View.hxx>
+#include <Window.hxx>
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <sdabstdlg.hxx>
+
+namespace sd
+{
+
+
+FuVectorize::FuVectorize (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor (pViewSh, pWin, pView, pDoc, rReq)
+{
+}
+
+rtl::Reference<FuPoor> FuVectorize::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuVectorize( pViewSh, pWin, pView, pDoc, rReq ) );
+ xFunc->DoExecute(rReq);
+ return xFunc;
+}
+
+void FuVectorize::DoExecute( SfxRequest& )
+{
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if( rMarkList.GetMarkCount() != 1 )
+ return;
+
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ auto pSdrGrafObj = dynamic_cast< const SdrGrafObj *>( pObj );
+ if( !pSdrGrafObj )
+ return;
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSdVectorizeDlg> pDlg(
+ pFact->CreateSdVectorizeDlg(mpWindow ? mpWindow->GetFrameWeld() : nullptr,
+ pSdrGrafObj->GetGraphic().GetBitmapEx().GetBitmap(), mpDocSh ) );
+ if( pDlg->Execute() != RET_OK )
+ return;
+
+ const GDIMetaFile& rMtf = pDlg->GetGDIMetaFile();
+ SdrPageView* pPageView = mpView->GetSdrPageView();
+
+ if( pPageView && rMtf.GetActionSize() )
+ {
+ SdrGrafObj* pVectObj = static_cast<SdrGrafObj*>( pObj->CloneSdrObject(pObj->getSdrModelFromSdrObject()) );
+ OUString aStr = mpView->GetDescriptionOfMarkedObjects() +
+ " " + SdResId( STR_UNDO_VECTORIZE );
+ mpView->BegUndo( aStr );
+ pVectObj->SetGraphic( rMtf );
+ mpView->ReplaceObjectAtView( pObj, *pPageView, pVectObj );
+ mpView->EndUndo();
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/fuzoom.cxx b/sd/source/ui/func/fuzoom.cxx
new file mode 100644
index 000000000..871d594d3
--- /dev/null
+++ b/sd/source/ui/func/fuzoom.cxx
@@ -0,0 +1,219 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fuzoom.hxx>
+
+#include <svx/svxids.hrc>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <app.hrc>
+#include <svx/svdpagv.hxx>
+#include <vcl/ptrstyle.hxx>
+
+#include <ViewShell.hxx>
+#include <View.hxx>
+#include <Window.hxx>
+#include <zoomlist.hxx>
+
+namespace sd {
+
+const sal_uInt16 SidArrayZoom[] = {
+ SID_ATTR_ZOOM,
+ SID_ZOOM_OUT,
+ SID_ZOOM_IN,
+ 0 };
+
+
+FuZoom::FuZoom(
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq)
+ : FuPoor(pViewSh, pWin, pView, pDoc, rReq),
+ bVisible(false),
+ bStartDrag(false),
+ aPtr(PointerStyle::Arrow)
+{
+}
+
+FuZoom::~FuZoom()
+{
+ if (bVisible)
+ {
+ // Hide ZoomRect
+ mpViewShell->DrawMarkRect(aZoomRect);
+
+ bVisible = false;
+ bStartDrag = false;
+ }
+}
+
+rtl::Reference<FuPoor> FuZoom::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
+{
+ rtl::Reference<FuPoor> xFunc( new FuZoom( pViewSh, pWin, pView, pDoc, rReq ) );
+ return xFunc;
+}
+
+bool FuZoom::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ mpWindow->CaptureMouse();
+ bStartDrag = true;
+
+ aBeginPosPix = rMEvt.GetPosPixel();
+ aBeginPos = mpWindow->PixelToLogic(aBeginPosPix);
+ aZoomRect.SetSize( Size( 0, 0 ) );
+ aZoomRect.SetPos( aBeginPos );
+
+ return true;
+}
+
+bool FuZoom::MouseMove(const MouseEvent& rMEvt)
+{
+ if (rMEvt.IsShift())
+ mpWindow->SetPointer(PointerStyle::Hand);
+ else if (nSlotId != SID_ZOOM_PANNING)
+ mpWindow->SetPointer(PointerStyle::Magnify);
+
+ if (bStartDrag)
+ {
+ if (bVisible)
+ {
+ mpViewShell->DrawMarkRect(aZoomRect);
+ }
+
+ Point aPosPix = rMEvt.GetPosPixel();
+ ForceScroll(aPosPix);
+
+ aEndPos = mpWindow->PixelToLogic(aPosPix);
+ aBeginPos = mpWindow->PixelToLogic(aBeginPosPix);
+
+ if (nSlotId == SID_ZOOM_PANNING || (rMEvt.IsShift() && !bVisible) )
+ {
+ // Panning
+
+ Point aScroll = aBeginPos - aEndPos;
+
+ if (aScroll.X() != 0 || aScroll.Y() != 0)
+ {
+ Size aWorkSize = mpView->GetWorkArea().GetSize();
+ Size aPageSize = mpView->GetSdrPageView()->GetPage()->GetSize();
+ if (aWorkSize.Width() != 0 && aWorkSize.Height() != 0 &&
+ aPageSize.Width() != 0 && aPageSize.Height() != 0)
+ {
+ aScroll.setX( aScroll.X() / ( aWorkSize.Width() / aPageSize.Width()) );
+ aScroll.setY( aScroll.Y() / ( aWorkSize.Height() / aPageSize.Height()) );
+ mpViewShell->Scroll(aScroll.X(), aScroll.Y());
+ aBeginPosPix = aPosPix;
+ }
+ }
+ }
+ else
+ {
+ ::tools::Rectangle aRect(aBeginPos, aEndPos);
+ aZoomRect = aRect;
+ aZoomRect.Justify();
+ mpViewShell->DrawMarkRect(aZoomRect);
+ bVisible = true;
+ }
+ }
+
+ return bStartDrag;
+}
+
+bool FuZoom::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ if (bVisible)
+ {
+ // Hide ZoomRect
+ mpViewShell->DrawMarkRect(aZoomRect);
+ bVisible = false;
+ }
+
+ Point aPosPix = rMEvt.GetPosPixel();
+
+ if(SID_ZOOM_PANNING != nSlotId && !rMEvt.IsShift())
+ {
+ // Zoom
+ Size aZoomSizePixel = mpWindow->LogicToPixel(aZoomRect).GetSize();
+ sal_uLong nTol = DRGPIX + DRGPIX;
+
+ if ( ( aZoomSizePixel.Width() < static_cast<::tools::Long>(nTol) && aZoomSizePixel.Height() < static_cast<::tools::Long>(nTol) ) || rMEvt.IsMod1() )
+ {
+ // click at place: double zoom factor
+ Point aPos = mpWindow->PixelToLogic(aPosPix);
+ Size aSize = mpWindow->PixelToLogic(mpWindow->GetOutputSizePixel());
+ if ( rMEvt.IsMod1() )
+ {
+ aSize.setWidth( aSize.Width() * 2 );
+ aSize.setHeight( aSize.Height() * 2 );
+ }
+ else
+ {
+ aSize.setWidth( aSize.Width() / 2 );
+ aSize.setHeight( aSize.Height() / 2 );
+ }
+ aPos.AdjustX( -(aSize.Width() / 2) );
+ aPos.AdjustY( -(aSize.Height() / 2) );
+ aZoomRect.SetPos(aPos);
+ aZoomRect.SetSize(aSize);
+ }
+
+ mpViewShell->SetZoomRect(aZoomRect);
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArrayZoom );
+ }
+
+ ::tools::Rectangle aVisAreaWin = mpWindow->PixelToLogic(::tools::Rectangle(Point(0,0),
+ mpWindow->GetOutputSizePixel()));
+ mpViewShell->GetZoomList()->InsertZoomRect(aVisAreaWin);
+
+ bStartDrag = false;
+ mpWindow->ReleaseMouse();
+
+ return true;
+}
+
+void FuZoom::Activate()
+{
+ aPtr = mpWindow->GetPointer();
+
+ if (nSlotId == SID_ZOOM_PANNING)
+ {
+ mpWindow->SetPointer(PointerStyle::Hand);
+ }
+ else
+ {
+ mpWindow->SetPointer(PointerStyle::Magnify);
+ }
+}
+
+void FuZoom::Deactivate()
+{
+ mpWindow->SetPointer( aPtr );
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SidArrayZoom );
+}
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/sdundogr.cxx b/sd/source/ui/func/sdundogr.cxx
new file mode 100644
index 000000000..a2e97386d
--- /dev/null
+++ b/sd/source/ui/func/sdundogr.cxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdundogr.hxx>
+#include <tools/long.hxx>
+
+SdUndoGroup::~SdUndoGroup() = default;
+
+bool SdUndoGroup::Merge(SfxUndoAction* pNextAction)
+{
+ bool bRet = false;
+
+ if (auto pSdUndoAction = dynamic_cast<SdUndoAction*>(pNextAction))
+ {
+ SdUndoAction* pClone = pSdUndoAction->Clone();
+
+ if (pClone)
+ {
+ AddAction(pClone);
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+/**
+ * Undo, reverse order of execution
+ */
+void SdUndoGroup::Undo()
+{
+ ::tools::Long nLast = aCtn.size();
+ for (::tools::Long nAction = nLast - 1; nAction >= 0; nAction--)
+ {
+ aCtn[nAction]->Undo();
+ }
+}
+
+void SdUndoGroup::Redo()
+{
+ size_t nLast = aCtn.size();
+ for (size_t nAction = 0; nAction < nLast; nAction++)
+ {
+ aCtn[nAction]->Redo();
+ }
+}
+
+void SdUndoGroup::AddAction(SdUndoAction* pAction) { aCtn.emplace_back(pAction); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/smarttag.cxx b/sd/source/ui/func/smarttag.cxx
new file mode 100644
index 000000000..ff5382116
--- /dev/null
+++ b/sd/source/ui/func/smarttag.cxx
@@ -0,0 +1,333 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/commandevent.hxx>
+
+#include <ViewShell.hxx>
+#include <smarttag.hxx>
+#include <Window.hxx>
+#include <View.hxx>
+
+namespace sd
+{
+
+SmartTag::SmartTag( ::sd::View& rView )
+: mrView( rView )
+, mbSelected( false )
+{
+ SmartTagReference xThis( this );
+ mrView.getSmartTags().add( xThis );
+}
+
+SmartTag::~SmartTag()
+{
+}
+
+bool SmartTag::MouseButtonDown( const MouseEvent&, SmartHdl& )
+{
+ return false;
+}
+
+/** returns true if the SmartTag consumes this event. */
+bool SmartTag::KeyInput( const KeyEvent& /*rKEvt*/ )
+{
+ return false;
+}
+
+/** returns true if the SmartTag consumes this event. */
+bool SmartTag::Command( const CommandEvent& /*rCEvt*/ )
+{
+ return false;
+}
+
+void SmartTag::addCustomHandles( SdrHdlList& /*rHandlerList*/ )
+{
+}
+
+void SmartTag::select()
+{
+ mbSelected = true;
+}
+
+void SmartTag::deselect()
+{
+ mbSelected = false;
+}
+
+void SmartTag::disposing()
+{
+ SmartTagReference xThis( this );
+ mrView.getSmartTags().remove( xThis );
+}
+
+bool SmartTag::getContext( SdrViewContext& /*rContext*/ )
+{
+ return false;
+}
+
+sal_Int32 SmartTag::GetMarkablePointCount() const
+{
+ return 0;
+}
+
+sal_Int32 SmartTag::GetMarkedPointCount() const
+{
+ return 0;
+}
+
+bool SmartTag::MarkPoint(SdrHdl& /*rHdl*/, bool /*bUnmark*/ )
+{
+ return false;
+}
+
+bool SmartTag::MarkPoints(const ::tools::Rectangle* /*pRect*/, bool /*bUnmark*/ )
+{
+ return false;
+}
+
+void SmartTag::CheckPossibilities()
+{
+}
+
+SmartTagSet::SmartTagSet( View& rView )
+: mrView( rView )
+{
+}
+
+SmartTagSet::~SmartTagSet()
+{
+}
+
+void SmartTagSet::add( const SmartTagReference& xTag )
+{
+ maSet.insert( xTag );
+ mrView.InvalidateAllWin();
+
+ if( xTag == mxMouseOverTag )
+ mxMouseOverTag.clear();
+
+ if( xTag == mxSelectedTag )
+ mxSelectedTag.clear();
+}
+
+void SmartTagSet::remove( const SmartTagReference& xTag )
+{
+ std::set< SmartTagReference >::iterator aIter( maSet.find( xTag ) );
+ if( aIter != maSet.end() )
+ maSet.erase( aIter );
+ mrView.InvalidateAllWin();
+
+ if( xTag == mxMouseOverTag )
+ mxMouseOverTag.clear();
+
+ if( xTag == mxSelectedTag )
+ mxSelectedTag.clear();
+}
+
+void SmartTagSet::Dispose()
+{
+ std::set< SmartTagReference > aSet;
+ aSet.swap( maSet );
+ for( auto& rxItem : aSet )
+ rxItem->Dispose();
+ mrView.InvalidateAllWin();
+ mxMouseOverTag.clear();
+ mxSelectedTag.clear();
+}
+
+void SmartTagSet::select( const SmartTagReference& xTag )
+{
+ if( mxSelectedTag == xTag )
+ return;
+
+ if( mxSelectedTag.is() )
+ mxSelectedTag->deselect();
+
+ mxSelectedTag = xTag;
+ mxSelectedTag->select();
+ mrView.SetPossibilitiesDirty();
+ if( mrView.GetMarkedObjectCount() > 0 )
+ mrView.UnmarkAllObj();
+ else
+ mrView.updateHandles();
+}
+
+void SmartTagSet::deselect()
+{
+ if( mxSelectedTag.is() )
+ {
+ mxSelectedTag->deselect();
+ mxSelectedTag.clear();
+ mrView.SetPossibilitiesDirty();
+ mrView.updateHandles();
+ }
+}
+
+bool SmartTagSet::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ Point aMDPos( mrView.GetViewShell()->GetActiveWindow()->PixelToLogic( rMEvt.GetPosPixel() ) );
+ SdrHdl* pHdl = mrView.PickHandle(aMDPos);
+
+ // check if a smart tag is selected and no handle is hit
+ if( mxSelectedTag.is() && !pHdl )
+ {
+ // deselect smart tag
+ deselect();
+ return false;
+ }
+
+ // if a smart tag handle is hit, forward event to its smart tag
+ SmartHdl* pSmartHdl = dynamic_cast< SmartHdl* >( pHdl );
+ if(pSmartHdl && pSmartHdl->getTag().is() )
+ {
+ SmartTagReference xTag( pSmartHdl->getTag() );
+ return xTag->MouseButtonDown( rMEvt, *pSmartHdl );
+ }
+
+ return false;
+}
+
+bool SmartTagSet::KeyInput( const KeyEvent& rKEvt )
+{
+ if( mxSelectedTag.is() )
+ return mxSelectedTag->KeyInput( rKEvt );
+ else if( rKEvt.GetKeyCode().GetCode() == KEY_SPACE )
+ {
+ SmartHdl* pSmartHdl = dynamic_cast< SmartHdl* >( mrView.GetHdlList().GetFocusHdl() );
+ if( pSmartHdl )
+ {
+ const_cast< SdrHdlList& >( mrView.GetHdlList() ).ResetFocusHdl();
+ const SmartTagReference& xTag( pSmartHdl->getTag() );
+ select( xTag );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** returns true if the SmartTag consumes this event. */
+bool SmartTagSet::Command( const CommandEvent& rCEvt )
+{
+ if( rCEvt.IsMouseEvent() )
+ {
+ Point aMDPos( mrView.GetViewShell()->GetActiveWindow()->PixelToLogic( rCEvt.GetMousePosPixel() ) );
+ SdrHdl* pHdl = mrView.PickHandle(aMDPos);
+
+ if( pHdl )
+ {
+ // if a smart tag handle is hit, forward event to its smart tag
+ SmartHdl* pSmartHdl = dynamic_cast< SmartHdl* >( pHdl );
+ if(pSmartHdl && pSmartHdl->getTag().is() )
+ {
+ const SmartTagReference& xTag( pSmartHdl->getTag() );
+ return xTag->Command( rCEvt );
+ }
+ }
+ }
+ else
+ {
+ if( mxSelectedTag.is() )
+ return mxSelectedTag->Command( rCEvt );
+
+ }
+
+ return false;
+}
+
+void SmartTagSet::addCustomHandles( SdrHdlList& rHandlerList )
+{
+ for( auto& rxItem : maSet )
+ rxItem->addCustomHandles( rHandlerList );
+}
+
+/** returns true if the currently selected smart tag has
+ a special context, returned in rContext. */
+bool SmartTagSet::getContext( SdrViewContext& rContext ) const
+{
+ if( mxSelectedTag.is() )
+ return mxSelectedTag->getContext( rContext );
+ else
+ return false;
+}
+
+// support point editing
+
+bool SmartTagSet::HasMarkablePoints() const
+{
+ return GetMarkablePointCount() != 0;
+}
+
+sal_uLong SmartTagSet::GetMarkablePointCount() const
+{
+ if( mxSelectedTag.is() )
+ return mxSelectedTag->GetMarkablePointCount();
+ return 0;
+}
+
+bool SmartTagSet::HasMarkedPoints() const
+{
+ return GetMarkedPointCount() != 0;
+}
+
+sal_uLong SmartTagSet::GetMarkedPointCount() const
+{
+ if( mxSelectedTag.is() )
+ return mxSelectedTag->GetMarkedPointCount();
+ else
+ return 0;
+}
+
+bool SmartTagSet::MarkPoint(SdrHdl& rHdl, bool bUnmark )
+{
+ if( mxSelectedTag.is() )
+ return mxSelectedTag->MarkPoint( rHdl, bUnmark );
+
+ return false;
+}
+
+bool SmartTagSet::MarkPoints(const ::tools::Rectangle* pRect, bool bUnmark)
+{
+ if( mxSelectedTag.is() )
+ return mxSelectedTag->MarkPoints( pRect, bUnmark );
+ return false;
+}
+
+void SmartTagSet::CheckPossibilities()
+{
+ if( mxSelectedTag.is() )
+ mxSelectedTag->CheckPossibilities();
+}
+
+SmartHdl::SmartHdl( const SmartTagReference& xTag, SdrObject* pObject, const Point& rPnt, SdrHdlKind eNewKind /*=SdrHdlKind::Move*/ )
+: SdrHdl( rPnt, eNewKind )
+, mxSmartTag( xTag )
+{
+ SetObj( pObject );
+}
+
+SmartHdl::SmartHdl( const SmartTagReference& xTag, const Point& rPnt, SdrHdlKind eNewKind /*=SdrHdlKind::Move*/ )
+: SdrHdl( rPnt, eNewKind )
+, mxSmartTag( xTag )
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/undoback.cxx b/sd/source/ui/func/undoback.cxx
new file mode 100644
index 000000000..768ca2ec2
--- /dev/null
+++ b/sd/source/ui/func/undoback.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <undoback.hxx>
+
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+
+#include <com/sun/star/drawing/FillStyle.hpp>
+
+#include <svl/itemset.hxx>
+
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xbtmpit.hxx>
+
+SdBackgroundObjUndoAction::SdBackgroundObjUndoAction(
+ SdDrawDocument& rDoc,
+ SdPage& rPage,
+ const SfxItemSet& rItemSet)
+: SdUndoAction(&rDoc),
+ mrPage(rPage),
+ mpItemSet(std::make_unique<SfxItemSet>(rItemSet)),
+ mbHasFillBitmap(false)
+{
+ OUString aString( SdResId( STR_UNDO_CHANGE_PAGEFORMAT ) );
+ SetComment( aString );
+ saveFillBitmap(*mpItemSet);
+}
+
+void SdBackgroundObjUndoAction::ImplRestoreBackgroundObj()
+{
+ std::unique_ptr<SfxItemSet> pNew = std::make_unique<SfxItemSet>(mrPage.getSdrPageProperties().GetItemSet());
+ mrPage.getSdrPageProperties().ClearItem();
+ if (bool(mpFillBitmapItem))
+ restoreFillBitmap(*mpItemSet);
+ mpFillBitmapItem.reset();
+ mbHasFillBitmap = false;
+ mrPage.getSdrPageProperties().PutItemSet(*mpItemSet);
+ mpItemSet = std::move(pNew);
+ saveFillBitmap(*mpItemSet);
+
+ // tell the page that it's visualization has changed
+ mrPage.ActionChanged();
+}
+
+void SdBackgroundObjUndoAction::Undo()
+{
+ ImplRestoreBackgroundObj();
+}
+
+void SdBackgroundObjUndoAction::Redo()
+{
+ ImplRestoreBackgroundObj();
+}
+
+SdUndoAction* SdBackgroundObjUndoAction::Clone() const
+{
+ std::unique_ptr<SdBackgroundObjUndoAction> pCopy = std::make_unique<SdBackgroundObjUndoAction>(*mpDoc, mrPage, *mpItemSet);
+ if (mpFillBitmapItem)
+ pCopy->mpFillBitmapItem.reset(mpFillBitmapItem->Clone());
+ pCopy->mbHasFillBitmap = mbHasFillBitmap;
+ return pCopy.release();
+}
+
+void SdBackgroundObjUndoAction::saveFillBitmap(SfxItemSet &rItemSet)
+{
+ if (const XFillBitmapItem *pItem = rItemSet.GetItemIfSet(XATTR_FILLBITMAP, false))
+ mpFillBitmapItem.reset(pItem->Clone());
+ if (bool(mpFillBitmapItem))
+ {
+ if (const XFillStyleItem* pItem = rItemSet.GetItemIfSet(XATTR_FILLSTYLE, false))
+ mbHasFillBitmap = pItem->GetValue() == css::drawing::FillStyle_BITMAP;
+ rItemSet.ClearItem(XATTR_FILLBITMAP);
+ if (mbHasFillBitmap)
+ rItemSet.ClearItem(XATTR_FILLSTYLE);
+ }
+}
+
+void SdBackgroundObjUndoAction::restoreFillBitmap(SfxItemSet &rItemSet)
+{
+ rItemSet.Put(*mpFillBitmapItem);
+ if (mbHasFillBitmap)
+ rItemSet.Put(XFillStyleItem(css::drawing::FillStyle_BITMAP));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/undoheaderfooter.cxx b/sd/source/ui/func/undoheaderfooter.cxx
new file mode 100644
index 000000000..e0183dac3
--- /dev/null
+++ b/sd/source/ui/func/undoheaderfooter.cxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <app.hrc>
+#include <undoheaderfooter.hxx>
+
+
+SdHeaderFooterUndoAction::SdHeaderFooterUndoAction( SdDrawDocument* pDoc, SdPage* pPage, const sd::HeaderFooterSettings& rNewSettings )
+: SdUndoAction(pDoc),
+ mpPage(pPage),
+ maOldSettings(pPage->getHeaderFooterSettings()),
+ maNewSettings(rNewSettings)
+{
+}
+
+SdHeaderFooterUndoAction::~SdHeaderFooterUndoAction()
+{
+}
+
+void SdHeaderFooterUndoAction::Undo()
+{
+ mpPage->setHeaderFooterSettings( maOldSettings );
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ pViewFrm->GetDispatcher()->Execute( SID_SWITCHPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+}
+
+void SdHeaderFooterUndoAction::Redo()
+{
+ mpPage->setHeaderFooterSettings( maNewSettings );
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ pViewFrm->GetDispatcher()->Execute( SID_SWITCHPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/undolayer.cxx b/sd/source/ui/func/undolayer.cxx
new file mode 100644
index 000000000..b29142ee8
--- /dev/null
+++ b/sd/source/ui/func/undolayer.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <undolayer.hxx>
+
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <DrawViewShell.hxx>
+#include <strings.hrc>
+#include <sdresid.hxx>
+
+
+SdLayerModifyUndoAction::SdLayerModifyUndoAction(
+ SdDrawDocument* _pDoc, SdrLayer* pLayer,
+ const OUString& rOldLayerName, const OUString& rOldLayerTitle, const OUString& rOldLayerDesc, bool bOldIsVisible, bool bOldIsLocked, bool bOldIsPrintable,
+ const OUString& rNewLayerName, const OUString& rNewLayerTitle, const OUString& rNewLayerDesc, bool bNewIsVisible, bool bNewIsLocked, bool bNewIsPrintable )
+: SdUndoAction( _pDoc ),
+ mpLayer( pLayer ),
+ maOldLayerName( rOldLayerName ),
+ maOldLayerTitle( rOldLayerTitle ),
+ maOldLayerDesc( rOldLayerDesc ),
+ mbOldIsVisible( bOldIsVisible ),
+ mbOldIsLocked( bOldIsLocked ),
+ mbOldIsPrintable( bOldIsPrintable ),
+ maNewLayerName( rNewLayerName ),
+ maNewLayerTitle( rNewLayerTitle ),
+ maNewLayerDesc( rNewLayerDesc ),
+ mbNewIsVisible( bNewIsVisible ),
+ mbNewIsLocked( bNewIsLocked ),
+ mbNewIsPrintable( bNewIsPrintable )
+{
+ OUString aString(SdResId(STR_MODIFYLAYER));
+ SetComment(aString);
+}
+
+void SdLayerModifyUndoAction::Undo()
+{
+ ::sd::DrawDocShell* pDocSh = mpDoc->GetDocSh();
+ if( pDocSh )
+ {
+ ::sd::DrawViewShell* pDrViewSh = dynamic_cast< ::sd::DrawViewShell*> ( pDocSh->GetViewShell() );
+ if( pDrViewSh )
+ {
+ pDrViewSh->ModifyLayer( mpLayer, maOldLayerName, maOldLayerTitle, maOldLayerDesc, mbOldIsVisible, mbOldIsLocked, mbOldIsPrintable );
+ }
+ }
+}
+
+void SdLayerModifyUndoAction::Redo()
+{
+ ::sd::DrawDocShell* pDocSh = mpDoc->GetDocSh();
+ if( pDocSh )
+ {
+ ::sd::DrawViewShell* pDrViewSh = dynamic_cast< ::sd::DrawViewShell* >( pDocSh->GetViewShell() );
+ if( pDrViewSh )
+ {
+ pDrViewSh->ModifyLayer( mpLayer, maNewLayerName, maNewLayerTitle, maNewLayerDesc, mbNewIsVisible, mbNewIsLocked, mbNewIsPrintable );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/undopage.cxx b/sd/source/ui/func/undopage.cxx
new file mode 100644
index 000000000..174747bf6
--- /dev/null
+++ b/sd/source/ui/func/undopage.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <undopage.hxx>
+#include <sdpage.hxx>
+
+
+SdPageFormatUndoAction::~SdPageFormatUndoAction()
+{
+}
+
+void SdPageFormatUndoAction::Undo()
+{
+ ::tools::Rectangle aOldBorderRect(mnOldLeft, mnOldUpper, mnOldRight, mnOldLower);
+ mpPage->ScaleObjects(maOldSize, aOldBorderRect, mbNewScale);
+ mpPage->SetSize(maOldSize);
+ mpPage->SetLeftBorder(mnOldLeft);
+ mpPage->SetRightBorder(mnOldRight);
+ mpPage->SetUpperBorder(mnOldUpper);
+ mpPage->SetLowerBorder(mnOldLower);
+ mpPage->SetOrientation(meOldOrientation);
+ mpPage->SetPaperBin( mnOldPaperBin );
+
+ mpPage->SetBackgroundFullSize( mbOldFullSize );
+ if( !mpPage->IsMasterPage() )
+ static_cast<SdPage&>( mpPage->TRG_GetMasterPage() ).SetBackgroundFullSize( mbOldFullSize );
+
+}
+
+void SdPageFormatUndoAction::Redo()
+{
+ ::tools::Rectangle aNewBorderRect(mnNewLeft, mnNewUpper, mnNewRight, mnNewLower);
+ mpPage->ScaleObjects(maNewSize, aNewBorderRect, mbNewScale);
+ mpPage->SetSize(maNewSize);
+ mpPage->SetLeftBorder(mnNewLeft);
+ mpPage->SetRightBorder(mnNewRight);
+ mpPage->SetUpperBorder(mnNewUpper);
+ mpPage->SetLowerBorder(mnNewLower);
+ mpPage->SetOrientation(meNewOrientation);
+ mpPage->SetPaperBin( mnNewPaperBin );
+
+ mpPage->SetBackgroundFullSize( mbNewFullSize );
+ if( !mpPage->IsMasterPage() )
+ static_cast<SdPage&>( mpPage->TRG_GetMasterPage() ).SetBackgroundFullSize( mbNewFullSize );
+
+}
+
+SdPageLRUndoAction::~SdPageLRUndoAction()
+{
+}
+
+void SdPageLRUndoAction::Undo()
+{
+ mpPage->SetLeftBorder(mnOldLeft);
+ mpPage->SetRightBorder(mnOldRight);
+}
+
+void SdPageLRUndoAction::Redo()
+{
+ mpPage->SetLeftBorder(mnNewLeft);
+ mpPage->SetRightBorder(mnNewRight);
+}
+
+SdPageULUndoAction::~SdPageULUndoAction()
+{
+}
+
+void SdPageULUndoAction::Undo()
+{
+ mpPage->SetUpperBorder(mnOldUpper);
+ mpPage->SetLowerBorder(mnOldLower);
+}
+
+/**
+ * UL-Redo()
+ */
+void SdPageULUndoAction::Redo()
+{
+ mpPage->SetUpperBorder(mnNewUpper);
+ mpPage->SetLowerBorder(mnNewLower);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/unmovss.cxx b/sd/source/ui/func/unmovss.cxx
new file mode 100644
index 000000000..d21f83b39
--- /dev/null
+++ b/sd/source/ui/func/unmovss.cxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unmovss.hxx>
+#include <drawdoc.hxx>
+#include <stlsheet.hxx>
+#include <stlpool.hxx>
+
+SdMoveStyleSheetsUndoAction::SdMoveStyleSheetsUndoAction( SdDrawDocument* pTheDoc, StyleSheetCopyResultVector& rTheStyles, bool bInserted)
+: SdUndoAction(pTheDoc)
+, mbMySheets( !bInserted )
+{
+ maStyles.swap( rTheStyles );
+
+ maListOfChildLists.resize( maStyles.size() );
+ // create list with lists of style sheet children
+ std::size_t i = 0;
+ for (const auto& a : maStyles)
+ {
+ maListOfChildLists[i++] = SdStyleSheetPool::CreateChildList(a.m_xStyleSheet.get());
+ }
+}
+
+void SdMoveStyleSheetsUndoAction::Undo()
+{
+ SfxStyleSheetBasePool* pPool = mpDoc->GetStyleSheetPool();
+
+ if (mbMySheets)
+ {
+ // the styles have to be inserted in the pool
+
+ // first insert all styles to the pool
+ for (auto& a : maStyles)
+ {
+ if (!a.m_bCreatedByCopy) // tdf#119259, existed before this action, so leave it alone
+ continue;
+ pPool->Insert(a.m_xStyleSheet.get());
+ }
+
+ // now assign the children again
+ std::vector< SdStyleSheetVector >::iterator childlistiter( maListOfChildLists.begin() );
+ for (const auto& a : maStyles)
+ {
+ OUString aParent(a.m_xStyleSheet->GetName());
+ for( auto& rxChild : *childlistiter )
+ {
+ rxChild->SetParent(aParent);
+ }
+ ++childlistiter;
+ }
+ }
+ else
+ {
+ // remove the styles again from the pool
+ for (auto& a : maStyles)
+ {
+ if (!a.m_bCreatedByCopy) // tdf#119259, existed before this action, so leave it alone
+ continue;
+ pPool->Remove(a.m_xStyleSheet.get());
+ }
+ }
+ mbMySheets = !mbMySheets;
+}
+
+void SdMoveStyleSheetsUndoAction::Redo()
+{
+ Undo();
+}
+
+SdMoveStyleSheetsUndoAction::~SdMoveStyleSheetsUndoAction()
+{
+}
+
+OUString SdMoveStyleSheetsUndoAction::GetComment() const
+{
+ return OUString();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/unoaprms.cxx b/sd/source/ui/func/unoaprms.cxx
new file mode 100644
index 000000000..3bf7d98a6
--- /dev/null
+++ b/sd/source/ui/func/unoaprms.cxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <drawdoc.hxx>
+#include <unoaprms.hxx>
+#include <anminfo.hxx>
+
+
+void SdAnimationPrmsUndoAction::Undo()
+{
+ // no new info created: restore data
+ if (!bInfoCreated)
+ {
+ SdDrawDocument* pDoc(dynamic_cast< SdDrawDocument* >(&pObject->getSdrModelFromSdrObject()));
+ SdAnimationInfo* pInfo = pDoc ? SdDrawDocument::GetAnimationInfo(pObject) : nullptr;
+ if (pInfo)
+ {
+ pInfo->mbActive = bOldActive;
+ pInfo->meEffect = eOldEffect;
+ pInfo->meTextEffect = eOldTextEffect;
+ pInfo->meSpeed = eOldSpeed;
+ pInfo->mbDimPrevious = bOldDimPrevious;
+ pInfo->maDimColor = aOldDimColor;
+ pInfo->mbDimHide = bOldDimHide;
+ pInfo->mbSoundOn = bOldSoundOn;
+ pInfo->maSoundFile = aOldSoundFile;
+ pInfo->mbPlayFull = bOldPlayFull;
+ pInfo->meClickAction = eOldClickAction;
+ pInfo->SetBookmark( aOldBookmark );
+ pInfo->mnVerb = nOldVerb;
+
+ pInfo->meSecondEffect = eOldSecondEffect;
+ pInfo->meSecondSpeed = eOldSecondSpeed;
+ pInfo->mbSecondSoundOn = bOldSecondSoundOn;
+ pInfo->mbSecondPlayFull = bOldSecondPlayFull;
+ }
+ }
+ // info was created by action: delete info
+ else
+ {
+ pObject->DeleteUserData(0);
+ }
+ // force ModelHasChanged() in order to update effect window (animation order)
+ pObject->SetChanged();
+ pObject->BroadcastObjectChange();
+}
+
+void SdAnimationPrmsUndoAction::Redo()
+{
+ SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pObject,true);
+
+ pInfo->mbActive = bNewActive;
+ pInfo->meEffect = eNewEffect;
+ pInfo->meTextEffect = eNewTextEffect;
+ pInfo->meSpeed = eNewSpeed;
+ pInfo->mbDimPrevious = bNewDimPrevious;
+ pInfo->maDimColor = aNewDimColor;
+ pInfo->mbDimHide = bNewDimHide;
+ pInfo->mbSoundOn = bNewSoundOn;
+ pInfo->maSoundFile = aNewSoundFile;
+ pInfo->mbPlayFull = bNewPlayFull;
+ pInfo->meClickAction = eNewClickAction;
+ pInfo->SetBookmark( aNewBookmark );
+ pInfo->mnVerb = nNewVerb;
+
+ pInfo->meSecondEffect = eNewSecondEffect;
+ pInfo->meSecondSpeed = eNewSecondSpeed;
+ pInfo->mbSecondSoundOn = bNewSecondSoundOn;
+ pInfo->mbSecondPlayFull = bNewSecondPlayFull;
+
+ // force ModelHasChanged() in order to update effect window (animation order)
+ pObject->SetChanged();
+ pObject->BroadcastObjectChange();
+}
+
+SdAnimationPrmsUndoAction::~SdAnimationPrmsUndoAction()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/func/unprlout.cxx b/sd/source/ui/func/unprlout.cxx
new file mode 100644
index 000000000..218883349
--- /dev/null
+++ b/sd/source/ui/func/unprlout.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 <tools/debug.hxx>
+
+#include <unprlout.hxx>
+
+#include <strings.hrc>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+
+
+SdPresentationLayoutUndoAction::SdPresentationLayoutUndoAction(
+ SdDrawDocument* pTheDoc,
+ const OUString& aTheOldLayoutName,
+ const OUString& aTheNewLayoutName,
+ AutoLayout eTheOldAutoLayout,
+ AutoLayout eTheNewAutoLayout,
+ bool bSet,
+ SdPage* pThePage):
+ SdUndoAction(pTheDoc)
+{
+ aOldLayoutName = aTheOldLayoutName;
+ aNewLayoutName = aTheNewLayoutName;
+ eOldAutoLayout = eTheOldAutoLayout;
+ eNewAutoLayout = eTheNewAutoLayout;
+ bSetAutoLayout = bSet;
+
+ DBG_ASSERT(pThePage, "No Page set!");
+ pPage = pThePage;
+ aComment = SdResId(STR_UNDO_SET_PRESLAYOUT);
+}
+
+void SdPresentationLayoutUndoAction::Undo()
+{
+ pPage->SetPresentationLayout(aOldLayoutName, true, true, true);
+ if (bSetAutoLayout)
+ pPage->SetAutoLayout(eOldAutoLayout, true);
+}
+
+void SdPresentationLayoutUndoAction::Redo()
+{
+ pPage->SetPresentationLayout(aNewLayoutName);
+ if (bSetAutoLayout)
+ pPage->SetAutoLayout(eNewAutoLayout, true);
+}
+
+SdPresentationLayoutUndoAction::~SdPresentationLayoutUndoAction()
+{
+}
+
+OUString SdPresentationLayoutUndoAction::GetComment() const
+{
+ return aComment;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessibleDocumentViewBase.hxx b/sd/source/ui/inc/AccessibleDocumentViewBase.hxx
new file mode 100644
index 000000000..0db25b689
--- /dev/null
+++ b/sd/source/ui/inc/AccessibleDocumentViewBase.hxx
@@ -0,0 +1,324 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this 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_SD_SOURCE_UI_INC_ACCESSIBLEDOCUMENTVIEWBASE_HXX
+#define INCLUDED_SD_SOURCE_UI_INC_ACCESSIBLEDOCUMENTVIEWBASE_HXX
+
+#include <editeng/AccessibleContextBase.hxx>
+#include <editeng/AccessibleComponentBase.hxx>
+#include <editeng/AccessibleSelectionBase.hxx>
+#include "AccessibleViewForwarder.hxx"
+#include <svx/AccessibleShapeTreeInfo.hxx>
+#include <svx/IAccessibleViewForwarderListener.hxx>
+
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/awt/XFocusListener.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <tools/link.hxx>
+
+#include <com/sun/star/accessibility/XAccessibleExtendedAttributes.hpp>
+
+#include "Window.hxx"
+
+namespace com::sun::star::accessibility { class XAccessible; }
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::awt { class XWindow; }
+
+class VclWindowEvent;
+
+namespace sd {
+class ViewShell;
+}
+
+namespace accessibility {
+
+/** Base class for the various document views of the Draw and
+ Impress applications.
+
+ <p>The different view modes of the Draw and Impress applications
+ are made accessible by derived classes. When the view mode is
+ changed then the object representing the document view is
+ disposed and replaced by a new instance of the then appropriate
+ derived class.</p>
+
+ <p>This base class also manages an optionally active accessible OLE
+ object. If you overwrite the <member>getAccessibleChildCount</member>
+ and <member>getAccessibleChild</member> methods then make sure to first
+ call the corresponding method of this class and adapt your child count
+ and indices accordingly. Only one active OLE object is allowed at a
+ time. This class does not listen for disposing calls at the moment
+ because it does not use the accessible OLE object directly and trusts on
+ getting informed through VCL window events.</p>
+
+ <p>This class implements three kinds of listeners:
+ <ol><li>The property change listener is not used directly but exists as
+ convenience for derived classes. May be moved to those classes
+ instead.</li>
+ <li>As window listener it waits for changes of the window geometry and
+ forwards those as view forwarder changes.</li>
+ <li>As focus listener it keeps track of the focus to give this class and
+ derived classes the opportunity to set and remove the focus to/from
+ shapes.</li>
+ </ol>
+ </p>
+*/
+class AccessibleDocumentViewBase
+ : public AccessibleContextBase,
+ public AccessibleComponentBase,
+ public AccessibleSelectionBase,
+ public IAccessibleViewForwarderListener,
+ public css::beans::XPropertyChangeListener,
+ public css::awt::XWindowListener,
+ public css::awt::XFocusListener,
+ public css::accessibility::XAccessibleExtendedAttributes
+{
+public:
+ //===== internal ========================================================
+
+ /** Create a new object. Note that the caller has to call the
+ Init method directly after this constructor has finished.
+ @param pSdWindow
+ The window whose content is to be made accessible.
+ @param pViewShell
+ The view shell associated with the given window.
+ @param rxController
+ The controller from which to get the model.
+ @param rxParent
+ The accessible parent of the new object. Note that this parent does
+ not necessarily correspond with the parent of the given window.
+ */
+ AccessibleDocumentViewBase (
+ ::sd::Window* pSdWindow,
+ ::sd::ViewShell* pViewShell,
+ const css::uno::Reference<css::frame::XController>& rxController,
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent);
+
+ virtual ~AccessibleDocumentViewBase() override;
+
+ /** Initialize a new object. Call this method directly after creating a
+ new object. It finished the initialization begun in the constructor
+ but which needs a fully created object.
+ */
+ virtual void Init();
+
+ /** Define callback for listening to window child events of VCL.
+ Listen for creation or destruction of OLE objects.
+ */
+ DECL_LINK( WindowChildEventListener, VclWindowEvent&, void );
+
+ //===== IAccessibleViewForwarderListener ================================
+
+ /** A view forwarder change is signalled for instance when any of the
+ window events is received. Thus, instead of overriding the four
+ windowResized... methods it will be sufficient in most cases just to
+ override this method.
+ */
+ virtual void ViewForwarderChanged() override;
+
+ //===== XAccessibleContext ==============================================
+
+ virtual css::uno::Reference<css::accessibility::XAccessible> SAL_CALL
+ getAccessibleParent() override;
+
+ /** This implementation returns either 1 or 0 depending on whether there
+ is an active accessible OLE object or not.
+ */
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ /** This implementation either returns the active accessible OLE object
+ if it exists and the given index is 0 or throws an exception.
+ */
+ virtual css::uno::Reference<css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild (sal_Int32 nIndex) override;
+
+ //===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference<css::accessibility::XAccessible > SAL_CALL
+ getAccessibleAtPoint (const css::awt::Point& aPoint) override;
+
+ virtual css::awt::Rectangle SAL_CALL getBounds() override;
+
+ virtual css::awt::Point SAL_CALL getLocation() override;
+
+ virtual css::awt::Point SAL_CALL getLocationOnScreen() override;
+
+ virtual css::awt::Size SAL_CALL getSize() override;
+
+ //===== XInterface ======================================================
+
+ virtual css::uno::Any SAL_CALL
+ queryInterface (const css::uno::Type & rType) override;
+
+ virtual void SAL_CALL
+ acquire()
+ noexcept override;
+
+ virtual void SAL_CALL
+ release()
+ noexcept override;
+
+ //===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+ //===== XTypeProvider ===================================================
+
+ virtual css::uno::Sequence< css::uno::Type> SAL_CALL
+ getTypes() override;
+
+ //===== lang::XEventListener ============================================
+
+ virtual void SAL_CALL
+ disposing (const css::lang::EventObject& rEventObject) override;
+
+ //===== XPropertyChangeListener =========================================
+
+ virtual void SAL_CALL
+ propertyChange (const css::beans::PropertyChangeEvent& rEventObject) override;
+
+ //===== XWindowListener =================================================
+
+ virtual void SAL_CALL
+ windowResized (const css::awt::WindowEvent& e) override;
+
+ virtual void SAL_CALL
+ windowMoved (const css::awt::WindowEvent& e) override;
+
+ virtual void SAL_CALL
+ windowShown (const css::lang::EventObject& e) override;
+
+ virtual void SAL_CALL
+ windowHidden (const css::lang::EventObject& e) override;
+
+ //===== XFocusListener =================================================
+
+ virtual void SAL_CALL focusGained (const css::awt::FocusEvent& e) override;
+ virtual void SAL_CALL focusLost (const css::awt::FocusEvent& e) override;
+ //----------------------------xAttribute----------------------------
+ virtual css::uno::Any SAL_CALL getExtendedAttributes() override;
+ ::sd::ViewShell* mpViewShell;
+private:
+
+ // return the member maMutex;
+ virtual ::osl::Mutex&
+ implGetMutex() override;
+
+ // return ourself as context in default case
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext >
+ implGetAccessibleContext() override;
+
+ // return sal_False in default case
+ virtual bool
+ implIsSelected( sal_Int32 nAccessibleChildIndex ) override;
+
+ // return nothing in default case
+ virtual void
+ implSelect( sal_Int32 nAccessibleChildIndex, bool bSelect ) override;
+
+protected:
+ /// The API window that is made accessible.
+ css::uno::Reference< css::awt::XWindow>
+ mxWindow;
+
+ /// The controller of the window in which this view is displayed.
+ css::uno::Reference< css::frame::XController>
+ mxController;
+
+ /// Model of the document.
+ css::uno::Reference < css::frame::XModel>
+ mxModel;
+
+ // Bundle of information that is passed down the shape tree.
+ AccessibleShapeTreeInfo maShapeTreeInfo;
+
+ /// The view forwarder passed to the children manager.
+ AccessibleViewForwarder maViewForwarder;
+
+ /** Accessible OLE object. Set or removed by the
+ <member>SetAccessibleOLEObject</member> method.
+ */
+ css::uno::Reference< css::accessibility::XAccessible>
+ mxAccessibleOLEObject;
+
+ Link<VclWindowEvent&,void> maWindowLink;
+
+ // This method is called from the component helper base class while
+ // disposing.
+ virtual void SAL_CALL disposing() override;
+
+ /** Create a name string. The current name is not modified and,
+ therefore, no events are sent. This method is usually called once
+ by the <member>getAccessibleName</member> method of the base class.
+ @return
+ A name string.
+ */
+ virtual OUString
+ CreateAccessibleName () override;
+
+ /** This method is called when (after) the frame containing this
+ document has been activated. Can be used to send FOCUSED state
+ changes for the currently selected element.
+
+ Note: Currently used as a substitute for FocusGained. Should be
+ renamed in the future.
+ */
+ virtual void Activated();
+
+ /** This method is called when (before or after?) the frame containing
+ this document has been deactivated. Can be used to send FOCUSED
+ state changes for the currently selected element.
+
+ Note: Currently used as a substitute for FocusLost. Should be
+ renamed in the future.
+ */
+ virtual void Deactivated();
+
+ /** Set or remove the currently active accessible OLE object.
+ @param xOLEObject
+ If this is a valid reference then a child event is send that
+ informs the listeners of a new child. If there has already been
+ an active accessible OLE object then this is removed first and
+ appropriate events are sent.
+
+ If this is an empty reference then the currently active
+ accessible OLE object (if there is one) is removed.
+ */
+ void SetAccessibleOLEObject (
+ const css::uno::Reference<css::accessibility::XAccessible>& xOLEObject);
+
+public:
+ void SwitchViewActivated() { Activated(); }
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+ virtual void impl_dispose();
+};
+
+} // end of namespace accessibility
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessibleDrawDocumentView.hxx b/sd/source/ui/inc/AccessibleDrawDocumentView.hxx
new file mode 100644
index 000000000..202edd0ea
--- /dev/null
+++ b/sd/source/ui/inc/AccessibleDrawDocumentView.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "AccessibleDocumentViewBase.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleGroupPosition.hpp>
+
+namespace accessibility { class AccessiblePageShape; }
+namespace accessibility { class ChildrenManager; }
+
+namespace accessibility {
+
+/** This class makes draw documents in the general view modes
+ accessible. It passes all shapes on the current draw page to a
+ children manager and additionally creates a new shape that
+ represents the actual draw page.
+
+ Please see the documentation of the base class for further
+ explanations of the individual methods.
+*/
+class AccessibleDrawDocumentView final :
+ public AccessibleDocumentViewBase
+ ,public css::accessibility::XAccessibleGroupPosition
+{
+public:
+ //===== internal ========================================================
+
+ AccessibleDrawDocumentView (::sd::Window* pSdWindow,
+ ::sd::ViewShell* pViewShell,
+ const css::uno::Reference<css::frame::XController>& rxController,
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent);
+
+ virtual ~AccessibleDrawDocumentView() override;
+
+ /** Complete the initialization begun in the constructor.
+ */
+ virtual void Init() override;
+
+ //===== IAccessibleViewForwarderListener ================================
+
+ virtual void ViewForwarderChanged() override;
+
+ //===== XAccessibleContext ==============================================
+
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild (sal_Int32 nIndex) override;
+
+ virtual OUString SAL_CALL
+ getAccessibleName() override;
+
+ //===== lang::XEventListener ============================================
+
+ virtual void SAL_CALL
+ disposing (const css::lang::EventObject& rEventObject) override;
+
+ //===== XPropertyChangeListener =========================================
+
+ virtual void SAL_CALL
+ propertyChange (const css::beans::PropertyChangeEvent& rEventObject) override;
+ //===== XInterface ======================================================
+
+ virtual css::uno::Any SAL_CALL
+ queryInterface (const css::uno::Type & rType) override;
+
+ virtual void SAL_CALL
+ acquire()
+ noexcept override;
+
+ virtual void SAL_CALL
+ release()
+ noexcept override;
+
+ //===== XAccessibleGroupPosition =========================================
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL
+ getGroupPosition( const css::uno::Any& rAny ) override;
+ virtual OUString SAL_CALL getObjectLink( const css::uno::Any& accoject ) override;
+
+private:
+
+ //===== XServiceInfo ====================================================
+
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+ virtual bool
+ implIsSelected( sal_Int32 nAccessibleChildIndex ) override;
+
+ /** Select or deselect the specified child or all children if the given
+ index has the special value ACCESSIBLE_SELECTION_CHILD_ALL.
+ Selecting or deselecting a child sets or resets the
+ <const>SELECTED</const> state and selects or deselects the UNO shape
+ being made accessible by the child.
+ @param nAccessibleChildIndex
+ Index of the child to select or deselect. If the parameter has
+ the value ACCESSIBLE_SELECTION_CHILD_ALL then all children are
+ selected or deselected.
+ @param bSelect
+ Indicates whether to select or deselect the specified child
+ reps. children.
+ */
+ virtual void
+ implSelect( sal_Int32 nAccessibleChildIndex, bool bSelect ) override;
+
+ ::sd::ViewShell* mpSdViewSh;
+
+ /** This object manages the shapes of the represented draw page. It is
+ responsible to determine the visible shapes and create on demand the
+ accessible objects representing them.
+ */
+ std::unique_ptr<ChildrenManager> mpChildrenManager;
+
+ // This method is called from the component helper base class while
+ // disposing.
+ virtual void SAL_CALL disposing() override;
+
+ /** Create a shape the represents the page as seen on the screen.
+ */
+ rtl::Reference<AccessiblePageShape> CreateDrawPageShape();
+
+ /// Create an accessible name that contains the current view mode.
+ virtual OUString
+ CreateAccessibleName () override;
+
+ /** Make sure that the currently focused shape sends a FOCUSED state
+ change event indicating that it has (regained) the focus.
+ */
+ virtual void Activated() override;
+
+ /** Make sure that the currently focused shape sends a FOCUSED state
+ change event indicating that it has lost the focus.
+ */
+ virtual void Deactivated() override;
+
+ virtual void impl_dispose() override;
+
+ void UpdateAccessibleName();
+};
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessibleOutlineEditSource.hxx b/sd/source/ui/inc/AccessibleOutlineEditSource.hxx
new file mode 100644
index 000000000..d13d27e97
--- /dev/null
+++ b/sd/source/ui/inc/AccessibleOutlineEditSource.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 .
+ */
+
+#pragma once
+
+#include <svl/SfxBroadcaster.hxx>
+#include <svl/lstner.hxx>
+#include <tools/link.hxx>
+#include <editeng/unoedsrc.hxx>
+#include <editeng/unoforou.hxx>
+#include <editeng/unoviwou.hxx>
+
+class OutlinerView;
+class SdrOutliner;
+class SdrView;
+namespace vcl { class Window; }
+
+namespace accessibility
+{
+ /** Implementation of the SvxEditSource interface in the SdOutlineView
+
+ This class connects the SdOutlineView and its EditEngine
+ outliner with the AccessibleTextHelper, which provides all
+ necessary functionality to make the outliner text accessible
+
+ @see SvxEditSource
+ @see SvxViewForwarder
+ */
+ class AccessibleOutlineEditSource final : public SvxEditSource, public SvxViewForwarder, public SfxBroadcaster, public SfxListener
+ {
+ public:
+ /// Create an SvxEditSource interface for the given Outliner
+ AccessibleOutlineEditSource(
+ SdrOutliner& rOutliner,
+ SdrView& rView,
+ OutlinerView& rOutlView,
+ const vcl::Window& rViewWindow );
+ virtual ~AccessibleOutlineEditSource() override;
+
+ /// This method is disabled and always returns NULL
+ virtual std::unique_ptr<SvxEditSource> Clone() const override;
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual SvxViewForwarder* GetViewForwarder() override;
+ virtual SvxEditViewForwarder* GetEditViewForwarder( bool bCreate = false ) override;
+ virtual void UpdateData() override;
+ virtual SfxBroadcaster& GetBroadcaster() const override;
+
+ // the view forwarder
+ 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;
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ private:
+ AccessibleOutlineEditSource( const AccessibleOutlineEditSource& ) = delete;
+ AccessibleOutlineEditSource& operator=( const AccessibleOutlineEditSource& ) = delete;
+
+ DECL_LINK( NotifyHdl, EENotify&, void );
+
+ SdrView& mrView;
+ const vcl::Window& mrWindow;
+ SdrOutliner* mpOutliner;
+ OutlinerView* mpOutlinerView;
+
+ SvxOutlinerForwarder mTextForwarder;
+ SvxDrawOutlinerViewForwarder mViewForwarder;
+
+ };
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessibleOutlineView.hxx b/sd/source/ui/inc/AccessibleOutlineView.hxx
new file mode 100644
index 000000000..5fa1df7c5
--- /dev/null
+++ b/sd/source/ui/inc/AccessibleOutlineView.hxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "AccessibleDocumentViewBase.hxx"
+#include <svx/AccessibleTextHelper.hxx>
+
+namespace sd { class OutlineViewShell; }
+
+namespace accessibility {
+
+/** This class makes the Impress outline view accessible.
+
+ Please see the documentation of the base class for further
+ explanations of the individual methods. This class is a mere
+ wrapper around the AccessibleTextHelper class; as basically the
+ Outline View is a big Outliner.
+*/
+class AccessibleOutlineView final
+ : public AccessibleDocumentViewBase
+{
+public:
+ AccessibleOutlineView (
+ ::sd::Window* pSdWindow,
+ ::sd::OutlineViewShell* pViewShell,
+ const css::uno::Reference<css::frame::XController>& rxController,
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent);
+
+ virtual ~AccessibleOutlineView() override;
+
+ /** Complete the initialization begun in the constructor.
+ */
+ virtual void Init() override;
+
+ //===== IAccessibleViewForwarderListener ================================
+
+ virtual void ViewForwarderChanged() override;
+
+ //===== XAccessibleContext ==============================================
+
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild (sal_Int32 nIndex) override;
+ virtual OUString SAL_CALL
+ getAccessibleName() override;
+ //===== XAccessibleEventBroadcaster ========================================
+
+ virtual void SAL_CALL
+ addAccessibleEventListener (
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener >& xListener) override;
+
+ virtual void SAL_CALL
+ removeAccessibleEventListener (
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener >& xListener) override;
+
+ //===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ //===== lang::XEventListener ============================================
+
+ using AccessibleDocumentViewBase::disposing;
+
+ //===== XPropertyChangeListener =========================================
+
+ virtual void SAL_CALL
+ propertyChange (const css::beans::PropertyChangeEvent& rEventObject) override;
+
+private:
+
+ // overridden to detect focus changes
+ virtual void Activated() override;
+
+ // overridden to detect focus changes
+ virtual void Deactivated() override;
+
+ // declared, but not defined
+ AccessibleOutlineView( const AccessibleOutlineView& );
+ AccessibleOutlineView& operator= ( const AccessibleOutlineView& );
+
+ // This method is called from the component helper base class while disposing.
+ virtual void SAL_CALL disposing() override;
+
+ /// Create an accessible name that contains the current view mode.
+ virtual OUString
+ CreateAccessibleName () override;
+
+ /// Invalidate text helper, updates visible children
+ void UpdateChildren();
+
+ AccessibleTextHelper maTextHelper;
+
+};
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessiblePageShape.hxx b/sd/source/ui/inc/AccessiblePageShape.hxx
new file mode 100644
index 000000000..164fb96fe
--- /dev/null
+++ b/sd/source/ui/inc/AccessiblePageShape.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <svx/AccessibleShape.hxx>
+
+namespace com::sun::star::accessibility { class XAccessible; }
+namespace com::sun::star::drawing { class XDrawPage; }
+namespace accessibility { class AccessibleShapeTreeInfo; }
+
+namespace accessibility {
+
+/** A page shape represents the actual page as seen on the screen.
+*/
+class AccessiblePageShape
+ : public AccessibleShape
+{
+public:
+ //===== internal ========================================================
+
+ /** Create a new accessible object that makes the given shape accessible.
+ @param rxParent
+ The accessible parent object. It will be used, for example when
+ the <member>getIndexInParent</member> method is called.
+ @param rShapeTreeInfo
+ Bundle of information passed to this shape and all of its descendants.
+ @attention
+ Always call the <member>init</member> method after creating a
+ new accessible shape. This is one way to overcome the potential
+ problem of registering the new object with e.g. event
+ broadcasters. That would delete the new object if a broadcaster
+ would not keep a strong reference to the new object.
+ */
+ AccessiblePageShape (
+ const css::uno::Reference<css::drawing::XDrawPage>& rxPage,
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo);
+
+ virtual ~AccessiblePageShape() override;
+
+ //===== XAccessibleContext ==============================================
+
+ /// Returns always 0 because there can be no children.
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ /** Return the specified child.
+ @param nIndex
+ Index of the requested child.
+ @return
+ Reference of the requested child which is the accessible object
+ of a visible shape.
+ @throws IndexOutOfBoundsException
+ Throws always an exception because there are no children.
+ */
+ virtual css::uno::Reference<css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild (sal_Int32 nIndex) override;
+
+ //===== XAccessibleComponent ============================================
+
+ virtual css::awt::Rectangle SAL_CALL getBounds() override;
+
+ virtual sal_Int32 SAL_CALL getForeground() override;
+
+ virtual sal_Int32 SAL_CALL getBackground() override;
+
+ //===== XComponent ======================================================
+
+ virtual void SAL_CALL
+ dispose() override;
+
+ //===== XServiceInfo ====================================================
+
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+ using AccessibleShape::disposing;
+
+protected:
+ /** Create a base name string that contains the accessible name.
+ */
+ virtual OUString
+ CreateAccessibleBaseName() override;
+
+ virtual OUString
+ CreateAccessibleName() override;
+
+private:
+ css::uno::Reference<css::drawing::XDrawPage> mxPage;
+
+ AccessiblePageShape (const AccessiblePageShape&) = delete;
+ AccessibleShape& operator= (const AccessiblePageShape&) = delete;
+};
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessiblePresentationGraphicShape.hxx b/sd/source/ui/inc/AccessiblePresentationGraphicShape.hxx
new file mode 100644
index 000000000..91e573835
--- /dev/null
+++ b/sd/source/ui/inc/AccessiblePresentationGraphicShape.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/AccessibleGraphicShape.hxx>
+
+namespace accessibility { class AccessibleShapeInfo; }
+namespace accessibility { class AccessibleShapeTreeInfo; }
+
+namespace accessibility {
+
+/** This class makes Impress shapes accessible.
+*/
+class AccessiblePresentationGraphicShape
+ : public AccessibleGraphicShape
+{
+public:
+ //===== internal ========================================================
+ AccessiblePresentationGraphicShape (
+ const AccessibleShapeInfo& rShapeInfo,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo);
+ virtual ~AccessiblePresentationGraphicShape() override;
+
+ //===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ //===== internal ========================================================
+
+ /// Create a name string that contains the accessible name.
+ virtual OUString
+ CreateAccessibleBaseName () override;
+
+ /// Return this object's role.
+ virtual sal_Int16 SAL_CALL getAccessibleRole () override;
+};
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessiblePresentationOLEShape.hxx b/sd/source/ui/inc/AccessiblePresentationOLEShape.hxx
new file mode 100644
index 000000000..a8ac60deb
--- /dev/null
+++ b/sd/source/ui/inc/AccessiblePresentationOLEShape.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/AccessibleOLEShape.hxx>
+
+namespace accessibility {
+
+/** This class makes Impress shapes accessible.
+*/
+class AccessiblePresentationOLEShape
+ : public AccessibleOLEShape
+{
+public:
+ //===== internal ========================================================
+ AccessiblePresentationOLEShape (
+ const AccessibleShapeInfo& rShapeInfo,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo);
+ virtual ~AccessiblePresentationOLEShape() override;
+
+ //===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ //===== internal ========================================================
+
+ /// Create a name string that contains the accessible name.
+ virtual OUString
+ CreateAccessibleBaseName () override;
+
+ /// Return this object's role.
+ virtual sal_Int16 SAL_CALL getAccessibleRole () override;
+};
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessiblePresentationShape.hxx b/sd/source/ui/inc/AccessiblePresentationShape.hxx
new file mode 100644
index 000000000..4a6447ae9
--- /dev/null
+++ b/sd/source/ui/inc/AccessiblePresentationShape.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/AccessibleShape.hxx>
+
+namespace accessibility {
+
+/** This class makes Impress shapes accessible.
+*/
+class AccessiblePresentationShape
+ : public AccessibleShape
+{
+public:
+ //===== internal ========================================================
+ AccessiblePresentationShape (
+ const AccessibleShapeInfo& rShapeInfo,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo);
+ virtual ~AccessiblePresentationShape() override;
+
+ //===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ //===== internal ========================================================
+
+ /// Create a name string that contains the accessible name.
+ virtual OUString
+ CreateAccessibleBaseName () override;
+
+ OUString GetStyle() const override;
+
+private:
+ AccessiblePresentationShape (const AccessiblePresentationShape&) = delete;
+
+ AccessiblePresentationShape& operator= (const AccessiblePresentationShape&) = delete;
+};
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessibleSlideSorterObject.hxx b/sd/source/ui/inc/AccessibleSlideSorterObject.hxx
new file mode 100644
index 000000000..6da56a152
--- /dev/null
+++ b/sd/source/ui/inc/AccessibleSlideSorterObject.hxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <comphelper/compbase.hxx>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+class SdPage;
+namespace sd::slidesorter { class SlideSorter; }
+
+namespace accessibility {
+
+typedef comphelper::WeakComponentImplHelper<
+ css::accessibility::XAccessible,
+ css::accessibility::XAccessibleEventBroadcaster,
+ css::accessibility::XAccessibleContext,
+ css::accessibility::XAccessibleComponent,
+ css::lang::XServiceInfo > AccessibleSlideSorterObjectBase;
+
+/** This class makes page objects of the slide sorter accessible.
+*/
+class AccessibleSlideSorterObject
+ : public AccessibleSlideSorterObjectBase
+{
+public:
+ /** Create a new object that represents a page object in the slide
+ sorter.
+ @param rxParent
+ The accessible parent.
+ @param rSlideSorter
+ The slide sorter whose model manages the page.
+ @param nPageNumber
+ The number of the page in the range [0,nPageCount).
+ */
+ AccessibleSlideSorterObject(
+ const css::uno::Reference<css::accessibility::XAccessible >& rxParent,
+ ::sd::slidesorter::SlideSorter& rSlideSorter,
+ sal_uInt16 nPageNumber);
+ virtual ~AccessibleSlideSorterObject() override;
+
+ /** Return the page that is made accessible by the called object.
+ */
+ SdPage* GetPage() const;
+
+ /** The page number as given to the constructor.
+ */
+ sal_uInt16 GetPageNumber() const { return mnPageNumber;}
+
+ void FireAccessibleEvent (
+ short nEventId,
+ const css::uno::Any& rOldValue,
+ const css::uno::Any& rNewValue);
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ //===== XAccessible =======================================================
+
+ virtual css::uno::Reference<css::accessibility::XAccessibleContext > SAL_CALL
+ getAccessibleContext() override;
+
+ //===== XAccessibleEventBroadcaster =======================================
+ virtual void SAL_CALL
+ addAccessibleEventListener(
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener >& rxListener) override;
+
+ virtual void SAL_CALL
+ removeAccessibleEventListener(
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener >& rxListener ) override;
+
+ //===== XAccessibleContext ==============================================
+
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild (sal_Int32 nIndex) override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleParent() override;
+
+ virtual sal_Int32 SAL_CALL
+ getAccessibleIndexInParent() override;
+
+ virtual sal_Int16 SAL_CALL
+ getAccessibleRole() override;
+
+ virtual OUString SAL_CALL
+ getAccessibleDescription() override;
+
+ virtual OUString SAL_CALL
+ getAccessibleName() override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet> SAL_CALL
+ getAccessibleRelationSet() override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet> SAL_CALL
+ getAccessibleStateSet() override;
+
+ virtual css::lang::Locale SAL_CALL
+ getLocale() override;
+
+ //===== XAccessibleComponent ================================================
+
+ virtual sal_Bool SAL_CALL containsPoint (
+ const css::awt::Point& aPoint) override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleAtPoint (
+ const css::awt::Point& aPoint) override;
+
+ virtual css::awt::Rectangle SAL_CALL getBounds() override;
+
+ virtual css::awt::Point SAL_CALL getLocation() override;
+
+ virtual css::awt::Point SAL_CALL getLocationOnScreen() override;
+
+ virtual css::awt::Size SAL_CALL getSize() override;
+
+ virtual void SAL_CALL grabFocus() override;
+
+ virtual sal_Int32 SAL_CALL getForeground() override;
+
+ virtual sal_Int32 SAL_CALL getBackground() override;
+
+ //===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ /** Return whether the specified service is supported by this class.
+ */
+ virtual sal_Bool SAL_CALL
+ supportsService (const OUString& sServiceName) override;
+
+ /** Returns a list of all supported services.
+ */
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+private:
+ css::uno::Reference<css::accessibility::XAccessible> mxParent;
+ sal_uInt16 mnPageNumber;
+ ::sd::slidesorter::SlideSorter& mrSlideSorter;
+ sal_uInt32 mnClientId;
+
+ /** Check whether or not the object has been disposed (or is in the
+ state of being disposed). If that is the case then
+ DisposedException is thrown to inform the (indirect) caller of the
+ foul deed.
+
+ @throws css::lang::DisposedException
+ */
+ void ThrowIfDisposed();
+
+ /** Check whether or not the object has been disposed (or is in the
+ state of being disposed).
+
+ @return sal_True, if the object is disposed or in the course
+ of being disposed. Otherwise, sal_False is returned.
+ */
+ bool IsDisposed() const;
+};
+
+} // end of namespace ::accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessibleSlideSorterView.hxx b/sd/source/ui/inc/AccessibleSlideSorterView.hxx
new file mode 100644
index 000000000..85003b72d
--- /dev/null
+++ b/sd/source/ui/inc/AccessibleSlideSorterView.hxx
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <vcl/vclptr.hxx>
+#include <vcl/window.hxx>
+
+#include <memory>
+
+namespace sd::slidesorter { class SlideSorter; }
+
+namespace accessibility {
+
+class AccessibleSlideSorterObject;
+
+typedef ::cppu::WeakComponentImplHelper<
+ css::accessibility::XAccessible,
+ css::accessibility::XAccessibleEventBroadcaster,
+ css::accessibility::XAccessibleContext,
+ css::accessibility::XAccessibleComponent,
+ css::accessibility::XAccessibleSelection,
+ css::lang::XServiceInfo
+ > AccessibleSlideSorterViewBase;
+
+/** This class makes the SlideSorterViewShell accessible. It uses objects
+ of the AccessibleSlideSorterObject class to the make the page objects
+ accessible.
+*/
+class AccessibleSlideSorterView
+ : public cppu::BaseMutex,
+ public AccessibleSlideSorterViewBase
+{
+public:
+ AccessibleSlideSorterView(
+ ::sd::slidesorter::SlideSorter& rSlideSorter,
+ vcl::Window* pParentWindow);
+
+ void Init();
+
+ virtual ~AccessibleSlideSorterView() override;
+
+ /** This method acts like a dispose call. It sends a disposing to all
+ of its listeners. It may be called twice.
+ */
+ void Destroyed();
+
+ void FireAccessibleEvent (
+ short nEventId,
+ const css::uno::Any& rOldValue,
+ const css::uno::Any& rNewValue);
+
+ virtual void SAL_CALL disposing() override;
+
+ /** Return the implementation object of the specified child.
+ @param nIndex
+ Index of the child for which to return the implementation object.
+ */
+ AccessibleSlideSorterObject* GetAccessibleChildImplementation (sal_Int32 nIndex);
+
+ //===== XAccessible =======================================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL
+ getAccessibleContext() override;
+
+ //===== XAccessibleEventBroadcaster =======================================
+ virtual void SAL_CALL
+ addAccessibleEventListener(
+ const css::uno::Reference< css::accessibility::XAccessibleEventListener >& rxListener) override;
+
+ virtual void SAL_CALL
+ removeAccessibleEventListener(
+ const css::uno::Reference< css::accessibility::XAccessibleEventListener >& rxListener ) override;
+
+ //===== XAccessibleContext ==============================================
+
+ /// Return the number of currently visible children.
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ /// Return the specified child or throw exception.
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild (sal_Int32 nIndex) override;
+
+ /// Return a reference to the parent.
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleParent() override;
+
+ /// Return this objects index among the parents children.
+ virtual sal_Int32 SAL_CALL
+ getAccessibleIndexInParent() override;
+
+ /// Return this object's role.
+ virtual sal_Int16 SAL_CALL
+ getAccessibleRole() override;
+
+ /// Return this object's description.
+ virtual OUString SAL_CALL
+ getAccessibleDescription() override;
+
+ /// Return the object's current name.
+ virtual OUString SAL_CALL
+ getAccessibleName() override;
+
+ /// Return NULL to indicate that an empty relation set.
+ virtual css::uno::Reference<
+ css::accessibility::XAccessibleRelationSet> SAL_CALL
+ getAccessibleRelationSet() override;
+
+ /// Return the set of current states.
+ virtual css::uno::Reference<
+ css::accessibility::XAccessibleStateSet> SAL_CALL
+ getAccessibleStateSet() override;
+
+ /** Return the parents locale or throw exception if this object has no
+ parent yet/anymore.
+ */
+ virtual css::lang::Locale SAL_CALL
+ getLocale() override;
+
+ //===== XAccessibleComponent ================================================
+
+ /** The default implementation uses the result of
+ <member>getBounds</member> to determine whether the given point lies
+ inside this object.
+ */
+ virtual sal_Bool SAL_CALL containsPoint (
+ const css::awt::Point& aPoint) override;
+
+ /** The default implementation returns an empty reference.
+ */
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleAtPoint (
+ const css::awt::Point& aPoint) override;
+
+ /** The default implementation returns an empty rectangle.
+ */
+ virtual css::awt::Rectangle SAL_CALL getBounds() override;
+
+ /** The default implementation uses the result of
+ <member>getBounds</member> to determine the location.
+ */
+ virtual css::awt::Point SAL_CALL getLocation() override;
+
+ /** The default implementation returns an empty position, i.e. the
+ * result of the default constructor of <type>css::awt::Point</type>.
+ */
+ virtual css::awt::Point SAL_CALL getLocationOnScreen() override;
+
+ /** The default implementation uses the result of
+ <member>getBounds</member> to determine the size.
+ */
+ virtual css::awt::Size SAL_CALL getSize() override;
+
+ /** The default implementation does nothing.
+ */
+ virtual void SAL_CALL grabFocus() override;
+
+ /** Returns black as the default foreground color.
+ */
+ virtual sal_Int32 SAL_CALL getForeground() override;
+
+ /** Returns white as the default background color.
+ */
+ virtual sal_Int32 SAL_CALL getBackground() override;
+
+ //===== XAccessibleSelection ==============================================
+
+ virtual void SAL_CALL
+ selectAccessibleChild (sal_Int32 nChildIndex) override;
+
+ virtual sal_Bool SAL_CALL
+ isAccessibleChildSelected( sal_Int32 nChildIndex ) override;
+
+ virtual void SAL_CALL
+ clearAccessibleSelection( ) override;
+
+ virtual void SAL_CALL
+ selectAllAccessibleChildren( ) override;
+
+ virtual sal_Int32 SAL_CALL
+ getSelectedAccessibleChildCount( ) override;
+
+ virtual css::uno::Reference<
+ css::accessibility::XAccessible > SAL_CALL
+ getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) override;
+
+ virtual void SAL_CALL
+ deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) override;
+
+ //===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ /** Return whether the specified service is supported by this class.
+ */
+ virtual sal_Bool SAL_CALL
+ supportsService (const OUString& sServiceName) override;
+
+ /** Returns a list of all supported services.
+ */
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+ void SwitchViewActivated();
+private:
+ class Implementation;
+ ::std::unique_ptr<Implementation> mpImpl;
+
+ ::sd::slidesorter::SlideSorter& mrSlideSorter;
+
+ sal_uInt32 mnClientId;
+
+ VclPtr<vcl::Window> mpContentWindow;
+
+ /** Check whether or not the object has been disposed (or is in the
+ state of being disposed). If that is the case then
+ DisposedException is thrown to inform the (indirect) caller of the
+ foul deed.
+
+ @throws css::lang::DisposedException
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AccessibleViewForwarder.hxx b/sd/source/ui/inc/AccessibleViewForwarder.hxx
new file mode 100644
index 000000000..c791921e6
--- /dev/null
+++ b/sd/source/ui/inc/AccessibleViewForwarder.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/IAccessibleViewForwarder.hxx>
+
+class SdrPaintView;
+class OutputDevice;
+
+namespace accessibility
+{
+/** <p>This class provides the means to transform between internal coordinates
+ and screen coordinates without giving direct access to the underlying
+ view. It represents a certain window. A call to
+ <method>GetVisArea</method> returns the corresponding visible
+ rectangle.</p>
+
+ @attention
+ Note, that modifications of the underlying view that lead to
+ different transformations between internal and screen coordinates or
+ change the validity of the forwarder have to be signaled separately.
+*/
+class AccessibleViewForwarder final : public IAccessibleViewForwarder
+{
+public:
+ //===== internal ========================================================
+
+ AccessibleViewForwarder(SdrPaintView* pView, const OutputDevice& rDevice);
+
+ virtual ~AccessibleViewForwarder() override;
+
+ //===== IAccessibleViewforwarder ========================================
+
+ /** Returns the area of the underlying document that is visible in the
+ * corresponding window.
+
+ @return
+ The rectangle of the visible part of the document.
+ */
+ virtual ::tools::Rectangle GetVisibleArea() const override;
+
+ /** Transform the specified point from internal coordinates to an
+ absolute screen position.
+
+ @param rPoint
+ Point in internal coordinates.
+
+ @return
+ The same point but in screen coordinates relative to the upper
+ left corner of the (current) screen.
+ */
+ virtual Point LogicToPixel(const Point& rPoint) const override;
+
+ /** Transform the specified size from internal coordinates to a screen
+ * position.
+
+ @param rSize
+ Size in internal coordinates.
+
+ @return
+ The same size but in screen coordinates.
+ */
+ virtual Size LogicToPixel(const Size& rSize) const override;
+
+private:
+ SdrPaintView* mpView;
+ sal_uInt16 mnWindowId;
+
+ AccessibleViewForwarder(AccessibleViewForwarder const&) = delete;
+ AccessibleViewForwarder& operator=(AccessibleViewForwarder const&) = delete;
+};
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/AnimationChildWindow.hxx b/sd/source/ui/inc/AnimationChildWindow.hxx
new file mode 100644
index 000000000..1223dfdbd
--- /dev/null
+++ b/sd/source/ui/inc/AnimationChildWindow.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/childwin.hxx>
+#include <sal/types.h>
+
+namespace vcl { class Window; }
+class SfxBindings;
+
+namespace sd {
+
+class AnimationChildWindow
+ : public SfxChildWindow
+{
+public:
+ AnimationChildWindow(
+ vcl::Window*,
+ sal_uInt16,
+ SfxBindings*,
+ SfxChildWinInfo*);
+
+ SFX_DECL_CHILDWINDOW_WITHID(AnimationChildWindow);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/BezierObjectBar.hxx b/sd/source/ui/inc/BezierObjectBar.hxx
new file mode 100644
index 000000000..a030576eb
--- /dev/null
+++ b/sd/source/ui/inc/BezierObjectBar.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/shell.hxx>
+#include <glob.hxx>
+
+namespace sd
+{
+class View;
+class ViewShell;
+
+class BezierObjectBar final : public SfxShell
+{
+public:
+ SFX_DECL_INTERFACE(SD_IF_SDDRAWBEZIEROBJECTBAR)
+
+ BezierObjectBar(ViewShell* pSdViewShell, View* pSdView);
+ virtual ~BezierObjectBar() override;
+
+ void GetAttrState(SfxItemSet& rSet);
+ void Execute(SfxRequest& rReq);
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+ View* mpView;
+ ViewShell* mpViewSh;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/BreakDlg.hxx b/sd/source/ui/inc/BreakDlg.hxx
new file mode 100644
index 000000000..ee2a8b15d
--- /dev/null
+++ b/sd/source/ui/inc/BreakDlg.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/progress.hxx>
+#include <svx/svdetc.hxx>
+#include <vcl/idle.hxx>
+
+namespace sd
+{
+class DrawDocShell;
+class DrawView;
+
+/**
+ * dialog to break meta files
+ */
+class BreakDlg : public SfxDialogController
+{
+public:
+ BreakDlg(weld::Window* pWindow, DrawView* pDrView, DrawDocShell* pShell,
+ sal_uLong nSumActionCount, sal_uLong nObjCount);
+
+ virtual short run() override;
+
+private:
+ std::unique_ptr<weld::Label> m_xFiObjInfo;
+ std::unique_ptr<weld::Label> m_xFiActInfo;
+ std::unique_ptr<weld::Label> m_xFiInsInfo;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ DrawView* m_pDrView;
+
+ bool m_bCancel;
+
+ Idle m_aUpdateIdle;
+ std::unique_ptr<SvdProgressInfo> m_xProgrInfo;
+ std::unique_ptr<SfxProgress> m_xProgress;
+
+ DECL_LINK(CancelButtonHdl, weld::Button&, void);
+ DECL_LINK(UpDate, void*, bool);
+ DECL_LINK(InitialUpdate, Timer*, void);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/BulletAndPositionDlg.hxx b/sd/source/ui/inc/BulletAndPositionDlg.hxx
new file mode 100644
index 000000000..6dde73753
--- /dev/null
+++ b/sd/source/ui/inc/BulletAndPositionDlg.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <vector>
+#include <memory>
+
+#include <editeng/numdef.hxx>
+#include <editeng/svxenum.hxx>
+#include <vcl/weld.hxx>
+#include "View.hxx"
+#include <cui/numberingpreview.hxx>
+
+#define MN_GALLERY_ENTRY 100
+
+class ColorListBox;
+class SvxNumValueSet;
+class SvxNumRule;
+class SvxBmpNumValueSet;
+class SvxBrushItem;
+class SdDrawDocument;
+
+namespace sd
+{
+class View;
+}
+
+/// Main class for handling the bullets, numbering format and their position.
+class SvxBulletAndPositionDlg : public weld::GenericDialogController
+{
+ OUString m_sNumCharFmtName;
+
+ Timer aInvalidateTimer;
+
+ std::unique_ptr<SvxNumRule> pActNum;
+ std::unique_ptr<SvxNumRule> pSaveNum;
+ const SfxItemSet& rFirstStateSet;
+
+ Size aInitSize[SVX_MAX_NUM];
+
+ bool bLastWidthModified : 1;
+ bool bModified : 1;
+ bool bInInitControl : 1; // workaround for Modify-error, is said to be corrected from 391 on
+ bool bLabelAlignmentPosAndSpaceModeActive;
+ bool bApplyToMaster;
+
+ std::vector<OUString> aGrfNames;
+ vcl::Font aActBulletFont;
+
+ sal_uInt8 nBullet;
+ sal_uInt16 nActNumLvl;
+ weld::Window* p_Window;
+ TypedWhichId<SvxNumBulletItem> nNumItemId;
+ MapUnit eCoreUnit;
+
+ SvxNumberingPreview m_aPreviewWIN;
+ std::unique_ptr<weld::Widget> m_xGrid;
+ std::unique_ptr<weld::TreeView> m_xLevelLB;
+ std::unique_ptr<weld::ComboBox> m_xFmtLB;
+ std::unique_ptr<weld::Label> m_xPrefixFT;
+ std::unique_ptr<weld::Entry> m_xPrefixED;
+ std::unique_ptr<weld::Label> m_xSuffixFT;
+ std::unique_ptr<weld::Entry> m_xSuffixED;
+ std::unique_ptr<weld::Frame> m_xBeforeAfter;
+ std::unique_ptr<weld::Label> m_xBulColorFT;
+ std::unique_ptr<ColorListBox> m_xBulColLB;
+ std::unique_ptr<weld::Label> m_xBulRelSizeFT;
+ std::unique_ptr<weld::MetricSpinButton> m_xBulRelSizeMF;
+ std::unique_ptr<weld::Label> m_xStartFT;
+ std::unique_ptr<weld::SpinButton> m_xStartED;
+ std::unique_ptr<weld::Label> m_xBulletFT;
+ std::unique_ptr<weld::Button> m_xBulletPB;
+ std::unique_ptr<weld::MenuButton> m_xBitmapMB;
+ std::unique_ptr<weld::Label> m_xWidthFT;
+ std::unique_ptr<weld::MetricSpinButton> m_xWidthMF;
+ std::unique_ptr<weld::Label> m_xHeightFT;
+ std::unique_ptr<weld::MetricSpinButton> m_xHeightMF;
+ std::unique_ptr<weld::CheckButton> m_xRatioCB;
+ std::unique_ptr<weld::Menu> m_xGalleryMenu;
+ std::unique_ptr<weld::CustomWeld> m_xPreviewWIN;
+ std::unique_ptr<weld::Label> m_xDistBorderFT;
+ std::unique_ptr<weld::MetricSpinButton> m_xDistBorderMF;
+ std::unique_ptr<weld::CheckButton> m_xRelativeCB;
+ std::unique_ptr<weld::Label> m_xIndentFT;
+ std::unique_ptr<weld::MetricSpinButton> m_xIndentMF;
+ std::unique_ptr<weld::Toggleable> m_xLeftTB;
+ std::unique_ptr<weld::Toggleable> m_xCenterTB;
+ std::unique_ptr<weld::Toggleable> m_xRightTB;
+ std::unique_ptr<weld::RadioButton> m_xSlideRB;
+ std::unique_ptr<weld::RadioButton> m_xSelectionRB;
+ std::unique_ptr<weld::Toggleable> m_xApplyToMaster;
+ std::unique_ptr<weld::Button> m_xReset;
+
+ void InitControls();
+ /** To switch between the numbering type
+ 0 - Number;
+ 1 - Bullet;
+ 2 - Bitmap; */
+ void SwitchNumberType(sal_uInt8 nType);
+ void CheckForStartValue_Impl(sal_uInt16 nNumberingType);
+
+ DECL_LINK(NumberTypeSelectHdl_Impl, weld::ComboBox&, void);
+ DECL_LINK(LevelHdl_Impl, weld::TreeView&, void);
+ DECL_LINK(PopupActivateHdl_Impl, weld::Toggleable&, void);
+ DECL_LINK(GraphicHdl_Impl, const OString&, void);
+ DECL_LINK(BulletHdl_Impl, weld::Button&, void);
+ DECL_LINK(SizeHdl_Impl, weld::MetricSpinButton&, void);
+ DECL_LINK(RatioHdl_Impl, weld::Toggleable&, void);
+ DECL_LINK(EditModifyHdl_Impl, weld::Entry&, void);
+ DECL_LINK(SpinModifyHdl_Impl, weld::SpinButton&, void);
+ DECL_LINK(BulColorHdl_Impl, ColorListBox&, void);
+ DECL_LINK(BulRelSizeHdl_Impl, weld::MetricSpinButton&, void);
+ DECL_LINK(PreviewInvalidateHdl_Impl, Timer*, void);
+ DECL_LINK(DistanceHdl_Impl, weld::MetricSpinButton&, void);
+ DECL_LINK(RelativeHdl_Impl, weld::Toggleable&, void);
+ DECL_LINK(SelectLeftAlignmentHdl_Impl, weld::Toggleable&, void);
+ DECL_LINK(SelectCenterAlignmentHdl_Impl, weld::Toggleable&, void);
+ DECL_LINK(SelectRightAlignmentHdl_Impl, weld::Toggleable&, void);
+ DECL_LINK(ApplyToMasterHdl_Impl, weld::Toggleable&, void);
+ DECL_LINK(ResetHdl_Impl, weld::Button&, void);
+ void EditModifyHdl_Impl(const weld::Entry*);
+ void InitPosAndSpaceMode();
+ void SetAlignmentHdl_Impl(SvxAdjust);
+
+public:
+ SvxBulletAndPositionDlg(weld::Window* pWindow, const SfxItemSet& rSet, const ::sd::View* pView);
+ virtual ~SvxBulletAndPositionDlg() override;
+
+ SfxItemSet* GetOutputItemSet(SfxItemSet* rSet);
+ bool IsApplyToMaster() const;
+ bool IsSlideScope() const;
+ void Reset(const SfxItemSet* rSet);
+
+ void SetCharFmt(const OUString& rNumName) { m_sNumCharFmtName = rNumName; }
+ void SetMetric(FieldUnit eSet);
+
+ void SetModified(bool bRepaint = true);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/Client.hxx b/sd/source/ui/inc/Client.hxx
new file mode 100644
index 000000000..6b999068e
--- /dev/null
+++ b/sd/source/ui/inc/Client.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/ipclient.hxx>
+class SdrOle2Obj;
+
+namespace sd
+{
+class ViewShell;
+
+class Client : public SfxInPlaceClient
+{
+ ViewShell* mpViewShell;
+ SdrOle2Obj* pSdrOle2Obj;
+
+ virtual void ObjectAreaChanged() override;
+ virtual void RequestNewObjectArea(::tools::Rectangle&) override;
+ virtual void ViewChanged() override;
+
+public:
+ Client(SdrOle2Obj* pObj, ViewShell* pSdViewShell, vcl::Window* pWindow);
+ virtual ~Client() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ClientView.hxx b/sd/source/ui/inc/ClientView.hxx
new file mode 100644
index 000000000..7a52053ba
--- /dev/null
+++ b/sd/source/ui/inc/ClientView.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "drawview.hxx"
+
+namespace sd
+{
+/**
+ * The SdClientView is used for DrawDocShell::Draw()
+ */
+class ClientView : public DrawView
+{
+public:
+ ClientView(DrawDocShell* pDocSh, OutputDevice* pOutDev);
+ virtual ~ClientView() override;
+
+ /* if the view should not do an Invalidate() on the windows, you have to
+ override the following two methods and do something different */
+ virtual void InvalidateOneWin(OutputDevice& rWin) override;
+ virtual void InvalidateOneWin(OutputDevice& rWin, const ::tools::Rectangle& rRect) override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/CustomAnimationList.hxx b/sd/source/ui/inc/CustomAnimationList.hxx
new file mode 100644
index 000000000..ca9673fd7
--- /dev/null
+++ b/sd/source/ui/inc/CustomAnimationList.hxx
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <vcl/transfer.hxx>
+#include <vcl/weld.hxx>
+#include <CustomAnimationEffect.hxx>
+
+namespace com::sun::star::drawing { class XShape; }
+
+struct ImplSVEvent;
+
+namespace sd {
+
+typedef std::shared_ptr< CustomAnimationEffect > CustomAnimationEffectPtr;
+
+class ICustomAnimationListController
+{
+public:
+ virtual void onSelect() = 0;
+ virtual void onDoubleClick() = 0;
+ virtual void onContextMenu(const OString &rIdent) = 0;
+ virtual void onDragNDropComplete( std::vector< CustomAnimationEffectPtr > pEffectsDragged, CustomAnimationEffectPtr pEffectInsertBefore ) = 0;
+ virtual ~ICustomAnimationListController() {}
+};
+
+class CustomAnimationList;
+class CustomAnimationListEntryItem;
+
+class CustomAnimationListDropTarget : public DropTargetHelper
+{
+private:
+ CustomAnimationList& m_rTreeView;
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+public:
+ CustomAnimationListDropTarget(CustomAnimationList& rTreeView);
+};
+
+class CustomAnimationList : public ISequenceListener
+{
+ friend class CustomAnimationListEntryItem;
+ friend struct stl_append_effect_func;
+
+public:
+ explicit CustomAnimationList(std::unique_ptr<weld::TreeView> xTreeView,
+ std::unique_ptr<weld::Label> xLabel,
+ std::unique_ptr<weld::Widget> xScrolledWindow);
+ virtual ~CustomAnimationList();
+
+ // methods
+
+ /** selects or deselects the given effect.
+ Selections of other effects are not changed */
+ void select( const CustomAnimationEffectPtr& pEffect );
+
+ /** populates the list with all effects from the given MainSequence */
+ void update( const MainSequencePtr& pMainSequence );
+
+ void update();
+
+ EffectSequence getSelection() const;
+
+ // events
+ void onSelectionChanged(const css::uno::Any& rSelection);
+
+ void Select();
+
+ virtual void notify_change() override;
+
+ bool isExpanded( const CustomAnimationEffectPtr& pEffect ) const;
+ bool isVisible( const CustomAnimationEffectPtr& pEffect ) const;
+
+ // clears all entries from the listbox
+ void clear();
+
+ void setController( ICustomAnimationListController* pController )
+ {
+ mpController = pController;
+ };
+
+ sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt);
+ sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt);
+
+ void set_sensitive(bool bSensitive) { mxTreeView->set_sensitive(bSensitive); }
+ int get_height_rows(int nRows) { return mxTreeView->get_height_rows(nRows); }
+ int get_approximate_digit_width() const { return mxTreeView->get_approximate_digit_width(); }
+ void set_size_request(int nWidth, int nHeight)
+ {
+ mxTreeView->set_size_request(nWidth, nHeight);
+ mxEmptyLabel->set_size_request(nWidth, nHeight);
+ }
+ void unselect_all() { mxTreeView->unselect_all(); }
+ weld::TreeView& get_widget() { return *mxTreeView; }
+
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ExpandHdl, const weld::TreeIter&, bool);
+ DECL_LINK(PostExpandHdl, void*, void);
+ DECL_LINK(CollapseHdl, const weld::TreeIter&, bool);
+ DECL_LINK(PostCollapseHdl, void*, void);
+
+private:
+ std::unique_ptr<weld::TreeView> mxTreeView;
+ CustomAnimationListDropTarget maDropTargetHelper;
+ std::unique_ptr<weld::Label> mxEmptyLabel;
+ std::unique_ptr<weld::Widget> mxEmptyLabelParent;
+ std::vector<std::unique_ptr<CustomAnimationListEntryItem>> mxEntries;
+ std::vector<std::unique_ptr<weld::TreeIter>> lastSelectedEntries;
+
+ bool mbIgnorePaint;
+
+ DECL_LINK(SelectHdl, weld::TreeView&, void);
+ DECL_LINK(CommandHdl, const CommandEvent&, bool);
+ DECL_LINK(DoubleClickHdl, weld::TreeView&, bool);
+ DECL_LINK(DragBeginHdl, bool&, bool);
+ DECL_STATIC_LINK(CustomAnimationList, CustomRenderHdl, weld::TreeView::render_args, void);
+ DECL_STATIC_LINK(CustomAnimationList, CustomGetSizeHdl, weld::TreeView::get_size_args, Size);
+
+ void ExecuteContextMenuAction(const OString& rSelectedPopupEntry);
+
+ /** appends the given effect to the list*/
+ void append( CustomAnimationEffectPtr pEffect );
+
+ ICustomAnimationListController* mpController;
+
+ MainSequencePtr mpMainSequence;
+
+ css::uno::Reference< css::drawing::XShape > mxLastTargetShape;
+ sal_Int32 mnLastGroupId;
+ ImplSVEvent* mnPostExpandEvent;
+ ImplSVEvent* mnPostCollapseEvent;
+
+ std::unique_ptr<weld::TreeIter> mxLastParentEntry;
+
+ // drag & drop
+ std::unique_ptr<weld::TreeIter> mxDndEffectDragging;
+ std::vector<std::unique_ptr<weld::TreeIter>> mDndEffectsSelected;
+};
+
+OUString getPropertyName( sal_Int32 nPropertyType );
+
+OUString getShapeDescription( const css::uno::Reference< css::drawing::XShape >& xShape, bool bWithText );
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/CustomAnimationPane.hxx b/sd/source/ui/inc/CustomAnimationPane.hxx
new file mode 100644
index 000000000..5e2d69658
--- /dev/null
+++ b/sd/source/ui/inc/CustomAnimationPane.hxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/sidebar/ILayoutableWindow.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <vcl/idle.hxx>
+#include "CustomAnimationList.hxx"
+#include <misc/scopelock.hxx>
+
+#include <vector>
+
+namespace com::sun::star::drawing { class XDrawPage; }
+namespace com::sun::star::drawing { class XDrawView; }
+namespace weld { class ComboBox; }
+namespace com::sun::star::animations { class XAnimationNode; }
+namespace sd::tools { class EventMultiplexerEvent; }
+
+enum class PathKind { NONE, CURVE, POLYGON, FREEFORM };
+
+namespace sd {
+
+class MotionPathTag;
+class SdPropertySubControl;
+class STLPropertySet;
+class ViewShellBase;
+
+typedef std::vector< rtl::Reference< MotionPathTag > > MotionPathTagVector;
+
+class CustomAnimationPane : public PanelLayout
+ , public sfx2::sidebar::ILayoutableWindow
+ , public ICustomAnimationListController
+{
+ friend class MotionPathTag;
+public:
+ CustomAnimationPane(weld::Widget* pParent, ViewShellBase& rBase);
+ virtual ~CustomAnimationPane() override;
+
+ // ILayoutableWindow
+ virtual css::ui::LayoutSize GetHeightForWidth (const sal_Int32 nWidth) override;
+
+ // callbacks
+ void onSelectionChanged();
+ void onChangeCurrentPage();
+ void onAdd();
+ void onRemove();
+ void onChangeStart();
+ void onChangeStart( sal_Int16 nNodeType );
+ void onChangeSpeed();
+
+ // methods
+ void preview( const css::uno::Reference< css::animations::XAnimationNode >& xAnimationNode );
+ void remove( CustomAnimationEffectPtr const & pEffect );
+
+ // ICustomAnimationListController
+ virtual void onSelect() override;
+ virtual void onDoubleClick() override;
+ virtual void onContextMenu(const OString& rIdent) override;
+ virtual void onDragNDropComplete( std::vector< CustomAnimationEffectPtr > pEffectsDragged, CustomAnimationEffectPtr pEffectInsertBefore ) override;
+
+ void addUndo();
+
+ double getDuration() const;
+ void updatePathFromMotionPathTag( const rtl::Reference< MotionPathTag >& xTag );
+
+private:
+ void initialize();
+ void addListener();
+ void removeListener();
+ void updateControls();
+ void updateMotionPathTags();
+
+ void showOptions(const OString& sPage = OString());
+ void moveSelection( bool bUp );
+ void onPreview( bool bForcePreview );
+
+ std::unique_ptr<STLPropertySet> createSelectionSet();
+ void changeSelection( STLPropertySet const * pResultSet, STLPropertySet const * pOldSet );
+
+ static css::uno::Any getProperty1Value( sal_Int32 nType, const CustomAnimationEffectPtr& pEffect );
+ static bool setProperty1Value( sal_Int32 nType, const CustomAnimationEffectPtr& pEffect, const css::uno::Any& rValue );
+ sal_Int32 fillAnimationLB( bool bHasText );
+ PathKind getCreatePathKind() const;
+ void createPath( PathKind eKind, std::vector< ::com::sun::star::uno::Any >& rTargets, double fDuration );
+
+ DECL_LINK( implControlListBoxHdl, weld::ComboBox&, void );
+ DECL_LINK( implClickHdl, weld::Button&, void );
+ DECL_LINK( implToggleHdl, weld::Toggleable&, void );
+ DECL_LINK( implPropertyHdl, LinkParamNone*, void );
+ DECL_LINK( EventMultiplexerListener, tools::EventMultiplexerEvent&, void );
+ DECL_LINK( lateInitCallback, Timer *, void );
+ DECL_LINK( DurationModifiedHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( DelayModifiedHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( DelayLoseFocusHdl, weld::Widget&, void );
+ DECL_LINK( UpdateAnimationLB, weld::ComboBox&, void );
+ DECL_LINK( AnimationSelectHdl, weld::TreeView&, void );
+ DECL_LINK( SelectionHandler, Timer*, void );
+ void implControlHdl(const weld::Widget* pControl);
+
+private:
+ ViewShellBase& mrBase;
+
+ // UI Elements
+ std::unique_ptr<weld::Label> mxFTAnimation;
+ std::unique_ptr<CustomAnimationList> mxCustomAnimationList;
+ std::unique_ptr<weld::Button> mxPBAddEffect;
+ std::unique_ptr<weld::Button> mxPBRemoveEffect;
+ std::unique_ptr<weld::Button> mxPBMoveUp;
+ std::unique_ptr<weld::Button> mxPBMoveDown;
+ std::unique_ptr<weld::Label> mxFTCategory;
+ std::unique_ptr<weld::ComboBox> mxLBCategory;
+ std::unique_ptr<weld::Label> mxFTEffect;
+ std::unique_ptr<weld::TreeView> mxLBAnimation;
+ std::unique_ptr<weld::Label> mxFTStart;
+ std::unique_ptr<weld::ComboBox> mxLBStart;
+ std::unique_ptr<weld::Label> mxFTProperty;
+ std::unique_ptr<SdPropertySubControl> mxLBSubControl;
+ std::unique_ptr<weld::Container> mxPlaceholderBox;
+ std::unique_ptr<weld::Button> mxPBPropertyMore;
+ std::unique_ptr<weld::Label> mxFTDuration;
+ std::unique_ptr<weld::MetricSpinButton> mxCBXDuration;
+ std::unique_ptr<weld::Label> mxFTStartDelay;
+ std::unique_ptr<weld::MetricSpinButton> mxMFStartDelay;
+ std::unique_ptr<weld::CheckButton> mxCBAutoPreview;
+ std::unique_ptr<weld::Button> mxPBPlay;
+
+ Idle maIdle;
+
+ OUString maStrModify;
+ OUString maStrProperty;
+
+ sal_Int32 mnLastSelectedAnimation;
+ sal_Int32 mnPropertyType;
+ static sal_Int32 const gnMotionPathPos = 3;
+ sal_Int32 mnCurvePathPos;
+ sal_Int32 mnPolygonPathPos;
+ sal_Int32 mnFreeformPathPos;
+
+ EffectSequence maListSelection;
+ css::uno::Any maViewSelection;
+
+ MainSequencePtr mpMainSequence;
+
+ css::uno::Reference< css::drawing::XDrawPage > mxCurrentPage;
+ css::uno::Reference< css::drawing::XDrawView > mxView;
+
+ /** The CustomAnimationPresets is initialized either on demand or
+ after a short time after the construction of a new object of this
+ class. This timer is responsible for the later.
+ */
+ Timer maLateInitTimer;
+
+ MotionPathTagVector maMotionPathTags;
+
+ ScopeLock maSelectionLock;
+};
+
+void fillRepeatComboBox(weld::ComboBox& rBox);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/DocumentRenderer.hxx b/sd/source/ui/inc/DocumentRenderer.hxx
new file mode 100644
index 000000000..7cbeefc79
--- /dev/null
+++ b/sd/source/ui/inc/DocumentRenderer.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/view/XRenderable.hpp>
+#include <comphelper/compbase.hxx>
+#include <memory>
+
+namespace sd { class ViewShellBase; }
+
+namespace sd {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::view::XRenderable
+ > DocumentRendererInterfaceBase;
+
+class DocumentRenderer final
+ : public DocumentRendererInterfaceBase
+{
+public:
+ DocumentRenderer (ViewShellBase& rBase);
+ virtual ~DocumentRenderer() override;
+
+ // XRenderable
+ virtual sal_Int32 SAL_CALL getRendererCount (
+ const css::uno::Any& aSelection,
+ const css::uno::Sequence<css::beans::PropertyValue >& xOptions) override;
+
+ virtual css::uno::Sequence<css::beans::PropertyValue> SAL_CALL getRenderer (
+ sal_Int32 nRenderer,
+ const css::uno::Any& rSelection,
+ const css::uno::Sequence<css::beans::PropertyValue>& rxOptions) override;
+
+ virtual void SAL_CALL render (
+ sal_Int32 nRenderer,
+ const css::uno::Any& rSelection,
+ const css::uno::Sequence<css::beans::PropertyValue>& rxOptions) override;
+
+private:
+ class Implementation;
+ std::unique_ptr<Implementation> mpImpl;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/DrawController.hxx b/sd/source/ui/inc/DrawController.hxx
new file mode 100644
index 000000000..2c15e26eb
--- /dev/null
+++ b/sd/source/ui/inc/DrawController.hxx
@@ -0,0 +1,327 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/propshlp.hxx>
+#include <sfx2/sfxbasecontroller.hxx>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/view/XFormLayerAccess.hpp>
+#include <com/sun/star/drawing/XDrawView.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <unotools/weakref.hxx>
+#include <tools/gen.hxx>
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::drawing { class XDrawSubController; }
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XModuleController; }
+namespace com::sun::star::drawing { class XLayer; }
+namespace osl { class Mutex; }
+
+class SdPage;
+
+namespace sd {
+
+typedef ::cppu::ImplInheritanceHelper <
+ SfxBaseController,
+ css::view::XSelectionSupplier,
+ css::lang::XServiceInfo,
+ css::drawing::XDrawView,
+ css::view::XSelectionChangeListener,
+ css::view::XFormLayerAccess,
+ css::drawing::framework::XControllerManager,
+ css::lang::XUnoTunnel
+ > DrawControllerInterfaceBase;
+
+class BroadcastHelperOwner
+{
+public:
+ explicit BroadcastHelperOwner (::osl::Mutex& rMutex) : maBroadcastHelper(rMutex) {};
+ ::cppu::OBroadcastHelper maBroadcastHelper;
+};
+
+class ViewShellBase;
+
+/** The DrawController is the UNO controller for Impress and Draw. It
+ relies objects that implement the DrawSubController interface for view
+ specific behaviour. The life time of the DrawController is roughly that
+ of ViewShellBase but note that the DrawController can (in the case of a
+ reload) outlive the ViewShellBase.
+
+ The implementation of the XControllerManager interface is not yet in its
+ final form.
+*/
+class DrawController final
+ : public DrawControllerInterfaceBase,
+ private BroadcastHelperOwner,
+ public ::cppu::OPropertySetHelper
+{
+public:
+ enum PropertyHandle {
+ PROPERTY_WORKAREA = 0,
+ PROPERTY_SUB_CONTROLLER = 1,
+ PROPERTY_CURRENTPAGE = 2,
+ PROPERTY_MASTERPAGEMODE = 3,
+ PROPERTY_LAYERMODE = 4,
+ PROPERTY_ACTIVE_LAYER = 5,
+ PROPERTY_ZOOMTYPE = 6,
+ PROPERTY_ZOOMVALUE = 7,
+ PROPERTY_VIEWOFFSET = 8,
+ PROPERTY_DRAWVIEWMODE = 9
+ ,PROPERTY_UPDATEACC = 10
+ ,PROPERTY_PAGE_CHANGE = 11
+ };
+
+ /** Create a new DrawController object for the given ViewShellBase.
+ */
+ explicit DrawController (ViewShellBase& rBase) noexcept;
+
+ virtual ~DrawController() noexcept override;
+
+ /** Replace the currently used sub controller with the given one. This
+ new sub controller is used from now on for the view (that is the
+ main view shell to be precise) specific tasks. Call this method
+ with a suitable sub controller whenever the view shell in the center
+ pane is exchanged.
+ @param pSubController
+ The ViewShell specific sub controller or NULL when (temporarily
+ while switching to another one) there is no ViewShell displayed
+ in the center pane.
+ */
+ void SetSubController (
+ const css::uno::Reference<css::drawing::XDrawSubController>& rxSubController);
+
+ /** Call this method when the VisArea has changed.
+ */
+ void FireVisAreaChanged (const ::tools::Rectangle& rVisArea) noexcept;
+
+ /** Call this method when the selection has changed.
+ */
+ void FireSelectionChangeListener() noexcept;
+
+ /** Call this method when the edit mode has changed.
+ */
+ void FireChangeEditMode (bool bMasterPageMode) noexcept;
+
+ /** Call this method when the layer mode has changed.
+ */
+ void FireChangeLayerMode (bool bLayerMode) noexcept;
+
+ /** Call this method when there is a new current page.
+ */
+ void FireSwitchCurrentPage (SdPage* pCurrentPage) noexcept;
+
+ /** Broadcast a sidebar context change that is caused by a view
+ switch.
+ */
+ void BroadcastContextChange() const;
+ void NotifyAccUpdate();
+ void fireChangeLayer( css::uno::Reference< css::drawing::XLayer>* pCurrentLayer ) noexcept;
+ // change the parameter to int
+ //void fireSwitchCurrentPage( String pageName) throw();
+ void fireSwitchCurrentPage( sal_Int32 pageIndex) noexcept;
+ bool IsDisposing() const { return mbDisposing; }
+
+ /** Return a pointer to the ViewShellBase object that the DrawController
+ is connected to.
+ @return
+ The returned pointer is <NULL/> after a call to
+ ReleaseViewShellBase().
+ */
+ ViewShellBase* GetViewShellBase() { return mpBase;}
+
+ /** This method is typically called from the destructor of ViewShellBase
+ to tell the DrawController that it and its members must not access
+ the ViewShellBase anymore.
+ After this call the DrawController is semi-disposed.
+ */
+ void ReleaseViewShellBase();
+
+ static const css::uno::Sequence<sal_Int8>& getUnoTunnelId();
+
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // XController
+ virtual sal_Bool SAL_CALL suspend( sal_Bool Suspend ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XSelectionSupplier
+ virtual sal_Bool SAL_CALL select( const css::uno::Any& aSelection ) override;
+ virtual css::uno::Any SAL_CALL getSelection( ) override;
+ virtual void SAL_CALL addSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XFormLayerAccess
+ virtual css::uno::Reference< css::form::runtime::XFormController > SAL_CALL getFormController( const css::uno::Reference< css::form::XForm >& Form ) override;
+ virtual sal_Bool SAL_CALL isFormDesignMode( ) override;
+ virtual void SAL_CALL setFormDesignMode( sal_Bool DesignMode ) override;
+
+ // XControlAccess
+ virtual css::uno::Reference< css::awt::XControl > SAL_CALL getControl( const css::uno::Reference< css::awt::XControlModel >& xModel ) override;
+
+ // XDrawView
+ virtual void SAL_CALL
+ setCurrentPage (
+ const css::uno::Reference<
+ css::drawing::XDrawPage >& xPage) override;
+
+ virtual css::uno::Reference<
+ css::drawing::XDrawPage > SAL_CALL
+ getCurrentPage() override;
+
+ // lang::XEventListener
+ virtual void SAL_CALL
+ disposing (const css::lang::EventObject& rEventObject) override;
+
+ // view::XSelectionChangeListener
+ virtual void SAL_CALL
+ selectionChanged (const css::lang::EventObject& rEvent) override;
+
+ // XControllerManager
+
+ virtual css::uno::Reference<css::drawing::framework::XConfigurationController> SAL_CALL
+ getConfigurationController() override;
+
+ virtual css::uno::Reference<css::drawing::framework::XModuleController> SAL_CALL
+ getModuleController() override;
+
+ // XUnoTunnel
+
+ virtual sal_Int64 SAL_CALL getSomething (const css::uno::Sequence<sal_Int8>& rId) override;
+
+private:
+ /** This method must return the name to index table. This table
+ contains all property names and types of this object.
+ */
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ static void FillPropertyTable (
+ ::std::vector< css::beans::Property>& rProperties);
+
+ /**
+ * The same as getFastPropertyValue, but return the value through
+ * rValue and nHandle is always valid.
+ */
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle ) const override;
+
+ /** Convert the value rValue and return the result in rConvertedValue and the
+ old value in rOldValue.
+ After this call the vetoable listeners are notified.
+
+ @param rConvertedValue
+ The converted value. Only set if return is true.
+ @param rOldValue
+ The old value. Only set if return is true.
+ @param nHandle
+ The handle of the property.
+ @return
+ <TRUE/> if the value is converted successfully.
+ @throws IllegalArgumentException
+ */
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+ /** The same as setFastPropertyValue, but no exception is thrown and nHandle
+ is always valid. You must not broadcast the changes in this method.
+ */
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+ /** When the called object has been disposed already this method throws
+ a Disposed exception and does not return.
+
+ @throws css::lang::DisposedException
+ */
+ void ThrowIfDisposed() const;
+
+ using cppu::OPropertySetHelper::disposing;
+ using cppu::OPropertySetHelper::getFastPropertyValue;
+
+ css::uno::Reference< css::drawing::XLayer>* mpCurrentLayer;
+
+ const css::uno::Type m_aSelectionTypeIdentifier;
+
+ /** This pointer to the ViewShellBase can be NULL (after a call to
+ ReleaseViewShellBase()).
+ */
+ ViewShellBase* mpBase;
+
+ ::tools::Rectangle maLastVisArea;
+ ::unotools::WeakReference<SdPage> mpCurrentPage;
+ bool mbMasterPageMode;
+ bool mbLayerMode;
+
+ /** This flag indicates whether the called DrawController is being
+ disposed or already has been disposed.
+ */
+ bool mbDisposing;
+
+ ::std::unique_ptr< ::cppu::IPropertyArrayHelper> mpPropertyArrayHelper;
+
+ /** The current sub controller. May be NULL.
+ */
+ css::uno::Reference<css::drawing::XDrawSubController> mxSubController;
+
+ css::uno::Reference<
+ css::drawing::framework::XConfigurationController> mxConfigurationController;
+ css::uno::Reference<
+ css::drawing::framework::XModuleController> mxModuleController;
+
+ /** Send an event to all relevant property listeners that a
+ property has changed its value. The fire() method of the
+ OPropertySetHelper is wrapped by this method to handle
+ exceptions thrown by called listeners.
+ */
+ void FirePropertyChange (
+ sal_Int32 nHandle,
+ const css::uno::Any& rNewValue,
+ const css::uno::Any& rOldValue);
+
+ void ProvideFrameworkControllers();
+ void DisposeFrameworkControllers();
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/DrawDocShell.hxx b/sd/source/ui/inc/DrawDocShell.hxx
new file mode 100644
index 000000000..15fa5ebd4
--- /dev/null
+++ b/sd/source/ui/inc/DrawDocShell.hxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <o3tl/span.hxx>
+#include <sfx2/docfac.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/style.hxx>
+
+#include <glob.hxx>
+#include <pres.hxx>
+#include <sddllapi.h>
+#include "fupoor.hxx"
+
+class FontList;
+class SdDrawDocument;
+class SdPage;
+class SfxPrinter;
+struct SpellCallbackInfo;
+class AbstractSvxNameDialog;
+class SfxUndoManager;
+
+namespace sd {
+
+class FrameView;
+class ViewShell;
+class DrawViewShell;
+
+// DrawDocShell
+class SD_DLLPUBLIC DrawDocShell : public SfxObjectShell
+{
+public:
+ SFX_DECL_INTERFACE(SD_IF_SDDRAWDOCSHELL)
+ SFX_DECL_OBJECTFACTORY();
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ DrawDocShell (
+ SfxObjectCreateMode eMode,
+ bool bSdDataObj,
+ DocumentType);
+
+ DrawDocShell (
+ SfxModelFlags nModelCreationFlags,
+ bool bSdDataObj,
+ DocumentType);
+
+ DrawDocShell (
+ SdDrawDocument* pDoc,
+ SfxObjectCreateMode eMode,
+ bool bSdDataObj,
+ DocumentType);
+ virtual ~DrawDocShell() override;
+
+ void UpdateRefDevice();
+ virtual void Activate( bool bMDI ) override;
+ virtual void Deactivate( bool bMDI ) override;
+ virtual bool InitNew( const css::uno::Reference< css::embed::XStorage >& xStorage ) override;
+ virtual bool ImportFrom(SfxMedium &rMedium,
+ css::uno::Reference<css::text::XTextRange> const& xInsertPosition)
+ override;
+ virtual bool ConvertFrom( SfxMedium &rMedium ) override;
+ virtual bool Save() override;
+ virtual bool SaveAsOwnFormat( SfxMedium& rMedium ) override;
+ virtual bool ConvertTo( SfxMedium &rMedium ) override;
+ virtual bool SaveCompleted( const css::uno::Reference< css::embed::XStorage >& xStorage ) override;
+
+ virtual bool Load( SfxMedium &rMedium ) override;
+ virtual bool LoadFrom( SfxMedium& rMedium ) override;
+ virtual bool SaveAs( SfxMedium &rMedium ) override;
+
+ virtual ::tools::Rectangle GetVisArea(sal_uInt16 nAspect) const override;
+ virtual void Draw(OutputDevice*, const JobSetup& rSetup, sal_uInt16 nAspect) override;
+ virtual SfxUndoManager* GetUndoManager() override;
+ virtual Printer* GetDocumentPrinter() override;
+ virtual void OnDocumentPrinterChanged(Printer* pNewPrinter) override;
+ virtual SfxStyleSheetBasePool* GetStyleSheetPool() override;
+ virtual void FillClass(SvGlobalName* pClassName, SotClipboardFormatId* pFormat, OUString* pFullTypeName, sal_Int32 nFileFormat, bool bTemplate = false ) const override;
+ virtual void SetModified( bool = true ) override;
+ virtual std::shared_ptr<SfxDocumentInfoDialog> CreateDocumentInfoDialog(weld::Window* pParent,
+ const SfxItemSet &rSet) override;
+
+ using SfxObjectShell::GetVisArea;
+ using SfxShell::GetViewShell;
+
+ sd::ViewShell* GetViewShell() { return mpViewShell; }
+ ::sd::FrameView* GetFrameView();
+
+ SdDrawDocument* GetDoc() { return mpDoc;}
+ DocumentType GetDocumentType() const { return meDocType; }
+
+ SfxPrinter* GetPrinter(bool bCreate);
+ void SetPrinter(SfxPrinter *pNewPrinter);
+ void UpdateFontList();
+
+ bool IsInDestruction() const { return mbInDestruction; }
+
+ void CancelSearching();
+
+ void Execute( SfxRequest& rReq );
+ void GetState(SfxItemSet&);
+
+ void Connect(sd::ViewShell* pViewSh);
+ void Disconnect(sd::ViewShell const * pViewSh);
+ void UpdateTablePointers();
+
+ void GotoBookmark(std::u16string_view rBookmark);
+
+ BitmapEx GetPagePreviewBitmap(SdPage* pPage);
+
+ /** checks, if the given name is a valid new name for a slide
+
+ <p>If the name is invalid, an <type>SvxNameDialog</type> pops up that
+ queries again for a new name until it is ok or the user chose
+ Cancel.</p>
+
+ @param pWin is necessary to pass to the <type>SvxNameDialog</type> in
+ case an invalid name was entered.
+ @param rName the new name that is to be set for a slide. This string
+ may be set to an empty string (see below).
+
+ @return sal_True, if the new name is unique. Note that if the user entered
+ a default name of a not-yet-existing slide (e.g. 'Slide 17'),
+ sal_True is returned, but rName is set to an empty string.
+ */
+ bool CheckPageName(weld::Window* pWin, OUString& rName );
+
+ void SetSlotFilter(bool bEnable = false, o3tl::span<sal_uInt16 const> pSIDs = o3tl::span<sal_uInt16 const>()) { mbFilterEnable = bEnable; mpFilterSIDs = pSIDs; }
+ void ApplySlotFilter() const;
+
+ SfxStyleFamily GetStyleFamily() const { return mnStyleFamily; }
+ void SetStyleFamily( SfxStyleFamily nSF ) { mnStyleFamily = nSF; }
+
+ /** executes the SID_OPENDOC slot to let the framework open a document
+ with the given URL and this document as a referer */
+ void OpenBookmark( const OUString& rBookmarkURL );
+
+ /** checks, if the given name is a valid new name for a slide
+
+ <p>This method does not pop up any dialog (like CheckPageName).</p>
+
+ @param rInOutPageName the new name for a slide that is to be renamed.
+ This string will be set to an empty string if
+ bResetStringIfStandardName is true and the name is of the
+ form of any, possibly not-yet existing, standard slide
+ (e.g. 'Slide 17')
+
+ @param bResetStringIfStandardName if true allows setting rInOutPageName
+ to an empty string, which returns true and implies that the
+ slide will later on get a new standard name (with a free
+ slide number).
+
+ @return true, if the new name is unique. If bResetStringIfStandardName
+ is true, the return value is also true, if the slide name is
+ a standard name (see above)
+ */
+ bool IsNewPageNameValid( OUString & rInOutPageName, bool bResetStringIfStandardName = false );
+
+ /** checks, if the given name is a *unique* name for an *existing* slide
+
+ @param rPageName the name of an existing slide
+
+ @return true, if the name is unique and the slide exists
+ */
+ bool IsPageNameUnique(std::u16string_view rPagName) const;
+
+ /** Return the reference device for the current document. When the
+ inherited implementation returns a device then this is passed to the
+ caller. Otherwise the returned value depends on the printer
+ independent layout mode and will usually be either a printer or a
+ virtual device used for screen rendering.
+ @return
+ Returns NULL when the current document has no reference device.
+ */
+ virtual OutputDevice* GetDocumentRefDev() override;
+
+ DECL_DLLPRIVATE_LINK( RenameSlideHdl, AbstractSvxNameDialog&, bool );
+
+ // ExecuteSpellPopup now handled by DrawDocShell
+ DECL_DLLPRIVATE_LINK( OnlineSpellCallback, SpellCallbackInfo&, void );
+
+ void ClearUndoBuffer();
+
+ std::vector<Color> GetThemeColors() override;
+
+protected:
+
+ SdDrawDocument* mpDoc;
+ std::unique_ptr<SfxUndoManager> mpUndoManager;
+ VclPtr<SfxPrinter> mpPrinter;
+ ::sd::ViewShell* mpViewShell;
+ std::unique_ptr<FontList> mpFontList;
+ DocumentType meDocType;
+ SfxStyleFamily mnStyleFamily;
+ o3tl::span<sal_uInt16 const>
+ mpFilterSIDs;
+ bool mbFilterEnable;
+ bool mbSdDataObj;
+ bool mbInDestruction;
+ bool mbOwnPrinter;
+
+ bool mbOwnDocument; // if true, we own mpDoc and will delete it in our d'tor
+ void Construct(bool bClipboard);
+private:
+ static void setEditMode(DrawViewShell* pDrawViewShell, bool isMasterPage);
+};
+
+#ifndef SV_DECL_DRAW_DOC_SHELL_DEFINED
+#define SV_DECL_DRAW_DOC_SHELL_DEFINED
+typedef ::tools::SvRef<DrawDocShell> DrawDocShellRef;
+#endif
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/DrawSubController.hxx b/sd/source/ui/inc/DrawSubController.hxx
new file mode 100644
index 000000000..d748d6378
--- /dev/null
+++ b/sd/source/ui/inc/DrawSubController.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/XDrawSubController.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/compbase.hxx>
+
+namespace sd {
+
+ class DrawSubControllerInterfaceBase : public ::cppu::WeakComponentImplHelper<
+ css::drawing::XDrawSubController,
+ css::lang::XServiceInfo >
+ {
+ public:
+ DrawSubControllerInterfaceBase( ::osl::Mutex& aMutex )
+ : ::cppu::WeakComponentImplHelper<
+ css::drawing::XDrawSubController,
+ css::lang::XServiceInfo >( aMutex ) {}
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override = 0;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override = 0;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override = 0;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/DrawViewShell.hxx b/sd/source/ui/inc/DrawViewShell.hxx
new file mode 100644
index 000000000..c56a0f33e
--- /dev/null
+++ b/sd/source/ui/inc/DrawViewShell.hxx
@@ -0,0 +1,513 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include "ViewShell.hxx"
+#include "tools/AsynchronousCall.hxx"
+#include "TabControl.hxx"
+#include <glob.hxx>
+#include <pres.hxx>
+#include <unotools/caserotate.hxx>
+#include <unotools/options.hxx>
+#include <sddllapi.h>
+
+namespace svx::sidebar { class SelectionChangeHandler; }
+namespace com::sun::star::lang { class XEventListener; }
+namespace com::sun::star::scanner { class XScannerManager2; }
+
+class Outliner;
+class SdPage;
+class SdStyleSheet;
+class SdrExternalToolEdit;
+class TabBar;
+class SdrObject;
+class SdrPageView;
+class TransferableDataHelper;
+class TransferableClipboardListener;
+class AbstractSvxNameDialog;
+class SdrLayer;
+class SvxClipboardFormatItem;
+struct ESelection;
+class AbstractSvxObjectNameDialog;
+
+namespace sd {
+
+class DrawView;
+class LayerTabBar;
+class Ruler;
+class AnnotationManager;
+class ViewOverlayManager;
+
+#define CHECK_RANGE(nMin, nValue, nMax) ((nValue >= nMin) && (nValue <= nMax))
+
+/** Base class of the stacked shells that provide graphical views to
+ Draw and Impress documents and editing functionality. In contrast
+ to this other stacked shells are responsible for showing an
+ overview over several slides or a textual
+ overview over the text in an Impress document (OutlineViewShell).
+*/
+class SAL_DLLPUBLIC_RTTI DrawViewShell
+ : public ViewShell,
+ public SfxListener,
+ public utl::ConfigurationListener
+{
+public:
+ SFX_DECL_INTERFACE(SD_IF_SDDRAWVIEWSHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ /** Create a new stackable shell that may take some information
+ (e.g. the frame view) from the given previous shell.
+ @param ePageKind
+ This parameter gives the initial page kind that the new shell
+ will show.
+ @param pFrameView
+ The frame view that makes it possible to pass information from
+ one view shell to the next.
+ */
+ DrawViewShell (
+ ViewShellBase& rViewShellBase,
+ vcl::Window* pParentWindow,
+ PageKind ePageKind,
+ FrameView* pFrameView);
+
+ virtual ~DrawViewShell() override;
+
+ virtual void Init (bool bIsMainViewShell) override;
+
+ virtual void Shutdown() override;
+
+ void PrePaint() override;
+ virtual void Paint(const ::tools::Rectangle& rRect, ::sd::Window* pWin) override;
+
+ /** Arrange and resize the GUI elements like rulers, sliders, and
+ buttons as well as the actual document view according to the size of
+ the enclosing window and current sizes of buttons, rulers, and
+ sliders.
+ */
+ virtual void ArrangeGUIElements() override;
+
+ void HidePage();
+
+ virtual bool KeyInput(const KeyEvent& rKEvt, ::sd::Window* pWin) override;
+ virtual void MouseMove(const MouseEvent& rMEvt, ::sd::Window* pWin) override;
+ virtual void MouseButtonUp(const MouseEvent& rMEvt, ::sd::Window* pWin) override;
+ virtual void MouseButtonDown(const MouseEvent& rMEvt, ::sd::Window* pWin) override;
+ virtual void Command(const CommandEvent& rCEvt, ::sd::Window* pWin) override;
+ bool IsMouseButtonDown() const { return mbMouseButtonDown; }
+ bool IsMouseSelecting() const { return mbMouseSelecting; }
+
+ virtual void Resize() override;
+
+ void ShowMousePosInfo(const ::tools::Rectangle& rRect, ::sd::Window const * pWin);
+
+ virtual void ChangeEditMode (EditMode eMode, bool bIsLayerModeActive);
+
+ virtual void SetZoom( ::tools::Long nZoom ) override;
+ virtual void SetZoomRect( const ::tools::Rectangle& rZoomRect ) override;
+
+ void InsertURLField(const OUString& rURL, const OUString& rText, const OUString& rTarget);
+ void InsertURLButton(const OUString& rURL, const OUString& rText, const OUString& rTarget,
+ const Point* pPos);
+
+ void SelectionHasChanged();
+ void ModelHasChanged();
+ virtual void Activate(bool bIsMDIActivate) override;
+ virtual void Deactivate(bool IsMDIActivate) override;
+ virtual void UIActivating( SfxInPlaceClient* ) override;
+ virtual void UIDeactivated( SfxInPlaceClient* ) override;
+ OUString GetSelectionText( bool bCompleteWords );
+ bool HasSelection( bool bText ) const;
+
+ //If we are editing a PresObjKind::Outline return the Outliner and fill rSel
+ //with the current selection
+ ::Outliner* GetOutlinerForMasterPageOutlineTextObj(ESelection &rSel);
+
+ void ExecCtrl(SfxRequest& rReq);
+ void GetCtrlState(SfxItemSet& rSet);
+ void GetDrawAttrState(SfxItemSet& rSet);
+ void GetMenuState(SfxItemSet& rSet);
+ void GetTableMenuState(SfxItemSet& rSet);
+ /** Set the items of the given item set that are related to
+ switching the editing mode to the correct values.
+ <p>This function also sets the states of the mode buttons
+ (those at the upper right corner) accordingly.</p>
+ */
+ void GetModeSwitchingMenuState (SfxItemSet &rSet);
+ void GetAttrState(SfxItemSet& rSet);
+ void GetSnapItemState(SfxItemSet& rSet);
+
+ void SetPageProperties (SfxRequest& rReq);
+ void GetPageProperties(SfxItemSet& rSet);
+ void GetMarginProperties(SfxItemSet& rSet);
+
+ void GetState (SfxItemSet& rSet);
+ void Execute (SfxRequest& rReq);
+
+ void ExecStatusBar(SfxRequest& rReq);
+ void GetStatusBarState(SfxItemSet& rSet);
+
+ void ExecOptionsBar(SfxRequest& rReq);
+ void GetOptionsBarState(SfxItemSet& rSet);
+
+ void ExecRuler(SfxRequest& rReq);
+ void GetRulerState(SfxItemSet& rSet);
+
+ void ExecFormText(SfxRequest& rReq);
+ void GetFormTextState(SfxItemSet& rSet);
+
+ void ExecAnimationWin(SfxRequest& rReq);
+ void GetAnimationWinState(SfxItemSet& rSet);
+
+ void ExecNavigatorWin(SfxRequest& rReq);
+ void GetNavigatorWinState(SfxItemSet& rSet);
+
+ void ExecutePropPanelAttr (SfxRequest const & rReq);
+ void GetStatePropPanelAttr(SfxItemSet& rSet);
+
+ void ExecEffectWin(SfxRequest& rReq);
+
+ void Update3DWindow();
+ void AssignFrom3DWindow();
+
+ void ExecGallery(SfxRequest const & rReq);
+
+ void ExecBmpMask( SfxRequest const & rReq );
+ void GetBmpMaskState( SfxItemSet& rSet );
+
+ void ExecIMap( SfxRequest const & rReq );
+ void GetIMapState( SfxItemSet& rSet );
+
+ void FuTemporary(SfxRequest& rReq);
+ void FuPermanent(SfxRequest& rReq);
+ void FuSupport(SfxRequest& rReq);
+ void FuDeleteSelectedObjects();
+ void FuSupportRotate(SfxRequest const & rReq);
+ void FuTable(SfxRequest& rReq);
+
+ void AttrExec (SfxRequest& rReq);
+ void AttrState (SfxItemSet& rSet);
+
+ void ExecGoToNextPage (SfxRequest& rReq);
+ void GetStateGoToNextPage (SfxItemSet& rSet);
+
+ void ExecGoToPreviousPage (SfxRequest& rReq);
+ void GetStateGoToPreviousPage (SfxItemSet& rSet);
+
+ void ExecGoToFirstPage (SfxRequest& rReq);
+ void GetStateGoToFirstPage (SfxItemSet& rSet);
+
+ void ExecGoToLastPage (SfxRequest& rReq);
+ void GetStateGoToLastPage (SfxItemSet& rSet);
+
+ SD_DLLPUBLIC void ExecChar(SfxRequest& rReq);
+
+ void ExecuteAnnotation (SfxRequest const & rRequest);
+ void GetAnnotationState (SfxItemSet& rItemSet);
+
+ void StartRulerDrag (const Ruler& rRuler, const MouseEvent& rMEvt);
+
+ virtual bool PrepareClose( bool bUI = true ) override;
+
+ PageKind GetPageKind() const { return mePageKind; }
+ void SetPageKind( PageKind ePageKind ) { mePageKind = ePageKind; }
+ const Point& GetMousePos() const { return maMousePos; }
+
+ EditMode GetEditMode() const { return meEditMode; }
+ virtual SdPage* GetActualPage() override { return mpActualPage; }
+
+ /// inherited from sd::ViewShell
+ virtual SdPage* getCurrentPage() const override;
+
+ void ResetActualPage();
+ void ResetActualLayer();
+ bool SwitchPage(sal_uInt16 nPage, bool bAllowChangeFocus = true);
+ bool IsSwitchPageAllowed() const;
+
+ /**
+ * Mark the desired page as selected (1), deselected (0), toggle (2).
+ * nPage refers to the page in question.
+ */
+ bool SelectPage(sal_uInt16 nPage, sal_uInt16 nSelect);
+ bool IsSelected(sal_uInt16 nPage);
+ bool IsVisible(sal_uInt16 nPage);
+
+ void GotoBookmark(std::u16string_view rBookmark);
+ //Realize multi-selection of objects, If object is marked, the
+ //corresponding entry is set true, else the corresponding entry is set
+ //false.
+ void FreshNavigatrTree();
+ void MakeVisible(const ::tools::Rectangle& rRect, vcl::Window& rWin);
+
+ virtual void ReadFrameViewData(FrameView* pView) override;
+ virtual void WriteFrameViewData() override;
+
+ virtual ErrCode DoVerb(sal_Int32 nVerb) override;
+ virtual bool ActivateObject(SdrOle2Obj* pObj, sal_Int32 nVerb) override;
+
+ void SetZoomOnPage( bool bZoom ) { mbZoomOnPage = bZoom; }
+ bool IsZoomOnPage() const { return mbZoomOnPage; }
+ static void CheckLineTo (SfxRequest& rReq);
+ void SetChildWindowState( SfxItemSet& rSet );
+
+ void UpdateIMapDlg( SdrObject* pObj );
+
+ void LockInput();
+ void UnlockInput();
+ bool IsInputLocked() const { return mnLockCount > 0; }
+
+ sal_uInt16 GetCurPagePos() const { return maTabControl->GetCurPagePos(); }
+
+ /** Show controls of the UI or hide them, depending on the given flag.
+ Do not call this method directly. Call the method at ViewShellBase
+ instead.
+ */
+ virtual void ShowUIControls (bool bVisible) override;
+
+ void ScannerEvent();
+
+ bool IsLayerModeActive() const { return mbIsLayerModeActive;}
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt, DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow, sal_uInt16 nPage, SdrLayerID nLayer ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt, DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow, sal_uInt16 nPage, SdrLayerID nLayer ) override;
+
+ virtual void WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& ) override;
+ virtual void ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& ) override;
+
+ virtual void VisAreaChanged(const ::tools::Rectangle& rRect) override;
+
+ /** Create an accessible object representing the specified window.
+ @param pWindow
+ The returned object makes the document displayed in this window
+ accessible.
+ @return
+ Returns an <type>AccessibleDrawDocumentView</type> object.
+ */
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ CreateAccessibleDocumentView (::sd::Window* pWindow) override;
+
+ /** Return the number of layers managed by the layer tab control. This
+ will usually differ from the number of layers managed by the layer
+ administrator.
+ @return
+ The number of layers managed by the layer tab control. The
+ returned value is independent of whether the layer mode is
+ currently active and the tab control is visible.
+ */
+ int GetTabLayerCount() const;
+
+ /** Return the numerical id of the currently active layer as seen by the
+ layer tab control.
+ @return
+ The returned id is a number between zero (inclusive) and the
+ number of layers as returned by the
+ <member>GetTabLayerCount</member> method (exclusive).
+ */
+ int GetActiveTabLayerIndex() const;
+
+ /** Set the active layer at the layer tab control and update the control
+ accordingly to reflect the change on screen.
+ @param nId
+ The id is expected to be a number between zero (inclusive) and
+ the number of layers as returned by the
+ <member>GetTabLayerCount</member> method (exclusive). Note that
+ Invalid values are ignored. No exception is thrown in that case.
+ */
+ void SetActiveTabLayerIndex (int nId);
+
+ /** Return a pointer to the tab control for pages.
+ */
+ TabControl& GetPageTabControl() { return *maTabControl; }
+
+ /** Return a pointer to the tab control for layers.
+ */
+ SD_DLLPUBLIC LayerTabBar* GetLayerTabControl(); // export for unit test
+
+ /** Renames the given slide using an SvxNameDialog
+
+ @param nPageId the index of the page in the SdTabControl.
+ @param rName the new name of the slide.
+
+ @return false, if the new name is invalid for some reason.
+
+ <p>Implemented in <code>drviews8.cxx</code>.</p>
+ */
+ bool RenameSlide( sal_uInt16 nPageId, const OUString & rName );
+
+ /** modifies the given layer with the given values */
+ void ModifyLayer( SdrLayer* pLayer, const OUString& rLayerName, const OUString& rLayerTitle, const OUString& rLayerDesc, bool bIsVisible, bool bIsLocked, bool bIsPrintable );
+
+ virtual css::uno::Reference<css::drawing::XDrawSubController> CreateSubController() override;
+
+ DrawView* GetDrawView() const { return mpDrawView.get(); }
+
+ /** Relocation to a new parent window is not supported for DrawViewShell
+ objects so this method always returns <FALSE/>.
+ */
+ virtual bool RelocateToParentWindow (vcl::Window* pParentWindow) override;
+
+ OUString const & GetSidebarContextName() const;
+
+ bool IsInSwitchPage() const { return mbIsInSwitchPage; }
+
+ //move this method to ViewShell.
+ //void NotifyAccUpdate();
+protected:
+ std::unique_ptr<DrawView> mpDrawView;
+ SdPage* mpActualPage;
+ ::tools::Rectangle maMarkRect;
+ Point maMousePos;
+ VclPtr<TabControl> maTabControl;
+ EditMode meEditMode;
+ PageKind mePageKind;
+ // tdf#137445 at context menu popup time set if the EditHyperlink entry
+ // should be disabled and use that state if queried about it if
+ // EditHyperlink is dispatched from the menu. So ignoring where the mouse
+ // currently happens to be when the menu was dismissed.
+ std::optional<bool> moAtContextMenu_DisableEditHyperlink;
+ bool mbZoomOnPage;
+ bool mbIsRulerDrag;
+ sal_uLong mnLockCount;
+ bool mbReadOnly;
+ static bool mbPipette;
+
+ DECL_DLLPRIVATE_LINK( ClipboardChanged, TransferableDataHelper*, void );
+ DECL_DLLPRIVATE_LINK( TabSplitHdl, TabBar *, void );
+ DECL_DLLPRIVATE_LINK( NameObjectHdl, AbstractSvxObjectNameDialog&, bool );
+ DECL_DLLPRIVATE_LINK( RenameSlideHdl, AbstractSvxNameDialog&, bool );
+
+ void DeleteActualPage();
+ void DeleteActualLayer();
+
+ virtual VclPtr<SvxRuler> CreateHRuler(::sd::Window* pWin) override;
+ virtual VclPtr<SvxRuler> CreateVRuler(::sd::Window* pWin) override;
+ virtual void UpdateHRuler() override;
+ virtual void UpdateVRuler() override;
+ virtual void SetZoomFactor(const Fraction& rZoomX, const Fraction& rZoomY) override;
+
+ void SetupPage( Size const &rSize, ::tools::Long nLeft, ::tools::Long nRight, ::tools::Long nUpper, ::tools::Long nLower,
+ bool bSize, bool bMargin, bool bScaleAll );
+
+ void GetMenuStateSel(SfxItemSet& rSet);
+
+private:
+ /** This flag controls whether the layer mode is active, i.e. the layer
+ dialog is visible.
+ */
+ bool mbIsLayerModeActive;
+
+ /** This item contains the clipboard formats of the current clipboard
+ content that are supported both by that content and by the
+ DrawViewShell.
+ */
+ ::std::unique_ptr<SvxClipboardFormatItem> mpCurrentClipboardFormats;
+
+ /** On some occasions it is necessary to make SwitchPage calls
+ asynchronously.
+ */
+ tools::AsynchronousCall maAsynchronousSwitchPageCall;
+
+ /** This flag is used to prevent nested calls to SwitchPage().
+ */
+ bool mbIsInSwitchPage;
+
+ RotateTransliteration m_aRotateCase;
+
+ /** Listen for selection changes and broadcast context changes for the sidebar.
+ */
+ ::rtl::Reference<svx::sidebar::SelectionChangeHandler> mpSelectionChangeHandler;
+
+ void Construct (DrawDocShell* pDocSh, PageKind ePageKind);
+
+ /** Depending on the given request create a new page or duplicate an
+ existing one. See ViewShell::CreateOrDuplicatePage() for more
+ information.
+ */
+ virtual SdPage* CreateOrDuplicatePage (
+ SfxRequest& rRequest,
+ PageKind ePageKind,
+ SdPage* pPage,
+ const sal_Int32 nInsertPosition = -1) override;
+
+ void DuplicateSelectedSlides (SfxRequest& rRequest);
+
+ css::uno::Reference< css::scanner::XScannerManager2 > mxScannerManager;
+ css::uno::Reference< css::lang::XEventListener > mxScannerListener;
+ rtl::Reference<TransferableClipboardListener> mxClipEvtLstnr;
+ bool mbPastePossible;
+ bool mbMouseButtonDown;
+ bool mbMouseSelecting;
+
+ virtual void Notify (SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+ /** Stop a running slide show.
+ */
+ void StopSlideShow();
+
+ /** Show the context menu for snap lines and points. Because snap lines
+ can not be selected the index of the snap line/point for which the
+ popup menu is opened has to be passed to the processing slot
+ handlers. This can be done only by manually showing the popup menu.
+ @param pParent
+ The parent for the context menu.
+ @param rRect
+ The location at which to display the context menu.
+ @param rPageView
+ The page view is used to access the help lines.
+ @param nSnapLineIndex
+ Index of the snap line or snap point for which to show the
+ context menu.
+ */
+ void ShowSnapLineContextMenu(weld::Window* pParent, const ::tools::Rectangle& rRect,
+ SdrPageView& rPageView, const sal_uInt16 nSnapLineIndex);
+
+ using ViewShell::Notify;
+
+ ::std::unique_ptr< AnnotationManager > mpAnnotationManager;
+ ::std::unique_ptr< ViewOverlayManager > mpViewOverlayManager;
+
+ std::vector<std::unique_ptr<SdrExternalToolEdit>> m_ExternalEdits;
+
+ virtual void ConfigurationChanged( utl::ConfigurationBroadcaster* pCb, ConfigurationHints ) override;
+
+ void ConfigureAppBackgroundColor( svtools::ColorConfig* pColorConfig = nullptr );
+
+ /// return true if "Edit Hyperlink" in context menu should be disabled
+ bool ShouldDisableEditHyperlink() const;
+ /// force "Edit Hyperlink" to true, with the expectation that SID_EDIT_HYPERLINK is
+ /// later Invalidated to reset it back to its natural value
+ void EnableEditHyperlink();
+
+ // The colour of the area behind the slide (used to be called "Wiese")
+ Color mnAppBackgroundColor;
+};
+
+ /// Merge the background properties together and deposit the result in rMergeAttr
+ void MergePageBackgroundFilling(SdPage *pPage, SdStyleSheet *pStyleSheet, bool bMasterPage, SfxItemSet& rMergedAttr);
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/EventMultiplexer.hxx b/sd/source/ui/inc/EventMultiplexer.hxx
new file mode 100644
index 000000000..d6d79d11b
--- /dev/null
+++ b/sd/source/ui/inc/EventMultiplexer.hxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <rtl/ref.hxx>
+
+template <typename Arg, typename Ret> class Link;
+
+namespace sd
+{
+class ViewShellBase;
+}
+
+enum class EventMultiplexerEventId
+{
+ /** The EventMultiplexer itself is being disposed. Called for a live
+ EventMultiplexer. Removing a listener as response is not necessary,
+ though.
+ */
+ Disposing,
+
+ /** The selection in the center pane has changed.
+ */
+ EditViewSelection,
+
+ /** The selection in the slide sorter has changed, regardless of whether
+ the slide sorter is displayed in the left pane or the center pane.
+ */
+ SlideSortedSelection,
+
+ /** The current page has changed.
+ */
+ CurrentPageChanged,
+
+ /** The current MainViewShell (the ViewShell displayed in the center
+ pane) has been removed.
+ */
+ MainViewRemoved,
+
+ /** A new ViewShell has been made the MainViewShell.
+ */
+ MainViewAdded,
+
+ /** A new ViewShell is being displayed in one of the panes. Note that
+ for the ViewShell in the center pane both this event type and
+ EventId::MainViewAdded is broadcasted.
+ */
+ ViewAdded,
+
+ /** Edit mode was (or is being) switched to normal mode. Find
+ EventId::EditModeMaster below.
+ */
+ EditModeNormal,
+
+ /** One or more pages have been inserted into or deleted from the model.
+ */
+ PageOrder,
+
+ /** Text editing in one of the shapes in the MainViewShell has started.
+ */
+ BeginTextEdit,
+
+ /** Text editing in one of the shapes in the MainViewShell has ended.
+ */
+ EndTextEdit,
+
+ /** A UNO controller has been attached to the UNO frame.
+ */
+ ControllerAttached,
+
+ /** A UNO controller has been detached to the UNO frame.
+ */
+ ControllerDetached,
+
+ /** The state of a shape has changed. The page is available in the user data.
+ */
+ ShapeChanged,
+
+ /** A shape has been inserted to a page. The page is available in the
+ user data.
+ */
+ ShapeInserted,
+
+ /** A shape has been removed from a page. The page is available in the
+ user data.
+ */
+ ShapeRemoved,
+
+ /** A configuration update has been completed.
+ */
+ ConfigurationUpdated,
+
+ /** Edit mode was (or is being) switched to master mode.
+ */
+ EditModeMaster,
+};
+
+namespace sd::tools
+{
+class EventMultiplexerEvent
+{
+public:
+ EventMultiplexerEventId meEventId;
+ const void* mpUserData;
+
+ EventMultiplexerEvent(EventMultiplexerEventId eEventId, const void* pUserData);
+};
+
+/** This convenience class makes it easy to listen to various events that
+ originally are broadcasted via different channels.
+
+ There is usually one EventMultiplexer instance per ViewShellBase().
+ Call the laters GetEventMultiplexer() method to get access to that
+ instance.
+*/
+class EventMultiplexer
+{
+public:
+ /** Create new EventMultiplexer for the given ViewShellBase object.
+ */
+ EventMultiplexer(ViewShellBase& rBase);
+ ~EventMultiplexer();
+
+ /** Add an event listener that will be informed about the specified
+ event types.
+ @param rCallback
+ The callback to call as soon as one of the event specified by
+ aEventTypeSet is received by the EventMultiplexer.
+ */
+ void AddEventListener(const Link<EventMultiplexerEvent&, void>& rCallback);
+
+ /** Remove an event listener for the specified event types.
+ */
+ void RemoveEventListener(const Link<EventMultiplexerEvent&, void>& rCallback);
+
+ /** This method is used for out-of-line events. An event of the
+ specified type will be sent to all listeners that are registered for
+ that type.
+ @param eEventId
+ The type of the event.
+ @param pUserData
+ Some data sent to the listeners along with the event.
+ */
+ void MultiplexEvent(EventMultiplexerEventId eEventId, void const* pUserData);
+
+private:
+ class Implementation;
+ rtl::Reference<Implementation> mpImpl;
+};
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/FormShellManager.hxx b/sd/source/ui/inc/FormShellManager.hxx
new file mode 100644
index 000000000..b2c03b3de
--- /dev/null
+++ b/sd/source/ui/inc/FormShellManager.hxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ViewShellManager.hxx"
+
+#include <tools/link.hxx>
+#include <svl/lstner.hxx>
+#include <vcl/vclptr.hxx>
+
+class VclWindowEvent;
+class FmFormShell;
+namespace vcl
+{
+class Window;
+}
+
+namespace sd::tools
+{
+class EventMultiplexerEvent;
+}
+
+namespace sd
+{
+class ViewShellBase;
+
+/** This simple class is responsible for putting the form shell above or
+ below the main view shell on the shell stack maintained by the ObjectBarManager.
+
+ The form shell is moved above the view shell when the form shell is
+ activated, i.e. the FormControlActivated handler is called.
+
+ It is moved below the view shell when the main window of the
+ main view shell is focused.
+
+ The form shell is created and destroyed by the ViewShellManager by using
+ a factory object provided by the FormShellManager.
+*/
+class FormShellManager : public SfxListener
+{
+public:
+ FormShellManager(ViewShellBase& rBase);
+ virtual ~FormShellManager() override;
+
+ /** Typically called by a ShellFactory. It tells the
+ FormShellManager which form shell to manage.
+ @param pFormShell
+ This may be <NULL/> to disconnect the ViewShellManager from the
+ form shell.
+ */
+ void SetFormShell(FmFormShell* pFormShell);
+
+ /** Return the form shell last set with SetFormShell().
+ @return
+ The result may be <NULL/> when the SetFormShell() method has not
+ yet been called or was last called with <NULL/>.
+ */
+ FmFormShell* GetFormShell() { return mpFormShell; }
+
+private:
+ ViewShellBase& mrBase;
+
+ /** Ownership of the form shell lies with the ViewShellManager. This
+ reference is kept so that the FormShellManager can detect when a new
+ form shell is passed to SetFormShell().
+ */
+ FmFormShell* mpFormShell;
+
+ /** Remember whether the form shell is currently above or below the main
+ view shell.
+ */
+ bool mbFormShellAboveViewShell;
+
+ /** The factory is remembered so that it removed from the
+ ViewShellManager when the FormShellManager is destroyed.
+ */
+ ViewShellManager::SharedShellFactory mpSubShellFactory;
+
+ bool mbIsMainViewChangePending;
+
+ VclPtr<vcl::Window> mpMainViewShellWindow;
+
+ /** Register at window of center pane and at the form shell that
+ represents the form tool bar. The former informs this manager about
+ the deselection of the form shell. The later informs about its
+ selection.
+ */
+ void RegisterAtCenterPane();
+
+ /** Unregister the listeners that were registered in
+ RegisterAtCenterPane().
+ */
+ void UnregisterAtCenterPane();
+
+ /** This call back is called by the application window (among others)
+ when the window gets the focus. In this case the form shell is
+ moved to the bottom of the shell stack.
+ */
+ DECL_LINK(WindowEventHandler, VclWindowEvent&, void);
+
+ /** This call back is called when view in the center pane is replaced.
+ When this happens then we unregister at the window of the old and
+ register at the window of the new shell.
+ */
+ DECL_LINK(ConfigurationUpdateHandler, ::sd::tools::EventMultiplexerEvent&, void);
+
+ /** This call back is called by the form shell when it gets the focus.
+ In this case the form shell is moved to the top of the shell stack.
+ */
+ DECL_LINK(FormControlActivated, LinkParamNone*, void);
+
+ /** This method is called by the form shell when that is destroyed. It
+ acts as a last resort against referencing a dead form shell. With
+ the factory working properly this method should not be necessary
+ (and may be removed in the future.)
+ */
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/FrameView.hxx b/sd/source/ui/inc/FrameView.hxx
new file mode 100644
index 000000000..8226746a3
--- /dev/null
+++ b/sd/source/ui/inc/FrameView.hxx
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ViewShell.hxx"
+#include <svx/svdview.hxx>
+#include <pres.hxx>
+
+class SdDrawDocument;
+class SdOptions;
+
+namespace sd {
+
+/**
+ * View for MDIFrame
+ */
+class SD_DLLPUBLIC FrameView
+ : public SdrView
+{
+public:
+ FrameView(SdDrawDocument* pDrawDoc, FrameView* pFrameView = nullptr );
+ FrameView(const FrameView& rFrameView);
+ virtual ~FrameView() override;
+
+ void Connect();
+ void Disconnect();
+
+ void Update(SdOptions const * pOptions);
+
+ void SetStandardHelpLines(const SdrHelpLineList& rHelpLines)
+ { maStandardHelpLines = rHelpLines; }
+ const SdrHelpLineList& GetStandardHelpLines() const { return maStandardHelpLines; }
+ void SetNotesHelpLines(const SdrHelpLineList& rHelpLines)
+ { maNotesHelpLines = rHelpLines; }
+ const SdrHelpLineList& GetNotesHelpLines() const { return maNotesHelpLines; }
+ void SetHandoutHelpLines(const SdrHelpLineList& rHelpLines)
+ { maHandoutHelpLines = rHelpLines; }
+ const SdrHelpLineList& GetHandoutHelpLines() const { return maHandoutHelpLines; }
+
+ void SetVisibleLayers(const SdrLayerIDSet& rVisibleLayers)
+ { maVisibleLayers = rVisibleLayers; }
+ const SdrLayerIDSet& GetVisibleLayers() const { return maVisibleLayers; }
+
+ void SetLockedLayers(const SdrLayerIDSet& rLockedLayers)
+ { maLockedLayers = rLockedLayers; }
+ const SdrLayerIDSet& GetLockedLayers() const { return maLockedLayers; }
+
+ void SetPrintableLayers(const SdrLayerIDSet& rPrintableLayers)
+ { maPrintableLayers = rPrintableLayers; }
+ const SdrLayerIDSet& GetPrintableLayers() const { return maPrintableLayers; }
+
+ void SetRuler(const bool bRulerOn)
+ { mbRuler = bRulerOn; }
+ bool HasRuler() const { return mbRuler; }
+
+ void SetNoColors(const bool bNoCol)
+ { mbNoColors = bNoCol; }
+ bool IsNoColors() const { return mbNoColors; }
+
+ void SetNoAttribs(const bool bNoAttr)
+ { mbNoAttribs = bNoAttr; }
+ bool IsNoAttribs() const { return mbNoAttribs; }
+
+ void SetVisArea(const ::tools::Rectangle& rVisArea)
+ { maVisArea = rVisArea; }
+ const ::tools::Rectangle& GetVisArea() const { return maVisArea; }
+
+ void SetPageKind(PageKind eKind) { mePageKind = eKind; }
+ PageKind GetPageKind() const { return mePageKind; }
+
+ /** is used in FrameView::ReadUserDataSequence() only to store the
+ page kind that was selected while last saving this document */
+ void SetPageKindOnLoad(PageKind eKind) { mePageKindOnLoad = eKind; }
+
+ /** can be used to get the page kind that was selected on last save of this document */
+ PageKind GetPageKindOnLoad() const { return mePageKindOnLoad; }
+
+ void SetSelectedPage (sal_uInt16 nPage);
+ sal_uInt16 GetSelectedPage () const { return mnSelectedPage;}
+
+ /** is used in FrameView::ReadUserDataSequence() only to store the
+ page that was selected while last saving this document */
+ void SetSelectedPageOnLoad (sal_uInt16 nPage) { mnSelectedPageOnLoad = nPage; }
+
+ /** can be used to get the page that was selected on last save of this document */
+ sal_uInt16 GetSelectedPageOnLoad () const { return mnSelectedPageOnLoad; }
+
+ void SetViewShEditMode(EditMode eMode);
+ EditMode GetViewShEditMode () const;
+
+ /** Remember the edit mode of the main view shell at the time when the
+ document is loaded.
+ */
+ void SetViewShEditModeOnLoad (const EditMode eMode);
+
+ /** Return the value of the edit mode as it was when the document was
+ loaded.
+ */
+ EditMode GetViewShEditModeOnLoad() const { return meEditModeOnLoad;}
+
+ void SetLayerMode(bool bMode)
+ { mbLayerMode = bMode; }
+ bool IsLayerMode() const { return mbLayerMode; }
+
+ void SetQuickEdit(bool bQEdit)
+ { mbQuickEdit = bQEdit; }
+ bool IsQuickEdit() const { return mbQuickEdit; }
+
+ void SetDoubleClickTextEdit( bool bOn ) { mbDoubleClickTextEdit = bOn; }
+ bool IsDoubleClickTextEdit() const { return mbDoubleClickTextEdit; }
+
+ void SetClickChangeRotation( bool bOn ) { mbClickChangeRotation = bOn; }
+ bool IsClickChangeRotation() const { return mbClickChangeRotation; }
+
+ /** Remember the type of the view shell that was (or soon will be)
+ previously associated with this frame view.
+ @param eType
+ The type of the previous view shell or ViewShell::ST_NONE to
+ indicate that there is no previous view shell.
+ */
+ void SetPreviousViewShellType (ViewShell::ShellType eType);
+
+ /** Return the type of the view shell previously associated with this
+ frame view.
+ */
+ ViewShell::ShellType GetPreviousViewShellType() const { return mePreviousViewShellType;}
+
+ /** Remember the type of the view shell at the time when the document is
+ loaded or, rather, when the ViewShellBase is constructed.
+ */
+ void SetViewShellTypeOnLoad (ViewShell::ShellType eType);
+
+ ViewShell::ShellType GetViewShellTypeOnLoad() const { return meViewShellTypeOnLoad;}
+
+ void SetPresentationViewShellId(sal_uInt16 nId)
+ { mnPresViewShellId = nId; }
+ sal_uInt16 GetPresentationViewShellId() const { return mnPresViewShellId; }
+
+ void SetSlidesPerRow(sal_uInt16 nSlides) { mnSlidesPerRow = nSlides; }
+ sal_uInt16 GetSlidesPerRow() const { return mnSlidesPerRow; }
+
+ void SetDrawMode(DrawModeFlags nNewDrawMode) { mnDrawMode = nNewDrawMode; };
+ DrawModeFlags GetDrawMode() const { return mnDrawMode; };
+
+ void SetIsNavigatorShowingAllShapes (const bool bIsNavigatorShowingAllShapes);
+ bool IsNavigatorShowingAllShapes() const { return mbIsNavigatorShowingAllShapes;}
+
+ void WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& );
+ void ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& );
+
+private:
+ sal_uInt16 mnRefCount;
+ bool mbRuler;
+ SdrLayerIDSet maVisibleLayers;
+ SdrLayerIDSet maLockedLayers;
+ SdrLayerIDSet maPrintableLayers;
+ SdrHelpLineList maStandardHelpLines;
+ SdrHelpLineList maNotesHelpLines;
+ SdrHelpLineList maHandoutHelpLines;
+ bool mbNoColors; ///< structuring mode
+ bool mbNoAttribs; ///< structuring mode
+ ::tools::Rectangle maVisArea; ///< visible area
+ PageKind mePageKind; ///< kind of page (standard, notes, handout)
+ sal_uInt16 mnSelectedPage;
+ PageKind mePageKindOnLoad;
+ sal_uInt16 mnSelectedPageOnLoad;
+ EditMode mePageEditMode; ///< edit mode in drawing mode (Page/MasterPage)
+ // EditMode meStandardEditMode; ///< edit mode in drawing mode (Page/MasterPage)
+ // EditMode meNotesEditMode; ///< edit mode in notes mode (Page/MasterPage)
+ // EditMode meHandoutEditMode; ///< edit mode in handout mode (Page/MasterPage)
+ EditMode meEditModeOnLoad;
+ bool mbLayerMode; ///< layer on/off
+ bool mbQuickEdit; ///< QuickEdit on/off
+ bool mbDoubleClickTextEdit; ///< text mode after double click
+ bool mbClickChangeRotation; ///< single click switches between selection/rotation mode
+ sal_uInt16 mnPresViewShellId; ///< ViewShell from which the presentation was started
+ sal_uInt16 mnSlidesPerRow; ///< slides per row on the slide-desk
+ DrawModeFlags mnDrawMode; ///< draw mode for the normal window
+ /** Remember whether the navigator shows all shapes (<TRUE/>) or only
+ the names ones (<FALSE/>). Not persistent.
+ */
+ bool mbIsNavigatorShowingAllShapes;
+
+ /** The type of the previous view shell. The (default) value
+ ViewShell::ST_NONE indicates that there was no previous view shell.
+ Note that this value is used only temporarily and is not saved or
+ restored.
+ */
+ ViewShell::ShellType mePreviousViewShellType;
+
+ ViewShell::ShellType meViewShellTypeOnLoad;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/GraphicDocShell.hxx b/sd/source/ui/inc/GraphicDocShell.hxx
new file mode 100644
index 000000000..40df981cf
--- /dev/null
+++ b/sd/source/ui/inc/GraphicDocShell.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 .
+ */
+
+#pragma once
+
+#include <sfx2/docfac.hxx>
+#include <sfx2/objsh.hxx>
+#include "DrawDocShell.hxx"
+#include <glob.hxx>
+#include <sddllapi.h>
+
+namespace sd
+{
+/**
+ * document shell for draw documents
+ */
+class SD_DLLPUBLIC GraphicDocShell : public DrawDocShell
+{
+public:
+ SFX_DECL_INTERFACE(SD_IF_SDGRAPHICDOCSHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ SFX_DECL_OBJECTFACTORY();
+
+ GraphicDocShell(SfxObjectCreateMode eMode);
+
+ GraphicDocShell(SfxModelFlags nModelCreationFlags);
+
+ virtual ~GraphicDocShell() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/GraphicObjectBar.hxx b/sd/source/ui/inc/GraphicObjectBar.hxx
new file mode 100644
index 000000000..7d53a86d2
--- /dev/null
+++ b/sd/source/ui/inc/GraphicObjectBar.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 .
+ */
+
+#pragma once
+
+#include <sfx2/shell.hxx>
+#include <glob.hxx>
+
+namespace sd {
+
+class View;
+class ViewShell;
+
+class GraphicObjectBar final
+ : public SfxShell
+{
+public:
+ SFX_DECL_INTERFACE( SD_IF_SDDRAWGRAFOBJECTBAR )
+
+ GraphicObjectBar (const ViewShell* pSdViewShell, ::sd::View* pSdView);
+ virtual ~GraphicObjectBar() override;
+
+ void GetAttrState( SfxItemSet& rSet );
+ void Execute( SfxRequest& rReq );
+
+ void GetFilterState( SfxItemSet& rSet );
+ void ExecuteFilter( SfxRequest const & rReq );
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+ ::sd::View* mpView;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/GraphicViewShell.hxx b/sd/source/ui/inc/GraphicViewShell.hxx
new file mode 100644
index 000000000..d730c2dd9
--- /dev/null
+++ b/sd/source/ui/inc/GraphicViewShell.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "DrawViewShell.hxx"
+
+namespace vcl
+{
+class Window;
+}
+
+namespace sd
+{
+/** View shell of the Draw application.
+
+ <p>This class is an example of how not to do it: specialization by
+ inheritance. A graphic view shell is similar to a draw view shell
+ but lacks some of its features. Thus is should be at most a base
+ class of DrawViewShell. There even is special case code in
+ ViewShell that turns off some of the features for GraphicViewShell
+ instances.</p>
+*/
+class SAL_DLLPUBLIC_RTTI GraphicViewShell final : public DrawViewShell
+{
+public:
+ SFX_DECL_VIEWFACTORY(GraphicViewShell);
+ SFX_DECL_INTERFACE(SD_IF_SDGRAPHICVIEWSHELL)
+
+ /** Create a new view shell for the Draw application.
+ @param rViewShellBase
+ The new object will be stacked on this view shell base.
+ @param pFrameView
+ The frame view that makes it possible to pass information from
+ one view shell to the next.
+ */
+ GraphicViewShell(ViewShellBase& rViewShellBase, vcl::Window* pParentWindow,
+ FrameView* pFrameView);
+
+ virtual ~GraphicViewShell() override;
+
+ /** Override this method in order to have the layer mode always active.
+ */
+ virtual void ChangeEditMode(EditMode eMode, bool bIsLayerModeActive) override;
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+ void ConstructGraphicViewShell();
+ virtual void ArrangeGUIElements() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/GraphicViewShellBase.hxx b/sd/source/ui/inc/GraphicViewShellBase.hxx
new file mode 100644
index 000000000..89a96cf51
--- /dev/null
+++ b/sd/source/ui/inc/GraphicViewShellBase.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ViewShellBase.hxx"
+
+namespace sd
+{
+/** This class exists to be able to register another factory that
+ creates the view shell for the Draw application.
+*/
+class GraphicViewShellBase : public ViewShellBase
+{
+public:
+ SFX_DECL_VIEWFACTORY(GraphicViewShellBase);
+
+ /** This constructor is used by the view factory of the SFX
+ macros.
+ */
+ GraphicViewShellBase(SfxViewFrame* pFrame, SfxViewShell* pOldShell);
+ virtual ~GraphicViewShellBase() override;
+
+ /** Callback function for general slot calls.
+ */
+ virtual void Execute(SfxRequest& rRequest) override;
+
+protected:
+ virtual void InitializeFramework() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ImpressViewShellBase.hxx b/sd/source/ui/inc/ImpressViewShellBase.hxx
new file mode 100644
index 000000000..80070e7c8
--- /dev/null
+++ b/sd/source/ui/inc/ImpressViewShellBase.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ViewShellBase.hxx"
+
+namespace sd
+{
+/** This class implements a few features that exist only for the Impress
+ application.
+*/
+class ImpressViewShellBase : public ViewShellBase
+{
+public:
+ SFX_DECL_VIEWFACTORY(ImpressViewShellBase);
+
+ /** This constructor is used by the view factory of the SFX
+ macros.
+ */
+ ImpressViewShellBase(SfxViewFrame* pFrame, SfxViewShell* pOldShell);
+ virtual ~ImpressViewShellBase() override;
+
+ /** Callback function for general slot calls.
+ */
+ virtual void Execute(SfxRequest& rRequest) override;
+
+protected:
+ virtual void InitializeFramework() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/LayerTabBar.hxx b/sd/source/ui/inc/LayerTabBar.hxx
new file mode 100644
index 000000000..297a9302d
--- /dev/null
+++ b/sd/source/ui/inc/LayerTabBar.hxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <svtools/tabbar.hxx>
+#include <vcl/transfer.hxx>
+#include <sddllapi.h>
+
+namespace sd {
+
+/**
+ * TabBar for layer administration
+ */
+class DrawViewShell;
+
+class SAL_DLLPUBLIC_RTTI LayerTabBar final
+ : public TabBar,
+ public DropTargetHelper
+{
+public:
+ LayerTabBar (
+ DrawViewShell* pDrViewSh,
+ vcl::Window* pParent);
+ virtual void dispose() override;
+ virtual ~LayerTabBar() override;
+
+ /** Inform all listeners of this control that the current layer has been
+ activated. Call this method after switching the current layer and is
+ not done elsewhere (like when using ctrl + page up/down keys).
+ */
+ void SendActivatePageEvent();
+
+ /** Inform all listeners of this control that the current layer has been
+ deactivated. Call this method before switching the current layer
+ and is not done elsewhere (like when using ctrl page up/down keys).
+ */
+ void SendDeactivatePageEvent();
+
+ // Expects not-localized, real layer name in rText. Generates a localized layer name
+ // that will be displayed on the tab of the LayerTabBar and writes the real name
+ // to maAuxiliaryText. In case you want no entry in maAuxiliaryText, use method from TabBar.
+ virtual void InsertPage( sal_uInt16 nPageId, const OUString& rText,
+ TabBarPageBits nBits = TabBarPageBits::NONE,
+ sal_uInt16 nPos = TabBar::APPEND ) override;
+ virtual void SetPageText( sal_uInt16 nPageId, const OUString& rText ) override;
+
+ // Returns the real layer name if exists and empty OUString otherwise.
+ OUString GetLayerName(sal_uInt16 nPageId) const;
+
+ // Used e.g. in DeleteActualLayer() to test whether deleting is allowed.
+ static bool IsRealNameOfStandardLayer(std::u16string_view rName);
+
+ // Used e.g. in validity test of user entered names
+ static bool IsLocalizedNameOfStandardLayer(std::u16string_view rName);
+
+ // In case rName is one of the sUNO_LayerName_*, it generates a localized name,
+ // otherwise it returns value of rName.
+ static OUString convertToLocalizedName(const OUString& rName);
+
+ // TabBar
+ virtual void Select() override;
+ virtual void DoubleClick() override;
+
+ SD_DLLPUBLIC virtual void MouseButtonDown(const MouseEvent& rMEvt) override; // export for unit test
+
+ virtual void Command(const CommandEvent& rCEvt) override;
+
+ virtual bool StartRenaming() override;
+ virtual TabBarAllowRenamingReturnCode AllowRenaming() override;
+ virtual void EndRenaming() override;
+
+ virtual void ActivatePage() override;
+
+ // DropTargetHelper
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+private:
+ DrawViewShell* pDrViewSh;
+
+ // Expects not-localized, real layer name in rText and writes it to maAuxiliaryText.
+ void SetLayerName( sal_uInt16 nPageId, const OUString& rText );
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/MasterPageObserver.hxx b/sd/source/ui/inc/MasterPageObserver.hxx
new file mode 100644
index 000000000..96f4a3741
--- /dev/null
+++ b/sd/source/ui/inc/MasterPageObserver.hxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <tools/link.hxx>
+#include "tools/SdGlobalResourceContainer.hxx"
+#include <memory>
+#include <set>
+
+namespace osl
+{
+class Mutex;
+}
+
+class SdDrawDocument;
+
+namespace sd
+{
+class MasterPageObserverEvent;
+
+/** This singleton observes all registered documents for changes in the used
+ master pages and in turn informs its listeners about it. One such
+ listener is the master page selector control in the tool panel that
+ shows the recently used master pages.
+*/
+class MasterPageObserver : public SdGlobalResource
+{
+public:
+ typedef ::std::set<OUString> MasterPageNameSet;
+
+ /** Return the single instance of this class.
+ */
+ static MasterPageObserver& Instance();
+
+ /** The master page observer will listen to events of this document and
+ detect changes of the use of master pages.
+ */
+ void RegisterDocument(SdDrawDocument& rDocument);
+
+ /** The master page observer will stop to listen to events of this
+ document.
+ */
+ void UnregisterDocument(SdDrawDocument& rDocument);
+
+ /** Add a listener that is informed of master pages that are newly
+ assigned to slides or become unassigned.
+ @param rEventListener
+ The event listener to call for future events. Call
+ RemoveEventListener() before the listener is destroyed.
+ */
+ void AddEventListener(const Link<MasterPageObserverEvent&, void>& rEventListener);
+
+ /** Remove the given listener from the list of listeners.
+ @param rEventListener
+ After this method returns the given listener is not called back
+ from this object. Passing a listener that has not
+ been registered before is safe and is silently ignored.
+ */
+ void RemoveEventListener(const Link<MasterPageObserverEvent&, void>& rEventListener);
+
+private:
+ class Implementation;
+ ::std::unique_ptr<Implementation> mpImpl;
+
+ MasterPageObserver();
+ virtual ~MasterPageObserver() override;
+
+ MasterPageObserver(const MasterPageObserver&) = delete;
+
+ MasterPageObserver& operator=(const MasterPageObserver&) = delete;
+};
+
+/** Objects of this class are sent to listeners of the MasterPageObserver
+ singleton when the list of master pages of one document has changed.
+*/
+class MasterPageObserverEvent
+{
+public:
+ enum EventType
+ {
+ /// Master page already exists when document is registered.
+ ET_MASTER_PAGE_EXISTS,
+ /// Master page has been added to a document.
+ ET_MASTER_PAGE_ADDED,
+ /// Master page has been removed from to a document.
+ ET_MASTER_PAGE_REMOVED
+ };
+
+ EventType meType;
+ const OUString& mrMasterPageName;
+
+ MasterPageObserverEvent(EventType eType, const OUString& rMasterPageName)
+ : meType(eType)
+ , mrMasterPageName(rMasterPageName)
+ {
+ }
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/MediaObjectBar.hxx b/sd/source/ui/inc/MediaObjectBar.hxx
new file mode 100644
index 000000000..b7c56ef00
--- /dev/null
+++ b/sd/source/ui/inc/MediaObjectBar.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/shell.hxx>
+#include <glob.hxx>
+
+class SfxInterface;
+class SfxItemSet;
+class SfxModule;
+class SfxRequest;
+
+namespace sd {
+
+class View;
+class ViewShell;
+
+class MediaObjectBar final
+ : public SfxShell
+{
+public:
+ SFX_DECL_INTERFACE( SD_IF_SDDRAWMEDIAOBJECTBAR )
+
+ MediaObjectBar (const ViewShell* pSdViewShell, ::sd::View* pSdView);
+ virtual ~MediaObjectBar() override;
+
+ void GetState( SfxItemSet& rSet );
+ void Execute( SfxRequest const & rReq );
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+ ::sd::View* mpView;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/NavigatorChildWindow.hxx b/sd/source/ui/inc/NavigatorChildWindow.hxx
new file mode 100644
index 000000000..4199cab67
--- /dev/null
+++ b/sd/source/ui/inc/NavigatorChildWindow.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/childwin.hxx>
+#include <sfx2/navigat.hxx>
+
+namespace vcl { class Window; }
+class SfxBindings;
+
+namespace sd {
+
+class SdNavigatorWrapper final : public SfxNavigatorWrapper
+{
+public:
+ SdNavigatorWrapper(vcl::Window *pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo* pInfo);
+ SFX_DECL_CHILDWINDOW(SdNavigatorWrapper);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/OutlineBulletDlg.hxx b/sd/source/ui/inc/OutlineBulletDlg.hxx
new file mode 100644
index 000000000..512d45f9a
--- /dev/null
+++ b/sd/source/ui/inc/OutlineBulletDlg.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+
+namespace sd
+{
+class View;
+
+/**
+ * Bullet-Tab-Dialog
+ */
+class OutlineBulletDlg : public SfxTabDialogController
+{
+public:
+ OutlineBulletDlg(weld::Window* pParent, const SfxItemSet* pAttr, ::sd::View* pView);
+ virtual ~OutlineBulletDlg() override;
+
+ const SfxItemSet* GetBulletOutputItemSet() const;
+
+protected:
+ virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override;
+
+private:
+ SfxItemSet m_aInputSet;
+ std::unique_ptr<SfxItemSet> m_xOutputSet;
+ bool m_bTitle;
+ ::sd::View* m_pSdView;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/OutlineView.hxx b/sd/source/ui/inc/OutlineView.hxx
new file mode 100644
index 000000000..058f6323a
--- /dev/null
+++ b/sd/source/ui/inc/OutlineView.hxx
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <vcl/image.hxx>
+#include <vcl/vclevent.hxx>
+#include <editeng/lrspitem.hxx>
+#include <o3tl/deleter.hxx>
+#include "View.hxx"
+
+class SdPage;
+class SdrPage;
+class SdrTextObj;
+class SfxProgress;
+struct PasteOrDropInfos;
+class EditView;
+
+namespace sd::tools {
+ class EventMultiplexerEvent;
+}
+
+namespace sd {
+
+class DrawDocShell;
+class OutlineViewShell;
+class OutlineViewModelChangeGuard;
+
+const int MAX_OUTLINERVIEWS = 4;
+
+/**
+ * Derivative of ::sd::View for the outline mode
+|*
+\************************************************************************/
+
+class OutlineView
+ : public ::sd::View
+{
+ friend class OutlineViewModelChangeGuard;
+public:
+ OutlineView (DrawDocShell& rDocSh,
+ vcl::Window* pWindow,
+ OutlineViewShell& rOutlineViewSh);
+ virtual ~OutlineView() override;
+
+ /** This method is called by the view shell that owns the view to tell
+ the view that it can safely connect to the application.
+ This method must not be called before the view shell is on the shell
+ stack.
+ */
+ void ConnectToApplication();
+ void DisconnectFromApplication();
+
+
+ static SdrTextObj* GetTitleTextObject(SdrPage const * pPage);
+ static SdrTextObj* GetOutlineTextObject(SdrPage const * pPage);
+
+ static SdrTextObj* CreateTitleTextObject(SdPage* pPage);
+ static SdrTextObj* CreateOutlineTextObject(SdPage* pPage);
+
+ virtual void AddWindowToPaintView(OutputDevice* pWin, vcl::Window* pWindow) override;
+ virtual void DeleteWindowFromPaintView(OutputDevice* pWin) override;
+
+ OutlinerView* GetViewByWindow(vcl::Window const * pWin) const;
+ SdrOutliner& GetOutliner() { return mrOutliner; }
+
+ Paragraph* GetPrevTitle(const Paragraph* pPara);
+ Paragraph* GetNextTitle(const Paragraph* pPara);
+ SdPage* GetActualPage();
+ SdPage* GetPageForParagraph( Paragraph* pPara );
+ Paragraph* GetParagraphForPage( ::Outliner const & rOutl, SdPage const * pPage );
+
+ /** selects the paragraph for the given page at the outliner view*/
+ void SetActualPage( SdPage const * pActual );
+
+ void Paint (const ::tools::Rectangle& rRect, ::sd::Window const * pWin);
+
+ // Callbacks for LINKs
+ DECL_LINK( ParagraphInsertedHdl, ::Outliner::ParagraphHdlParam, void );
+ DECL_LINK( ParagraphRemovingHdl, ::Outliner::ParagraphHdlParam, void );
+ DECL_LINK( DepthChangedHdl, ::Outliner::DepthChangeHdlParam, void );
+ DECL_LINK( StatusEventHdl, EditStatus&, void );
+ DECL_LINK( BeginMovingHdl, ::Outliner *, void );
+ DECL_LINK( EndMovingHdl, ::Outliner *, void );
+ DECL_LINK( RemovingPagesHdl, OutlinerView *, bool );
+ DECL_LINK( IndentingPagesHdl, OutlinerView *, bool );
+ DECL_LINK( BeginDropHdl, EditView*, void );
+ DECL_LINK( EndDropHdl, EditView*, void );
+ DECL_LINK( PaintingFirstLineHdl, PaintFirstLineInfo*, void );
+
+ sal_uLong GetPaperWidth() const { return mnPaperWidth;}
+
+ void PrepareClose();
+
+ virtual void GetAttributes( SfxItemSet& rTargetSet, bool bOnlyHardAttr = false ) const override;
+ virtual bool SetAttributes(const SfxItemSet& rSet, bool bReplaceAll = false, bool bSlide = false, bool bMaster = false) override;
+
+ void FillOutliner();
+ void SetLinks();
+ void ResetLinks() const;
+
+ SfxStyleSheet* GetStyleSheet() const override;
+
+ void SetSelectedPages();
+
+ virtual sal_Int8 AcceptDrop (
+ const AcceptDropEvent& rEvt,
+ DropTargetHelper& rTargetHelper,
+ SdrLayerID nLayer) override;
+ virtual sal_Int8 ExecuteDrop (
+ const ExecuteDropEvent& rEvt,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer) override;
+
+ // Re-implement GetScriptType for this view to get correct results
+ virtual SvtScriptType GetScriptType() const override;
+
+ /** After this method has been called with <TRUE/> following changes of
+ the current page are ignored in that the corresponding text is not
+ selected.
+ This is used to suppress unwanted side effects between selection and
+ cursor position.
+ */
+ void IgnoreCurrentPageChanges (bool bIgnore);
+
+ /** creates and inserts an empty slide for the given paragraph. */
+ SdPage* InsertSlideForParagraph( Paragraph* pPara );
+
+ void UpdateParagraph( sal_Int32 nPara );
+
+protected:
+ virtual void OnBeginPasteOrDrop( PasteOrDropInfos* pInfo ) override;
+ virtual void OnEndPasteOrDrop( PasteOrDropInfos* pInfo ) override;
+
+private:
+ /** call this method before you do anything that can modify the outliner
+ and or the drawing document model. It will create needed undo actions */
+ void BeginModelChange();
+
+ /** call this method after BeginModelChange(), when all possible model
+ changes are done. */
+ void EndModelChange();
+
+ /** merge edit engine undo actions if possible */
+ void TryToMergeUndoActions();
+
+ /** updates all changes in the outliner model to the draw model */
+ void UpdateDocument();
+
+ OutlineViewShell& mrOutlineViewShell;
+ SdrOutliner& mrOutliner;
+ std::unique_ptr<OutlinerView> mpOutlinerViews[MAX_OUTLINERVIEWS];
+
+ std::vector<Paragraph*> maOldParaOrder;
+ std::vector<Paragraph*> maSelectedParas;
+
+ sal_Int32 mnPagesToProcess; // for the progress bar
+ sal_Int32 mnPagesProcessed;
+
+ bool mbFirstPaint;
+
+ sal_uLong mnPaperWidth;
+
+ std::unique_ptr<SfxProgress> mpProgress;
+
+ /** stores the last used document color.
+ this is changed in onUpdateStyleSettings()
+ */
+ Color maDocColor;
+
+ /** updates the high contrast settings and document color if they changed.
+ @param bForceUpdate forces the method to set all style settings
+ */
+ void onUpdateStyleSettings( bool bForceUpdate );
+
+ /** this link is called from the vcl application when the stylesettings
+ change. Its only purpose is to call onUpdateStyleSettings() then.
+ */
+ DECL_LINK( AppEventListenerHdl, VclSimpleEvent&, void );
+
+ DECL_LINK(EventMultiplexerListener, sd::tools::EventMultiplexerEvent&, void);
+
+ /** holds a model guard during drag and drop between BeginMovingHdl and EndMovingHdl */
+ std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> maDragAndDropModelGuard;
+
+ SvxLRSpaceItem maLRSpaceItem;
+ Image maSlideImage;
+};
+
+// calls IgnoreCurrentPageChangesLevel with true in ctor and with false in dtor
+class OutlineViewPageChangesGuard
+{
+public:
+ OutlineViewPageChangesGuard( OutlineView* pView );
+ ~OutlineViewPageChangesGuard();
+private:
+ OutlineView* mpView;
+};
+
+// calls BeginModelChange() on c'tor and EndModelChange() on d'tor
+class OutlineViewModelChangeGuard
+{
+public:
+ OutlineViewModelChangeGuard( OutlineView& rView );
+ ~OutlineViewModelChangeGuard() COVERITY_NOEXCEPT_FALSE;
+private:
+ OutlineView& mrView;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/OutlineViewShell.hxx b/sd/source/ui/inc/OutlineViewShell.hxx
new file mode 100644
index 000000000..6bc230189
--- /dev/null
+++ b/sd/source/ui/inc/OutlineViewShell.hxx
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ViewShell.hxx"
+#include <glob.hxx>
+
+class SdPage;
+class TransferableDataHelper;
+class TransferableClipboardListener;
+
+namespace sd { class OutlineView; }
+
+namespace sd {
+
+/** Show a textual overview of the text contents of all slides.
+*/
+class OutlineViewShell
+ : public ViewShell
+{
+public:
+
+ SFX_DECL_VIEWFACTORY(OutlineViewShell);
+ SFX_DECL_INTERFACE(SD_IF_SDOUTLINEVIEWSHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ /** Create a new view shell for the outline mode.
+ @param rViewShellBase
+ The new object will be stacked on this view shell base.
+ @param pFrameView
+ The frame view that makes it possible to pass information from
+ one view shell to the next.
+ */
+ OutlineViewShell (
+ SfxViewFrame* pFrame,
+ ViewShellBase& rViewShellBase,
+ vcl::Window* pParentWindow,
+ FrameView* pFrameView);
+
+ virtual ~OutlineViewShell() override;
+
+ virtual void Shutdown() override;
+
+ virtual void Paint(const ::tools::Rectangle& rRect, ::sd::Window* pWin) override;
+
+ /** Arrange and resize the GUI elements like rulers, sliders, and
+ buttons as well as the actual document view according to the size of
+ the enclosing window and current sizes of buttons, rulers, and
+ sliders.
+ */
+ virtual void ArrangeGUIElements() override;
+
+ virtual bool PrepareClose( bool bUI = true ) override;
+
+ virtual void VirtHScrollHdl(ScrollBar* pHScroll) override;
+ virtual void VirtVScrollHdl(ScrollBar* pVHScroll) override;
+
+ virtual void Activate( bool IsMDIActivate ) override;
+ virtual void Deactivate( bool IsMDIActivate ) override;
+
+ virtual SdPage* GetActualPage() override;
+
+ /// inherited from sd::ViewShell
+ virtual SdPage* getCurrentPage() const override;
+
+ void ExecCtrl(SfxRequest &rReq);
+ void GetCtrlState(SfxItemSet &rSet);
+ // FIXME non-virtual override???
+ void GetMenuState(SfxItemSet &rSet);
+ void GetAttrState(SfxItemSet &rSet);
+ void GetState (SfxItemSet& rSet);
+
+ static void ExecStatusBar(SfxRequest& rReq);
+ void GetStatusBarState(SfxItemSet& rSet);
+
+ void FuTemporary(SfxRequest &rReq);
+ void FuTemporaryModify(SfxRequest &rReq);
+ void FuPermanent(SfxRequest &rReq);
+ void FuSupport(SfxRequest &rReq);
+
+ virtual void SetZoom(::tools::Long nZoom) override;
+ virtual void SetZoomRect(const ::tools::Rectangle& rZoomRect) override;
+
+ void Execute(SfxRequest& rReq);
+
+ virtual void ReadFrameViewData(FrameView* pView) override;
+ virtual void WriteFrameViewData() override;
+
+ virtual void Command( const CommandEvent& rCEvt, ::sd::Window* pWin ) override;
+ virtual bool KeyInput(const KeyEvent& rKEvt, ::sd::Window* pWin) override;
+ virtual void MouseButtonUp(const MouseEvent& rMEvt, ::sd::Window* pWin) override;
+
+ ErrCode ReadRtf(SvStream& rInput);
+
+ virtual void WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& ) override;
+ virtual void ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& ) override;
+
+ /** this method is called when the visible area of the view from this viewshell is changed */
+ virtual void VisAreaChanged(const ::tools::Rectangle& rRect) override;
+
+ /** Create an accessible object representing the specified window.
+ @param pWindow
+ The returned object makes the document displayed in this window
+ accessible.
+ @return
+ Returns an <type>AccessibleDrawDocumentView</type> object.
+ */
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ CreateAccessibleDocumentView (::sd::Window* pWindow) override;
+
+ /** Update the preview to show the specified page.
+ */
+ virtual void UpdatePreview (SdPage* pPage) override;
+
+ virtual css::uno::Reference<css::drawing::XDrawSubController> CreateSubController() override;
+
+ /** Make the given page the new current page. This method
+ notifies the controller and adapts the selection of the
+ model.
+ @param pPage
+ The new current page. Pass NULL when there is no current page.
+ */
+ void SetCurrentPage (SdPage* pPage);
+
+ void UpdateTitleObject( SdPage* pPage, Paragraph const * pPara );
+ void UpdateOutlineObject( SdPage* pPage, Paragraph* pPara );
+
+private:
+ OUString m_StrOldPageName;
+ std::unique_ptr<OutlineView> pOlView;
+ SdPage* pLastPage; // For efficient processing of the preview
+ rtl::Reference<TransferableClipboardListener> mxClipEvtLstnr;
+ bool bPastePossible;
+ bool mbInitialized;
+
+ void Construct();
+ DECL_LINK( ClipboardChanged, TransferableDataHelper*, void );
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/OutlineViewShellBase.hxx b/sd/source/ui/inc/OutlineViewShellBase.hxx
new file mode 100644
index 000000000..13527d80d
--- /dev/null
+++ b/sd/source/ui/inc/OutlineViewShellBase.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ImpressViewShellBase.hxx"
+
+namespace sd
+{
+/** This class exists to be able to register a factory that
+ creates an outline view shell as default.
+*/
+class OutlineViewShellBase : public ImpressViewShellBase
+{
+public:
+ SFX_DECL_VIEWFACTORY(OutlineViewShellBase);
+
+ /** This constructor is used by the view factory of the SFX
+ macros.
+ */
+ OutlineViewShellBase(SfxViewFrame* pFrame, SfxViewShell* pOldShell);
+ virtual ~OutlineViewShellBase() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/OutlinerIteratorImpl.hxx b/sd/source/ui/inc/OutlinerIteratorImpl.hxx
new file mode 100644
index 000000000..00be547c0
--- /dev/null
+++ b/sd/source/ui/inc/OutlinerIteratorImpl.hxx
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <OutlinerIterator.hxx>
+#include <memory>
+
+class SdDrawDocument;
+class SdPage;
+class SdrObjListIter;
+
+namespace sd {
+
+class ViewShell;
+
+namespace outliner {
+
+/** Base class for the polymorphic implementation class of the
+ <type>Iterator</type> class. The iterators based on this class are
+ basically uni directional iterators. Their direction can, however, be
+ reversed at any point of their life time.
+*/
+class IteratorImplBase
+{
+public:
+ /** The constructor stores the given arguments to be used by the derived
+ classes.
+ @param pDocument
+ The document provides the information to be iterated on.
+ @param pViewShellWeak
+ Some information has to be taken from the view shell.
+ @param bDirectionIsForward
+ This flag defines the iteration direction. When <TRUE/> then
+ the direction is forwards otherwise it is backwards.
+ */
+ IteratorImplBase (SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward);
+ IteratorImplBase (SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward, PageKind ePageKind, EditMode eEditMode);
+ virtual ~IteratorImplBase();
+
+ /** Advance to the next text of the current object or to the next object.
+ This takes the iteration direction into
+ account. The new object pointed to can be retrieved (among other
+ information) by calling the <member>GetPosition</member> method.
+ */
+ virtual void GotoNextText() = 0;
+ /** Return an object that describes the current object.
+ @return
+ The returned object describes the current object pointed to by
+ the iterator. See the description of
+ <type>IteratorPosition</type> for details on the available
+ information.
+ */
+ virtual const IteratorPosition& GetPosition();
+ /** Create an exact copy of this object. No argument should be
+ specified when called from the outside. It then creates an object
+ first and passes that to the inherited <member>Clone()</member>
+ methods to fill in class specific information.
+ @return
+ Returns a copy of this object. When this method is called with
+ an argument then this value will be returned.
+ */
+ virtual IteratorImplBase* Clone (IteratorImplBase* pObject=nullptr) const;
+ /** Test the equality of the this object and the given iterator. Two
+ iterators are taken to be equal when they point to the same object.
+ Iteration direction is not taken into account.
+ @param rIterator
+ The iterator to compare to.
+ @return
+ When both iterators are equal <TRUE/> is returned, <FALSE/> otherwise.
+ */
+ virtual bool operator== (const IteratorImplBase& rIterator) const;
+ /** This method is used by the equality operator. It is part of a "multimethod" pattern.
+ @param rIterator
+ The iterator to compare to.
+ @return
+ Returns <TRUE/> when both iterators point to the same object.
+ */
+ virtual bool IsEqualSelection(const IteratorImplBase& rIterator) const;
+ /** Reverse the direction of iteration. The current object stays the same.
+ */
+ virtual void Reverse();
+
+protected:
+ /// The current position as returned by <member>GetPosition()</member>.
+ IteratorPosition maPosition;
+ /// The document on whose data the iterator operates.
+ SdDrawDocument* mpDocument;
+ /// Necessary secondary source of information.
+ std::weak_ptr<ViewShell> mpViewShellWeak;
+ /// Specifies the search direction.
+ bool mbDirectionIsForward;
+};
+
+/** Iterator all objects that belong to the current mark list
+ a.k.a. selection. It is assumed that all marked objects belong to the
+ same page. It is further assumed that the mark list does not change
+ while an iterator is alive. It is therefore the responsibility of an
+ iterator's owner to handle the case of a changed mark list.
+
+ <p>For documentation of the methods please refer to the base class
+ <type>IteratorImplBase</type>.</p>
+*/
+class SelectionIteratorImpl
+ : public IteratorImplBase
+{
+public:
+ SelectionIteratorImpl (
+ const ::std::vector< ::tools::WeakReference<SdrObject> >& rObjectList,
+ sal_Int32 nObjectIndex,
+ SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward);
+ SelectionIteratorImpl (const SelectionIteratorImpl& rObject);
+ virtual ~SelectionIteratorImpl() override;
+
+ virtual void GotoNextText() override;
+ virtual const IteratorPosition& GetPosition() override;
+ virtual IteratorImplBase* Clone (IteratorImplBase* pObject = nullptr) const override;
+ virtual bool operator== (const IteratorImplBase& rIterator) const override;
+
+private:
+ const ::std::vector<::tools::WeakReference<SdrObject>>& mrObjectList;
+ sal_Int32 mnObjectIndex;
+
+ /** Compare the given iterator with this object. This method handles
+ only the case that the given iterator is an instance of this class.
+ @param rIterator
+ The iterator to compare to.
+ @return
+ Returns <TRUE/> when both iterators point to the same object.
+ */
+ virtual bool IsEqualSelection(const IteratorImplBase& rIterator) const override;
+
+ IteratorImplBase& operator= (const IteratorImplBase& rIterator);
+};
+
+/** Iterator for iteration over all objects in a single view. On reaching
+ the last object on the last page (or the first object on the first page)
+ the view is *not* switched. Further calls to the
+ <member>GotoNextObject()</member> method will be ignored.
+
+ <p>For documentation of the methods please refer to the base class
+ <type>IteratorImplBase</type>.</p>
+*/
+class ViewIteratorImpl : public IteratorImplBase
+{
+public:
+ ViewIteratorImpl (
+ sal_Int32 nPageIndex,
+ SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward);
+ ViewIteratorImpl (
+ sal_Int32 nPageIndex,
+ SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward,
+ PageKind ePageKind,
+ EditMode eEditMode);
+ virtual ~ViewIteratorImpl() override;
+
+ virtual void GotoNextText() override;
+ virtual IteratorImplBase* Clone (IteratorImplBase* pObject = nullptr) const override;
+ virtual void Reverse() override;
+
+protected:
+ /** Set up page pointer and object list iterator for the specified
+ page.
+ @param nPageIndex
+ Index of the new page. It may lie outside the valid range for
+ page indices.
+ */
+ void SetPage (sal_Int32 nPageIndex);
+
+private:
+ /// Indicates whether a page changed occurred on switching to current page.
+ bool mbPageChangeOccurred;
+ /// Pointer to the page associated with the current page index. May be NULL.
+ SdPage* mpPage;
+ /// Iterator of all objects on the current page.
+ std::unique_ptr<SdrObjListIter> mpObjectIterator;
+
+ // Don't use this operator.
+ ViewIteratorImpl& operator= (const ViewIteratorImpl&) = delete;
+};
+
+/** Iterator for iteration over all objects in all views. It automatically
+ switches views when reaching the end/beginning of a view.
+
+ <p>For documentation of the methods please refer to the base class
+ <type>IteratorImplBase</type>.</p>
+*/
+class DocumentIteratorImpl : public ViewIteratorImpl
+{
+public:
+ DocumentIteratorImpl (
+ sal_Int32 nPageIndex,
+ PageKind ePageKind,
+ EditMode eEditMode,
+ SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward);
+ virtual ~DocumentIteratorImpl() override;
+
+ virtual void GotoNextText() override;
+ virtual IteratorImplBase* Clone (IteratorImplBase* pObject = nullptr) const override;
+
+private:
+ /// Number of pages in the view that is specified by <member>maPosition</member>.
+ sal_Int32 mnPageCount;
+
+ // Don't use this operator.
+ DocumentIteratorImpl& operator= (const DocumentIteratorImpl& ) = delete;
+};
+
+} } // end of namespace ::sd::outliner
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/PaneChildWindows.hxx b/sd/source/ui/inc/PaneChildWindows.hxx
new file mode 100644
index 000000000..e323353ee
--- /dev/null
+++ b/sd/source/ui/inc/PaneChildWindows.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/childwin.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace sd {
+
+/// Base class of Impress and Draw left sidebars/panes.
+class PaneChildWindow
+ : public SfxChildWindow
+{
+public:
+ PaneChildWindow (
+ vcl::Window* pParentWindow,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo,
+ TranslateId pTitleBarResId);
+ virtual ~PaneChildWindow() override;
+};
+
+/// The slide-sorter sidebar (on the left) in Impress.
+class LeftPaneImpressChildWindow
+ : public PaneChildWindow
+{
+public:
+ LeftPaneImpressChildWindow(vcl::Window* pParentWindow, sal_uInt16 nId, SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo);
+
+ SFX_DECL_CHILDWINDOW_WITHID(LeftPaneImpressChildWindow);
+};
+
+/// The pages sidebar (on the left) in Draw.
+class LeftPaneDrawChildWindow
+ : public PaneChildWindow
+{
+public:
+ LeftPaneDrawChildWindow(vcl::Window* pParentWindow, sal_uInt16 nId, SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo);
+
+ SFX_DECL_CHILDWINDOW_WITHID(LeftPaneDrawChildWindow);
+};
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/PaneDockingWindow.hxx b/sd/source/ui/inc/PaneDockingWindow.hxx
new file mode 100644
index 000000000..c69cb6f94
--- /dev/null
+++ b/sd/source/ui/inc/PaneDockingWindow.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "titledockwin.hxx"
+
+namespace sd {
+
+ class PaneDockingWindow : public ::sd::TitledDockingWindow
+{
+public:
+ /** Create a new docking window.
+ @param pBindings
+ Used, among others, to determine the ViewShellBase and
+ PaneManager that manage the new docking window.
+ @param pChildWindow
+ This child window is the logical container for the new docking
+ window.
+ @param pParent
+ The parent window of the new docking window.
+ @param rsTitle
+ the initial title
+ */
+ PaneDockingWindow (
+ SfxBindings *pBindings,
+ SfxChildWindow *pChildWindow,
+ vcl::Window* pParent,
+ const OUString& rsTitle);
+
+ virtual ~PaneDockingWindow() override;
+ virtual void StateChanged( StateChangedType nType ) override;
+ virtual void MouseButtonDown (const MouseEvent& rEvent) override;
+ /** When docked the given range is passed to the parent SplitWindow.
+ */
+ void SetValidSizeRange (const Range& rValidSizeRange);
+
+ enum Orientation { HorizontalOrientation, VerticalOrientation, UnknownOrientation };
+ /** When the PaneDockingWindow is docked and managed by a split window
+ it can derive its orientation from the orientation of the split
+ window and return either HorizontalOrientation or
+ VerticalOrientation.
+ Otherwise UnknownOrientation is returned.
+ */
+ Orientation GetOrientation() const;
+};
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/PaneShells.hxx b/sd/source/ui/inc/PaneShells.hxx
new file mode 100644
index 000000000..fe5809a8f
--- /dev/null
+++ b/sd/source/ui/inc/PaneShells.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/shell.hxx>
+#include <glob.hxx>
+
+namespace sd
+{
+/** Shell that displays the left pane for Impress. The shell does not do
+ anything else and has especially no slots.
+*/
+class LeftImpressPaneShell : public SfxShell
+{
+public:
+ SFX_DECL_INTERFACE(SD_IF_SDLEFTIMPRESSPANESHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ LeftImpressPaneShell();
+ virtual ~LeftImpressPaneShell() override;
+};
+
+/** Shell that displays the left pane for Draw. The shell does not do
+ anything else and has especially no slots.
+*/
+class LeftDrawPaneShell : public SfxShell
+{
+public:
+ SFX_DECL_INTERFACE(SD_IF_SDLEFTDRAWPANESHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ LeftDrawPaneShell();
+ virtual ~LeftDrawPaneShell() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/PresentationViewShell.hxx b/sd/source/ui/inc/PresentationViewShell.hxx
new file mode 100644
index 000000000..f37b31e08
--- /dev/null
+++ b/sd/source/ui/inc/PresentationViewShell.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "DrawViewShell.hxx"
+
+namespace sd
+{
+/** This view shell is responsible for showing the presentation of an
+ Impress document.
+*/
+class PresentationViewShell : public DrawViewShell
+{
+public:
+ SFX_DECL_INTERFACE(SD_IF_SDPRESVIEWSHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ PresentationViewShell(ViewShellBase& rViewShellBase, vcl::Window* pParentWindow,
+ FrameView* pFrameView);
+ virtual ~PresentationViewShell() override;
+
+ /** This method is used by a simple class that passes some
+ arguments from the creator of the new view shell to the new view
+ shell object by waiting for its asynchronous creation.
+ @param pFrameView
+ The frame view that is typically used by the creating object and
+ that shall be shared by the created view shell.
+ */
+ void FinishInitialization(FrameView* pFrameView);
+
+ virtual void Resize() override;
+
+protected:
+ virtual VclPtr<SvxRuler> CreateHRuler(::sd::Window* pWin) override;
+ virtual VclPtr<SvxRuler> CreateVRuler(::sd::Window* pWin) override;
+
+private:
+ ::tools::Rectangle maOldVisArea;
+ ImplSVEvent* mnAbortSlideShowEvent;
+
+ virtual void Activate(bool bIsMDIActivate) override;
+ virtual void Paint(const ::tools::Rectangle& rRect, ::sd::Window* pWin) override;
+
+ DECL_LINK(AbortSlideShowHdl, void*, void);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/PresentationViewShellBase.hxx b/sd/source/ui/inc/PresentationViewShellBase.hxx
new file mode 100644
index 000000000..684e5ee61
--- /dev/null
+++ b/sd/source/ui/inc/PresentationViewShellBase.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ViewShellBase.hxx"
+
+namespace sd
+{
+/** This class exists to be able to register another factory that
+ creates the view shell for the presentation.
+*/
+class PresentationViewShellBase : public ViewShellBase
+{
+public:
+ SFX_DECL_VIEWFACTORY(PresentationViewShellBase);
+
+ /** This constructor is used by the view factory of the SFX
+ macros.
+ */
+ PresentationViewShellBase(SfxViewFrame* pFrame, SfxViewShell* pOldShell);
+ virtual ~PresentationViewShellBase() override;
+
+protected:
+ virtual void InitializeFramework() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/PreviewRenderer.hxx b/sd/source/ui/inc/PreviewRenderer.hxx
new file mode 100644
index 000000000..245f0b638
--- /dev/null
+++ b/sd/source/ui/inc/PreviewRenderer.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 .
+ */
+
+#pragma once
+
+#include <vcl/image.hxx>
+#include <memory>
+
+#include <svl/lstner.hxx>
+
+class SdPage;
+class VirtualDevice;
+
+namespace sd {
+
+class DrawDocShell;
+class DrawView;
+
+class PreviewRenderer
+ : public SfxListener
+{
+public:
+ /** Create a new preview renderer that takes some of its initial values
+ from the given output device.
+ @param bPaintFrame
+ When <TRUE/> (the default) then a frame is painted around the
+ preview. This makes the actual preview smaller.
+ */
+ PreviewRenderer(const bool bPaintFrame = true);
+
+ virtual ~PreviewRenderer() override;
+
+ /** Render a page with the given pixel size.
+ Use this version when only the width of the preview is known to the
+ caller. The height is then calculated according to the aspect
+ ratio of the given page.
+ @param pPage
+ The page to render.
+ @param nWidth
+ The width of the preview in device coordinates.
+ The high contrast mode of the application is
+ ignored and the preview is rendered in normal mode.
+ */
+ Image RenderPage (
+ const SdPage* pPage,
+ const sal_Int32 nWidth);
+
+ /** Render a page with the given pixel size.
+ @param pPage
+ The page to render.
+ @param aPreviewPixelSize
+ The size in device coordinates of the preview.
+ @param bObeyHighContrastMode
+ When <FALSE/> then the high contrast mode of the application is
+ ignored and the preview is rendered in normal mode. When
+ <TRUE/> and high contrast mode is active then the preview is
+ rendered in high contrast mode.
+ @param bDisplayPresentationObjects
+ When <FALSE/> then the PresObj place holders are not displayed
+ in the returned preview.
+ */
+ Image RenderPage (
+ const SdPage* pPage,
+ const Size aPreviewPixelSize,
+ const bool bObeyHighContrastMode,
+ const bool bDisplayPresentationObjects = true);
+
+ /** Render an image that contains the given substitution text instead of a
+ slide preview.
+ @param aPreviewPixelSize
+ The size in device coordinates of the image.
+ */
+ Image RenderSubstitution (
+ const Size& rPreviewPixelSize,
+ const OUString& sSubstitutionText);
+
+ /** Scale the given bitmap by keeping its aspect ratio to the desired
+ width. Add a frame to it afterwards.
+ */
+ Image ScaleBitmap (
+ const BitmapEx& rBitmap,
+ int nWidth);
+
+protected:
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+private:
+ ScopedVclPtr<VirtualDevice> mpPreviewDevice;
+ ::std::unique_ptr<DrawView> mpView;
+ DrawDocShell* mpDocShellOfView;
+ const Color maFrameColor;
+ const bool mbHasFrame;
+ static const int snSubstitutionTextSize;
+ // Width of the frame that is painted around the preview.
+ static const int snFrameWidth;
+
+ bool Initialize (
+ const SdPage* pPage,
+ const Size& rPixelSize,
+ const bool bObeyHighContrastMode);
+ void PaintPage (
+ const SdPage* pPage,
+ const bool bDisplayPresentationObjects);
+ void PaintSubstitutionText (const OUString& rSubstitutionText);
+ void PaintFrame();
+
+ /** Set up the map mode so that the given page is renderer into a bitmap
+ with the specified width.
+ @param rPage
+ The page for which the preview is created.
+ @param rPixelSize
+ The size of the resulting preview bitmap. Note that this size
+ includes the frame. The actual preview is smaller accordingly.
+ */
+ void SetupOutputSize (const SdPage& rPage, const Size& rPixelSize);
+
+ /** When mpView is empty then create a new view and initialize it.
+ Otherwise just initialize it.
+ */
+ void ProvideView (DrawDocShell* pDocShell);
+};
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/RemoteServer.hxx b/sd/source/ui/inc/RemoteServer.hxx
new file mode 100644
index 000000000..965bf7a27
--- /dev/null
+++ b/sd/source/ui/inc/RemoteServer.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <osl/socket_decl.hxx>
+#include <salhelper/thread.hxx>
+
+#include <sddllapi.h>
+
+namespace osl { class Mutex; }
+namespace com::sun::star::presentation { class XSlideShowController; }
+namespace com::sun::star::uno { template <class interface_type> class Reference; }
+
+/**
+* The port for use for the main communication between LibO and remote control app.
+*/
+#define PORT 1599
+
+namespace sd
+{
+ class BufferedStreamSocket;
+ class Communicator;
+
+ struct ClientInfo
+ {
+ OUString mName;
+
+ bool mbIsAlreadyAuthorised;
+
+ ClientInfo( const OUString& rName,
+ const bool bIsAlreadyAuthorised ) :
+ mName( rName ),
+ mbIsAlreadyAuthorised( bIsAlreadyAuthorised ) {}
+
+ virtual ~ClientInfo() {};
+ };
+
+ struct ClientInfoInternal;
+
+ class RemoteServer final : public salhelper::Thread
+ {
+ public:
+ // Internal setup
+ static void setup();
+
+ // For slideshowimpl to inform us.
+ static void presentationStarted( const css::uno::Reference<
+ css::presentation::XSlideShowController > &rController );
+ static void presentationStopped();
+
+ // For the control dialog
+ SD_DLLPUBLIC static std::vector< std::shared_ptr< ClientInfo > > getClients();
+ SD_DLLPUBLIC static bool connectClient( const std::shared_ptr< ClientInfo >& pClient,
+ std::u16string_view aPin );
+ SD_DLLPUBLIC static void deauthoriseClient( const std::shared_ptr< ClientInfo >& pClient );
+
+ /// ensure that discoverability (eg. for Bluetooth) is enabled
+ SD_DLLPUBLIC static void ensureDiscoverable();
+ /// restore the state of discoverability from before ensureDiscoverable
+ SD_DLLPUBLIC static void restoreDiscoverable();
+
+ // For the communicator
+ static void removeCommunicator( Communicator const * pCommunicator );
+ private:
+ RemoteServer();
+ virtual ~RemoteServer() override;
+ static RemoteServer *spServer;
+ static ::osl::Mutex sDataMutex;
+ static ::std::vector<Communicator*> sCommunicators;
+ osl::AcceptorSocket mSocket;
+
+ ::std::vector< std::shared_ptr< ClientInfoInternal > > mAvailableClients;
+
+ void execute() override;
+ void handleAcceptedConnection( BufferedStreamSocket *pSocket ) ;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/Ruler.hxx b/sd/source/ui/inc/Ruler.hxx
new file mode 100644
index 000000000..5cf1d18bb
--- /dev/null
+++ b/sd/source/ui/inc/Ruler.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/ruler.hxx>
+
+namespace sd {
+
+class DrawViewShell;
+class RulerCtrlItem;
+class Window;
+
+class Ruler final
+ : public SvxRuler
+{
+public:
+ Ruler (
+ DrawViewShell& rViewSh,
+ vcl::Window* pParent,
+ ::sd::Window* pWin,
+ SvxRulerSupportFlags nRulerFlags,
+ SfxBindings& rBindings,
+ WinBits nWinStyle);
+ virtual ~Ruler() override;
+ virtual void dispose() override;
+
+ void SetNullOffset(const Point& rOffset);
+
+ bool IsHorizontal() const { return bHorz; }
+
+ using ::Ruler::SetNullOffset;
+
+private:
+ DrawViewShell* pDrViewShell;
+ std::unique_ptr<RulerCtrlItem> pCtrlItem;
+ bool bHorz;
+
+ virtual void MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual void Command(const CommandEvent& rCEvt) override;
+ virtual void ExtraDown() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/SdUnoDrawView.hxx b/sd/source/ui/inc/SdUnoDrawView.hxx
new file mode 100644
index 000000000..6b62e4cb2
--- /dev/null
+++ b/sd/source/ui/inc/SdUnoDrawView.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "DrawSubController.hxx"
+#include <cppuhelper/basemutex.hxx>
+
+class SdXImpressDocument;
+namespace com::sun::star::drawing { class XLayer; }
+
+namespace sd {
+
+class DrawViewShell;
+class View;
+
+/** This class implements the DrawViewShell specific part of the controller.
+*/
+class SdUnoDrawView final
+ : private cppu::BaseMutex,
+ public DrawSubControllerInterfaceBase
+{
+public:
+ SdUnoDrawView (
+ DrawViewShell& rViewShell,
+ View& rView) noexcept;
+ virtual ~SdUnoDrawView() noexcept override;
+
+ // XSelectionSupplier
+
+ virtual sal_Bool SAL_CALL select (
+ const css::uno::Any& aSelection) override;
+
+ virtual css::uno::Any SAL_CALL getSelection() override;
+
+ virtual void SAL_CALL addSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>& rxListener) override;
+
+ virtual void SAL_CALL removeSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>& rxListener) override;
+
+ // XDrawView
+
+ virtual void SAL_CALL setCurrentPage (
+ const css::uno::Reference<css::drawing::XDrawPage >& xPage) override;
+
+ virtual css::uno::Reference<css::drawing::XDrawPage> SAL_CALL getCurrentPage() override;
+
+ // XFastPropertySet
+
+ virtual void SAL_CALL setFastPropertyValue (
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+
+ virtual css::uno::Any SAL_CALL getFastPropertyValue (
+ sal_Int32 nHandle) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ /** Return a reference to the active layer object.
+ @return
+ The returned value may be empty when the internal state of this
+ view is not valid (like during destruction.)
+ */
+ css::uno::Reference< css::drawing::XLayer> getActiveLayer() const;
+
+private:
+ bool getMasterPageMode() const noexcept;
+ void setMasterPageMode(bool MasterPageMode_) noexcept;
+ bool getLayerMode() const noexcept;
+ void setLayerMode(bool LayerMode_) noexcept;
+ /** Make the specified object the active layer.
+ @param rxLayer
+ The new layer object.
+ @throws css::uno::RuntimeException
+ */
+ void setActiveLayer (const css::uno::Reference< css::drawing::XLayer>& rxLayer);
+
+ void SetZoom( sal_Int16 nZoom );
+ sal_Int16 GetZoom() const;
+
+ void SetViewOffset(const css::awt::Point& rWinPos );
+ css::awt::Point GetViewOffset() const;
+
+ void SetZoomType( sal_Int16 nType );
+
+ css::uno::Any getDrawViewMode() const;
+
+ SdXImpressDocument* GetModel() const noexcept;
+
+ DrawViewShell& mrDrawViewShell;
+ sd::View& mrView;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/SdUnoOutlineView.hxx b/sd/source/ui/inc/SdUnoOutlineView.hxx
new file mode 100644
index 000000000..2789cabee
--- /dev/null
+++ b/sd/source/ui/inc/SdUnoOutlineView.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "DrawSubController.hxx"
+#include <cppuhelper/basemutex.hxx>
+
+namespace sd {
+
+class OutlineViewShell;
+
+/** This class implements the OutlineViewShell specific part of the controller.
+*/
+class SdUnoOutlineView final
+ : private cppu::BaseMutex,
+ public DrawSubControllerInterfaceBase
+{
+public:
+ SdUnoOutlineView (
+ OutlineViewShell& rViewShell) noexcept;
+ virtual ~SdUnoOutlineView() noexcept override;
+
+ virtual void SAL_CALL disposing() override;
+
+ // XSelectionSupplier
+
+ virtual sal_Bool SAL_CALL select (
+ const css::uno::Any& aSelection) override;
+
+ virtual css::uno::Any SAL_CALL getSelection() override;
+
+ virtual void SAL_CALL addSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>& rxListener) override;
+
+ virtual void SAL_CALL removeSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>& rxListener) override;
+
+ // XDrawView
+
+ virtual void SAL_CALL setCurrentPage (
+ const css::uno::Reference<css::drawing::XDrawPage >& xPage) override;
+
+ virtual css::uno::Reference<css::drawing::XDrawPage> SAL_CALL getCurrentPage() override;
+
+ // XFastPropertySet
+
+ virtual void SAL_CALL setFastPropertyValue (
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+
+ virtual css::uno::Any SAL_CALL getFastPropertyValue (
+ sal_Int32 nHandle) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+ OutlineViewShell& mrOutlineViewShell;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/SdUnoSlideView.hxx b/sd/source/ui/inc/SdUnoSlideView.hxx
new file mode 100644
index 000000000..7ca40a1ab
--- /dev/null
+++ b/sd/source/ui/inc/SdUnoSlideView.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "DrawSubController.hxx"
+#include <cppuhelper/basemutex.hxx>
+
+namespace sd::slidesorter { class SlideSorter; }
+namespace com::sun::star::drawing { class XDrawPage; }
+
+namespace sd {
+
+/** This class implements the SlideSorter specific part of the
+ controller.
+ */
+class SdUnoSlideView final
+ : private cppu::BaseMutex,
+ public DrawSubControllerInterfaceBase
+{
+public:
+ SdUnoSlideView (
+ slidesorter::SlideSorter& rSlideSorter) noexcept;
+ virtual ~SdUnoSlideView() noexcept override;
+
+ // XSelectionSupplier
+
+ virtual sal_Bool SAL_CALL select (const css::uno::Any& aSelection) override;
+
+ virtual css::uno::Any SAL_CALL getSelection() override;
+
+ virtual void SAL_CALL addSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>& rxListener) override;
+
+ virtual void SAL_CALL removeSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>& rxListener) override;
+
+ // XDrawView
+
+ virtual void SAL_CALL setCurrentPage (
+ const css::uno::Reference< css::drawing::XDrawPage >& xPage) override;
+
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL
+ getCurrentPage() override;
+
+ // XFastPropertySet
+
+ virtual void SAL_CALL setFastPropertyValue (
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+
+ virtual css::uno::Any SAL_CALL getFastPropertyValue (
+ sal_Int32 nHandle) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+ slidesorter::SlideSorter& mrSlideSorter;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ShellFactory.hxx b/sd/source/ui/inc/ShellFactory.hxx
new file mode 100644
index 000000000..fc05c41ab
--- /dev/null
+++ b/sd/source/ui/inc/ShellFactory.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/toolbarids.hxx>
+
+namespace sd
+{
+typedef ToolbarId ShellId;
+
+template <class ShellType> class ShellFactory
+{
+public:
+ /** This abstract virtual class needs a destructor so that the
+ destructors of derived classes are called.
+ */
+ virtual ~ShellFactory(){};
+
+ /** Create a new instance of a view shell for the given id that will
+ be stacked onto the given view shell base.
+ @return
+ Return the new view shell or NULL when a creation is not
+ possible.
+ */
+ virtual ShellType* CreateShell(ShellId nId) = 0;
+
+ /** Tell the factory that a shell is no longer in use. It may destroy
+ it or put it for future use in a cache.
+ */
+ virtual void ReleaseShell(ShellType* pShell) = 0;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/SlideSorter.hxx b/sd/source/ui/inc/SlideSorter.hxx
new file mode 100644
index 000000000..9ed70cf9b
--- /dev/null
+++ b/sd/source/ui/inc/SlideSorter.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <cppuhelper/weakref.hxx>
+#include <vcl/scrbar.hxx>
+#include <sddllapi.h>
+#include <memory>
+
+namespace vcl { class Window; }
+namespace com::sun::star::frame { class XController; }
+namespace rtl { template <class reference_type> class Reference; }
+
+namespace sd {
+class ViewShell;
+class ViewShellBase;
+class Window;
+class FuPoor;
+}
+
+namespace sd::slidesorter::model { class SlideSorterModel; }
+
+namespace sd::slidesorter::view {
+ class SlideSorterView;
+ class Theme;
+}
+
+namespace sd::slidesorter::controller {
+ class SlideSorterController;
+ class SlotManager;
+ class Properties;
+}
+
+namespace sd::slidesorter {
+
+/** Show previews for all the slides in a document and allow the user to
+ insert or delete slides and modify the order of the slides.
+
+ This class is a facade for the model, view, and controller classes.
+ It is a hub that allows access to the various parts of a slide sorter.
+
+ Note that this class is not in its final state.
+*/
+class SlideSorter final
+{
+ friend class controller::SlotManager;
+public:
+ ~SlideSorter();
+
+ /// Forbid copy construction and copy assignment
+ SlideSorter(const SlideSorter&) = delete;
+ SlideSorter& operator=(const SlideSorter&) = delete;
+
+ /** Return whether the called SlideSorter object is valid and calling
+ its Get(Model,View,Controller) methods is safe. When <FALSE/> is
+ called then no other methods should be called.
+ Calling this method should be necessary only during startup and
+ shutdown (when that can be detected).
+ */
+ bool IsValid() const { return mbIsValid;}
+
+ /** Create a new slide sorter that is strongly coupled to the given view
+ shell. Use this function for a slide sorter in the left pane.
+ @param rViewShell
+ Typically a SlideSorterViewShell object.
+ @param rpContentWindow
+ Typically the content window of the ViewShell.
+ @param rpHorizontalScrollBar
+ Typically the horizontal scroll bar of the ViewShell.
+ @param rpVerticalScrollBar
+ Typically the vertical scroll bar of the ViewShell.
+ @param rpScrollBarBox
+ The little square enclosed by the two scroll bars. Typically
+ the one from the ViewShell.
+ */
+ static std::shared_ptr<SlideSorter> CreateSlideSorter (
+ ViewShell& rViewShell,
+ sd::Window* pContentWindow,
+ ScrollBar* pHorizontalScrollBar,
+ ScrollBar* pVerticalScrollBar,
+ ScrollBarBox* pScrollBarBox);
+
+ /** Create a new slide sorter that is loosely coupled to the given view
+ shell. The view shell may even be missing.
+ @param rBase
+ ViewShellBase object of the enclosing application.
+ @param pViewShell
+ Supply when at hand.
+ @param rParentWindow
+ The parent window of the internally created content window and
+ scroll bars.
+ */
+ static std::shared_ptr<SlideSorter> CreateSlideSorter (
+ ViewShellBase& rBase,
+ vcl::Window& rParentWindow);
+
+ /** Return the control of the vertical scroll bar.
+ */
+ const VclPtr<ScrollBar>& GetVerticalScrollBar() const { return mpVerticalScrollBar;}
+
+ /** Return the control of the horizontal scroll bar.
+ */
+ const VclPtr<ScrollBar>& GetHorizontalScrollBar() const { return mpHorizontalScrollBar;}
+
+ /** Return the scroll bar filler that paints the little square that is
+ enclosed by the two scroll bars.
+ */
+ const VclPtr<ScrollBarBox>& GetScrollBarFiller (void) const { return mpScrollBarBox;}
+
+ /** Return the content window. This is a sibling and is geometrically
+ enclosed by the scroll bars.
+ */
+ const VclPtr<sd::Window>& GetContentWindow() const { return mpContentWindow;}
+
+ model::SlideSorterModel& GetModel() const;
+
+ view::SlideSorterView& GetView() const;
+
+ // Exported for unit test
+ SD_DLLPUBLIC controller::SlideSorterController& GetController() const;
+
+ /** Return the view shell that was given at construction.
+ @return
+ May be empty.
+ */
+ ViewShell* GetViewShell() const { return mpViewShell;}
+
+ /** Return the XController object of the main view.
+ */
+ css::uno::Reference<css::frame::XController>
+ GetXController() const;
+
+ /** Return the ViewShellBase object.
+ @return
+ May be empty.
+ */
+ ViewShellBase* GetViewShellBase() const { return mpViewShellBase;}
+
+ void Paint (const ::tools::Rectangle& rRepaintArea);
+
+ /** Place and size the controls and windows. You may want to call this
+ method when something has changed that for instance affects the
+ visibility state of the scroll bars.
+ */
+ void ArrangeGUIElements (
+ const Point& rOffset,
+ const Size& rSize);
+
+ void RelocateToWindow (vcl::Window* pWindow);
+
+ /** Set the current function at the view shell or, when it is not
+ present, set it at the content window. This method supports the use
+ of functions even when there is no SlideSorterViewShell.
+ */
+ void SetCurrentFunction (const rtl::Reference<FuPoor>& rpFunction);
+
+ /** Return a collection of properties that are used throughout the slide
+ sorter.
+ */
+ std::shared_ptr<controller::Properties> const & GetProperties() const;
+
+ /** Return the active theme which gives access to colors and fonts.
+ */
+ std::shared_ptr<view::Theme> const & GetTheme() const;
+
+private:
+ /** This virtual method makes it possible to create a specialization of
+ the slide sorter view shell that works with its own implementation
+ of model, view, and controller. The default implementation simply
+ calls the CreateModel(), CreateView(), and CreateController()
+ methods in this order.
+ */
+ void CreateModelViewController();
+
+ /** Create the model for the view shell. When called from the default
+ implementation of CreateModelViewController() then neither view nor
+ controller do exist. Test their pointers when in doubt.
+ */
+ model::SlideSorterModel* CreateModel();
+
+ bool mbIsValid;
+
+ std::unique_ptr<controller::SlideSorterController> mpSlideSorterController;
+ std::unique_ptr<model::SlideSorterModel> mpSlideSorterModel;
+ std::unique_ptr<view::SlideSorterView> mpSlideSorterView;
+ css::uno::WeakReference<css::frame::XController> mxControllerWeak;
+ ViewShell* mpViewShell;
+ ViewShellBase* mpViewShellBase;
+ VclPtr<sd::Window> mpContentWindow;
+ VclPtr<ScrollBar> mpHorizontalScrollBar;
+ VclPtr<ScrollBar> mpVerticalScrollBar;
+ VclPtr<ScrollBarBox> mpScrollBarBox;
+
+ /** Some slide sorter wide properties that are used in different
+ classes.
+ */
+ std::shared_ptr<controller::Properties> mpProperties;
+ std::shared_ptr<view::Theme> mpTheme;
+
+ SlideSorter (
+ ViewShell& rViewShell,
+ sd::Window* pContentWindow,
+ ScrollBar* pHorizontalScrollBar,
+ ScrollBar* pVerticalScrollBar,
+ ScrollBarBox* pScrollBarBox);
+ SlideSorter (
+ ViewShellBase& rBase,
+ vcl::Window& rParentWindow);
+
+ void Init();
+ /** Create the controls for the slide sorter. This are the tab bar
+ for switching the edit mode, the scroll bar, and the actual
+ slide sorter view window.
+ This method is usually called exactly one time from the
+ constructor.
+ */
+ void SetupControls();
+
+ /** This method is usually called exactly one time from the
+ constructor.
+ */
+ void SetupListeners();
+
+ /** Release the listeners that have been installed in SetupListeners().
+ */
+ void ReleaseListeners();
+};
+
+} // end of namespace ::sd::slidesorter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/SlideSorterViewShell.hxx b/sd/source/ui/inc/SlideSorterViewShell.hxx
new file mode 100644
index 000000000..64808d434
--- /dev/null
+++ b/sd/source/ui/inc/SlideSorterViewShell.hxx
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ViewShell.hxx"
+#include <glob.hxx>
+#include <sfx2/shell.hxx>
+#include <sddllapi.h>
+#include <memory>
+#include <vector>
+
+namespace sd::slidesorter::controller { class SlotManager; }
+
+namespace sd::slidesorter {
+
+class SlideSorter;
+
+class SAL_DLLPUBLIC_RTTI SlideSorterViewShell final
+ : public ViewShell
+{
+ friend class controller::SlotManager;
+
+public:
+ SFX_DECL_INTERFACE(SD_IF_SDSLIDESORTERVIEWSHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ static std::shared_ptr<SlideSorterViewShell> Create(
+ SfxViewFrame* pFrame,
+ ViewShellBase& rViewShellBase,
+ vcl::Window* pParentWindow,
+ FrameView* pFrameView);
+
+ virtual ~SlideSorterViewShell() override;
+
+ /** Late initialization that has to be called after a new instance has
+ completed its construction.
+ */
+ virtual void Init (bool bIsMainViewShell) override;
+
+ /** Return a slide sorter that is currently displayed in one of the
+ panes that belong to the given ViewShellBase object.
+ When there is only one slide sorter visible then that one is
+ returned. When two (or more) are visible then the one in the center
+ pane is returned. When no slidesorter is visible then NULL is
+ returned.
+ */
+ // Exported for unit test
+ SD_DLLPUBLIC static SlideSorterViewShell* GetSlideSorter(ViewShellBase& rBase);
+
+ virtual SdPage* GetActualPage() override;
+
+ /// inherited from sd::ViewShell
+ virtual SdPage* getCurrentPage() const override;
+
+ void ExecCtrl (SfxRequest& rRequest);
+ void GetCtrlState (SfxItemSet &rSet);
+ void FuSupport (SfxRequest& rRequest);
+ void FuTemporary (SfxRequest& rRequest);
+ void GetStatusBarState (SfxItemSet& rSet);
+ void FuPermanent (SfxRequest& rRequest);
+ void GetAttrState (SfxItemSet& rSet);
+ static void ExecStatusBar (SfxRequest& rRequest);
+ virtual void Command (const CommandEvent& rEvent, ::sd::Window* pWindow) override;
+ void GetMenuState (SfxItemSet &rSet);
+ void GetClipboardState (SfxItemSet &rSet);
+
+ virtual void ReadFrameViewData (FrameView* pView) override;
+ virtual void WriteFrameViewData() override;
+
+ /** Set the zoom factor. The given value is clipped against an upper
+ bound.
+ @param nZoom
+ An integer percent value, i.e. nZoom/100 is the actual zoom
+ factor.
+ */
+ virtual void SetZoom (::tools::Long nZoom) override;
+ virtual void SetZoomRect (const ::tools::Rectangle& rZoomRect) override;
+
+ /** This is a callback method used by the active window to delegate its
+ Paint() call to. This view shell itself delegates it to the view.
+ */
+ virtual void Paint(const ::tools::Rectangle& rRect, ::sd::Window* pWin) override;
+
+ /** Place and size the controls and windows. You may want to call this
+ method when something has changed that for instance affects the
+ visibility state of the scroll bars.
+ */
+ virtual void ArrangeGUIElements() override;
+
+ virtual void Activate (bool IsMDIActivate) override;
+ virtual void Deactivate (bool IsMDIActivate) override;
+
+ /** Move slides up and down. Mainly uno commands. */
+ void ExecMovePageUp (SfxRequest& rReq);
+ void GetStateMovePageUp (SfxItemSet& rSet);
+
+ void ExecMovePageDown (SfxRequest& rReq);
+ void GetStateMovePageDown (SfxItemSet& rSet);
+
+ void ExecMovePageFirst (SfxRequest& rReq);
+ void GetStateMovePageFirst (SfxItemSet& rSet);
+
+ void ExecMovePageLast (SfxRequest& rReq);
+ void GetStateMovePageLast (SfxItemSet& rSet);
+
+
+ //===== Drag and Drop =====================================================
+
+ void StartDrag (
+ const Point& rDragPt,
+ vcl::Window* pWindow );
+ virtual sal_Int8 AcceptDrop (
+ const AcceptDropEvent& rEvt,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer ) override;
+ virtual sal_Int8 ExecuteDrop (
+ const ExecuteDropEvent& rEvt,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer) override;
+
+ typedef ::std::vector<SdPage*> PageSelection;
+
+ /** Return the set of selected pages.
+ */
+ std::shared_ptr<PageSelection> GetPageSelection() const;
+
+ void SetPageSelection (const std::shared_ptr<PageSelection>& rSelection);
+
+ /** Add a listener that is called when the selection of the slide sorter
+ changes.
+ @param rListener
+ When this method is called multiple times for the same listener
+ the second and all following calls are ignored. Each listener
+ is added only once.
+ */
+ void AddSelectionChangeListener (const Link<LinkParamNone*,void>& rListener);
+
+ /** Remove a listener that was called when the selection of the slide
+ sorter changes.
+ @param rListener
+ It is safe to pass a listener that was not added are has been
+ removed previously. Such calls are ignored.
+ */
+ void RemoveSelectionChangeListener (const Link<LinkParamNone*,void>& rListener);
+
+ virtual css::uno::Reference<css::drawing::XDrawSubController> CreateSubController() override;
+
+ /** Create an accessible object representing the specified window.
+ @param pWindow
+ The returned object makes the document displayed in this window
+ accessible.
+ @return
+ Returns an <type>AccessibleSlideSorterView</type> object.
+ */
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ CreateAccessibleDocumentView (::sd::Window* pWindow) override;
+ // handle SlideSorterView specially because AccessibleSlideSorterView doesn't inherit from AccessibleDocumentViewBase
+ virtual void SwitchViewFireFocus( const css::uno::Reference< css::accessibility::XAccessible >& xAcc ) override;
+
+ // Exported for unit test
+ SD_DLLPUBLIC SlideSorter& GetSlideSorter() const;
+
+ /** Try to relocate all toplevel window elements to the given parent
+ window.
+ */
+ virtual bool RelocateToParentWindow (vcl::Window* pParentWindow) override;
+
+private:
+
+ /** Override this method to handle a missing tool bar correctly.
+ This is the case when the slide sorter is not the main view shell.
+ */
+ virtual SfxUndoManager* ImpGetUndoManager() const override;
+
+ std::shared_ptr<SlideSorter> mpSlideSorter;
+ bool mbIsArrangeGUIElementsPending;
+
+ SlideSorterViewShell (
+ SfxViewFrame* pFrame,
+ ViewShellBase& rViewShellBase,
+ vcl::Window* pParentWindow,
+ FrameView* pFrameView);
+ void Initialize();
+
+ /** This method overwrites the one from our base class: We do our own
+ scroll bar and the base class call is thus unnecessary. It simply
+ calls UpdateScrollBars(false).
+ */
+ virtual void UpdateScrollBars() override;
+
+ void PostMoveSlidesActions(const std::shared_ptr<SlideSorterViewShell::PageSelection> &rpSelection);
+
+ void MainViewEndEditAndUnmarkAll();
+
+ /** Select the same pages in the document as are selected in the
+ SlideSorterViewShell
+
+ return the page numbers of the first and last selected pages
+ */
+ std::pair<sal_uInt16, sal_uInt16> SyncPageSelectionToDocument(const std::shared_ptr<SlideSorterViewShell::PageSelection> &rpSelection);
+};
+
+typedef std::shared_ptr<SlideSorterViewShell::PageSelection> SharedPageSelection;
+
+} // end of namespace ::sd::slidesorter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/SlideSorterViewShellBase.hxx b/sd/source/ui/inc/SlideSorterViewShellBase.hxx
new file mode 100644
index 000000000..e1ca1b57b
--- /dev/null
+++ b/sd/source/ui/inc/SlideSorterViewShellBase.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ImpressViewShellBase.hxx"
+
+namespace sd
+{
+/** This class exists to be able to register a factory that creates a
+ slide sorter view shell as default.
+*/
+class SlideSorterViewShellBase final : public ImpressViewShellBase
+{
+public:
+ SFX_DECL_VIEWFACTORY(SlideSorterViewShellBase);
+
+ /** This constructor is used by the view factory of the SFX
+ macros.
+ */
+ SlideSorterViewShellBase(SfxViewFrame* pFrame, SfxViewShell* pOldShell);
+ virtual ~SlideSorterViewShellBase() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/SlideTransitionPane.hxx b/sd/source/ui/inc/SlideTransitionPane.hxx
new file mode 100644
index 000000000..2b6ea8f93
--- /dev/null
+++ b/sd/source/ui/inc/SlideTransitionPane.hxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "SlideSorterViewShell.hxx"
+
+#include <svtools/valueset.hxx>
+#include <sfx2/sidebar/ILayoutableWindow.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <vcl/weld.hxx>
+
+#include <vector>
+#include <map>
+
+class SdDrawDocument;
+
+namespace com::sun::star::drawing { class XDrawView; }
+namespace com::sun::star::frame { class XModel; }
+namespace sd::tools { class EventMultiplexerEvent; }
+
+namespace sd
+{
+
+class TransitionPane;
+class ViewShellBase;
+
+namespace impl
+{
+ struct TransitionEffect;
+}
+
+class SlideTransitionPane final : public PanelLayout
+ , public sfx2::sidebar::ILayoutableWindow
+{
+public:
+ explicit SlideTransitionPane(
+ weld::Widget* pParent,
+ ViewShellBase & rBase);
+ virtual ~SlideTransitionPane() override;
+
+ // ILayoutableWindow
+ virtual css::ui::LayoutSize GetHeightForWidth (const sal_Int32 nWidth) override;
+
+ void onSelectionChanged();
+ void onChangeCurrentPage();
+
+private:
+ void updateControls();
+ void updateControlState();
+ void updateVariants(size_t nPresetOffset);
+
+ void updateSoundList();
+ void openSoundFileDialog();
+
+ impl::TransitionEffect getTransitionEffectFromControls() const;
+
+ void applyToSelectedPages(bool bPreview);
+ void playCurrentEffect();
+
+ void addListener();
+ void removeListener();
+
+ ::sd::slidesorter::SharedPageSelection getSelectedPages() const;
+
+ void Initialize(SdDrawDocument* pDoc);
+
+ DECL_LINK( ApplyToAllButtonClicked, weld::Button&, void );
+ DECL_LINK( PlayButtonClicked, weld::Button&, void );
+ DECL_LINK( AutoPreviewClicked, weld::Toggleable&, void );
+
+ DECL_LINK( TransitionSelected, ValueSet*, void );
+ DECL_LINK( AdvanceSlideRadioButtonToggled, weld::Toggleable&, void );
+ DECL_LINK( AdvanceTimeModified, weld::MetricSpinButton&, void );
+ DECL_LINK( VariantListBoxSelected, weld::ComboBox&, void );
+ DECL_LINK( DurationModifiedHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( DurationLoseFocusHdl, weld::Widget&, void );
+ DECL_LINK( SoundListBoxSelected, weld::ComboBox&, void );
+ DECL_LINK( LoopSoundBoxChecked, weld::Toggleable&, void );
+ DECL_LINK( EventMultiplexerListener, tools::EventMultiplexerEvent&, void );
+ DECL_LINK(LateInitCallback, Timer *, void);
+
+ ViewShellBase & mrBase;
+ SdDrawDocument * mpDrawDoc;
+
+ std::unique_ptr<TransitionPane> mxVS_TRANSITION_ICONS;
+ std::unique_ptr<weld::CustomWeld> mxVS_TRANSITION_ICONSWin;
+ std::unique_ptr<weld::Label> mxFT_VARIANT;
+ std::unique_ptr<weld::ComboBox> mxLB_VARIANT;
+ std::unique_ptr<weld::Label> mxFT_duration;
+ std::unique_ptr<weld::MetricSpinButton> mxCBX_duration;
+ std::unique_ptr<weld::Label> mxFT_SOUND;
+ std::unique_ptr<weld::ComboBox> mxLB_SOUND;
+ std::unique_ptr<weld::CheckButton> mxCB_LOOP_SOUND;
+ std::unique_ptr<weld::RadioButton> mxRB_ADVANCE_ON_MOUSE;
+ std::unique_ptr<weld::RadioButton> mxRB_ADVANCE_AUTO;
+ std::unique_ptr<weld::MetricSpinButton> mxMF_ADVANCE_AUTO_AFTER;
+ std::unique_ptr<weld::Button> mxPB_APPLY_TO_ALL;
+ std::unique_ptr<weld::Button> mxPB_PLAY;
+ std::unique_ptr<weld::CheckButton> mxCB_AUTO_PREVIEW;
+
+ css::uno::Reference< css::drawing::XDrawView > mxView;
+ css::uno::Reference< css::frame::XModel > mxModel;
+
+ bool mbHasSelection;
+ bool mbUpdatingControls;
+ bool mbIsMainViewChangePending;
+
+ std::vector<OUString> maSoundList;
+ mutable OUString maCurrentSoundFile;
+
+ // How many variants each transition set has
+ std::map< OUString, int > m_aNumVariants;
+
+ Timer maLateInitTimer;
+};
+
+} // namespace sd
+
+// INCLUDED_SD_SOURCE_UI_ANIMATIONS_SLIDETRANSITIONPANE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/SpellDialogChildWindow.hxx b/sd/source/ui/inc/SpellDialogChildWindow.hxx
new file mode 100644
index 000000000..3d2163a7e
--- /dev/null
+++ b/sd/source/ui/inc/SpellDialogChildWindow.hxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/SpellDialogChildWindow.hxx>
+#include <svl/lstner.hxx>
+
+class SdOutliner;
+
+namespace sd
+{
+/** This derivation of the svx::SpellDialogChildWindow base class
+ provides Draw and Impress specific implementations of
+ GetNextWrongSentence() and ApplyChangedSentence().
+*/
+class SpellDialogChildWindow final : public svx::SpellDialogChildWindow, public SfxListener
+{
+public:
+ SpellDialogChildWindow(vcl::Window* pParent, sal_uInt16 nId, SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo);
+ virtual ~SpellDialogChildWindow() override;
+
+ /** This method makes the one from the base class public so that
+ it can be called from the view shell when one is created.
+ */
+ void InvalidateSpellDialog();
+
+ // SfxListener
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+ SFX_DECL_CHILDWINDOW_WITHID(SpellDialogChildWindow);
+
+private:
+ /** Iterate over the sentences in all text shapes and stop at the
+ next sentence with spelling errors. While doing so the view
+ mode may be changed and text shapes are set into edit mode.
+ */
+ virtual svx::SpellPortions GetNextWrongSentence(bool bRecheck) override;
+
+ /** This method is responsible for merging corrections made in the
+ spelling dialog back into the document.
+ */
+ virtual void ApplyChangedSentence(const svx::SpellPortions& rChanged, bool bRecheck) override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+
+ /** This outliner is used to do the main work of iterating over a
+ document and finding sentences with spelling errors.
+ */
+ SdOutliner* mpSdOutliner;
+
+ /** When this flag is <TRUE/> then eventually we have to destroy
+ the outliner in mpSdOutliner.
+ */
+ bool mbOwnOutliner;
+
+ /** Provide an outliner in the mpSdOutliner data member. When the
+ view shell has changed since the last call this include the
+ deletion/release of formerly created/obtained one prior to
+ construction/obtaining of a new one.
+ */
+ void ProvideOutliner();
+
+ void EndSpellingAndClearOutliner();
+};
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/TabControl.hxx b/sd/source/ui/inc/TabControl.hxx
new file mode 100644
index 000000000..5e5eba7bb
--- /dev/null
+++ b/sd/source/ui/inc/TabControl.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svtools/tabbar.hxx>
+#include <vcl/transfer.hxx>
+
+namespace sd {
+
+/**
+ * TabControl-Class for page switch
+ */
+
+class DrawViewShell;
+
+class TabControl final
+ : public TabBar,
+ public DragSourceHelper,
+ public DropTargetHelper
+{
+public:
+ TabControl (DrawViewShell* pDrViewSh, vcl::Window* pParent);
+ virtual void dispose() override;
+ virtual ~TabControl() override;
+
+ /** Inform all listeners of this control that the current page has been
+ activated. Call this method after switching the current page and is
+ not done elsewhere (like when using page up/down keys).
+ */
+ void SendActivatePageEvent();
+
+ /** Inform all listeners of this control that the current page has been
+ deactivated. Call this method before switching the current page and
+ is not done elsewhere (like when using page up/down keys).
+ */
+ void SendDeactivatePageEvent();
+
+private:
+ DrawViewShell* pDrViewSh;
+ bool bInternalMove;
+
+ // TabBar
+ virtual void Select() override;
+ virtual void DoubleClick() override;
+ virtual void MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Command(const CommandEvent& rCEvt) override;
+
+ virtual bool StartRenaming() override;
+ virtual TabBarAllowRenamingReturnCode AllowRenaming() override;
+ virtual void EndRenaming() override;
+
+ virtual void ActivatePage() override;
+ virtual bool DeactivatePage() override;
+
+ // DragSourceHelper
+ virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override;
+
+ // DropTargetHelper
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+ // nested class to implement the TransferableHelper
+ class TabControlTransferable final : public TransferableHelper
+ {
+ public:
+ explicit TabControlTransferable( TabControl& rParent ) :
+ mrParent( rParent ) {}
+ private:
+
+ TabControl& mrParent;
+
+ virtual ~TabControlTransferable() override;
+
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ virtual void DragFinished( sal_Int8 nDropAction ) override;
+
+ };
+
+ friend class TabControl::TabControlTransferable;
+
+ void DragFinished();
+
+ using TabBar::StartDrag;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/TableDesignPane.hxx b/sd/source/ui/inc/TableDesignPane.hxx
new file mode 100644
index 000000000..042eb6137
--- /dev/null
+++ b/sd/source/ui/inc/TableDesignPane.hxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svtools/valueset.hxx>
+#include <sfx2/sidebar/ILayoutableWindow.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <vcl/weld.hxx>
+
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::container { class XIndexAccess; }
+namespace com::sun::star::drawing { class XDrawView; }
+
+namespace sd
+{
+
+namespace tools {
+class EventMultiplexerEvent;
+}
+
+class ViewShellBase;
+
+enum TableCheckBox : sal_uInt16
+{
+ CB_HEADER_ROW = 0,
+ CB_TOTAL_ROW = 1,
+ CB_BANDED_ROWS = 2,
+ CB_FIRST_COLUMN = 3,
+ CB_LAST_COLUMN = 4,
+ CB_BANDED_COLUMNS = 5,
+ CB_COUNT = CB_BANDED_COLUMNS + 1
+};
+
+class TableValueSet final : public ValueSet
+{
+private:
+ bool m_bModal;
+public:
+ TableValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow);
+ virtual void Resize() override;
+ virtual void StyleUpdated() override;
+ void updateSettings();
+ void setModal(bool bModal) { m_bModal = bModal; }
+};
+
+class TableDesignWidget final
+{
+public:
+ TableDesignWidget(weld::Builder& rBuilder, ViewShellBase& rBase);
+ ~TableDesignWidget();
+
+ // callbacks
+ void onSelectionChanged();
+
+ void ApplyOptions();
+ void ApplyStyle();
+
+private:
+ void addListener();
+ void removeListener();
+ void updateControls();
+
+ void FillDesignPreviewControl();
+
+ DECL_LINK(EventMultiplexerListener, tools::EventMultiplexerEvent&, void);
+ DECL_LINK(implValueSetHdl, ValueSet*, void);
+ DECL_LINK(implCheckBoxHdl, weld::Toggleable&, void);
+
+ ViewShellBase& mrBase;
+
+ std::unique_ptr<TableValueSet> m_xValueSet;
+ std::unique_ptr<weld::CustomWeld> m_xValueSetWin;
+ std::unique_ptr<weld::CheckButton> m_aCheckBoxes[CB_COUNT];
+
+ css::uno::Reference< css::beans::XPropertySet > mxSelectedTable;
+ css::uno::Reference< css::drawing::XDrawView > mxView;
+ css::uno::Reference< css::container::XIndexAccess > mxTableFamily;
+};
+
+class TableDesignPane final : public PanelLayout
+ , public sfx2::sidebar::ILayoutableWindow
+{
+private:
+ std::unique_ptr<TableDesignWidget> m_xImpl;
+public:
+ TableDesignPane( weld::Widget* pParent, ViewShellBase& rBase )
+ : PanelLayout(pParent, "TableDesignPanel",
+ "modules/simpress/ui/tabledesignpanel.ui")
+ , m_xImpl(new TableDesignWidget(*m_xBuilder, rBase))
+ {
+ }
+ virtual css::ui::LayoutSize GetHeightForWidth(const sal_Int32 /*nWidth*/) override
+ {
+ sal_Int32 nMinimumHeight = get_preferred_size().Height();
+ return css::ui::LayoutSize(nMinimumHeight, -1, nMinimumHeight);
+ }
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/TemplateScanner.hxx b/sd/source/ui/inc/TemplateScanner.hxx
new file mode 100644
index 000000000..034f000a6
--- /dev/null
+++ b/sd/source/ui/inc/TemplateScanner.hxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "tools/AsynchronousTask.hxx"
+#include <ucbhelper/content.hxx>
+#include <com/sun/star/uno/Reference.h>
+
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::ucb
+{
+class XContent;
+class XCommandEnvironment;
+}
+
+namespace com::sun::star::sdbc
+{
+class XResultSet;
+}
+
+namespace sd
+{
+/** Representation of a template or layout file.
+*/
+class TemplateEntry
+{
+public:
+ TemplateEntry(const OUString& rsTitle, const OUString& rsPath)
+ : msTitle(rsTitle)
+ , msPath(rsPath)
+ {
+ }
+
+ OUString msTitle;
+ OUString msPath;
+};
+
+/** This class scans the template folders for impress templates. There are
+ two ways to use this class.
+ 1. The old and deprecated way is to call Scan() to scan all templates
+ and collect the supported ones in a tree structure. This structure is
+ returned by GetFolderList().
+ 2. The new way implements the AsynchronousTask interface. Call
+ RunNextStep() as long HasNextStep() returns <TRUE/>. After every step
+ GetLastAddedEntry() returns the template that was scanned (and has a
+ supported format) last. When a step does not add a new template then
+ the value of the previous step is returned.
+*/
+class TemplateScanner final : public ::sd::tools::AsynchronousTask
+{
+public:
+ /** Create a new template scanner and prepare but do not execute the scanning.
+ */
+ TemplateScanner();
+
+ /** The destructor deletes any remaining entries of the local list of
+ templates.
+ */
+ virtual ~TemplateScanner();
+
+ /** Implementation of the AsynchronousTask interface method.
+ */
+ virtual void RunNextStep() override;
+
+ /** Implementation of the AsynchronousTask interface method.
+ */
+ virtual bool HasNextStep() override;
+
+ /** Return the TemplateDir object that was last added to
+ mpTemplateEntries.
+ @return
+ <nullptr/> is returned either before the template scanning is
+ started or after it has ended.
+ */
+ const TemplateEntry* GetLastAddedEntry() const
+ {
+ return mpTemplateEntries.empty() ? nullptr : mpTemplateEntries.back().get();
+ }
+
+private:
+ /** The current state determines which step will be executed next by
+ RunNextStep().
+ */
+ enum State
+ {
+ INITIALIZE_SCANNING,
+ INITIALIZE_FOLDER_SCANNING,
+ GATHER_FOLDER_LIST,
+ SCAN_FOLDER,
+ INITIALIZE_ENTRY_SCAN,
+ SCAN_ENTRY,
+ DONE,
+ ERROR
+ };
+ State meState;
+
+ ::ucbhelper::Content maFolderContent;
+ ::std::vector<std::unique_ptr<TemplateEntry>> mpTemplateEntries;
+
+ /** The folders that are collected by GatherFolderList().
+ */
+ class FolderDescriptorList;
+ std::unique_ptr<FolderDescriptorList> mpFolderDescriptors;
+
+ /** Set of state variables used by the methods
+ InitializeFolderScanning(), GatherFolderList(), ScanFolder(),
+ InitializeEntryScanning(), and ScanEntry().
+ */
+ css::uno::Reference<css::ucb::XContent> mxTemplateRoot;
+ css::uno::Reference<css::ucb::XCommandEnvironment> mxFolderEnvironment;
+ css::uno::Reference<css::ucb::XCommandEnvironment> mxEntryEnvironment;
+ css::uno::Reference<css::sdbc::XResultSet> mxFolderResultSet;
+ css::uno::Reference<css::sdbc::XResultSet> mxEntryResultSet;
+
+ /** Obtain the root folder of the template folder hierarchy. The result
+ is stored in mxTemplateRoot for later use.
+ */
+ State GetTemplateRoot();
+
+ /** Initialize the scanning of folders. This is called exactly once.
+ @return
+ Returns one of the two states ERROR or GATHER_FOLDER_LIST.
+ */
+ State InitializeFolderScanning();
+
+ /** Collect all available top-level folders in an ordered list which can
+ then be processed by ScanFolder().
+ @return
+ Returns one of the two states ERROR or SCAN_FOLDER.
+ */
+ State GatherFolderList();
+
+ /** From the list of top-level folders collected by GatherFolderList()
+ the one with highest priority is processed.
+ @return
+ Returns one of the states ERROR, DONE, or INITIALIZE_ENTRY_SCAN.
+ */
+ State ScanFolder();
+
+ /** Initialize the scanning of entries of a top-level folder.
+ @return
+ Returns one of the states ERROR or SCAN_ENTRY.
+ */
+ State InitializeEntryScanning();
+
+ /** Scan one entry. When this entry matches the recognized template
+ types it is appended to the result set.
+ @return
+ Returns one of the states ERROR, SCAN_ENTRY, or SCAN_FOLDER.
+ */
+ State ScanEntry();
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/TextObjectBar.hxx b/sd/source/ui/inc/TextObjectBar.hxx
new file mode 100644
index 000000000..61394834f
--- /dev/null
+++ b/sd/source/ui/inc/TextObjectBar.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/shell.hxx>
+#include <glob.hxx>
+
+namespace sd {
+
+class View;
+class ViewShell;
+
+class TextObjectBar final
+ : public SfxShell
+{
+public:
+ SFX_DECL_INTERFACE(SD_IF_SDDRAWTEXTOBJECTBAR)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ TextObjectBar (
+ ViewShell* pSdViewShell,
+ SfxItemPool& rItemPool,
+ ::sd::View* pSdView);
+ virtual ~TextObjectBar() override;
+
+ void GetAttrState( SfxItemSet& rSet );
+ void GetCharState( SfxItemSet& rSet );
+ void Execute( SfxRequest &rReq );
+
+private:
+ ViewShell* mpViewShell;
+ ::sd::View* mpView;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ToolBarManager.hxx b/sd/source/ui/inc/ToolBarManager.hxx
new file mode 100644
index 000000000..45f4532fb
--- /dev/null
+++ b/sd/source/ui/inc/ToolBarManager.hxx
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ShellFactory.hxx"
+#include <rtl/ustring.hxx>
+
+#include <sal/types.h>
+#include <memory>
+
+class SdrView;
+namespace sd { class ViewShell; }
+namespace sd::tools { class EventMultiplexer; }
+
+namespace sd {
+
+class ViewShellBase;
+class ViewShellManager;
+
+/** Manage the set of visible tool bars (and object bars). Usually they
+ belong to the current view in the center pane.
+
+ Tool bars are managed in groups. Each group can be set, reset, or
+ modified independently of the others. This allows for instance to
+ replace the toolbars associated with the current function independently
+ from those associated with the main view.
+
+ The ToolBarManager has two high level methods which contain the
+ knowledge about which tool bars to show in a specific context.
+ When the view in the center pane changes then MainViewShellChanged()
+ sets up the tool bars for the new view. On changes of the selection the
+ SelectionHasChanged() method shows the tool bars for the new context.
+
+ The update of the actually visible tool bars to the set currently
+ required by the main view shell and its functions is divided into two
+ parts, PreUpdate() and PostUpdate(). This are to be called before
+ respectively after the update of the view shell stack. The reason for
+ this is to save time by not updating tool bars that will not be visible
+ in a short time on a view shell switch.
+*/
+class ToolBarManager
+ : public std::enable_shared_from_this<ToolBarManager>
+{
+public:
+ /** Use this method instead of the constructor to create new objects of
+ this class.
+ */
+ static std::shared_ptr<ToolBarManager> Create (
+ ViewShellBase& rBase,
+ const std::shared_ptr<tools::EventMultiplexer>& rpMultiplexer,
+ const std::shared_ptr<ViewShellManager>& rpViewShellManager);
+
+ ~ToolBarManager();
+
+ /** Call this method prior to the destructor to prevent the
+ ToolBarManager from accessing the ViewShellManager or the
+ XLayoutManager when those are possibly not well and alive anymore
+ (like during the destruction of the ViewShellBase.)
+ */
+ void Shutdown();
+
+ /** When the view in the center pane changes then this method sets up
+ the initial set of tool bars for the new view.
+ The ToolBarManager listens for view switching itself and then calls
+ MainViewShellChanged(). Calling this method from the outside should
+ not be necessary.
+ @param nShellType
+ The type of the new main view shell.
+ */
+ void MainViewShellChanged ();
+ void MainViewShellChanged (const ViewShell& rMainViewShell);
+
+ /** Call this method when the selection has changed to update the more
+ temporary tool bars (those in the ToolBarGroup::Function group.)
+ */
+ void SelectionHasChanged (
+ const ViewShell& rViewShell,
+ const SdrView& rView);
+
+ /** The set of tool bars that are handled by this manager class.
+ */
+ constexpr static OUStringLiteral msToolBar = u"toolbar"; // Draw_Toolbox_Sd, 23011
+ constexpr static OUStringLiteral msOptionsToolBar = u"optionsbar";
+ // Draw_Options_Toolbox, 23020
+ constexpr static OUStringLiteral msCommonTaskToolBar = u"commontaskbar";
+ // Draw_CommonTask_Toolbox, 23021
+ constexpr static OUStringLiteral msViewerToolBar = u"viewerbar"; // Draw_Viewer_Toolbox, 23023
+ constexpr static OUStringLiteral msSlideSorterToolBar = u"slideviewtoolbar";
+ // Slide_Toolbox, 23012
+ constexpr static OUStringLiteral msSlideSorterObjectBar = u"slideviewobjectbar";
+ // Slide_Obj_Toolbox, 23014
+ constexpr static OUStringLiteral msOutlineToolBar = u"outlinetoolbar"; // Outline_Toolbox, 23017
+ constexpr static OUStringLiteral msMasterViewToolBar = u"masterviewtoolbar";
+ // SID_MASTERPAGE, 27053
+ constexpr static OUStringLiteral msDrawingObjectToolBar = u"drawingobjectbar";
+ // Draw_Obj_Toolbox, 23013
+ constexpr static OUStringLiteral msGluePointsToolBar = u"gluepointsobjectbar";
+ // Gluepoints_Toolbox, 23019
+ constexpr static OUStringLiteral msTextObjectBar = u"textobjectbar";
+ // Draw_Text_Toolbox_Sd, 23016
+ constexpr static OUStringLiteral msBezierObjectBar = u"bezierobjectbar";
+ // Bezier_Toolbox_Sd, 23015
+ constexpr static OUStringLiteral msGraphicObjectBar = u"graphicobjectbar";
+ // Draw_Graf_Toolbox, 23030
+ constexpr static OUStringLiteral msMediaObjectBar = u"mediaobjectbar";
+ // Draw_Media_Toolbox, 23031
+ constexpr static OUStringLiteral msTableObjectBar = u"tableobjectbar";
+ // Draw_Table_Toolbox, 23018
+
+ /** The set of tool bar groups.
+ */
+ enum class ToolBarGroup {
+ Permanent,
+ Function,
+ CommonTask,
+ MasterMode,
+ LAST = MasterMode
+ };
+
+ /** Reset the set of visible object bars in the specified group. Tool
+ bars in other groups are not affected.
+ @param rParentShell
+ When this shell is not the main view then the method returns
+ immediately.
+ @param eGroup
+ Only the tool bars in this group are rest.
+ */
+ void ResetToolBars (ToolBarGroup eGroup);
+
+ /** Reset all tool bars, regardless of the group they belong to.
+ @param rParentShell
+ When this shell is not the main view then the method returns
+ immediately.
+ */
+ void ResetAllToolBars();
+
+ /** Add the tool bar with the given name to the specified group of tool
+ bars.
+ @param rParentShell
+ When this shell is not the main view then the method returns
+ immediately.
+ @param eGroup
+ The new tool bar is added to this group.
+ @param rsToolBarName
+ The base name of the tool bar. A proper prefix (like
+ private:resource/toolbar/) is added. The name may be one of the
+ ones defined above. Other names are allowed as well.
+ */
+ void AddToolBar (
+ ToolBarGroup eGroup,
+ const OUString& rsToolBarName);
+
+ /** Add the tool bar shell to the shell stack. This method basically
+ forwards the call to the ViewShellManager.
+ For some tool bar shells additional tool bars are made visible.
+ @param rParentShell
+ When this shell is not the main view then the method returns
+ immediately.
+ @param eGroup
+ The group is used for the actual tool bars.
+ @param nToolBarId
+ Id of the tool bar shell.
+ */
+ void AddToolBarShell (
+ ToolBarGroup eGroup,
+ ShellId nToolBarId);
+
+ /** Remove the tool bar with the given name from the specified group.
+ If the tool bar is not visible then nothing happens.
+ If the tool bar is a member of another group then nothing happens
+ either.
+ */
+ void RemoveToolBar (
+ ToolBarGroup eGroup,
+ const OUString& rsToolBarName);
+
+ /** This is basically a shortcut for ResetToolBars(),AddToolBar(). The
+ main difference is, that all sub shells of the specified parent
+ shell are deactivated as well.
+ @param rParentShell
+ When this shell is not the main view then the method returns
+ immediately.
+ @param eGroup
+ The new tool bar is added to this group.
+ @param rsToolBarName
+ The base name of the tool bar. A proper prefix (like
+ private:resource/toolbar/) is added. The name may be one of the
+ ones defined above. Other names are allowed as well.
+ */
+ void SetToolBar (
+ ToolBarGroup eGroup,
+ const OUString& rsToolBarName);
+
+ /** This is basically a shortcut for ResetToolBars(),AddToolBar(). The
+ main difference is, that all sub shells of the specified parent
+ shell are deactivated as well.
+ @param rParentShell
+ When this shell is not the main view then the method returns
+ immediately.
+ @param rParentShell
+ When this shell is not the main view then the method returns
+ immediately.
+ @param eGroup
+ The group is currently not used.
+ @param nToolBarId
+ Id of the tool bar shell.
+ */
+ void SetToolBarShell (
+ ToolBarGroup eGroup,
+ ShellId nToolBarId);
+
+ void PreUpdate();
+
+ /** Request an update of the active tool bars. The update is made
+ asynchronously.
+ */
+ void RequestUpdate();
+
+ /** This is a hint for the ToolBarManager to improve the performance
+ when it updates its tool bars when its own lock is released. Taking
+ control of the release of the update lock of the ViewShellManager
+ avoids some shell stack modifications and tool bar updates.
+ */
+ void LockViewShellManager();
+
+ /** Use this class to prevent the visible tool bars from being updated
+ (and thus causing repaints and GUI rearrangements) when several tool
+ bar operations are made in a row.
+ */
+ class UpdateLock { public:
+ UpdateLock(const std::shared_ptr<ToolBarManager>& rpManager)
+ : mpManager(rpManager) { mpManager->LockUpdate(); }
+ ~UpdateLock() COVERITY_NOEXCEPT_FALSE { mpManager->UnlockUpdate(); }
+ private:
+ std::shared_ptr<ToolBarManager> mpManager;
+ };
+ friend class UpdateLock;
+
+ void ToolBarsDestroyed();
+
+private:
+ class Implementation;
+ std::unique_ptr<Implementation> mpImpl;
+
+ /** The ViewShellBase is used to get the XLayoutManager and to determine
+ the plug in mode.
+ */
+ ToolBarManager();
+
+ void LockUpdate();
+ void UnlockUpdate();
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/View.hxx b/sd/source/ui/inc/View.hxx
new file mode 100644
index 000000000..4e530e3f9
--- /dev/null
+++ b/sd/source/ui/inc/View.hxx
@@ -0,0 +1,300 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <pres.hxx>
+#include <tools/gen.hxx>
+#include <vcl/transfer.hxx>
+#include <svx/fmview.hxx>
+#include <svx/svdpage.hxx>
+#include <vcl/idle.hxx>
+
+#include "smarttag.hxx"
+#include "fusearch.hxx"
+
+class SdDrawDocument;
+class SdPage;
+class SdrOle2Obj;
+class SdrGrafObj;
+class SdrMediaObj;
+class OutputDevice;
+class ImageMap;
+class Graphic;
+class SdrOutliner;
+
+namespace avmedia { class PlayerListener; }
+
+namespace sd {
+
+class DrawDocShell;
+class ViewShell;
+class Window;
+class ViewClipboard;
+
+//For master view we want to force that master
+//textboxes have readonly text, because the
+//text is the auto-generated click-here-to-edit
+//and it doesn't help to change it
+class OutlinerMasterViewFilter
+{
+private:
+ SdrOutliner *m_pOutl;
+ bool m_bReadOnly;
+public:
+ OutlinerMasterViewFilter()
+ : m_pOutl(nullptr)
+ , m_bReadOnly(false)
+ {
+ }
+ void Start(SdrOutliner *pOutl);
+ void End();
+};
+
+class SearchContext
+{
+private:
+ rtl::Reference<FuSearch> maFunctionSearch;
+
+public:
+ rtl::Reference<FuSearch>& getFunctionSearch()
+ {
+ return maFunctionSearch;
+ }
+
+ void setSearchFunction(rtl::Reference<FuSearch> const & xFunction)
+ {
+ resetSearchFunction();
+ maFunctionSearch = xFunction;
+ }
+
+ void resetSearchFunction()
+ {
+ if (maFunctionSearch.is())
+ maFunctionSearch->Dispose();
+ }
+};
+
+class SAL_DLLPUBLIC_RTTI View : public FmFormView
+{
+public:
+
+ View (
+ SdDrawDocument& rDrawDoc,
+ OutputDevice* pOutDev,
+ ViewShell* pViewSh=nullptr);
+ virtual ~View() override;
+
+ void CompleteRedraw( OutputDevice* pOutDev, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector = nullptr) override;
+
+ virtual void GetAttributes( SfxItemSet& rTargetSet, bool bOnlyHardAttr = false ) const;
+ virtual bool SetAttributes(const SfxItemSet& rSet, bool bReplaceAll = false, bool bSlide = false, bool bMaster = false);
+ virtual void MarkListHasChanged() override;
+ void SelectAll();
+ void DoCut();
+ void DoCopy();
+ void DoPaste(::sd::Window* pWindow=nullptr);
+ virtual void DoConnect(SdrOle2Obj* pOleObj) override;
+ virtual bool SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr = false);
+ void StartDrag( const Point& rStartPos, vcl::Window* pWindow );
+ virtual void DragFinished( sal_Int8 nDropAction );
+ virtual sal_Int8 AcceptDrop (
+ const AcceptDropEvent& rEvt,
+ DropTargetHelper& rTargetHelper,
+ SdrLayerID nLayer);
+ virtual sal_Int8 ExecuteDrop (
+ const ExecuteDropEvent& rEvt,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer);
+
+ css::uno::Reference<css::datatransfer::XTransferable>
+ CreateClipboardDataObject ();
+ css::uno::Reference<css::datatransfer::XTransferable>
+ CreateDragDataObject (::sd::View*, vcl::Window& rWindow,
+ const Point& rDragPos);
+ css::uno::Reference<css::datatransfer::XTransferable>
+ CreateSelectionDataObject (::sd::View*);
+
+ // update clipboard to what is selected
+ void UpdateSelectionClipboard();
+
+ // release content of clipboard, if we own the content
+ void ClearSelectionClipboard();
+
+ DrawDocShell* GetDocSh() const { return mpDocSh; }
+ inline SdDrawDocument& GetDoc() const;
+ ViewShell* GetViewShell() const { return mpViewSh; }
+ SfxViewShell* GetSfxViewShell() const override;
+
+ // Create a local UndoManager
+ std::unique_ptr<SdrUndoManager> createLocalTextUndoManager() override;
+
+ virtual bool SdrBeginTextEdit(SdrObject* pObj, SdrPageView* pPV = nullptr, vcl::Window* pWin = nullptr, bool bIsNewObj = false,
+ SdrOutliner* pGivenOutliner = nullptr, OutlinerView* pGivenOutlinerView = nullptr,
+ bool bDontDeleteOutliner = false, bool bOnlyOneView = false, bool bGrabFocus = true) override;
+
+ virtual SdrEndTextEditKind SdrEndTextEdit(bool bDontDeleteReally = false) override;
+
+ bool RestoreDefaultText( SdrTextObj* pTextObj );
+
+ bool InsertData( const TransferableDataHelper& rDataHelper,
+ const Point& rPos, sal_Int8& rDnDAction, bool bDrag,
+ SotClipboardFormatId nFormat = SotClipboardFormatId::NONE,
+ sal_uInt16 nPage = SDRPAGE_NOTFOUND, SdrLayerID nLayer = SDRLAYER_NOTFOUND );
+ /** gets the metafile from the given transferable helper and insert it as a graphic shape.
+ @param bOptimize if set to true, the metafile is analyzed and if only one bitmap action is
+ present, then is inserted as a single graphic.
+ */
+ bool InsertMetaFile( const TransferableDataHelper& rDataHelper,
+ const Point& rInsertPos,
+ ImageMap const * pImageMap, bool bOptimize );
+ SdrGrafObj* InsertGraphic( const Graphic& rGraphic,
+ sal_Int8& rAction, const Point& rPos,
+ SdrObject* pSelectedObj, ImageMap const * pImageMap );
+ void InsertMediaURL( const OUString& rMediaURL, sal_Int8& rAction,
+ const Point& rPos, const Size& rSize,
+ bool const bLink );
+ SdrMediaObj* InsertMediaObj( const OUString& rURL, const OUString& rMimeType, sal_Int8& rAction,
+ const Point& rPos, const Size& rSize );
+
+ bool PasteRTFTable( const ::tools::SvRef<SotTempStream>& xStm, SdrPage* pPage, SdrInsertFlags nPasteOptions );
+
+ bool IsPresObjSelected(bool bOnPage = true, bool bOnMasterPage = true, bool bCheckPresObjListOnly = false, bool bCheckLayoutOnly = false) const;
+
+ void SetMarkedOriginalSize();
+
+ bool IsMorphingAllowed() const;
+ bool IsVectorizeAllowed() const;
+
+ virtual SfxStyleSheet* GetStyleSheet() const;
+
+ /** return parameter:
+ pExchangeList == NULL -> all names are unique
+ bNameOK == false -> cancel by user
+ nType == 0 -> pages
+ nType == 1 -> objects
+ nType == 2 -> pages and objects */
+
+ bool GetExchangeList( std::vector<OUString> &rExchangeList,
+ std::vector<OUString> &rBookmarkList,
+ const sal_uInt16 nType );
+
+ virtual void onAccessibilityOptionsChanged() override;
+
+ /** returns true if we have an undo manager and there is an open list undo action */
+ bool isRecordingUndo() const;
+
+ virtual void AddCustomHdl() override;
+
+ SmartTagSet& getSmartTags() { return maSmartTags; }
+ void updateHandles();
+
+ virtual SdrViewContext GetContext() const override;
+ virtual bool HasMarkablePoints() const override;
+ virtual sal_Int32 GetMarkablePointCount() const override;
+ virtual bool HasMarkedPoints() const override;
+ virtual bool MarkPoint(SdrHdl& rHdl, bool bUnmark=false) override;
+ virtual void CheckPossibilities() override;
+ virtual bool MarkPoints(const ::tools::Rectangle* pRect, bool bUnmark) override;
+ using SdrMarkView::MarkPoints;
+
+ bool ShouldToggleOn(
+ const bool bBulletOnOffMode,
+ const bool bNormalBullet);
+
+ /** change the bullets/numbering of the marked objects
+
+ @param bToggle
+ true: just toggle the current bullets/numbering on --> off resp. off --> on
+
+ @param bHandleBullets
+ true: handle bullets
+ false: handle numbering
+
+ @param pNumRule
+ numbering rule which needs to be applied. can be 0.
+ */
+ void ChangeMarkedObjectsBulletsNumbering(
+ const bool bToggle,
+ const bool bHandleBullets,
+ const SvxNumRule* pNumRule);
+
+ void SetPossibilitiesDirty() { m_bPossibilitiesDirty = true; }
+ void SetMoveAllowed( bool bSet ) { m_bMoveAllowed = bSet; }
+ void SetMoveProtected( bool bSet ) { m_bMoveProtect = bSet; }
+ void SetResizeFreeAllowed( bool bSet ) { m_bResizeFreeAllowed = bSet; }
+ void SetResizePropAllowed( bool bSet ) { m_bResizePropAllowed = bSet; }
+ void SetResizeProtected( bool bSet ) { m_bResizeProtect = bSet; }
+
+ SdrObject* GetEmptyPresentationObject( PresObjKind eKind );
+ SdPage* GetPage();
+ SdrObject* GetSelectedSingleObject(SdPage const * pPage);
+ void SetAuthor(const OUString& rAuthor) { m_sAuthor = rAuthor; }
+ const OUString& GetAuthor() const { return m_sAuthor; }
+
+ SearchContext& getSearchContext() { return maSearchContext; }
+protected:
+ DECL_DLLPRIVATE_LINK( OnParagraphInsertedHdl, ::Outliner::ParagraphHdlParam, void );
+ DECL_DLLPRIVATE_LINK( OnParagraphRemovingHdl, ::Outliner::ParagraphHdlParam, void );
+
+ virtual void OnBeginPasteOrDrop( PasteOrDropInfos* pInfo ) override;
+ virtual void OnEndPasteOrDrop( PasteOrDropInfos* pInfo ) override;
+
+ SdDrawDocument& mrDoc;
+ DrawDocShell* mpDocSh;
+ ViewShell* mpViewSh;
+ std::unique_ptr<SdrMarkList> mpDragSrcMarkList;
+ SdrObject* mpDropMarkerObj;
+ std::unique_ptr<SdrDropMarkerOverlay> mpDropMarker;
+ sal_uInt16 mnDragSrcPgNum;
+ Point maDropPos;
+ ::std::vector<OUString> maDropFileVector;
+ sal_Int8 mnAction;
+ Idle maDropErrorIdle;
+ Idle maDropInsertFileIdle;
+ rtl::Reference<avmedia::PlayerListener> mxDropMediaSizeListener;
+ sal_uInt16 mnLockRedrawSmph;
+ bool mbIsDropAllowed;
+
+ DECL_DLLPRIVATE_LINK( DropErrorHdl, Timer*, void );
+ DECL_DLLPRIVATE_LINK( DropInsertFileHdl, Timer*, void );
+ DECL_DLLPRIVATE_LINK( ExecuteNavigatorDrop, void*, void );
+
+ void ImplClearDrawDropMarker();
+
+ SmartTagSet maSmartTags;
+
+private:
+ ::std::unique_ptr<ViewClipboard> mpClipboard;
+ OutlinerMasterViewFilter maMasterViewFilter;
+ SearchContext maSearchContext;
+
+ OUString m_sAuthor;
+};
+
+SdDrawDocument& View::GetDoc() const
+{
+ return mrDoc;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ViewClipboard.hxx b/sd/source/ui/inc/ViewClipboard.hxx
new file mode 100644
index 000000000..f16c0ad33
--- /dev/null
+++ b/sd/source/ui/inc/ViewClipboard.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+class SdPage;
+class SdTransferable;
+
+namespace sd
+{
+class View;
+
+/** Handle clipboard related tasks for the draw view.
+*/
+class ViewClipboard
+{
+public:
+ ViewClipboard(::sd::View& rView);
+ virtual ~ViewClipboard();
+
+ /** Handle the drop of a drag-and-drop action where the transferable
+ contains a set of pages.
+ */
+ void HandlePageDrop(const SdTransferable& rTransferable);
+
+protected:
+ ::sd::View& mrView;
+
+ /** Return the first master page of the given transferable. When the
+ bookmark list of the transferable contains at least one non-master
+ page then NULL is returned.
+ */
+ static SdPage* GetFirstMasterPage(const SdTransferable& rTransferable);
+
+ /** Assign the (first) master page of the given transferable to the
+ (...) slide.
+ */
+ void AssignMasterPage(const SdTransferable& rTransferable, SdPage const* pMasterPage);
+
+ /** Return an index of a page after which the pages of the transferable
+ are to be inserted into the target document.
+ */
+ virtual sal_uInt16 DetermineInsertPosition();
+
+ /** Insert the slides in the given transferable behind the last selected
+ slide or, when the selection is empty, behind the last slide.
+ @param rTransferable
+ This transferable defines which pages to insert.
+ @param nInsertPosition
+ The pages of the transferable will be inserted behind the page
+ with this index.
+ @return
+ Returns the number of inserted slides.
+ */
+ sal_uInt16 InsertSlides(const SdTransferable& rTransferable, sal_uInt16 nInsertPosition);
+};
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ViewShell.hxx b/sd/source/ui/inc/ViewShell.hxx
new file mode 100644
index 000000000..1eeede9e2
--- /dev/null
+++ b/sd/source/ui/inc/ViewShell.hxx
@@ -0,0 +1,559 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ref.hxx>
+
+#include <sfx2/viewsh.hxx>
+#include <svl/typedwhich.hxx>
+#include <vcl/prntypes.hxx>
+#include <vcl/scrbar.hxx>
+#include <o3tl/deleter.hxx>
+#include <pres.hxx>
+#include "View.hxx"
+#include "fupoor.hxx"
+#include <sddllapi.h>
+
+#include <memory>
+
+class SdPage;
+class SvxRuler;
+class SdrOle2Obj; // for the ones, who have undefined parts of SVDRAW
+class SdDrawDocument;
+class SvxNumBulletItem;
+
+namespace weld
+{
+ class Window;
+}
+
+namespace com::sun::star::drawing { class XDrawSubController; }
+
+namespace sd {
+
+class DrawDocShell;
+class FrameView;
+class LayerTabBar;
+class ViewShellBase;
+class Window;
+class WindowUpdater;
+class ZoomList;
+
+#undef OUTPUT_DRAWMODE_COLOR
+#undef OUTPUT_DRAWMODE_CONTRAST
+
+const DrawModeFlags OUTPUT_DRAWMODE_COLOR = DrawModeFlags::Default;
+const DrawModeFlags OUTPUT_DRAWMODE_GRAYSCALE
+ = DrawModeFlags::GrayLine | DrawModeFlags::GrayFill
+ | DrawModeFlags::BlackText | DrawModeFlags::GrayBitmap
+ | DrawModeFlags::GrayGradient;
+const DrawModeFlags OUTPUT_DRAWMODE_BLACKWHITE
+ = DrawModeFlags::BlackLine | DrawModeFlags::BlackText
+ | DrawModeFlags::WhiteFill | DrawModeFlags::GrayBitmap
+ | DrawModeFlags::WhiteGradient;
+const DrawModeFlags OUTPUT_DRAWMODE_CONTRAST
+ = DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill
+ | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient;
+
+/** Base class of the stacked shell hierarchy.
+
+ <p>Despite its name this class is not a descendant of SfxViewShell
+ but of SfxShell. Its name expresses the fact that it acts like a
+ view shell. Being a stacked shell rather than being an actual view shell
+ there can be several instances of this class that
+ <ul>
+ <li>all are based on the same view shell and thus show the same
+ document and share common view functionality and</li>
+ <li>are all visible at the same time and live in the same
+ frame.</li>
+ <ul></p>
+
+ <p>This class replaces the former ViewShell class.</p>
+*/
+class SAL_DLLPUBLIC_RTTI ViewShell
+ : public SfxShell
+{
+public:
+ enum ShellType {
+ ST_NONE,
+ ST_DRAW, // The Draw application.
+ ST_IMPRESS, // Main view of the Impress application.
+ ST_NOTES,
+ ST_HANDOUT,
+ ST_OUTLINE,
+ ST_SLIDE_SORTER,
+ ST_PRESENTATION,
+ ST_SIDEBAR
+ };
+ static const int MAX_HSPLIT_CNT = 1;
+ static const int MAX_VSPLIT_CNT = 1;
+ static const int MIN_SCROLLBAR_SIZE = 50;
+
+
+ ViewShell (
+ vcl::Window* pParentWindow,
+ ViewShellBase& rViewShellBase);
+ virtual ~ViewShell() override;
+
+ /** The Init method has to be called from the outside directly
+ after a new object of this class has been created. It can be
+ used for that part of the initialisation that can be run only
+ after the creation of the new object is finished. This
+ includes registration as listener at event broadcasters.
+
+ Derived classes should call this method at the head of their
+ Init() methods.
+ @param bIsMainViewShell
+ This flag tells the Init() method whether the new ViewShell will
+ be the main view shell.
+ */
+ virtual void Init (bool bIsMainViewShell);
+
+ /** The Exit() method has to be called before the destructor so that the
+ view shell is still a valid object and can safely call methods that
+ rely on that.
+ */
+ void Exit();
+
+ void Cancel();
+
+ /** Return the window that is the parent of all controls of this view
+ shell. This may or may not be the window of the frame.
+ */
+ vcl::Window* GetParentWindow() const { return mpParentWindow; }
+
+ sd::Window* GetContentWindow() const;
+
+ ::sd::View* GetView() const { return mpView; }
+ inline SdrView* GetDrawView() const;
+ SD_DLLPUBLIC DrawDocShell* GetDocSh() const;
+
+ SdDrawDocument* GetDoc() const;
+
+ SD_DLLPUBLIC SfxViewFrame* GetViewFrame() const;
+
+ /** The active window is usually the mpContentWindow. When there is a
+ show running then the active window is a ShowWindow.
+ */
+ ::sd::Window* GetActiveWindow() const { return mpActiveWindow;}
+ SD_DLLPUBLIC weld::Window* GetFrameWeld() const;
+
+ /** Set the active window. When the shell is displayed in the center
+ pane then the window of the ViewShellBase is also set to the given
+ window.
+ */
+ void SetActiveWindow (::sd::Window* pWindow);
+
+ /** Return the rectangle that encloses all windows of the view. That
+ excludes the controls in the frame like rulers, scroll bars, tab
+ bar, and buttons.
+ @return
+ The rectangle is returned in screen coordinates, i.e. pixel
+ values relative to the upper left corner of the screen?.
+ */
+ const ::tools::Rectangle& GetAllWindowRect();
+
+ // Mouse- & Key-Events
+ virtual void PrePaint();
+ virtual void Paint (const ::tools::Rectangle& rRect, ::sd::Window* pWin);
+ virtual bool KeyInput(const KeyEvent& rKEvt, ::sd::Window* pWin);
+ virtual void MouseMove(const MouseEvent& rMEvt, ::sd::Window* pWin);
+ virtual void MouseButtonUp(const MouseEvent& rMEvt, ::sd::Window* pWin);
+ virtual void MouseButtonDown(const MouseEvent& rMEvt, ::sd::Window* pWin);
+ virtual void Command(const CommandEvent& rCEvt, ::sd::Window* pWin);
+ bool RequestHelp( const HelpEvent& rEvt );
+ bool Notify( NotifyEvent const & rNEvt, ::sd::Window* pWin );
+
+ bool HandleScrollCommand(const CommandEvent& rCEvt, ::sd::Window* pWin);
+
+ void SetUIUnit(FieldUnit eUnit);
+ void SetDefTabHRuler( sal_uInt16 nDefTab );
+
+ const SvxNumBulletItem* GetNumBulletItem(SfxItemSet& aNewAttr, TypedWhichId<SvxNumBulletItem>& nNumItemId);
+
+ bool HasRuler() const { return mbHasRulers;}
+ void SetRuler(bool bRuler);
+ // Hides horizontal, vertical scrollbar as well as scrollbox
+ void SetScrollBarsVisible(bool bVisible);
+
+ /** Set internal values of all scroll bars that determine thumb size and
+ position. The external values like size and position of the scroll
+ bar controls are not modified.
+ */
+ virtual void UpdateScrollBars();
+ void Scroll(::tools::Long nX, ::tools::Long nY);
+ void ScrollLines(::tools::Long nX, ::tools::Long nY);
+ virtual void SetZoom(::tools::Long nZoom);
+ ::tools::Long GetZoom() const;
+ virtual void SetZoomRect(const ::tools::Rectangle& rZoomRect);
+ void InitWindows(const Point& rViewOrigin, const Size& rViewSize,
+ const Point& rWinPos, bool bUpdate = false);
+ void InvalidateWindows();
+ /** This method is still used by the OutlineViewShell to update the
+ model according to the content of the outline view. This in turn
+ updates the previews in the slide sorter.
+ */
+ virtual void UpdatePreview (SdPage* pPage);
+
+ void DrawMarkRect(const ::tools::Rectangle& rRect) const;
+
+ void ExecReq( SfxRequest &rReq );
+
+ ZoomList* GetZoomList() { return mpZoomList.get();}
+
+ FrameView* GetFrameView() { return mpFrameView; }
+ /** Setting a frame view triggers ReadFrameViewData() for the new
+ frame.
+ @param pFrameView
+ The new frame view that replaces the old one.
+ */
+ void SetFrameView (FrameView* pFrameView);
+ virtual void ReadFrameViewData(FrameView* pView);
+ virtual void WriteFrameViewData();
+ void WriteUserData();
+ void ReadUserData();
+
+ virtual bool ActivateObject(SdrOle2Obj* pObj, sal_Int32 nVerb);
+
+ /** @returns
+ current or selected page or 0. This method
+ will fail in master page mode.
+
+ @deprecated, please use getCurrentPage();
+ */
+ virtual SdPage* GetActualPage() = 0;
+
+ /** @returns
+ current or selected page or 0.
+ */
+ virtual SdPage* getCurrentPage() const = 0;
+
+ const rtl::Reference<FuPoor>& GetOldFunction() const { return mxOldFunction; }
+ bool HasOldFunction() const { return mxOldFunction.is(); }
+ const rtl::Reference<FuPoor>& GetCurrentFunction() const { return mxCurrentFunction; }
+ bool HasCurrentFunction( sal_uInt16 nSID ) { return mxCurrentFunction.is() && (mxCurrentFunction->GetSlotID() == nSID ); }
+ bool HasCurrentFunction() const { return mxCurrentFunction.is(); }
+
+ void SetCurrentFunction(const rtl::Reference<FuPoor>& xFunction);
+ void SetOldFunction(const rtl::Reference<FuPoor>& xFunction);
+ void DeactivateCurrentFunction( bool bPermanent = false );
+
+ void SetPageSizeAndBorder(PageKind ePageKind, const Size& rNewSize,
+ ::tools::Long nLeft, ::tools::Long nRight, ::tools::Long nUpper, ::tools::Long nLower,
+ bool bScaleAll, Orientation eOrient, sal_uInt16 nPaperBin,
+ bool bBackgroundFullSize );
+
+ void SetStartShowWithDialog( bool bIn ) { mbStartShowWithDialog = bIn; }
+ bool IsStartShowWithDialog() const { return mbStartShowWithDialog; }
+
+ sal_uInt16 GetPrintedHandoutPageNum() const { return mnPrintedHandoutPageNum; }
+ void SetPrintedHandoutPageNum (sal_uInt16 nPageNumber) {mnPrintedHandoutPageNum=nPageNumber; }
+
+ sal_uInt16 GetPrintedHandoutPageCount() const { return mnPrintedHandoutPageCount; }
+ void SetPrintedHandoutPageCount (sal_uInt16 nPageCount) {mnPrintedHandoutPageCount=nPageCount; }
+
+ virtual bool PrepareClose( bool bUI = true );
+
+ void GetMenuState(SfxItemSet& rSet);
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt, DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow, sal_uInt16 nPage, SdrLayerID nLayer );
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt, DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow, sal_uInt16 nPage, SdrLayerID nLayer );
+
+ virtual void WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& );
+ virtual void ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& );
+
+ /** this method is called when the visible area of the view from this viewshell is changed */
+ virtual void VisAreaChanged(const ::tools::Rectangle& rRect);
+
+ /** Create an accessible object representing the specified window.
+ Override this method to provide view mode specific objects. The
+ default implementation returns an empty reference.
+ @param pWindow
+ Make the document displayed in this window accessible.
+ @return
+ This default implementation returns an empty reference.
+ */
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ CreateAccessibleDocumentView (::sd::Window* pWindow);
+
+ virtual void SwitchViewFireFocus( const css::uno::Reference< css::accessibility::XAccessible >& xAcc );
+ void SwitchActiveViewFireFocus( );
+ // Move these two methods from DrawViewShell to enable slide show view
+ void NotifyAccUpdate();
+ void fireSwitchCurrentPage(sal_Int32 pageIndex);
+ void SetWinViewPos(const Point& rWinPos);
+ Point const & GetWinViewPos() const;
+ Point const & GetViewOrigin() const;
+
+ /** Return the window updater of this view shell.
+ @return
+ In rare circumstances the returned pointer may be <null/>,
+ i.e. when no memory is available anymore.
+ */
+ ::sd::WindowUpdater* GetWindowUpdater() const;
+
+ /** Return the border that is drawn around the actual document view.
+ The border contains typically rulers and scroll bars.
+ */
+ SvBorder GetBorder();
+
+ /** Notify the view shell that its parent window has been resized.
+ The ViewShell places and resizes its UI elements accordingly.
+ The new size can be obtained from the parent window.
+ */
+ virtual void Resize();
+
+ /** Set position and size of the GUI elements that are controlled by
+ the view shell like rulers and scroll bars as well as the actual
+ document view according to the position and size that were given
+ with the last Resize() call.
+ */
+ virtual void ArrangeGUIElements();
+
+ // virtual void OuterResizePixel(const Point &rPos, const Size &rSize);
+ // virtual void InnerResizePixel(const Point &rPos, const Size &rSize);
+
+ // Exported for unit test
+ SD_DLLPUBLIC ViewShellBase& GetViewShellBase() const;
+
+ /** Return <TRUE/> when the called view shell is the main sub shell of
+ its ViewShellBase object, i.e. is display in the center pane. This
+ convenience function is equivalent to comparing the this pointer to
+ the result of ViewShellBase::GetViewShell(PT_CENTER).
+ */
+ bool IsMainViewShell() const;
+
+ /** Set or reset the flag that indicates whether the called shell is the
+ one displayed in the center pane. By default this flag is set to
+ <FALSE/>. For the main view shell it thus has to be set to <TRUE/>.
+ */
+ void SetIsMainViewShell (bool bIsMainViewShell);
+
+ /** Return a sub controller that implements the view shell specific
+ part of the DrawController.
+ */
+ virtual css::uno::Reference<css::drawing::XDrawSubController> CreateSubController() = 0;
+
+ /** Return the type of the shell.
+ */
+ SD_DLLPUBLIC ShellType GetShellType() const; //Export for unit test
+
+ /** This method is more or less an alias to Deactivate(). It is called
+ before an object of this class is taken from the stack of view
+ shells.
+
+ <p>When this method is not called before a view shell is taken from
+ a stack then the Deactivate() call from the SFX as a response to
+ RemoveSubShell() comes too late when the view shell is not on the
+ stack anymore.</p>
+ */
+ virtual void Shutdown();
+
+ /** This function is called from the underlying ViewShellBase
+ object to handle a verb execution request.
+ */
+ virtual ErrCode DoVerb(sal_Int32 nVerb);
+
+ virtual void UIActivating( SfxInPlaceClient* );
+ virtual void UIDeactivated( SfxInPlaceClient* );
+
+ /** Show controls of the UI or hide them, depending on the given flag.
+ As a result the border is adapted.
+ */
+ virtual void ShowUIControls (bool bVisible);
+ bool IsPageFlipMode() const;
+
+ /** Set the given window as new parent window. This is not possible for
+ all views, so the return value tells the caller if the relocation
+ was successful.
+ */
+ virtual bool RelocateToParentWindow (vcl::Window* pParentWindow);
+
+ /** Depending on the given request create a new page or duplicate an
+ existing one. A new page is created behind the given slide.
+ @param rRequest
+ The request as passed to an Execute() method. Its arguments are
+ evaluated. Its slot id determines whether to create or
+ duplicate a slide.
+ @param pPage
+ This page is either duplicated or becomes the predecessor of the
+ new slide. If NULL a duplication request is ignored. A new
+ slide is inserted as first slide.
+ @param nInsertPosition
+ When -1 (the default) then insert after pPage. Otherwise insert
+ before the given index (of a standard page).
+ @return
+ The new slide is returned. If for some reason a new page can
+ not be created then NULL is returned.
+ */
+ virtual SdPage* CreateOrDuplicatePage (
+ SfxRequest& rRequest,
+ PageKind ePageKind,
+ SdPage* pPage,
+ const sal_Int32 nInsertPosition = -1);
+
+ /// Allows adjusting the point or mark of the selection to a document coordinate.
+ void SetCursorMm100Position(const Point& rPosition, bool bPoint, bool bClearMark);
+ /// Gets the current selection
+ css::uno::Reference<css::datatransfer::XTransferable> GetSelectionTransferrable() const;
+ /// Allows starting or ending a graphic move or resize action.
+ void SetGraphicMm100Position(bool bStart, const Point& rPosition);
+
+ class Implementation;
+
+protected:
+ /** must be called in the beginning of each subclass d'tor.
+ disposes and clears both current and old function. */
+ void DisposeFunctions();
+
+ friend class ViewShellBase;
+
+ /** Window inside the rulers and scroll bars that shows a view of the
+ document.
+ */
+
+ VclPtr<sd::Window> mpContentWindow;
+
+ /// Horizontal scroll bar for the current slide is displayed when needed.
+ VclPtr<ScrollBar> mpHorizontalScrollBar;
+ /// Vertical scroll bar for whole document is always visible.
+ VclPtr<ScrollBar> mpVerticalScrollBar;
+ /// Horizontal ruler is not shown by default.
+ VclPtr<SvxRuler> mpHorizontalRuler;
+ /// Vertical ruler is not shown by default.
+ VclPtr<SvxRuler> mpVerticalRuler;
+ /// Filler of the little square enclosed by the two scroll bars.
+ VclPtr<ScrollBarBox> mpScrollBarBox;
+ /// Layer tab bar.
+ VclPtr<LayerTabBar> mpLayerTabBar;
+
+ /// This flag controls whether the rulers are visible.
+ bool mbHasRulers;
+
+ /// The active window.
+ VclPtr< ::sd::Window> mpActiveWindow;
+ ::sd::View* mpView;
+ FrameView* mpFrameView;
+
+ rtl::Reference<FuPoor> mxCurrentFunction;
+ rtl::Reference<FuPoor> mxOldFunction;
+ std::unique_ptr<ZoomList> mpZoomList;
+
+ Point maViewPos;
+ Size maViewSize;
+ Size maScrBarWH;
+
+ bool mbStartShowWithDialog; // presentation is started by dialog
+ sal_uInt16 mnPrintedHandoutPageNum; // Page number of the handout page that is to be printed.
+ sal_uInt16 mnPrintedHandoutPageCount; // Page count of the handout pages that are to be printed.
+
+ //af bool bPrintDirectSelected; // Print only selected objects in direct print
+ //afString sPageRange; // pagerange if selected objects in direct print
+
+ /** Area covered by all windows, i.e. the area of the parent window
+ without the controls at the borders like rulers, scroll bars, tab
+ bar, buttons.
+ This rectangle may be set in window coordinates (i.e. pixel values
+ relative to the parent window). It is transformed by every call to
+ GetAllWindowRectangle() into screen coordinates (relative to the
+ upper left corner of the screen.
+ */
+ ::tools::Rectangle maAllWindowRectangle;
+
+ /// The type of the shell. Returned by GetShellType().
+ ShellType meShellType;
+
+ std::unique_ptr<Implementation, o3tl::default_delete<Implementation>> mpImpl;
+
+ // Support methods for centralized UNDO/REDO
+ virtual SfxUndoManager* ImpGetUndoManager() const;
+ void ImpGetUndoStrings(SfxItemSet &rSet) const;
+ void ImpGetRedoStrings(SfxItemSet &rSet) const;
+ void ImpSidUndo(SfxRequest& rReq);
+ void ImpSidRedo(SfxRequest& rReq);
+
+ DECL_DLLPRIVATE_LINK( HScrollHdl, ScrollBar *, void );
+ DECL_DLLPRIVATE_LINK( VScrollHdl, ScrollBar *, void );
+
+ // virtual scroll handler, here, derivative classes can add themselves here
+ virtual void VirtHScrollHdl(ScrollBar* pHScroll);
+ virtual void VirtVScrollHdl(ScrollBar* pVScroll);
+
+ // virtual functions ruler handling
+ virtual VclPtr<SvxRuler> CreateHRuler(::sd::Window* pWin);
+ virtual VclPtr<SvxRuler> CreateVRuler(::sd::Window* pWin);
+ virtual void UpdateHRuler();
+ virtual void UpdateVRuler();
+
+ virtual void Activate(bool IsMDIActivate) override;
+ virtual void Deactivate(bool IsMDIActivate) override;
+
+ virtual void SetZoomFactor( const Fraction &rZoomX,
+ const Fraction &rZoomY );
+
+ /**
+ This must be called after the ctor, but before anything else.
+ It's the part of construction that is dependent
+ on showing the top-level window.
+
+ Showing a window with a11y enabled causes various callbacks
+ to be triggered.
+
+ Due to the "virtual methods are not virtual during constructors"
+ problem, this is a disaster to call from the ctor
+
+ i.e. construct calls Show, and if a11y is enabled this
+ reenters the not-fully constructed object and calls
+ CreateAccessibleDocumentView, so if construct is called
+ from the ctor then if a derived class is constructed the base-case
+ CreateAccessibleDocumentView is used, not the derived
+ CreateAccessibleDocumentView. i.e. run smoketest under a11y with
+ debugging assertions enabled
+ */
+ void doShow();
+
+private:
+ VclPtr<vcl::Window> mpParentWindow;
+ /** This window updater is used to keep all relevant windows up to date
+ with reference to the digit language used to display digits in text
+ shapes.
+ */
+ ::std::unique_ptr< ::sd::WindowUpdater> mpWindowUpdater;
+
+ /** Code common to all constructors. It generally is a bad idea
+ to call this function from outside a constructor.
+ */
+ void construct();
+
+ /** Create the rulers.
+ */
+ void SetupRulers();
+};
+
+SdrView* ViewShell::GetDrawView() const
+{
+ return static_cast<SdrView*>(mpView);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ViewShellBase.hxx b/sd/source/ui/inc/ViewShellBase.hxx
new file mode 100644
index 000000000..eab26ec8a
--- /dev/null
+++ b/sd/source/ui/inc/ViewShellBase.hxx
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <glob.hxx>
+#include <sfx2/viewsh.hxx>
+#include <memory>
+
+class SdDrawDocument;
+class SfxRequest;
+
+namespace sd::tools {
+class EventMultiplexer;
+}
+
+namespace sd {
+
+class DrawController;
+class DrawDocShell;
+class FormShellManager;
+class ToolBarManager;
+class ViewShell;
+class ViewShellManager;
+class ViewTabBar;
+
+/** SfxViewShell descendant that the stacked Draw/Impress shells are
+ based on.
+
+ <p>The "base" part of the name does not mean that this is a base
+ class of some class hierarchy. It rather is the base of the
+ stacked shells.</p>
+
+ <p>This class starts as a new and relatively small class. Over
+ time as much code as possible should be moved from the stacked
+ shells to this class.</p>
+*/
+class ViewShellBase
+ : public SfxViewShell
+{
+public:
+ SFX_DECL_INTERFACE(SD_IF_SDVIEWSHELLBASE)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ /** This constructor is used by the view factory of the SFX macros.
+ Note that LateInit() has to be called after the constructor
+ terminates and before doing anything else.
+ */
+ ViewShellBase (
+ SfxViewFrame *pFrame,
+ SfxViewShell* pOldShell);
+
+ virtual ~ViewShellBase() override;
+
+ /** This method is part of the object construction. It HAS to be called
+ after the constructor has created a new object.
+ */
+ void LateInit (const OUString& rsDefaultView);
+
+ std::shared_ptr<ViewShellManager> const & GetViewShellManager() const;
+
+ /** Return the main view shell stacked on the called ViewShellBase
+ object. This is usually the view shell displayed in the center
+ pane.
+ */
+ std::shared_ptr<ViewShell> GetMainViewShell() const;
+
+ /** When given a view frame this static method returns the
+ corresponding sd::ViewShellBase object.
+ @return
+ When the SfxViewShell of the given frame is not a
+ ViewShellBase object then NULL is returned.
+ */
+ static ViewShellBase* GetViewShellBase (SfxViewFrame const * pFrame);
+
+ DrawDocShell* GetDocShell() const { return mpDocShell;}
+ SdDrawDocument* GetDocument() const { return mpDocument;}
+
+ /** Callback function for general slot calls. At the moment these are
+ slots for switching the pane docking windows on and off.
+ */
+ virtual void Execute (SfxRequest& rRequest);
+
+ /** Callback function for retrieving item values related to certain
+ slots. This is the companion of Execute() and handles the slots
+ concerned with showing the pane docking windows.
+ */
+ void GetState (SfxItemSet& rSet);
+
+ /* override these from SfxViewShell */
+ virtual OUString GetSelectionText(bool = false, bool bOnlyASample = false) override;
+ virtual bool HasSelection(bool = true ) const override;
+
+ SvBorder GetBorder (bool bOuterResize);
+ virtual void InnerResizePixel (const Point& rOrigin, const Size& rSize, bool inplaceEditModeChange) override;
+ virtual void OuterResizePixel (const Point& rOrigin, const Size& rSize) override;
+
+ /** This call is forwarded to the main sub-shell.
+ */
+ virtual ErrCode DoVerb(sal_Int32 nVerb) override;
+
+ /** Return a new renderer that can be used for example for printing the
+ document.
+ */
+ virtual css::uno::Reference<css::view::XRenderable> GetRenderable() override;
+
+ /// Forwarded to the print manager.
+ virtual SfxPrinter* GetPrinter (bool bCreate = false) override;
+
+ /// Forwarded to the print manager.
+ virtual sal_uInt16 SetPrinter (
+ SfxPrinter* pNewPrinter,
+ SfxPrinterChangeFlags nDiffFlags = SFX_PRINTER_ALL) override;
+
+ /// Forward methods to main sub shell.
+ virtual void WriteUserDataSequence (
+ css::uno::Sequence< css::beans::PropertyValue >&) override;
+
+ /** Pass the given properties to the main view shell. After that we
+ ensure that the right view shell type is displayed in the center
+ pane.
+ */
+ virtual void ReadUserDataSequence (
+ const css::uno::Sequence< css::beans::PropertyValue >&) override;
+
+ virtual void UIActivating( SfxInPlaceClient* ) override;
+ virtual void UIDeactivated( SfxInPlaceClient* ) override;
+ virtual void Activate (bool IsMDIActivate) override;
+ using SfxViewShell::Deactivate;
+ virtual void SetZoomFactor (
+ const Fraction &rZoomX,
+ const Fraction &rZoomY) override;
+ virtual bool PrepareClose (bool bUI = true) override;
+ virtual void WriteUserData (OUString&, bool bBrowse = false) override;
+ virtual void ReadUserData (const OUString&, bool bBrowse = false) override;
+ virtual SdrView* GetDrawView() const override;
+
+ /** When <TRUE/> is given, then the mouse shape is set to hour glass (or
+ whatever the busy shape looks like on the system.)
+ */
+ void SetBusyState (bool bBusy);
+
+ /** Call this method when the controls of this view shell or the
+ embedded sub shell need to be rearranged. This is necessary
+ e.g. when the border has been modified (UpdateBorder() calls this
+ method).
+
+ This method is like ResizePixel() with no arguments.
+ */
+ void Rearrange();
+
+ /** Update the border that is set with SfxViewShell::SetBorderPixel().
+ This is done by adding the border used by the ViewShellBase itself
+ with the border used by the main view shell.
+
+ @param bForce if true the borders are also updated if old border
+ and new border are same.
+ */
+ void UpdateBorder ( bool bForce = false );
+
+ /** With this method the UI controls can be turned on or off. It is
+ used by the FuSlideShow to hide the UI controls while showing a
+ non-full-screen or in-window presentation in the center pane.
+ */
+ void ShowUIControls (bool bVisible);
+
+ /** Return an event multiplexer. It is a single class that forwards
+ events from various sources. This method must not be called before
+ LateInit() has terminated.
+ */
+ std::shared_ptr<tools::EventMultiplexer> const & GetEventMultiplexer() const;
+
+ /** returns the complete area of the current view relative to the frame
+ window
+ */
+ const ::tools::Rectangle& getClientRectangle() const;
+
+ std::shared_ptr<ToolBarManager> const & GetToolBarManager() const;
+ std::shared_ptr<FormShellManager> const & GetFormShellManager() const;
+
+ DrawController& GetDrawController() const;
+
+ void SetViewTabBar (const ::rtl::Reference<ViewTabBar>& rViewTabBar);
+
+ /** Return the window that is used by the main view shell to display its
+ view and other UI elements, like scroll bars and rulers. Ownership
+ of that window remains with the called ViewShellBase object.
+ */
+ vcl::Window* GetViewWindow();
+
+ /** returns the ui descriptive name for the given uno slot. The result is taken from the configuration
+ and not cached, so do not use it excessive (f.e. in status updates) */
+ OUString RetrieveLabelFromCommand( const OUString& aCmdURL ) const;
+ /// See SfxViewShell::getPart().
+ int getPart() const override;
+ /// See SfxViewShell::NotifyCursor().
+ void NotifyCursor(SfxViewShell* pViewShell) const override;
+
+ void setLOKVisibleArea(const ::tools::Rectangle& rArea) { maLOKVisibleArea = rArea; }
+ virtual ::tools::Rectangle getLOKVisibleArea() const override { return maLOKVisibleArea; }
+
+protected:
+
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+ virtual void InitializeFramework();
+
+private:
+ class Implementation;
+ std::unique_ptr<Implementation> mpImpl;
+ DrawDocShell* mpDocShell;
+ SdDrawDocument* mpDocument;
+ ::tools::Rectangle maLOKVisibleArea;
+
+ /** Determine from the properties of the document shell the initial type
+ of the view shell in the center pane. We use this method to avoid
+ starting with the wrong type. When ReadUserDataSequence() is called
+ we check that the right type is active and change again if that is
+ not the case because something went wrong.
+ */
+ OUString GetInitialViewShellType() const;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ViewShellHint.hxx b/sd/source/ui/inc/ViewShellHint.hxx
new file mode 100644
index 000000000..05a0c8328
--- /dev/null
+++ b/sd/source/ui/inc/ViewShellHint.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svl/hint.hxx>
+
+namespace sd
+{
+/** Local derivation of the SfxHint class that defines some hint ids that
+ are used by the ViewShell class and its descendants.
+*/
+class ViewShellHint final : public SfxHint
+{
+public:
+ enum HintId
+ {
+ // Indicate that a page resize is about to begin.
+ HINT_PAGE_RESIZE_START,
+ // Indicate that a page resize has been completed.
+ HINT_PAGE_RESIZE_END,
+ // Indicate that an edit mode change is about to begin.
+ HINT_CHANGE_EDIT_MODE_START,
+ // Indicate that an edit mode change has been completed.
+ HINT_CHANGE_EDIT_MODE_END,
+
+ HINT_COMPLEX_MODEL_CHANGE_START,
+ HINT_COMPLEX_MODEL_CHANGE_END
+ };
+
+ ViewShellHint(HintId nHintId);
+
+ HintId GetHintId() const { return meHintId; }
+
+private:
+ HintId meHintId;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ViewShellImplementation.hxx b/sd/source/ui/inc/ViewShellImplementation.hxx
new file mode 100644
index 000000000..b4a02c3d5
--- /dev/null
+++ b/sd/source/ui/inc/ViewShellImplementation.hxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ViewShell.hxx"
+#include "ViewShellManager.hxx"
+#include "ToolBarManager.hxx"
+#include <o3tl/deleter.hxx>
+#include <memory>
+
+class SvxIMapDlg;
+
+namespace sd
+{
+/** This class contains (will contain) the implementation of methods that
+ have not be accessible from the outside.
+*/
+class ViewShell::Implementation
+{
+public:
+ bool mbIsMainViewShell;
+ /// Set to true when the ViewShell::Init() method has been called.
+ bool mbIsInitialized;
+ /** Set to true while ViewShell::ArrangeGUIElements() is being
+ executed. It is used as guard against recursive execution.
+ */
+ bool mbArrangeActive;
+
+ /** Remember a link to the sub shell factory, so that it can be
+ unregistered at the ViewShellManager when a ViewShell is deleted.
+ */
+ ViewShellManager::SharedShellFactory mpSubShellFactory;
+
+ /** This update lock for the ToolBarManager exists in order to avoid
+ problems with tool bars being displayed while the mouse button is
+ pressed. With docked tool bars this can lead to a size change of
+ the view. This would change the relative mouse coordinates and thus
+ interpret every mouse click as move command.
+ */
+ class ToolBarManagerLock
+ {
+ public:
+ /** Create a new instance. This allows the mpSelf member to be set
+ automatically.
+ */
+ static std::shared_ptr<ToolBarManagerLock>
+ Create(const std::shared_ptr<ToolBarManager>& rpManager);
+ /** Release the lock. When the UI is captured
+ (Application::IsUICaptured() returns <TRUE/>) then the lock is
+ released later asynchronously.
+ @param bForce
+ When this flag is <TRUE/> then the lock is released even
+ when IsUICaptured() returns <TRUE/>.
+ */
+ void Release(bool bForce = false);
+ DECL_DLLPRIVATE_LINK(TimeoutCallback, Timer*, void);
+
+ private:
+ ::std::unique_ptr<ToolBarManager::UpdateLock,
+ o3tl::default_delete<ToolBarManager::UpdateLock>>
+ mpLock;
+ /** The timer is used both as a safe guard to unlock the update lock
+ when Release() is not called explicitly. It is also used to
+ defer the release of the lock to a time when the UI is not
+ captured.
+ */
+ Timer maTimer;
+ /** The shared_ptr to this allows the ToolBarManagerLock to control
+ its own lifetime. This, of course, does work only when no one
+ holds another shared_ptr longer than only temporary.
+ */
+ std::shared_ptr<ToolBarManagerLock> mpSelf;
+ ToolBarManagerLock(const std::shared_ptr<sd::ToolBarManager>& rpManager);
+ ~ToolBarManagerLock();
+
+ class Deleter;
+ friend class Deleter;
+ };
+ // The member is not a unique_ptr because it takes over its own life time
+ // control.
+ std::weak_ptr<ToolBarManagerLock> mpUpdateLockForMouse;
+
+ Implementation(ViewShell& rViewShell);
+ ~Implementation() COVERITY_NOEXCEPT_FALSE;
+
+ /** Process the SID_MODIFY slot.
+ */
+ void ProcessModifyPageSlot(SfxRequest& rRequest, SdPage* pCurrentPage, PageKind ePageKind);
+
+ /** Assign the given layout to the given page. This method is at the
+ moment merely a front end for ProcessModifyPageSlot.
+ @param pPage
+ If a NULL pointer is given then this call is ignored.
+ */
+ void AssignLayout(SfxRequest const& rRequest, PageKind ePageKind);
+
+ /** Determine the view id of the view shell. This corresponds to the
+ view id stored in the SfxViewFrame class.
+
+ We can not use the view of that class because with the introduction
+ of the multi pane GUI we do not switch the SfxViewShell anymore when
+ switching the view in the center pane. The view id of the
+ SfxViewFrame is thus not modified and we can not set it from the
+ outside.
+
+ The view id is still needed for the SFX to determine on start up
+ (e.g. after loading a document) which ViewShellBase sub class to
+ use. These sub classes--like OutlineViewShellBase--exist only to be
+ used by the SFX as factories. They only set the initial pane
+ configuration, nothing more.
+
+ So what we do here in essence is to return one of the
+ ViewShellFactoryIds that can be used to select the factory that
+ creates the ViewShellBase subclass with the initial pane
+ configuration that has in the center pane a view shell of the same
+ type as mrViewShell.
+ */
+ SfxInterfaceId GetViewId() const;
+
+ /** Return a pointer to the image map dialog that is displayed in some
+ child window.
+ @return
+ Returns <NULL/> when the image map dialog is not available.
+ */
+ static SvxIMapDlg* GetImageMapDialog();
+
+private:
+ ViewShell& mrViewShell;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ViewShellManager.hxx b/sd/source/ui/inc/ViewShellManager.hxx
new file mode 100644
index 000000000..a2c8f1ef2
--- /dev/null
+++ b/sd/source/ui/inc/ViewShellManager.hxx
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ShellFactory.hxx"
+#include <o3tl/deleter.hxx>
+#include <memory>
+
+class FmFormShell;
+class SfxShell;
+
+namespace sd
+{
+class ViewShell;
+class ViewShellBase;
+
+/** The ViewShellManager has the responsibility to manage the view shells
+ and sub shells on the SFX shell stack. They form a two level hierarchy
+ (the underlying ViewShellBase, the only true SfxViewShell descendant,
+ forms a third level.) On the first level there are the view shells
+ (what formerly was called view shell, anyway; nowadays they are derived
+ from SfxShell) and shells for panes. On the second level there are sub
+ shells (also derived from SfxShell) that usually are tool bars.
+
+ <p>On the SFX shell stack the regular sub shells are placed above their
+ view shells. The FormShell is a special case. With the SetFormShell()
+ method it can be placed directly above or below one of the view
+ shells.</p>
+
+ <p>Shells managed by this class are created by factories or are given
+ directly to Activate... methods. For the sub shells there is one
+ factory for every view shell. Factories are added or removed via the
+ (Add|Remove)SubShellFactory() methods. The FormShell is managed with the
+ factory of its view shell.</p>
+*/
+class ViewShellManager
+{
+public:
+ typedef std::shared_ptr<ShellFactory<SfxShell>> SharedShellFactory;
+
+ ViewShellManager(ViewShellBase& rBase);
+
+ /** Before the destructor is called the method Shutdown() has to have
+ been called.
+ */
+ ~ViewShellManager();
+
+ /** Tell a ViewShellManager object to prepare to be deleted, i.e. to
+ destroy all of its resources and to ignore all following calls.
+ Use this when the owner of the view shell manager is about being
+ destroyed but the view shell manager itself can not yet be deleted.
+ */
+ void Shutdown();
+
+ /** Set the factory for sub shells of the specified view shell.
+ */
+ void AddSubShellFactory(ViewShell const* pViewShell, const SharedShellFactory& rpFactory);
+ void RemoveSubShellFactory(ViewShell const* pViewShell, const SharedShellFactory& rpFactory);
+
+ /** Activate the given view shell.
+ */
+ void ActivateViewShell(ViewShell* pViewShell);
+
+ /** Activate the given shell which is not a view shell. For view shells
+ use the ActivateViewShell() method.
+ */
+ void ActivateShell(SfxShell* pShell);
+
+ /** Deactivate the specified shell, i.e. take it and all of its
+ object bars from the shell stack.
+ @param pShell
+ The shell to deactivate.
+ */
+ void DeactivateViewShell(const ViewShell* pShell);
+
+ /** Deactivate the specified shell. The shell is not destroyed.
+ */
+ void DeactivateShell(const SfxShell* pShell);
+
+ /** Associate the form shell with a view shell and their relative
+ position. This method does not change the shell stack, it just
+ stores the given values for the next shell stack update.
+ @param pParentShell
+ The view shell of the form shell.
+ @param pFormShell
+ The form shell.
+ @param bAbove
+ When <TRUE/> then the form shell will be placed directly above
+ pViewShell on the SFX shell stack. Otherwise the form shell is
+ placed directly below the view shell.
+ */
+ void SetFormShell(const ViewShell* pParentShell, FmFormShell* pFormShell, bool bAbove);
+
+ /** Activate the specified shell as sub shell for the given view shell.
+ The sub shell factory associated with the view shell is used to
+ create the sub shell.
+ @param rParentShell
+ The new sub shell will be placed above this view shell.
+ @param nId
+ This id is used only with the factory registered for the parent
+ view shell.
+ */
+ void ActivateSubShell(const ViewShell& rParentShell, ShellId nId);
+
+ /** Deactivate the specified sub shell.
+ */
+ void DeactivateSubShell(const ViewShell& rParentShell, ShellId nId);
+
+ /** Send all sub shells of the specified view shell an Invalidate()
+ call. This does not modify the shell stack.
+ */
+ void InvalidateAllSubShells(ViewShell const* pViewShell);
+
+ /** Move the specified view shell to the top most position on the stack
+ of view shells in relation to the other view shells. After this the
+ only shells that are higher on the stack are its object bars.
+
+ Call this method after a focus change to bring a view mode view
+ shell and is associated tool bar shells to the top of the
+ stack.
+
+ The mbKeepMainViewShellOnTop flag is not obeyed.
+
+ @param nId
+ The id of the shell to move to the top.
+ */
+ void MoveToTop(const ViewShell& rShell);
+
+ /** Return the first, i.e. top most, view shell that has been activated
+ under the given id.
+ @param nId
+ The id of the shell for which to return a pointer.
+ @return
+ When the specified shell is currently not active then NULL is
+ returned.
+ */
+ SfxShell* GetShell(ShellId nId) const;
+
+ /** Return the top-most shell on the SFX shell stack regardless of
+ whether that is a view shell or a sub shell.
+ */
+ SfxShell* GetTopShell() const;
+
+ /** Return the top-most active view shell on the internal shell stack.
+ */
+ SfxShell* GetTopViewShell() const;
+
+ /** Use this class to safely lock updates of the view shell stack.
+ */
+ class UpdateLock
+ {
+ public:
+ UpdateLock(const std::shared_ptr<ViewShellManager>& rpManager)
+ : mpManager(rpManager)
+ {
+ mpManager->LockUpdate();
+ }
+ ~UpdateLock() COVERITY_NOEXCEPT_FALSE { mpManager->UnlockUpdate(); }
+
+ private:
+ std::shared_ptr<ViewShellManager> mpManager;
+ };
+ friend class UpdateLock;
+
+private:
+ class Implementation;
+ std::unique_ptr<ViewShellManager::Implementation,
+ o3tl::default_delete<ViewShellManager::Implementation>>
+ mpImpl;
+ bool mbValid;
+
+ void LockUpdate();
+ void UnlockUpdate();
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ViewTabBar.hxx b/sd/source/ui/inc/ViewTabBar.hxx
new file mode 100644
index 000000000..ca9db932e
--- /dev/null
+++ b/sd/source/ui/inc/ViewTabBar.hxx
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/TabBarButton.hpp>
+#include <com/sun/star/drawing/framework/XTabBar.hpp>
+#include <com/sun/star/drawing/framework/XToolBar.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <comphelper/compbase.hxx>
+#include <vcl/InterimItemWindow.hxx>
+
+#include <vector>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+namespace com::sun::star::drawing::framework { struct ConfigurationChangeEvent; }
+namespace com::sun::star::frame { class XController; }
+namespace vcl { class Window; }
+
+namespace sd {
+ class ViewShellBase;
+ class ViewTabBar;
+}
+
+namespace sd {
+
+class TabBarControl final : public InterimItemWindow
+{
+public:
+ TabBarControl(vcl::Window* pParentWindow, const ::rtl::Reference<ViewTabBar>& rpViewTabBar);
+ virtual void dispose() override;
+ virtual ~TabBarControl() override;
+ weld::Notebook& GetNotebook() { return *mxTabControl; }
+ int GetAllocatedWidth() const { return mnAllocatedWidth; }
+private:
+ std::unique_ptr<weld::Notebook> mxTabControl;
+ ::rtl::Reference<ViewTabBar> mpViewTabBar;
+ int mnAllocatedWidth;
+
+ DECL_LINK(ActivatePageHdl, const OString&, void);
+ DECL_LINK(NotebookSizeAllocHdl, const Size&, void);
+};
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XToolBar,
+ css::drawing::framework::XTabBar,
+ css::drawing::framework::XConfigurationChangeListener,
+ css::lang::XUnoTunnel
+ > ViewTabBarInterfaceBase;
+
+/** Tab control for switching between views in the center pane.
+*/
+class ViewTabBar final
+ : public ViewTabBarInterfaceBase
+{
+public:
+ ViewTabBar (
+ const css::uno::Reference< css::drawing::framework::XResourceId>& rxViewTabBarId,
+ const css::uno::Reference< css::frame::XController>& rxController);
+ virtual ~ViewTabBar() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ const VclPtr<TabBarControl>& GetTabControl() const { return mpTabControl; }
+
+ bool ActivatePage(size_t nIndex);
+
+ //----- drawing::framework::XConfigurationChangeListener ------------------
+
+ virtual void SAL_CALL
+ notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ //----- XEventListener ----------------------------------------------------
+
+ virtual void SAL_CALL disposing(
+ const css::lang::EventObject& rEvent) override;
+
+ //----- XTabBar -----------------------------------------------------------
+
+ virtual void
+ SAL_CALL addTabBarButtonAfter (
+ const css::drawing::framework::TabBarButton& rButton,
+ const css::drawing::framework::TabBarButton& rAnchor) override;
+
+ virtual void
+ SAL_CALL appendTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton) override;
+
+ virtual void
+ SAL_CALL removeTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton) override;
+
+ virtual sal_Bool
+ SAL_CALL hasTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton) override;
+
+ virtual css::uno::Sequence<css::drawing::framework::TabBarButton>
+ SAL_CALL getTabBarButtons() override;
+
+ //----- XResource ---------------------------------------------------------
+
+ virtual css::uno::Reference<
+ css::drawing::framework::XResourceId> SAL_CALL getResourceId() override;
+
+ virtual sal_Bool SAL_CALL isAnchorOnly() override;
+
+ //----- XUnoTunnel --------------------------------------------------------
+
+ static const css::uno::Sequence<sal_Int8>& getUnoTunnelId();
+
+ virtual sal_Int64 SAL_CALL getSomething (const css::uno::Sequence<sal_Int8>& rId) override;
+
+ /** The returned value is calculated as the difference between the
+ total height of the control and the height of its first tab page.
+ This can be considered a hack.
+ This procedure works only when the control is visible. Calling this
+ method when the control is not visible results in returning a
+ default value.
+ To be on the safe side wait for this control to become visible and
+ the call this method again.
+ */
+ int GetHeight() const;
+
+ void UpdateActiveButton();
+
+ void AddTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton,
+ const css::drawing::framework::TabBarButton& rAnchor);
+ void AddTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton);
+ void RemoveTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton);
+ bool HasTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton);
+ css::uno::Sequence<css::drawing::framework::TabBarButton>
+ GetTabBarButtons();
+
+private:
+ VclPtr<TabBarControl> mpTabControl;
+ css::uno::Reference<css::frame::XController> mxController;
+ css::uno::Reference<css::drawing::framework::XConfigurationController> mxConfigurationController;
+ typedef ::std::vector<css::drawing::framework::TabBarButton> TabBarButtonList;
+ TabBarButtonList maTabBarButtons;
+ css::uno::Reference<css::drawing::framework::XResourceId> mxViewTabBarId;
+ ViewShellBase* mpViewShellBase;
+ int mnNoteBookWidthPadding;
+
+ void AddTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton,
+ sal_Int32 nPosition);
+ void UpdateTabBarButtons();
+
+ /** This method is called from the constructor to get the window for an
+ anchor ResourceId and pass it to our base class. It has to be
+ static because it must not access any of the, not yet initialized
+ members.
+ */
+ static vcl::Window* GetAnchorWindow(
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewTabBarId,
+ const css::uno::Reference<css::frame::XController>& rxController);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/Window.hxx b/sd/source/ui/inc/Window.hxx
new file mode 100644
index 000000000..f1beddbc6
--- /dev/null
+++ b/sd/source/ui/inc/Window.hxx
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/gen.hxx>
+#include <tools/long.hxx>
+#include <vcl/window.hxx>
+#include <vcl/transfer.hxx>
+
+class OutlinerView;
+
+namespace sd
+{
+class ViewShell;
+
+/** An SdWindow contains the actual working area of ViewShell.
+
+ <p>The zoom factor used by this class controls how much the page and the
+ shapes on it are scaled down (<100%) or up (>100%) when displayed on the
+ output device represented by the <type>OutputDevice</type>base class. A
+ zoom factor of 100% would result (with a correctly set DPI value for an
+ output device) in a one to one mapping of the internal coordinates that
+ are stored in 100th of mm. The zoom factor is stored in the map mode
+ member of the <type>OutputDevice</type> base class. It is calculated to
+ be an integer percent value.
+*/
+class Window : public vcl::Window, public ::DropTargetHelper
+{
+public:
+ Window(vcl::Window* pParent);
+ virtual ~Window() override;
+ virtual void dispose() override;
+
+ void SetViewShell(ViewShell* pViewSh);
+ ViewShell* GetViewShell();
+
+ /** Set the zoom factor to the specified value and center the display
+ area around the zoom center.
+ @param nZoom
+ The zoom factor is given as integral percent value.
+ */
+ void SetZoomIntegral(::tools::Long nZoom);
+
+ /** This internally used method performs the actual adaptation of the
+ window's map mode to the specified zoom factor.
+ @param nZoom
+ The zoom factor is given as integral percent value.
+ @return
+ When the given zoom factor lies outside the valid range enclosed
+ by the minimal zoom factor previously calculated by
+ <member>CalcMinZoom</member> and a constant upper value it is
+ forced into that interval. Therefore the returned value is a
+ valid zoom factor.
+ */
+ ::tools::Long SetZoomFactor(::tools::Long nZoom);
+
+ /** This method is called when the whole page shall be displayed in the
+ window. Position and zoom factor are set so that the given
+ rectangle is displayed as large as possible in the window while at
+ the same time maintaining the rectangle's aspect ratio and adding a
+ small space at all its four sides (about 3% of width and height).
+ The map mode is adapted accordingly.
+ @param rZoomRect
+ The rectangle is expected to be given relative to the upper left
+ corner of the window in logical coordinates (100th of mm).
+ @return
+ The new zoom factor is returned as integral percent value.
+ */
+ ::tools::Long SetZoomRect(const ::tools::Rectangle& rZoomRect);
+
+ ::tools::Long GetZoomForRect(const ::tools::Rectangle& rZoomRect);
+
+ void SetMinZoomAutoCalc(bool bAuto);
+
+ /** Calculate the minimal zoom factor as the value at which the
+ application area would completely fill the window. All values set
+ manually or programmatically are set to this value if they are
+ smaller. If the currently used zoom factor is smaller than the minimal zoom
+ factor than set the minimal zoom factor as the new current zoom
+ factor.
+
+ <p>This calculation is performed only when the
+ <member>bMinZoomAutoCalc</member> is set (to <TRUE/>).</p>
+ */
+ void CalcMinZoom();
+ void SetMinZoom(::tools::Long nMin);
+ ::tools::Long GetMinZoom() const { return mnMinZoom; }
+ void SetMaxZoom(::tools::Long nMax);
+ ::tools::Long GetMaxZoom() const { return mnMaxZoom; }
+
+ ::tools::Long GetZoom() const;
+
+ const Point& GetWinViewPos() const { return maWinPos; }
+ const Point& GetViewOrigin() const { return maViewOrigin; }
+ const Size& GetViewSize() const { return maViewSize; }
+ void SetWinViewPos(const Point& rPnt);
+ void SetViewOrigin(const Point& rPnt);
+ void SetViewSize(const Size& rSize);
+ void SetCenterAllowed(bool bIsAllowed);
+
+ /** Calculate origin of the map mode according to the size of the view
+ and window (its size in model coordinates; that takes the zoom
+ factor into account), and the bCenterAllowed flag. When it is not
+ set then nothing is changed. When in any direction the window is
+ larger than the view or the value of aWinPos in this direction is -1
+ then the window is centered in this direction.
+ */
+ void UpdateMapOrigin(bool bInvalidate = true);
+
+ void UpdateMapMode();
+
+ double GetVisibleX() const; // interface for ScrollBars
+ double GetVisibleY() const;
+ void SetVisibleXY(double fX, double fY);
+ double GetVisibleWidth() const;
+ double GetVisibleHeight() const;
+ Point GetVisibleCenter();
+ double GetScrlLineWidth() const;
+ double GetScrlLineHeight() const;
+ double GetScrlPageWidth() const;
+ double GetScrlPageHeight() const;
+ void GrabFocus();
+ virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
+
+ // DropTargetHelper
+ virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override;
+ virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override;
+
+ /** The DropScroll() method is used by AcceptDrop() to scroll the
+ content of the window while dragging and dropping. With this method
+ you can control whether DropScroll() shall be used.
+ */
+ void SetUseDropScroll(bool bUseDropScroll);
+ void DropScroll(const Point& rMousePos);
+ virtual void KeyInput(const KeyEvent& rKEvt) override;
+
+private:
+ OutlinerView* GetOutlinerView() const;
+
+protected:
+ Point maWinPos;
+ Point maViewOrigin;
+ Size maViewSize;
+ Size maPrevSize; // contains previous window size in logical coords
+ sal_uInt16 mnMinZoom;
+ sal_uInt16 mnMaxZoom;
+
+ /** This flag tells whether to re-calculate the minimal zoom factor
+ depending on the current zoom factor. Its default value is now false.
+ */
+ bool mbMinZoomAutoCalc;
+ bool mbCenterAllowed;
+ ::tools::Long mnTicks;
+
+ ViewShell* mpViewShell;
+ bool mbUseDropScroll;
+
+ virtual void Resize() override;
+ virtual void PrePaint(vcl::RenderContext& rRenderContext) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext,
+ const ::tools::Rectangle& rRect) override;
+ virtual void MouseMove(const MouseEvent& rMEvt) override;
+ virtual void MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual void Command(const CommandEvent& rCEvt) override;
+ virtual void RequestHelp(const HelpEvent& rEvt) override;
+ virtual void LoseFocus() override;
+ virtual bool EventNotify(NotifyEvent& rNEvt) override;
+
+ /** Create an accessibility object that makes this window accessible.
+
+ @return
+ The returned reference is empty if an accessible object could
+ not be created.
+ */
+ virtual css::uno::Reference<css::accessibility::XAccessible> CreateAccessible() override;
+
+ OUString GetSurroundingText() const override;
+ Selection GetSurroundingTextSelection() const override;
+ bool DeleteSurroundingText(const Selection& rSelection) override;
+
+ /// @see Window::LogicInvalidate().
+ void LogicInvalidate(const ::tools::Rectangle* pRectangle) override;
+ /// Same as MouseButtonDown(), but coordinates are in logic unit.
+ virtual void LogicMouseButtonDown(const MouseEvent& rMouseEvent) override;
+ /// Same as MouseButtonUp(), but coordinates are in logic unit.
+ virtual void LogicMouseButtonUp(const MouseEvent& rMouseEvent) override;
+ /// Same as MouseMove(), but coordinates are in logic unit.
+ virtual void LogicMouseMove(const MouseEvent& rMouseEvent) override;
+
+ FactoryFunction GetUITestFactory() const override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/WindowUpdater.hxx b/sd/source/ui/inc/WindowUpdater.hxx
new file mode 100644
index 000000000..2545af79f
--- /dev/null
+++ b/sd/source/ui/inc/WindowUpdater.hxx
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svl/ctloptions.hxx>
+#include <vcl/vclptr.hxx>
+
+#include <vector>
+
+namespace vcl
+{
+class Window;
+}
+class OutputDevice;
+class SdDrawDocument;
+
+namespace sd
+{
+/** The purpose of the <type>WindowUpdater</type> is to update output
+ devices to take care of modified global values. These values are
+ monitored for changes. At the moment this is
+ the digit language that defines the glyphs to use to render digits.
+ Other values may be added in the future.
+
+ <p>The methods of this class have not been included into the
+ <type>ViewShell</type> class in order to not clutter its interface any
+ further. This class accesses some of <type>ViewShell</type> data
+ members directly and thus is declared as its friend.</p>
+
+ <p>Windows that are to be kept up-to-date have to be registered via the
+ <member>RegisterWindow()</member> method. When a document is given then
+ this document is reformatted when the monitored option changes.</p>
+*/
+class WindowUpdater final : public utl::ConfigurationListener
+{
+public:
+ explicit WindowUpdater();
+ virtual ~WindowUpdater() noexcept override;
+
+ /** Add the given device to the list of devices which will be updated
+ when one of the monitored values changes.
+ @param pWindow
+ This device is added to the device list if it is not <null/> and
+ when it is not already a member of that list.
+ */
+ void RegisterWindow(vcl::Window* pWindow);
+
+ /** Remove the given device from the list of devices which will be updated
+ when one of the monitored values changes.
+ @param pWindow
+ This device is removed from the device list when it is a member
+ of that list.
+ */
+ void UnregisterWindow(vcl::Window* pWindow);
+
+ /** Set the document so that it is reformatted when one of the monitored
+ values changes.
+ @param pDocument
+ When <null/> is given document reformatting will not take
+ place in the future.
+ */
+ void SetDocument(SdDrawDocument* pDocument);
+
+ /** Update the given output device and update all text objects of the
+ view shell if not told otherwise.
+ @param pWindow
+ The device to update. When the given pointer is NULL then
+ nothing is done.
+ */
+ void Update(OutputDevice* pDevice) const;
+
+ /** Callback that waits for notifications of a
+ <type>SvtCTLOptions</type> object.
+ */
+ virtual void ConfigurationChanged(utl::ConfigurationBroadcaster*,
+ ConfigurationHints nHint) override;
+
+private:
+ /// Options to monitor for changes.
+ SvtCTLOptions maCTLOptions;
+
+ /// The document rendered in the output devices.
+ SdDrawDocument* mpDocument;
+
+ WindowUpdater(const WindowUpdater& rUpdater) = delete;
+
+ WindowUpdater operator=(const WindowUpdater& rUpdater) = delete;
+
+ /** Type and data member for a list of devices that have to be kept
+ up-to-date.
+ */
+ typedef ::std::vector<VclPtr<vcl::Window>> tWindowList;
+ tWindowList maWindowList;
+
+ /** The central method of this class. Update the given output device.
+ It is the task of the caller to initiate a reformatting of the
+ document that is rendered on this device to reflect the changes.
+ @param pWindow
+ The output device to update. When it is <null/> then the call
+ is ignored.
+ */
+ void UpdateWindow(OutputDevice* pDevice) const;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/animobjs.hxx b/sd/source/ui/inc/animobjs.hxx
new file mode 100644
index 000000000..b44a5fb3d
--- /dev/null
+++ b/sd/source/ui/inc/animobjs.hxx
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/dockwin.hxx>
+#include <tools/fract.hxx>
+#include <sfx2/ctrlitem.hxx>
+#include <sfx2/progress.hxx>
+#include <misc/scopelock.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+
+class SdDrawDocument;
+
+namespace sd {
+
+class AnimationControllerItem;
+class View;
+
+enum BitmapAdjustment
+{
+ BA_LEFT_UP,
+ BA_LEFT,
+ BA_LEFT_DOWN,
+ BA_UP,
+ BA_CENTER,
+ BA_DOWN,
+ BA_RIGHT_UP,
+ BA_RIGHT,
+ BA_RIGHT_DOWN
+};
+
+class SdDisplay : public weld::CustomWidgetController
+{
+private:
+ BitmapEx aBitmapEx;
+ Fraction aScale;
+
+public:
+ SdDisplay();
+ virtual ~SdDisplay() override;
+
+ virtual void Paint( vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect ) override;
+
+ void SetBitmapEx( BitmapEx const * pBmpEx );
+ void SetScale( const Fraction& rFrac );
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+};
+
+class AnimationWindow : public SfxDockingWindow
+{
+ friend class AnimationChildWindow;
+ friend class AnimationControllerItem;
+
+public:
+ AnimationWindow(SfxBindings* pBindings, SfxChildWindow *pCW, vcl::Window* pParent);
+ virtual ~AnimationWindow() override;
+ virtual void dispose() override;
+
+ void AddObj( ::sd::View& rView );
+ void CreateAnimObj( ::sd::View& rView );
+
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+
+protected:
+ virtual bool Close() override;
+ virtual void Resize() override;
+
+private:
+ std::unique_ptr<SdDisplay> m_xCtlDisplay;
+ std::unique_ptr<weld::CustomWeld> m_xCtlDisplayWin;
+ std::unique_ptr<weld::Button> m_xBtnFirst;
+ std::unique_ptr<weld::Button> m_xBtnReverse;
+ std::unique_ptr<weld::Button> m_xBtnStop;
+ std::unique_ptr<weld::Button> m_xBtnPlay;
+ std::unique_ptr<weld::Button> m_xBtnLast;
+ std::unique_ptr<weld::SpinButton> m_xNumFldBitmap;
+ std::unique_ptr<weld::FormattedSpinButton> m_xTimeField;
+ std::unique_ptr<weld::TimeFormatter> m_xFormatter;
+ std::unique_ptr<weld::ComboBox> m_xLbLoopCount;
+ std::unique_ptr<weld::Button> m_xBtnGetOneObject;
+ std::unique_ptr<weld::Button> m_xBtnGetAllObjects;
+ std::unique_ptr<weld::Button> m_xBtnRemoveBitmap;
+ std::unique_ptr<weld::Button> m_xBtnRemoveAll;
+ std::unique_ptr<weld::Label> m_xFiCount;
+
+ std::unique_ptr<weld::RadioButton> m_xRbtGroup;
+ std::unique_ptr<weld::RadioButton> m_xRbtBitmap;
+ std::unique_ptr<weld::Label> m_xFtAdjustment;
+ std::unique_ptr<weld::ComboBox> m_xLbAdjustment;
+ std::unique_ptr<weld::Button> m_xBtnCreateGroup;
+ std::unique_ptr<weld::Button> m_xBtnHelp;
+
+ ::std::vector< ::std::pair<BitmapEx, ::tools::Time> > m_FrameList;
+ static const size_t EMPTY_FRAMELIST;
+ size_t m_nCurrentFrame;
+ std::unique_ptr<SdDrawDocument> pMyDoc;
+
+ bool bMovie;
+ bool bAllObjects;
+
+ std::unique_ptr<AnimationControllerItem> pControllerItem;
+
+ ScopeLock maPlayLock;
+
+ DECL_LINK( ClickFirstHdl, weld::Button&, void );
+ DECL_LINK( ClickStopHdl, weld::Button&, void );
+ DECL_LINK( ClickPlayHdl, weld::Button&, void );
+ DECL_LINK( ClickLastHdl, weld::Button&, void );
+ DECL_LINK( ClickGetObjectHdl, weld::Button&, void );
+ DECL_LINK( ClickRemoveBitmapHdl, weld::Button&, void );
+ DECL_LINK( ClickRbtHdl, weld::Toggleable&, void );
+ DECL_LINK( ClickHelpHdl, weld::Button&, void );
+ DECL_LINK( ClickCreateGroupHdl, weld::Button&, void );
+ DECL_LINK( ModifyBitmapHdl, weld::SpinButton&, void );
+ DECL_LINK( ModifyTimeHdl, weld::FormattedSpinButton&, void );
+
+ void UpdateControl(bool bDisableCtrls = false);
+ void ResetAttrs();
+ void WaitInEffect( sal_uLong nMilliSeconds, sal_uLong nTime,
+ SfxProgress* pStbMgr ) const;
+ Fraction GetScale();
+};
+
+/**
+ * ControllerItem for Animator
+ */
+class AnimationControllerItem : public SfxControllerItem
+{
+
+public:
+ AnimationControllerItem( sal_uInt16, AnimationWindow*, SfxBindings* );
+
+protected:
+ virtual void StateChangedAtToolBoxControl( sal_uInt16 nSId, SfxItemState eState,
+ const SfxPoolItem* pState ) override;
+private:
+ VclPtr<AnimationWindow> pAnimationWin;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/annotationmanager.hxx b/sd/source/ui/inc/annotationmanager.hxx
new file mode 100644
index 000000000..6f47efd1f
--- /dev/null
+++ b/sd/source/ui/inc/annotationmanager.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ref.hxx>
+
+class SfxRequest;
+class SfxItemSet;
+
+namespace sd
+{
+class ViewShellBase;
+class AnnotationManagerImpl;
+
+class AnnotationManager
+{
+public:
+ AnnotationManager(ViewShellBase& rViewShellBase);
+ ~AnnotationManager();
+
+ void ExecuteAnnotation(SfxRequest const& rRequest);
+ void GetAnnotationState(SfxItemSet& rItemSet);
+
+private:
+ ::rtl::Reference<AnnotationManagerImpl> mxImpl;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/assclass.hxx b/sd/source/ui/inc/assclass.hxx
new file mode 100644
index 000000000..2b366e971
--- /dev/null
+++ b/sd/source/ui/inc/assclass.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <sddllapi.h>
+
+#define MAX_PAGES 10
+
+namespace weld { class Widget; }
+
+class SD_DLLPUBLIC Assistent
+{
+ /** contains for every page the controls, which have to be
+ connected? correctly */
+ std::vector<weld::Widget*> maPages[MAX_PAGES];
+
+ /// number of pages
+ int mnPages;
+
+ int mnCurrentPage;
+
+ std::unique_ptr<bool[]> mpPageStatus;
+
+public:
+
+ Assistent(int nNoOfPage);
+
+ bool IsEnabled ( int nPage ) const;
+ void EnablePage( int nPage );
+ void DisablePage( int nPage );
+
+ /// adds a control to the specified page
+ bool InsertControl(int nDestPage, weld::Widget* pUsedControl);
+
+ void NextPage();
+
+ void PreviousPage();
+
+ bool GotoPage(const int nPageToGo);
+
+ bool IsLastPage() const;
+
+ bool IsFirstPage() const;
+
+ int GetCurrentPage() const { return mnCurrentPage;}
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/bulmaper.hxx b/sd/source/ui/inc/bulmaper.hxx
new file mode 100644
index 000000000..3de99d262
--- /dev/null
+++ b/sd/source/ui/inc/bulmaper.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sddllapi.h>
+
+class SfxItemSet;
+class SvxNumRule;
+
+class SD_DLLPUBLIC SdBulletMapper
+{
+public:
+ /* #i35937#
+ static void PreMapNumBulletForDialog( SfxItemSet& rSet );
+ static void PostMapNumBulletForDialog( SfxItemSet& rSet );
+*/
+ static void MapFontsInNumRule(SvxNumRule& aNumRule, const SfxItemSet& rSet);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/copydlg.hxx b/sd/source/ui/inc/copydlg.hxx
new file mode 100644
index 000000000..7d8274743
--- /dev/null
+++ b/sd/source/ui/inc/copydlg.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/basedlgs.hxx>
+#include <tools/fract.hxx>
+
+class ColorListBox;
+
+namespace sd
+{
+class View;
+
+/**
+ * dialog to adjust screen
+ */
+class CopyDlg : public SfxDialogController
+{
+public:
+ CopyDlg(weld::Window* pWindow, const SfxItemSet& rInAttrs, ::sd::View* pView);
+ virtual ~CopyDlg() override;
+
+ void GetAttr(SfxItemSet& rOutAttrs);
+ void Reset();
+
+private:
+ const SfxItemSet& mrOutAttrs;
+ Fraction maUIScale;
+ ::sd::View* mpView;
+
+ std::unique_ptr<weld::SpinButton> m_xNumFldCopies;
+ std::unique_ptr<weld::Button> m_xBtnSetViewData;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldMoveX;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldMoveY;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldAngle;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldWidth;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldHeight;
+ std::unique_ptr<weld::Label> m_xFtEndColor;
+ std::unique_ptr<weld::Button> m_xBtnSetDefault;
+ std::unique_ptr<ColorListBox> m_xLbStartColor;
+ std::unique_ptr<ColorListBox> m_xLbEndColor;
+
+ DECL_LINK(SelectColorHdl, ColorListBox&, void);
+ DECL_LINK(SetViewData, weld::Button&, void);
+ DECL_LINK(SetDefault, weld::Button&, void);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/createtableobjectbar.hxx b/sd/source/ui/inc/createtableobjectbar.hxx
new file mode 100644
index 000000000..8fc21f19f
--- /dev/null
+++ b/sd/source/ui/inc/createtableobjectbar.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+class SfxShell;
+
+namespace sd
+{
+class View;
+class ViewShell;
+}
+
+namespace sd::ui::table
+{
+SfxShell* CreateTableObjectBar(ViewShell& rShell, ::sd::View* pView);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/custsdlg.hxx b/sd/source/ui/inc/custsdlg.hxx
new file mode 100644
index 000000000..52ae87852
--- /dev/null
+++ b/sd/source/ui/inc/custsdlg.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+
+class SdDrawDocument;
+class SdCustomShow;
+class SdCustomShowList;
+
+class SdCustomShowDlg : public weld::GenericDialogController
+{
+private:
+ SdDrawDocument& rDoc;
+ SdCustomShowList* pCustomShowList;
+
+ std::unique_ptr<weld::TreeView> m_xLbCustomShows;
+ std::unique_ptr<weld::Button> m_xBtnNew;
+ std::unique_ptr<weld::Button> m_xBtnEdit;
+ std::unique_ptr<weld::Button> m_xBtnRemove;
+ std::unique_ptr<weld::Button> m_xBtnCopy;
+ std::unique_ptr<weld::Button> m_xBtnHelp;
+ std::unique_ptr<weld::Button> m_xBtnStartShow;
+ std::unique_ptr<weld::Button> m_xBtnOK;
+
+ void CheckState();
+
+ DECL_LINK( ClickButtonHdl, weld::Button&, void );
+ DECL_LINK( SelectListBoxHdl, weld::TreeView&, void );
+ DECL_LINK( StartShowHdl, weld::Button&, void );
+ void SelectHdl(void const *);
+
+public:
+ SdCustomShowDlg(weld::Window* pWindow, SdDrawDocument& rDrawDoc);
+ virtual ~SdCustomShowDlg() override;
+ bool IsCustomShow() const;
+};
+
+class SdDefineCustomShowDlg : public weld::GenericDialogController
+{
+private:
+ SdDrawDocument& rDoc;
+ std::unique_ptr<SdCustomShow>& rpCustomShow;
+ bool bModified;
+ OUString aOldName;
+
+ std::unique_ptr<weld::Entry> m_xEdtName;
+ std::unique_ptr<weld::TreeView> m_xLbPages;
+ std::unique_ptr<weld::Button> m_xBtnAdd;
+ std::unique_ptr<weld::Button> m_xBtnRemove;
+ std::unique_ptr<weld::TreeView> m_xLbCustomPages;
+ std::unique_ptr<weld::ReorderingDropTarget> m_xDropTargetHelper;
+ std::unique_ptr<weld::Button> m_xBtnOK;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+ std::unique_ptr<weld::Button> m_xBtnHelp;
+
+ void CheckState();
+ void CheckCustomShow();
+
+ DECL_LINK( ClickButtonHdl, weld::Button&, void );
+ DECL_LINK( ClickButtonEditHdl, weld::Entry&, void );
+ DECL_LINK( ClickButtonHdl3, weld::TreeView&, void );
+ DECL_LINK( ClickButtonHdl4, weld::TreeView&, void );
+ DECL_LINK( OKHdl, weld::Button&, void );
+ void ClickButtonHdl2(void const *);
+
+public:
+
+ SdDefineCustomShowDlg(weld::Window* pWindow, SdDrawDocument& rDrawDoc, std::unique_ptr<SdCustomShow>& rpCS);
+ virtual ~SdDefineCustomShowDlg() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/diactrl.hxx b/sd/source/ui/inc/diactrl.hxx
new file mode 100644
index 000000000..12e76762e
--- /dev/null
+++ b/sd/source/ui/inc/diactrl.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/InterimItemWindow.hxx>
+#include <sfx2/tbxctrl.hxx>
+
+namespace com::sun::star::frame
+{
+class XFrame;
+}
+class SfxUInt16Item;
+
+// SdPagesField:
+
+class SdPagesField final : public InterimItemWindow
+{
+private:
+ std::unique_ptr<weld::SpinButton> m_xWidget;
+ css::uno::Reference<css::frame::XFrame> m_xFrame;
+
+ DECL_LINK(ModifyHdl, weld::SpinButton&, void);
+ DECL_STATIC_LINK(SdPagesField, OutputHdl, weld::SpinButton&, void);
+ DECL_LINK(spin_button_input, int* result, bool);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+
+public:
+ SdPagesField(vcl::Window* pParent, const css::uno::Reference<css::frame::XFrame>& rFrame);
+ virtual void dispose() override;
+ void set_sensitive(bool bSensitive);
+ virtual ~SdPagesField() override;
+
+ void UpdatePagesField(const SfxUInt16Item* pItem);
+};
+
+// SdTbxCtlDiaPages:
+
+class SdTbxCtlDiaPages : public SfxToolBoxControl
+{
+public:
+ virtual void StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState) override;
+ virtual VclPtr<InterimItemWindow> CreateItemWindow(vcl::Window* pParent) override;
+
+ SFX_DECL_TOOLBOX_CONTROL();
+
+ SdTbxCtlDiaPages(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx);
+ virtual ~SdTbxCtlDiaPages() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/dlg_char.hxx b/sd/source/ui/inc/dlg_char.hxx
new file mode 100644
index 000000000..36e791a09
--- /dev/null
+++ b/sd/source/ui/inc/dlg_char.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+
+class SfxItemSet;
+class SfxObjectShell;
+
+/**
+ * Character-Tab-Dialog
+ */
+class SdCharDlg : public SfxTabDialogController
+{
+private:
+ const SfxObjectShell& rDocShell;
+
+ virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override;
+
+public:
+ SdCharDlg(weld::Window* pParent, const SfxItemSet* pAttr, const SfxObjectShell* pDocShell);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/dlgfield.hxx b/sd/source/ui/inc/dlgfield.hxx
new file mode 100644
index 000000000..769dc12c7
--- /dev/null
+++ b/sd/source/ui/inc/dlgfield.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <memory>
+#include <svl/itemset.hxx>
+
+class SvxFieldData;
+class SvxLanguageBox;
+
+/**
+ * dialog to adjust field-commands
+ */
+class SdModifyFieldDlg : public weld::GenericDialogController
+{
+private:
+ SfxItemSet m_aInputSet;
+ const SvxFieldData* m_pField;
+
+ std::unique_ptr<weld::RadioButton> m_xRbtFix;
+ std::unique_ptr<weld::RadioButton> m_xRbtVar;
+ std::unique_ptr<SvxLanguageBox> m_xLbLanguage;
+ std::unique_ptr<weld::ComboBox> m_xLbFormat;
+
+ void FillFormatList();
+ void FillControls();
+
+ DECL_LINK(LanguageChangeHdl, weld::ComboBox&, void);
+
+public:
+ SdModifyFieldDlg(weld::Window* pWindow, const SvxFieldData* pInField, const SfxItemSet& rSet);
+ virtual ~SdModifyFieldDlg() override;
+
+ SvxFieldData* GetField();
+ SfxItemSet GetItemSet() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/dlgpage.hxx b/sd/source/ui/inc/dlgpage.hxx
new file mode 100644
index 000000000..718ccf0c6
--- /dev/null
+++ b/sd/source/ui/inc/dlgpage.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+#include <svx/xtable.hxx>
+
+class SfxObjectShell;
+enum class ChangeType;
+
+/**
+ * Page configuration-tab-dialog
+ */
+class SdPageDlg : public SfxTabDialogController
+{
+private:
+ bool mbIsImpressDoc;
+
+ XColorListRef mpColorList;
+ XGradientListRef mpGradientList;
+ XHatchListRef mpHatchingList;
+ XBitmapListRef mpBitmapList;
+ XPatternListRef mpPatternList;
+public:
+
+ SdPageDlg(SfxObjectShell const * pDocSh, weld::Window* pParent, const SfxItemSet* pAttr, bool bAreaPage, bool bIsImpressDoc, bool bIsImpressMaster);
+
+ virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/dlgsnap.hxx b/sd/source/ui/inc/dlgsnap.hxx
new file mode 100644
index 000000000..97fe09ccb
--- /dev/null
+++ b/sd/source/ui/inc/dlgsnap.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/fract.hxx>
+#include <vcl/weld.hxx>
+
+/************************************************************************/
+
+class SfxItemSet;
+namespace sd {
+ class View;
+}
+
+/**
+ * dialog to adjust snap- lines and points
+ */
+class SdSnapLineDlg : public weld::GenericDialogController
+{
+private:
+ int nXValue;
+ int nYValue;
+ Fraction aUIScale;
+
+ std::unique_ptr<weld::Label> m_xFtX;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldX;
+ std::unique_ptr<weld::Label> m_xFtY;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldY;
+ std::unique_ptr<weld::Widget> m_xRadioGroup;
+ std::unique_ptr<weld::RadioButton> m_xRbPoint;
+ std::unique_ptr<weld::RadioButton> m_xRbVert;
+ std::unique_ptr<weld::RadioButton> m_xRbHorz;
+ std::unique_ptr<weld::Button> m_xBtnDelete;
+
+ DECL_LINK(ClickHdl, weld::Button&, void);
+ DECL_LINK(ToggleHdl, weld::Toggleable&, void);
+
+public:
+ SdSnapLineDlg(weld::Window* pWindow, const SfxItemSet& rInAttrs, ::sd::View const * pView);
+ virtual ~SdSnapLineDlg() override;
+
+ void GetAttr(SfxItemSet& rOutAttrs);
+
+ void HideRadioGroup();
+ void HideDeleteBtn() { m_xBtnDelete->hide(); }
+ void SetInputFields(bool bEnableX, bool bEnableY);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/drawview.hxx b/sd/source/ui/inc/drawview.hxx
new file mode 100644
index 000000000..daa5cc026
--- /dev/null
+++ b/sd/source/ui/inc/drawview.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "View.hxx"
+
+#include <sddllapi.h>
+
+namespace sd {
+
+class DrawDocShell;
+class DrawViewShell;
+
+/**
+ * Derivative of ::sd::View; contains also a pointer to the document
+ */
+class SD_DLLPUBLIC DrawView : public ::sd::View
+{
+public:
+
+ DrawView (
+ DrawDocShell* pDocSh,
+ OutputDevice* pOutDev,
+ DrawViewShell* pShell);
+ virtual ~DrawView() override;
+
+ virtual void MarkListHasChanged() override;
+ void CompleteRedraw(OutputDevice* pOutDev, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector = nullptr) override;
+
+ virtual bool SetAttributes(const SfxItemSet& rSet, bool bReplaceAll = false, bool bSlide = false, bool bMaster = false) override;
+ void SetMasterAttributes(SdrObject* pObject, const SdPage& rPage, SfxItemSet rSet, SfxStyleSheetBasePool* pStShPool, bool& bOk, bool bMaster, bool bSlide);
+
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+ void BlockPageOrderChangedHint(bool bBlock);
+
+ bool SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr = false) override;
+
+ virtual void MakeVisible(const ::tools::Rectangle& rRect, vcl::Window& rWin) override;
+ virtual void HideSdrPage() override; // SdrPageView* pPV);
+
+ virtual void DeleteMarked() override; // from SdrView
+protected:
+ virtual void ModelHasChanged() override;
+
+private:
+ DrawDocShell* mpDocShell;
+ DrawViewShell* mpDrawViewShell;
+
+ sal_uInt16 mnPOCHSmph; ///< for blocking PageOrderChangedHint
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/filedlg.hxx b/sd/source/ui/inc/filedlg.hxx
new file mode 100644
index 000000000..6a22d6ba5
--- /dev/null
+++ b/sd/source/ui/inc/filedlg.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/errcode.hxx>
+#include <vcl/weld.hxx>
+
+#include <memory>
+
+#include <sddllapi.h>
+
+class SdFileDialog_Imp;
+
+/******************************************************************************/
+
+/**
+ The class SdOpenSoundFileDialog wraps the FileDialogHelper, displaying the
+ FILEOPEN_PLAY dialog template and performing the 'preview' functionality
+ (playing the selected sound file). The interface is a downstripped version
+ of the aforementioned class, with similar semantics.
+ */
+class SD_DLLPUBLIC SdOpenSoundFileDialog
+{
+ const std::unique_ptr<SdFileDialog_Imp> mpImpl;
+
+ SdOpenSoundFileDialog(const SdOpenSoundFileDialog&) = delete;
+ SdOpenSoundFileDialog& operator=(const SdOpenSoundFileDialog&) = delete;
+
+public:
+ SdOpenSoundFileDialog(weld::Window* pParent);
+ ~SdOpenSoundFileDialog();
+
+ ErrCode Execute();
+ OUString GetPath() const;
+ void SetPath(const OUString& rPath);
+ // WIP, please don't remove, dear Clang plugins
+ bool IsInsertAsLinkSelected() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/Configuration.hxx b/sd/source/ui/inc/framework/Configuration.hxx
new file mode 100644
index 000000000..8f33ef431
--- /dev/null
+++ b/sd/source/ui/inc/framework/Configuration.hxx
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfiguration.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <comphelper/compbase.hxx>
+
+#include <memory>
+
+namespace com::sun::star::util { class XCloneable; }
+namespace com::sun::star::drawing::framework { class XConfigurationControllerBroadcaster; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfiguration,
+ css::container::XNamed,
+ css::lang::XServiceInfo
+ > ConfigurationInterfaceBase;
+
+/** A configuration describes the resources of an application like panes,
+ views, and tool bars and their relationships that are currently active
+ or are requested to be activated. Resources are specified by URLs rather
+ than references so that not only the current configuration but also a
+ requested configuration can be represented.
+
+ A resource URL describes the type of a resource, not its actual
+ instance. For resources, like panes, that are unique with respect to an
+ application frame, that does not mean much of a difference. For other
+ resources like views, that may have more than one instance per
+ application frame, this is different. To identify them unambiguously a
+ second URL, one of a unique resource, is necessary. This second URL is
+ called the anchor of the first. The two types of resources are called
+ unique and linked respectively.
+
+ Direct manipulation of a configuration object is not advised with the
+ exception of the configuration controller and objects that implement the
+ XConfigurationChangeOperation interface.
+*/
+class Configuration final
+ : public ConfigurationInterfaceBase
+{
+public:
+ /** Create a new configuration with a broadcaster that is used to send
+ events about requested configuration changes.
+ @param rxBroadcaster
+ This broadcaster is typically the same as the one used by the
+ ConfigurationController.
+ @param bBroadcastRequestEvents
+ When this is <TRUE/> then modifications to the configuration
+ trigger the broadcasting of "ResourceActivationRequestEvent" and
+ "ResourceDeactivationRequestEvent". When this flag is <FALSE/>
+ then events with type "ResourceActivationEvent" and
+ "ResourceDeactivationEvent" are broadcasted.
+ */
+ Configuration (const css::uno::Reference<css::drawing::framework::XConfigurationControllerBroadcaster>& rxBroadcaster,
+ bool bBroadcastRequestEvents);
+ virtual ~Configuration() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfiguration
+
+ virtual void SAL_CALL addResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>&
+ rxResourceId) override;
+
+ virtual void SAL_CALL removeResource(
+ const css::uno::Reference<css::drawing::framework::XResourceId>&
+ rxResourceId) override;
+
+ virtual css::uno::Sequence< css::uno::Reference<
+ css::drawing::framework::XResourceId> > SAL_CALL getResources (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxAnchorId,
+ const OUString& rsResourceURLPrefix,
+ css::drawing::framework::AnchorBindingMode eMode) override;
+
+ virtual sal_Bool SAL_CALL hasResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>&
+ rxResourceId) override;
+
+ // XCloneable
+
+ virtual css::uno::Reference<css::util::XCloneable>
+ SAL_CALL createClone() override;
+
+ // XNamed
+
+ /** Return a human readable string representation. This is used for
+ debugging purposes.
+ */
+ virtual OUString SAL_CALL getName() override;
+
+ /** This call is ignored because the XNamed interface is (mis)used to
+ give access to a human readable name for debugging purposes.
+ */
+ virtual void SAL_CALL setName (const OUString& rName) override;
+
+ OUString SAL_CALL getImplementationName() override;
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+private:
+ class ResourceContainer;
+ /** The resource container holds the URLs of unique resource and of
+ resource linked to unique resources.
+ */
+ std::unique_ptr<ResourceContainer> mpResourceContainer;
+
+ /** The broadcaster used for notifying listeners of requests for
+ configuration changes.
+ */
+ css::uno::Reference<css::drawing::framework::XConfigurationControllerBroadcaster>
+ mxBroadcaster;
+
+ bool mbBroadcastRequestEvents;
+
+ /** This private variant of the constructor is used for cloning a
+ Configuration object.
+ @param rResourceContainer
+ The new Configuration is created with a copy of the elements in
+ this container.
+ */
+ Configuration (const css::uno::Reference<css::drawing::framework::XConfigurationControllerBroadcaster>& rxBroadcaster,
+ bool bBroadcastRequestEvents,
+ const ResourceContainer& rResourceContainer);
+
+ /** Send an event to all interested listeners that a resource has been
+ added or removed. The event is sent to the listeners via the
+ ConfigurationController.
+ @param rxResourceId
+ The resource that is added to or removed from the configuration.
+ @param bActivation
+ This specifies whether an activation or deactivation is
+ broadcasted. The mbBroadcastRequestEvents member is also taken
+ into account when the actual event type field is determined.
+ */
+ void PostEvent (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const bool bActivation);
+
+ /** When the called object has already been disposed this method throws
+ an exception and does not return.
+
+ @throws css::lang::DisposedException
+ */
+ void ThrowIfDisposed() const;
+};
+
+/** Return whether the two given configurations contain the same resource
+ ids. The order of resource ids is ignored. Empty references are
+ treated like empty configurations.
+*/
+bool AreConfigurationsEquivalent (
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration1,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration2);
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/ConfigurationController.hxx b/sd/source/ui/inc/framework/ConfigurationController.hxx
new file mode 100644
index 000000000..2fe2f48d0
--- /dev/null
+++ b/sd/source/ui/inc/framework/ConfigurationController.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+
+#include <memory>
+
+
+namespace com::sun::star::drawing::framework { class XConfiguration; }
+namespace com::sun::star::drawing::framework { class XConfigurationChangeRequest; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+namespace com::sun::star::drawing::framework { struct ConfigurationChangeEvent; }
+
+namespace sd::framework {
+
+typedef ::cppu::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationController,
+ css::lang::XInitialization
+ > ConfigurationControllerInterfaceBase;
+
+/** The configuration controller is responsible for maintaining the current
+ configuration.
+
+ @see css::drawing::framework::XConfigurationController
+ for an extended documentation.
+*/
+class ConfigurationController
+ : private cppu::BaseMutex,
+ public ConfigurationControllerInterfaceBase
+{
+public:
+ ConfigurationController() noexcept;
+ virtual ~ConfigurationController() noexcept override;
+ ConfigurationController(const ConfigurationController&) = delete;
+ ConfigurationController& operator=(const ConfigurationController&) = delete;
+
+ virtual void SAL_CALL disposing() override;
+
+ void ProcessEvent();
+
+ /** Normally the requested changes of the configuration are executed
+ asynchronously. However, there is at least one situation (searching
+ with the Outliner) where the surrounding code does not cope with
+ this. So, instead of calling Reschedule until the global event loop
+ executes the configuration update, this method does (almost) the
+ same without the reschedules.
+
+ Do not use this method until there is absolutely no other way.
+ */
+ void RequestSynchronousUpdate();
+
+ // XConfigurationController
+
+ virtual void SAL_CALL lock() override;
+
+ virtual void SAL_CALL unlock() override;
+
+ virtual void SAL_CALL requestResourceActivation (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ css::drawing::framework::ResourceActivationMode eMode) override;
+
+ virtual void SAL_CALL requestResourceDeactivation (
+ const css::uno::Reference<css::drawing::framework::XResourceId>&
+ rxResourceId) override;
+
+ virtual css::uno::Reference<css::drawing::framework::XResource>
+ SAL_CALL getResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId) override;
+
+ virtual void SAL_CALL update() override;
+
+ virtual css::uno::Reference<
+ css::drawing::framework::XConfiguration>
+ SAL_CALL getRequestedConfiguration() override;
+
+ virtual css::uno::Reference<
+ css::drawing::framework::XConfiguration>
+ SAL_CALL getCurrentConfiguration() override;
+
+ virtual void SAL_CALL restoreConfiguration (
+ const css::uno::Reference<css::drawing::framework::XConfiguration>&
+ rxConfiguration) override;
+
+ // XConfigurationControllerBroadcaster
+
+ virtual void SAL_CALL addConfigurationChangeListener (
+ const css::uno::Reference<
+ css::drawing::framework::XConfigurationChangeListener>& rxListener,
+ const OUString& rsEventType,
+ const css::uno::Any& rUserData) override;
+
+ virtual void SAL_CALL removeConfigurationChangeListener (
+ const css::uno::Reference<
+ css::drawing::framework::XConfigurationChangeListener>& rxListener) override;
+
+ virtual void SAL_CALL notifyEvent (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XConfigurationRequestQueue
+
+ virtual sal_Bool SAL_CALL hasPendingRequests() override;
+
+ virtual void SAL_CALL postChangeRequest (
+ const css::uno::Reference<
+ css::drawing::framework::XConfigurationChangeRequest>& rxRequest) override;
+
+ // XResourceFactoryManager
+
+ virtual void SAL_CALL addResourceFactory(
+ const OUString& sResourceURL,
+ const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxResourceFactory) override;
+
+ virtual void SAL_CALL removeResourceFactoryForURL(
+ const OUString& sResourceURL) override;
+
+ virtual void SAL_CALL removeResourceFactoryForReference(
+ const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxResourceFactory) override;
+
+ virtual css::uno::Reference<css::drawing::framework::XResourceFactory>
+ SAL_CALL getResourceFactory (
+ const OUString& sResourceURL) override;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ /** Use this class instead of calling lock() and unlock() directly in
+ order to be exception safe.
+ */
+ class Lock
+ {
+ public:
+ Lock (const css::uno::Reference<
+ css::drawing::framework::XConfigurationController>& rxController);
+ ~Lock();
+ private:
+ css::uno::Reference<
+ css::drawing::framework::XConfigurationController> mxController;
+ };
+
+private:
+ class Implementation;
+ std::unique_ptr<Implementation> mpImplementation;
+ bool mbIsDisposed;
+
+ /** When the called object has already been disposed this method throws
+ an exception and does not return.
+
+ @throws css::lang::DisposedException
+ @throws css::uno::RuntimeException
+ */
+ void ThrowIfDisposed () const;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/DrawModule.hxx b/sd/source/ui/inc/framework/DrawModule.hxx
new file mode 100644
index 000000000..79a59b4f9
--- /dev/null
+++ b/sd/source/ui/inc/framework/DrawModule.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+namespace com::sun::star::frame
+{
+class XController;
+}
+namespace com::sun::star::uno
+{
+template <typename> class Reference;
+}
+
+namespace sd::framework
+{
+/** The task of this module is to instantiate all modules that belong to the
+ Draw application.
+*/
+class DrawModule
+{
+public:
+ static void Initialize(css::uno::Reference<css::frame::XController> const& rxController);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/FrameworkHelper.hxx b/sd/source/ui/inc/framework/FrameworkHelper.hxx
new file mode 100644
index 000000000..c9bf981bb
--- /dev/null
+++ b/sd/source/ui/inc/framework/FrameworkHelper.hxx
@@ -0,0 +1,340 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ViewShell.hxx>
+
+#include <tools/SdGlobalResourceContainer.hxx>
+
+#include <functional>
+#include <map>
+#include <memory>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+namespace com::sun::star::drawing::framework { class XView; }
+namespace com::sun::star::drawing::framework { struct ConfigurationChangeEvent; }
+
+namespace sd {
+class ViewShellBase;
+}
+
+
+namespace sd::framework {
+
+/** The FrameworkHelper is a convenience class that simplifies the
+ access to the drawing framework.
+ It has three main tasks:
+ 1. Provide frequently used strings of resource URLs and event names.
+ 2. Provide shortcuts for accessing the sd framework.
+ 3. Ease the migration to the drawing framework.
+
+ Note that a FrameworkHelper disposes itself when one of the resource
+ controllers called by it throws a DisposedException.
+*/
+class FrameworkHelper
+ : public std::enable_shared_from_this<FrameworkHelper>,
+ public SdGlobalResource
+{
+public:
+ // URLs of frequently used panes.
+ static constexpr OUStringLiteral msPaneURLPrefix = u"private:resource/pane/";
+ static const OUString msCenterPaneURL;
+ static const OUString msFullScreenPaneURL;
+ static const OUString msLeftImpressPaneURL;
+ static const OUString msLeftDrawPaneURL;
+
+ // URLs of frequently used views.
+ static constexpr OUStringLiteral msViewURLPrefix = u"private:resource/view/";
+ static const OUString msImpressViewURL;
+ static const OUString msDrawViewURL;
+ static const OUString msOutlineViewURL;
+ static const OUString msNotesViewURL;
+ static const OUString msHandoutViewURL;
+ static const OUString msSlideSorterURL;
+ static const OUString msPresentationViewURL;
+ static const OUString msSidebarViewURL;
+
+ // URLs of frequently used tool bars.
+ static constexpr OUStringLiteral msToolBarURLPrefix = u"private:resource/toolbar/";
+ static const OUString msViewTabBarURL;
+
+ // Names of frequently used events.
+ static constexpr OUStringLiteral msResourceActivationRequestEvent
+ = u"ResourceActivationRequested";
+ static constexpr OUStringLiteral msResourceDeactivationRequestEvent
+ = u"ResourceDeactivationRequest";
+ static constexpr OUStringLiteral msResourceActivationEvent = u"ResourceActivation";
+ static constexpr OUStringLiteral msResourceDeactivationEvent = u"ResourceDeactivation";
+ static constexpr OUStringLiteral msResourceDeactivationEndEvent = u"ResourceDeactivationEnd";
+ static constexpr OUStringLiteral msConfigurationUpdateStartEvent = u"ConfigurationUpdateStart";
+ static constexpr OUStringLiteral msConfigurationUpdateEndEvent = u"ConfigurationUpdateEnd";
+
+ /** Return the FrameworkHelper object that is associated with the given
+ ViewShellBase. If such an object does not yet exist, a new one is
+ created.
+ */
+ static ::std::shared_ptr<FrameworkHelper> Instance (ViewShellBase& rBase);
+
+ /** Mark the FrameworkHelper object for the given ViewShellBase as
+ disposed. A following ReleaseInstance() call will destroy the
+ FrameworkHelper object.
+
+ Do not call this method. It is an internally used method that can
+ not be made private.
+ */
+ static void DisposeInstance (const ViewShellBase& rBase);
+
+ /** Destroy the FrameworkHelper object for the given ViewShellBase.
+
+ Do not call this method. It is an internally used method that can
+ not be made private.
+ */
+ static void ReleaseInstance (const ViewShellBase& rBase);
+
+ /** Return an identifier for the given view URL. This identifier can be
+ used in a switch statement. See GetViewURL() for a mapping in the
+ opposite direction.
+ */
+ static ViewShell::ShellType GetViewId (const OUString& rsViewURL);
+
+ /** Return a view URL for the given identifier. See GetViewId() for a
+ mapping in the opposite direction.
+ */
+ static OUString GetViewURL (ViewShell::ShellType eType);
+
+ /** Return a ViewShell pointer for the given XView reference. This
+ assumes that the given reference is implemented by the
+ ViewShellWrapper class that supports the XTunnel interface.
+ @return
+ When the ViewShell pointer can not be inferred from the given
+ reference then an empty pointer is returned.
+ */
+ static ::std::shared_ptr<ViewShell> GetViewShell (
+ const css::uno::Reference<css::drawing::framework::XView>& rxView);
+
+ typedef ::std::function<bool (const css::drawing::framework::ConfigurationChangeEvent&)>
+ ConfigurationChangeEventFilter;
+ typedef ::std::function<void (bool bEventSeen)> Callback;
+ typedef ::std::function<
+ void (
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>&)
+ > ResourceFunctor;
+
+ /** Test whether the called FrameworkHelper object is valid.
+ @return
+ When the object has already been disposed then <FALSE/> is returned.
+ */
+ bool IsValid() const;
+
+ /** Return a pointer to the view shell that is displayed in the
+ specified pane. See GetView() for a variant that returns a
+ reference to XView instead of a ViewShell pointer.
+ @return
+ An empty pointer is returned when for example the specified pane
+ does not exist or is not visible or does not show a view or one
+ of the involved objects does not support XUnoTunnel (where
+ necessary).
+ */
+ ::std::shared_ptr<ViewShell> GetViewShell (const OUString& rsPaneURL);
+
+ /** Return a reference to the view that is displayed in the specified
+ pane. See GetViewShell () for a variant that returns a ViewShell
+ pointer instead of a reference to XView.
+ @param rxPaneOrViewId
+ When this ResourceId specifies a view then that view is
+ returned. When it belongs to a pane then one view in that pane
+ is returned.
+ @return
+ An empty reference is returned when for example the specified pane
+ does not exist or is not visible or does not show a view or one
+ of the involved objects does not support XTunnel (where
+ necessary).
+ */
+ css::uno::Reference<css::drawing::framework::XView> GetView (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneOrViewId);
+
+ /** Request the specified view to be displayed in the specified pane.
+ When the pane is not visible its creation is also requested. The
+ update that creates the actual view object is done asynchronously.
+ @param rsResourceURL
+ The resource URL of the view to show.
+ @param rsAnchorURL
+ The URL of the pane in which to show the view.
+ @return
+ The resource id of the requested view is returned. With that
+ the caller can, for example, call RunOnResourceActivation() to
+ do some initialization after the requested view becomes active.
+ */
+ css::uno::Reference<css::drawing::framework::XResourceId> RequestView (
+ const OUString& rsResourceURL,
+ const OUString& rsAnchorURL);
+
+ /** Process a slot call that requests a view shell change.
+ */
+ void HandleModeChangeSlot (
+ sal_uInt16 nSlotId,
+ SfxRequest const & rRequest);
+
+ /** Run the given callback when the specified event is notified by the
+ ConfigurationManager. When there are no pending requests and
+ therefore no events would be notified (in the foreseeable future)
+ then the callback is called immediately.
+ The callback is called with a flag that tells the callback whether
+ the event it waits for has been sent.
+ */
+ void RunOnConfigurationEvent(
+ const OUString& rsEventType,
+ const Callback& rCallback);
+
+ /** Run the given callback when the specified resource has been
+ activated. When the resource is active already when this method is
+ called then rCallback is called before this method returns.
+ @param rxResourceId
+ Wait for the activation of this resource before calling
+ rCallback.
+ @param rCallback
+ The callback to be called when the resource is activated.
+
+ */
+ void RunOnResourceActivation(
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const Callback& rCallback);
+
+ /** Normally the requested changes of the configuration are executed
+ asynchronously. However, there is at least one situation (searching
+ with the Outliner) where the surrounding code does not cope with
+ this. So, instead of calling Reschedule until the global event loop
+ executes the configuration update, this method does (almost) the
+ same without the reschedules.
+
+ Do not use this method until there is absolutely no other way.
+ */
+ void RequestSynchronousUpdate();
+
+ /** Block until the specified event is notified by the configuration
+ controller. When the configuration controller is not processing any
+ requests the method returns immediately.
+ */
+ void WaitForEvent (const OUString& rsEventName) const;
+
+ /** This is a short cut for WaitForEvent(msConfigurationUpdateEndEvent).
+ Call this method to execute the pending requests.
+ */
+ void WaitForUpdate() const;
+
+ /** Explicit request for an update of the current configuration. Call
+ this method when one of the resources managed by the sd framework
+ has been activated or deactivated from the outside, i.e. not by the
+ framework itself. An example for this is a click on the closer
+ button of one of the side panes.
+ */
+ void UpdateConfiguration();
+
+ /** Return a string representation of the given XResourceId object.
+ */
+ static OUString ResourceIdToString (
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxResourceId);
+
+ /** Create a new XResourceId object for the given resource URL.
+ */
+ static css::uno::Reference<
+ css::drawing::framework::XResourceId>
+ CreateResourceId (
+ const OUString& rsResourceURL);
+
+ /** Create a new XResourceId object for the given resource URL and a
+ single anchor URL.
+ */
+ static css::uno::Reference<
+ css::drawing::framework::XResourceId>
+ CreateResourceId (
+ const OUString& rsResourceURL,
+ const OUString& rsAnchorURL);
+
+ /** Create a new XResourceId object for the given resource URL.
+ */
+ static css::uno::Reference<
+ css::drawing::framework::XResourceId>
+ CreateResourceId (
+ const OUString& rsResourceURL,
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxAnchor);
+
+ const css::uno::Reference<css::drawing::framework::XConfigurationController>&
+ GetConfigurationController() const { return mxConfigurationController;}
+
+private:
+ typedef ::std::map<
+ const ViewShellBase*,
+ ::std::shared_ptr<FrameworkHelper> > InstanceMap;
+ /** The instance map holds (at least) one FrameworkHelper instance for
+ every ViewShellBase object.
+ */
+ static InstanceMap maInstanceMap;
+ class ViewURLMap;
+ static ViewURLMap maViewURLMap;
+
+ ViewShellBase& mrBase;
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+
+ class DisposeListener;
+ friend class DisposeListener;
+ css::uno::Reference<css::lang::XComponent>
+ mxDisposeListener;
+
+ FrameworkHelper (ViewShellBase& rBase);
+ FrameworkHelper (const FrameworkHelper& rHelper) = delete;
+ virtual ~FrameworkHelper() override;
+ class Deleter; friend class Deleter;
+ FrameworkHelper& operator= (const FrameworkHelper& rHelper) = delete;
+
+ void Initialize();
+
+ void Dispose();
+
+ /** Run the given callback when an event of the specified type is
+ received from the ConfigurationController or when the
+ ConfigurationController has no pending change requests.
+ @param rsEventType
+ Run rCallback only on this event.
+ @param rFilter
+ This filter has to return <TRUE/> in order for rCallback to be
+ called.
+ @param rCallback
+ The callback functor to be called.
+ */
+ void RunOnEvent(
+ const OUString& rsEventType,
+ const ConfigurationChangeEventFilter& rFilter,
+ const Callback& rCallback) const;
+
+ /** This disposing method is forwarded from the inner DisposeListener class.
+ */
+ void disposing (const css::lang::EventObject& rEventObject);
+};
+
+} // end of namespace sd::framework
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/ImpressModule.hxx b/sd/source/ui/inc/framework/ImpressModule.hxx
new file mode 100644
index 000000000..da7ede9d9
--- /dev/null
+++ b/sd/source/ui/inc/framework/ImpressModule.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+namespace com::sun::star::frame
+{
+class XController;
+}
+namespace com::sun::star::uno
+{
+template <class interface_type> class Reference;
+}
+
+namespace sd::framework
+{
+/** The task of this module is to instantiate all modules that belong to the
+ Impress application.
+*/
+class ImpressModule
+{
+public:
+ static void Initialize(css::uno::Reference<css::frame::XController> const& rxController);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/ModuleController.hxx b/sd/source/ui/inc/framework/ModuleController.hxx
new file mode 100644
index 000000000..4efc6cc15
--- /dev/null
+++ b/sd/source/ui/inc/framework/ModuleController.hxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XModuleController.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/compbase.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <unordered_map>
+
+namespace com::sun::star::frame { class XController; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XModuleController,
+ css::lang::XInitialization
+ > ModuleControllerInterfaceBase;
+
+/** The ModuleController has two tasks:
+
+ 1. It reads the
+ org.openoffice.Office.Impress/MultiPaneGUI/Framework/ResourceFactories
+ configuration data that maps from resource URLs to service names of
+ factories that can create resources for the URLs. When the
+ configuration controller wants to create a resource for which it does
+ not have a factory, it asks the ModuleController to provide one. The
+ ModuleController looks up the service name registered for the URL of the
+ resource and instantiates this service. The service is expected to
+ register on its creation a factory for the resource in question.
+
+ 2. The ModuleController reads on its creation
+ org.openoffice.Office.Impress/MultiPaneGUI/Framework/StartupServices
+ configuration data and instantiates all listed services. These services
+ can then register as listeners at the ConfigurationController or do
+ whatever they like.
+*/
+class ModuleController final
+ : public ModuleControllerInterfaceBase
+{
+public:
+ static css::uno::Reference<
+ css::drawing::framework::XModuleController>
+ CreateInstance (
+ const css::uno::Reference<css::uno::XComponentContext>&
+ rxContext);
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XModuleController
+
+ virtual void SAL_CALL requestResource(const OUString& rsResourceURL) override;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence<css::uno::Any>& aArguments) override;
+
+private:
+ css::uno::Reference<
+ css::frame::XController> mxController;
+
+ std::unordered_map<OUString, OUString> maResourceToFactoryMap;
+ std::unordered_map<OUString, css::uno::WeakReference<css::uno::XInterface>> maLoadedFactories;
+
+ /// @throws std::exception
+ ModuleController (
+ const css::uno::Reference<css::uno::XComponentContext>& rxContext);
+ ModuleController (const ModuleController&) = delete;
+ virtual ~ModuleController() noexcept override;
+
+ /** Called for every entry in the ResourceFactories configuration entry.
+ */
+ void ProcessFactory (const ::std::vector<css::uno::Any>& rValues);
+
+ /** Instantiate all startup services that are found in the
+ /org.openoffice.Office.Impress/MultiPaneGUI/Framework/StartupServices
+ configuration entry. This method is called once when a new
+ ModuleController object is created.
+ */
+ void InstantiateStartupServices();
+
+ /** Called for one entry in the StartupServices configuration list this
+ method instantiates the service described by the entry. It does not
+ hold references to the new object so that the object will be
+ destroyed on function exit when it does not register itself
+ somewhere. It typically will register as
+ XConfigurationChangeListener at the configuration controller.
+ */
+ void ProcessStartupService (const ::std::vector<css::uno::Any>& rValues);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/Pane.hxx b/sd/source/ui/inc/framework/Pane.hxx
new file mode 100644
index 000000000..9e8ee25a1
--- /dev/null
+++ b/sd/source/ui/inc/framework/Pane.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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XPane.hpp>
+#include <com/sun/star/drawing/framework/XPane2.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/window.hxx>
+
+namespace sd::framework {
+
+typedef ::cppu::WeakComponentImplHelper <
+ css::drawing::framework::XPane,
+ css::drawing::framework::XPane2,
+ css::lang::XUnoTunnel
+ > PaneInterfaceBase;
+
+/** A pane is a wrapper for a window and possibly for a tab bar (for view
+ switching). Panes are unique resources.
+
+ This class has two responsibilities:
+ 1. It implements the XPane interface. This is the most important
+ interface of this class for API based views (of which there not that
+ many yet) because it gives access to the XWindow.
+ 2. It gives access to the underlying VCL Window by implementing the
+ XUnoTunnel interface. This is necessary at the moment and in the
+ foreseeable future because many parts of the Draw and Impress views rely
+ on direct access on the Window class.
+*/
+class Pane
+ : protected cppu::BaseMutex,
+ public PaneInterfaceBase
+{
+public:
+ /** Create a new Pane object that wraps the given window.
+ @param rsPaneURL
+ The URL that is used by the configuration to identify the pane.
+ The given URL has to be valid.
+ @param pWindow
+ The VCL Window (usually this really is an sd::Window) that is
+ wrapped by the new Pane object. The given pointer must not be
+ NULL.
+ */
+ Pane (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId,
+ vcl::Window* pWindow)
+ noexcept;
+ virtual ~Pane() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ static const css::uno::Sequence<sal_Int8>& getUnoTunnelId();
+
+ /** This method is typically used together with the XUnoTunnel to obtain
+ a Window pointer from an XPane object.
+ */
+ virtual vcl::Window* GetWindow();
+
+ //----- XPane -------------------------------------------------------------
+
+ /** For a UNO API based implementation of a view this may the most
+ important method of this class because the view is only interested
+ in the window of the pane.
+ */
+ virtual css::uno::Reference<css::awt::XWindow>
+ SAL_CALL getWindow() override;
+
+ virtual css::uno::Reference<css::rendering::XCanvas>
+ SAL_CALL getCanvas() override;
+
+ //----- XPane2 -------------------------------------------------------------
+
+ virtual sal_Bool SAL_CALL isVisible() override;
+
+ virtual void SAL_CALL setVisible (sal_Bool bIsVisible) override;
+
+ virtual css::uno::Reference<css::accessibility::XAccessible> SAL_CALL getAccessible() override;
+
+ virtual void SAL_CALL setAccessible (
+ const css::uno::Reference<css::accessibility::XAccessible>& rxAccessible) override;
+
+ //----- XResource ---------------------------------------------------------
+
+ virtual css::uno::Reference<css::drawing::framework::XResourceId>
+ SAL_CALL getResourceId() override;
+
+ /** For the typical pane it makes no sense to be displayed without a
+ view. Therefore this default implementation returns always <TRUE/>.
+ */
+ virtual sal_Bool SAL_CALL isAnchorOnly() override;
+
+ //----- XUnoTunnel --------------------------------------------------------
+
+ virtual sal_Int64 SAL_CALL getSomething (const css::uno::Sequence<sal_Int8>& rId) override;
+
+protected:
+ css::uno::Reference<css::drawing::framework::XResourceId> mxPaneId;
+ VclPtr<vcl::Window> mpWindow;
+ css::uno::Reference<css::awt::XWindow> mxWindow;
+ css::uno::Reference<css::rendering::XCanvas> mxCanvas;
+
+ /** Override this method, not getCanvas(), when you want to provide a
+ different canvas.
+
+ @throws css::uno::RuntimeException
+ */
+ virtual css::uno::Reference<css::rendering::XCanvas>
+ CreateCanvas();
+
+ /** Throw DisposedException when the object has already been disposed or
+ is currently being disposed. Otherwise this method returns
+ normally.
+
+ @throws css::lang::DisposedException
+ */
+ void ThrowIfDisposed() const;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/PresentationFactory.hxx b/sd/source/ui/inc/framework/PresentationFactory.hxx
new file mode 100644
index 000000000..897825c8a
--- /dev/null
+++ b/sd/source/ui/inc/framework/PresentationFactory.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XResourceFactory.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::frame { class XController; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XResourceFactory,
+ css::drawing::framework::XConfigurationChangeListener
+ > PresentationFactoryInterfaceBase;
+
+/** This factory creates a marker view whose existence in a configuration
+ indicates that a slideshow is running (in another but associated
+ application window).
+*/
+class PresentationFactory final
+ : public PresentationFactoryInterfaceBase
+{
+public:
+ PresentationFactory (
+ const css::uno::Reference<css::frame::XController>& rxController);
+ virtual ~PresentationFactory() override;
+
+ // XResourceFactory
+
+ virtual css::uno::Reference<css::drawing::framework::XResource>
+ SAL_CALL createResource (
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxViewId) override;
+
+ virtual void SAL_CALL releaseResource (
+ const css::uno::Reference<css::drawing::framework::XResource>& xView) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // lang::XEventListener
+
+ using WeakComponentImplHelperBase::disposing;
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEventObject) override;
+
+private:
+ css::uno::Reference<css::frame::XController> mxController;
+
+ /// @throws css::lang::DisposedException
+ void ThrowIfDisposed() const;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/PresentationModule.hxx b/sd/source/ui/inc/framework/PresentationModule.hxx
new file mode 100644
index 000000000..f6dcfbc69
--- /dev/null
+++ b/sd/source/ui/inc/framework/PresentationModule.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+namespace com::sun::star::frame
+{
+class XController;
+}
+namespace com::sun::star::uno
+{
+template <class interface_type> class Reference;
+}
+
+namespace sd::framework
+{
+/** The task of this module is to instantiate all modules that belong to the
+ fullscreen presentation.
+*/
+class PresentationModule
+{
+public:
+ static void Initialize(css::uno::Reference<css::frame::XController> const& rxController);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/ResourceId.hxx b/sd/source/ui/inc/framework/ResourceId.hxx
new file mode 100644
index 000000000..98b456c76
--- /dev/null
+++ b/sd/source/ui/inc/framework/ResourceId.hxx
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <vector>
+
+#include <com/sun/star/drawing/framework/XResourceId.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+
+namespace com::sun::star::util { class XURLTransformer; }
+namespace com::sun::star::uno { template <class interface_type> class WeakReference; }
+
+namespace sd::framework {
+
+typedef ::cppu::WeakImplHelper <
+ css::drawing::framework::XResourceId,
+ css::lang::XInitialization,
+ css::lang::XServiceInfo
+ > ResourceIdInterfaceBase;
+
+/** Implementation of the css::drawing::framework::ResourceId
+ service and the css::drawing::framework::XResourceId
+ interface.
+*/
+class ResourceId
+ : public ResourceIdInterfaceBase
+{
+public:
+ /** Create a new, empty resource id.
+ */
+ ResourceId();
+
+ /** Create a new resource id that is described by the given URLs.
+ @param rsResourceURLs
+ The first URL specifies the type of resource. The other URLs
+ describe its anchor.
+ The set of URLs may be empty. The result is then the same as
+ returned by ResourceId() default constructor.
+ */
+ ResourceId (std::vector<OUString>&& rsResourceURLs);
+
+ /** Create a new resource id that has an empty anchor.
+ @param rsResourceURL
+ When this resource URL is empty then the resulting ResourceId
+ object is identical to when the ResourceId() default constructor
+ had been called.
+ */
+ ResourceId (
+ const OUString& rsResourceURL);
+
+ /** Create a new resource id for the given resource type and an anchor
+ that is specified by a single URL. This constructor can be used for
+ example for views that are bound to panes.
+ @param rsResourceURL
+ The URL of the actual resource.
+ @param rsAnchorURL
+ The single URL of the anchor.
+ */
+ ResourceId (
+ const OUString& rsResourceURL,
+ const OUString& rsAnchorURL);
+
+ /** Create a new resource id with an anchor that consists of a sequence
+ of URLs that is extended by a further URL.
+ @param rsResourceURL
+ The URL of the actual resource.
+ @param rsFirstAnchorURL
+ This URL extends the anchor given by rAnchorURLs.
+ @param rAnchorURLs
+ An anchor as it is returned by XResourceId::getAnchorURLs().
+ */
+ ResourceId (
+ const OUString& rsResourceURL,
+ const OUString& rsFirstAnchorURL,
+ const css::uno::Sequence<OUString>& rAnchorURLs);
+
+ virtual ~ResourceId() override;
+
+ //===== XResourceId =======================================================
+
+ virtual OUString SAL_CALL
+ getResourceURL() override;
+
+ virtual css::util::URL SAL_CALL
+ getFullResourceURL() override;
+
+ virtual sal_Bool SAL_CALL
+ hasAnchor() override;
+
+ virtual css::uno::Reference<
+ css::drawing::framework::XResourceId> SAL_CALL
+ getAnchor() override;
+
+ virtual css::uno::Sequence<OUString> SAL_CALL
+ getAnchorURLs() override;
+
+ virtual OUString SAL_CALL
+ getResourceTypePrefix() override;
+
+ virtual sal_Int16 SAL_CALL
+ compareTo (const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxResourceId) override;
+
+ virtual sal_Bool SAL_CALL
+ isBoundTo (
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxResourceId,
+ css::drawing::framework::AnchorBindingMode eMode) override;
+
+ virtual sal_Bool SAL_CALL
+ isBoundToURL (
+ const OUString& rsAnchorURL,
+ css::drawing::framework::AnchorBindingMode eMode) override;
+
+ virtual css::uno::Reference<
+ css::drawing::framework::XResourceId> SAL_CALL
+ clone() override;
+
+ //===== XInitialization ===================================================
+
+ void SAL_CALL initialize (
+ const css::uno::Sequence<css::uno::Any>& aArguments) override;
+
+ OUString SAL_CALL getImplementationName() override;
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+private:
+ /** The set of URLs that consist of the resource URL at index 0 and the
+ anchor URLs and indices 1 and above.
+ */
+ std::vector<OUString> maResourceURLs;
+
+ std::unique_ptr<css::util::URL> mpURL;
+
+ static css::uno::WeakReference<css::util::XURLTransformer> mxURLTransformerWeak;
+
+ /** Compare the called ResourceId object to the given ResourceId object.
+ This uses the implementation of both objects to speed up the
+ comparison.
+ */
+ sal_Int16 CompareToLocalImplementation (const ResourceId& rId) const;
+
+ /** Compare the called ResourceId object to the given XResourceId object
+ reference. The comparison is done via the UNO interface. Namely,
+ it uses the getResourceURL() and the getAnchorURLs() methods to get
+ access to the URLs of the given object.
+ */
+ sal_Int16 CompareToExternalImplementation (const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxId) const;
+
+ /** Return whether the called ResourceId object is bound to the anchor
+ consisting of the URLs given by psFirstAnchorURL and paAnchorURLs.
+ @param psFirstAnchorURL
+ Optional first URL of the anchor. This can be missing or present
+ independently of paAnchorURLs.
+ @param paAnchorURLs
+ Optional set of additional anchor URLs. This can be missing or
+ present independently of psFirstAnchorURL.
+ @param eMode
+ This specifies whether the called resource has to be directly
+ bound to the given anchor in order to return <TRUE/> or whether
+ it can be bound indirectly, too.
+ */
+ bool IsBoundToAnchor (
+ const OUString* psFirstAnchorURL,
+ const css::uno::Sequence<OUString>* paAnchorURLs,
+ css::drawing::framework::AnchorBindingMode eMode) const;
+
+ /** Return whether the called ResourceId object is bound to the anchor
+ consisting of the URLs in rResourceURLs.
+ @param rResourceURLs
+ A possibly empty list of anchor URLs.
+ @param eMode
+ This specifies whether the called resource has to be directly
+ bound to the given anchor in order to return <TRUE/> or whether
+ it can be bound indirectly, too.
+ */
+ bool IsBoundToAnchor (
+ const ::std::vector<OUString>& rResourceURLs,
+ css::drawing::framework::AnchorBindingMode eMode) const;
+
+ void ParseResourceURL();
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/framework/ViewShellWrapper.hxx b/sd/source/ui/inc/framework/ViewShellWrapper.hxx
new file mode 100644
index 000000000..43dca4d67
--- /dev/null
+++ b/sd/source/ui/inc/framework/ViewShellWrapper.hxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XView.hpp>
+#include <com/sun/star/drawing/framework/XRelocatableResource.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <comphelper/compbase.hxx>
+
+#include <memory>
+
+namespace sd { class ViewShell; }
+namespace sd::slidesorter { class SlideSorterViewShell; }
+namespace com::sun::star::awt { class XWindow; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper < css::lang::XUnoTunnel
+ , css::awt::XWindowListener
+ , css::view::XSelectionSupplier
+ , css::drawing::framework::XRelocatableResource
+ , css::drawing::framework::XView
+ > ViewShellWrapperInterfaceBase;
+
+/** This class wraps ViewShell objects and makes them look like an XView.
+ Most importantly it provides a tunnel to the ViewShell implementation.
+ Then it forwards size changes of the pane window to the view shell.
+*/
+class ViewShellWrapper final : public ViewShellWrapperInterfaceBase
+{
+public:
+ /** Create a new ViewShellWrapper object that wraps the given ViewShell
+ object.
+ @param pViewShell
+ The ViewShell object to wrap.
+ @param rsViewURL
+ URL of the view type of the wrapped view shell.
+ @param rxWindow
+ This window reference is optional. When a valid reference is
+ given then size changes of the referenced window are forwarded
+ to the ViewShell object.
+ */
+ ViewShellWrapper (
+ const ::std::shared_ptr<ViewShell>& pViewShell,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId,
+ const css::uno::Reference<css::awt::XWindow>& rxWindow);
+ virtual ~ViewShellWrapper() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+
+ static const css::uno::Sequence<sal_Int8>& getUnoTunnelId();
+
+ /** This method is typically used together with the XUnoTunnel interface
+ to obtain a pointer to the wrapped ViewShell object for a given
+ XView object.
+ */
+ const ::std::shared_ptr<ViewShell>& GetViewShell() const { return mpViewShell;}
+
+ // XUnoTunnel
+
+ virtual sal_Int64 SAL_CALL getSomething (const css::uno::Sequence<sal_Int8>& rId) override;
+
+ // XResource
+
+ virtual css::uno::Reference<css::drawing::framework::XResourceId>
+ SAL_CALL getResourceId() override;
+
+ virtual sal_Bool SAL_CALL isAnchorOnly() override;
+
+ // XSelectionSupplier
+
+ virtual sal_Bool SAL_CALL select( const css::uno::Any& aSelection ) override;
+ virtual css::uno::Any SAL_CALL getSelection() override;
+ virtual void SAL_CALL addSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+
+ // XRelocatableResource
+
+ virtual sal_Bool SAL_CALL relocateToAnchor (
+ const css::uno::Reference<
+ css::drawing::framework::XResource>& xResource) override;
+
+ // XWindowListener
+
+ virtual void SAL_CALL windowResized(
+ const css::awt::WindowEvent& rEvent) override;
+
+ virtual void SAL_CALL windowMoved(
+ const css::awt::WindowEvent& rEvent) override;
+
+ virtual void SAL_CALL windowShown(
+ const css::lang::EventObject& rEvent) override;
+
+ virtual void SAL_CALL windowHidden(
+ const css::lang::EventObject& rEvent) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing(
+ const css::lang::EventObject& rEvent) override;
+
+private:
+ ::std::shared_ptr< ViewShell > mpViewShell;
+ ::std::shared_ptr< ::sd::slidesorter::SlideSorterViewShell > mpSlideSorterViewShell;
+ const css::uno::Reference< css::drawing::framework::XResourceId > mxViewId;
+ css::uno::Reference<css::awt::XWindow > mxWindow;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuarea.hxx b/sd/source/ui/inc/fuarea.hxx
new file mode 100644
index 000000000..38f0b48b6
--- /dev/null
+++ b/sd/source/ui/inc/fuarea.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuArea : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+private:
+ FuArea (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ virtual void DoExecute( SfxRequest& rReq ) override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fubullet.hxx b/sd/source/ui/inc/fubullet.hxx
new file mode 100644
index 000000000..a8b771f06
--- /dev/null
+++ b/sd/source/ui/inc/fubullet.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 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+class SfxItemSet;
+class SfxViewFrame;
+
+namespace sd {
+
+class ViewShell;
+
+class FuBullet : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ static void GetSlotState( SfxItemSet& rSet, ViewShell const * pViewShell, SfxViewFrame* pViewFrame );
+
+private:
+ FuBullet (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ void InsertSpecialCharacter( SfxRequest const & rReq );
+ void InsertFormattingMark( sal_Unicode cMark );
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuchar.hxx b/sd/source/ui/inc/fuchar.hxx
new file mode 100644
index 000000000..10331b87d
--- /dev/null
+++ b/sd/source/ui/inc/fuchar.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuChar
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+private:
+ FuChar (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fucon3d.hxx b/sd/source/ui/inc/fucon3d.hxx
new file mode 100644
index 000000000..545b19327
--- /dev/null
+++ b/sd/source/ui/inc/fucon3d.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fuconstr.hxx"
+
+class E3dCompoundObject;
+class E3dScene;
+class SdDrawDocument;
+class SfxRequest;
+
+namespace sd {
+
+class FuConstruct3dObject
+ : public FuConstruct
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ // Mouse- & Key-Events
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override;
+
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle) override;
+
+private:
+ FuConstruct3dObject (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ void ImpPrepareBasic3DShape(E3dCompoundObject const * p3DObj, E3dScene *pScene);
+ E3dCompoundObject* ImpCreateBasic3DShape();
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuconarc.hxx b/sd/source/ui/inc/fuconarc.hxx
new file mode 100644
index 000000000..9a1beae89
--- /dev/null
+++ b/sd/source/ui/inc/fuconarc.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 .
+ */
+
+#pragma once
+
+#include "fuconstr.hxx"
+
+namespace sd {
+
+class FuConstructArc final
+ : public FuConstruct
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ // Mouse- & Key-Events
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override;
+
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle) override;
+
+private:
+ FuConstructArc (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuconbez.hxx b/sd/source/ui/inc/fuconbez.hxx
new file mode 100644
index 000000000..fe9aceae2
--- /dev/null
+++ b/sd/source/ui/inc/fuconbez.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Any.hxx>
+#include "fuconstr.hxx"
+
+class SdDrawDocument;
+
+namespace sd {
+
+class FuConstructBezierPolygon final
+ : public FuConstruct
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent );
+ void DoExecute( SfxRequest& rReq ) override;
+
+ // Mouse- & Key-Events
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ virtual void SelectionHasChanged() override;
+
+ void SetEditMode(sal_uInt16 nMode);
+ sal_uInt16 GetEditMode() const { return nEditMode; }
+
+ /**
+ * set attribute for the object to be created
+ */
+ void SetAttributes(SfxItemSet& rAttr, SdrObject* pObj);
+
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle) override;
+
+private:
+ FuConstructBezierPolygon (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ sal_uInt16 nEditMode;
+ css::uno::Any maTargets; // used for creating a path for custom animations
+
+ //Extra attributes coming from parameters
+ sal_uInt16 mnTransparence; // Default: 0
+ OUString msColor; // Default: ""
+ sal_uInt16 mnWidth; // Default: 0
+ OUString msShapeName; // Default: ""
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuconcs.hxx b/sd/source/ui/inc/fuconcs.hxx
new file mode 100644
index 000000000..f4f4ef30e
--- /dev/null
+++ b/sd/source/ui/inc/fuconcs.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fuconstr.hxx"
+#include <rtl/ustring.hxx>
+
+class SdDrawDocument;
+
+namespace sd {
+
+class FuConstructCustomShape final
+ : public FuConstruct
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ // Mouse- & Key-Events
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override;
+
+ void SetAttributes( SdrObject* pObj );
+ const OUString& GetShapeType() const;
+
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle) override;
+
+ // #i33136#
+ virtual bool doConstructOrthogonal() const override;
+
+private:
+ FuConstructCustomShape (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ OUString aCustomShape;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuconnct.hxx b/sd/source/ui/inc/fuconnct.hxx
new file mode 100644
index 000000000..f8000e5bc
--- /dev/null
+++ b/sd/source/ui/inc/fuconnct.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuConnectionDlg
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuConnectionDlg (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuconrec.hxx b/sd/source/ui/inc/fuconrec.hxx
new file mode 100644
index 000000000..caf8ac7eb
--- /dev/null
+++ b/sd/source/ui/inc/fuconrec.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fuconstr.hxx"
+
+class SdDrawDocument;
+class SfxItemSet;
+
+namespace sd {
+
+/**
+ * draw rectangle
+ */
+class FuConstructRectangle final
+ : public FuConstruct
+{
+private:
+ //Extra attributes coming from parameters
+ sal_uInt16 mnFillTransparence; // Default: 0
+ OUString msFillColor; // Default: ""
+ sal_uInt16 mnLineStyle; // Default: SAL_MAX_UINT16
+ OUString msShapeName; // Default: ""
+
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ // Mouse- & Key-Events
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ void SetAttributes(SfxItemSet& rAttr, SdrObject* pObj);
+ void SetLineEnds(SfxItemSet& rAttr, SdrObject const & rObj);
+
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle) override;
+
+private:
+ FuConstructRectangle (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuconstr.hxx b/sd/source/ui/inc/fuconstr.hxx
new file mode 100644
index 000000000..743c6cd5b
--- /dev/null
+++ b/sd/source/ui/inc/fuconstr.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fudraw.hxx"
+
+class SdrObject;
+class SfxItemSet;
+
+namespace sd {
+
+class FuConstruct : public FuDraw
+{
+public:
+
+ // Mouse Events
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ virtual void SelectionHasChanged() override { bSelectionChanged = true; }
+
+ // SJ: setting stylesheet, the use of a filled or unfilled style
+ // is determined by the member nSlotId :
+ void SetStyleSheet(SfxItemSet& rAttr, SdrObject* pObj);
+
+ // SJ: setting stylesheet, the use of a filled or unfilled style
+ // is determined by the parameters bUseFillStyle and bUseNoFillStyle :
+ void SetStyleSheet( SfxItemSet& rAttr, SdrObject* pObj,
+ const bool bUseFillStyle, const bool bUseNoFillStyle );
+
+protected:
+ FuConstruct (ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+private:
+ bool bSelectionChanged;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuconuno.hxx b/sd/source/ui/inc/fuconuno.hxx
new file mode 100644
index 000000000..df8e4d415
--- /dev/null
+++ b/sd/source/ui/inc/fuconuno.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fuconstr.hxx"
+#include <rtl/ustring.hxx>
+
+enum class SdrInventor : sal_uInt32;
+
+namespace sd {
+
+/**
+ * draw control
+ */
+class FuConstructUnoControl final
+ : public FuConstruct
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ // Mouse- & Key-Events
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle) override;
+
+private:
+ FuConstructUnoControl(
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ OUString aOldLayer;
+ SdrInventor nInventor;
+ SdrObjKind nIdentifier;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fucopy.hxx b/sd/source/ui/inc/fucopy.hxx
new file mode 100644
index 000000000..89b950a8f
--- /dev/null
+++ b/sd/source/ui/inc/fucopy.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuCopy
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+
+ FuCopy (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fucushow.hxx b/sd/source/ui/inc/fucushow.hxx
new file mode 100644
index 000000000..005aea218
--- /dev/null
+++ b/sd/source/ui/inc/fucushow.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuCustomShowDlg
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuCustomShowDlg (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fudraw.hxx b/sd/source/ui/inc/fudraw.hxx
new file mode 100644
index 000000000..e1d25a521
--- /dev/null
+++ b/sd/source/ui/inc/fudraw.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+struct SdrViewEvent;
+class SdrObject;
+
+namespace sd {
+
+/**
+ * Base class for all Draw specific functions
+ */
+class FuDraw
+ : public FuPoor
+{
+public:
+
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool RequestHelp(const HelpEvent& rHEvt) override;
+
+ virtual void Activate() override;
+
+ virtual void ForcePointer(const MouseEvent* pMEvt = nullptr);
+
+ virtual void DoubleClick(const MouseEvent& rMEvt);
+
+ bool SetPointer(const SdrObject* pObj, const Point& rPos);
+ bool SetHelpText(const SdrObject* pObj, const Point& rPos, const SdrViewEvent& rVEvt);
+
+ void SetPermanent(bool bSet) { bPermanent = bSet; }
+
+ /** is called when the current function should be aborted. <p>
+ This is used when a function gets a KEY_ESCAPE but can also
+ be called directly.
+
+ @returns true if an active function was aborted
+ */
+ virtual bool cancel() override;
+
+protected:
+ FuDraw (ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ virtual ~FuDraw() override;
+
+ PointerStyle aNewPointer;
+ PointerStyle aOldPointer;
+ bool bMBDown;
+ bool bDragHelpLine;
+ sal_uInt16 nHelpLine;
+ bool bPermanent;
+
+private:
+ void DoModifiers(const MouseEvent& rMEvt, bool bSnapModPressed);
+
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fudspord.hxx b/sd/source/ui/inc/fudspord.hxx
new file mode 100644
index 000000000..2c6089442
--- /dev/null
+++ b/sd/source/ui/inc/fudspord.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+class SdrDropMarkerOverlay;
+class SdrObject;
+
+namespace sd {
+
+class FuDisplayOrder final
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+
+ // Mouse- & Key-Events
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+private:
+ virtual ~FuDisplayOrder() override;
+ void implClearOverlay();
+
+ PointerStyle maPtr;
+ SdrObject* mpRefObj;
+ std::unique_ptr<SdrDropMarkerOverlay> mpOverlay;
+
+ FuDisplayOrder (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuediglu.hxx b/sd/source/ui/inc/fuediglu.hxx
new file mode 100644
index 000000000..19c32cefd
--- /dev/null
+++ b/sd/source/ui/inc/fuediglu.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fudraw.hxx"
+
+namespace sd {
+
+class FuEditGluePoints final
+ : public FuDraw
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq, bool bPermanent );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ // Mouse- & Key-Events
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool Command(const CommandEvent& rCEvt) override;
+ virtual void ReceiveRequest(SfxRequest& rReq) override;
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ //Add Shift+UP/DOWN/LEFT/RIGHT key to move the position of insert point,
+ //and SHIFT+ENTER key to decide the position and draw the new insert point
+ virtual void ForcePointer(const MouseEvent* pMEvt = nullptr) override;
+
+private:
+ bool bBeginInsertPoint;
+ Point oldPoint;
+
+ FuEditGluePoints (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+ virtual ~FuEditGluePoints() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuexecuteinteraction.hxx b/sd/source/ui/inc/fuexecuteinteraction.hxx
new file mode 100644
index 000000000..1fb733b55
--- /dev/null
+++ b/sd/source/ui/inc/fuexecuteinteraction.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+#include <com/sun/star/media/XPlayer.hpp>
+
+namespace sd
+{
+class FuExecuteInteraction : public FuPoor
+{
+public:
+ static rtl::Reference<FuPoor> Create(ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView,
+ SdDrawDocument* pDoc, SfxRequest& rReq);
+ virtual void DoExecute(SfxRequest& rReq) override;
+
+private:
+ FuExecuteInteraction(ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView,
+ SdDrawDocument* pDoc, SfxRequest& rReq);
+
+ css::uno::Reference<css::media::XPlayer> mxPlayer;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuexpand.hxx b/sd/source/ui/inc/fuexpand.hxx
new file mode 100644
index 000000000..ccdffb661
--- /dev/null
+++ b/sd/source/ui/inc/fuexpand.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuExpandPage
+ : public FuPoor
+{
+ public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuExpandPage (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuformatpaintbrush.hxx b/sd/source/ui/inc/fuformatpaintbrush.hxx
new file mode 100644
index 000000000..0de28d4a8
--- /dev/null
+++ b/sd/source/ui/inc/fuformatpaintbrush.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "futext.hxx"
+
+namespace sd {
+
+class DrawViewShell;
+
+class FuFormatPaintBrush : public FuText
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ static void GetMenuState( DrawViewShell const & rDrawViewShell, SfxItemSet &rSet );
+
+private:
+ FuFormatPaintBrush ( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq);
+
+ void DoExecute( SfxRequest& rReq ) override;
+
+ bool HasContentForThisType( SdrInventor nObjectInventor, SdrObjKind nObjectIdentifier ) const;
+ void Paste( bool, bool );
+
+ void implcancel();
+
+ std::shared_ptr<SfxItemSet> mxItemSet;
+ bool mbPermanent;
+ bool mbOldIsQuickTextEditMode;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuhhconv.hxx b/sd/source/ui/inc/fuhhconv.hxx
new file mode 100644
index 000000000..a009b3023
--- /dev/null
+++ b/sd/source/ui/inc/fuhhconv.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+class SdOutliner;
+
+namespace sd {
+
+class FuHangulHanjaConversion final : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+
+ void StartConversion( LanguageType nSourceLanguage, LanguageType nTargetLanguage,
+ const vcl::Font *pTargetFont, sal_Int32 nOptions, bool bIsInteractive );
+
+ void StartChineseConversion();
+
+ void ConvertStyles( LanguageType nTargetLanguage, const vcl::Font *pTargetFont );
+
+private:
+ virtual ~FuHangulHanjaConversion() override;
+
+ SdOutliner* pSdOutliner;
+ bool bOwnOutliner;
+
+ FuHangulHanjaConversion (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq );
+
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuinsert.hxx b/sd/source/ui/inc/fuinsert.hxx
new file mode 100644
index 000000000..a2b335961
--- /dev/null
+++ b/sd/source/ui/inc/fuinsert.hxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <config_features.h>
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuInsertGraphic
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin,
+ ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq,
+ bool replaceExistingImage);
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+
+ FuInsertGraphic (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq,
+ bool replaceExistingImage);
+
+ bool mbReplaceExistingImage;
+};
+
+/************************************************************************/
+
+class FuInsertClipboard
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuInsertClipboard (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+/************************************************************************/
+
+class FuInsertOLE
+ : public FuPoor
+{
+ public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuInsertOLE (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+/************************************************************************/
+
+class FuInsertAVMedia
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuInsertAVMedia (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+#if HAVE_FEATURE_AVMEDIA
+ void InsertMediaURL(const OUString& rURL, const Size& rPrefSize, bool bLink);
+#endif
+};
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuinsfil.hxx b/sd/source/ui/inc/fuinsfil.hxx
new file mode 100644
index 000000000..f29b0764d
--- /dev/null
+++ b/sd/source/ui/inc/fuinsfil.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+#include <vector>
+#include <rtl/ustring.hxx>
+
+class SfxMedium;
+
+namespace sd {
+
+class FuInsertFile
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ static void GetSupportedFilterVector( ::std::vector< OUString >& rFilterVector );
+
+private:
+ FuInsertFile (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ OUString aLayoutName; ///< layout name of the currently inserted page
+ OUString aFilterName; ///< chosen file filter
+ OUString aFile; ///< chosen file name
+
+ void InsTextOrRTFinOlMode(SfxMedium* pMedium);
+ bool InsSDDinOlMode(SfxMedium* pMedium);
+ void InsTextOrRTFinDrMode(SfxMedium* pMedium);
+ bool InsSDDinDrMode(SfxMedium* pMedium);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuline.hxx b/sd/source/ui/inc/fuline.hxx
new file mode 100644
index 000000000..459ff83ee
--- /dev/null
+++ b/sd/source/ui/inc/fuline.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuLine
+ : public FuPoor
+{
+public:
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+
+ FuLine (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fulinend.hxx b/sd/source/ui/inc/fulinend.hxx
new file mode 100644
index 000000000..ea17a559a
--- /dev/null
+++ b/sd/source/ui/inc/fulinend.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuLineEnd
+ : public FuPoor
+{
+public:
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+
+ FuLineEnd (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fulink.hxx b/sd/source/ui/inc/fulink.hxx
new file mode 100644
index 000000000..38c9d0c07
--- /dev/null
+++ b/sd/source/ui/inc/fulink.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuLink
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+
+ FuLink (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq );
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fumeasur.hxx b/sd/source/ui/inc/fumeasur.hxx
new file mode 100644
index 000000000..1900dba17
--- /dev/null
+++ b/sd/source/ui/inc/fumeasur.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuMeasureDlg
+ : public FuPoor
+{
+ public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+
+ FuMeasureDlg (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fumorph.hxx b/sd/source/ui/inc/fumorph.hxx
new file mode 100644
index 000000000..2d896b8eb
--- /dev/null
+++ b/sd/source/ui/inc/fumorph.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 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+#include <vector>
+
+namespace basegfx {
+ class B2DPolygon;
+ class B2DPoint;
+}
+
+namespace sd {
+
+class FuMorph
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ typedef ::std::vector< ::basegfx::B2DPolyPolygon > B2DPolyPolygonList_impl;
+
+ FuMorph (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ void ImpInsertPolygons(
+ B2DPolyPolygonList_impl& rPolyPolyList3D,
+ bool bAttributeFade,
+ const SdrObject* pObj1,
+ const SdrObject* pObj2
+ );
+
+ static ::basegfx::B2DPolyPolygon ImpCreateMorphedPolygon(
+ const ::basegfx::B2DPolyPolygon& rPolyPolyStart,
+ const ::basegfx::B2DPolyPolygon& rPolyPolyEnd,
+ double fMorphingFactor
+ );
+
+ static void ImpMorphPolygons(
+ const ::basegfx::B2DPolyPolygon& rPolyPoly1,
+ const ::basegfx::B2DPolyPolygon& rPolyPoly2,
+ const sal_uInt16 nSteps,
+ B2DPolyPolygonList_impl& rPolyPolyList3D
+ );
+
+ static void ImpAddPolys(
+ ::basegfx::B2DPolyPolygon& rSmaller,
+ const ::basegfx::B2DPolyPolygon& rBigger
+ );
+
+ static void ImpEqualizePolyPointCount(
+ ::basegfx::B2DPolygon& rSmall,
+ const ::basegfx::B2DPolygon& rBig
+ );
+
+ static sal_uInt32 ImpGetNearestIndex(
+ const ::basegfx::B2DPolygon& rPoly,
+ const ::basegfx::B2DPoint& rPos
+ );
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/funavig.hxx b/sd/source/ui/inc/funavig.hxx
new file mode 100644
index 000000000..d717ce202
--- /dev/null
+++ b/sd/source/ui/inc/funavig.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuNavigation
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuNavigation (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuoaprms.hxx b/sd/source/ui/inc/fuoaprms.hxx
new file mode 100644
index 000000000..09e69c8d1
--- /dev/null
+++ b/sd/source/ui/inc/fuoaprms.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuObjectAnimationParameters
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+
+ FuObjectAnimationParameters (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuolbull.hxx b/sd/source/ui/inc/fuolbull.hxx
new file mode 100644
index 000000000..1ed73cf91
--- /dev/null
+++ b/sd/source/ui/inc/fuolbull.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+class SdDrawDocument;
+class SfxRequest;
+class SfxItemSet;
+class SfxPoolItem;
+class SvxNumBulletItem;
+
+namespace sd {
+
+class View;
+class ViewShell;
+
+/**
+ * bullet functions in outline mode
+ */
+
+class FuBulletAndPosition
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuBulletAndPosition (
+ ViewShell* pViewShell,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ void SetCurrentBulletsNumbering(SfxRequest& rReq);
+
+ const SvxNumBulletItem* GetNumBulletItem(SfxItemSet& aNewAttr, TypedWhichId<SvxNumBulletItem>& nNumItemId);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuoltext.hxx b/sd/source/ui/inc/fuoltext.hxx
new file mode 100644
index 000000000..288bcf190
--- /dev/null
+++ b/sd/source/ui/inc/fuoltext.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+class SdDrawDocument;
+class SfxRequest;
+
+namespace sd {
+
+class View;
+class ViewShell;
+class OutlineView;
+class OutlineViewShell;
+
+/**
+ * text functions in outline mode
+ */
+class FuOutlineText final
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+
+ virtual bool Command(const CommandEvent& rCEvt) override;
+
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void DoCut() override;
+ virtual void DoCopy() override;
+ virtual void DoPaste() override;
+ virtual void DoPasteUnformatted() override;
+
+ /** Call this method when the text in the outliner (may) has changed.
+ It will invalidate some slots of the view frame and update the
+ preview in the slide sorter.
+ */
+ void UpdateForKeyPress (const KeyEvent& rEvent);
+
+private:
+ FuOutlineText (
+ ViewShell* pViewShell,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ OutlineViewShell* pOutlineViewShell;
+ OutlineView* pOutlineView;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fupage.hxx b/sd/source/ui/inc/fupage.hxx
new file mode 100644
index 000000000..8540d80d7
--- /dev/null
+++ b/sd/source/ui/inc/fupage.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include "fupoor.hxx"
+#include <vcl/weld.hxx>
+
+class SfxItemSet;
+class SdBackgroundObjUndoAction;
+class SdPage;
+
+namespace sd {
+class DrawViewShell;
+
+class FuPage
+ : public FuPoor
+{
+ public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ const SfxItemSet* ExecuteDialog(weld::Window* pParent, const SfxRequest& rReq);
+
+protected:
+ virtual ~FuPage() override;
+
+private:
+ FuPage (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq );
+
+ void ApplyItemSet( const SfxItemSet* pArgs );
+
+ SfxRequest& mrReq;
+ const SfxItemSet* mpArgs;
+ std::unique_ptr<SdBackgroundObjUndoAction>
+ mpBackgroundObjUndoAction;
+ Size maSize;
+ bool mbPageBckgrdDeleted;
+ bool mbMasterPage;
+ bool mbDisplayBackgroundTabPage;
+ SdPage* mpPage;
+ DrawViewShell* mpDrawViewShell;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuparagr.hxx b/sd/source/ui/inc/fuparagr.hxx
new file mode 100644
index 000000000..559dd0de6
--- /dev/null
+++ b/sd/source/ui/inc/fuparagr.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuParagraph
+ : public FuPoor
+{
+public:
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuParagraph (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fupoor.hxx b/sd/source/ui/inc/fupoor.hxx
new file mode 100644
index 000000000..553f6688d
--- /dev/null
+++ b/sd/source/ui/inc/fupoor.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <vcl/timer.hxx>
+#include <tools/link.hxx>
+#include <tools/gen.hxx>
+#include <vcl/vclptr.hxx>
+#include <svx/svdobj.hxx>
+
+#include <helper/simplereferencecomponent.hxx>
+
+class SdDrawDocument;
+class SfxRequest;
+class CommandEvent;
+class HelpEvent;
+class KeyEvent;
+class MouseEvent;
+
+namespace sd {
+
+class DrawDocShell;
+class View;
+class ViewShell;
+class Window;
+
+/**
+ * Base class for all functions
+ */
+class FuPoor : public SimpleReferenceComponent
+{
+public:
+ static const int HITPIX = 2; // hit tolerance in pixel
+ static const int HITLOG = 53; // hit tolerance in mm100
+ static const int DRGPIX = 2; // minimal drag move in pixel
+ static const int DRGLOG = 53; // minimal drag move in mm100
+
+
+ virtual void DoExecute( SfxRequest& rReq );
+
+ void SetMouseButtonCode(sal_uInt16 nNew) { if(nNew != mnCode) mnCode = nNew; }
+ sal_uInt16 GetMouseButtonCode() const { return mnCode; }
+
+ DrawDocShell* GetDocSh() { return mpDocSh; }
+
+ virtual void DoCut();
+ virtual void DoCopy();
+ virtual void DoPaste();
+ virtual void DoPasteUnformatted();
+
+ // mouse & key events; return value = sal_True: event has been handled
+ virtual bool KeyInput(const KeyEvent& rKEvt);
+ virtual bool MouseMove(const MouseEvent& );
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt);
+
+ // moved from inline to *.cxx
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt);
+
+ virtual bool Command(const CommandEvent& rCEvt);
+ virtual bool RequestHelp(const HelpEvent& rHEvt);
+ virtual void ReceiveRequest(SfxRequest& rReq);
+
+ virtual void Activate(); ///< activates the function
+ virtual void Deactivate(); ///< deactivates the function
+
+ void SetWindow(::sd::Window* pWin);
+
+ virtual void SelectionHasChanged();
+
+ sal_uInt16 GetSlotID() const { return nSlotId; }
+
+ void StartDelayToScrollTimer ();
+
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle);
+
+ /** is called when the current function should be aborted. <p>
+ This is used when a function gets a KEY_ESCAPE but can also
+ be called directly.
+
+ @returns true if an active function was aborted
+ */
+ virtual bool cancel();
+
+ // #i33136#
+ /** Decide if the object to be created should be created
+ orthogonal. Default implementation uses nSlotID
+ to decide. May be overridden to use other criteria
+ for this decision
+
+ @returns true if the to be created object should be orthogonal.
+ */
+ virtual bool doConstructOrthogonal() const;
+
+protected:
+ /**
+ @param pViewSh
+ May be NULL.
+ */
+ FuPoor (ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+ virtual ~FuPoor() override;
+
+ DECL_LINK( DelayHdl, Timer *, void );
+
+ static void ImpForceQuadratic(::tools::Rectangle& rRect);
+
+ /** Switch to another layer. The layer to switch to is specified by an
+ offset relative to the active layer. With respect to the layer bar
+ control at the lower left of the document window positive values
+ move to the right and negative values move to the left.
+
+ <p>Switching the layer is independent of the view's layer mode. The
+ layers are switched even when the layer mode is turned off and the
+ layer control is not visible.</p>
+ @param nOffset
+ If the offset is positive skip that many layers in selecting the
+ next layer. If it is negative then select a previous one. An
+ offset or zero does not change the current layer. If the
+ resulting index lies outside the valid range of indices then it
+ is set to either the minimal or maximal valid index, whichever
+ is nearer.
+ */
+ void SwitchLayer (sal_Int32 nOffset);
+
+ ::sd::View* mpView;
+ ViewShell* mpViewShell;
+ VclPtr< ::sd::Window> mpWindow;
+ DrawDocShell* mpDocSh;
+ SdDrawDocument* mpDoc;
+
+ sal_uInt16 nSlotId;
+
+ Timer aScrollTimer; ///< for auto-scrolling
+ DECL_LINK( ScrollHdl, Timer *, void );
+ void ForceScroll(const Point& aPixPos);
+
+ Timer aDragTimer; ///< for Drag&Drop
+ DECL_LINK(DragHdl, Timer *, void);
+ bool bIsInDragMode;
+ Point aMDPos; ///< position of MouseButtonDown
+
+ /// Flag to prevent auto-scrolling until one drags from outside into the window
+ bool bNoScrollUntilInside;
+
+ /// timer to delay scrolling (~ 1 sec) when dragging out of the window
+ Timer aDelayToScrollTimer;
+ bool bScrollable;
+ bool bDelayActive;
+ bool bFirstMouseMove;
+
+ /// member to hold state of the mouse buttons for creation of own MouseEvents (like in ScrollHdl)
+
+private:
+ sal_uInt16 mnCode;
+
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuprlout.hxx b/sd/source/ui/inc/fuprlout.hxx
new file mode 100644
index 000000000..183ea124f
--- /dev/null
+++ b/sd/source/ui/inc/fuprlout.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+class SdDrawDocument;
+class SfxRequest;
+
+namespace sd {
+
+class View;
+class ViewShell;
+
+class FuPresentationLayout
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuPresentationLayout (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuprobjs.hxx b/sd/source/ui/inc/fuprobjs.hxx
new file mode 100644
index 000000000..732c73526
--- /dev/null
+++ b/sd/source/ui/inc/fuprobjs.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+class SdDrawDocument;
+class SfxRequest;
+
+namespace sd {
+
+class View;
+class ViewShell;
+
+class FuPresentationObjects
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuPresentationObjects (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuscale.hxx b/sd/source/ui/inc/fuscale.hxx
new file mode 100644
index 000000000..9b70492b8
--- /dev/null
+++ b/sd/source/ui/inc/fuscale.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuScale
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuScale (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fusearch.hxx b/sd/source/ui/inc/fusearch.hxx
new file mode 100644
index 000000000..7088dd776
--- /dev/null
+++ b/sd/source/ui/inc/fusearch.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+class SvxSearchItem;
+class SdOutliner;
+
+namespace sd {
+
+class FuSearch final : public FuPoor
+{
+public:
+
+ static FuSearch* createPtr(ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq);
+
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ void SearchAndReplace( const SvxSearchItem* pSearchItem );
+
+private:
+ virtual ~FuSearch() override;
+
+ SdOutliner* m_pSdOutliner;
+ bool m_bOwnOutliner;
+
+ FuSearch (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fusel.hxx b/sd/source/ui/inc/fusel.hxx
new file mode 100644
index 000000000..3896a6d42
--- /dev/null
+++ b/sd/source/ui/inc/fusel.hxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fudraw.hxx"
+
+namespace com::sun::star::media { class XPlayer; }
+
+class SdrHdl;
+class SdrObject;
+
+namespace sd {
+
+class FuSelection final
+ : public FuDraw
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ // Mouse- & Key-Events
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override;
+
+ virtual void SelectionHasChanged() override;
+
+ void SetEditMode(sal_uInt16 nMode);
+ sal_uInt16 GetEditMode() const { return nEditMode; }
+
+ bool HandleImageMapClick(const SdrObject* pObj, const Point& rPos);
+
+ /** is called when the current function should be aborted. <p>
+ This is used when a function gets a KEY_ESCAPE but can also
+ be called directly.
+
+ @returns true if an active function was aborted
+ */
+ virtual bool cancel() override;
+
+ //let mouse cursor move
+ virtual void ForcePointer(const MouseEvent* pMEvt = nullptr) override;
+
+private:
+ FuSelection (ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+ virtual ~FuSelection() override;
+
+ bool bTempRotation;
+ bool bSelectionChanged;
+ SdrHdl* pHdl;
+ bool bSuppressChangesOfSelection;
+ bool bMirrorSide0;
+ sal_uInt16 nEditMode;
+
+ /** This pointer stores a candidate for assigning a style in the water
+ can mode between mouse button down and mouse button up.
+ */
+ SdrObject* pWaterCanCandidate;
+
+ /** Find the object under the given test point without selecting it.
+ @param rTestPoint
+ The coordinates at which to search for a shape.
+ @return
+ The shape at the test point. When there is no shape at this
+ position then NULL is returned.
+ */
+ SdrObject* pickObject (const Point& rTestPoint);
+ //Add Shift+UP/DOWN/LEFT/RIGHT key to move the position of insert point,
+ //and SHIFT+ENTER key to decide the position and draw the new insert point
+ bool bBeginInsertPoint;
+ Point oldPoint;
+ //let mouse cursor move
+ bool bMovedToCenterPoint;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fusldlg.hxx b/sd/source/ui/inc/fusldlg.hxx
new file mode 100644
index 000000000..89f0e69ad
--- /dev/null
+++ b/sd/source/ui/inc/fusldlg.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuSlideShowDlg
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuSlideShowDlg (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fusnapln.hxx b/sd/source/ui/inc/fusnapln.hxx
new file mode 100644
index 000000000..aba91f696
--- /dev/null
+++ b/sd/source/ui/inc/fusnapln.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuSnapLine
+ : public FuPoor
+{
+public:
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuSnapLine (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fusumry.hxx b/sd/source/ui/inc/fusumry.hxx
new file mode 100644
index 000000000..3a20d3813
--- /dev/null
+++ b/sd/source/ui/inc/fusumry.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuSummaryPage
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuSummaryPage (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/futempl.hxx b/sd/source/ui/inc/futempl.hxx
new file mode 100644
index 000000000..e51447f7b
--- /dev/null
+++ b/sd/source/ui/inc/futempl.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuTemplate
+ : public FuPoor
+{
+public:
+
+ virtual void Activate() override;
+ virtual void Deactivate() override;
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuTemplate (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/futext.hxx b/sd/source/ui/inc/futext.hxx
new file mode 100644
index 000000000..f101e07a0
--- /dev/null
+++ b/sd/source/ui/inc/futext.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fuconstr.hxx"
+#include <tools/weakbase.h>
+
+class SdrTextObj;
+class FontList;
+class OutlinerView;
+
+namespace sd {
+
+/**
+ * Base class for text functions
+ */
+class FuText
+ : public FuConstruct
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool RequestHelp(const HelpEvent& rHEvt) override;
+ virtual void ReceiveRequest(SfxRequest& rReq) override;
+ virtual void DoubleClick(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override; ///< activates the function
+ virtual void Deactivate() override; ///< deactivates the function
+
+ void SetInEditMode(const MouseEvent& rMEvt, bool bQuickDrag);
+ void DeleteDefaultText();
+ SdrTextObj* GetTextObj() { return mxTextObj.get(); }
+
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const ::tools::Rectangle& rRectangle) override;
+
+ /** is called when the current function should be aborted. <p>
+ This is used when a function gets a KEY_ESCAPE but can also
+ be called directly.
+
+ @returns true if an active function was aborted
+ */
+ virtual bool cancel() override;
+
+ static void ChangeFontSize( bool, OutlinerView*, const FontList*, ::sd::View* );
+
+ void InvalidateBindings();
+
+
+protected:
+ FuText (ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+
+private:
+ virtual void disposing() override;
+
+ ::tools::WeakReference<SdrTextObj>
+ mxTextObj;
+ bool bFirstObjCreated;
+ bool bJustEndedEdit;
+
+ SfxRequest& rRequest;
+
+ void ImpSetAttributesForNewTextObject(SdrTextObj* pTxtObj);
+ void ImpSetAttributesFitToSize(SdrTextObj* pTxtObj);
+ void ImpSetAttributesFitToSizeVertical(SdrTextObj* pTxtObj);
+ void ImpSetAttributesFitCommon(SdrTextObj* pTxtObj);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/futhes.hxx b/sd/source/ui/inc/futhes.hxx
new file mode 100644
index 000000000..3b9533ddd
--- /dev/null
+++ b/sd/source/ui/inc/futhes.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuThesaurus
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuThesaurus (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/futransf.hxx b/sd/source/ui/inc/futransf.hxx
new file mode 100644
index 000000000..dd7ae19a0
--- /dev/null
+++ b/sd/source/ui/inc/futransf.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuTransform
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuTransform (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/futxtatt.hxx b/sd/source/ui/inc/futxtatt.hxx
new file mode 100644
index 000000000..584e59c0d
--- /dev/null
+++ b/sd/source/ui/inc/futxtatt.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuTextAttrDlg
+ : public FuPoor
+{
+ public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+ FuTextAttrDlg (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuvect.hxx b/sd/source/ui/inc/fuvect.hxx
new file mode 100644
index 000000000..0501fb224
--- /dev/null
+++ b/sd/source/ui/inc/fuvect.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+class FuVectorize
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+ virtual void DoExecute( SfxRequest& rReq ) override;
+
+private:
+
+ FuVectorize (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/fuzoom.hxx b/sd/source/ui/inc/fuzoom.hxx
new file mode 100644
index 000000000..54c352dd3
--- /dev/null
+++ b/sd/source/ui/inc/fuzoom.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "fupoor.hxx"
+
+namespace sd {
+
+extern const sal_uInt16 SidArrayZoom[];
+
+class FuZoom final
+ : public FuPoor
+{
+public:
+
+ static rtl::Reference<FuPoor> Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq );
+
+ // Mouse- & Key-Events
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ virtual void Activate() override; ///< activates the function
+ virtual void Deactivate() override; ///< deactivates the function
+
+private:
+ virtual ~FuZoom() override;
+
+ Point aBeginPosPix;
+ Point aBeginPos;
+ Point aEndPos;
+ ::tools::Rectangle aZoomRect;
+ bool bVisible;
+ bool bStartDrag;
+ PointerStyle aPtr;
+
+ FuZoom (
+ ViewShell* pViewSh,
+ ::sd::Window* pWin,
+ ::sd::View* pView,
+ SdDrawDocument* pDoc,
+ SfxRequest& rReq);
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/gluectrl.hxx b/sd/source/ui/inc/gluectrl.hxx
new file mode 100644
index 000000000..58aa13944
--- /dev/null
+++ b/sd/source/ui/inc/gluectrl.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/InterimItemWindow.hxx>
+#include <sfx2/tbxctrl.hxx>
+
+enum class SdrEscapeDirection;
+
+/**
+ * GluePointEscDirLB
+ */
+class GlueEscDirLB final : public InterimItemWindow
+{
+private:
+ css::uno::Reference<css::frame::XFrame> m_xFrame;
+ std::unique_ptr<weld::ComboBox> m_xWidget;
+
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+
+public:
+ GlueEscDirLB(vcl::Window* pParent, const css::uno::Reference<css::frame::XFrame>& rFrame);
+ virtual void dispose() override;
+ virtual ~GlueEscDirLB() override;
+
+ void set_active(int nPos) { m_xWidget->set_active(nPos); }
+ void set_sensitive(bool bSensitive);
+
+ void Fill();
+};
+
+/**
+ * Toolbox controller for glue-point escape direction
+ */
+class SdTbxCtlGlueEscDir : public SfxToolBoxControl
+{
+private:
+ static sal_uInt16 GetEscDirPos(SdrEscapeDirection nEscDir);
+
+public:
+ virtual void StateChangedAtToolBoxControl(sal_uInt16 nSId, SfxItemState eState,
+ const SfxPoolItem* pState) override;
+ virtual VclPtr<InterimItemWindow> CreateItemWindow(vcl::Window* pParent) override;
+
+ SFX_DECL_TOOLBOX_CONTROL();
+
+ SdTbxCtlGlueEscDir(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/headerfooterdlg.hxx b/sd/source/ui/inc/headerfooterdlg.hxx
new file mode 100644
index 000000000..e794712d3
--- /dev/null
+++ b/sd/source/ui/inc/headerfooterdlg.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+
+#include <sdpage.hxx>
+
+class SdUndoGroup;
+
+namespace sd
+{
+class ViewShell;
+
+class HeaderFooterTabPage;
+
+class HeaderFooterDialog : public weld::GenericDialogController
+{
+private:
+ DECL_LINK( ActivatePageHdl, const OString&, void );
+ DECL_LINK( ClickApplyToAllHdl, weld::Button&, void );
+ DECL_LINK( ClickApplyHdl, weld::Button&, void );
+ DECL_LINK( ClickCancelHdl, weld::Button&, void );
+
+ HeaderFooterSettings maSlideSettings;
+ HeaderFooterSettings maNotesHandoutSettings;
+
+ SdDrawDocument* mpDoc;
+ SdPage* mpCurrentPage;
+ ViewShell* mpViewShell;
+
+ std::unique_ptr<weld::Notebook> mxTabCtrl;
+ std::unique_ptr<weld::Button> mxPBApplyToAll;
+ std::unique_ptr<weld::Button> mxPBApply;
+ std::unique_ptr<weld::Button> mxPBCancel;
+ std::unique_ptr<HeaderFooterTabPage> mxSlideTabPage;
+ std::unique_ptr<HeaderFooterTabPage> mxNotesHandoutsTabPage;
+
+ void apply( bool bToAll, bool bForceSlides );
+ void change( SdUndoGroup* pUndoGroup, SdPage* pPage, const HeaderFooterSettings& rNewSettings );
+
+public:
+ HeaderFooterDialog(ViewShell* pViewShell, weld::Window* pParent, SdDrawDocument* pDoc, SdPage* pCurrentPage);
+ virtual ~HeaderFooterDialog() override;
+
+ void ApplyToAll();
+ void Apply();
+
+ virtual short run() override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/ins_paste.hxx b/sd/source/ui/inc/ins_paste.hxx
new file mode 100644
index 000000000..5031d09b0
--- /dev/null
+++ b/sd/source/ui/inc/ins_paste.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+// SdInsertPasteDlg
+class SdInsertPasteDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::RadioButton> m_xRbBefore;
+ std::unique_ptr<weld::RadioButton> m_xRbAfter;
+
+public:
+ SdInsertPasteDlg(weld::Window* pWindow);
+ virtual ~SdInsertPasteDlg() override;
+ bool IsInsertBefore() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/inspagob.hxx b/sd/source/ui/inc/inspagob.hxx
new file mode 100644
index 000000000..d906a10f7
--- /dev/null
+++ b/sd/source/ui/inc/inspagob.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+class SdDrawDocument;
+class SdPageObjsTLV;
+class SfxMedium;
+
+class SdInsertPagesObjsDlg : public weld::GenericDialogController
+{
+private:
+ SfxMedium* m_pMedium;
+ const SdDrawDocument* m_pDoc;
+ const OUString& m_rName;
+
+ std::unique_ptr<SdPageObjsTLV> m_xLbTree;
+ std::unique_ptr<weld::CheckButton> m_xCbxLink;
+ std::unique_ptr<weld::CheckButton> m_xCbxMasters;
+
+ void Reset();
+ DECL_LINK(SelectObjectHdl, weld::TreeView&, void);
+
+public:
+ SdInsertPagesObjsDlg(weld::Window* pParent, const SdDrawDocument* pDoc,
+ SfxMedium* pSfxMedium, const OUString& rFileName);
+ virtual ~SdInsertPagesObjsDlg() override;
+
+ /** returns the list
+ nType == 0 -> pages
+ nType == 1 -> objects */
+
+ std::vector<OUString> GetList ( const sal_uInt16 nType ) ;
+
+ bool IsLink() const;
+ bool IsRemoveUnnecessaryMasterPages() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/layeroptionsdlg.hxx b/sd/source/ui/inc/layeroptionsdlg.hxx
new file mode 100644
index 000000000..300994937
--- /dev/null
+++ b/sd/source/ui/inc/layeroptionsdlg.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sddllapi.h>
+
+#include <vcl/weld.hxx>
+
+class SfxItemSet;
+
+class SD_DLLPUBLIC SdInsertLayerDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::Entry> m_xEdtName;
+ std::unique_ptr<weld::Entry> m_xEdtTitle;
+ std::unique_ptr<weld::TextView> m_xEdtDesc;
+ std::unique_ptr<weld::CheckButton> m_xCbxVisible;
+ std::unique_ptr<weld::CheckButton> m_xCbxPrintable;
+ std::unique_ptr<weld::CheckButton> m_xCbxLocked;
+ std::unique_ptr<weld::Widget> m_xNameFrame;
+
+public:
+
+ SdInsertLayerDlg(weld::Window* pWindow, const SfxItemSet& rInAttrs,
+ bool bDeletable, const OUString& rStr);
+ virtual ~SdInsertLayerDlg() override;
+
+ void GetAttr( SfxItemSet& rOutAttrs );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/masterlayoutdlg.hxx b/sd/source/ui/inc/masterlayoutdlg.hxx
new file mode 100644
index 000000000..0acbb18d7
--- /dev/null
+++ b/sd/source/ui/inc/masterlayoutdlg.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+
+#include <pres.hxx>
+
+class SdDrawDocument;
+class SdPage;
+
+namespace sd
+{
+
+class MasterLayoutDialog : public weld::GenericDialogController
+{
+private:
+ SdDrawDocument* mpDoc;
+ SdPage* mpCurrentPage;
+
+ std::unique_ptr<weld::CheckButton> mxCBDate;
+ std::unique_ptr<weld::CheckButton> mxCBPageNumber;
+ std::unique_ptr<weld::CheckButton> mxCBSlideNumber;
+ std::unique_ptr<weld::CheckButton> mxCBHeader;
+ std::unique_ptr<weld::CheckButton> mxCBFooter;
+
+ bool mbOldHeader;
+ bool mbOldFooter;
+ bool mbOldDate;
+ bool mbOldPageNumber;
+
+ void applyChanges();
+ void remove( PresObjKind eKind );
+ void create( PresObjKind eKind );
+
+public:
+ MasterLayoutDialog(weld::Window* pParent, SdDrawDocument* pDoc, SdPage* pCurrentPage);
+ virtual ~MasterLayoutDialog() override;
+
+ virtual short run() override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/morphdlg.hxx b/sd/source/ui/inc/morphdlg.hxx
new file mode 100644
index 000000000..77b20d718
--- /dev/null
+++ b/sd/source/ui/inc/morphdlg.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+class SdrObject;
+
+namespace sd {
+
+class MorphDlg : public weld::GenericDialogController
+{
+public:
+ MorphDlg(weld::Window* pParent, const SdrObject* pObj1, const SdrObject* pObj2);
+ virtual ~MorphDlg() override;
+
+ void SaveSettings() const;
+ sal_uInt16 GetFadeSteps() const { return static_cast<sal_uInt16>(m_xMtfSteps->get_value()); }
+ bool IsAttributeFade() const { return m_xCbxAttributes->get_active(); }
+ bool IsOrientationFade() const { return m_xCbxOrientation->get_active(); }
+
+private:
+ std::unique_ptr<weld::SpinButton> m_xMtfSteps;
+ std::unique_ptr<weld::CheckButton> m_xCbxAttributes;
+ std::unique_ptr<weld::CheckButton> m_xCbxOrientation;
+
+ void LoadSettings();
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/navigatr.hxx b/sd/source/ui/inc/navigatr.hxx
new file mode 100644
index 000000000..0e500eb0f
--- /dev/null
+++ b/sd/source/ui/inc/navigatr.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <sfx2/ctrlitem.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <sfx2/navigat.hxx>
+#include "sdtreelb.hxx"
+#include <pres.hxx>
+
+// forward
+namespace vcl { class Window; }
+
+namespace sd {
+class DrawDocShell;
+class SdNavigatorFloat;
+}
+class Menu;
+class SdNavigatorControllerItem;
+class SdPageNameControllerItem;
+
+enum class NavState {
+ NONE = 0x000000,
+ TableUpdate = 0x000100,
+ BtnFirstEnabled = 0x001000,
+ BtnFirstDisabled = 0x002000,
+ BtnPrevEnabled = 0x004000,
+ BtnPrevDisabled = 0x008000,
+ BtnLastEnabled = 0x010000,
+ BtnLastDisabled = 0x020000,
+ BtnNextEnabled = 0x040000,
+ BtnNextDisabled = 0x080000,
+};
+namespace o3tl {
+ template<> struct typed_flags<NavState> : is_typed_flags<NavState, 0x0ff100> {};
+}
+
+class NavDocInfo
+{
+public:
+ NavDocInfo()
+ : bName(false)
+ , bActive(false)
+ , mpDocShell(nullptr)
+ {
+ }
+
+ bool HasName() const { return bName; }
+ bool IsActive() const { return bActive; }
+
+ void SetName( bool bOn ) { bName = bOn; }
+ void SetActive( bool bOn ) { bActive = bOn; }
+
+ ::sd::DrawDocShell* GetDrawDocShell() {return mpDocShell;}
+
+private:
+ friend class SdNavigatorWin;
+ bool bName : 1;
+ bool bActive : 1;
+ ::sd::DrawDocShell* mpDocShell;
+};
+
+namespace sd {
+
+class SdNavigatorFloat : public SfxNavigator
+{
+private:
+ std::unique_ptr<SdNavigatorWin> m_xNavWin;
+ bool m_bSetInitialFocusOnActivate;
+
+public:
+ SdNavigatorFloat(SfxBindings* _pBindings, SfxChildWindow* pMgr,
+ vcl::Window* pParent, SfxChildWinInfo* pInfo);
+ void InitTreeLB(const SdDrawDocument* pDoc);
+ void FreshTree(const SdDrawDocument* pDoc);
+ virtual void Activate() override;
+ virtual void dispose() override;
+ virtual ~SdNavigatorFloat() override;
+};
+
+}
+
+class SD_DLLPUBLIC SdNavigatorWin : public PanelLayout
+{
+public:
+ typedef ::std::function<void ()> UpdateRequestFunctor;
+
+ /** Create a new instance of the navigator.
+ @param bUseActiveUpdate
+ When <TRUE/>, the default, then the SdNavigatorWin object
+ will make a SID_NAVIGATOR_INIT call whenever it thinks an
+ update is necessary. When <FALSE/> the navigator will
+ rely on others to trigger updates.
+ */
+ SdNavigatorWin(weld::Widget* pParent, SfxBindings* pBindings, SfxNavigator* pNavigatorDlg);
+ void SetUpdateRequestFunctor(const UpdateRequestFunctor& rUpdateRequest);
+ virtual ~SdNavigatorWin() override;
+
+ void InitTreeLB( const SdDrawDocument* pDoc );
+ void RefreshDocumentLB( const OUString* pDocName = nullptr );
+ void FirstFocus();
+
+ bool InsertFile(const OUString& rFileName);
+
+ NavigatorDragType GetNavigatorDragType();
+ SdPageObjsTLV& GetObjects();
+
+private:
+ friend class SdNavigatorFloat;
+ friend class SdNavigatorControllerItem;
+ friend class SdPageNameControllerItem;
+
+ std::unique_ptr<weld::Toolbar> mxToolbox;
+ std::unique_ptr<SdPageObjsTLV> mxTlbObjects;
+ std::unique_ptr<weld::ComboBox> mxLbDocs;
+ std::unique_ptr<weld::Menu> mxDragModeMenu;
+ std::unique_ptr<weld::Menu> mxShapeMenu;
+
+ VclPtr<SfxNavigator> mxNavigatorDlg;
+
+ bool mbDocImported;
+ OUString maDropFileName;
+ NavigatorDragType meDragType;
+ std::vector<NavDocInfo> maDocList;
+ SfxBindings* mpBindings;
+ std::unique_ptr<SdNavigatorControllerItem> mpNavigatorCtrlItem;
+ std::unique_ptr<SdPageNameControllerItem> mpPageNameCtrlItem;
+
+ /** This flag controls whether all shapes or only the named shapes are
+ shown.
+ */
+ // bool mbShowAllShapes;
+
+ static OUString GetDragTypeSdBmpId(NavigatorDragType eDT);
+ NavDocInfo* GetDocInfo();
+
+ DECL_DLLPRIVATE_LINK( SelectToolboxHdl, const OString&, void );
+ DECL_DLLPRIVATE_LINK( DropdownClickToolBoxHdl, const OString&, void );
+ DECL_DLLPRIVATE_LINK( ClickObjectHdl, weld::TreeView&, bool );
+ DECL_DLLPRIVATE_LINK( SelectDocumentHdl, weld::ComboBox&, void );
+ DECL_DLLPRIVATE_LINK( MenuSelectHdl, const OString&, void );
+ DECL_DLLPRIVATE_LINK( ShapeFilterCallback, const OString&, void );
+ DECL_DLLPRIVATE_LINK( KeyInputHdl, const KeyEvent&, bool );
+
+ void SetDragImage();
+
+public:
+ //when object is marked , fresh the corresponding entry tree .
+ void FreshTree ( const SdDrawDocument* pDoc );
+
+ virtual weld::Window* GetFrameWeld() const override;
+};
+
+/**
+ * ControllerItem for Navigator
+ */
+class SdNavigatorControllerItem : public SfxControllerItem
+{
+public:
+ SdNavigatorControllerItem( sal_uInt16, SdNavigatorWin*, SfxBindings*,
+ const SdNavigatorWin::UpdateRequestFunctor& rUpdateRequest);
+
+protected:
+ virtual void StateChangedAtToolBoxControl( sal_uInt16 nSId, SfxItemState eState,
+ const SfxPoolItem* pState ) override;
+
+private:
+ SdNavigatorWin* pNavigatorWin;
+ const SdNavigatorWin::UpdateRequestFunctor maUpdateRequest;
+};
+
+/**
+ * ControllerItem for Navigator to show the page in the TreeLB
+ */
+class SdPageNameControllerItem : public SfxControllerItem
+{
+public:
+ SdPageNameControllerItem( sal_uInt16, SdNavigatorWin*, SfxBindings*);
+
+protected:
+ virtual void StateChangedAtToolBoxControl( sal_uInt16 nSId, SfxItemState eState,
+ const SfxPoolItem* pState ) override;
+
+private:
+ SdNavigatorWin* pNavigatorWin;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/optsitem.hxx b/sd/source/ui/inc/optsitem.hxx
new file mode 100644
index 000000000..979b90b78
--- /dev/null
+++ b/sd/source/ui/inc/optsitem.hxx
@@ -0,0 +1,580 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <unotools/configitem.hxx>
+#include <sfx2/module.hxx>
+#include <svx/optgrid.hxx>
+#include <tools/degree.hxx>
+#include <sddllapi.h>
+#include <memory>
+
+class SdOptions;
+
+namespace sd {
+class FrameView;
+}
+
+class SdOptionsGeneric;
+
+class SD_DLLPUBLIC SdOptionsItem : public ::utl::ConfigItem
+{
+
+private:
+
+ const SdOptionsGeneric& mrParent;
+
+ virtual void ImplCommit() override;
+
+public:
+
+ SdOptionsItem( const SdOptionsGeneric& rParent, const OUString& rSubTree );
+ virtual ~SdOptionsItem() override;
+
+ SdOptionsItem(SdOptionsItem const &) = default;
+ SdOptionsItem(SdOptionsItem &&) = default;
+ SdOptionsItem & operator =(SdOptionsItem const &) = delete; // due to ConfigItem
+ SdOptionsItem & operator =(SdOptionsItem &&) = delete; // due to ConfigItem
+
+ virtual void Notify( const css::uno::Sequence<OUString>& aPropertyNames) override;
+
+ css::uno::Sequence< css::uno::Any > GetProperties( const css::uno::Sequence< OUString >& rNames );
+ bool PutProperties( const css::uno::Sequence< OUString >& rNames,
+ const css::uno::Sequence< css::uno::Any>& rValues );
+ using ConfigItem::SetModified;
+};
+
+class SD_DLLPUBLIC SdOptionsGeneric
+{
+friend class SdOptionsItem;
+
+private:
+
+ OUString maSubTree;
+ std::unique_ptr<SdOptionsItem>
+ mpCfgItem;
+ bool mbImpress;
+ bool mbInit : 1;
+ bool mbEnableModify : 1;
+
+ SAL_DLLPRIVATE void Commit( SdOptionsItem& rCfgItem ) const;
+ SAL_DLLPRIVATE css::uno::Sequence< OUString > GetPropertyNames() const;
+
+protected:
+
+ void Init() const;
+ void OptionsChanged() { if( mpCfgItem && mbEnableModify ) mpCfgItem->SetModified(); }
+
+protected:
+
+ virtual void GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const = 0;
+ virtual bool ReadData( const css::uno::Any* pValues ) = 0;
+ virtual bool WriteData( css::uno::Any* pValues ) const = 0;
+
+public:
+
+ SdOptionsGeneric(bool bImpress, const OUString& rSubTree);
+ SdOptionsGeneric(SdOptionsGeneric const &);
+ virtual ~SdOptionsGeneric();
+
+ SdOptionsGeneric& operator=( SdOptionsGeneric const & );
+
+ bool IsImpress() const { return mbImpress; }
+
+ void EnableModify( bool bModify ) { mbEnableModify = bModify; }
+
+ void Store();
+
+ static bool isMetricSystem();
+};
+
+class SD_DLLPUBLIC SdOptionsLayout : public SdOptionsGeneric
+{
+private:
+
+ bool bRuler; // Layout/Display/Ruler
+ bool bMoveOutline; // Layout/Display/Contour
+ bool bDragStripes; // Layout/Display/Guide
+ bool bHandlesBezier; // Layout/Display/Bezier
+ bool bHelplines; // Layout/Display/Helpline
+ sal_uInt16 nMetric; // Layout/Other/MeasureUnit
+ sal_uInt16 nDefTab; // Layout/Other/TabStop
+
+protected:
+
+ virtual void GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const override;
+ virtual bool ReadData( const css::uno::Any* pValues ) override;
+ virtual bool WriteData( css::uno::Any* pValues ) const override;
+
+public:
+ SdOptionsLayout(bool bImpress, bool bUseConfig);
+
+ bool operator==( const SdOptionsLayout& rOpt ) const;
+
+ bool IsRulerVisible() const { Init(); return bRuler; }
+ bool IsMoveOutline() const { Init(); return bMoveOutline; }
+ bool IsDragStripes() const { Init(); return bDragStripes; }
+ bool IsHandlesBezier() const { Init(); return bHandlesBezier; }
+ bool IsHelplines() const { Init(); return bHelplines; }
+ sal_uInt16 GetMetric() const { Init(); return( ( 0xffff == nMetric ) ? static_cast<sal_uInt16>(SfxModule::GetCurrentFieldUnit()) : nMetric ); }
+ sal_uInt16 GetDefTab() const { Init(); return nDefTab; }
+
+ void SetRulerVisible( bool bOn ) { if( bRuler != bOn ) { OptionsChanged(); bRuler = bOn; } }
+ void SetMoveOutline( bool bOn ) { if( bMoveOutline != bOn ) { OptionsChanged(); bMoveOutline = bOn; } }
+ void SetDragStripes( bool bOn ) { if( bDragStripes != bOn ) { OptionsChanged(); bDragStripes = bOn; } }
+ void SetHandlesBezier( bool bOn ) { if( bHandlesBezier != bOn ) { OptionsChanged(); bHandlesBezier = bOn; } }
+ void SetHelplines( bool bOn ) { if( bHelplines != bOn ) { OptionsChanged(); bHelplines = bOn; } }
+ void SetMetric( sal_uInt16 nInMetric ) { if( nMetric != nInMetric ) { OptionsChanged(); nMetric = nInMetric; } }
+ void SetDefTab( sal_uInt16 nTab ) { if( nDefTab != nTab ) { OptionsChanged(); nDefTab = nTab; } }
+};
+
+class SD_DLLPUBLIC SdOptionsLayoutItem : public SfxPoolItem
+{
+public:
+
+ explicit SdOptionsLayoutItem();
+ SdOptionsLayoutItem( SdOptions const * pOpts, ::sd::FrameView const * pView );
+
+ virtual SdOptionsLayoutItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+ virtual bool operator==( const SfxPoolItem& ) const override;
+
+ void SetOptions( SdOptions* pOpts ) const;
+
+ SdOptionsLayout& GetOptionsLayout() { return maOptionsLayout; }
+private:
+ SdOptionsLayout maOptionsLayout;
+};
+
+class SdOptionsContents : public SdOptionsGeneric
+{
+private:
+protected:
+
+ virtual void GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const override;
+ virtual bool ReadData( const css::uno::Any* pValues ) override;
+ virtual bool WriteData( css::uno::Any* pValues ) const override;
+
+public:
+
+ SdOptionsContents(bool bImpress);
+
+ bool operator==( const SdOptionsContents& rOpt ) const;
+};
+
+class SD_DLLPUBLIC SdOptionsMisc : public SdOptionsGeneric
+{
+private:
+
+ sal_Int32 nDefaultObjectSizeWidth;
+ sal_Int32 nDefaultObjectSizeHeight;
+
+ bool bStartWithTemplate : 1; // Misc/NewDoc/AutoPilot
+ bool bMarkedHitMovesAlways : 1; // Misc/ObjectMoveable
+ bool bMoveOnlyDragging : 1; // Currently, not in use !!!
+ bool bCrookNoContortion : 1; // Misc/NoDistort
+ bool bQuickEdit : 1; // Misc/TextObject/QuickEditing
+ bool bMasterPageCache : 1; // Misc/BackgroundCache
+ bool bDragWithCopy : 1; // Misc/CopyWhileMoving
+ bool bPickThrough : 1; // Misc/TextObject/Selectable
+ bool bDoubleClickTextEdit : 1; // Misc/DclickTextedit
+ bool bClickChangeRotation : 1; // Misc/RotateClick
+ bool bEnableSdremote : 1; // Misc/Start/EnableSdremote
+ bool bEnablePresenterScreen : 1; // Misc/Start/EnablePresenterDisplay
+ bool bSolidDragging : 1; // Misc/ModifyWithAttributes
+ bool bSummationOfParagraphs : 1; // misc/SummationOfParagraphs
+ bool bTabBarVisible : 1; // Misc/TabBarVisible
+ bool bShowUndoDeleteWarning : 1; // Misc/ShowUndoDeleteWarning
+ // #i75315#
+ bool bSlideshowRespectZOrder : 1; // Misc/SlideshowRespectZOrder
+ bool bShowComments : 1; // Misc/ShowComments
+
+ bool bPreviewNewEffects;
+ bool bPreviewChangedEffects;
+ bool bPreviewTransitions;
+
+
+ sal_Int32 mnDisplay;
+
+ sal_Int32 mnPenColor;
+ double mnPenWidth;
+
+ /** This value controls the device to use for formatting documents.
+ The currently supported values are 0 for the current printer or 1
+ for the printer independent virtual device the can be retrieved from
+ the modules.
+ */
+ sal_uInt16 mnPrinterIndependentLayout; // Misc/Compatibility/PrinterIndependentLayout
+// Misc
+
+protected:
+
+ virtual void GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const override;
+ virtual bool ReadData( const css::uno::Any* pValues ) override;
+ virtual bool WriteData( css::uno::Any* pValues ) const override;
+
+public:
+
+ SdOptionsMisc(bool bImpress, bool bUseConfig);
+
+ bool operator==( const SdOptionsMisc& rOpt ) const;
+
+ bool IsStartWithTemplate() const { Init(); return bStartWithTemplate; }
+ bool IsMarkedHitMovesAlways() const { Init(); return bMarkedHitMovesAlways; }
+ bool IsMoveOnlyDragging() const { Init(); return bMoveOnlyDragging; }
+ bool IsCrookNoContortion() const { Init(); return bCrookNoContortion; }
+ bool IsQuickEdit() const { Init(); return bQuickEdit; }
+ bool IsMasterPagePaintCaching() const { Init(); return bMasterPageCache; }
+ bool IsDragWithCopy() const { Init(); return bDragWithCopy; }
+ bool IsPickThrough() const { Init(); return bPickThrough; }
+ bool IsDoubleClickTextEdit() const { Init(); return bDoubleClickTextEdit; }
+ bool IsClickChangeRotation() const { Init(); return bClickChangeRotation; }
+ bool IsEnableSdremote() const { Init(); return bEnableSdremote; }
+ bool IsEnablePresenterScreen() const { Init(); return bEnablePresenterScreen; }
+ bool IsSolidDragging() const { Init(); return bSolidDragging; }
+ bool IsSummationOfParagraphs() const { Init(); return bSummationOfParagraphs; };
+ bool IsTabBarVisible() const { Init(); return bTabBarVisible; };
+
+ /** Return the currently selected printer independent layout mode.
+ @return
+ Returns 1 for printer independent layout enabled and 0 when it
+ is disabled. Other values are reserved for future use.
+ */
+ sal_uInt16 GetPrinterIndependentLayout() const { Init(); return mnPrinterIndependentLayout; };
+ bool IsShowUndoDeleteWarning() const { Init(); return bShowUndoDeleteWarning; }
+ bool IsSlideshowRespectZOrder() const { Init(); return bSlideshowRespectZOrder; }
+ sal_Int32 GetDefaultObjectSizeWidth() const { Init(); return nDefaultObjectSizeWidth; }
+ sal_Int32 GetDefaultObjectSizeHeight() const { Init(); return nDefaultObjectSizeHeight; }
+
+ bool IsPreviewNewEffects() const { Init(); return bPreviewNewEffects; }
+ bool IsPreviewChangedEffects() const { Init(); return bPreviewChangedEffects; }
+ bool IsPreviewTransitions() const { Init(); return bPreviewTransitions; }
+
+ sal_Int32 GetDisplay() const;
+ void SetDisplay( sal_Int32 nDisplay );
+
+ sal_Int32 GetPresentationPenColor() const { Init(); return mnPenColor; }
+ void SetPresentationPenColor( sal_Int32 nPenColor ) { if( mnPenColor != nPenColor ) { OptionsChanged(); mnPenColor = nPenColor; } }
+
+ double GetPresentationPenWidth() const { Init(); return mnPenWidth; }
+ void SetPresentationPenWidth( double nPenWidth ) { if( mnPenWidth != nPenWidth ) { OptionsChanged(); mnPenWidth = nPenWidth; } }
+
+ void SetStartWithTemplate( bool bOn ) { if( bStartWithTemplate != bOn ) { OptionsChanged(); bStartWithTemplate = bOn; } }
+ void SetMarkedHitMovesAlways( bool bOn ) { if( bMarkedHitMovesAlways != bOn ) { OptionsChanged(); bMarkedHitMovesAlways = bOn; } }
+ void SetMoveOnlyDragging( bool bOn ) { if( bMoveOnlyDragging != bOn ) { OptionsChanged(); bMoveOnlyDragging = bOn; } }
+ void SetCrookNoContortion( bool bOn ) { if( bCrookNoContortion != bOn ) { OptionsChanged(); bCrookNoContortion = bOn; } }
+ void SetQuickEdit( bool bOn ) { if( bQuickEdit != bOn ) { OptionsChanged(); bQuickEdit = bOn; } }
+ void SetMasterPagePaintCaching( bool bOn ) { if( bMasterPageCache != bOn ) { OptionsChanged(); bMasterPageCache = bOn; } }
+ void SetDragWithCopy( bool bOn ) { if( bDragWithCopy != bOn ) { OptionsChanged(); bDragWithCopy = bOn; } }
+ void SetPickThrough( bool bOn ) { if( bPickThrough != bOn ) { OptionsChanged(); bPickThrough = bOn; } }
+ void SetDoubleClickTextEdit( bool bOn ) { if( bDoubleClickTextEdit != bOn ) { OptionsChanged(); bDoubleClickTextEdit = bOn; } }
+ void SetClickChangeRotation( bool bOn ) { if( bClickChangeRotation != bOn ) { OptionsChanged(); bClickChangeRotation = bOn; } }
+ void SetEnableSdremote( bool bOn ) { if( bEnableSdremote != bOn ) { OptionsChanged(); bEnableSdremote = bOn; } }
+ void SetEnablePresenterScreen( bool bOn ) { if( bEnablePresenterScreen != bOn ) { OptionsChanged(); bEnablePresenterScreen = bOn; } }
+ void SetSummationOfParagraphs( bool bOn ){ if ( bOn != bSummationOfParagraphs ) { OptionsChanged(); bSummationOfParagraphs = bOn; } }
+ void SetTabBarVisible( bool bOn ){ if ( bOn != bTabBarVisible ) { OptionsChanged(); bTabBarVisible = bOn; } }
+ /** Set the printer independent layout mode.
+ @param nOn
+ The default value is to switch printer independent layout on,
+ hence the parameters name. Use 0 for turning it off. Other
+ values are reserved for future use.
+ */
+ void SetPrinterIndependentLayout (sal_uInt16 nOn ){ if ( nOn != mnPrinterIndependentLayout ) { OptionsChanged(); mnPrinterIndependentLayout = nOn; } }
+ void SetSolidDragging( bool bOn ) { if( bSolidDragging != bOn ) { OptionsChanged(); bSolidDragging = bOn; } }
+ void SetShowUndoDeleteWarning( bool bOn ) { if( bShowUndoDeleteWarning != bOn ) { OptionsChanged(); bShowUndoDeleteWarning = bOn; } }
+ void SetSlideshowRespectZOrder( bool bOn ) { if( bSlideshowRespectZOrder != bOn ) { OptionsChanged(); bSlideshowRespectZOrder = bOn; } }
+ void SetDefaultObjectSizeWidth( sal_Int32 nWidth ) { if( nDefaultObjectSizeWidth != nWidth ) { OptionsChanged(); nDefaultObjectSizeWidth = nWidth; } }
+ void SetDefaultObjectSizeHeight( sal_Int32 nHeight ) { if( nDefaultObjectSizeHeight != nHeight ) { OptionsChanged(); nDefaultObjectSizeHeight = nHeight; } }
+
+ void SetPreviewNewEffects( bool bOn ) { if( bPreviewNewEffects != bOn ) { OptionsChanged(); bPreviewNewEffects = bOn; } }
+ void SetPreviewChangedEffects( bool bOn ) { if( bPreviewChangedEffects != bOn ) { OptionsChanged(); bPreviewChangedEffects = bOn; } }
+ void SetPreviewTransitions( bool bOn ) { if( bPreviewTransitions != bOn ) { OptionsChanged(); bPreviewTransitions = bOn; } }
+
+ bool IsShowComments() const { Init(); return bShowComments; }
+ void SetShowComments( bool bShow ) { if( bShowComments != bShow ) { OptionsChanged(); bShowComments = bShow; } }
+};
+
+class SD_DLLPUBLIC SdOptionsMiscItem : public SfxPoolItem
+{
+public:
+
+ explicit SdOptionsMiscItem();
+ SdOptionsMiscItem( SdOptions const * pOpts, ::sd::FrameView const * pView );
+
+ virtual SdOptionsMiscItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+ virtual bool operator==( const SfxPoolItem& ) const override;
+
+ void SetOptions( SdOptions* pOpts ) const;
+
+ SdOptionsMisc& GetOptionsMisc() { return maOptionsMisc; }
+ const SdOptionsMisc& GetOptionsMisc() const { return maOptionsMisc; }
+private:
+ SdOptionsMisc maOptionsMisc;
+};
+
+class SD_DLLPUBLIC SdOptionsSnap : public SdOptionsGeneric
+{
+private:
+
+ bool bSnapHelplines : 1; // Snap/Object/SnapLine
+ bool bSnapBorder : 1; // Snap/Object/PageMargin
+ bool bSnapFrame : 1; // Snap/Object/ObjectFrame
+ bool bSnapPoints : 1; // Snap/Object/ObjectPoint
+ bool bOrtho : 1; // Snap/Position/CreatingMoving
+ bool bBigOrtho : 1; // Snap/Position/ExtendEdges
+ bool bRotate : 1; // Snap/Position/Rotating
+ sal_Int16 nSnapArea; // Snap/Object/Range
+ Degree100 nAngle; // Snap/Position/RotatingValue
+ Degree100 nBezAngle; // Snap/Position/PointReduction
+
+protected:
+
+ virtual void GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const override;
+ virtual bool ReadData( const css::uno::Any* pValues ) override;
+ virtual bool WriteData( css::uno::Any* pValues ) const override;
+
+public:
+
+ SdOptionsSnap(bool bImpress, bool bUseConfig);
+
+ bool operator==( const SdOptionsSnap& rOpt ) const;
+
+ bool IsSnapHelplines() const { Init(); return bSnapHelplines; }
+ bool IsSnapBorder() const { Init(); return bSnapBorder; }
+ bool IsSnapFrame() const { Init(); return bSnapFrame; }
+ bool IsSnapPoints() const { Init(); return bSnapPoints; }
+ bool IsOrtho() const { Init(); return bOrtho; }
+ bool IsBigOrtho() const { Init(); return bBigOrtho; }
+ bool IsRotate() const { Init(); return bRotate; }
+ sal_Int16 GetSnapArea() const { Init(); return nSnapArea; }
+ Degree100 GetAngle() const { Init(); return nAngle; }
+ Degree100 GetEliminatePolyPointLimitAngle() const { Init(); return nBezAngle; }
+
+ void SetSnapHelplines( bool bOn ) { if( bSnapHelplines != bOn ) { OptionsChanged(); bSnapHelplines = bOn; } }
+ void SetSnapBorder( bool bOn ) { if( bSnapBorder != bOn ) { OptionsChanged(); bSnapBorder = bOn; } }
+ void SetSnapFrame( bool bOn ) { if( bSnapFrame != bOn ) { OptionsChanged(); bSnapFrame = bOn; } }
+ void SetSnapPoints( bool bOn ) { if( bSnapPoints != bOn ) { OptionsChanged(); bSnapPoints = bOn; } }
+ void SetOrtho( bool bOn ) { if( bOrtho != bOn ) { OptionsChanged(); bOrtho = bOn; } }
+ void SetBigOrtho( bool bOn ) { if( bBigOrtho != bOn ) { OptionsChanged(); bBigOrtho = bOn; } }
+ void SetRotate( bool bOn ) { if( bRotate != bOn ) { OptionsChanged(); bRotate = bOn; } }
+ void SetSnapArea( sal_Int16 nIn ) { if( nSnapArea != nIn ) { OptionsChanged(); nSnapArea = nIn; } }
+ void SetAngle( Degree100 nIn ) { if( nAngle != nIn ) { OptionsChanged(); nAngle = nIn; } }
+ void SetEliminatePolyPointLimitAngle( Degree100 nIn ) { if( nBezAngle != nIn ) { OptionsChanged(); nBezAngle = nIn; } }
+};
+
+class SD_DLLPUBLIC SdOptionsSnapItem : public SfxPoolItem
+{
+public:
+
+ explicit SdOptionsSnapItem();
+ SdOptionsSnapItem( SdOptions const * pOpts, ::sd::FrameView const * pView );
+
+ virtual SdOptionsSnapItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+ virtual bool operator==( const SfxPoolItem& ) const override;
+
+ void SetOptions( SdOptions* pOpts ) const;
+
+ SdOptionsSnap& GetOptionsSnap() { return maOptionsSnap; }
+private:
+ SdOptionsSnap maOptionsSnap;
+};
+
+class SdOptionsZoom : public SdOptionsGeneric
+{
+private:
+
+ sal_Int32 nX; // Zoom/ScaleX
+ sal_Int32 nY; // Zoom/ScaleY
+
+protected:
+
+ virtual void GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const override;
+ virtual bool ReadData( const css::uno::Any* pValues ) override;
+ virtual bool WriteData( css::uno::Any* pValues ) const override;
+
+public:
+
+ explicit SdOptionsZoom(bool bImpress);
+
+ void GetScale( sal_Int32& rX, sal_Int32& rY ) const { Init(); rX = nX; rY = nY; }
+ void SetScale( sal_Int32 nInX, sal_Int32 nInY ) { if( nX != nInX || nY != nInY ) { OptionsChanged(); nX = nInX; nY = nInY; } }
+};
+
+class SdOptionsGrid : public SdOptionsGeneric, public SvxOptionsGrid
+{
+protected:
+
+ virtual void GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const override;
+ virtual bool ReadData( const css::uno::Any* pValues ) override;
+ virtual bool WriteData( css::uno::Any* pValues ) const override;
+
+public:
+
+ explicit SdOptionsGrid(bool bImpress);
+ virtual ~SdOptionsGrid() override;
+
+ void SetDefaults();
+
+ sal_uInt32 GetFieldDrawX() const { Init(); return SvxOptionsGrid::GetFieldDrawX(); }
+ sal_uInt32 GetFieldDivisionX() const { Init(); return SvxOptionsGrid::GetFieldDivisionX(); }
+ sal_uInt32 GetFieldDrawY() const { Init(); return SvxOptionsGrid::GetFieldDrawY(); }
+ sal_uInt32 GetFieldDivisionY() const { Init(); return SvxOptionsGrid::GetFieldDivisionY(); }
+ sal_uInt32 GetFieldSnapX() const { Init(); return SvxOptionsGrid::GetFieldSnapX(); }
+ sal_uInt32 GetFieldSnapY() const { Init(); return SvxOptionsGrid::GetFieldSnapY(); }
+ bool IsUseGridSnap() const { Init(); return SvxOptionsGrid::GetUseGridSnap(); }
+ bool IsSynchronize() const { Init(); return SvxOptionsGrid::GetSynchronize(); }
+ bool IsGridVisible() const { Init(); return SvxOptionsGrid::GetGridVisible(); }
+ bool IsEqualGrid() const { Init(); return SvxOptionsGrid::GetEqualGrid(); }
+
+ void SetFieldDrawX( sal_uInt32 nSet ) { if( nSet != SvxOptionsGrid::GetFieldDrawX() ) { OptionsChanged(); SvxOptionsGrid::SetFieldDrawX( nSet ); } }
+ void SetFieldDivisionX( sal_uInt32 nSet ) { if( nSet != SvxOptionsGrid::GetFieldDivisionX() ) { OptionsChanged(); SvxOptionsGrid::SetFieldDivisionX( nSet ); } }
+ void SetFieldDrawY( sal_uInt32 nSet ) { if( nSet != SvxOptionsGrid::GetFieldDrawY() ) { OptionsChanged(); SvxOptionsGrid::SetFieldDrawY( nSet ); } }
+ void SetFieldDivisionY( sal_uInt32 nSet ) { if( nSet != SvxOptionsGrid::GetFieldDivisionY() ) { OptionsChanged(); SvxOptionsGrid::SetFieldDivisionY( nSet ); } }
+ void SetFieldSnapX( sal_uInt32 nSet ) { if( nSet != SvxOptionsGrid::GetFieldSnapX() ) { OptionsChanged(); SvxOptionsGrid::SetFieldSnapX( nSet ); } }
+ void SetFieldSnapY( sal_uInt32 nSet ) { if( nSet != SvxOptionsGrid::GetFieldSnapY() ) { OptionsChanged(); SvxOptionsGrid::SetFieldSnapY( nSet ); } }
+ void SetUseGridSnap( bool bSet ) { if( bSet != SvxOptionsGrid::GetUseGridSnap() ) { OptionsChanged(); SvxOptionsGrid::SetUseGridSnap( bSet ); } }
+ void SetSynchronize( bool bSet ) { if( bSet != SvxOptionsGrid::GetSynchronize() ) { OptionsChanged(); SvxOptionsGrid::SetSynchronize( bSet ); } }
+ void SetGridVisible( bool bSet ) { if( bSet != SvxOptionsGrid::GetGridVisible() ) { OptionsChanged(); SvxOptionsGrid::SetGridVisible( bSet ); } }
+ void SetEqualGrid( bool bSet ) { if( bSet != SvxOptionsGrid::GetEqualGrid() ) { OptionsChanged(); SvxOptionsGrid::SetEqualGrid( bSet ); } }
+};
+
+class SdOptionsGridItem : public SvxGridItem
+{
+
+public:
+ explicit SdOptionsGridItem( SdOptions const * pOpts );
+
+ void SetOptions( SdOptions* pOpts ) const;
+};
+
+class SD_DLLPUBLIC SdOptionsPrint : public SdOptionsGeneric
+{
+private:
+
+ bool bDraw : 1; // Print/Content/Drawing
+ bool bNotes : 1; // Print/Content/Note
+ bool bHandout : 1; // Print/Content/Handout
+ bool bOutline : 1; // Print/Content/Outline
+ bool bDate : 1; // Print/Other/Date
+ bool bTime : 1; // Print/Other/Time
+ bool bPagename : 1; // Print/Other/PageName
+ bool bHiddenPages : 1; // Print/Other/HiddenPage
+ bool bPagesize : 1; // Print/Page/PageSize
+ bool bPagetile : 1; // Print/Page/PageTile
+ bool bWarningPrinter : 1; // These flags you get
+ bool bWarningSize : 1; // from the common options,
+ bool bWarningOrientation : 1; // currently org.openoffice.Office.Common.xml (class OfaMiscCfg ; sfx2/misccfg.hxx )
+ bool bBooklet : 1; // Print/Page/Booklet
+ bool bFront : 1; // Print/Page/BookletFront
+ bool bBack : 1; // Print/Page/BookletFront
+ bool bCutPage : 1; // NOT persistent !!!
+ bool bPaperbin : 1; // Print/Other/FromPrinterSetup
+ bool mbHandoutHorizontal : 1; // Order Page previews on Handout Pages horizontal
+ sal_uInt16 mnHandoutPages; // Number of page previews on handout page (only 1/2/4/6/9 are supported)
+ sal_uInt16 nQuality; // Print/Other/Quality
+
+protected:
+
+ virtual void GetPropNameArray( const char**& ppNames, sal_uLong& rCount ) const override;
+ virtual bool ReadData( const css::uno::Any* pValues ) override;
+ virtual bool WriteData( css::uno::Any* pValues ) const override;
+
+public:
+
+ SdOptionsPrint(bool bImpress, bool bUseConfig);
+
+ bool operator==( const SdOptionsPrint& rOpt ) const;
+
+ bool IsDraw() const { Init(); return bDraw; }
+ bool IsNotes() const { Init(); return bNotes; }
+ bool IsHandout() const { Init(); return bHandout; }
+ bool IsOutline() const { Init(); return bOutline; }
+ bool IsDate() const { Init(); return bDate; }
+ bool IsTime() const { Init(); return bTime; }
+ bool IsPagename() const { Init(); return bPagename; }
+ bool IsHiddenPages() const { Init(); return bHiddenPages; }
+ bool IsPagesize() const { Init(); return bPagesize; }
+ bool IsPagetile() const { Init(); return bPagetile; }
+ bool IsWarningPrinter() const { Init(); return bWarningPrinter; }
+ bool IsWarningSize() const { Init(); return bWarningSize; }
+ bool IsWarningOrientation() const { Init(); return bWarningOrientation; }
+ bool IsBooklet() const { Init(); return bBooklet; }
+ bool IsFrontPage() const { Init(); return bFront; }
+ bool IsBackPage() const { Init(); return bBack; }
+ bool IsCutPage() const { Init(); return bCutPage; }
+ bool IsPaperbin() const { Init(); return bPaperbin; }
+ sal_uInt16 GetOutputQuality() const { Init(); return nQuality; }
+ bool IsHandoutHorizontal() const { Init(); return mbHandoutHorizontal; }
+ sal_uInt16 GetHandoutPages() const { Init(); return mnHandoutPages; }
+
+ void SetDraw( bool bOn ) { if( bDraw != bOn ) { OptionsChanged(); bDraw = bOn; } }
+ void SetNotes( bool bOn ) { if( bNotes != bOn ) { OptionsChanged(); bNotes = bOn; } }
+ void SetHandout( bool bOn ) { if( bHandout != bOn ) { OptionsChanged(); bHandout = bOn; } }
+ void SetOutline( bool bOn ) { if( bOutline != bOn ) { OptionsChanged(); bOutline = bOn; } }
+ void SetDate( bool bOn ) { if( bDate != bOn ) { OptionsChanged(); bDate = bOn; } }
+ void SetTime( bool bOn ) { if( bTime != bOn ) { OptionsChanged(); bTime = bOn; } }
+ void SetPagename( bool bOn ) { if( bPagename != bOn ) { OptionsChanged(); bPagename = bOn; } }
+ void SetHiddenPages( bool bOn ) { if( bHiddenPages != bOn ) { OptionsChanged(); bHiddenPages = bOn; } }
+ void SetPagesize( bool bOn ) { if( bPagesize != bOn ) { OptionsChanged(); bPagesize = bOn; } }
+ void SetPagetile( bool bOn ) { if( bPagetile != bOn ) { OptionsChanged(); bPagetile = bOn; } }
+ void SetWarningPrinter( bool bOn ) { if( bWarningPrinter != bOn ) { OptionsChanged(); bWarningPrinter = bOn; } }
+ void SetWarningSize( bool bOn ) { if( bWarningSize != bOn ) { OptionsChanged(); bWarningSize = bOn; } }
+ void SetWarningOrientation( bool bOn) { if( bWarningOrientation != bOn ) { OptionsChanged(); bWarningOrientation = bOn; } }
+ void SetBooklet( bool bOn ) { if( bBooklet != bOn ) { OptionsChanged(); bBooklet = bOn; } }
+ void SetFrontPage( bool bOn ) { if( bFront != bOn ) { OptionsChanged(); bFront = bOn; } }
+ void SetBackPage( bool bOn ) { if( bBack != bOn ) { OptionsChanged(); bBack = bOn; } }
+ void SetCutPage( bool bOn ) { if( bCutPage != bOn ) { OptionsChanged(); bCutPage = bOn; } }
+ void SetPaperbin( bool bOn ) { if( bPaperbin != bOn ) { OptionsChanged(); bPaperbin = bOn; } }
+ void SetOutputQuality( sal_uInt16 nInQuality ) { if( nQuality != nInQuality ) { OptionsChanged(); nQuality = nInQuality; } }
+ void SetHandoutHorizontal( bool bHandoutHorizontal ) { if( mbHandoutHorizontal != bHandoutHorizontal ) { OptionsChanged(); mbHandoutHorizontal = bHandoutHorizontal; } }
+ void SetHandoutPages( sal_uInt16 nHandoutPages ) { if( nHandoutPages != mnHandoutPages ) { OptionsChanged(); mnHandoutPages = nHandoutPages; } }
+};
+
+class SD_DLLPUBLIC SdOptionsPrintItem : public SfxPoolItem
+{
+public:
+
+ explicit SdOptionsPrintItem();
+ explicit SdOptionsPrintItem( SdOptions const * pOpts );
+
+ virtual SdOptionsPrintItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+ virtual bool operator==( const SfxPoolItem& ) const override;
+
+ void SetOptions( SdOptions* pOpts ) const;
+
+ SdOptionsPrint& GetOptionsPrint() { return maOptionsPrint; }
+ const SdOptionsPrint& GetOptionsPrint() const { return maOptionsPrint; }
+private:
+ SdOptionsPrint maOptionsPrint;
+};
+
+class SdOptions : public SdOptionsLayout, public SdOptionsContents,
+ public SdOptionsMisc, public SdOptionsSnap,
+ public SdOptionsZoom, public SdOptionsGrid,
+ public SdOptionsPrint
+{
+public:
+
+ explicit SdOptions(bool bImpress);
+ virtual ~SdOptions() override;
+
+ void StoreConfig();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/paragr.hxx b/sd/source/ui/inc/paragr.hxx
new file mode 100644
index 000000000..30304d800
--- /dev/null
+++ b/sd/source/ui/inc/paragr.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+
+/**
+ * Paragraph-Tab-Dialog
+ */
+class SdParagraphDlg : public SfxTabDialogController
+{
+private:
+ virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override;
+
+public:
+ SdParagraphDlg(weld::Window* pParent, const SfxItemSet* pAttr);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/pgjump.hxx b/sd/source/ui/inc/pgjump.hxx
new file mode 100644
index 000000000..c4d434caa
--- /dev/null
+++ b/sd/source/ui/inc/pgjump.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+enum PageJump
+{
+ PAGE_NONE,
+ PAGE_FIRST,
+ PAGE_PREVIOUS,
+ PAGE_NEXT,
+ PAGE_LAST
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/present.hxx b/sd/source/ui/inc/present.hxx
new file mode 100644
index 000000000..00c78ac79
--- /dev/null
+++ b/sd/source/ui/inc/present.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 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+
+class SfxItemSet;
+class SdCustomShowList;
+
+/**
+ * Dialog to define optionsm_xnd to start the presentation
+ */
+class SdStartPresentationDlg : public weld::GenericDialogController
+{
+private:
+ SdCustomShowList* pCustomShowList;
+ const SfxItemSet& rOutAttrs;
+ sal_Int32 mnMonitors;
+
+ std::unique_ptr<weld::RadioButton> m_xRbtAll;
+ std::unique_ptr<weld::RadioButton> m_xRbtAtDia;
+ std::unique_ptr<weld::RadioButton> m_xRbtCustomshow;
+ std::unique_ptr<weld::ComboBox> m_xLbDias;
+ std::unique_ptr<weld::ComboBox> m_xLbCustomshow;
+
+ std::unique_ptr<weld::RadioButton> m_xRbtStandard;
+ std::unique_ptr<weld::RadioButton> m_xRbtWindow;
+ std::unique_ptr<weld::RadioButton> m_xRbtAuto;
+ std::unique_ptr<weld::FormattedSpinButton> m_xTmfPause;
+ std::unique_ptr<weld::TimeFormatter> m_xFormatter;
+ std::unique_ptr<weld::CheckButton> m_xCbxAutoLogo;
+
+ std::unique_ptr<weld::CheckButton> m_xCbxManuel;
+ std::unique_ptr<weld::CheckButton> m_xCbxMousepointer;
+ std::unique_ptr<weld::CheckButton> m_xCbxPen;
+ std::unique_ptr<weld::CheckButton> m_xCbxAnimationAllowed;
+ std::unique_ptr<weld::CheckButton> m_xCbxChangePage;
+ std::unique_ptr<weld::CheckButton> m_xCbxAlwaysOnTop;
+
+ std::unique_ptr<weld::Label> m_xFtMonitor;
+ std::unique_ptr<weld::ComboBox> m_xLBMonitor;
+
+ std::unique_ptr<weld::Label> m_xMonitor;
+ std::unique_ptr<weld::Label> m_xAllMonitors;
+ std::unique_ptr<weld::Label> m_xMonitorExternal;
+ std::unique_ptr<weld::Label> m_xExternal;
+
+ DECL_LINK(ChangeRangeHdl, weld::Toggleable&, void);
+ DECL_LINK(ClickWindowPresentationHdl, weld::Toggleable&, void);
+ void ChangePause();
+ DECL_LINK(ChangePauseHdl, weld::FormattedSpinButton&, void);
+
+ void InitMonitorSettings();
+ enum DisplayType {
+ EXTERNAL_IS_NUMBER,
+ MONITOR_NORMAL,
+ MONITOR_IS_EXTERNAL,
+ };
+ sal_Int32 InsertDisplayEntry(const OUString &aName,
+ sal_Int32 nDisplay);
+ OUString GetDisplayName( sal_Int32 nDisplay,
+ DisplayType eType );
+public:
+ SdStartPresentationDlg(weld::Window* pWindow,
+ const SfxItemSet& rInAttrs,
+ const std::vector<OUString> &rPageNames,
+ SdCustomShowList* pCSList);
+ virtual ~SdStartPresentationDlg() override;
+ void GetAttr( SfxItemSet& rOutAttrs );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/prltempl.hxx b/sd/source/ui/inc/prltempl.hxx
new file mode 100644
index 000000000..efd50e4f7
--- /dev/null
+++ b/sd/source/ui/inc/prltempl.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+#include <svx/xtable.hxx>
+
+#include <prlayout.hxx>
+
+class SfxObjectShell;
+class SfxStyleSheetBase;
+class SfxStyleSheetBasePool;
+
+/**
+ * Template-Tab-Dialog
+ */
+class SdPresLayoutTemplateDlg final : public SfxTabDialogController
+{
+private:
+ const SfxObjectShell* mpDocShell;
+
+ XColorListRef pColorTab;
+ XGradientListRef pGradientList;
+ XHatchListRef pHatchingList;
+ XBitmapListRef pBitmapList;
+ XPatternListRef pPatternList;
+ XDashListRef pDashList;
+ XLineEndListRef pLineEndList;
+
+ PresentationObjects ePO;
+
+ virtual void PageCreated(const OString& rId, SfxTabPage &rPage) override;
+
+ // for mapping with the new SvxNumBulletItem
+ SfxItemSet aInputSet;
+ std::unique_ptr<SfxItemSet> pOutSet;
+
+ sal_uInt16 GetOutlineLevel() const;
+
+public:
+ SdPresLayoutTemplateDlg(SfxObjectShell const * pDocSh, weld::Window* pParent, bool bBackground, SfxStyleSheetBase& rStyleBase, PresentationObjects ePO, SfxStyleSheetBasePool* pSSPool);
+ virtual ~SdPresLayoutTemplateDlg() override;
+
+ const SfxItemSet* GetOutputItemSet() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/prntopts.hxx b/sd/source/ui/inc/prntopts.hxx
new file mode 100644
index 000000000..51c3a3603
--- /dev/null
+++ b/sd/source/ui/inc/prntopts.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+
+class SdPrintOptions final : public SfxTabPage
+{
+ friend class SdModule;
+
+private:
+ std::unique_ptr<weld::Frame> m_xFrmContent;
+ std::unique_ptr<weld::CheckButton> m_xCbxDraw;
+ std::unique_ptr<weld::CheckButton> m_xCbxNotes;
+ std::unique_ptr<weld::CheckButton> m_xCbxHandout;
+ std::unique_ptr<weld::CheckButton> m_xCbxOutline;
+ std::unique_ptr<weld::RadioButton> m_xRbtColor;
+ std::unique_ptr<weld::RadioButton> m_xRbtGrayscale;
+ std::unique_ptr<weld::RadioButton> m_xRbtBlackWhite;
+ std::unique_ptr<weld::CheckButton> m_xCbxPagename;
+ std::unique_ptr<weld::CheckButton> m_xCbxDate;
+ std::unique_ptr<weld::CheckButton> m_xCbxTime;
+ std::unique_ptr<weld::CheckButton> m_xCbxHiddenPages;
+ std::unique_ptr<weld::RadioButton> m_xRbtDefault;
+ std::unique_ptr<weld::RadioButton> m_xRbtPagesize;
+ std::unique_ptr<weld::RadioButton> m_xRbtPagetile;
+ std::unique_ptr<weld::RadioButton> m_xRbtBooklet;
+ std::unique_ptr<weld::CheckButton> m_xCbxFront;
+ std::unique_ptr<weld::CheckButton> m_xCbxBack;
+ std::unique_ptr<weld::CheckButton> m_xCbxPaperbin;
+
+ DECL_LINK(ClickCheckboxHdl, weld::Toggleable&, void);
+ DECL_LINK(ClickBookletHdl, weld::Toggleable&, void);
+
+ void updateControls();
+
+public:
+ SdPrintOptions(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& rInAttrs);
+ virtual ~SdPrintOptions() override;
+
+ static std::unique_ptr<SfxTabPage>
+ Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet*);
+
+ virtual bool FillItemSet(SfxItemSet*) override;
+ virtual void Reset(const SfxItemSet*) override;
+
+ void SetDrawMode();
+ virtual void PageCreated(const SfxAllItemSet& aSet) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/pubdlg.hxx b/sd/source/ui/inc/pubdlg.hxx
new file mode 100644
index 000000000..1f0b7274c
--- /dev/null
+++ b/sd/source/ui/inc/pubdlg.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <svtools/valueset.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+#include <pres.hxx>
+#include "assclass.hxx"
+
+#include <memory>
+#include <vector>
+
+class ListBox;
+class Edit;
+class SdHtmlAttrPreview;
+class SdPublishingDesign;
+class ButtonSet;
+
+namespace com::sun::star::beans
+{
+struct PropertyValue;
+}
+namespace com::sun::star::uno
+{
+template <class E> class Sequence;
+}
+
+// *********************************************************************
+// Html-Export Autopilot
+// *********************************************************************
+// should turn this into a wizard
+class SdPublishingDlg final : public weld::GenericDialogController
+{
+private:
+ // page 1 controls
+ std::unique_ptr<weld::Container> m_xPage1;
+ std::unique_ptr<weld::Label> m_xPage1_Title;
+ std::unique_ptr<weld::RadioButton> m_xPage1_NewDesign;
+ std::unique_ptr<weld::RadioButton> m_xPage1_OldDesign;
+ std::unique_ptr<weld::TreeView> m_xPage1_Designs;
+ std::unique_ptr<weld::Button> m_xPage1_DelDesign;
+ std::unique_ptr<weld::Label> m_xPage1_Desc;
+
+ // page 2 controls
+ std::unique_ptr<weld::Container> m_xPage2;
+ std::unique_ptr<weld::Container> m_xPage2Frame2;
+ std::unique_ptr<weld::Container> m_xPage2Frame3;
+ std::unique_ptr<weld::Container> m_xPage2Frame4;
+ std::unique_ptr<weld::Label> m_xPage2_Title;
+ std::unique_ptr<weld::RadioButton> m_xPage2_Standard;
+ std::unique_ptr<weld::RadioButton> m_xPage2_Frames;
+ std::unique_ptr<weld::RadioButton> m_xPage2_SingleDocument;
+ std::unique_ptr<weld::RadioButton> m_xPage2_Kiosk;
+ std::unique_ptr<weld::RadioButton> m_xPage2_WebCast;
+ std::unique_ptr<weld::Image> m_xPage2_Standard_FB;
+ std::unique_ptr<weld::Image> m_xPage2_Frames_FB;
+ std::unique_ptr<weld::Image> m_xPage2_Kiosk_FB;
+ std::unique_ptr<weld::Image> m_xPage2_WebCast_FB;
+
+ std::unique_ptr<weld::Label> m_xPage2_Title_Html;
+ std::unique_ptr<weld::CheckButton> m_xPage2_Content;
+ std::unique_ptr<weld::CheckButton> m_xPage2_Notes;
+
+ std::unique_ptr<weld::Label> m_xPage2_Title_WebCast;
+ std::unique_ptr<weld::RadioButton> m_xPage2_ASP;
+ std::unique_ptr<weld::RadioButton> m_xPage2_PERL;
+ std::unique_ptr<weld::Label> m_xPage2_URL_txt;
+ std::unique_ptr<weld::Entry> m_xPage2_URL;
+ std::unique_ptr<weld::Label> m_xPage2_CGI_txt;
+ std::unique_ptr<weld::Entry> m_xPage2_CGI;
+ std::unique_ptr<weld::Label> m_xPage2_Index_txt;
+ std::unique_ptr<weld::Entry> m_xPage2_Index;
+ std::unique_ptr<weld::Label> m_xPage2_Title_Kiosk;
+ std::unique_ptr<weld::RadioButton> m_xPage2_ChgDefault;
+ std::unique_ptr<weld::RadioButton> m_xPage2_ChgAuto;
+ std::unique_ptr<weld::Label> m_xPage2_Duration_txt;
+ std::unique_ptr<weld::FormattedSpinButton> m_xPage2_Duration;
+ std::unique_ptr<weld::TimeFormatter> m_xFormatter;
+ std::unique_ptr<weld::CheckButton> m_xPage2_Endless;
+
+ // page 3 controls
+ std::unique_ptr<weld::Container> m_xPage3;
+ std::unique_ptr<weld::Label> m_xPage3_Title1;
+ std::unique_ptr<weld::RadioButton> m_xPage3_Png;
+ std::unique_ptr<weld::RadioButton> m_xPage3_Gif;
+ std::unique_ptr<weld::RadioButton> m_xPage3_Jpg;
+ std::unique_ptr<weld::Label> m_xPage3_Quality_txt;
+ std::unique_ptr<weld::ComboBox> m_xPage3_Quality;
+ std::unique_ptr<weld::Label> m_xPage3_Title2;
+ std::unique_ptr<weld::RadioButton> m_xPage3_Resolution_1;
+ std::unique_ptr<weld::RadioButton> m_xPage3_Resolution_2;
+ std::unique_ptr<weld::RadioButton> m_xPage3_Resolution_3;
+ std::unique_ptr<weld::RadioButton> m_xPage3_Resolution_4;
+ std::unique_ptr<weld::Label> m_xPage3_Title3;
+ std::unique_ptr<weld::CheckButton> m_xPage3_SldSound;
+ std::unique_ptr<weld::CheckButton> m_xPage3_HiddenSlides;
+
+ // page 4 controls
+ std::unique_ptr<weld::Container> m_xPage4;
+ std::unique_ptr<weld::Label> m_xPage4_Title1;
+ std::unique_ptr<weld::Label> m_xPage4_Author_txt;
+ std::unique_ptr<weld::Entry> m_xPage4_Author;
+ std::unique_ptr<weld::Label> m_xPage4_Email_txt;
+ std::unique_ptr<weld::Entry> m_xPage4_Email;
+ std::unique_ptr<weld::Label> m_xPage4_WWW_txt;
+ std::unique_ptr<weld::Entry> m_xPage4_WWW;
+ std::unique_ptr<weld::Label> m_xPage4_Title2;
+ std::unique_ptr<weld::TextView> m_xPage4_Misc;
+ std::unique_ptr<weld::CheckButton> m_xPage4_Download;
+
+ // page 5 controls
+ std::unique_ptr<weld::Container> m_xPage5;
+ std::unique_ptr<weld::Label> m_xPage5_Title;
+ std::unique_ptr<weld::CheckButton> m_xPage5_TextOnly;
+ std::unique_ptr<ValueSet> m_xPage5_Buttons;
+ std::unique_ptr<weld::CustomWeld> m_xPage5_ButtonsWnd;
+
+ // page 6 controls
+ std::unique_ptr<weld::Container> m_xPage6;
+ std::unique_ptr<weld::Label> m_xPage6_Title;
+ std::unique_ptr<weld::RadioButton> m_xPage6_Default;
+ std::unique_ptr<weld::RadioButton> m_xPage6_User;
+ std::unique_ptr<weld::Button> m_xPage6_Back;
+ std::unique_ptr<weld::Button> m_xPage6_Text;
+ std::unique_ptr<weld::Button> m_xPage6_Link;
+ std::unique_ptr<weld::Button> m_xPage6_VLink;
+ std::unique_ptr<weld::Button> m_xPage6_ALink;
+ std::unique_ptr<weld::RadioButton> m_xPage6_DocColors;
+ std::unique_ptr<SdHtmlAttrPreview> m_xPage6_Preview;
+ std::unique_ptr<weld::CustomWeld> m_xPage6_PreviewWnd;
+
+ std::unique_ptr<ButtonSet> m_xButtonSet;
+
+ // standard controls
+ std::unique_ptr<weld::Button> m_xLastPageButton;
+ std::unique_ptr<weld::Button> m_xNextPageButton;
+ std::unique_ptr<weld::Button> m_xFinishButton;
+
+ Assistent aAssistentFunc;
+
+ bool m_bImpress;
+ bool m_bButtonsDirty;
+
+ void SetDefaults();
+ void CreatePages();
+
+ Color m_aBackColor, m_aTextColor, m_aLinkColor;
+ Color m_aVLinkColor, m_aALinkColor;
+
+ void ChangePage();
+ void UpdatePage();
+
+ std::vector<SdPublishingDesign> m_aDesignList;
+ bool m_bDesignListDirty;
+ SdPublishingDesign* m_pDesign;
+ void Load();
+ bool Save();
+
+ void GetDesign(SdPublishingDesign* pDesign);
+ void SetDesign(SdPublishingDesign const* pDesign);
+
+ void LoadPreviewButtons();
+
+ DECL_LINK(FinishHdl, weld::Button&, void);
+ DECL_LINK(NextPageHdl, weld::Button&, void);
+ DECL_LINK(LastPageHdl, weld::Button&, void);
+
+ DECL_LINK(DesignHdl, weld::Toggleable&, void);
+ DECL_LINK(DesignSelectHdl, weld::TreeView&, void);
+ DECL_LINK(DesignDeleteHdl, weld::Button&, void);
+ DECL_LINK(BaseHdl, weld::Toggleable&, void);
+ DECL_LINK(ContentHdl, weld::Toggleable&, void);
+ DECL_LINK(GfxFormatHdl, weld::Toggleable&, void);
+ DECL_LINK(ResolutionHdl, weld::Toggleable&, void);
+ DECL_LINK(ButtonsHdl, ValueSet*, void);
+ DECL_LINK(ColorHdl, weld::Button&, void);
+ DECL_LINK(WebServerHdl, weld::Toggleable&, void);
+ DECL_LINK(SlideChgHdl, weld::Toggleable&, void);
+
+public:
+ SdPublishingDlg(weld::Window* pWindow, DocumentType eDocType);
+ virtual ~SdPublishingDlg() override;
+
+ void GetParameterSequence(css::uno::Sequence<css::beans::PropertyValue>& rParams);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/registerinterfaces.hxx b/sd/source/ui/inc/registerinterfaces.hxx
new file mode 100644
index 000000000..5a8be7dc0
--- /dev/null
+++ b/sd/source/ui/inc/registerinterfaces.hxx
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <sfx2/module.hxx>
+
+namespace sd::ui::table
+{
+void RegisterInterfaces(const SfxModule* pMod);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/scalectrl.hxx b/sd/source/ui/inc/scalectrl.hxx
new file mode 100644
index 000000000..2a0ed5b28
--- /dev/null
+++ b/sd/source/ui/inc/scalectrl.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/stbitem.hxx>
+
+class SdScaleControl final : public SfxStatusBarControl
+{
+public:
+ SdScaleControl(sal_uInt16 nSlotId, sal_uInt16 nId, StatusBar& rStb);
+ virtual ~SdScaleControl() override;
+
+ virtual void StateChangedAtStatusBarControl(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ SFX_DECL_STATUSBAR_CONTROL();
+
+private:
+ virtual void Command(const CommandEvent& rCEvt) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/sdpopup.hxx b/sd/source/ui/inc/sdpopup.hxx
new file mode 100644
index 000000000..0eccc914d
--- /dev/null
+++ b/sd/source/ui/inc/sdpopup.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <i18nlangtag/lang.h>
+#include <vcl/weld.hxx>
+
+class SvxFieldData;
+
+/**
+ * PopupMenu for editing field-commands
+ */
+class SdFieldPopup
+{
+private:
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Menu> m_xPopup;
+ const SvxFieldData* m_pField;
+
+ void Fill( LanguageType eLanguage );
+
+public:
+ SdFieldPopup(const SvxFieldData* pInField, LanguageType eLanguage);
+ void Execute(weld::Window* pParent, const tools::Rectangle& rRect);
+ ~SdFieldPopup();
+
+ SvxFieldData* GetField();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/sdpreslt.hxx b/sd/source/ui/inc/sdpreslt.hxx
new file mode 100644
index 000000000..77187a0b3
--- /dev/null
+++ b/sd/source/ui/inc/sdpreslt.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <vcl/weld.hxx>
+
+class SfxItemSet;
+class ValueSet;
+namespace weld { class CustomWeld; }
+
+namespace sd {
+class DrawDocShell;
+}
+
+class SdPresLayoutDlg final
+ : public weld::GenericDialogController
+{
+public:
+ SdPresLayoutDlg(
+ ::sd::DrawDocShell* pDocShell,
+ weld::Window* pWindow,
+ const SfxItemSet& rInAttrs);
+ virtual ~SdPresLayoutDlg() override;
+
+ void GetAttr(SfxItemSet& rOutAttrs);
+
+ DECL_LINK(ClickLayoutHdl, ValueSet*, void);
+ DECL_LINK(ClickLoadHdl, weld::Button&, void);
+
+private:
+ ::sd::DrawDocShell* mpDocSh;
+
+ const SfxItemSet& mrOutAttrs;
+
+ std::vector<OUString> maLayoutNames;
+
+ OUString maName; ///< layout name or file name
+ tools::Long mnLayoutCount; ///< number of master pages in the document
+ const OUString maStrNone;
+
+ std::unique_ptr<weld::CheckButton> m_xCbxMasterPage;
+ std::unique_ptr<weld::CheckButton> m_xCbxCheckMasters;
+ std::unique_ptr<weld::Button> m_xBtnLoad;
+ std::unique_ptr<ValueSet> m_xVS;
+ std::unique_ptr<weld::CustomWeld> m_xVSWin;
+
+ void FillValueSet();
+ void Reset();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/sdtreelb.hxx b/sd/source/ui/inc/sdtreelb.hxx
new file mode 100644
index 000000000..ea59ed0b5
--- /dev/null
+++ b/sd/source/ui/inc/sdtreelb.hxx
@@ -0,0 +1,395 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <pres.hxx>
+#include <sddllapi.h>
+#include <vcl/weld.hxx>
+#include <svl/urlbmk.hxx>
+#include <tools/ref.hxx>
+#include "sdxfer.hxx"
+#include <memory>
+#include <vector>
+
+class SdDrawDocument;
+class SfxMedium;
+class SfxViewFrame;
+class SdNavigatorWin;
+class SdrObject;
+class SdrObjList;
+class SdPage;
+struct ImplSVEvent;
+
+namespace sd {
+class ViewShell;
+
+class DrawDocShell;
+#ifndef SV_DECL_DRAW_DOC_SHELL_DEFINED
+#define SV_DECL_DRAW_DOC_SHELL_DEFINED
+typedef ::tools::SvRef<DrawDocShell> DrawDocShellRef;
+#endif
+}
+namespace svt {
+ class AcceleratorExecute;
+}
+
+class SdPageObjsTLVDropTarget final : public DropTargetHelper
+{
+private:
+ weld::TreeView& m_rTreeView;
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+public:
+ SdPageObjsTLVDropTarget(weld::TreeView& rTreeView);
+};
+
+class SD_DLLPUBLIC SdPageObjsTLV
+{
+private:
+ static bool SAL_DLLPRIVATE bIsInDrag; ///< static, in the case the navigator is deleted in ExecuteDrag
+
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+ std::unique_ptr<weld::TreeIter> m_xScratchIter;
+ std::unique_ptr<SdPageObjsTLVDropTarget> m_xDropTargetHelper;
+ std::unique_ptr<::svt::AcceleratorExecute> m_xAccel;
+ SdNavigatorWin* m_pNavigator;
+ const SdDrawDocument* m_pDoc;
+ SdDrawDocument* m_pBookmarkDoc;
+ SfxMedium* m_pMedium;
+ SfxMedium* m_pOwnMedium;
+ bool m_bLinkableSelected;
+ bool m_bShowAllShapes;
+
+ /** This flag controls whether to show all pages.
+ */
+ bool m_bShowAllPages;
+
+ /**
+ * If changing the selection should also result in navigating to the
+ * relevant shape.
+ */
+ bool m_bSelectionHandlerNavigates;
+
+ /**
+ * If navigation should not only select the relevant shape but also change
+ * focus to it.
+ */
+ bool m_bNavigationGrabsFocus;
+
+ SelectionMode m_eSelectionMode;
+
+ ImplSVEvent* m_nSelectEventId;
+ ImplSVEvent* m_nRowActivateEventId;
+
+ OUString m_aDocName;
+ ::sd::DrawDocShellRef m_xBookmarkDocShRef; ///< for the loading of bookmarks
+ Link<weld::TreeView&, void> m_aChangeHdl;
+ Link<weld::TreeView&, bool> m_aRowActivatedHdl;
+ Link<const KeyEvent&, bool> m_aKeyPressHdl;
+
+ /** Return the name of the object. When the object has no user supplied
+ name and the bCreate flag is <TRUE/> then a name is created
+ automatically. Additionally the mbShowAllShapes flag is taken into
+ account when there is no user supplied name. When this flag is
+ <FALSE/> then no name is created.
+ @param pObject
+ When this is NULL then an empty string is returned, regardless
+ of the value of bCreate.
+ @param bCreate
+ This flag controls for objects without user supplied name
+ whether a name is created. When a name is created then this
+ name is not stored in the object.
+ */
+ OUString GetObjectName (
+ const SdrObject* pObject,
+ const bool bCreate = true) const;
+
+ void CloseBookmarkDoc();
+
+ DECL_DLLPRIVATE_LINK(RequestingChildrenHdl, const weld::TreeIter&, bool);
+ DECL_DLLPRIVATE_LINK(SelectHdl, weld::TreeView&, void);
+ DECL_DLLPRIVATE_LINK(AsyncSelectHdl, void*, void);
+ DECL_DLLPRIVATE_LINK(RowActivatedHdl, weld::TreeView&, bool);
+ DECL_DLLPRIVATE_LINK(AsyncRowActivatedHdl, void*, void);
+ DECL_DLLPRIVATE_LINK(DragBeginHdl, bool&, bool);
+ DECL_DLLPRIVATE_LINK(KeyInputHdl, const KeyEvent&, bool);
+
+ /** Determine whether the specified page belongs to the current show
+ which is either the standard show or a custom show.
+ @param pPage
+ Pointer to the page for which to check whether it belongs to the
+ show.
+ @return
+ Returns <FALSE/> if there is no custom show or if the current
+ show does not contain the specified page at least once.
+ */
+ bool PageBelongsToCurrentShow (const SdPage* pPage) const;
+
+ bool DoDrag();
+ static void OnDragFinished();
+
+ // DragSourceHelper
+ bool StartDrag();
+
+public:
+
+ SdPageObjsTLV(std::unique_ptr<weld::TreeView> xTreeview);
+ ~SdPageObjsTLV();
+
+ void set_sensitive(bool bSensitive)
+ {
+ m_xTreeView->set_sensitive(bSensitive);
+ }
+
+ void hide()
+ {
+ m_xTreeView->hide();
+ }
+
+ void show()
+ {
+ m_xTreeView->show();
+ }
+
+ void grab_focus()
+ {
+ m_xTreeView->grab_focus();
+ }
+
+ void set_size_request(int nWidth, int nHeight)
+ {
+ m_xTreeView->set_size_request(nWidth, nHeight);
+ }
+
+ float get_approximate_digit_width() const
+ {
+ return m_xTreeView->get_approximate_digit_width();
+ }
+
+ DECL_LINK(MousePressHdl, const MouseEvent&, bool);
+ DECL_LINK(MouseReleaseHdl, const MouseEvent&, bool);
+
+ void Select();
+
+ int get_height_rows(int nRows) const
+ {
+ return m_xTreeView->get_height_rows(nRows);
+ }
+
+ void set_selection_mode(SelectionMode eMode)
+ {
+ m_eSelectionMode = eMode;
+ m_xTreeView->set_selection_mode(eMode);
+ }
+
+ SelectionMode get_selection_mode() const
+ {
+ return m_eSelectionMode;
+ }
+
+ void connect_row_activated(const Link<weld::TreeView&, bool>& rLink)
+ {
+ m_aRowActivatedHdl = rLink;
+ }
+
+ void connect_key_press(const Link<const KeyEvent&, bool>& rLink)
+ {
+ m_aKeyPressHdl = rLink;
+ }
+
+ bool HasSelectedChildren(std::u16string_view rName);
+ bool SelectEntry(std::u16string_view rName);
+
+ OUString get_selected_text() const
+ {
+ return m_xTreeView->get_selected_text();
+ }
+
+ bool get_selected() const
+ {
+ return m_xTreeView->get_selected(nullptr);
+ }
+
+ int count_selected_rows() const
+ {
+ return m_xTreeView->count_selected_rows();
+ }
+
+ void connect_changed(const Link<weld::TreeView&, void>& rLink)
+ {
+ m_aChangeHdl = rLink;
+ }
+
+ bool is_selected(const weld::TreeIter& rIter) const
+ {
+ return m_xTreeView->is_selected(rIter);
+ }
+
+ bool get_iter_first(weld::TreeIter& rIter) const
+ {
+ return m_xTreeView->get_iter_first(rIter);
+ }
+
+ std::unique_ptr<weld::TreeIter> make_iterator()
+ {
+ return m_xTreeView->make_iterator();
+ }
+
+ bool get_visible() const
+ {
+ return m_xTreeView->get_visible();
+ }
+
+ void unselect_all()
+ {
+ m_xTreeView->unselect_all();
+ }
+
+ void SetViewFrame(const SfxViewFrame* pViewFrame);
+
+ void Fill(const SdDrawDocument*, bool bAllPages, const OUString& rDocName);
+ void Fill(const SdDrawDocument*, SfxMedium* pSfxMedium, const OUString& rDocName);
+
+ void SetShowAllShapes (const bool bShowAllShapes, const bool bFill);
+ bool GetShowAllShapes() const { return m_bShowAllShapes; }
+
+ bool IsNavigationGrabsFocus() const { return m_bNavigationGrabsFocus; }
+ bool IsEqualToDoc(const SdDrawDocument* pInDoc);
+ /// Visits rList recursively and tries to advance rEntry accordingly.
+ bool IsEqualToShapeList(std::unique_ptr<weld::TreeIter>& rEntry, const SdrObjList& rList,
+ std::u16string_view rListName);
+
+ static bool IsInDrag();
+
+ /** Return the view shell that is linked to the given doc shell.
+ Call this method when the there is a chance that the doc shell
+ has been disconnected from the view shell (but not the other
+ way round.)
+ @return
+ May return <NULL/> when the link between view shell and
+ doc shell has been severed.
+ */
+ static ::sd::ViewShell* GetViewShellForDocShell (::sd::DrawDocShell &rDocShell);
+
+ /** Add one list box entry for the parent of the given shapes and one child entry for
+ each of the given shapes.
+ @param rList
+ The container of shapes that are to be inserted.
+ @param pShape
+ The parent shape or NULL when the parent is a page.
+ @param rsName
+ The name to be displayed for the new parent node.
+ @param bIsExcluded
+ Some pages can be excluded (from the show?).
+ @param pParentEntry
+ The parent entry of the new parent entry.
+ */
+ void AddShapeList (
+ const SdrObjList& rList,
+ const SdrObject* pShape,
+ const OUString& rsName,
+ const bool bIsExcluded,
+ const weld::TreeIter* pParentEntry);
+
+ /** Add the given object to a transferable object so that the object can
+ be dragged and dropped without having a name.
+ */
+ void AddShapeToTransferable (
+ SdTransferable& rTransferable,
+ const SdrObject& rObject) const;
+
+ /** return selected entries
+ nDepth == 0 -> pages
+ nDepth == 1 -> objects */
+
+ std::vector<OUString> GetSelectEntryList(const int nDepth) const;
+
+ SdDrawDocument* GetBookmarkDoc(SfxMedium* pMedium = nullptr);
+
+ bool IsLinkableSelected() const { return m_bLinkableSelected; }
+
+ void InsertEntry(const OUString &rName, const OUString &rExpander)
+ {
+ m_xTreeView->insert(nullptr, -1, &rName, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
+ m_xTreeView->set_image(*m_xScratchIter, rExpander);
+ }
+
+ void InsertEntry(const weld::TreeIter* pParent, const OUString& rId, const OUString &rName, const OUString &rExpander, weld::TreeIter* pEntry = nullptr)
+ {
+ m_xTreeView->insert(pParent, -1, &rName, &rId, nullptr, nullptr, false, m_xScratchIter.get());
+ m_xTreeView->set_image(*m_xScratchIter, rExpander);
+ if (pEntry)
+ m_xTreeView->copy_iterator(*m_xScratchIter, *pEntry);
+ }
+
+ //Mark Current Entry
+ void SetSdNavigator(SdNavigatorWin* pNavigator);
+
+ void clear()
+ {
+ m_xTreeView->clear();
+ }
+
+ // nested class to implement the TransferableHelper
+ class SAL_DLLPRIVATE SdPageObjsTransferable final : public SdTransferable
+ {
+ public:
+ SdPageObjsTransferable(
+ const INetBookmark& rBookmark,
+ ::sd::DrawDocShell& rDocShell,
+ NavigatorDragType eDragType );
+ ::sd::DrawDocShell& GetDocShell() const { return mrDocShell;}
+ NavigatorDragType GetDragType() const { return meDragType;}
+
+ static const css::uno::Sequence< sal_Int8 >& getUnoTunnelId();
+ static SdPageObjsTransferable* getImplementation( const css::uno::Reference< css::uno::XInterface >& rxData ) noexcept;
+ /** Return a temporary transferable data flavor that is used
+ internally in the navigator for reordering entries. Its
+ lifetime ends with the office application.
+ */
+ static SotClipboardFormatId GetListBoxDropFormatId();
+
+ private:
+ /** Temporary drop flavor id that is used internally in the
+ navigator.
+ */
+ static SotClipboardFormatId mnListBoxDropFormatId;
+
+ INetBookmark const maBookmark;
+ ::sd::DrawDocShell& mrDocShell;
+ NavigatorDragType const meDragType;
+ virtual ~SdPageObjsTransferable() override;
+
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ virtual void DragFinished( sal_Int8 nDropAction ) override;
+
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& rId ) override;
+ };
+
+ friend class SdPageObjsTLV::SdPageObjsTransferable;
+
+private:
+ rtl::Reference<SdPageObjsTransferable> m_xHelper;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/sdundogr.hxx b/sd/source/ui/inc/sdundogr.hxx
new file mode 100644
index 000000000..466182faf
--- /dev/null
+++ b/sd/source/ui/inc/sdundogr.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdundo.hxx>
+#include <sddllapi.h>
+
+#include <memory>
+#include <vector>
+
+class SD_DLLPUBLIC SdUndoGroup final : public SdUndoAction
+{
+ std::vector<std::unique_ptr<SdUndoAction>> aCtn;
+public:
+ SdUndoGroup(SdDrawDocument* pSdDrawDocument)
+ : SdUndoAction(pSdDrawDocument)
+ {}
+ virtual ~SdUndoGroup() override;
+
+ virtual bool Merge( SfxUndoAction* pNextAction ) override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+ void AddAction(SdUndoAction* pAction);
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/sdxfer.hxx b/sd/source/ui/inc/sdxfer.hxx
new file mode 100644
index 000000000..5e25ba682
--- /dev/null
+++ b/sd/source/ui/inc/sdxfer.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <vcl/transfer.hxx>
+#include <vcl/vclptr.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/lstner.hxx>
+
+// SdTransferable
+class SdDrawDocument;
+class SdrObject;
+class INetBookmark;
+class ImageMap;
+class VirtualDevice;
+
+namespace sd {
+class DrawDocShell;
+class View;
+}
+
+class SAL_DLLPUBLIC_RTTI SdTransferable : public TransferDataContainer, public SfxListener
+{
+public:
+
+ SdTransferable( SdDrawDocument* pSrcDoc, ::sd::View* pWorkView, bool bInitOnGetData );
+ virtual ~SdTransferable() override;
+
+ void SetDocShell( const SfxObjectShellRef& rRef ) { maDocShellRef = rRef; }
+ const SfxObjectShellRef& GetDocShell() const { return maDocShellRef; }
+
+ void SetWorkDocument( const SdDrawDocument* pWorkDoc ) { mpSdDrawDocument = mpSdDrawDocumentIntern = const_cast<SdDrawDocument*>(pWorkDoc); }
+ const SdDrawDocument* GetWorkDocument() const { return mpSdDrawDocument; }
+
+ void SetView(const ::sd::View* pView);
+ const ::sd::View* GetView() const { return mpSdView; }
+
+ void SetObjectDescriptor( std::unique_ptr<TransferableObjectDescriptor> pObjDesc );
+
+ void SetStartPos( const Point& rStartPos ) { maStartPos = rStartPos; }
+ const Point& GetStartPos() const { return maStartPos; }
+
+ void SetInternalMove( bool bSet ) { mbInternalMove = bSet; }
+ bool IsInternalMove() const { return mbInternalMove; }
+
+ bool HasSourceDoc( const SdDrawDocument* pDoc ) const { return( mpSourceDoc == pDoc ); }
+
+ void SetPageBookmarks( std::vector<OUString>&& rPageBookmarks, bool bPersistent );
+ bool IsPageTransferable() const { return mbPageTransferable; }
+ bool HasPageBookmarks() const { return( mpPageDocShell && ( !maPageBookmarks.empty() ) ); }
+ const std::vector<OUString>& GetPageBookmarks() const { return maPageBookmarks; }
+ ::sd::DrawDocShell* GetPageDocShell() const { return mpPageDocShell; }
+
+ bool SetTableRTF( SdDrawDocument* );
+
+ static const css::uno::Sequence< sal_Int8 >& getUnoTunnelId();
+ static SdTransferable* getImplementation( const css::uno::Reference< css::uno::XInterface >& rxData ) noexcept;
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual void DragFinished( sal_Int8 nDropAction ) override;
+ SdDrawDocument* GetSourceDoc() const { return mpSourceDoc;}
+
+ /** User data objects can be used to store information temporarily
+ at the transferable. The slide sorter uses this to store
+ previews of the slides that are referenced by the
+ transferable.
+ */
+ class UserData {public:virtual~UserData(){}};
+
+ /** Add a user data object. When it was added before (and not
+ removed) then this call is ignored.
+ */
+ void AddUserData (const std::shared_ptr<UserData>& rpData);
+
+ /** Return the number of user data objects.
+ */
+ sal_Int32 GetUserDataCount() const;
+
+ /** Return the specified user data object. When the index is not
+ valid, ie not in the range [0,count) then an empty pointer is
+ returned.
+ */
+ std::shared_ptr<UserData> GetUserData (const sal_Int32 nIndex) const;
+
+ // XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence< sal_Int8 >& rId) override;
+
+protected:
+
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ virtual bool WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& rFlavor ) override;
+ virtual void ObjectReleased() override final;
+
+private:
+
+ SfxObjectShellRef maDocShellRef;
+ ::sd::DrawDocShell* mpPageDocShell;
+ std::vector<OUString> maPageBookmarks;
+ std::unique_ptr<TransferableDataHelper> mpOLEDataHelper;
+ std::unique_ptr<TransferableObjectDescriptor> mpObjDesc;
+ const ::sd::View* mpSdView;
+ ::sd::View* mpSdViewIntern;
+ SdDrawDocument* mpSdDrawDocument;
+ SdDrawDocument* mpSdDrawDocumentIntern;
+ SdDrawDocument* mpSourceDoc;
+ VclPtr<VirtualDevice> mpVDev;
+ std::unique_ptr<INetBookmark> mpBookmark;
+ std::unique_ptr<Graphic> mpGraphic;
+ std::unique_ptr<ImageMap> mpImageMap;
+ ::tools::Rectangle maVisArea;
+ Point maStartPos;
+ bool mbInternalMove : 1;
+ bool mbOwnDocument : 1;
+ bool mbOwnView : 1;
+ bool mbLateInit : 1;
+ bool mbPageTransferable : 1;
+ bool mbPageTransferablePersistent : 1;
+ ::std::vector<std::shared_ptr<UserData> > maUserData;
+
+ SdTransferable( const SdTransferable& ) = delete;
+ SdTransferable& operator=( const SdTransferable& ) = delete;
+
+ void CreateObjectReplacement( SdrObject* pObj );
+ void CreateData();
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/slideshow.hxx b/sd/source/ui/inc/slideshow.hxx
new file mode 100644
index 000000000..35b93afe8
--- /dev/null
+++ b/sd/source/ui/inc/slideshow.hxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/presentation/XPresentation2.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <rtl/ref.hxx>
+
+#include <tools/link.hxx>
+
+#include <comphelper/compbase.hxx>
+
+#include <editeng/unoipset.hxx>
+
+#include <memory>
+#include <sddllapi.h>
+
+namespace com::sun::star {
+ namespace drawing {
+ class XDrawPage;
+ }
+ namespace animations {
+ class XAnimationNode;
+ }
+}
+class SdDrawDocument;
+class KeyEvent;
+class OutputDevice;
+class Size;
+namespace vcl { class Window; }
+class SfxRequest;
+class WorkWindow;
+class CommandSwipeData;
+class CommandLongPressData;
+struct ImplSVEvent;
+
+// TODO: Remove
+#define PAGE_NO_END 65535
+
+/* Definition of SlideShow class */
+
+namespace sd
+{
+
+class SlideshowImpl;
+class View;
+class ViewShell;
+class ViewShellBase;
+struct PresentationSettingsEx;
+class FrameView;
+
+enum AnimationMode
+{
+ ANIMATIONMODE_SHOW,
+ ANIMATIONMODE_PREVIEW
+};
+
+typedef comphelper::WeakComponentImplHelper< css::presentation::XPresentation2, css::lang::XServiceInfo > SlideshowBase;
+
+class SlideShow final : public SlideshowBase
+{
+public:
+ /// used by the model to create a slideshow for it
+ static rtl::Reference< SlideShow > Create( SdDrawDocument* pDoc );
+
+ // static helper api
+ static rtl::Reference< SlideShow > GetSlideShow( SdDrawDocument const * pDocument );
+ static rtl::Reference< SlideShow > GetSlideShow( SdDrawDocument const & rDocument );
+ static rtl::Reference< SlideShow > GetSlideShow( ViewShellBase const & rBase );
+
+ static css::uno::Reference< css::presentation::XSlideShowController > GetSlideShowController(ViewShellBase const & rBase );
+
+ static bool StartPreview( ViewShellBase const & rBase,
+ const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage,
+ const css::uno::Reference< css::animations::XAnimationNode >& xAnimationNode );
+
+ static void Stop( ViewShellBase const & rBase );
+
+ /// returns true if there is a running presentation for the given ViewShellBase
+ static bool IsRunning( ViewShellBase const & rBase );
+
+ /// returns true if there is a running presentation inside the given ViewShell
+ /// returns false even if there is a running presentation but in another ViewShell
+ static bool IsRunning( const ViewShell& rViewShell );
+
+ // helper api
+
+ void startPreview(
+ const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage,
+ const css::uno::Reference< css::animations::XAnimationNode >& xAnimationNode );
+
+ // uno api
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // XPresentation
+ virtual void SAL_CALL start( ) override;
+ virtual void SAL_CALL end() override;
+ virtual void SAL_CALL rehearseTimings( ) override;
+
+ // XPresentation2
+ virtual void SAL_CALL startWithArguments(const css::uno::Sequence< css::beans::PropertyValue >& Arguments) override;
+ virtual sal_Bool SAL_CALL isRunning( ) override;
+ virtual css::uno::Reference< css::presentation::XSlideShowController > SAL_CALL getController( ) override;
+
+ // legacy api
+
+ // actions
+ void jumpToPageNumber( sal_Int32 nPage ); // a.k.a. FuSlideShow::JumpToPage()
+ void jumpToPageIndex( sal_Int32 nIndex );
+ void jumpToBookmark( const OUString& sBookmark ); // a.k.a. FuSlideShow::JumpToBookmark()
+
+ /** sets or clears the pause state of the running slideshow.
+ !!!! This should only be called by the SdShowWindow !!!!*/
+ void pause( bool bPause );
+ bool swipe(const CommandSwipeData &rSwipeData);
+ bool longpress(const CommandLongPressData& rLongPressData);
+
+ // settings
+ bool isFullScreen() const; // a.k.a. FuSlideShow::IsFullScreen()
+ OutputDevice* getShowWindow(); // a.k.a. FuSlideShow::GetShowWindow()
+ int getAnimationMode() const; // a.k.a. FuSlideShow::GetAnimationMode()
+ sal_Int32 getCurrentPageNumber() const; // a.k.a. FuSlideShow::GetCurrentPage()
+
+ // events
+ void resize( const Size &rSize );
+ // return false if the activate failed. callers should call end in response to failure
+ bool activate(ViewShellBase& rBase);
+ void deactivate();
+ void paint();
+
+ bool keyInput(const KeyEvent& rKEvt);
+
+ bool dependsOn( ViewShellBase const * pViewShellBase );
+
+ static sal_Int32 GetDisplay();
+
+ bool IsExitAfterPresenting() const;
+ void SetExitAfterPresenting(bool bExit);
+
+private:
+ SlideShow( SdDrawDocument* pDoc );
+
+ DECL_LINK( StartInPlacePresentationConfigurationHdl, void *, void );
+ void StartInPlacePresentationConfigurationCallback();
+
+ void StartInPlacePresentation();
+ void StartFullscreenPresentation();
+
+ /// @throws css::uno::RuntimeException
+ void ThrowIfDisposed() const;
+
+ void CreateController( ViewShell* pViewSh, ::sd::View* pView, vcl::Window* pParentWindow );
+ WorkWindow *GetWorkWindow();
+
+ SlideShow(const SlideShow&) = delete;
+ SlideShow& operator=( const SlideShow& ) = delete;
+
+ SvxItemPropertySet maPropSet;
+
+ rtl::Reference< SlideshowImpl > mxController;
+ /** This flag is used together with mxController.is() to prevent
+ multiple instances of the slide show for one document. The flag
+ covers the time before mxController is set.
+ */
+ bool mbIsInStartup;
+ SdDrawDocument* mpDoc;
+
+ std::shared_ptr< PresentationSettingsEx > mxCurrentSettings;
+
+ ViewShellBase* mpCurrentViewShellBase;
+ ViewShellBase* mpFullScreenViewShellBase;
+ FrameView* mpFullScreenFrameView;
+ ImplSVEvent * mnInPlaceConfigEvent;
+};
+
+namespace slideshowhelp
+{
+ SD_DLLPUBLIC void ShowSlideShow(SfxRequest const& rReq, SdDrawDocument& rDoc);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/smarttag.hxx b/sd/source/ui/inc/smarttag.hxx
new file mode 100644
index 000000000..6e27979d6
--- /dev/null
+++ b/sd/source/ui/inc/smarttag.hxx
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <helper/simplereferencecomponent.hxx>
+#include <rtl/ref.hxx>
+#include <set>
+#include <svx/svdhdl.hxx>
+#include <svx/svdview.hxx>
+
+class KeyEvent;
+class MouseEvent;
+
+namespace sd
+{
+class View;
+class SmartHdl;
+
+/** a smart tag represents a visual user interface element on the documents edit view
+ that is not part of the document. It uses derivations from SmartHdl for its visuals.
+ A SmartTag adds himself to the given view if created. It removes himself if it
+ is disposed before the view is disposed.
+
+ Derive from this class to implement your own smart tag.
+*/
+class SmartTag : public SimpleReferenceComponent
+{
+ friend class SmartTagSet;
+
+public:
+ explicit SmartTag(::sd::View& rView);
+ virtual ~SmartTag() override;
+
+ /** returns true if the SmartTag consumes this event. */
+ virtual bool MouseButtonDown(const MouseEvent&, SmartHdl&);
+
+ /** returns true if the SmartTag consumes this event. */
+ virtual bool KeyInput(const KeyEvent& rKEvt);
+
+ /** returns true if the SmartTag consumes this event. */
+ virtual bool Command(const CommandEvent& rCEvt);
+
+ /** returns true if this smart tag is currently selected */
+ bool isSelected() const { return mbSelected; }
+
+ ::sd::View& getView() const { return mrView; }
+
+protected:
+ virtual sal_Int32 GetMarkablePointCount() const;
+ virtual sal_Int32 GetMarkedPointCount() const;
+ virtual bool MarkPoint(SdrHdl& rHdl, bool bUnmark);
+ virtual void CheckPossibilities();
+ virtual bool MarkPoints(const ::tools::Rectangle* pRect, bool bUnmark);
+
+ virtual void addCustomHandles(SdrHdlList& rHandlerList);
+ virtual void select();
+ virtual void deselect();
+ virtual bool getContext(SdrViewContext& rContext);
+
+ virtual void disposing() override;
+
+ ::sd::View& mrView;
+ bool mbSelected;
+
+private:
+ SmartTag(const SmartTag&) = delete;
+ SmartTag& operator=(const SmartTag&) = delete;
+};
+
+typedef rtl::Reference<SmartTag> SmartTagReference;
+
+/** class to administrate the available smart tags for a single view. */
+class SmartTagSet
+{
+ friend class SmartTag;
+
+public:
+ explicit SmartTagSet(::sd::View& rView);
+ ~SmartTagSet();
+
+ /** selects the given smart tag and updates all handles */
+ void select(const SmartTagReference& xTag);
+
+ /** deselects the current selected smart tag and updates all handles */
+ void deselect();
+
+ /** returns the currently selected tag or an empty reference. */
+ const SmartTagReference& getSelected() const { return mxSelectedTag; }
+
+ /** returns true if a SmartTag consumes this event. */
+ bool MouseButtonDown(const MouseEvent&);
+
+ /** returns true if a SmartTag consumes this event. */
+ bool KeyInput(const KeyEvent& rKEvt);
+
+ /** returns true if a SmartTag consumes this event. */
+ bool Command(const CommandEvent& rCEvt);
+
+ /** disposes all smart tags and clears the set */
+ void Dispose();
+
+ /** adds the handles from all smart tags to the given list */
+ void addCustomHandles(SdrHdlList& rHandlerList);
+
+ /** returns true if the currently selected smart tag has
+ a special context, returned in rContext. */
+ bool getContext(SdrViewContext& rContext) const;
+
+ // support point editing
+ bool HasMarkablePoints() const;
+ sal_uLong GetMarkablePointCount() const;
+ bool HasMarkedPoints() const;
+ sal_uLong GetMarkedPointCount() const;
+ bool MarkPoint(SdrHdl& rHdl, bool bUnmark);
+ bool MarkPoints(const ::tools::Rectangle* pRect, bool bUnmark);
+
+ void CheckPossibilities();
+
+private:
+ SmartTagSet(const SmartTagSet&) = delete;
+ SmartTagSet& operator=(const SmartTagSet&) = delete;
+
+ /** adds a new smart tag to this set */
+ void add(const SmartTagReference& xTag);
+
+ /** removes the given smart tag from this set */
+ void remove(const SmartTagReference& xTag);
+
+ std::set<SmartTagReference> maSet;
+
+ ::sd::View& mrView;
+ SmartTagReference mxSelectedTag;
+ SmartTagReference mxMouseOverTag;
+};
+
+/** a derivation from this handle is the visual representation for a smart tag.
+ One smart tag can have more than one handle.
+*/
+class SmartHdl : public SdrHdl
+{
+public:
+ SmartHdl(const SmartTagReference& xTag, SdrObject* pObject, const Point& rPnt,
+ SdrHdlKind eNewKind);
+ SmartHdl(const SmartTagReference& xTag, const Point& rPnt, SdrHdlKind eNewKind);
+
+ const SmartTagReference& getTag() const { return mxSmartTag; }
+
+private:
+ SmartTagReference mxSmartTag;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tablefunction.hxx b/sd/source/ui/inc/tablefunction.hxx
new file mode 100644
index 000000000..fe32f16b5
--- /dev/null
+++ b/sd/source/ui/inc/tablefunction.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <tools/stream.hxx>
+#include <drawdoc.hxx>
+
+namespace sd
+{
+void CreateTableFromRTF(SvStream& rStream, SdDrawDocument* pModel);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tabtempl.hxx b/sd/source/ui/inc/tabtempl.hxx
new file mode 100644
index 000000000..d32388d7b
--- /dev/null
+++ b/sd/source/ui/inc/tabtempl.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/styledlg.hxx>
+#include <svx/xtable.hxx>
+
+class SdrModel;
+class SfxObjectShell;
+class SdrView;
+
+/**
+ * Template-Tab-Dialog
+ */
+class SdTabTemplateDlg final : public SfxStyleDialogController
+{
+private:
+ const SfxObjectShell& rDocShell;
+ SdrView* pSdrView;
+
+ XColorListRef pColorList;
+ XGradientListRef pGradientList;
+ XHatchListRef pHatchingList;
+ XBitmapListRef pBitmapList;
+ XPatternListRef pPatternList;
+ XDashListRef pDashList;
+ XLineEndListRef pLineEndList;
+
+ virtual void PageCreated(const OString& rId, SfxTabPage &rPage) override;
+ virtual void RefreshInputSet() override;
+
+public:
+ SdTabTemplateDlg(weld::Window* pParent,
+ const SfxObjectShell* pDocShell,
+ SfxStyleSheetBase& rStyleBase,
+ SdrModel const * pModel,
+ SdrView* pView);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/titledockwin.hxx b/sd/source/ui/inc/titledockwin.hxx
new file mode 100644
index 000000000..59e7e04b3
--- /dev/null
+++ b/sd/source/ui/inc/titledockwin.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/dockwin.hxx>
+#include <tools/svborder.hxx>
+#include <vcl/vclptr.hxx>
+
+class ToolBox;
+
+namespace sd
+{
+ class TitledDockingWindow : public SfxDockingWindow
+ {
+ public:
+ TitledDockingWindow(
+ SfxBindings* i_pBindings, SfxChildWindow* i_pChildWindow,
+ vcl::Window* i_pParent
+ );
+
+ virtual ~TitledDockingWindow() override;
+ virtual void dispose() override;
+
+ /** sets a title to be displayed in the docking window
+ */
+ void SetTitle( const OUString& i_rTitle );
+
+ /** returns the content window, which is to be used as parent window for any content to be displayed
+ in the docking window.
+ */
+ vcl::Window& GetContentWindow() { return *m_aContentWindow; }
+ const vcl::Window& GetContentWindow() const { return *m_aContentWindow; }
+
+ /** Return the border that is painted around the inner window as
+ decoration.
+ */
+ const SvBorder& GetDecorationBorder() const { return m_aBorder; }
+
+ protected:
+ // Window overridables
+ virtual void Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& i_rArea) override;
+ virtual void Resize() override;
+ virtual void StateChanged( StateChangedType i_nType ) override;
+ virtual void DataChanged( const DataChangedEvent& i_rDataChangedEvent ) override;
+ virtual void SetText( const OUString& i_rText ) override;
+
+ virtual void ApplySettings(vcl::RenderContext& rRenderContext) override;
+ protected:
+ /** internal version of ResetToolBox
+ */
+ void impl_resetToolBox();
+
+ private:
+ DECL_LINK(OnToolboxItemSelected, ToolBox*, void);
+
+ void impl_layout();
+
+ private:
+ OUString m_sTitle;
+ VclPtr<ToolBox> m_aToolbox;
+ VclPtr<Window> m_aContentWindow;
+
+ /** The border that is painted around the inner window. The bevel
+ shadow lines are part of the border, so where the border is 0 no
+ such line is painted.
+ */
+ SvBorder m_aBorder;
+
+ /** Height of the title bar. Calculated in impl_layout().
+ */
+ int m_nTitleBarHeight;
+
+ };
+
+} // namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tmplctrl.hxx b/sd/source/ui/inc/tmplctrl.hxx
new file mode 100644
index 000000000..bdf6eed86
--- /dev/null
+++ b/sd/source/ui/inc/tmplctrl.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sfx2/stbitem.hxx>
+
+class SdTemplateControl final : public SfxStatusBarControl
+{
+public:
+ SdTemplateControl( sal_uInt16 nSlotId, sal_uInt16 nId, StatusBar& rStb );
+ virtual ~SdTemplateControl() override;
+
+ virtual void StateChangedAtStatusBarControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) override;
+ virtual void Paint( const UserDrawEvent& rEvt ) override;
+
+ SFX_DECL_STATUSBAR_CONTROL();
+
+private:
+ virtual void Command( const CommandEvent& rCEvt ) override;
+
+ OUString msTemplate;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tools/AsynchronousCall.hxx b/sd/source/ui/inc/tools/AsynchronousCall.hxx
new file mode 100644
index 000000000..fa4c18020
--- /dev/null
+++ b/sd/source/ui/inc/tools/AsynchronousCall.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/timer.hxx>
+
+#include <memory>
+#include <functional>
+
+namespace sd::tools
+{
+/** Store a function object and execute it asynchronous.
+
+ The features of this class are:
+ a) It provides a wrapper around a VCL Timer so that generic function
+ objects can be used.
+ b) When more than one function objects are posted to be executed later
+ then the pending ones are erased and only the last one will actually be
+ executed.
+
+ Use this class like this:
+ aInstanceOfAsynchronousCall.Post(
+ ::std::bind(
+ ::std::mem_fun(&DrawViewShell::SwitchPage),
+ pDrawViewShell,
+ 11));
+*/
+class AsynchronousCall
+{
+public:
+ /** Create a new asynchronous call. Each object of this class processes
+ one (semantical) type of call.
+ */
+ AsynchronousCall();
+
+ ~AsynchronousCall();
+
+ /** Post a function object that is to be executed asynchronously. When
+ this method is called while the current function object has not been
+ executed then the latter is destroyed and only the given function
+ object will be executed.
+ @param rFunction
+ The function object that may be called asynchronously in the
+ near future.
+ */
+ typedef ::std::function<void()> AsynchronousFunction;
+ void Post(const AsynchronousFunction& rFunction);
+
+private:
+ Timer maTimer;
+ /** The function object that will be executed when the TimerCallback
+ function is called the next time. This pointer may be NULL.
+ */
+ ::std::unique_ptr<AsynchronousFunction> mpFunction;
+ DECL_LINK(TimerCallback, Timer*, void);
+};
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tools/AsynchronousTask.hxx b/sd/source/ui/inc/tools/AsynchronousTask.hxx
new file mode 100644
index 000000000..696423439
--- /dev/null
+++ b/sd/source/ui/inc/tools/AsynchronousTask.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+namespace sd::tools
+{
+/** Interface for the asynchronous execution of a task. This interface
+ allows a controller to run the task either timer based with a fixed
+ amount of time between the steps or thread based one step right after
+ the other.
+*/
+class AsynchronousTask
+{
+public:
+ /** Run the next step of the task. After HasNextStep() returns false
+ this method should ignore further calls.
+ */
+ virtual void RunNextStep() = 0;
+
+ /** Return <TRUE/> when there is at least one more step to execute.
+ When the task has been executed completely then <FALSE/> is
+ returned.
+ */
+ virtual bool HasNextStep() = 0;
+
+protected:
+ ~AsynchronousTask() {}
+};
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tools/ConfigurationAccess.hxx b/sd/source/ui/inc/tools/ConfigurationAccess.hxx
new file mode 100644
index 000000000..b86a30fff
--- /dev/null
+++ b/sd/source/ui/inc/tools/ConfigurationAccess.hxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/uno/XInterface.hpp>
+
+#include <vector>
+#include <functional>
+
+namespace com::sun::star::container { class XHierarchicalNameAccess; }
+namespace com::sun::star::container { class XNameAccess; }
+namespace com::sun::star::lang { class XMultiServiceFactory; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace sd::tools {
+
+/** This class gives access to the configuration. Create an object of this
+ class for one node of the configuration. This will be the root node.
+ Its children are then accessible through the new ConfigurationAccess
+ object.
+*/
+class ConfigurationAccess
+{
+public:
+ enum WriteMode { READ_WRITE, READ_ONLY };
+
+ /** Create a new object to access the configuration entries below the
+ given root.
+ @param rsRootName
+ Name of the root.
+ @param eMode
+ This flag specifies whether to give read-write or read-only
+ access.
+ */
+ ConfigurationAccess(
+ const OUString& rsRootName,
+ const WriteMode eMode);
+
+ ConfigurationAccess(
+ const css::uno::Reference<css::uno::XComponentContext>& rxContext,
+ const OUString& rsRootName,
+ const WriteMode eMode);
+
+ /** Return a configuration node below the root of the called object.
+ @param rsPathToNode
+ The relative path from the root (as given the constructor) to
+ the node.
+ @return
+ The type of the returned node varies with the requested node.
+ It is empty when the node was not found.
+ */
+ css::uno::Any GetConfigurationNode (
+ const OUString& rsPathToNode);
+
+ /** Return a configuration node below the given node.
+ @param rxNode
+ The node that acts as root to the given relative path.
+ @param rsPathToNode
+ The relative path from the given node to the requested node.
+ @return
+ The type of the returned node varies with the requested node.
+ It is empty when the node was not found.
+ */
+ static css::uno::Any GetConfigurationNode (
+ const css::uno::Reference<css::container::XHierarchicalNameAccess>& rxNode,
+ const OUString& rsPathToNode);
+
+ /** Write any changes that have been made back to the configuration.
+ This call is ignored when the called ConfigurationAccess object was
+ not create with read-write mode.
+ */
+ void CommitChanges();
+
+ /** This functor is typically called for every item in a set. Its two
+ parameters are the name of key item (often of no further interest)
+ and the value of the item.
+ */
+ typedef ::std::function<void (
+ const OUString&,
+ const std::vector<css::uno::Any>&) > Functor;
+
+ /** Execute a functor for all elements of the given container.
+ @param rxContainer
+ The container is a XNameAccess to a list of the configuration.
+ This can be a node returned by GetConfigurationNode().
+ @param rArguments
+ The functor is called with arguments that are children of each
+ element of the container. The set of children is specified in this
+ list.
+ @param rFunctor
+ The functor to be executed for some or all of the elements in
+ the given container.
+ */
+ static void ForAll (
+ const css::uno::Reference<css::container::XNameAccess>& rxContainer,
+ const ::std::vector<OUString>& rArguments,
+ const Functor& rFunctor);
+
+ /** Fill a list with the string contents of all sub-elements in the given container.
+ @param rxContainer
+ The container is a XNameAccess to a list of the configuration.
+ This can be a node returned by GetConfigurationNode().
+ @param rsArgument
+ This specifies which string children of the elements in the
+ container are to be inserted into the list. The specified child
+ has to be of type string.
+ @param rList
+ The list to be filled.
+ */
+ static void FillList(
+ const css::uno::Reference<css::container::XNameAccess>& rxContainer,
+ const OUString& rsArgument,
+ ::std::vector<OUString>& rList);
+
+private:
+ css::uno::Reference<css::uno::XInterface> mxRoot;
+
+ void Initialize (
+ const css::uno::Reference<css::lang::XMultiServiceFactory>& rxProvider,
+ const OUString& rsRootName,
+ const WriteMode eMode);
+};
+
+} // end of namespace sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tools/GraphicSizeCheck.hxx b/sd/source/ui/inc/tools/GraphicSizeCheck.hxx
new file mode 100644
index 000000000..44f78e4eb
--- /dev/null
+++ b/sd/source/ui/inc/tools/GraphicSizeCheck.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#pragma once
+
+#include <memory>
+#include <drawdoc.hxx>
+#include <svx/GenericCheckDialog.hxx>
+#include <svx/svdograf.hxx>
+
+namespace sd
+{
+/**
+ * Class responsible to check if a graphic object violates the size
+ * constraints and store the results.
+ */
+class GraphicSizeViolation final
+{
+private:
+ SdrGrafObj* m_pGraphicObject;
+
+ sal_Int32 m_nLowDPILimit = 0;
+ sal_Int32 m_nHighDPILimit = 0;
+
+ sal_Int32 m_nDPIX = 0;
+ sal_Int32 m_nDPIY = 0;
+
+public:
+ GraphicSizeViolation(sal_Int32 nDPI, SdrGrafObj* pGraphicObject);
+ bool check();
+
+ const OUString& getGraphicName();
+
+ SdrGrafObj* getObject() const { return m_pGraphicObject; }
+
+ bool isDPITooLow() { return m_nDPIX < m_nLowDPILimit || m_nDPIY < m_nLowDPILimit; }
+
+ bool isDPITooHigh() { return m_nDPIX > m_nHighDPILimit || m_nDPIY > m_nHighDPILimit; }
+
+ sal_Int32 getDPIX() { return m_nDPIX; }
+
+ sal_Int32 getDPIY() { return m_nDPIY; }
+};
+
+/**
+ * Run the graphic size checks for all the graphic objects in the DOM
+ * and store a list of violations.
+ */
+class GraphicSizeCheck final
+{
+private:
+ SdDrawDocument* m_pDocument;
+ std::vector<std::unique_ptr<GraphicSizeViolation>> m_aGraphicSizeViolationList;
+
+public:
+ GraphicSizeCheck(SdDrawDocument* pDocument)
+ : m_pDocument(pDocument)
+ {
+ }
+
+ void check();
+
+ std::vector<std::unique_ptr<GraphicSizeViolation>>& getViolationList()
+ {
+ return m_aGraphicSizeViolationList;
+ }
+};
+
+/** The UI part of the GraphicSizeViolation used by GenericCheckDialog */
+class GraphicSizeCheckGUIEntry : public svx::CheckData
+{
+private:
+ SdDrawDocument* m_pDocument;
+ std::unique_ptr<GraphicSizeViolation> m_pViolation;
+
+public:
+ GraphicSizeCheckGUIEntry(SdDrawDocument* pDocument,
+ std::unique_ptr<GraphicSizeViolation>&& pViolation)
+ : m_pDocument(pDocument)
+ , m_pViolation(std::move(pViolation))
+ {
+ }
+
+ OUString getText() override;
+
+ bool canMarkObject() override { return true; }
+
+ void markObject() override;
+
+ bool hasProperties() override { return true; }
+
+ void runProperties() override;
+};
+
+/**
+ * The UI part presenting the graphic size check results, which is
+ * used by GenericCheckDialog
+ */
+class GraphicSizeCheckGUIResult : public svx::CheckDataCollection
+{
+public:
+ GraphicSizeCheckGUIResult(SdDrawDocument* m_pDocument);
+
+ OUString getTitle() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tools/IconCache.hxx b/sd/source/ui/inc/tools/IconCache.hxx
new file mode 100644
index 000000000..fef994764
--- /dev/null
+++ b/sd/source/ui/inc/tools/IconCache.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <tools/SdGlobalResourceContainer.hxx>
+#include <vcl/image.hxx>
+
+namespace sd
+{
+/** This simple class stores frequently used icons so that the classes that
+ use the icons do not have to store them in every one of their
+ instances.
+
+ Icons are addressed over their resource id and are loaded on demand.
+
+ This cache acts like a singleton with a lifetime equal to that of the sd
+ module.
+*/
+class IconCache final : public SdGlobalResource
+{
+public:
+ /** The lifetime of the returned reference is limited to that of the sd
+ module.
+ */
+ static IconCache& Instance();
+
+ /** Return the icon with the given resource id.
+ @return
+ The returned Image may be empty when there is no icon for the
+ given id or an error occurred. Should not happen under normal
+ circumstances.
+ */
+ Image GetIcon(const OUString& rResourceId);
+
+private:
+ class Implementation;
+ ::std::unique_ptr<Implementation> mpImpl;
+
+ /** The constructor creates the one instance of the cache and registers
+ it at the SdGlobalResourceContainer to limit is lifetime to that of
+ the sd module.
+ */
+ IconCache();
+
+ /** This destructor is called by SdGlobalResourceContainer.
+ */
+ virtual ~IconCache() override;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tools/IdleDetection.hxx b/sd/source/ui/inc/tools/IdleDetection.hxx
new file mode 100644
index 000000000..decf5ff26
--- /dev/null
+++ b/sd/source/ui/inc/tools/IdleDetection.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <o3tl/typed_flags_set.hxx>
+
+namespace vcl { class Window; }
+
+namespace sd::tools {
+ enum class IdleState {
+ /** When GetIdleState() returns this value, then the system is idle.
+ */
+ Idle = 0x0000,
+
+ /** There are system event pending.
+ */
+ SystemEventPending = 0x0001,
+
+ /** A full screen slide show is running and is active. In contrast
+ there may be a full screen show be running in an inactive window,
+ i.e. in the background.
+ */
+ FullScreenShowActive = 0x0002,
+
+ /** A slide show is running in a window.
+ */
+ WindowShowActive = 0x0004,
+
+ /** A window is being painted.
+ */
+ WindowPainting = 0x0008,
+ };
+} // end of namespace ::sd::tools
+namespace o3tl {
+ template<> struct typed_flags<::sd::tools::IdleState> : is_typed_flags<::sd::tools::IdleState, 0x0f> {};
+}
+
+namespace sd::tools {
+
+/** Detect whether the system is idle and some time consuming operation may
+ be carried out. This class distinguishes between different states of
+ idle-ness.
+*/
+class IdleDetection
+{
+public:
+ /** Determine whether the system is idle.
+ @param pWindow
+ When a valid Window pointer is given then it is checked
+ whether the window is currently being painting.
+ @return
+ This method either returns IdleState::Idle or a combination of
+ IdleStates values or-ed together that describe what the system
+ is currently doing so that the caller can decide what to do.
+ */
+ static IdleState GetIdleState (const vcl::Window* pWindow);
+
+private:
+ /** Check whether there are input events pending.
+ */
+ static IdleState CheckInputPending();
+
+ /** Check whether a slide show is running full screen or in a window.
+ */
+ static IdleState CheckSlideShowRunning();
+
+ static IdleState CheckWindowPainting (const vcl::Window& rWindow);
+};
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tools/PropertySet.hxx b/sd/source/ui/inc/tools/PropertySet.hxx
new file mode 100644
index 000000000..c432783da
--- /dev/null
+++ b/sd/source/ui/inc/tools/PropertySet.hxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <map>
+#include <memory>
+
+namespace sd::tools {
+
+typedef ::cppu::WeakComponentImplHelper <
+ css::beans::XPropertySet
+> PropertySetInterfaceBase;
+
+/** A very simple implementation of the XPropertySet interface. It does not
+ support constrained properties and thus does not support vetoable
+ listeners. It does not support the optional property set info.
+
+ In order to use it you have to derive from this class and implement the
+ GetPropertyValue() and SetPropertyValue() methods.
+*/
+class PropertySet
+ : protected ::cppu::BaseMutex,
+ public PropertySetInterfaceBase
+{
+public:
+ explicit PropertySet();
+ virtual ~PropertySet() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ // XPropertySet
+
+ virtual css::uno::Reference<css::beans::XPropertySetInfo>
+ SAL_CALL getPropertySetInfo() override;
+
+ virtual void SAL_CALL setPropertyValue (
+ const OUString& rsPropertyName,
+ const css::uno::Any& rsPropertyValue) override;
+
+ virtual css::uno::Any SAL_CALL getPropertyValue (const OUString& rsPropertyName) override;
+
+ virtual void SAL_CALL addPropertyChangeListener (
+ const OUString& rsPropertyName,
+ const css::uno::Reference<css::beans::XPropertyChangeListener>& rxListener) override;
+
+ virtual void SAL_CALL removePropertyChangeListener (
+ const OUString& rsPropertyName,
+ const css::uno::Reference<css::beans::XPropertyChangeListener>& rxListener) override;
+
+ virtual void SAL_CALL addVetoableChangeListener (
+ const OUString& rsPropertyName,
+ const css::uno::Reference<css::beans::XVetoableChangeListener>& rxListener) override;
+
+ virtual void SAL_CALL removeVetoableChangeListener (
+ const OUString& rsPropertyName,
+ const css::uno::Reference<css::beans::XVetoableChangeListener>& rxListener) override;
+
+protected:
+ /** Return the requested property value.
+ @throw css::beans::UnknownPropertyException when the
+ property is not supported.
+ */
+ virtual css::uno::Any GetPropertyValue (const OUString& rsPropertyName) = 0;
+ /** Set the given property value.
+ @return the old value.
+ @throw css::beans::UnknownPropertyException when the
+ property is not supported.
+ */
+ virtual css::uno::Any SetPropertyValue (
+ const OUString& rsPropertyName,
+ const css::uno::Any& rValue) = 0;
+
+private:
+ typedef ::std::multimap<OUString,
+ css::uno::Reference<css::beans::XPropertyChangeListener> > ChangeListenerContainer;
+ std::unique_ptr<ChangeListenerContainer> mpChangeListeners;
+
+ /** Call all listeners that are registered for the given property name.
+ Call this method with an empty property name to call listeners that
+ are registered for all properties.
+ */
+ void CallListeners (
+ const OUString& rsPropertyName,
+ const css::beans::PropertyChangeEvent& rEvent);
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tools/SdGlobalResourceContainer.hxx b/sd/source/ui/inc/tools/SdGlobalResourceContainer.hxx
new file mode 100644
index 000000000..a582ffa72
--- /dev/null
+++ b/sd/source/ui/inc/tools/SdGlobalResourceContainer.hxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <sal/types.h>
+#include <o3tl/deleter.hxx>
+
+namespace com::sun::star::uno
+{
+template <class interface_type> class Reference;
+}
+namespace com::sun::star::uno
+{
+class XInterface;
+}
+
+namespace sd
+{
+class SdGlobalResource
+{
+public:
+ virtual ~SdGlobalResource() COVERITY_NOEXCEPT_FALSE{};
+};
+
+/** The purpose of this container is to hold references to resources that
+ are globally available to all interested objects and to destroy them
+ when the sd module is destroyed. Examples for resources can be
+ containers of bitmaps or the container of master pages used by the
+ MasterPagesSelector objects in the task panel.
+
+ It works like a singleton in that there is one instance per sd module.
+ Resources can be added (by themselves or their owners) to the
+ container. The main task of the container is the destruction of all
+ resources that have been added to it.
+
+ As you may note, there is no method to get a resource from the
+ container. It is the task of the resource to provide other means of
+ access to it.
+
+ The reason for this design is not to have to change the SdModule
+ destructor every time when there is a new resource. This is done by
+ reversing the dependency between module and resource: the resource knows
+ about the module--this container class to be more precisely--and tells
+ it to destroy the resource when the sd module is at the end of its
+ lifetime.
+*/
+class SdGlobalResourceContainer final
+{
+public:
+ static SdGlobalResourceContainer& Instance();
+
+ /** Add a resource to the container. The ownership of the resource is
+ transferred to the container. The resource is destroyed when the
+ container is destroyed, i.e. when the sd module is destroyed.
+
+ When in doubt, use the shared_ptr variant of this method.
+ */
+ void AddResource(::std::unique_ptr<SdGlobalResource> pResource);
+
+ /** Add a resource to the container. By using a shared_ptr and
+ releasing it only when the SgGlobalResourceContainer is destroyed
+ the given resource is kept alive at least that long. When at the
+ time of the destruction of SgGlobalResourceContainer no other
+ references exist the resource is destroyed as well.
+ */
+ void AddResource(const std::shared_ptr<SdGlobalResource>& pResource);
+
+ /** Add a resource that is implemented as UNO object. Destruction
+ (when the sd modules is unloaded) is done by a) calling dispose()
+ when the XComponent is supported and by b) releasing the reference.
+ */
+ void AddResource(const css::uno::Reference<css::uno::XInterface>& rxResource);
+
+private:
+ friend class SdGlobalResourceContainerInstance;
+ friend struct o3tl::default_delete<SdGlobalResourceContainer>;
+
+ class Implementation;
+ ::std::unique_ptr<Implementation> mpImpl;
+
+ SdGlobalResourceContainer();
+ ~SdGlobalResourceContainer();
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tools/SlotStateListener.hxx b/sd/source/ui/inc/tools/SlotStateListener.hxx
new file mode 100644
index 000000000..54a2e463d
--- /dev/null
+++ b/sd/source/ui/inc/tools/SlotStateListener.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <comphelper/compbase.hxx>
+#include <tools/link.hxx>
+#include <cppuhelper/weakref.hxx>
+
+namespace com::sun::star::frame { class XDispatch; }
+namespace com::sun::star::frame { class XDispatchProvider; }
+namespace com::sun::star::frame { class XStatusListener; }
+namespace com::sun::star::frame { struct FeatureStateEvent; }
+
+namespace sd::tools {
+
+typedef comphelper::WeakComponentImplHelper<
+ css::frame::XStatusListener
+ > SlotStateListenerInterfaceBase;
+
+/** Listen for state changes of slots. This class has been created in order
+ to be informed when the support for vertical writing changes but it can
+ be used to relay state changes of other slots as well.
+*/
+class SlotStateListener final
+ : public SlotStateListenerInterfaceBase
+{
+public:
+ /** This convenience version of the constructor takes all parameters
+ that are necessary to observe a single slot. See descriptions of
+ the SetCallback(), ConnectToFrame(), and ObserveSlot() methods for
+ explanations about the parameters.
+ */
+ SlotStateListener (
+ Link<const OUString&,void> const & rCallback,
+ const css::uno::Reference<css::frame::XDispatchProvider>& rxDispatchProvider,
+ const OUString& rSlotName);
+
+ /** The constructor de-registers all remaining listeners. Usually a prior
+ dispose() call should have done that already.
+ */
+ virtual ~SlotStateListener() override;
+
+ /** Set the callback to the given value. Whenever one of the observed
+ slots changes its state this callback is informed about it.
+ Changing the callback does not release the listeners.
+ @throws DisposedException
+ */
+ void SetCallback (const Link<const OUString&,void>& rCallback);
+
+ /** Set the frame whose slots shall be observed. When an object of this
+ class is already observing slots of another frame then these
+ listeners are released first.
+ @throws DisposedException
+ */
+ void ConnectToDispatchProvider (
+ const css::uno::Reference<css::frame::XDispatchProvider>& rxDispatchProvider);
+
+ /** Observe the slot specified by the given name. Note that
+ ConnectToFrame() has to have been called earlier.
+ @param rSlotName
+ The name of the slot to observe. An example is
+ ".uno:VerticalTextState".
+ @throws DisposedException
+ */
+ void ObserveSlot (const OUString& rSlotName);
+
+ //===== frame::XStatusListener ==========================================
+
+ /** Called by slot state change broadcasters. In turn the callback is
+ informed about the state change.
+ @throws DisposedException
+ */
+ virtual void SAL_CALL
+ statusChanged (
+ const css::frame::FeatureStateEvent& rState) override;
+
+ //===== lang::XEventListener ============================================
+
+ virtual void SAL_CALL
+ disposing(const css::lang::EventObject& rEvent) override;
+
+private:
+ /** This method is called by the WeakComponentImplHelper base class in
+ reaction to a XComponent::dispose() call. It releases all currently
+ active listeners.
+ */
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ Link<const OUString&,void> maCallback;
+
+ /** Remember the URLs that describe slots whose state changes we are
+ listening to.
+ */
+ std::vector<css::util::URL> maRegisteredURLList;
+
+ css::uno::WeakReference<css::frame::XDispatchProvider> mxDispatchProviderWeak;
+
+ /** Deregister all currently active state change listeners.
+ */
+ void ReleaseListeners();
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+
+ /** Transform the given string into a URL object.
+ */
+ static css::util::URL MakeURL (const OUString& rSlotName);
+
+ /** Return an XDispatch object for the given URL.
+ */
+ css::uno::Reference<css::frame::XDispatch>
+ GetDispatch (
+ const css::util::URL& rURL) const;
+};
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tools/TimerBasedTaskExecution.hxx b/sd/source/ui/inc/tools/TimerBasedTaskExecution.hxx
new file mode 100644
index 000000000..bbff549f1
--- /dev/null
+++ b/sd/source/ui/inc/tools/TimerBasedTaskExecution.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/timer.hxx>
+
+#include <memory>
+
+namespace sd::tools {
+
+class AsynchronousTask;
+
+/** Execute an AsynchronousTask timer based, i.e. every
+ nMillisecondsBetweenSteps milliseconds as much steps are executed as fit
+ into a nMaxTimePerStep millisecond interval.
+
+ When a task is executed completely, i.e. HasNextStep() returns <FALSE/>,
+ the TimerBasedTaskExecution destroys itself. This, of course, works
+ only if the creating instance does not hold a shared_ptr to that object.
+*/
+class TimerBasedTaskExecution
+{
+public:
+ /** Create a new object of this class.
+ @param rpTask
+ The AsynchronousTask that is to be executed.
+ @param nMillisecondsBetweenSteps
+ Wait at least this long between the execution of steps. Note
+ that more than one step may be executed in succession.
+ @param nMaxTimePerStep
+ The maximal time for executing steps without yielding control.
+ */
+ static std::shared_ptr<TimerBasedTaskExecution> Create (
+ const std::shared_ptr<AsynchronousTask>& rpTask,
+ sal_uInt32 nMillisecondsBetweenSteps,
+ sal_uInt32 nMaxTimePerStep);
+
+ /** Stop the execution of the task and release the shared pointer to
+ itself so that it will eventually be destroyed.
+ */
+ void Release();
+
+ /** Convenience method that calls Release() on the given task. It
+ checks the given weak_ptr for being expired and catches bad_weak_ptr
+ exceptions.
+ */
+ static void ReleaseTask (const std::weak_ptr<TimerBasedTaskExecution>& rpTask);
+
+private:
+ std::shared_ptr<AsynchronousTask> mpTask;
+ Timer maTimer;
+ /** This shared_ptr to this is used to destroy a TimerBasedTaskExecution
+ object when its task has been executed completely.
+ */
+ std::shared_ptr<TimerBasedTaskExecution> mpSelf;
+ sal_uInt32 mnMaxTimePerStep;
+
+ TimerBasedTaskExecution (
+ const std::shared_ptr<AsynchronousTask>& rpTask,
+ sal_uInt32 nMillisecondsBetweenSteps,
+ sal_uInt32 nMaxTimePerStep);
+ ~TimerBasedTaskExecution();
+
+ class Deleter;
+ friend class Deleter;
+
+ DECL_LINK(TimerCallback, Timer *, void);
+};
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tpaction.hxx b/sd/source/ui/inc/tpaction.hxx
new file mode 100644
index 000000000..893192d25
--- /dev/null
+++ b/sd/source/ui/inc/tpaction.hxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/presentation/ClickAction.hpp>
+#include <sfx2/tabdlg.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <svx/xtable.hxx>
+#include <unotools/resmgr.hxx>
+#include "sdtreelb.hxx"
+
+#include <vector>
+
+namespace sd {
+ class View;
+}
+class SdDrawDocument;
+
+/**
+ * Effect-SingleTab-Dialog
+ */
+class SdActionDlg final : public SfxSingleTabDialogController
+{
+public:
+ SdActionDlg(weld::Window* pParent, const SfxItemSet* pAttr, ::sd::View const * pView);
+};
+
+/**
+ * Interaction-Tab-Page
+ */
+class SdTPAction final : public SfxTabPage
+{
+private:
+ const ::sd::View* mpView;
+ SdDrawDocument* mpDoc;
+ XColorListRef pColList;
+
+ bool bTreeUpdated;
+ std::vector<css::presentation::ClickAction> maCurrentActions;
+ OUString aLastFile;
+ ::std::vector< tools::Long > aVerbVector;
+
+ std::unique_ptr<weld::ComboBox> m_xLbAction;
+ std::unique_ptr<weld::Label> m_xFtTree; // jump destination controls
+ std::unique_ptr<SdPageObjsTLV> m_xLbTree;
+ std::unique_ptr<SdPageObjsTLV> m_xLbTreeDocument;
+ std::unique_ptr<weld::TreeView> m_xLbOLEAction;
+ std::unique_ptr<weld::Frame> m_xFrame;
+ std::unique_ptr<weld::Entry> m_xEdtSound;
+ std::unique_ptr<weld::Entry> m_xEdtBookmark;
+ std::unique_ptr<weld::Entry> m_xEdtDocument;
+ std::unique_ptr<weld::Entry> m_xEdtProgram;
+ std::unique_ptr<weld::Entry> m_xEdtMacro;
+ std::unique_ptr<weld::Button> m_xBtnSearch;
+ std::unique_ptr<weld::Button> m_xBtnSeek;
+
+ DECL_LINK( ClickSearchHdl, weld::Button&, void );
+ DECL_LINK( ClickActionHdl, weld::ComboBox&, void );
+ DECL_LINK( SelectTreeHdl, weld::TreeView&, void );
+ DECL_LINK( CheckFileHdl, weld::Widget&, void );
+
+ void UpdateTree();
+ void OpenFileDialog();
+ css::presentation::ClickAction GetActualClickAction();
+ void SetActualClickAction( css::presentation::ClickAction eCA );
+ void SetEditText( OUString const & rStr );
+ OUString GetEditText( bool bURL = false );
+public:
+ SD_DLLPUBLIC static TranslateId GetClickActionSdResId(css::presentation::ClickAction eCA);
+
+ SdTPAction(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs);
+ virtual ~SdTPAction() override;
+
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& );
+
+ virtual bool FillItemSet( SfxItemSet* ) override;
+ virtual void Reset( const SfxItemSet * ) override;
+
+ virtual void ActivatePage( const SfxItemSet& rSet ) override;
+ virtual DeactivateRC DeactivatePage( SfxItemSet* pSet ) override;
+
+ void Construct();
+
+ void SetView( const ::sd::View* pSdView );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/tpoption.hxx b/sd/source/ui/inc/tpoption.hxx
new file mode 100644
index 000000000..8657db27a
--- /dev/null
+++ b/sd/source/ui/inc/tpoption.hxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+#include <svx/optgrid.hxx>
+
+/**
+ * Option-Tab-Page: Snap
+ */
+class SdTpOptionsSnap final : public SvxGridTabPage
+{
+public:
+ SdTpOptionsSnap(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs);
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* );
+ virtual ~SdTpOptionsSnap() override;
+
+ virtual bool FillItemSet( SfxItemSet* ) override;
+ virtual void Reset( const SfxItemSet * ) override;
+};
+
+/**
+ * Option-Tab-Page: Contents
+ */
+class SdTpOptionsContents final : public SfxTabPage
+{
+private:
+ std::unique_ptr<weld::CheckButton> m_xCbxRuler;
+ std::unique_ptr<weld::CheckButton> m_xCbxDragStripes;
+ std::unique_ptr<weld::CheckButton> m_xCbxHandlesBezier;
+ std::unique_ptr<weld::CheckButton> m_xCbxMoveOutline;
+
+public:
+ SdTpOptionsContents(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs);
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* );
+ virtual ~SdTpOptionsContents() override;
+
+ virtual bool FillItemSet( SfxItemSet* ) override;
+ virtual void Reset( const SfxItemSet * ) override;
+};
+
+/**
+ * Option-Tab-Page: View
+ */
+
+class SdTpOptionsMisc final : public SfxTabPage
+{
+ friend class SdModule;
+
+private:
+ sal_uInt32 nWidth;
+ sal_uInt32 nHeight;
+ OUString aInfo1;
+ OUString aInfo2;
+
+ MapUnit ePoolUnit;
+
+ std::unique_ptr<weld::CheckButton> m_xCbxQuickEdit;
+ std::unique_ptr<weld::CheckButton> m_xCbxPickThrough;
+
+ std::unique_ptr<weld::Frame> m_xNewDocumentFrame;
+ std::unique_ptr<weld::CheckButton> m_xCbxStartWithTemplate;
+
+ std::unique_ptr<weld::CheckButton> m_xCbxMasterPageCache;
+ std::unique_ptr<weld::CheckButton> m_xCbxCopy;
+ std::unique_ptr<weld::CheckButton> m_xCbxMarkedHitMovesAlways;
+ std::unique_ptr<weld::Frame> m_xPresentationFrame;
+
+ std::unique_ptr<weld::ComboBox> m_xLbMetric;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldTabstop;
+
+ std::unique_ptr<weld::CheckButton> m_xCbxEnableSdremote;
+ std::unique_ptr<weld::CheckButton> m_xCbxEnablePresenterScreen;
+ std::unique_ptr<weld::CheckButton> m_xCbxUsePrinterMetrics;
+ std::unique_ptr<weld::CheckButton> m_xCbxCompatibility;
+
+ //Scale
+ std::unique_ptr<weld::Frame> m_xScaleFrame;
+ std::unique_ptr<weld::ComboBox> m_xCbScale;
+ std::unique_ptr<weld::Label> m_xNewDocLb;
+ std::unique_ptr<weld::Label> m_xFiInfo1;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldOriginalWidth;
+ std::unique_ptr<weld::Label> m_xWidthLb;
+ std::unique_ptr<weld::Label> m_xHeightLb;
+ std::unique_ptr<weld::Label> m_xFiInfo2;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldOriginalHeight;
+ std::unique_ptr<weld::CheckButton> m_xCbxDistort;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldInfo1;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrFldInfo2;
+
+ static OUString GetScale( sal_Int32 nX, sal_Int32 nY );
+ static bool SetScale( std::u16string_view aScale, sal_Int32& rX, sal_Int32& rY );
+
+ DECL_LINK( SelectMetricHdl_Impl, weld::ComboBox&, void );
+
+ /** Enable or disable the controls in the compatibility section of the
+ 'general' tab page depending on whether there is at least one
+ document.
+ */
+ void UpdateCompatibilityControls();
+
+ virtual void ActivatePage( const SfxItemSet& rSet ) override;
+ virtual DeactivateRC DeactivatePage( SfxItemSet* pSet ) override;
+
+public:
+ SdTpOptionsMisc(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs);
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* );
+ virtual ~SdTpOptionsMisc() override;
+
+ virtual bool FillItemSet( SfxItemSet* ) override;
+ virtual void Reset( const SfxItemSet * ) override;
+
+ /** Hide Impress specific controls, make Draw specific controls visible
+ and arrange the visible controls. Do not call this method or the
+ <member>SetImpressMode()</member> method more than once.
+ */
+ void SetDrawMode();
+
+ /** Hide Draw specific controls, make Impress specific controls visible
+ and arrange the visible controls. Do not call this method or the
+ <member>SetDrawMode()</member> method more than once.
+ */
+ void SetImpressMode();
+ virtual void PageCreated(const SfxAllItemSet& aSet) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/uiobject.hxx b/sd/source/ui/inc/uiobject.hxx
new file mode 100644
index 000000000..06cb6105f
--- /dev/null
+++ b/sd/source/ui/inc/uiobject.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <memory>
+#include <vcl/uitest/uiobject.hxx>
+#include "Window.hxx"
+
+class ImpressWindowUIObject final : public WindowUIObject
+{
+public:
+ ImpressWindowUIObject(const VclPtr<sd::Window>& xWindow);
+
+ virtual StringMap get_state() override;
+
+ virtual void execute(const OUString& rAction, const StringMap& rParameters) override;
+
+ virtual std::unique_ptr<UIObject> get_child(const OUString& rID) override;
+
+ virtual std::set<OUString> get_children() const override;
+
+ static std::unique_ptr<UIObject> create(vcl::Window* pWindow);
+
+private:
+ virtual OUString get_name() const override;
+
+ VclPtr<sd::Window> mxWindow;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/unchss.hxx b/sd/source/ui/inc/unchss.hxx
new file mode 100644
index 000000000..7c3845f8b
--- /dev/null
+++ b/sd/source/ui/inc/unchss.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <svl/itemset.hxx>
+
+#include <sdundo.hxx>
+
+class SfxItemSet;
+class SfxStyleSheet;
+class SdDrawDocument;
+
+class StyleSheetUndoAction final : public SdUndoAction
+{
+ SfxStyleSheet* mpStyleSheet;
+
+ std::unique_ptr<SfxItemSet> mpNewSet;
+ std::unique_ptr<SfxItemSet> mpOldSet;
+
+public:
+ StyleSheetUndoAction(SdDrawDocument* pTheDoc, SfxStyleSheet* pTheStyleSheet,
+ const SfxItemSet* pTheNewItemSet);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/undoback.hxx b/sd/source/ui/inc/undoback.hxx
new file mode 100644
index 000000000..afbb13eca
--- /dev/null
+++ b/sd/source/ui/inc/undoback.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <sdundo.hxx>
+
+#include <svl/itemset.hxx>
+
+class SdDrawDocument;
+class SdPage;
+class SfxItemSet;
+class SfxPoolItem;
+
+class SdBackgroundObjUndoAction final : public SdUndoAction
+{
+private:
+
+ SdPage& mrPage;
+ std::unique_ptr<SfxItemSet> mpItemSet;
+ std::unique_ptr<SfxPoolItem> mpFillBitmapItem;
+ bool mbHasFillBitmap;
+
+ void ImplRestoreBackgroundObj();
+ void saveFillBitmap(SfxItemSet &rItemSet);
+ void restoreFillBitmap(SfxItemSet &rItemSet);
+
+public:
+ SdBackgroundObjUndoAction(
+ SdDrawDocument& rDoc,
+ SdPage& rPage,
+ const SfxItemSet& rItemSet);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+ virtual SdUndoAction* Clone() const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/undoheaderfooter.hxx b/sd/source/ui/inc/undoheaderfooter.hxx
new file mode 100644
index 000000000..2c8c9c8e9
--- /dev/null
+++ b/sd/source/ui/inc/undoheaderfooter.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdundo.hxx>
+#include <sdpage.hxx>
+#include <sddllapi.h>
+
+class SdDrawDocument;
+
+/************************************************************************/
+
+class SD_DLLPUBLIC SdHeaderFooterUndoAction final : public SdUndoAction
+{
+ SdPage* mpPage;
+
+ const sd::HeaderFooterSettings maOldSettings;
+ const sd::HeaderFooterSettings maNewSettings;
+
+public:
+ SdHeaderFooterUndoAction( SdDrawDocument* pDoc, SdPage* pPage, const sd::HeaderFooterSettings& rNewSettings );
+ virtual ~SdHeaderFooterUndoAction() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/undolayer.hxx b/sd/source/ui/inc/undolayer.hxx
new file mode 100644
index 000000000..431f60d4f
--- /dev/null
+++ b/sd/source/ui/inc/undolayer.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdundo.hxx>
+
+class SdDrawDocument;
+class SdrLayer;
+
+/************************************************************************/
+
+class SdLayerModifyUndoAction final : public SdUndoAction
+{
+
+public:
+ SdLayerModifyUndoAction( SdDrawDocument* _pDoc, SdrLayer* pLayer,
+ const OUString& rOldLayerName, const OUString& rOldLayerTitle, const OUString& rOldLayerDesc, bool bOldIsVisible, bool bOldIsLocked, bool bOldIsPrintable,
+ const OUString& rNewLayerName, const OUString& rNewLayerTitle, const OUString& rNewLayerDesc, bool bNewIsVisible, bool bNewIsLocked, bool bNewIsPrintable );
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+private:
+ SdrLayer* mpLayer;
+ OUString maOldLayerName;
+ OUString maOldLayerTitle;
+ OUString maOldLayerDesc;
+ bool mbOldIsVisible;
+ bool mbOldIsLocked;
+ bool mbOldIsPrintable;
+ OUString maNewLayerName;
+ OUString maNewLayerTitle;
+ OUString maNewLayerDesc;
+ bool mbNewIsVisible;
+ bool mbNewIsLocked;
+ bool mbNewIsPrintable;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/undopage.hxx b/sd/source/ui/inc/undopage.hxx
new file mode 100644
index 000000000..87d5b5b21
--- /dev/null
+++ b/sd/source/ui/inc/undopage.hxx
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/gen.hxx>
+#include <vcl/prntypes.hxx>
+
+#include <sdundo.hxx>
+
+class SdDrawDocument;
+class SdPage;
+
+/************************************************************************/
+
+class SdPageFormatUndoAction final : public SdUndoAction
+{
+ SdPage* mpPage;
+
+ Size maOldSize;
+ sal_Int32 mnOldLeft;
+ sal_Int32 mnOldRight;
+ sal_Int32 mnOldUpper;
+ sal_Int32 mnOldLower;
+ Orientation meOldOrientation;
+ sal_uInt16 mnOldPaperBin;
+ bool mbOldFullSize;
+
+ Size maNewSize;
+ sal_Int32 mnNewLeft;
+ sal_Int32 mnNewRight;
+ sal_Int32 mnNewUpper;
+ sal_Int32 mnNewLower;
+ bool mbNewScale;
+ Orientation meNewOrientation;
+ sal_uInt16 mnNewPaperBin;
+ bool mbNewFullSize;
+
+public:
+ SdPageFormatUndoAction( SdDrawDocument* pDoc,
+ SdPage* pThePage,
+ const Size& rOldSz,
+ sal_Int32 nOldLft,
+ sal_Int32 nOldRgt,
+ sal_Int32 nOldUpr,
+ sal_Int32 nOldLwr,
+ Orientation eOldOrient,
+ sal_uInt16 nOPaperBin,
+ bool bOFullSize,
+
+ const Size& rNewSz,
+ sal_Int32 nNewLft,
+ sal_Int32 nNewRgt,
+ sal_Int32 nNewUpr,
+ sal_Int32 nNewLwr,
+ bool bNewScl,
+ Orientation eNewOrient,
+ sal_uInt16 nNPaperBin,
+ bool bNFullSize
+ ) :
+ SdUndoAction(pDoc),
+ mpPage (pThePage),
+ maOldSize (rOldSz),
+ mnOldLeft (nOldLft),
+ mnOldRight (nOldRgt),
+ mnOldUpper (nOldUpr),
+ mnOldLower (nOldLwr),
+ meOldOrientation(eOldOrient),
+ mnOldPaperBin (nOPaperBin),
+ mbOldFullSize (bOFullSize),
+
+ maNewSize (rNewSz),
+ mnNewLeft (nNewLft),
+ mnNewRight (nNewRgt),
+ mnNewUpper (nNewUpr),
+ mnNewLower (nNewLwr),
+ mbNewScale (bNewScl),
+ meNewOrientation(eNewOrient),
+ mnNewPaperBin (nNPaperBin),
+ mbNewFullSize (bNFullSize)
+
+ {}
+ virtual ~SdPageFormatUndoAction() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+};
+
+/************************************************************************/
+
+class SdPageLRUndoAction final : public SdUndoAction
+{
+ SdPage* mpPage;
+
+ sal_Int32 mnOldLeft;
+ sal_Int32 mnOldRight;
+ sal_Int32 mnNewLeft;
+ sal_Int32 mnNewRight;
+
+public:
+ SdPageLRUndoAction( SdDrawDocument* pDoc, SdPage* pThePage,
+ sal_Int32 nOldLft, sal_Int32 nOldRgt,
+ sal_Int32 nNewLft, sal_Int32 nNewRgt ) :
+ SdUndoAction(pDoc),
+ mpPage (pThePage),
+ mnOldLeft (nOldLft),
+ mnOldRight (nOldRgt),
+ mnNewLeft (nNewLft),
+ mnNewRight (nNewRgt)
+ {}
+ virtual ~SdPageLRUndoAction() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+};
+
+/************************************************************************/
+
+class SdPageULUndoAction final : public SdUndoAction
+{
+ SdPage* mpPage;
+
+ sal_Int32 mnOldUpper;
+ sal_Int32 mnOldLower;
+ sal_Int32 mnNewUpper;
+ sal_Int32 mnNewLower;
+
+public:
+ SdPageULUndoAction( SdDrawDocument* pDoc, SdPage* pThePage,
+ sal_Int32 nOldUpr, sal_Int32 nOldLwr,
+ sal_Int32 nNewUpr, sal_Int32 nNewLwr ) :
+ SdUndoAction(pDoc),
+ mpPage (pThePage),
+ mnOldUpper (nOldUpr),
+ mnOldLower (nOldLwr),
+ mnNewUpper (nNewUpr),
+ mnNewLower (nNewLwr)
+ {}
+ virtual ~SdPageULUndoAction() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/unmodpg.hxx b/sd/source/ui/inc/unmodpg.hxx
new file mode 100644
index 000000000..9248642bf
--- /dev/null
+++ b/sd/source/ui/inc/unmodpg.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <xmloff/autolayout.hxx>
+
+#include <sdundo.hxx>
+
+class SdDrawDocument;
+class SdPage;
+
+class ModifyPageUndoAction final : public SdUndoAction
+{
+ SdPage* mpPage;
+ OUString maOldName;
+ OUString maNewName;
+ AutoLayout meOldAutoLayout;
+ AutoLayout meNewAutoLayout;
+ bool mbOldBckgrndVisible;
+ bool mbNewBckgrndVisible;
+ bool mbOldBckgrndObjsVisible;
+ bool mbNewBckgrndObjsVisible;
+
+public:
+ ModifyPageUndoAction(
+ SdDrawDocument* pTheDoc,
+ SdPage* pThePage,
+ const OUString& aTheNewName,
+ AutoLayout eTheNewAutoLayout,
+ bool bTheNewBckgrndVisible,
+ bool bTheNewBckgrndObjsVisible);
+
+ virtual ~ModifyPageUndoAction() override;
+ virtual void Undo() override;
+ virtual void Redo() override;
+};
+
+class RenameLayoutTemplateUndoAction final : public SdUndoAction
+{
+public:
+ RenameLayoutTemplateUndoAction(
+ SdDrawDocument* pDocument,
+ const OUString& rOldLayoutName,
+ const OUString& rNewLayoutName);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ OUString maOldName;
+ OUString maNewName;
+ const OUString maComment;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/unmovss.hxx b/sd/source/ui/inc/unmovss.hxx
new file mode 100644
index 000000000..93e87cd40
--- /dev/null
+++ b/sd/source/ui/inc/unmovss.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdundo.hxx>
+#include <stlsheet.hxx>
+#include <vector>
+
+class SdDrawDocument;
+
+class SdMoveStyleSheetsUndoAction final : public SdUndoAction
+{
+ StyleSheetCopyResultVector maStyles;
+ std::vector< SdStyleSheetVector > maListOfChildLists;
+ bool mbMySheets;
+
+public:
+ SdMoveStyleSheetsUndoAction(SdDrawDocument* pTheDoc, StyleSheetCopyResultVector& rTheStyles, bool bInserted);
+
+ virtual ~SdMoveStyleSheetsUndoAction() override;
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+ virtual OUString GetComment() const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/unoaprms.hxx b/sd/source/ui/inc/unoaprms.hxx
new file mode 100644
index 000000000..9ad327668
--- /dev/null
+++ b/sd/source/ui/inc/unoaprms.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/presentation/AnimationEffect.hpp>
+#include <com/sun/star/presentation/AnimationSpeed.hpp>
+#include <com/sun/star/presentation/ClickAction.hpp>
+#include <sdundo.hxx>
+#include <tools/color.hxx>
+
+class SdDrawDocument;
+class SdrObject;
+
+class SdAnimationPrmsUndoAction final : public SdUndoAction
+{
+ SdrObject* pObject;
+ bool bOldActive;
+ bool bNewActive;
+ bool bOldDimPrevious;
+ bool bNewDimPrevious;
+ bool bOldDimHide;
+ bool bNewDimHide;
+ bool bOldSoundOn;
+ bool bNewSoundOn;
+ bool bOldSecondSoundOn;
+ bool bNewSecondSoundOn;
+ bool bOldPlayFull;
+ bool bNewPlayFull;
+ bool bOldSecondPlayFull;
+ bool bNewSecondPlayFull;
+ css::presentation::AnimationEffect eOldEffect;
+ css::presentation::AnimationEffect eNewEffect;
+ css::presentation::AnimationEffect eOldTextEffect;
+ css::presentation::AnimationEffect eNewTextEffect;
+ css::presentation::AnimationSpeed eOldSpeed;
+ css::presentation::AnimationSpeed eNewSpeed;
+ css::presentation::AnimationEffect eOldSecondEffect;
+ css::presentation::AnimationEffect eNewSecondEffect;
+ css::presentation::AnimationSpeed eOldSecondSpeed;
+ css::presentation::AnimationSpeed eNewSecondSpeed;
+ Color aOldDimColor;
+ Color aNewDimColor;
+ OUString aOldSoundFile;
+ OUString aNewSoundFile;
+ css::presentation::ClickAction eOldClickAction;
+ css::presentation::ClickAction eNewClickAction;
+ OUString aOldBookmark;
+ OUString aNewBookmark;
+ sal_uInt16 nOldVerb;
+ sal_uInt16 nNewVerb;
+
+ bool bInfoCreated;
+
+public:
+ SdAnimationPrmsUndoAction(SdDrawDocument* pTheDoc, SdrObject* pObj,
+ bool bCreated)
+ : SdUndoAction(pTheDoc)
+ , pObject(pObj)
+ , bOldActive(false)
+ , bNewActive(false)
+ , bOldDimPrevious(false)
+ , bNewDimPrevious(false)
+ , bOldDimHide(false)
+ , bNewDimHide(false)
+ , bOldSoundOn(false)
+ , bNewSoundOn(false)
+ , bOldSecondSoundOn(false)
+ , bNewSecondSoundOn(false)
+ , bOldPlayFull(false)
+ , bNewPlayFull(false)
+ , bOldSecondPlayFull(false)
+ , bNewSecondPlayFull(false)
+ , eOldEffect(css::presentation::AnimationEffect_NONE)
+ , eNewEffect(css::presentation::AnimationEffect_NONE)
+ , eOldTextEffect(css::presentation::AnimationEffect_NONE)
+ , eNewTextEffect(css::presentation::AnimationEffect_NONE)
+ , eOldSpeed(css::presentation::AnimationSpeed_SLOW)
+ , eNewSpeed(css::presentation::AnimationSpeed_SLOW)
+ , eOldSecondEffect(css::presentation::AnimationEffect_NONE)
+ , eNewSecondEffect(css::presentation::AnimationEffect_NONE)
+ , eOldSecondSpeed(css::presentation::AnimationSpeed_SLOW)
+ , eNewSecondSpeed(css::presentation::AnimationSpeed_SLOW)
+ , eOldClickAction(css::presentation::ClickAction_NONE)
+ , eNewClickAction(css::presentation::ClickAction_NONE)
+ , nOldVerb(0)
+ , nNewVerb(0)
+ , bInfoCreated(bCreated)
+ {
+ }
+
+ void SetActive(bool bTheOldActive, bool bTheNewActive)
+ { bOldActive = bTheOldActive; bNewActive = bTheNewActive; }
+ void SetEffect(css::presentation::AnimationEffect eTheOldEffect, css::presentation::AnimationEffect eTheNewEffect)
+ { eOldEffect = eTheOldEffect; eNewEffect = eTheNewEffect; }
+ void SetTextEffect(css::presentation::AnimationEffect eTheOldEffect, css::presentation::AnimationEffect eTheNewEffect)
+ { eOldTextEffect = eTheOldEffect; eNewTextEffect = eTheNewEffect; }
+ void SetSpeed(css::presentation::AnimationSpeed eTheOldSpeed, css::presentation::AnimationSpeed eTheNewSpeed)
+ { eOldSpeed = eTheOldSpeed; eNewSpeed = eTheNewSpeed; }
+ void SetDim(bool bTheOldDim, bool bTheNewDim)
+ { bOldDimPrevious = bTheOldDim; bNewDimPrevious = bTheNewDim; }
+ void SetDimColor(Color aTheOldDimColor, Color aTheNewDimColor)
+ { aOldDimColor = aTheOldDimColor; aNewDimColor = aTheNewDimColor; }
+ void SetDimHide(bool bTheOldDimHide, bool bTheNewDimHide)
+ { bOldDimHide = bTheOldDimHide; bNewDimHide = bTheNewDimHide; }
+ void SetSoundOn(bool bTheOldSoundOn, bool bTheNewSoundOn)
+ { bOldSoundOn = bTheOldSoundOn; bNewSoundOn = bTheNewSoundOn; }
+ void SetSound(const OUString& aTheOldSound, const OUString& aTheNewSound)
+ { aOldSoundFile = aTheOldSound; aNewSoundFile = aTheNewSound; }
+ void SetPlayFull(bool bTheOldPlayFull, bool bTheNewPlayFull)
+ { bOldPlayFull = bTheOldPlayFull; bNewPlayFull = bTheNewPlayFull; }
+ void SetClickAction(css::presentation::ClickAction eTheOldAction, css::presentation::ClickAction eTheNewAction)
+ { eOldClickAction = eTheOldAction; eNewClickAction = eTheNewAction; }
+ void SetBookmark(const OUString& aTheOldBookmark, const OUString& aTheNewBookmark)
+ { aOldBookmark = aTheOldBookmark; aNewBookmark = aTheNewBookmark; }
+ void SetVerb(sal_uInt16 nTheOldVerb, sal_uInt16 nTheNewVerb)
+ { nOldVerb = nTheOldVerb; nNewVerb = nTheNewVerb; }
+ void SetSecondEffect(css::presentation::AnimationEffect eTheOldEffect, css::presentation::AnimationEffect eTheNewEffect)
+ { eOldSecondEffect = eTheOldEffect; eNewSecondEffect = eTheNewEffect; }
+ void SetSecondSpeed(css::presentation::AnimationSpeed eTheOldSpeed, css::presentation::AnimationSpeed eTheNewSpeed)
+ { eOldSecondSpeed = eTheOldSpeed; eNewSecondSpeed = eTheNewSpeed; }
+ void SetSecondSoundOn(bool bTheOldSoundOn, bool bTheNewSoundOn)
+ { bOldSecondSoundOn = bTheOldSoundOn; bNewSecondSoundOn = bTheNewSoundOn; }
+ void SetSecondPlayFull(bool bTheOldPlayFull, bool bTheNewPlayFull)
+ { bOldSecondPlayFull = bTheOldPlayFull; bNewSecondPlayFull = bTheNewPlayFull; }
+
+ virtual ~SdAnimationPrmsUndoAction() override;
+ virtual void Undo() override;
+ virtual void Redo() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/unokywds.hxx b/sd/source/ui/inc/unokywds.hxx
new file mode 100644
index 000000000..37a03d3d6
--- /dev/null
+++ b/sd/source/ui/inc/unokywds.hxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <rtl/ustring.hxx>
+
+// SdUnoPseudoStyleFamily
+inline constexpr OUStringLiteral sUNO_PseudoSheet_Background = u"background";
+
+// SdLayer
+inline constexpr OUStringLiteral sUNO_LayerName_background = u"background";
+inline constexpr OUStringLiteral sUNO_LayerName_background_objects = u"backgroundobjects";
+inline constexpr OUStringLiteral sUNO_LayerName_layout = u"layout";
+inline constexpr OUStringLiteral sUNO_LayerName_controls = u"controls";
+inline constexpr OUStringLiteral sUNO_LayerName_measurelines = u"measurelines";
+
+// services
+inline constexpr OUStringLiteral sUNO_Service_FillProperties
+ = u"com.sun.star.drawing.FillProperties";
+inline constexpr OUStringLiteral sUNO_Service_PageBackground
+ = u"com.sun.star.drawing.PageBackground";
+inline constexpr OUStringLiteral sUNO_Service_ImageMapRectangleObject
+ = u"com.sun.star.image.ImageMapRectangleObject";
+inline constexpr OUStringLiteral sUNO_Service_ImageMapCircleObject
+ = u"com.sun.star.image.ImageMapCircleObject";
+inline constexpr OUStringLiteral sUNO_Service_ImageMapPolygonObject
+ = u"com.sun.star.image.ImageMapPolygonObject";
+
+// properties
+inline constexpr OUStringLiteral sUNO_Prop_ForbiddenCharacters = u"ForbiddenCharacters";
+inline constexpr OUStringLiteral sUNO_Prop_MapUnit = u"MapUnit";
+inline constexpr OUStringLiteral sUNO_Prop_VisibleArea = u"VisibleArea";
+inline constexpr OUStringLiteral sUNO_Prop_TabStop = u"TabStop";
+inline constexpr OUStringLiteral sUNO_Prop_CharLocale = u"CharLocale";
+inline constexpr OUStringLiteral sUNO_Prop_AutomContFocus = u"AutomaticControlFocus";
+inline constexpr OUStringLiteral sUNO_Prop_ApplyFrmDsgnMode = u"ApplyFormDesignMode";
+inline constexpr OUStringLiteral sUNO_Prop_IsBackgroundVisible = u"IsBackgroundVisible";
+inline constexpr OUStringLiteral sUNO_Prop_IsBackgroundObjectsVisible
+ = u"IsBackgroundObjectsVisible";
+inline constexpr OUStringLiteral sUNO_Prop_UserDefinedAttributes = u"UserDefinedAttributes";
+inline constexpr OUStringLiteral sUNO_Prop_BookmarkURL = u"BookmarkURL";
+inline constexpr OUStringLiteral sUNO_Prop_RuntimeUID = u"RuntimeUID";
+inline constexpr OUStringLiteral sUNO_Prop_HasValidSignatures = u"HasValidSignatures";
+inline constexpr OUStringLiteral sUNO_Prop_InteropGrabBag = u"InteropGrabBag";
+inline constexpr OUStringLiteral sUNO_Prop_Theme = u"Theme";
+
+// view settings
+inline constexpr OUStringLiteral sUNO_View_ViewId = u"ViewId";
+inline constexpr OUStringLiteral sUNO_View_SnapLinesDrawing = u"SnapLinesDrawing";
+inline constexpr OUStringLiteral sUNO_View_SnapLinesNotes = u"SnapLinesNotes";
+inline constexpr OUStringLiteral sUNO_View_SnapLinesHandout = u"SnapLinesHandout";
+inline constexpr OUStringLiteral sUNO_View_RulerIsVisible = u"RulerIsVisible";
+inline constexpr OUStringLiteral sUNO_View_PageKind = u"PageKind";
+inline constexpr OUStringLiteral sUNO_View_SelectedPage = u"SelectedPage";
+inline constexpr OUStringLiteral sUNO_View_IsLayerMode = u"IsLayerMode";
+inline constexpr OUStringLiteral sUNO_View_IsDoubleClickTextEdit = u"IsDoubleClickTextEdit";
+inline constexpr OUStringLiteral sUNO_View_IsClickChangeRotation = u"IsClickChangeRotation";
+inline constexpr OUStringLiteral sUNO_View_SlidesPerRow = u"SlidesPerRow";
+inline constexpr OUStringLiteral sUNO_View_EditMode = u"EditMode";
+inline const char sUNO_View_EditModeStandard[] = "EditModeStandard"; // To be deprecated
+// inline const char sUNO_View_EditModeNotes[] = "EditModeNotes";
+// inline const char sUNO_View_EditModeHandout[] = "EditModeHandout";
+
+inline constexpr OUStringLiteral sUNO_View_GridIsVisible = u"GridIsVisible";
+inline constexpr OUStringLiteral sUNO_View_GridIsFront = u"GridIsFront";
+inline constexpr OUStringLiteral sUNO_View_IsSnapToGrid = u"IsSnapToGrid";
+inline constexpr OUStringLiteral sUNO_View_IsSnapToPageMargins = u"IsSnapToPageMargins";
+inline constexpr OUStringLiteral sUNO_View_IsSnapToSnapLines = u"IsSnapToSnapLines";
+inline constexpr OUStringLiteral sUNO_View_IsSnapToObjectFrame = u"IsSnapToObjectFrame";
+inline constexpr OUStringLiteral sUNO_View_IsSnapToObjectPoints = u"IsSnapToObjectPoints";
+inline constexpr OUStringLiteral sUNO_View_IsPlusHandlesAlwaysVisible
+ = u"IsPlusHandlesAlwaysVisible";
+inline constexpr OUStringLiteral sUNO_View_IsFrameDragSingles = u"IsFrameDragSingles";
+inline constexpr OUStringLiteral sUNO_View_EliminatePolyPointLimitAngle
+ = u"EliminatePolyPointLimitAngle";
+inline constexpr OUStringLiteral sUNO_View_IsEliminatePolyPoints = u"IsEliminatePolyPoints";
+inline const char sUNO_View_ActiveLayer[] = "ActiveLayer";
+inline constexpr OUStringLiteral sUNO_View_NoAttribs = u"NoAttribs";
+inline constexpr OUStringLiteral sUNO_View_NoColors = u"NoColors";
+inline constexpr OUStringLiteral sUNO_View_GridCoarseWidth = u"GridCoarseWidth";
+inline constexpr OUStringLiteral sUNO_View_GridCoarseHeight = u"GridCoarseHeight";
+inline constexpr OUStringLiteral sUNO_View_GridFineWidth = u"GridFineWidth";
+inline constexpr OUStringLiteral sUNO_View_GridFineHeight = u"GridFineHeight";
+inline constexpr OUStringLiteral sUNO_View_IsAngleSnapEnabled = u"IsAngleSnapEnabled";
+inline constexpr OUStringLiteral sUNO_View_SnapAngle = u"SnapAngle";
+inline constexpr OUStringLiteral sUNO_View_GridSnapWidthXNumerator = u"GridSnapWidthXNumerator";
+inline constexpr OUStringLiteral sUNO_View_GridSnapWidthXDenominator = u"GridSnapWidthXDenominator";
+inline constexpr OUStringLiteral sUNO_View_GridSnapWidthYNumerator = u"GridSnapWidthYNumerator";
+inline constexpr OUStringLiteral sUNO_View_GridSnapWidthYDenominator = u"GridSnapWidthYDenominator";
+inline constexpr OUStringLiteral sUNO_View_VisibleLayers = u"VisibleLayers";
+inline constexpr OUStringLiteral sUNO_View_PrintableLayers = u"PrintableLayers";
+inline constexpr OUStringLiteral sUNO_View_LockedLayers = u"LockedLayers";
+
+inline constexpr OUStringLiteral sUNO_View_VisibleAreaTop = u"VisibleAreaTop";
+inline constexpr OUStringLiteral sUNO_View_VisibleAreaLeft = u"VisibleAreaLeft";
+inline constexpr OUStringLiteral sUNO_View_VisibleAreaWidth = u"VisibleAreaWidth";
+inline constexpr OUStringLiteral sUNO_View_VisibleAreaHeight = u"VisibleAreaHeight";
+
+inline constexpr OUStringLiteral sUNO_View_ZoomOnPage = u"ZoomOnPage";
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/unomodel.hxx b/sd/source/ui/inc/unomodel.hxx
new file mode 100644
index 000000000..cf88666f6
--- /dev/null
+++ b/sd/source/ui/inc/unomodel.hxx
@@ -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 .
+ */
+#pragma once
+
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/document/XLinkTargetSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPageDuplicator.hpp>
+#include <com/sun/star/drawing/XLayerSupplier.hpp>
+#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
+#include <com/sun/star/presentation/XPresentationSupplier.hpp>
+#include <com/sun/star/presentation/XCustomPresentationSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/drawing/XDrawPages.hpp>
+#include <com/sun/star/ucb/XAnyCompareFactory.hpp>
+#include <com/sun/star/presentation/XHandoutMasterSupplier.hpp>
+#include <com/sun/star/view/XRenderable.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <rtl/ref.hxx>
+
+#include <sfx2/sfxbasemodel.hxx>
+#include <svx/fmdmod.hxx>
+
+#include <vcl/ITiledRenderable.hxx>
+
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <sddllapi.h>
+
+namespace com::sun::star::container { class XNameContainer; }
+namespace com::sun::star::i18n { class XForbiddenCharacters; }
+namespace com::sun::star::presentation { class XPresentation; }
+
+class SdDrawDocument;
+class SdPage;
+class SvxItemPropertySet;
+
+namespace sd {
+class DrawDocShell;
+class DrawViewShell;
+}
+
+extern OUString getPageApiName( SdPage const * pPage );
+extern OUString getPageApiNameFromUiName( const OUString& rUIName );
+
+class SD_DLLPUBLIC SdXImpressDocument final : public SfxBaseModel, // implements SfxListener, OWEAKOBJECT & other
+ public SvxFmMSFactory,
+ public css::drawing::XDrawPageDuplicator,
+ public css::drawing::XLayerSupplier,
+ public css::drawing::XMasterPagesSupplier,
+ public css::drawing::XDrawPagesSupplier,
+ public css::presentation::XPresentationSupplier,
+ public css::presentation::XCustomPresentationSupplier,
+ public css::document::XLinkTargetSupplier,
+ public css::beans::XPropertySet,
+ public css::style::XStyleFamiliesSupplier,
+ public css::lang::XServiceInfo,
+ public css::ucb::XAnyCompareFactory,
+ public css::presentation::XHandoutMasterSupplier,
+ public css::view::XRenderable,
+ public vcl::ITiledRenderable
+{
+ friend class SdDrawPagesAccess;
+ friend class SdMasterPagesAccess;
+ friend class SdLayerManager;
+
+private:
+ ::sd::DrawDocShell* mpDocShell;
+ SdDrawDocument* mpDoc;
+ bool mbDisposed;
+
+ css::uno::Reference<css::uno::XInterface> create(
+ OUString const & aServiceSpecifier, OUString const & referer);
+
+ /// @throws css::uno::RuntimeException
+ SdPage* InsertSdPage( sal_uInt16 nPage, bool bDuplicate );
+
+ const bool mbImpressDoc;
+ bool mbClipBoard;
+
+ css::uno::WeakReference< css::drawing::XDrawPages > mxDrawPagesAccess;
+ css::uno::WeakReference< css::drawing::XDrawPages > mxMasterPagesAccess;
+ css::uno::WeakReference< css::container::XNameAccess > mxLayerManager;
+ css::uno::WeakReference< css::container::XNameContainer > mxCustomPresentationAccess;
+ css::uno::WeakReference< css::i18n::XForbiddenCharacters > mxForbiddenCharacters;
+ css::uno::Reference< css::container::XNameAccess > mxLinks;
+
+ css::uno::Reference< css::uno::XInterface > mxDashTable;
+ css::uno::Reference< css::uno::XInterface > mxGradientTable;
+ css::uno::Reference< css::uno::XInterface > mxHatchTable;
+ css::uno::Reference< css::uno::XInterface > mxBitmapTable;
+ css::uno::Reference< css::uno::XInterface > mxTransGradientTable;
+ css::uno::Reference< css::uno::XInterface > mxMarkerTable;
+ css::uno::Reference< css::uno::XInterface > mxDrawingPool;
+
+ const SvxItemPropertySet* mpPropSet;
+
+ css::uno::Sequence< css::uno::Type > maTypeSequence;
+
+ OUString maBuildId;
+
+ void initializeDocument();
+
+ sd::DrawViewShell* GetViewShell();
+
+ /** abstract SdrModel provider */
+ virtual SdrModel& getSdrModelFromUnoModel() const override;
+
+public:
+ SdXImpressDocument(::sd::DrawDocShell* pShell, bool bClipBoard);
+ SdXImpressDocument(SdDrawDocument* pDoc, bool bClipBoard);
+ virtual ~SdXImpressDocument() noexcept override;
+
+ static rtl::Reference< SdXImpressDocument > GetModel( SdDrawDocument const & rDoc );
+
+ // intern
+ bool operator==( const SdXImpressDocument& rModel ) const { return mpDoc == rModel.mpDoc; }
+ bool operator!=( const SdXImpressDocument& rModel ) const { return mpDoc != rModel.mpDoc; }
+
+ ::sd::DrawDocShell* GetDocShell() const { return mpDocShell; }
+ SdDrawDocument* GetDoc() const { return mpDoc; }
+ bool IsImpressDocument() const { return mbImpressDoc; }
+
+ void SetModified() noexcept;
+
+ css::uno::Reference< css::i18n::XForbiddenCharacters > getForbiddenCharsTable();
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ UNO3_GETIMPLEMENTATION_DECL(SdXImpressDocument)
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XModel
+ virtual void SAL_CALL lockControllers( ) override;
+ virtual void SAL_CALL unlockControllers( ) override;
+ virtual sal_Bool SAL_CALL hasControllersLocked( ) override;
+ virtual css::uno::Reference < css::container::XIndexAccess > SAL_CALL getViewData() override;
+ virtual void SAL_CALL setViewData( const css::uno::Reference < css::container::XIndexAccess >& aData ) override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // XDrawPageDuplicator
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL duplicate( const css::uno::Reference< css::drawing::XDrawPage >& xPage ) override;
+
+ // XDrawPagesSupplier
+ virtual css::uno::Reference< css::drawing::XDrawPages > SAL_CALL getDrawPages( ) override;
+
+ // XMasterPagesSupplier
+ virtual css::uno::Reference< css::drawing::XDrawPages > SAL_CALL getMasterPages( ) override;
+
+ // XLayerManagerSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getLayerManager( ) override;
+
+ // XCustomPresentationSupplier
+ virtual css::uno::Reference< css::container::XNameContainer > SAL_CALL getCustomPresentations( ) override;
+
+ // XHandoutMasterSupplier
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getHandoutMasterPage( ) override;
+
+ // XPresentationSupplier
+ virtual css::uno::Reference< css::presentation::XPresentation > SAL_CALL getPresentation( ) override;
+
+ // XMultiServiceFactory ( SvxFmMSFactory )
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( const OUString& aServiceSpecifier ) override;
+ virtual css::uno::Reference<css::uno::XInterface> SAL_CALL
+ createInstanceWithArguments(
+ OUString const & ServiceSpecifier,
+ css::uno::Sequence<css::uno::Any> const & Arguments) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // XLinkTargetSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getLinks( ) override;
+
+ // XStyleFamiliesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getStyleFamilies( ) override;
+
+ // XAnyCompareFactory
+ virtual css::uno::Reference< css::ucb::XAnyCompare > SAL_CALL createAnyCompareByName( const OUString& PropertyName ) override;
+
+ // XRenderable
+ virtual sal_Int32 SAL_CALL getRendererCount( const css::uno::Any& aSelection, const css::uno::Sequence< css::beans::PropertyValue >& xOptions ) override;
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getRenderer( sal_Int32 nRenderer, const css::uno::Any& aSelection, const css::uno::Sequence< css::beans::PropertyValue >& xOptions ) override;
+ virtual void SAL_CALL render( sal_Int32 nRenderer, const css::uno::Any& aSelection, const css::uno::Sequence< css::beans::PropertyValue >& xOptions ) override;
+
+ // ITiledRenderable
+ virtual void paintTile( VirtualDevice& rDevice,
+ int nOutputWidth,
+ int nOutputHeight,
+ int nTilePosX,
+ int nTilePosY,
+ tools::Long nTileWidth,
+ tools::Long nTileHeight ) override;
+ virtual Size getDocumentSize() override;
+ virtual void setPart( int nPart, bool bAllowChangeFocus = true ) override;
+ virtual int getPart() override;
+ virtual int getParts() override;
+ virtual OUString getPartName( int nPart ) override;
+ virtual OUString getPartHash( int nPart ) override;
+ virtual VclPtr<vcl::Window> getDocWindow() override;
+ bool isMasterViewMode();
+
+ virtual void setPartMode( int nPartMode ) override;
+
+ /// @see vcl::ITiledRenderable::initializeForTiledRendering().
+ virtual void initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments) override;
+ /// @see vcl::ITiledRenderable::postKeyEvent().
+ virtual void postKeyEvent(int nType, int nCharCode, int nKeyCode) override;
+ /// @see vcl::ITiledRenderable::postMouseEvent().
+ virtual void postMouseEvent(int nType, int nX, int nY, int nCount, int nButtons, int nModifier) override;
+ /// @see vcl::ITiledRenderable::setTextSelection().
+ virtual void setTextSelection(int nType, int nX, int nY) override;
+ /// @see vcl::ITiledRenderable::getSelection().
+ virtual css::uno::Reference<css::datatransfer::XTransferable> getSelection() override;
+ /// @see vcl::ITiledRenderable::setGraphicSelection().
+ virtual void setGraphicSelection(int nType, int nX, int nY) override;
+ /// @see lok::Document::resetSelection().
+ virtual void resetSelection() override;
+ /// @see vcl::ITiledRenderable::setClientVisibleArea().
+ virtual void setClientVisibleArea(const tools::Rectangle& rRectangle) override;
+ /// @see vcl::ITiledRenderable::setClipboard().
+ virtual void setClipboard(const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& xClipboard) override;
+ /// @see vcl::ITiledRenderable::isMimeTypeSupported().
+ virtual bool isMimeTypeSupported() override;
+ /// @see vcl::ITiledRenderable::getPointer().
+ virtual PointerStyle getPointer() override;
+ /// @see vcl::ITiledRenderable::getPostIts().
+ virtual void getPostIts(tools::JsonWriter& /*rJsonWriter*/) override;
+ /// @see vcl::ITiledRenderable::selectPart().
+ virtual void selectPart(int nPart, int nSelect) override;
+ /// @see vcl::ITiledRenderable::moveSelectedParts().
+ virtual void moveSelectedParts(int nPosition, bool bDuplicate) override;
+ /// @see vcl::ITiledRenderable::getPartInfo().
+ virtual OUString getPartInfo(int nPart) override;
+ /// @see vcl::ITiledRenderable::isDisposed().
+ virtual bool isDisposed() const override
+ {
+ return mbDisposed;
+ }
+
+ // XComponent
+
+ /** This dispose implementation releases the resources held by the
+ called object and forwards the call to its base class.
+ When close() has not yet been called then this is done first. As a
+ consequence the implementation has to cope with being called twice
+ and still has to forward the second call to the base class.
+ See also comments of issue 27847.
+ */
+ virtual void SAL_CALL dispose() override;
+};
+
+/***********************************************************************
+* *
+***********************************************************************/
+
+class SdDrawPagesAccess final : public ::cppu::WeakImplHelper< css::drawing::XDrawPages, css::container::XNameAccess, css::lang::XServiceInfo, css::lang::XComponent >
+{
+private:
+ SdXImpressDocument* mpModel;
+
+public:
+ SdDrawPagesAccess( SdXImpressDocument& rMyModel ) noexcept;
+ virtual ~SdDrawPagesAccess() noexcept override;
+
+ // XDrawPages
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL insertNewByIndex( sal_Int32 nIndex ) override;
+ virtual void SAL_CALL remove( const css::uno::Reference< css::drawing::XDrawPage >& xPage ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+};
+
+/***********************************************************************
+* *
+***********************************************************************/
+
+class SdMasterPagesAccess final : public ::cppu::WeakImplHelper< css::drawing::XDrawPages, css::lang::XServiceInfo, css::lang::XComponent >
+{
+private:
+ SdXImpressDocument* mpModel;
+
+public:
+ SdMasterPagesAccess( SdXImpressDocument& rMyModel ) noexcept;
+ virtual ~SdMasterPagesAccess() noexcept override;
+
+ // XDrawPages
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL insertNewByIndex( sal_Int32 nIndex ) override;
+ virtual void SAL_CALL remove( const css::uno::Reference< css::drawing::XDrawPage >& xPage ) override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+};
+
+/***********************************************************************
+* *
+***********************************************************************/
+
+class SdDocLinkTargets final : public ::cppu::WeakImplHelper< css::container::XNameAccess,
+ css::lang::XServiceInfo , css::lang::XComponent >
+{
+private:
+ SdXImpressDocument* mpModel;
+
+public:
+ SdDocLinkTargets( SdXImpressDocument& rMyModel ) noexcept;
+ virtual ~SdDocLinkTargets() noexcept override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // intern
+ /// @throws std::exception
+ SdPage* FindPage( std::u16string_view rName ) const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/unopage.hxx b/sd/source/ui/inc/unopage.hxx
new file mode 100644
index 000000000..af09e5982
--- /dev/null
+++ b/sd/source/ui/inc/unopage.hxx
@@ -0,0 +1,304 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/document/XLinkTargetSupplier.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/XMasterPageTarget.hpp>
+#include <com/sun/star/drawing/XShapeCombiner.hpp>
+#include <com/sun/star/drawing/XShapeBinder.hpp>
+#include <com/sun/star/presentation/XPresentationPage.hpp>
+#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/office/XAnnotationAccess.hpp>
+
+#include <svx/unopage.hxx>
+#include <svx/fmdpage.hxx>
+
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include "unosrch.hxx"
+#include <sdpage.hxx>
+
+class SdrObject;
+class SdXImpressDocument;
+
+class SdGenericDrawPage : public SvxFmDrawPage,
+ public SdUnoSearchReplaceShape,
+ public css::drawing::XShapeCombiner,
+ public css::drawing::XShapeBinder,
+ public css::container::XNamed,
+ public css::beans::XPropertySet,
+ public css::beans::XMultiPropertySet,
+ public css::animations::XAnimationNodeSupplier,
+ public css::office::XAnnotationAccess,
+ public css::document::XLinkTargetSupplier
+{
+private:
+ SdXImpressDocument* mpDocModel;
+ SdrModel* mpSdrModel;
+ bool mbIsImpressDocument;
+ sal_Int16 mnTempPageNumber; // for printing handouts
+
+ void UpdateModel();
+
+protected:
+ friend class SdXImpressDocument;
+
+ const SvxItemPropertySet* mpPropSet;
+
+ /// @throws css::lang::IllegalArgumentException
+ virtual void setBackground( const css::uno::Any& rValue );
+ /// @throws std::exception
+ virtual void getBackground( css::uno::Any& rValue );
+
+ OUString getBookmarkURL() const;
+ void setBookmarkURL( std::u16string_view rURL );
+
+ void SetLeftBorder( sal_Int32 nValue );
+ void SetRightBorder( sal_Int32 nValue );
+ void SetUpperBorder( sal_Int32 nValue );
+ void SetLowerBorder( sal_Int32 nValue );
+
+ void SetWidth( sal_Int32 nWidth );
+ void SetHeight( sal_Int32 nHeight );
+
+ bool IsImpressDocument() const;
+
+ virtual void disposing() noexcept override;
+
+ css::uno::Any getNavigationOrder();
+ void setNavigationOrder( const css::uno::Any& rValue );
+
+ /// @throws css::uno::RuntimeException
+ void throwIfDisposed() const;
+
+public:
+ SdGenericDrawPage(SdXImpressDocument* pModel, SdPage* pInPage, const SvxItemPropertySet* pSet);
+ virtual ~SdGenericDrawPage() noexcept override;
+
+ // intern
+ bool isValid() const { return (SvxDrawPage::mpPage != nullptr) && (mpModel != nullptr); }
+
+ SdPage* GetPage() const { return static_cast<SdPage*>(SvxDrawPage::mpPage); }
+ SdXImpressDocument* GetModel() const;
+
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId() noexcept;
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+
+ // this is called whenever a SdrObject must be created for an empty api shape wrapper
+ virtual SdrObject *CreateSdrObject_( const css::uno::Reference< css::drawing::XShape >& xShape ) override;
+
+ // SvxFmDrawPage
+ virtual css::uno::Reference<css::drawing::XShape> CreateShape(SdrObject *pObj) const override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XShapeCombiner
+ virtual css::uno::Reference< css::drawing::XShape > SAL_CALL combine( const css::uno::Reference< css::drawing::XShapes >& xShapes ) override;
+ virtual void SAL_CALL split( const css::uno::Reference< css::drawing::XShape >& xGroup ) override;
+
+ // XShapeBinder
+ virtual css::uno::Reference< css::drawing::XShape > SAL_CALL bind( const css::uno::Reference< css::drawing::XShapes >& xShapes ) override;
+ virtual void SAL_CALL unbind( const css::uno::Reference< css::drawing::XShape >& xShape ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // XMultiPropertySet
+ virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override;
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override;
+ virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+
+ // XLinkTargetSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getLinks( ) override;
+
+ // XServiceInfo
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XAnimationNodeSupplier
+ virtual css::uno::Reference< css::animations::XAnimationNode > SAL_CALL getAnimationNode( ) override;
+
+ // XAnnotationAccess:
+ virtual css::uno::Reference< css::office::XAnnotation > SAL_CALL createAndInsertAnnotation() override;
+ virtual void SAL_CALL removeAnnotation(const css::uno::Reference< css::office::XAnnotation > & annotation) override;
+ virtual css::uno::Reference< css::office::XAnnotationEnumeration > SAL_CALL createAnnotationEnumeration() override;
+};
+
+/***********************************************************************
+* *
+***********************************************************************/
+
+class SdDrawPage final : public css::drawing::XMasterPageTarget,
+ public css::presentation::XPresentationPage,
+ public SdGenericDrawPage
+{
+private:
+ css::uno::Sequence< css::uno::Type > maTypeSequence;
+
+ virtual void setBackground( const css::uno::Any& rValue ) override;
+ virtual void getBackground( css::uno::Any& rValue ) override;
+public:
+ SdDrawPage(SdXImpressDocument* pModel, SdPage* pInPage);
+ virtual ~SdDrawPage() noexcept override;
+
+ UNO3_GETIMPLEMENTATION_DECL( SdDrawPage )
+
+ static OUString getPageApiName( SdPage const * pPage );
+ static OUString getPageApiNameFromUiName( const OUString& rUIName );
+ static OUString getUiNameFromPageApiName( const OUString& rApiName );
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XMasterPageTarget
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getMasterPage( ) override;
+ virtual void SAL_CALL setMasterPage( const css::uno::Reference< css::drawing::XDrawPage >& xMasterPage ) override;
+
+ // XPresentationPage
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getNotesPage( ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XShapes
+ virtual void SAL_CALL add( const css::uno::Reference< css::drawing::XShape >& xShape ) override;
+ virtual void SAL_CALL remove( const css::uno::Reference< css::drawing::XShape >& xShape ) override;
+};
+
+/***********************************************************************
+* *
+***********************************************************************/
+
+class SdMasterPage final : public css::presentation::XPresentationPage,
+ public SdGenericDrawPage
+{
+private:
+ css::uno::Sequence< css::uno::Type > maTypeSequence;
+
+ virtual void setBackground( const css::uno::Any& rValue ) override;
+ virtual void getBackground( css::uno::Any& rValue ) override;
+
+public:
+ SdMasterPage(SdXImpressDocument* pModel, SdPage* pInPage);
+ virtual ~SdMasterPage() noexcept override;
+
+ UNO3_GETIMPLEMENTATION_DECL(SdMasterPage)
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XPresentationPage
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getNotesPage( ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+
+ // XShapes
+ virtual void SAL_CALL add( const css::uno::Reference< css::drawing::XShape >& xShape ) override;
+ virtual void SAL_CALL remove( const css::uno::Reference< css::drawing::XShape >& xShape ) override;
+};
+
+/***********************************************************************
+* *
+***********************************************************************/
+
+class SdPageLinkTargets final : public ::cppu::WeakImplHelper< css::container::XNameAccess,
+ css::lang::XServiceInfo >
+{
+private:
+ css::uno::Reference< css::drawing::XDrawPage > mxPage;
+ SdGenericDrawPage* mpUnoPage;
+
+public:
+ SdPageLinkTargets( SdGenericDrawPage* pUnoPage ) noexcept;
+ virtual ~SdPageLinkTargets() noexcept override;
+
+ // intern
+ SdrObject* FindObject( std::u16string_view rName ) const noexcept;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+};
+
+OUString getUiNameFromPageApiNameImpl( const OUString& rApiName );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/unoprnms.hxx b/sd/source/ui/inc/unoprnms.hxx
new file mode 100644
index 000000000..1d3a90552
--- /dev/null
+++ b/sd/source/ui/inc/unoprnms.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+
+#define UNO_NAME_PAGE_BACKGROUND "Background"
+#define UNO_NAME_PAGE_LEFT "BorderLeft"
+#define UNO_NAME_PAGE_RIGHT "BorderRight"
+#define UNO_NAME_PAGE_TOP "BorderTop"
+#define UNO_NAME_PAGE_BOTTOM "BorderBottom"
+#define UNO_NAME_PAGE_CHANGE "Change"
+#define UNO_NAME_PAGE_DURATION "Duration"
+#define UNO_NAME_PAGE_EFFECT "Effect"
+#define UNO_NAME_PAGE_HEIGHT "Height"
+#define UNO_NAME_PAGE_LAYOUT "Layout"
+#define UNO_NAME_PAGE_NUMBER "Number"
+#define UNO_NAME_PAGE_ORIENTATION "Orientation"
+#define UNO_NAME_PAGE_SPEED "Speed"
+#define UNO_NAME_PAGE_TRANSITION_DURATION "TransitionDuration"
+#define UNO_NAME_PAGE_WIDTH "Width"
+#define UNO_NAME_PAGE_PREVIEW "Preview"
+#define UNO_NAME_PAGE_PREVIEWBITMAP "PreviewBitmap"
+#define UNO_NAME_PAGE_PREVIEWMETAFILE "PreviewMetafile"
+#define UNO_NAME_PAGE_VISIBLE "Visible"
+
+#define UNO_NAME_OBJ_BOOKMARK "Bookmark"
+#define UNO_NAME_OBJ_DIMCOLOR "DimColor"
+#define UNO_NAME_OBJ_DIMHIDE "DimHide"
+#define UNO_NAME_OBJ_DIMPREV "DimPrevious"
+#define UNO_NAME_OBJ_EFFECT "Effect"
+#define UNO_NAME_OBJ_ISEMPTYPRESOBJ "IsEmptyPresentationObject"
+#define UNO_NAME_OBJ_ISPRESOBJ "IsPresentationObject"
+#define UNO_NAME_OBJ_CLICKACTION "OnClick"
+#define UNO_NAME_OBJ_PLAYFULL "PlayFull"
+#define UNO_NAME_OBJ_PRESORDER "PresentationOrder"
+#define UNO_NAME_OBJ_SOUNDFILE "Sound"
+#define UNO_NAME_OBJ_SOUNDON "SoundOn"
+#define UNO_NAME_OBJ_SPEED "Speed"
+#define UNO_NAME_OBJ_TEXTEFFECT "TextEffect"
+#define UNO_NAME_OBJ_BLUESCREEN "TransparentColor"
+#define UNO_NAME_OBJ_VERB "Verb"
+#define UNO_NAME_OBJ_STYLE "Style"
+#define UNO_NAME_OBJ_MASTERDEPENDENT "IsPlaceholderDependent"
+#define UNO_NAME_OBJ_ANIMATIONPATH "AnimationPath"
+#define UNO_NAME_OBJ_LEGACYFRAGMENT "LegacyFragment"
+
+#define UNO_NAME_LAYER_LOCKED "IsLocked"
+#define UNO_NAME_LAYER_PRINTABLE "IsPrintable"
+#define UNO_NAME_LAYER_VISIBLE "IsVisible"
+#define UNO_NAME_LAYER_NAME "Name"
+
+
+#define UNO_NAME_SEARCH_BACKWARDS "SearchBackwards"
+#define UNO_NAME_SEARCH_CASE "SearchCaseSensitive"
+#define UNO_NAME_SEARCH_WORDS "SearchWords"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/unosrch.hxx b/sd/source/ui/inc/unosrch.hxx
new file mode 100644
index 000000000..6dcf681cb
--- /dev/null
+++ b/sd/source/ui/inc/unosrch.hxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <com/sun/star/util/XReplaceable.hpp>
+#include <com/sun/star/util/XReplaceDescriptor.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <editeng/editdata.hxx>
+
+namespace com::sun::star::drawing { class XDrawPage; }
+namespace com::sun::star::drawing { class XShape; }
+namespace com::sun::star::text { class XTextRange; }
+namespace com::sun::star::util { class XSearchDescriptor; }
+
+class SvxItemPropertySet;
+class SdUnoSearchReplaceDescriptor;
+
+/** this class implements a search or replace operation on a given page or a given sdrobj */
+class SdUnoSearchReplaceShape : public css::util::XReplaceable
+{
+protected:
+ css::drawing::XDrawPage* mpPage;
+
+ css::uno::Reference< css::text::XTextRange > Search( const css::uno::Reference< css::text::XTextRange >& xText, SdUnoSearchReplaceDescriptor* pDescr );
+ bool Search( const OUString& rText, sal_Int32& nStartPos, sal_Int32& nEndPos, SdUnoSearchReplaceDescriptor* pDescr ) noexcept;
+ static ESelection GetSelection( const css::uno::Reference< css::text::XTextRange >& xTextRange ) noexcept;
+ static css::uno::Reference< css::drawing::XShape > GetShape( const css::uno::Reference< css::text::XTextRange >& xTextRange ) noexcept;
+ css::uno::Reference< css::drawing::XShape > GetNextShape( const css::uno::Reference< css::container::XIndexAccess >& xShapes, const css::uno::Reference< css::drawing::XShape >& xCurrentShape ) noexcept;
+ css::uno::Reference< css::drawing::XShape > GetCurrentShape() const noexcept;
+
+public:
+ // danger, this c'tor is only usable if the given shape or page is derived
+ // from this class!!!
+ SdUnoSearchReplaceShape( css::drawing::XDrawPage* xPage ) noexcept;
+ virtual ~SdUnoSearchReplaceShape() noexcept;
+
+ // XReplaceable
+ virtual css::uno::Reference< css::util::XReplaceDescriptor > SAL_CALL createReplaceDescriptor( ) override;
+ virtual sal_Int32 SAL_CALL replaceAll( const css::uno::Reference< css::util::XSearchDescriptor >& xDesc ) override;
+
+ // XSearchable
+ virtual css::uno::Reference< css::util::XSearchDescriptor > SAL_CALL createSearchDescriptor( ) override;
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL findAll( const css::uno::Reference< css::util::XSearchDescriptor >& xDesc ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL findFirst( const css::uno::Reference< css::util::XSearchDescriptor >& xDesc ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL findNext( const css::uno::Reference< css::uno::XInterface >& xStartAt, const css::uno::Reference< css::util::XSearchDescriptor >& xDesc ) override;
+};
+
+/* ================================================================= */
+
+/** this class holds the parameters and status of a search or replace operation performed
+ by class SdUnoSearchReplaceShape */
+
+class SdUnoSearchReplaceDescriptor final : public ::cppu::WeakImplHelper< css::lang::XUnoTunnel, css::util::XReplaceDescriptor > // public css::util::XSearchDescriptor, css::beans::XPropertySet
+{
+ std::unique_ptr<SvxItemPropertySet> mpPropSet;
+
+ bool mbBackwards;
+ bool mbCaseSensitive;
+ bool mbWords;
+
+ OUString maSearchStr;
+ OUString maReplaceStr;
+
+public:
+ /// @throws css::uno::RuntimeException
+ SdUnoSearchReplaceDescriptor();
+ virtual ~SdUnoSearchReplaceDescriptor() noexcept override;
+
+ bool IsCaseSensitive() const { return mbCaseSensitive; }
+ bool IsWords() const { return mbWords; }
+
+ UNO3_GETIMPLEMENTATION_DECL( SdUnoSearchReplaceDescriptor )
+
+ // XSearchDescriptor
+ virtual OUString SAL_CALL getSearchString( ) override;
+ virtual void SAL_CALL setSearchString( const OUString& aString ) override;
+
+ // XReplaceDescriptor
+ virtual OUString SAL_CALL getReplaceString( ) override;
+ virtual void SAL_CALL setReplaceString( const OUString& aReplaceString ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+};
+
+/* ================================================================= */
+
+/** this class holds a sequence that is a result from a find all and
+ lets people access it through the XIndexAccess Interface. */
+class SdUnoFindAllAccess final : public ::cppu::WeakImplHelper< css::container::XIndexAccess > // public css::container::XElementAccess
+{
+ css::uno::Sequence< css::uno::Reference< css::uno::XInterface > > maSequence;
+
+public:
+ SdUnoFindAllAccess( css::uno::Sequence< css::uno::Reference< css::uno::XInterface > > const & rSequence ) noexcept;
+ virtual ~SdUnoFindAllAccess() noexcept override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/unprlout.hxx b/sd/source/ui/inc/unprlout.hxx
new file mode 100644
index 000000000..8d75204f1
--- /dev/null
+++ b/sd/source/ui/inc/unprlout.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <xmloff/autolayout.hxx>
+
+#include <sdundo.hxx>
+
+class SdDrawDocument;
+class SdPage;
+
+class SdPresentationLayoutUndoAction final : public SdUndoAction
+{
+ OUString aOldLayoutName;
+ OUString aNewLayoutName;
+ AutoLayout eOldAutoLayout;
+ AutoLayout eNewAutoLayout;
+ bool bSetAutoLayout; // sal_True: change AutoLayout
+ SdPage* pPage;
+ OUString aComment;
+
+public:
+ SdPresentationLayoutUndoAction(SdDrawDocument* pTheDoc,
+ const OUString& aTheOldLayoutName,
+ const OUString& aTheNewLayoutName,
+ AutoLayout eTheOldAutoLayout,
+ AutoLayout eTheNewAutoLayout,
+ bool bSet,
+ SdPage* pThePage);
+
+ virtual ~SdPresentationLayoutUndoAction() override;
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+ virtual OUString GetComment() const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/vectdlg.hxx b/sd/source/ui/inc/vectdlg.hxx
new file mode 100644
index 000000000..ac7a1bfd4
--- /dev/null
+++ b/sd/source/ui/inc/vectdlg.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <svx/graphctl.hxx>
+
+namespace sd {
+class DrawDocShell;
+}
+
+/******************************************************************************
+|*
+|* SdVectorizeDlg
+|*
+\******************************************************************************/
+
+class SdVectorizeDlg final : public weld::GenericDialogController
+{
+ ::sd::DrawDocShell* m_pDocSh;
+ Bitmap aBmp;
+ Bitmap aPreviewBmp;
+ GDIMetaFile aMtf;
+
+ GraphCtrl m_aBmpWin;
+ GraphCtrl m_aMtfWin;
+
+ std::unique_ptr<weld::SpinButton> m_xNmLayers;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtReduce;
+ std::unique_ptr<weld::Label> m_xFtFillHoles;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtFillHoles;
+ std::unique_ptr<weld::CheckButton> m_xCbFillHoles;
+ std::unique_ptr<weld::CustomWeld> m_xBmpWin;
+ std::unique_ptr<weld::CustomWeld> m_xMtfWin;
+ std::unique_ptr<weld::ProgressBar> m_xPrgs;
+ std::unique_ptr<weld::Button> m_xBtnOK;
+ std::unique_ptr<weld::Button> m_xBtnPreview;
+
+ void LoadSettings();
+ void SaveSettings() const;
+ void InitPreviewBmp();
+
+ static ::tools::Rectangle GetRect( const Size& rDispSize, const Size& rBmpSize );
+ Bitmap GetPreparedBitmap( Bitmap const & rBmp, Fraction& rScale );
+ void Calculate( Bitmap const & rBmp, GDIMetaFile& rMtf );
+ static void AddTile( BitmapReadAccess const * pRAcc, GDIMetaFile& rMtf,
+ tools::Long nPosX, tools::Long nPosY, tools::Long nWidth, tools::Long nHeight );
+
+ DECL_LINK( ProgressHdl, tools::Long, void );
+ DECL_LINK( ClickPreviewHdl, weld::Button&, void );
+ DECL_LINK( ClickOKHdl, weld::Button&, void );
+ DECL_LINK( ToggleHdl, weld::Toggleable&, void );
+ DECL_LINK( ModifyHdl, weld::SpinButton&, void );
+ DECL_LINK( MetricModifyHdl, weld::MetricSpinButton&, void );
+
+public:
+
+ SdVectorizeDlg(weld::Window* pParent, const Bitmap& rBmp, ::sd::DrawDocShell* pDocShell);
+ virtual ~SdVectorizeDlg() override;
+
+ const GDIMetaFile& GetGDIMetaFile() const { return aMtf; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/view/viewoverlaymanager.hxx b/sd/source/ui/inc/view/viewoverlaymanager.hxx
new file mode 100644
index 000000000..3a5c98deb
--- /dev/null
+++ b/sd/source/ui/inc/view/viewoverlaymanager.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ref.hxx>
+#include <tools/link.hxx>
+#include <svl/lstner.hxx>
+
+#include <vector>
+
+namespace sd
+{
+class SmartTag;
+}
+namespace sd::tools
+{
+class EventMultiplexerEvent;
+}
+namespace sd
+{
+class ViewShellBase;
+}
+struct ImplSVEvent;
+
+namespace sd
+{
+typedef std::vector<rtl::Reference<SmartTag>> ViewTagVector;
+
+class ViewOverlayManager final : public SfxListener
+{
+public:
+ ViewOverlayManager(ViewShellBase& rViewShellBase);
+ virtual ~ViewOverlayManager() override;
+
+ void onZoomChanged();
+ void UpdateTags();
+
+ DECL_LINK(EventMultiplexerListener, tools::EventMultiplexerEvent&, void);
+ DECL_LINK(UpdateTagsHdl, void*, void);
+
+ bool CreateTags();
+ bool DisposeTags();
+
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+private:
+ ViewShellBase& mrBase;
+ ImplSVEvent* mnUpdateTagsEvent;
+
+ ViewTagVector maTagVector;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/zoomlist.hxx b/sd/source/ui/inc/zoomlist.hxx
new file mode 100644
index 000000000..b7f7da79d
--- /dev/null
+++ b/sd/source/ui/inc/zoomlist.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <tools/gen.hxx>
+
+namespace sd
+{
+class ViewShell;
+
+class ZoomList
+{
+public:
+ ZoomList(ViewShell* pViewShell);
+
+ void InsertZoomRect(const ::tools::Rectangle& rRect);
+ ::tools::Rectangle const& GetNextZoomRect();
+ ::tools::Rectangle const& GetPreviousZoomRect();
+ bool IsNextPossible() const;
+ bool IsPreviousPossible() const;
+
+private:
+ ViewShell* mpViewShell;
+ sal_uInt32 mnCurPos;
+
+ std::vector<::tools::Rectangle> maRectangles;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/CanvasUpdateRequester.cxx b/sd/source/ui/presenter/CanvasUpdateRequester.cxx
new file mode 100644
index 000000000..2271ba781
--- /dev/null
+++ b/sd/source/ui/presenter/CanvasUpdateRequester.cxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "CanvasUpdateRequester.hxx"
+#include <vcl/svapp.hxx>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/rendering/XSpriteCanvas.hpp>
+#include <cppuhelper/weakref.hxx>
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::presenter {
+
+//===== CanvasUpdateRequester::Deleter ========================================
+
+class CanvasUpdateRequester::Deleter
+{
+public:
+ void operator() (CanvasUpdateRequester* pObject) { delete pObject; }
+};
+
+//===== CanvasUpdateRequester =================================================
+
+std::shared_ptr<CanvasUpdateRequester> CanvasUpdateRequester::Instance (
+ const Reference<rendering::XSpriteCanvas>& rxSharedCanvas)
+{
+ // this global must not own anything or we crash on shutdown
+ static std::vector<std::pair<
+ uno::WeakReference<rendering::XSpriteCanvas>,
+ std::weak_ptr<CanvasUpdateRequester>>> s_RequesterMap;
+ for (auto it = s_RequesterMap.begin(); it != s_RequesterMap.end(); )
+ {
+ uno::Reference<rendering::XSpriteCanvas> const xCanvas(it->first);
+ if (!xCanvas.is())
+ {
+ it = s_RequesterMap.erase(it); // remove stale entry
+ }
+ else if (xCanvas == rxSharedCanvas)
+ {
+ std::shared_ptr<CanvasUpdateRequester> pRequester(it->second);
+ if (pRequester)
+ {
+ return pRequester;
+ }
+ else
+ {
+ std::shared_ptr<CanvasUpdateRequester> const pNew(
+ new CanvasUpdateRequester(rxSharedCanvas), Deleter());
+ it->second = pNew;
+ return pNew;
+ }
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ // No requester for the given canvas found. Create a new one.
+ std::shared_ptr<CanvasUpdateRequester> pRequester (
+ new CanvasUpdateRequester(rxSharedCanvas), Deleter());
+ s_RequesterMap.emplace_back(rxSharedCanvas, pRequester);
+ return pRequester;
+}
+
+
+CanvasUpdateRequester::CanvasUpdateRequester (
+ const Reference<rendering::XSpriteCanvas>& rxCanvas)
+ : mxCanvas(rxCanvas)
+ , m_pUserEventId(nullptr)
+ , mbUpdateFlag(false)
+{
+ Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
+ if (xComponent.is())
+ {
+ //xComponent->addEventListener(this);
+ }
+}
+
+CanvasUpdateRequester::~CanvasUpdateRequester()
+{
+ assert(m_pUserEventId == nullptr);
+}
+
+void CanvasUpdateRequester::RequestUpdate (const bool bUpdateAll)
+{
+ if (m_pUserEventId == nullptr)
+ {
+ m_pThis = shared_from_this(); // keep instance alive until dispatch
+ mbUpdateFlag = bUpdateAll;
+ m_pUserEventId = Application::PostUserEvent(LINK(this, CanvasUpdateRequester, Callback));
+ }
+ else
+ {
+ mbUpdateFlag |= bUpdateAll;
+ }
+}
+
+IMPL_LINK_NOARG(CanvasUpdateRequester, Callback, void*, void)
+{
+ m_pUserEventId = nullptr;
+ if (mxCanvas.is())
+ {
+ mxCanvas->updateScreen(mbUpdateFlag);
+ mbUpdateFlag = false;
+ }
+ assert(m_pThis);
+ m_pThis.reset(); // possibly delete "this"
+}
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/CanvasUpdateRequester.hxx b/sd/source/ui/presenter/CanvasUpdateRequester.hxx
new file mode 100644
index 000000000..ebb582ead
--- /dev/null
+++ b/sd/source/ui/presenter/CanvasUpdateRequester.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <tools/link.hxx>
+#include <memory>
+
+namespace com::sun::star::rendering
+{
+class XSpriteCanvas;
+}
+
+struct ImplSVEvent;
+
+namespace sd::presenter
+{
+/** Each UpdateRequester handles update requests (calls to
+ XCanvas::updateScreen()) for one shared canvas (a canvas that has one or
+ more PresenterCanvas wrappers). Multiple calls are collected and lead
+ to a single call to updateScreen.
+*/
+class CanvasUpdateRequester : public std::enable_shared_from_this<CanvasUpdateRequester>
+{
+public:
+ CanvasUpdateRequester(const CanvasUpdateRequester&) = delete;
+ CanvasUpdateRequester& operator=(const CanvasUpdateRequester&) = delete;
+
+ /** @return the Canvas UpdateRequester object for the given shared canvas.
+ A new object is created when it does not already exist.
+ */
+ static std::shared_ptr<CanvasUpdateRequester>
+ Instance(const css::uno::Reference<css::rendering::XSpriteCanvas>& rxCanvas);
+
+ void RequestUpdate(const bool bUpdateAll);
+
+private:
+ explicit CanvasUpdateRequester(
+ const css::uno::Reference<css::rendering::XSpriteCanvas>& rxCanvas);
+ ~CanvasUpdateRequester();
+ class Deleter;
+ friend class Deleter;
+
+ /// keep instance alive waiting for event dispatch
+ std::shared_ptr<CanvasUpdateRequester> m_pThis;
+ css::uno::Reference<css::rendering::XSpriteCanvas> mxCanvas;
+ ImplSVEvent* m_pUserEventId;
+ bool mbUpdateFlag;
+
+ DECL_LINK(Callback, void*, void);
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterCanvas.cxx b/sd/source/ui/presenter/PresenterCanvas.cxx
new file mode 100644
index 000000000..f586969bc
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterCanvas.cxx
@@ -0,0 +1,790 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PresenterCanvas.hxx"
+#include "CanvasUpdateRequester.hxx"
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/utils/canvastools.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <comphelper/compbase.hxx>
+#include <rtl/ref.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/window.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::presenter {
+
+//===== PresenterCustomSprite =================================================
+
+/** Wrapper around a sprite that is displayed on a PresenterCanvas.
+*/
+namespace {
+ typedef comphelper::WeakComponentImplHelper <
+ css::rendering::XCustomSprite
+ > PresenterCustomSpriteInterfaceBase;
+
+class PresenterCustomSprite final
+ : public PresenterCustomSpriteInterfaceBase
+{
+public:
+ PresenterCustomSprite (
+ const rtl::Reference<PresenterCanvas>& rpCanvas,
+ const Reference<rendering::XCustomSprite>& rxSprite,
+ const Reference<awt::XWindow>& rxBaseWindow);
+ PresenterCustomSprite(const PresenterCustomSprite&) = delete;
+ PresenterCustomSprite& operator=(const PresenterCustomSprite&) = delete;
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XSprite
+
+ virtual void SAL_CALL setAlpha (double nAlpha) override;
+
+ virtual void SAL_CALL move (const geometry::RealPoint2D& rNewPos,
+ const rendering::ViewState& rViewState,
+ const rendering::RenderState& rRenderState) override;
+
+ virtual void SAL_CALL transform (const geometry::AffineMatrix2D& rTransformation) override;
+
+ virtual void SAL_CALL clip (const Reference<rendering::XPolyPolygon2D>& rClip) override;
+
+ virtual void SAL_CALL setPriority (double nPriority) override;
+
+ virtual void SAL_CALL show() override;
+
+ virtual void SAL_CALL hide() override;
+
+ // XCustomSprite
+
+ virtual Reference<rendering::XCanvas> SAL_CALL getContentCanvas() override;
+
+private:
+ rtl::Reference<PresenterCanvas> mpCanvas;
+ Reference<rendering::XCustomSprite> mxSprite;
+ Reference<awt::XWindow> mxBaseWindow;
+ geometry::RealPoint2D maPosition;
+
+ /// @throws css::lang::DisposedException
+ void ThrowIfDisposed();
+};
+
+}
+
+//===== PresenterCanvas =======================================================
+
+PresenterCanvas::PresenterCanvas (
+ const Reference<rendering::XSpriteCanvas>& rxUpdateCanvas,
+ const Reference<awt::XWindow>& rxUpdateWindow,
+ const Reference<rendering::XCanvas>& rxSharedCanvas,
+ const Reference<awt::XWindow>& rxSharedWindow,
+ const Reference<awt::XWindow>& rxWindow)
+ : mxUpdateCanvas(rxUpdateCanvas),
+ mxUpdateWindow(rxUpdateWindow),
+ mxSharedCanvas(rxSharedCanvas),
+ mxSharedWindow(rxSharedWindow),
+ mxWindow(rxWindow),
+ mbOffsetUpdatePending(true)
+{
+ if (mxWindow.is())
+ mxWindow->addWindowListener(this);
+
+ if (mxUpdateCanvas.is())
+ {
+ m_pUpdateRequester = CanvasUpdateRequester::Instance(mxUpdateCanvas);
+ }
+}
+
+PresenterCanvas::~PresenterCanvas()
+{
+}
+
+void PresenterCanvas::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxWindow.is())
+ {
+ mxWindow->removeWindowListener(this);
+ mxWindow.clear();
+ }
+}
+
+//----- XCanvas ---------------------------------------------------------------
+
+void SAL_CALL PresenterCanvas::clear()
+{
+ ThrowIfDisposed();
+ // ToDo: Clear the area covered by the child window. A simple forward
+ // would clear the whole shared canvas.
+}
+
+void SAL_CALL PresenterCanvas::drawPoint (
+ const css::geometry::RealPoint2D& aPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ mxSharedCanvas->drawPoint(aPoint,MergeViewState(aViewState),aRenderState);
+}
+
+void SAL_CALL PresenterCanvas::drawLine (
+ const css::geometry::RealPoint2D& aStartPoint,
+ const css::geometry::RealPoint2D& aEndPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ mxSharedCanvas->drawLine(aStartPoint,aEndPoint,MergeViewState(aViewState),aRenderState);
+}
+
+void SAL_CALL PresenterCanvas::drawBezier (
+ const css::geometry::RealBezierSegment2D& aBezierSegment,
+ const css::geometry::RealPoint2D& aEndPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ mxSharedCanvas->drawBezier(aBezierSegment,aEndPoint,MergeViewState(aViewState),aRenderState);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL PresenterCanvas::drawPolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->drawPolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL PresenterCanvas::strokePolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::rendering::StrokeAttributes& aStrokeAttributes)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->strokePolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState, aStrokeAttributes);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::strokeTexturedPolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence< css::rendering::Texture >& aTextures,
+ const css::rendering::StrokeAttributes& aStrokeAttributes)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->strokeTexturedPolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState, aTextures, aStrokeAttributes);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::strokeTextureMappedPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence<css::rendering::Texture>& aTextures,
+ const css::uno::Reference<css::geometry::XMapping2D>& xMapping,
+ const css::rendering::StrokeAttributes& aStrokeAttributes)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->strokeTextureMappedPolyPolygon(
+ xPolyPolygon,
+ MergeViewState(aViewState),
+ aRenderState,
+ aTextures,
+ xMapping,
+ aStrokeAttributes);
+}
+
+css::uno::Reference<css::rendering::XPolyPolygon2D> SAL_CALL
+ PresenterCanvas::queryStrokeShapes(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::rendering::StrokeAttributes& aStrokeAttributes)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->queryStrokeShapes(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState, aStrokeAttributes);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::fillPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->fillPolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::fillTexturedPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence<css::rendering::Texture>& xTextures)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->fillTexturedPolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState, xTextures);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::fillTextureMappedPolyPolygon(
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence< css::rendering::Texture >& xTextures,
+ const css::uno::Reference< css::geometry::XMapping2D >& xMapping)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->fillTextureMappedPolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState, xTextures, xMapping);
+}
+
+css::uno::Reference<css::rendering::XCanvasFont> SAL_CALL
+ PresenterCanvas::createFont(
+ const css::rendering::FontRequest& aFontRequest,
+ const css::uno::Sequence< css::beans::PropertyValue >& aExtraFontProperties,
+ const css::geometry::Matrix2D& aFontMatrix)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->createFont(
+ aFontRequest, aExtraFontProperties, aFontMatrix);
+}
+
+css::uno::Sequence<css::rendering::FontInfo> SAL_CALL
+ PresenterCanvas::queryAvailableFonts(
+ const css::rendering::FontInfo& aFilter,
+ const css::uno::Sequence< css::beans::PropertyValue >& aFontProperties)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->queryAvailableFonts(aFilter, aFontProperties);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::drawText(
+ const css::rendering::StringContext& aText,
+ const css::uno::Reference< css::rendering::XCanvasFont >& xFont,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ ::sal_Int8 nTextDirection)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->drawText(
+ aText, xFont, MergeViewState(aViewState), aRenderState, nTextDirection);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::drawTextLayout(
+ const css::uno::Reference< css::rendering::XTextLayout >& xLayoutetText,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->drawTextLayout(
+ xLayoutetText, MergeViewState(aViewState), aRenderState);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::drawBitmap(
+ const css::uno::Reference< css::rendering::XBitmap >& xBitmap,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->drawBitmap(
+ xBitmap, MergeViewState(aViewState), aRenderState);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::drawBitmapModulated(
+ const css::uno::Reference< css::rendering::XBitmap>& xBitmap,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->drawBitmapModulated(
+ xBitmap, MergeViewState(aViewState), aRenderState);
+}
+
+css::uno::Reference<css::rendering::XGraphicDevice> SAL_CALL
+ PresenterCanvas::getDevice()
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->getDevice();
+}
+
+//----- XSpriteCanvas ---------------------------------------------------------
+
+Reference<rendering::XAnimatedSprite> SAL_CALL
+ PresenterCanvas::createSpriteFromAnimation (
+ const css::uno::Reference<css::rendering::XAnimation>& rAnimation)
+{
+ ThrowIfDisposed();
+
+ Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxSharedCanvas, UNO_QUERY);
+ if (xSpriteCanvas.is())
+ return xSpriteCanvas->createSpriteFromAnimation(rAnimation);
+ else
+ return nullptr;
+}
+
+Reference<rendering::XAnimatedSprite> SAL_CALL
+ PresenterCanvas::createSpriteFromBitmaps (
+ const css::uno::Sequence<
+ css::uno::Reference< css::rendering::XBitmap > >& rAnimationBitmaps,
+ ::sal_Int8 nInterpolationMode)
+{
+ ThrowIfDisposed();
+
+ Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxSharedCanvas, UNO_QUERY);
+ if (xSpriteCanvas.is())
+ return xSpriteCanvas->createSpriteFromBitmaps(rAnimationBitmaps, nInterpolationMode);
+ else
+ return nullptr;
+}
+
+Reference<rendering::XCustomSprite> SAL_CALL
+ PresenterCanvas::createCustomSprite (
+ const css::geometry::RealSize2D& rSpriteSize)
+{
+ ThrowIfDisposed();
+
+ Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxSharedCanvas, UNO_QUERY);
+ if (xSpriteCanvas.is())
+ return new PresenterCustomSprite(
+ this,
+ xSpriteCanvas->createCustomSprite(rSpriteSize),
+ mxSharedWindow);
+ else if (mxUpdateCanvas.is())
+ return new PresenterCustomSprite(
+ this,
+ mxUpdateCanvas->createCustomSprite(rSpriteSize),
+ mxUpdateWindow);
+ else
+ return nullptr;
+}
+
+Reference<rendering::XSprite> SAL_CALL
+ PresenterCanvas::createClonedSprite (
+ const css::uno::Reference< css::rendering::XSprite >& rxOriginal)
+{
+ ThrowIfDisposed();
+
+ Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxSharedCanvas, UNO_QUERY);
+ if (xSpriteCanvas.is())
+ return xSpriteCanvas->createClonedSprite(rxOriginal);
+ if (mxUpdateCanvas.is())
+ return mxUpdateCanvas->createClonedSprite(rxOriginal);
+ return nullptr;
+}
+
+sal_Bool SAL_CALL PresenterCanvas::updateScreen (sal_Bool bUpdateAll)
+{
+ ThrowIfDisposed();
+
+ mbOffsetUpdatePending = true;
+ if (m_pUpdateRequester != nullptr)
+ {
+ m_pUpdateRequester->RequestUpdate(bUpdateAll);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//----- XEventListener --------------------------------------------------------
+
+void SAL_CALL PresenterCanvas::disposing (const css::lang::EventObject& rEvent)
+{
+ ThrowIfDisposed();
+ if (rEvent.Source == mxWindow)
+ mxWindow = nullptr;
+}
+
+//----- XWindowListener -------------------------------------------------------
+
+void SAL_CALL PresenterCanvas::windowResized (const css::awt::WindowEvent&)
+{
+ ThrowIfDisposed();
+ mbOffsetUpdatePending = true;
+}
+
+void SAL_CALL PresenterCanvas::windowMoved (const css::awt::WindowEvent&)
+{
+ ThrowIfDisposed();
+ mbOffsetUpdatePending = true;
+}
+
+void SAL_CALL PresenterCanvas::windowShown (const css::lang::EventObject&)
+{
+ ThrowIfDisposed();
+ mbOffsetUpdatePending = true;
+}
+
+void SAL_CALL PresenterCanvas::windowHidden (const css::lang::EventObject&)
+{
+ ThrowIfDisposed();
+}
+
+//----- XBitmap ---------------------------------------------------------------
+
+geometry::IntegerSize2D SAL_CALL PresenterCanvas::getSize()
+{
+ ThrowIfDisposed();
+
+ if (mxWindow.is())
+ {
+ const awt::Rectangle aWindowBox (mxWindow->getPosSize());
+ return geometry::IntegerSize2D(aWindowBox.Width, aWindowBox.Height);
+ }
+ else
+ return geometry::IntegerSize2D(0,0);
+}
+
+sal_Bool SAL_CALL PresenterCanvas::hasAlpha()
+{
+ Reference<rendering::XBitmap> xBitmap (mxSharedCanvas, UNO_QUERY);
+ if (xBitmap.is())
+ return xBitmap->hasAlpha();
+ else
+ return false;
+}
+
+Reference<rendering::XBitmap> SAL_CALL PresenterCanvas::getScaledBitmap(
+ const css::geometry::RealSize2D&,
+ sal_Bool)
+{
+ ThrowIfDisposed();
+
+ // Not implemented.
+
+ return nullptr;
+}
+
+rendering::ViewState PresenterCanvas::MergeViewState (
+ const rendering::ViewState& rViewState)
+{
+ // Make sure the offset is up-to-date.
+ if (mbOffsetUpdatePending)
+ maOffset = GetOffset(mxSharedWindow);
+ return MergeViewState(rViewState, maOffset);
+}
+
+css::rendering::ViewState PresenterCanvas::MergeViewState (
+ const css::rendering::ViewState& rViewState,
+ const css::awt::Point& rOffset)
+{
+ // Early rejects.
+ if ( ! mxSharedCanvas.is())
+ return rViewState;
+
+ Reference<rendering::XGraphicDevice> xDevice (mxSharedCanvas->getDevice());
+ if ( ! xDevice.is())
+ return rViewState;
+
+ // Create a modifiable copy of the given view state.
+ rendering::ViewState aViewState (rViewState);
+
+ // Prepare the local clip rectangle.
+ ::basegfx::B2DRectangle aWindowRange (GetClipRectangle(aViewState.AffineTransform, rOffset));
+
+ // Adapt the offset of the view state.
+ aViewState.AffineTransform.m02 += rOffset.X;
+ aViewState.AffineTransform.m12 += rOffset.Y;
+
+ // Adapt the clip polygon.
+ if ( ! aViewState.Clip.is())
+ {
+ // Cancel out the later multiplication with the view state
+ // transformation.
+ aViewState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ xDevice,
+ ::basegfx::B2DPolyPolygon(::basegfx::utils::createPolygonFromRect(aWindowRange)));
+ }
+ else
+ {
+ // Have to compute the intersection of the given clipping polygon in
+ // the view state and the local clip rectangle.
+
+ // Clip the view state clipping polygon against the local clip rectangle.
+ const ::basegfx::B2DPolyPolygon aClipPolygon (
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
+ aViewState.Clip));
+ const ::basegfx::B2DPolyPolygon aClippedClipPolygon (
+ ::basegfx::utils::clipPolyPolygonOnRange(
+ aClipPolygon,
+ aWindowRange,
+ true, /* bInside */
+ false /* bStroke */));
+
+ aViewState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ xDevice,
+ aClippedClipPolygon);
+ }
+
+ return aViewState;
+}
+
+awt::Point PresenterCanvas::GetOffset (const Reference<awt::XWindow>& rxBaseWindow)
+{
+ mbOffsetUpdatePending = false;
+ if (mxWindow.is() && rxBaseWindow.is())
+ {
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(mxWindow);
+ VclPtr<vcl::Window> pSharedWindow = VCLUnoHelper::GetWindow(rxBaseWindow);
+ if (pWindow && pSharedWindow)
+ {
+ ::tools::Rectangle aBox = pWindow->GetWindowExtentsRelative(pSharedWindow);
+
+ // Calculate offset of this canvas with respect to the shared
+ // canvas.
+ return awt::Point(aBox.Left(), aBox.Top());
+ }
+ }
+
+ return awt::Point(0, 0);
+}
+
+::basegfx::B2DRectangle PresenterCanvas::GetClipRectangle (
+ const css::geometry::AffineMatrix2D& rViewTransform,
+ const awt::Point& rOffset)
+{
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(mxWindow);
+ if (!pWindow)
+ return ::basegfx::B2DRectangle();
+
+ VclPtr<vcl::Window> pSharedWindow = VCLUnoHelper::GetWindow(mxSharedWindow);
+ if (!pSharedWindow)
+ return ::basegfx::B2DRectangle();
+
+ // Get the bounding box of the window and create a range in the
+ // coordinate system of the child window.
+ // Use the window extents.
+ ::tools::Rectangle aLocalClip = pWindow->GetWindowExtentsRelative(pSharedWindow);
+
+ // The local clip rectangle is used to clip the view state clipping
+ // polygon.
+ ::basegfx::B2DRectangle aWindowRectangle (
+ aLocalClip.Left() - rOffset.X,
+ aLocalClip.Top() - rOffset.Y,
+ aLocalClip.Right() - rOffset.X + 1,
+ aLocalClip.Bottom() - rOffset.Y + 1);
+
+ // Calculate the inverted view state transformation to cancel out a
+ // later transformation of the local clip polygon with the view state
+ // transformation.
+ ::basegfx::B2DHomMatrix aInvertedViewStateTransformation;
+ ::basegfx::unotools::homMatrixFromAffineMatrix(
+ aInvertedViewStateTransformation,
+ rViewTransform);
+ if (aInvertedViewStateTransformation.invert())
+ {
+ // Cancel out the later multiplication with the view state
+ // transformation.
+ aWindowRectangle.transform(aInvertedViewStateTransformation);
+ }
+
+ return aWindowRectangle;
+}
+
+Reference<rendering::XPolyPolygon2D> PresenterCanvas::UpdateSpriteClip (
+ const Reference<rendering::XPolyPolygon2D>& rxOriginalClip,
+ const geometry::RealPoint2D& rLocation)
+{
+ // Check used resources and just return the original clip when not
+ // every one of them is available.
+ if ( ! mxWindow.is())
+ return rxOriginalClip;
+
+ Reference<rendering::XGraphicDevice> xDevice (mxSharedCanvas->getDevice());
+ if ( ! xDevice.is())
+ return rxOriginalClip;
+
+ // Determine the bounds of the clip rectangle (the window border) in the
+ // coordinate system of the sprite.
+ const awt::Rectangle aWindowBox (mxWindow->getPosSize());
+ const double nMinX (-rLocation.X);
+ const double nMinY (-rLocation.Y);
+ const double nMaxX (aWindowBox.Width-rLocation.X);
+ const double nMaxY (aWindowBox.Height-rLocation.Y);
+
+ // Create a clip polygon.
+ Reference<rendering::XPolyPolygon2D> xPolygon;
+ if (rxOriginalClip.is())
+ {
+ // Combine the original clip with the window clip.
+ const ::basegfx::B2DPolyPolygon aOriginalClip (
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rxOriginalClip));
+ ::basegfx::B2DRectangle aWindowRange (nMinX, nMinY, nMaxX, nMaxY);
+ const ::basegfx::B2DPolyPolygon aClippedClipPolygon (
+ ::basegfx::utils::clipPolyPolygonOnRange(
+ aOriginalClip,
+ aWindowRange,
+ true, /* bInside */
+ false /* bStroke */));
+ xPolygon = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ xDevice,
+ aClippedClipPolygon);
+ }
+ else
+ {
+ // Create a new clip polygon from the window clip rectangle.
+ Sequence<Sequence<geometry::RealPoint2D> > aPoints
+ {
+ {
+ { nMinX,nMinY },
+ { nMaxX,nMinY },
+ { nMaxX,nMaxY },
+ { nMinX,nMaxY }
+ }
+ };
+ Reference<rendering::XLinePolyPolygon2D> xLinePolygon(
+ xDevice->createCompatibleLinePolyPolygon(aPoints));
+ if (xLinePolygon.is())
+ xLinePolygon->setClosed(0, true);
+ xPolygon = xLinePolygon;
+ }
+
+ return xPolygon;
+}
+
+void PresenterCanvas::ThrowIfDisposed()
+{
+ if (m_bDisposed || ! mxSharedCanvas.is())
+ {
+ throw lang::DisposedException ("PresenterCanvas object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+//===== PresenterCustomSprite =================================================
+
+PresenterCustomSprite::PresenterCustomSprite (
+ const rtl::Reference<PresenterCanvas>& rpCanvas,
+ const Reference<rendering::XCustomSprite>& rxSprite,
+ const Reference<awt::XWindow>& rxBaseWindow)
+ : mpCanvas(rpCanvas),
+ mxSprite(rxSprite),
+ mxBaseWindow(rxBaseWindow),
+ maPosition(0,0)
+{
+}
+
+void PresenterCustomSprite::disposing(std::unique_lock<std::mutex>&)
+{
+ Reference<XComponent> xComponent (mxSprite, UNO_QUERY);
+ mxSprite = nullptr;
+ if (xComponent.is())
+ xComponent->dispose();
+ mpCanvas.clear();
+}
+
+//----- XSprite ---------------------------------------------------------------
+
+void SAL_CALL PresenterCustomSprite::setAlpha (const double nAlpha)
+{
+ ThrowIfDisposed();
+ mxSprite->setAlpha(nAlpha);
+}
+
+void SAL_CALL PresenterCustomSprite::move (
+ const geometry::RealPoint2D& rNewPos,
+ const rendering::ViewState& rViewState,
+ const rendering::RenderState& rRenderState)
+{
+ ThrowIfDisposed();
+ maPosition = rNewPos;
+ mxSprite->move(
+ rNewPos,
+ mpCanvas->MergeViewState(rViewState, mpCanvas->GetOffset(mxBaseWindow)),
+ rRenderState);
+ // Clip sprite against window bounds. This call is necessary because
+ // sprite clipping is done in the coordinate system of the sprite.
+ // Therefore, after each change of the sprites location the window
+ // bounds have to be transformed into the sprites coordinate system.
+ clip(nullptr);
+}
+
+void SAL_CALL PresenterCustomSprite::transform (const geometry::AffineMatrix2D& rTransformation)
+{
+ ThrowIfDisposed();
+ mxSprite->transform(rTransformation);
+}
+
+void SAL_CALL PresenterCustomSprite::clip (const Reference<rendering::XPolyPolygon2D>& rxClip)
+{
+ ThrowIfDisposed();
+ // The clip region is expected in the coordinate system of the sprite.
+ // UpdateSpriteClip() integrates the window bounds, transformed into the
+ // sprites coordinate system, with the given clip.
+ mxSprite->clip(mpCanvas->UpdateSpriteClip(rxClip, maPosition));
+}
+
+void SAL_CALL PresenterCustomSprite::setPriority (const double nPriority)
+{
+ ThrowIfDisposed();
+ mxSprite->setPriority(nPriority);
+}
+
+void SAL_CALL PresenterCustomSprite::show()
+{
+ ThrowIfDisposed();
+ mxSprite->show();
+}
+
+void SAL_CALL PresenterCustomSprite::hide()
+{
+ ThrowIfDisposed();
+ mxSprite->hide();
+}
+
+//----- XCustomSprite ---------------------------------------------------------
+
+Reference<rendering::XCanvas> PresenterCustomSprite::getContentCanvas()
+{
+ ThrowIfDisposed();
+ return mxSprite->getContentCanvas();
+}
+
+void PresenterCustomSprite::ThrowIfDisposed()
+{
+ if (m_bDisposed || ! mxSprite.is())
+ {
+ throw lang::DisposedException ("PresenterCustomSprite object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterCanvas.hxx b/sd/source/ui/presenter/PresenterCanvas.hxx
new file mode 100644
index 000000000..da2f51a79
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterCanvas.hxx
@@ -0,0 +1,320 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/rendering/XSpriteCanvas.hpp>
+#include <com/sun/star/rendering/XBitmap.hpp>
+#include <comphelper/compbase.hxx>
+#include <memory>
+
+namespace sd::presenter { class CanvasUpdateRequester; }
+namespace com::sun::star::awt { class XWindow; }
+namespace com::sun::star::geometry { struct AffineMatrix2D; }
+
+namespace sd::presenter {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::rendering::XSpriteCanvas,
+ css::rendering::XBitmap,
+ css::awt::XWindowListener
+> PresenterCanvasInterfaceBase;
+
+/** Wrapper around a shared canvas that forwards most of its methods to the
+ shared canvas. Most notable differences are:
+ 1. The transformation of the ViewState of forwarded calls is modified by adding
+ an offset.
+ 2. The clip polygon of the ViewState of forwarded calls is intersected
+ with a clip rectangle that can be set via SetClip().
+ 3. Calls to updateScreen() are collected. One call to the updateScreen()
+ method of the shared canvas is made asynchronously.
+
+ The canvas can use different canvases for sharing and for sprite
+ construction. This allows the shared canvas to be a canvas of sprite itself.
+*/
+class PresenterCanvas
+ : public PresenterCanvasInterfaceBase
+{
+public:
+ /** This constructor is used when a PresenterCanvas object is created
+ directly, typically by the PresenterCanvasFactory.
+ @param rxUpdateCanvas
+ This canvas is used to call updateScreen() at and to create
+ sprites. In the typical case this canvas is identical to the
+ rxSharedCanvas argument.
+ @param rxUpdateWindow
+ The window that belongs to the canvas given by the
+ rxUpdateCanvas argument.
+ @param rxSharedCanvas
+ The canvas that is wrapped by the new instance of this class.
+ Typically this is a regular XSpriteCanvas and then is identical
+ to the one given by the rxUpdateCanvas argument. It may be the
+ canvas of a sprite which does not support the XSpriteCanvas
+ interface. In that case the canvas that created the sprite can
+ be given as rxUpdateCanvas argument to allow to create further
+ sprites and to have proper calls to updateScreen().
+ @param rxSharedWindow
+ The window that belongs to the canvas given by the
+ rxSharedCanvas argument.
+ @param rxWindow
+ The window that is represented by the new PresenterCanvas
+ object. It is expected to be a direct descendant of
+ rxSharedWindow. Its position inside rxSharedWindow defines the
+ offset of the canvas implemented by the new PresenterCanvas
+ object and rxSharedCanvas.
+ */
+ PresenterCanvas (
+ const css::uno::Reference<css::rendering::XSpriteCanvas>& rxUpdateCanvas,
+ const css::uno::Reference<css::awt::XWindow>& rxUpdateWindow,
+ const css::uno::Reference<css::rendering::XCanvas>& rxSharedCanvas,
+ const css::uno::Reference<css::awt::XWindow>& rxSharedWindow,
+ const css::uno::Reference<css::awt::XWindow>& rxWindow);
+ virtual ~PresenterCanvas() override;
+ PresenterCanvas(const PresenterCanvas&) = delete;
+ PresenterCanvas& operator=(const PresenterCanvas&) = delete;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ css::awt::Point GetOffset (const css::uno::Reference<css::awt::XWindow>& rxBaseWindow);
+
+ /** Merge the given view state with the view state that translates the
+ (virtual) child canvas to the shared canvas.
+ */
+ css::rendering::ViewState MergeViewState (
+ const css::rendering::ViewState& rViewState,
+ const css::awt::Point& raOffset);
+
+ /** Called by custom sprites to update their clip polygon so that they
+ are clipped at the borders of the canvas. This method has to be
+ called after each change of the sprite location so that the bounds
+ of the canvas can be transformed into the coordinate system of the
+ sprite.
+ */
+ css::uno::Reference<css::rendering::XPolyPolygon2D> UpdateSpriteClip (
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& rxOriginalClip,
+ const css::geometry::RealPoint2D& rLocation);
+
+ // XCanvas
+
+ virtual void SAL_CALL clear() override;
+
+ virtual void SAL_CALL drawPoint (
+ const css::geometry::RealPoint2D& aPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual void SAL_CALL drawLine (
+ const css::geometry::RealPoint2D& aStartPoint,
+ const css::geometry::RealPoint2D& aEndPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual void SAL_CALL drawBezier (
+ const css::geometry::RealBezierSegment2D& aBezierSegment,
+ const css::geometry::RealPoint2D& aEndPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL drawPolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL strokePolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::rendering::StrokeAttributes& aStrokeAttributes) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ strokeTexturedPolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence< css::rendering::Texture >& aTextures,
+ const css::rendering::StrokeAttributes& aStrokeAttributes) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ strokeTextureMappedPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence<css::rendering::Texture>& aTextures,
+ const css::uno::Reference<css::geometry::XMapping2D>& xMapping,
+ const css::rendering::StrokeAttributes& aStrokeAttributes) override;
+
+ virtual css::uno::Reference<css::rendering::XPolyPolygon2D> SAL_CALL
+ queryStrokeShapes(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::rendering::StrokeAttributes& aStrokeAttributes) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ fillPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ fillTexturedPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence<css::rendering::Texture>& xTextures) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ fillTextureMappedPolyPolygon(
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence< css::rendering::Texture >& xTextures,
+ const css::uno::Reference< css::geometry::XMapping2D >& xMapping) override;
+
+ virtual css::uno::Reference<css::rendering::XCanvasFont> SAL_CALL
+ createFont(
+ const css::rendering::FontRequest& aFontRequest,
+ const css::uno::Sequence< css::beans::PropertyValue >& aExtraFontProperties,
+ const css::geometry::Matrix2D& aFontMatrix) override;
+
+ virtual css::uno::Sequence<css::rendering::FontInfo> SAL_CALL
+ queryAvailableFonts(
+ const css::rendering::FontInfo& aFilter,
+ const css::uno::Sequence< css::beans::PropertyValue >& aFontProperties) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ drawText(
+ const css::rendering::StringContext& aText,
+ const css::uno::Reference< css::rendering::XCanvasFont >& xFont,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ ::sal_Int8 nTextDirection) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ drawTextLayout(
+ const css::uno::Reference< css::rendering::XTextLayout >& xLayoutetText,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ drawBitmap(
+ const css::uno::Reference< css::rendering::XBitmap >& xBitmap,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ drawBitmapModulated(
+ const css::uno::Reference< css::rendering::XBitmap>& xBitmap,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XGraphicDevice> SAL_CALL
+ getDevice() override;
+
+ // XSpriteCanvas
+
+ css::uno::Reference< css::rendering::XAnimatedSprite > SAL_CALL
+ createSpriteFromAnimation (
+ const css::uno::Reference< css::rendering::XAnimation >& animation) override;
+
+ css::uno::Reference< css::rendering::XAnimatedSprite > SAL_CALL
+ createSpriteFromBitmaps (
+ const css::uno::Sequence<
+ css::uno::Reference< css::rendering::XBitmap > >& animationBitmaps,
+ ::sal_Int8 interpolationMode) override;
+
+ css::uno::Reference< css::rendering::XCustomSprite > SAL_CALL
+ createCustomSprite (
+ const css::geometry::RealSize2D& spriteSize) override;
+
+ css::uno::Reference< css::rendering::XSprite > SAL_CALL
+ createClonedSprite (
+ const css::uno::Reference< css::rendering::XSprite >& original) override;
+
+ sal_Bool SAL_CALL updateScreen (sal_Bool bUpdateAll) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
+
+ // XWindowListener
+
+ virtual void SAL_CALL windowResized (const css::awt::WindowEvent& rEvent) override;
+
+ virtual void SAL_CALL windowMoved (const css::awt::WindowEvent& rEvent) override;
+
+ virtual void SAL_CALL windowShown (const css::lang::EventObject& rEvent) override;
+
+ virtual void SAL_CALL windowHidden (const css::lang::EventObject& rEvent) override;
+
+ // XBitmap
+
+ virtual css::geometry::IntegerSize2D SAL_CALL getSize() override;
+
+ virtual sal_Bool SAL_CALL hasAlpha() override;
+
+ virtual css::uno::Reference<css::rendering::XBitmap> SAL_CALL getScaledBitmap(
+ const css::geometry::RealSize2D& rNewSize,
+ sal_Bool bFast) override;
+
+private:
+ css::uno::Reference<css::rendering::XSpriteCanvas> mxUpdateCanvas;
+ css::uno::Reference<css::awt::XWindow> mxUpdateWindow;
+ css::uno::Reference<css::rendering::XCanvas> mxSharedCanvas;
+ css::uno::Reference<css::awt::XWindow> mxSharedWindow;
+
+ /** The window for which a canvas is emulated.
+ */
+ css::uno::Reference<css::awt::XWindow> mxWindow;
+
+ /** Offset of the emulated canvas with respect to the shared canvas.
+ */
+ css::awt::Point maOffset;
+
+ /** The UpdateRequester is used by updateScreen() to schedule
+ updateScreen() calls at the shared canvas.
+ */
+ std::shared_ptr<CanvasUpdateRequester> m_pUpdateRequester;
+
+ /** When this flag is true (it is set to true after every call to
+ updateScreen()) then the next call to MergeViewState updates the
+ maOffset member. A possible optimization would set this flag only
+ to true when one of the windows between mxWindow and mxSharedWindow
+ changes its position.
+ */
+ bool mbOffsetUpdatePending;
+
+ ::basegfx::B2DRectangle GetClipRectangle (
+ const css::geometry::AffineMatrix2D& rViewTransform,
+ const css::awt::Point& rOffset);
+
+ css::rendering::ViewState MergeViewState (const css::rendering::ViewState& rViewState);
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterHelper.cxx b/sd/source/ui/presenter/PresenterHelper.cxx
new file mode 100644
index 000000000..a93113a75
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterHelper.cxx
@@ -0,0 +1,466 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstddef>
+
+#include "PresenterHelper.hxx"
+#include "PresenterCanvas.hxx"
+#include <cppcanvas/vclfactory.hxx>
+#include <com/sun/star/awt/XWindowPeer.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/window.hxx>
+#include <vcl/wrkwin.hxx>
+
+
+#include <bitmaps.hlst>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::presenter {
+
+//===== PresenterHelper =======================================================
+
+PresenterHelper::PresenterHelper (
+ const Reference<XComponentContext>& rxContext)
+ : mxComponentContext(rxContext)
+{
+}
+
+PresenterHelper::~PresenterHelper()
+{
+}
+
+//----- XInitialize -----------------------------------------------------------
+
+void SAL_CALL PresenterHelper::initialize (const Sequence<Any>&) {}
+
+//----- XPaneHelper ----------------------------------------------------
+
+Reference<awt::XWindow> SAL_CALL PresenterHelper::createWindow (
+ const Reference<awt::XWindow>& rxParentWindow,
+ sal_Bool bCreateSystemChildWindow,
+ sal_Bool bInitiallyVisible,
+ sal_Bool bEnableChildTransparentMode,
+ sal_Bool bEnableParentClip)
+{
+ VclPtr<vcl::Window> pParentWindow(VCLUnoHelper::GetWindow(rxParentWindow));
+
+ // Create a new window.
+ VclPtr<vcl::Window> pWindow;
+ if (bCreateSystemChildWindow)
+ {
+ pWindow = VclPtr<WorkWindow>::Create(pParentWindow, WB_SYSTEMCHILDWINDOW);
+ }
+ else
+ {
+ pWindow = VclPtr<vcl::Window>::Create(pParentWindow);
+ }
+ Reference<awt::XWindow> xWindow (pWindow->GetComponentInterface(), UNO_QUERY);
+
+ if (bEnableChildTransparentMode)
+ {
+ // Make the frame window transparent and make the parent able to
+ // draw behind it.
+ if (pParentWindow)
+ pParentWindow->EnableChildTransparentMode();
+ }
+
+ pWindow->Show(bInitiallyVisible);
+
+ pWindow->SetMapMode(MapMode(MapUnit::MapPixel));
+ pWindow->SetBackground();
+ if ( ! bEnableParentClip)
+ {
+ pWindow->SetParentClipMode(ParentClipMode::NoClip);
+ pWindow->SetPaintTransparent(true);
+ }
+ else
+ {
+ pWindow->SetParentClipMode(ParentClipMode::Clip);
+ pWindow->SetPaintTransparent(false);
+ }
+
+ return xWindow;
+}
+
+Reference<rendering::XCanvas> SAL_CALL PresenterHelper::createSharedCanvas (
+ const Reference<rendering::XSpriteCanvas>& rxUpdateCanvas,
+ const Reference<awt::XWindow>& rxUpdateWindow,
+ const Reference<rendering::XCanvas>& rxSharedCanvas,
+ const Reference<awt::XWindow>& rxSharedWindow,
+ const Reference<awt::XWindow>& rxWindow)
+{
+ if ( ! rxSharedCanvas.is()
+ || ! rxSharedWindow.is()
+ || ! rxWindow.is())
+ {
+ throw RuntimeException("illegal argument", static_cast<XWeak*>(this));
+ }
+
+ if (rxWindow == rxSharedWindow)
+ return rxSharedCanvas;
+ else
+ return new PresenterCanvas(
+ rxUpdateCanvas,
+ rxUpdateWindow,
+ rxSharedCanvas,
+ rxSharedWindow,
+ rxWindow);
+}
+
+Reference<rendering::XCanvas> SAL_CALL PresenterHelper::createCanvas (
+ const Reference<awt::XWindow>& rxWindow,
+ sal_Int16,
+ const OUString& rsOptionalCanvasServiceName)
+{
+ // No shared window is given or an explicit canvas service name is
+ // specified. Create a new canvas.
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(rxWindow);
+ if (!pWindow)
+ throw RuntimeException();
+
+ Sequence<Any> aArg{ // common: first any is VCL pointer to window (for VCL canvas)
+ Any(reinterpret_cast<sal_Int64>(pWindow.get())),
+ Any(css::awt::Rectangle()),
+ Any(false),
+ Any(rxWindow)
+ };
+
+ Reference<lang::XMultiServiceFactory> xFactory (
+ mxComponentContext->getServiceManager(), UNO_QUERY_THROW);
+ return Reference<rendering::XCanvas>(
+ xFactory->createInstanceWithArguments(
+ !rsOptionalCanvasServiceName.isEmpty()
+ ? rsOptionalCanvasServiceName
+ : OUString("com.sun.star.rendering.Canvas.VCL"),
+ aArg),
+ UNO_QUERY);
+}
+
+void SAL_CALL PresenterHelper::toTop (
+ const Reference<awt::XWindow>& rxWindow)
+{
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(rxWindow);
+ if (pWindow)
+ {
+ pWindow->ToTop();
+ pWindow->SetZOrder(nullptr, ZOrderFlags::Last);
+ }
+}
+
+namespace {
+
+struct IdMapEntry {
+ char const * sid;
+ rtl::OUStringConstExpr bmpid;
+};
+
+}
+
+Reference<rendering::XBitmap> SAL_CALL PresenterHelper::loadBitmap (
+ const OUString& id,
+ const Reference<rendering::XCanvas>& rxCanvas)
+{
+ if ( ! rxCanvas.is())
+ return nullptr;
+
+ static IdMapEntry const map[] = {
+ { "bitmaps/Background.png", BMP_PRESENTERSCREEN_BACKGROUND },
+ { "bitmaps/Animation.png",
+ BMP_PRESENTERSCREEN_ANIMATION },
+ { "bitmaps/Transition.png",
+ BMP_PRESENTERSCREEN_TRANSITION },
+ { "bitmaps/BorderActiveBottom.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_BOTTOM },
+ { "bitmaps/BorderActiveBottomCallout.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_BOTTOM_CALLOUT },
+ { "bitmaps/BorderActiveBottomLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_BOTTOM_LEFT },
+ { "bitmaps/BorderActiveBottomRight.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_BOTTOM_RIGHT },
+ { "bitmaps/BorderActiveLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_LEFT },
+ { "bitmaps/BorderActiveRight.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_RIGHT },
+ { "bitmaps/BorderActiveTop.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_TOP },
+ { "bitmaps/BorderActiveTopLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_TOP_LEFT },
+ { "bitmaps/BorderActiveTopRight.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_TOP_RIGHT },
+ { "bitmaps/BorderBottom.png", BMP_PRESENTERSCREEN_BORDER_BOTTOM },
+ { "bitmaps/BorderBottomLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_BOTTOM_LEFT },
+ { "bitmaps/BorderBottomRight.png",
+ BMP_PRESENTERSCREEN_BORDER_BOTTOM_RIGHT },
+ { "bitmaps/BorderCurrentSlideBottom.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_BOTTOM },
+ { "bitmaps/BorderCurrentSlideBottomLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_BOTTOM_LEFT },
+ { "bitmaps/BorderCurrentSlideBottomRight.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_BOTTOM_RIGHT },
+ { "bitmaps/BorderCurrentSlideLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_LEFT },
+ { "bitmaps/BorderCurrentSlideRight.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_RIGHT },
+ { "bitmaps/BorderCurrentSlideTop.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_TOP },
+ { "bitmaps/BorderCurrentSlideTopLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_TOP_LEFT },
+ { "bitmaps/BorderCurrentSlideTopRight.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_TOP_RIGHT },
+ { "bitmaps/BorderLeft.png", BMP_PRESENTERSCREEN_BORDER_LEFT },
+ { "bitmaps/BorderRight.png", BMP_PRESENTERSCREEN_BORDER_RIGHT },
+ { "bitmaps/BorderToolbarBottom.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_BOTTOM },
+ { "bitmaps/BorderToolbarLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_LEFT },
+ { "bitmaps/BorderToolbarRight.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_RIGHT },
+ { "bitmaps/BorderToolbarTop.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_TOP },
+ { "bitmaps/BorderToolbarTopLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_TOP_LEFT },
+ { "bitmaps/BorderToolbarTopRight.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_TOP_RIGHT },
+ { "bitmaps/BorderTop.png", BMP_PRESENTERSCREEN_BORDER_TOP },
+ { "bitmaps/BorderTopLeft.png", BMP_PRESENTERSCREEN_BORDER_TOP_LEFT },
+ { "bitmaps/BorderTopRight.png", BMP_PRESENTERSCREEN_BORDER_TOP_RIGHT },
+ { "bitmaps/ButtonEffectNextDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_EFFECT_NEXT_DISABLED },
+ { "bitmaps/ButtonEffectNextMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_EFFECT_NEXT_MOUSE_OVER },
+ { "bitmaps/ButtonEffectNextNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_EFFECT_NEXT_NORMAL },
+ { "bitmaps/ButtonEffectNextSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_EFFECT_NEXT_SELECTED },
+ { "bitmaps/ButtonFrameCenterMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_CENTER_MOUSE_OVER },
+ { "bitmaps/ButtonFrameCenterNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_CENTER_NORMAL },
+ { "bitmaps/ButtonFrameLeftMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_LEFT_MOUSE_OVER },
+ { "bitmaps/ButtonFrameLeftNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_LEFT_NORMAL },
+ { "bitmaps/ButtonFrameRightMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_RIGHT_MOUSE_OVER },
+ { "bitmaps/ButtonFrameRightNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_RIGHT_NORMAL },
+ { "bitmaps/ButtonHelpDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_HELP_DISABLED },
+ { "bitmaps/ButtonHelpMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_HELP_MOUSE_OVER },
+ { "bitmaps/ButtonHelpNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_HELP_NORMAL },
+ { "bitmaps/ButtonHelpSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_HELP_SELECTED },
+ { "bitmaps/ButtonExitPresenterMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_EXIT_PRESENTER_MOUSE_OVER },
+ { "bitmaps/ButtonExitPresenterNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_EXIT_PRESENTER_NORMAL },
+ { "bitmaps/ButtonMinusDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_MINUS_DISABLED },
+ { "bitmaps/ButtonMinusMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_MINUS_MOUSE_OVER },
+ { "bitmaps/ButtonMinusNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_MINUS_NORMAL },
+ { "bitmaps/ButtonMinusSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_MINUS_SELECTED },
+ { "bitmaps/ButtonNotesDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_NOTES_DISABLED },
+ { "bitmaps/ButtonNotesMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_NOTES_MOUSE_OVER },
+ { "bitmaps/ButtonNotesNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_NOTES_NORMAL },
+ { "bitmaps/ButtonNotesSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_NOTES_SELECTED },
+ { "bitmaps/ButtonPlusDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_PLUS_DISABLED },
+ { "bitmaps/ButtonPlusMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_PLUS_MOUSE_OVER },
+ { "bitmaps/ButtonPlusNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_PLUS_NORMAL },
+ { "bitmaps/ButtonPlusSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_PLUS_SELECTED },
+ { "bitmaps/ButtonSlideNextDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_NEXT_DISABLED },
+ { "bitmaps/ButtonSlideNextMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_NEXT_MOUSE_OVER },
+ { "bitmaps/ButtonSlideNextNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_NEXT_NORMAL },
+ { "bitmaps/ButtonSlidePreviousDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_PREVIOUS_DISABLED },
+ { "bitmaps/ButtonSlidePreviousMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_PREVIOUS_MOUSE_OVER },
+ { "bitmaps/ButtonSlidePreviousNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_PREVIOUS_NORMAL },
+ { "bitmaps/ButtonSlidePreviousSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_PREVIOUS_SELECTED },
+ { "bitmaps/ButtonSlideSorterDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_SORTER_DISABLED },
+ { "bitmaps/ButtonSlideSorterMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_SORTER_MOUSE_OVER },
+ { "bitmaps/ButtonSlideSorterNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_SORTER_NORMAL },
+ { "bitmaps/ButtonSlideSorterSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_SORTER_SELECTED },
+ { "bitmaps/ButtonSwitchMonitorMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_SWITCH_MONITOR_MOUSE_OVER },
+ { "bitmaps/ButtonSwitchMonitorNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_SWITCH_MONITOR_NORMAL },
+ { "bitmaps/ButtonRestartTimerMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_RESTART_TIMER_MOUSE_OVER },
+ { "bitmaps/ButtonRestartTimerNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_RESTART_TIMER_NORMAL },
+ { "bitmaps/ButtonPauseTimerMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_PAUSE_TIMER_MOUSE_OVER },
+ { "bitmaps/ButtonPauseTimerNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_PAUSE_TIMER_NORMAL },
+ { "bitmaps/ButtonResumeTimerMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_RESUME_TIMER_MOUSE_OVER },
+ { "bitmaps/ButtonResumeTimerNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_RESUME_TIMER_NORMAL },
+ { "bitmaps/LabelMouseOverCenter.png",
+ BMP_PRESENTERSCREEN_LABEL_MOUSE_OVER_CENTER },
+ { "bitmaps/LabelMouseOverLeft.png",
+ BMP_PRESENTERSCREEN_LABEL_MOUSE_OVER_LEFT },
+ { "bitmaps/LabelMouseOverRight.png",
+ BMP_PRESENTERSCREEN_LABEL_MOUSE_OVER_RIGHT },
+ { "bitmaps/ScrollbarArrowDownDisabled.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_DOWN_DISABLED },
+ { "bitmaps/ScrollbarArrowDownMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_DOWN_MOUSE_OVER },
+ { "bitmaps/ScrollbarArrowDownNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_DOWN_NORMAL },
+ { "bitmaps/ScrollbarArrowDownSelected.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_DOWN_SELECTED },
+ { "bitmaps/ScrollbarArrowUpDisabled.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_UP_DISABLED },
+ { "bitmaps/ScrollbarArrowUpMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_UP_MOUSE_OVER },
+ { "bitmaps/ScrollbarArrowUpNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_UP_NORMAL },
+ { "bitmaps/ScrollbarArrowUpSelected.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_UP_SELECTED },
+ { "bitmaps/ScrollbarPagerMiddleMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_PAGER_MIDDLE_MOUSE_OVER },
+ { "bitmaps/ScrollbarPagerMiddleNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_PAGER_MIDDLE_NORMAL },
+ { "bitmaps/ScrollbarThumbBottomMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_BOTTOM_MOUSE_OVER },
+ { "bitmaps/ScrollbarThumbBottomNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_BOTTOM_NORMAL },
+ { "bitmaps/ScrollbarThumbMiddleMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_MIDDLE_MOUSE_OVER },
+ { "bitmaps/ScrollbarThumbMiddleNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_MIDDLE_NORMAL },
+ { "bitmaps/ScrollbarThumbTopMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_TOP_MOUSE_OVER },
+ { "bitmaps/ScrollbarThumbTopNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_TOP_NORMAL },
+ { "bitmaps/ViewBackground.png", BMP_PRESENTERSCREEN_VIEW_BACKGROUND },
+ { "bitmaps/Separator.png",
+ BMP_PRESENTERSCREEN_SEPARATOR }
+ };
+ OUString bmpid;
+ for (std::size_t i = 0; i != SAL_N_ELEMENTS(map); ++i) {
+ if (id.equalsAscii(map[i].sid)) {
+ bmpid = map[i].bmpid;
+ break;
+ }
+ }
+ if (bmpid.isEmpty()) {
+ return nullptr;
+ }
+
+ ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
+
+ const cppcanvas::CanvasSharedPtr pCanvas (
+ cppcanvas::VCLFactory::createCanvas(rxCanvas));
+
+ if (pCanvas)
+ {
+ BitmapEx aBitmapEx(bmpid);
+ cppcanvas::BitmapSharedPtr xBitmap(
+ cppcanvas::VCLFactory::createBitmap(pCanvas,
+ aBitmapEx));
+ if (!xBitmap)
+ return nullptr;
+ return xBitmap->getUNOBitmap();
+ }
+
+ return nullptr;
+}
+
+void SAL_CALL PresenterHelper::captureMouse (
+ const Reference<awt::XWindow>& rxWindow)
+{
+ ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
+
+ // Capture the mouse (if not already done.)
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(rxWindow);
+ if (pWindow && ! pWindow->IsMouseCaptured())
+ {
+ pWindow->CaptureMouse();
+ }
+}
+
+void SAL_CALL PresenterHelper::releaseMouse (const Reference<awt::XWindow>& rxWindow)
+{
+ ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
+
+ // Release the mouse (if not already done.)
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(rxWindow);
+ if (pWindow && pWindow->IsMouseCaptured())
+ {
+ pWindow->ReleaseMouse();
+ }
+}
+
+awt::Rectangle PresenterHelper::getWindowExtentsRelative (
+ const Reference<awt::XWindow>& rxChildWindow,
+ const Reference<awt::XWindow>& rxParentWindow)
+{
+ VclPtr<vcl::Window> pChildWindow = VCLUnoHelper::GetWindow(rxChildWindow);
+ VclPtr<vcl::Window> pParentWindow = VCLUnoHelper::GetWindow(rxParentWindow);
+ if (pChildWindow && pParentWindow)
+ {
+ ::tools::Rectangle aBox (pChildWindow->GetWindowExtentsRelative(pParentWindow));
+ return awt::Rectangle(aBox.Left(),aBox.Top(),aBox.GetWidth(),aBox.GetHeight());
+ }
+ else
+ return awt::Rectangle();
+}
+
+} // end of namespace ::sd::presenter
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_PresenterHelper_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::presenter::PresenterHelper(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterHelper.hxx b/sd/source/ui/presenter/PresenterHelper.hxx
new file mode 100644
index 000000000..cee7e39fb
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterHelper.hxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/XPresenterHelper.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace sd::presenter {
+
+typedef comphelper::WeakComponentImplHelper<
+ css::lang::XInitialization,
+ css::drawing::XPresenterHelper
+> PresenterHelperInterfaceBase;
+
+/** Implementation of the XPresenterHelper interface: functionality that can
+ not be implemented in an extension.
+*/
+class PresenterHelper final
+ : public PresenterHelperInterfaceBase
+{
+public:
+ explicit PresenterHelper (const css::uno::Reference<css::uno::XComponentContext>& rxContext);
+ virtual ~PresenterHelper() override;
+ PresenterHelper(const PresenterHelper&) = delete;
+ PresenterHelper& operator=(const PresenterHelper&) = delete;
+
+ // XInitialize
+
+ virtual void SAL_CALL initialize (const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ // XPresenterHelper
+
+ virtual css::uno::Reference<css::awt::XWindow> SAL_CALL createWindow (
+ const css::uno::Reference<css::awt::XWindow>& rxParentWindow,
+ sal_Bool bCreateSystemChildWindow,
+ sal_Bool bInitiallyVisible,
+ sal_Bool bEnableChildTransparentMode,
+ sal_Bool bEnableParentClip) override;
+
+ virtual css::uno::Reference<css::rendering::XCanvas> SAL_CALL createSharedCanvas (
+ const css::uno::Reference<css::rendering::XSpriteCanvas>& rxUpdateCanvas,
+ const css::uno::Reference<css::awt::XWindow>& rxUpdateWindow,
+ const css::uno::Reference<css::rendering::XCanvas>& rxSharedCanvas,
+ const css::uno::Reference<css::awt::XWindow>& rxSharedWindow,
+ const css::uno::Reference<css::awt::XWindow>& rxWindow) override;
+
+ virtual css::uno::Reference<css::rendering::XCanvas> SAL_CALL createCanvas (
+ const css::uno::Reference<css::awt::XWindow>& rxWindow,
+ sal_Int16 nRequestedCanvasFeatures,
+ const OUString& rsOptionalCanvasServiceName) override;
+
+ virtual void SAL_CALL toTop (
+ const css::uno::Reference<css::awt::XWindow>& rxWindow) override;
+
+ virtual css::uno::Reference<css::rendering::XBitmap> SAL_CALL loadBitmap (
+ const OUString& rsURL,
+ const css::uno::Reference<css::rendering::XCanvas>& rxCanvas) override;
+
+ virtual void SAL_CALL captureMouse (const css::uno::Reference<css::awt::XWindow>& rxWindow) override;
+
+ virtual void SAL_CALL releaseMouse (const css::uno::Reference<css::awt::XWindow>& rxWindow) override;
+
+ virtual css::awt::Rectangle SAL_CALL getWindowExtentsRelative (
+ const css::uno::Reference<css::awt::XWindow>& rxChildWindow,
+ const css::uno::Reference<css::awt::XWindow>& rxParentWindow) override;
+
+private:
+ css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterPreviewCache.cxx b/sd/source/ui/presenter/PresenterPreviewCache.cxx
new file mode 100644
index 000000000..fd29cdbfa
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterPreviewCache.cxx
@@ -0,0 +1,360 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PresenterPreviewCache.hxx"
+
+#include <cache/SlsPageCache.hxx>
+#include <cache/SlsCacheContext.hxx>
+#include <vcl/bitmapex.hxx>
+#include <sdpage.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <osl/diagnose.h>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::sd::slidesorter::cache;
+
+namespace sd::presenter {
+
+class PresenterPreviewCache::PresenterCacheContext : public CacheContext
+{
+public:
+ PresenterCacheContext();
+
+ void SetDocumentSlides (
+ const Reference<container::XIndexAccess>& rxSlides,
+ const Reference<XInterface>& rxDocument);
+ void SetVisibleSlideRange (
+ const sal_Int32 nFirstVisibleSlideIndex,
+ const sal_Int32 nLastVisibleSlideIndex);
+ const SdrPage* GetPage (const sal_Int32 nSlideIndex) const;
+ void AddPreviewCreationNotifyListener (const Reference<drawing::XSlidePreviewCacheListener>& rxListener);
+ void RemovePreviewCreationNotifyListener (const Reference<drawing::XSlidePreviewCacheListener>& rxListener);
+
+ // CacheContext
+ virtual void NotifyPreviewCreation (CacheKey aKey) override;
+ virtual bool IsIdle() override;
+ virtual bool IsVisible (CacheKey aKey) override;
+ virtual const SdrPage* GetPage (CacheKey aKey) override;
+ virtual std::shared_ptr<std::vector<CacheKey> > GetEntryList (bool bVisible) override;
+ virtual sal_Int32 GetPriority (CacheKey aKey) override;
+ virtual css::uno::Reference<css::uno::XInterface> GetModel() override;
+
+private:
+ Reference<container::XIndexAccess> mxSlides;
+ Reference<XInterface> mxDocument;
+ sal_Int32 mnFirstVisibleSlideIndex;
+ sal_Int32 mnLastVisibleSlideIndex;
+ typedef ::std::vector<css::uno::Reference<css::drawing::XSlidePreviewCacheListener> > ListenerContainer;
+ ListenerContainer maListeners;
+
+ void CallListeners (const sal_Int32 nSlideIndex);
+};
+
+//===== PresenterPreviewCache =================================================
+
+PresenterPreviewCache::PresenterPreviewCache ()
+ : maPreviewSize(Size(200,200)),
+ mpCacheContext(std::make_shared<PresenterCacheContext>()),
+ mpCache(std::make_shared<PageCache>(maPreviewSize, Bitmap::HasFastScale(), mpCacheContext))
+{
+}
+
+PresenterPreviewCache::~PresenterPreviewCache()
+{
+}
+
+//----- XInitialize -----------------------------------------------------------
+
+void SAL_CALL PresenterPreviewCache::initialize (const Sequence<Any>& rArguments)
+{
+ if (rArguments.hasElements())
+ throw RuntimeException();
+}
+
+//----- XSlidePreviewCache ----------------------------------------------------
+
+void SAL_CALL PresenterPreviewCache::setDocumentSlides (
+ const Reference<container::XIndexAccess>& rxSlides,
+ const Reference<XInterface>& rxDocument)
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCacheContext != nullptr);
+
+ mpCacheContext->SetDocumentSlides(rxSlides, rxDocument);
+}
+
+void SAL_CALL PresenterPreviewCache::setVisibleRange (
+ sal_Int32 nFirstVisibleSlideIndex,
+ sal_Int32 nLastVisibleSlideIndex)
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCacheContext != nullptr);
+
+ mpCacheContext->SetVisibleSlideRange (nFirstVisibleSlideIndex, nLastVisibleSlideIndex);
+}
+
+void SAL_CALL PresenterPreviewCache::setPreviewSize (
+ const css::geometry::IntegerSize2D& rSize)
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCache != nullptr);
+
+ maPreviewSize = Size(rSize.Width, rSize.Height);
+ mpCache->ChangeSize(maPreviewSize, Bitmap::HasFastScale());
+}
+
+Reference<rendering::XBitmap> SAL_CALL PresenterPreviewCache::getSlidePreview (
+ sal_Int32 nSlideIndex,
+ const Reference<rendering::XCanvas>& rxCanvas)
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCacheContext != nullptr);
+
+ cppcanvas::CanvasSharedPtr pCanvas (
+ cppcanvas::VCLFactory::createCanvas(rxCanvas));
+
+ const SdrPage* pPage = mpCacheContext->GetPage(nSlideIndex);
+ if (pPage == nullptr)
+ throw RuntimeException();
+
+ const BitmapEx aPreview (mpCache->GetPreviewBitmap(pPage,true));
+ if (aPreview.IsEmpty())
+ return nullptr;
+ else
+ return cppcanvas::VCLFactory::createBitmap(
+ pCanvas,
+ aPreview)->getUNOBitmap();
+}
+
+void SAL_CALL PresenterPreviewCache::addPreviewCreationNotifyListener (
+ const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
+{
+ if (m_bDisposed)
+ return;
+ if (rxListener.is())
+ mpCacheContext->AddPreviewCreationNotifyListener(rxListener);
+}
+
+void SAL_CALL PresenterPreviewCache::removePreviewCreationNotifyListener (
+ const css::uno::Reference<css::drawing::XSlidePreviewCacheListener>& rxListener)
+{
+ ThrowIfDisposed();
+ mpCacheContext->RemovePreviewCreationNotifyListener(rxListener);
+}
+
+void SAL_CALL PresenterPreviewCache::pause()
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCache != nullptr);
+ mpCache->Pause();
+}
+
+void SAL_CALL PresenterPreviewCache::resume()
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCache != nullptr);
+ mpCache->Resume();
+}
+
+void PresenterPreviewCache::ThrowIfDisposed()
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("PresenterPreviewCache object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+//===== PresenterPreviewCache::PresenterCacheContext ==========================
+
+PresenterPreviewCache::PresenterCacheContext::PresenterCacheContext()
+ : mnFirstVisibleSlideIndex(-1),
+ mnLastVisibleSlideIndex(-1)
+{
+}
+
+void PresenterPreviewCache::PresenterCacheContext::SetDocumentSlides (
+ const Reference<container::XIndexAccess>& rxSlides,
+ const Reference<XInterface>& rxDocument)
+{
+ mxSlides = rxSlides;
+ mxDocument = rxDocument;
+ mnFirstVisibleSlideIndex = -1;
+ mnLastVisibleSlideIndex = -1;
+}
+
+void PresenterPreviewCache::PresenterCacheContext::SetVisibleSlideRange (
+ const sal_Int32 nFirstVisibleSlideIndex,
+ const sal_Int32 nLastVisibleSlideIndex)
+{
+ if (nFirstVisibleSlideIndex > nLastVisibleSlideIndex || nFirstVisibleSlideIndex<0)
+ {
+ mnFirstVisibleSlideIndex = -1;
+ mnLastVisibleSlideIndex = -1;
+ }
+ else
+ {
+ mnFirstVisibleSlideIndex = nFirstVisibleSlideIndex;
+ mnLastVisibleSlideIndex = nLastVisibleSlideIndex;
+ }
+ if (mxSlides.is() && mnLastVisibleSlideIndex >= mxSlides->getCount())
+ mnLastVisibleSlideIndex = mxSlides->getCount() - 1;
+}
+
+void PresenterPreviewCache::PresenterCacheContext::AddPreviewCreationNotifyListener (
+ const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
+{
+ maListeners.push_back(rxListener);
+}
+
+void PresenterPreviewCache::PresenterCacheContext::RemovePreviewCreationNotifyListener (
+ const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
+{
+ auto iListener = std::find(maListeners.begin(), maListeners.end(), rxListener);
+ if (iListener != maListeners.end())
+ maListeners.erase(iListener);
+}
+
+//----- CacheContext ----------------------------------------------------------
+
+void PresenterPreviewCache::PresenterCacheContext::NotifyPreviewCreation (
+ CacheKey aKey)
+{
+ if ( ! mxSlides.is())
+ return;
+ const sal_Int32 nCount(mxSlides->getCount());
+ for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
+ if (aKey == GetPage(nIndex))
+ CallListeners(nIndex);
+}
+
+bool PresenterPreviewCache::PresenterCacheContext::IsIdle()
+{
+ return true;
+}
+
+bool PresenterPreviewCache::PresenterCacheContext::IsVisible (CacheKey aKey)
+{
+ if (mnFirstVisibleSlideIndex < 0)
+ return false;
+ for (sal_Int32 nIndex=mnFirstVisibleSlideIndex; nIndex<=mnLastVisibleSlideIndex; ++nIndex)
+ {
+ const SdrPage* pPage = GetPage(nIndex);
+ if (pPage == aKey)
+ return true;
+ }
+ return false;
+}
+
+const SdrPage* PresenterPreviewCache::PresenterCacheContext::GetPage (CacheKey aKey)
+{
+ return aKey;
+}
+
+std::shared_ptr<std::vector<CacheKey> >
+ PresenterPreviewCache::PresenterCacheContext::GetEntryList (bool bVisible)
+{
+ auto pKeys = std::make_shared<std::vector<CacheKey>>();
+
+ if ( ! mxSlides.is())
+ return pKeys;
+
+ const sal_Int32 nFirstIndex (bVisible ? mnFirstVisibleSlideIndex : 0);
+ const sal_Int32 nLastIndex (bVisible ? mnLastVisibleSlideIndex : mxSlides->getCount()-1);
+
+ if (nFirstIndex < 0)
+ return pKeys;
+
+ for (sal_Int32 nIndex=nFirstIndex; nIndex<=nLastIndex; ++nIndex)
+ {
+ pKeys->push_back(GetPage(nIndex));
+ }
+
+ return pKeys;
+}
+
+sal_Int32 PresenterPreviewCache::PresenterCacheContext::GetPriority (CacheKey aKey)
+{
+ if ( ! mxSlides.is())
+ return 0;
+
+ const sal_Int32 nCount (mxSlides->getCount());
+
+ for (sal_Int32 nIndex=mnFirstVisibleSlideIndex; nIndex<=mnLastVisibleSlideIndex; ++nIndex)
+ if (aKey == GetPage(nIndex))
+ return -nCount-1+nIndex;
+
+ for (sal_Int32 nIndex=0; nIndex<=nCount; ++nIndex)
+ if (aKey == GetPage(nIndex))
+ return nIndex;
+
+ return 0;
+}
+
+Reference<XInterface> PresenterPreviewCache::PresenterCacheContext::GetModel()
+{
+ return mxDocument;
+}
+
+const SdrPage* PresenterPreviewCache::PresenterCacheContext::GetPage (
+ const sal_Int32 nSlideIndex) const
+{
+ if ( ! mxSlides.is())
+ return nullptr;
+ if (nSlideIndex < 0 || nSlideIndex >= mxSlides->getCount())
+ return nullptr;
+
+ Reference<drawing::XDrawPage> xSlide (mxSlides->getByIndex(nSlideIndex), UNO_QUERY);
+ const SdPage* pPage = SdPage::getImplementation(xSlide);
+ return pPage;
+}
+
+void PresenterPreviewCache::PresenterCacheContext::CallListeners (
+ const sal_Int32 nIndex)
+{
+ ListenerContainer aListeners (maListeners);
+ for (const auto& rxListener : aListeners)
+ {
+ try
+ {
+ rxListener->notifyPreviewCreation(nIndex);
+ }
+ catch (lang::DisposedException&)
+ {
+ RemovePreviewCreationNotifyListener(rxListener);
+ }
+ }
+}
+
+} // end of namespace ::sd::presenter
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_PresenterPreviewCache_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::presenter::PresenterPreviewCache);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterPreviewCache.hxx b/sd/source/ui/presenter/PresenterPreviewCache.hxx
new file mode 100644
index 000000000..4f8c52280
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterPreviewCache.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/XSlidePreviewCache.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <tools/gen.hxx>
+#include <comphelper/compbase.hxx>
+#include <memory>
+
+namespace sd::slidesorter::cache { class PageCache; }
+
+namespace sd::presenter {
+
+typedef comphelper::WeakComponentImplHelper<
+ css::lang::XInitialization,
+ css::drawing::XSlidePreviewCache
+> PresenterPreviewCacheInterfaceBase;
+
+/** Uno API wrapper around the slide preview cache.
+*/
+class PresenterPreviewCache final
+ : public PresenterPreviewCacheInterfaceBase
+{
+public:
+ PresenterPreviewCache ();
+ virtual ~PresenterPreviewCache() override;
+ PresenterPreviewCache(const PresenterPreviewCache&) = delete;
+ PresenterPreviewCache& operator=(const PresenterPreviewCache&) = delete;
+
+ // XInitialize
+
+ /** Accepts no arguments. All values that are necessary to set up a
+ preview cache can be provided via methods.
+ */
+ virtual void SAL_CALL initialize (const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ // XSlidePreviewCache
+
+ virtual void SAL_CALL setDocumentSlides (
+ const css::uno::Reference<css::container::XIndexAccess>& rxSlides,
+ const css::uno::Reference<css::uno::XInterface>& rxDocument) override;
+
+ virtual void SAL_CALL setVisibleRange (
+ sal_Int32 nFirstVisibleSlideIndex,
+ sal_Int32 nLastVisibleSlideIndex) override;
+
+ virtual void SAL_CALL setPreviewSize (
+ const css::geometry::IntegerSize2D& rSize) override;
+
+ virtual css::uno::Reference<css::rendering::XBitmap> SAL_CALL
+ getSlidePreview (
+ sal_Int32 nSlideIndex,
+ const css::uno::Reference<css::rendering::XCanvas>& rxCanvas) override;
+
+ virtual void SAL_CALL addPreviewCreationNotifyListener (
+ const css::uno::Reference<css::drawing::XSlidePreviewCacheListener>& rxListener) override;
+
+ virtual void SAL_CALL removePreviewCreationNotifyListener (
+ const css::uno::Reference<css::drawing::XSlidePreviewCacheListener>& rxListener) override;
+
+ virtual void SAL_CALL pause() override;
+
+ virtual void SAL_CALL resume() override;
+
+private:
+ class PresenterCacheContext;
+ Size maPreviewSize;
+ std::shared_ptr<PresenterCacheContext> mpCacheContext;
+ std::shared_ptr<sd::slidesorter::cache::PageCache> mpCache;
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterTextView.cxx b/sd/source/ui/presenter/PresenterTextView.cxx
new file mode 100644
index 000000000..affa21b03
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterTextView.cxx
@@ -0,0 +1,466 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PresenterTextView.hxx"
+
+#include <i18nlangtag/mslangid.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <svl/itempool.hxx>
+#include <unotools/lingucfg.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+constexpr OUStringLiteral gsTextPropertyName(u"Text");
+constexpr OUStringLiteral gsBitmapPropertyName(u"Bitmap");
+constexpr OUStringLiteral gsSizePropertyName(u"Size");
+constexpr OUStringLiteral gsBackgroundColorPropertyName(u"BackgroundColor");
+constexpr OUStringLiteral gsTextColorPropertyName(u"TextColor");
+constexpr OUStringLiteral gsFontDescriptorPropertyName(u"FontDescriptor");
+constexpr OUStringLiteral gsTopPropertyName(u"Top");
+constexpr OUStringLiteral gsTopRelativePropertyName(u"RelativeTop");
+constexpr OUStringLiteral gsTotalHeightPropertyName(u"TotalHeight");
+
+namespace sd::presenter {
+
+// PresenterTextView::Implementation
+class PresenterTextView::Implementation
+{
+public:
+ Implementation();
+ ~Implementation();
+
+ void SetCanvas (const cppcanvas::CanvasSharedPtr& rCanvas);
+ void SetSize (const Size aSize);
+ void SetBackgroundColor (const Color aColor);
+ void SetTextColor (const Color aColor);
+ void SetFontDescriptor (const awt::FontDescriptor& rFontDescriptor);
+ sal_Int32 GetTop() const { return mnTop;}
+ void SetTop (const sal_Int32 nTop);
+ void SetText (const OUString& Text);
+ sal_Int32 ParseDistance (const OUString& rsDistance) const;
+ Reference<rendering::XBitmap> const & GetBitmap();
+ sal_Int32 GetTotalHeight();
+
+private:
+ Reference<rendering::XBitmap> mxBitmap;
+ cppcanvas::CanvasSharedPtr mpCanvas;
+ VclPtr<VirtualDevice> mpOutputDevice;
+ std::unique_ptr<EditEngine> mpEditEngine;
+ rtl::Reference<SfxItemPool> mpEditEngineItemPool;
+ Size maSize;
+ OUString msText;
+ sal_Int32 mnTop;
+ sal_Int32 mnTotalHeight;
+
+ void CheckTop();
+};
+
+// PresenterTextView
+PresenterTextView::PresenterTextView ()
+ : mpImplementation(new Implementation())
+{
+}
+
+PresenterTextView::~PresenterTextView()
+{
+}
+
+void SAL_CALL PresenterTextView::disposing()
+{
+ mpImplementation.reset();
+}
+
+// XInitialization
+void SAL_CALL PresenterTextView::initialize (const Sequence<Any>& rArguments)
+{
+ ThrowIfDisposed();
+
+ if (rArguments.getLength() != 1)
+ {
+ throw RuntimeException("PresenterTextView: invalid number of arguments",
+ static_cast<XWeak*>(this));
+ }
+
+ Reference<rendering::XCanvas> xCanvas (rArguments[0], UNO_QUERY_THROW);
+ mpImplementation->SetCanvas(
+ cppcanvas::VCLFactory::createCanvas(xCanvas));
+}
+
+Any PresenterTextView::GetPropertyValue (const OUString& rsPropertyName)
+{
+ ThrowIfDisposed();
+
+ if (rsPropertyName == gsBitmapPropertyName)
+ {
+ return Any(mpImplementation->GetBitmap());
+ }
+ else if (rsPropertyName == gsTopPropertyName)
+ {
+ return Any(mpImplementation->GetTop());
+ }
+ else if (rsPropertyName == gsTotalHeightPropertyName)
+ {
+ return Any(mpImplementation->GetTotalHeight());
+ }
+
+ return Any();
+}
+
+Any PresenterTextView::SetPropertyValue (
+ const OUString& rsPropertyName,
+ const css::uno::Any& rValue)
+{
+ ThrowIfDisposed();
+
+ Any aOldValue;
+ if (rsPropertyName == gsTextPropertyName)
+ {
+ OUString sText;
+ if (rValue >>= sText)
+ mpImplementation->SetText(sText);
+ }
+ else if (rsPropertyName == gsSizePropertyName)
+ {
+ awt::Size aSize;
+ if (rValue >>= aSize)
+ mpImplementation->SetSize(Size(aSize.Width,aSize.Height));
+ }
+ else if (rsPropertyName == gsBackgroundColorPropertyName)
+ {
+ ::Color aColor;
+ if (rValue >>= aColor)
+ mpImplementation->SetBackgroundColor(aColor);
+ }
+ else if (rsPropertyName == gsTextColorPropertyName)
+ {
+ ::Color aColor;
+ if (rValue >>= aColor)
+ mpImplementation->SetTextColor(aColor);
+ }
+ else if (rsPropertyName == gsFontDescriptorPropertyName)
+ {
+ awt::FontDescriptor aFontDescriptor;
+ if (rValue >>= aFontDescriptor)
+ mpImplementation->SetFontDescriptor(aFontDescriptor);
+ }
+ else if (rsPropertyName == gsTopPropertyName)
+ {
+ sal_Int32 nTop = 0;
+ if (rValue >>= nTop)
+ mpImplementation->SetTop(nTop);
+ }
+ else if (rsPropertyName == gsTopRelativePropertyName)
+ {
+ OUString sDistance;
+ if (rValue >>= sDistance)
+ mpImplementation->SetTop(
+ mpImplementation->GetTop()
+ + mpImplementation->ParseDistance(sDistance));
+ }
+ return aOldValue;
+}
+
+void PresenterTextView::ThrowIfDisposed()
+{
+ if (PresenterTextViewInterfaceBase::rBHelper.bDisposed
+ || PresenterTextViewInterfaceBase::rBHelper.bInDispose || mpImplementation == nullptr)
+ {
+ throw lang::DisposedException ("PresenterTextView object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+// PresenterTextView::Implementation
+PresenterTextView::Implementation::Implementation()
+ : mpOutputDevice(VclPtr<VirtualDevice>::Create(*Application::GetDefaultDevice(), DeviceFormat::DEFAULT, DeviceFormat::DEFAULT)),
+ mpEditEngineItemPool(EditEngine::CreatePool()),
+ maSize(100,100),
+ mnTop(0),
+ mnTotalHeight(-1)
+{
+ mpOutputDevice->SetMapMode(MapMode(MapUnit::MapPixel));
+
+ // set fonts to be used
+ SvtLinguOptions aOpt;
+ SvtLinguConfig().GetOptions( aOpt );
+
+ struct FontDta {
+ LanguageType nFallbackLang;
+ LanguageType nLang;
+ DefaultFontType nFontType;
+ sal_uInt16 nFontInfoId;
+ } aTable[3] =
+ {
+ // info to get western font to be used
+ { LANGUAGE_ENGLISH_US, LANGUAGE_NONE,
+ DefaultFontType::SERIF, EE_CHAR_FONTINFO },
+ // info to get CJK font to be used
+ { LANGUAGE_JAPANESE, LANGUAGE_NONE,
+ DefaultFontType::CJK_TEXT, EE_CHAR_FONTINFO_CJK },
+ // info to get CTL font to be used
+ { LANGUAGE_ARABIC_SAUDI_ARABIA, LANGUAGE_NONE,
+ DefaultFontType::CTL_TEXT, EE_CHAR_FONTINFO_CTL }
+ };
+ aTable[0].nLang = MsLangId::resolveSystemLanguageByScriptType(aOpt.nDefaultLanguage, css::i18n::ScriptType::LATIN);
+ aTable[1].nLang = MsLangId::resolveSystemLanguageByScriptType(aOpt.nDefaultLanguage_CJK, css::i18n::ScriptType::ASIAN);
+ aTable[2].nLang = MsLangId::resolveSystemLanguageByScriptType(aOpt.nDefaultLanguage_CTL, css::i18n::ScriptType::COMPLEX);
+
+ for (const FontDta & rFntDta : aTable)
+ {
+ LanguageType nLang = (LANGUAGE_NONE == rFntDta.nLang) ?
+ rFntDta.nFallbackLang : rFntDta.nLang;
+ vcl::Font aFont = OutputDevice::GetDefaultFont(
+ rFntDta.nFontType, nLang, GetDefaultFontFlags::OnlyOne);
+ mpEditEngineItemPool->SetPoolDefaultItem(
+ SvxFontItem(
+ aFont.GetFamilyType(),
+ aFont.GetFamilyName(),
+ aFont.GetStyleName(),
+ aFont.GetPitch(),
+ aFont.GetCharSet(),
+ rFntDta.nFontInfoId));
+ }
+
+ mpEditEngine.reset( new EditEngine (mpEditEngineItemPool.get()) );
+
+ mpEditEngine->EnableUndo (true);
+ mpEditEngine->SetDefTab (sal_uInt16(
+ Application::GetDefaultDevice()->GetTextWidth("XXXX")));
+
+ mpEditEngine->SetControlWord(
+ EEControlBits(mpEditEngine->GetControlWord() | EEControlBits::AUTOINDENTING) &
+ EEControlBits(~EEControlBits::UNDOATTRIBS) &
+ EEControlBits(~EEControlBits::PASTESPECIAL) );
+
+ mpEditEngine->SetWordDelimiters (" .=+-*/(){}[];\"");
+ mpEditEngine->SetRefMapMode(MapMode(MapUnit::MapPixel));
+ mpEditEngine->SetPaperSize (Size(800, 0));
+ mpEditEngine->EraseVirtualDevice();
+ mpEditEngine->ClearModifyFlag();
+}
+
+PresenterTextView::Implementation::~Implementation()
+{
+ mpEditEngine.reset();
+ mpEditEngineItemPool.clear();
+ mpOutputDevice.disposeAndClear();
+}
+
+void PresenterTextView::Implementation::SetCanvas (const cppcanvas::CanvasSharedPtr& rpCanvas)
+{
+ mpCanvas = rpCanvas;
+ mxBitmap = nullptr;
+}
+
+void PresenterTextView::Implementation::SetSize (const Size aSize)
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+
+ maSize = aSize;
+ mpEditEngine->SetPaperSize(maSize);
+ mnTotalHeight = -1;
+ mxBitmap = nullptr;
+}
+
+void PresenterTextView::Implementation::SetBackgroundColor (const Color aColor)
+{
+ mxBitmap = nullptr;
+
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+ DBG_ASSERT(mpEditEngineItemPool!=nullptr, "EditEngineItemPool missing");
+ mpEditEngine->SetBackgroundColor(aColor);
+ mpEditEngine->EnableAutoColor(false);
+ mpEditEngine->ForceAutoColor(false);
+}
+
+void PresenterTextView::Implementation::SetTextColor (const Color aColor)
+{
+ mxBitmap = nullptr;
+
+ DBG_ASSERT(mpEditEngineItemPool!=nullptr, "EditEngineItemPool missing");
+ mpEditEngineItemPool->SetPoolDefaultItem(SvxColorItem(aColor, EE_CHAR_COLOR));
+}
+
+void PresenterTextView::Implementation::SetFontDescriptor (
+ const awt::FontDescriptor& rFontDescriptor)
+{
+ mxBitmap = nullptr;
+
+ DBG_ASSERT(mpEditEngineItemPool!=nullptr, "EditEngineItemPool missing");
+
+ const sal_Int32 nFontHeight = rFontDescriptor.Height;
+
+ SvxFontHeightItem aFontHeight(
+ Application::GetDefaultDevice()->LogicToPixel(
+ Size(0, nFontHeight), MapMode (MapUnit::MapPoint)).Height(),
+ 100,
+ EE_CHAR_FONTHEIGHT);
+ mpEditEngineItemPool->SetPoolDefaultItem( aFontHeight);
+ aFontHeight.SetWhich (EE_CHAR_FONTHEIGHT_CJK);
+ mpEditEngineItemPool->SetPoolDefaultItem( aFontHeight);
+ aFontHeight.SetWhich (EE_CHAR_FONTHEIGHT_CTL);
+ mpEditEngineItemPool->SetPoolDefaultItem( aFontHeight);
+
+ SvxFontItem aSvxFontItem (EE_CHAR_FONTINFO);
+ aSvxFontItem.SetFamilyName( rFontDescriptor.Name );
+ mpEditEngineItemPool->SetPoolDefaultItem(aSvxFontItem);
+
+ mnTotalHeight = -1;
+ mxBitmap = nullptr;
+
+ CheckTop();
+ mnTotalHeight = -1;
+}
+
+void PresenterTextView::Implementation::SetTop (const sal_Int32 nTop)
+{
+ if (nTop == mnTop)
+ return;
+
+ mnTop = nTop;
+ mxBitmap = nullptr;
+ CheckTop();
+}
+
+void PresenterTextView::Implementation::SetText (const OUString& rText)
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+ msText = rText;
+ mpEditEngine->SetPaperSize(maSize);
+ mnTotalHeight = -1;
+ mxBitmap = nullptr;
+}
+
+sal_Int32 PresenterTextView::Implementation::ParseDistance (const OUString& rsDistance) const
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+ sal_Int32 nDistance (0);
+ if (rsDistance.endsWith("px"))
+ {
+ nDistance = o3tl::toInt32(rsDistance.subView(0,rsDistance.getLength()-2));
+ }
+ else if (rsDistance.endsWith("l"))
+ {
+ const sal_Int32 nLines (o3tl::toInt32(rsDistance.subView(0,rsDistance.getLength()-1)));
+ // Take the height of the first line as the height of every line.
+ const sal_uInt32 nFirstLineHeight (mpEditEngine->GetLineHeight(0));
+ nDistance = nFirstLineHeight * nLines;
+ }
+
+ return nDistance;
+}
+
+Reference<rendering::XBitmap> const & PresenterTextView::Implementation::GetBitmap()
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+
+ if ( ! mxBitmap.is())
+ {
+ mpOutputDevice.disposeAndClear();
+ mpOutputDevice = VclPtr<VirtualDevice>::Create(*Application::GetDefaultDevice(),
+ DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
+ mpOutputDevice->SetMapMode(MapMode(MapUnit::MapPixel));
+ mpOutputDevice->SetOutputSizePixel(maSize);
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->SetFillColor();
+ mpOutputDevice->SetBackground(Wallpaper());
+ mpOutputDevice->Erase();
+
+ MapMode aMapMode (mpOutputDevice->GetMapMode());
+ aMapMode.SetOrigin(Point(0,0));
+ mpOutputDevice->SetMapMode(aMapMode);
+ const ::tools::Rectangle aWindowBox (Point(0,0), maSize);
+ mpOutputDevice->DrawRect(aWindowBox);
+
+ mpEditEngine->Clear();
+ mpEditEngine->SetText(msText);
+ mpEditEngine->SetPaperSize(maSize);
+
+ mpEditEngine->Draw(*mpOutputDevice, aWindowBox, Point(0,mnTop));
+
+ const BitmapEx aBitmap (mpOutputDevice->GetBitmapEx(Point(0,0), maSize));
+ mxBitmap = cppcanvas::VCLFactory::createBitmap(
+ mpCanvas,
+ aBitmap
+ )->getUNOBitmap();
+ }
+ return mxBitmap;
+}
+
+sal_Int32 PresenterTextView::Implementation::GetTotalHeight()
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+
+ if (mnTotalHeight < 0)
+ {
+ if ( ! mxBitmap.is())
+ GetBitmap();
+ mnTotalHeight = mpEditEngine->GetTextHeight();
+ }
+ return mnTotalHeight;
+}
+
+void PresenterTextView::Implementation::CheckTop()
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+
+ if (mpEditEngine!=nullptr && mnTotalHeight < 0)
+ mnTotalHeight = mpEditEngine->GetTextHeight();
+ if (mpEditEngine!=nullptr && mnTop >= mnTotalHeight)
+ mnTop = mnTotalHeight - mpEditEngine->GetLineHeight(0);
+
+ if (mnTotalHeight < maSize.Height())
+ mnTop = 0;
+
+ if (mnTotalHeight - mnTop < maSize.Height())
+ mnTop = mnTotalHeight - maSize.Height();
+
+ if (mnTop < 0)
+ mnTop = 0;
+}
+
+} // end of namespace ::sd::presenter
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_PresenterTextView_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::presenter::PresenterTextView);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterTextView.hxx b/sd/source/ui/presenter/PresenterTextView.hxx
new file mode 100644
index 000000000..28b68aaa5
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterTextView.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/PropertySet.hxx>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <memory>
+
+namespace sd::presenter {
+
+typedef ::cppu::ImplInheritanceHelper <
+ tools::PropertySet,
+ css::lang::XInitialization
+> PresenterTextViewInterfaceBase;
+
+/** Render text into bitmaps. An edit engine is used to render the text.
+ This service is used by the presenter screen to render the notes view.
+*/
+class PresenterTextView
+ : public PresenterTextViewInterfaceBase
+{
+public:
+ PresenterTextView ();
+ virtual ~PresenterTextView() override;
+ PresenterTextView(const PresenterTextView&) = delete;
+ PresenterTextView& operator=(const PresenterTextView&) = delete;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize (const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+ virtual css::uno::Any GetPropertyValue (
+ const OUString& rsPropertyName) override;
+ virtual css::uno::Any SetPropertyValue (
+ const OUString& rsPropertyName,
+ const css::uno::Any& rValue) override;
+
+private:
+ class Implementation;
+ std::unique_ptr<Implementation> mpImplementation;
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/SlideRenderer.cxx b/sd/source/ui/presenter/SlideRenderer.cxx
new file mode 100644
index 000000000..1b57b195a
--- /dev/null
+++ b/sd/source/ui/presenter/SlideRenderer.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 "SlideRenderer.hxx"
+#include <sdpage.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/svapp.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::presenter {
+
+//===== SlideRenderer ==========================================================
+
+SlideRenderer::SlideRenderer ()
+{
+}
+
+SlideRenderer::~SlideRenderer()
+{
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL SlideRenderer::initialize (const Sequence<Any>& rArguments)
+{
+ ThrowIfDisposed();
+
+ if (rArguments.hasElements())
+ {
+ throw RuntimeException("SlideRenderer: invalid number of arguments",
+ static_cast<XWeak*>(this));
+ }
+}
+
+OUString SlideRenderer::getImplementationName()
+{
+ return "com.sun.star.comp.Draw.SlideRenderer";
+}
+
+sal_Bool SlideRenderer::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> SlideRenderer::getSupportedServiceNames()
+{
+ return {"com.sun.star.drawing.SlideRenderer"};
+}
+
+//----- XSlideRenderer --------------------------------------------------------
+
+Reference<awt::XBitmap> SlideRenderer::createPreview (
+ const Reference<drawing::XDrawPage>& rxSlide,
+ const awt::Size& rMaximalSize,
+ sal_Int16 nSuperSampleFactor)
+{
+ ThrowIfDisposed();
+ SolarMutexGuard aGuard;
+
+ return VCLUnoHelper::CreateBitmap(
+ CreatePreview(rxSlide, rMaximalSize, nSuperSampleFactor));
+}
+
+Reference<rendering::XBitmap> SlideRenderer::createPreviewForCanvas (
+ const Reference<drawing::XDrawPage>& rxSlide,
+ const awt::Size& rMaximalSize,
+ sal_Int16 nSuperSampleFactor,
+ const Reference<rendering::XCanvas>& rxCanvas)
+{
+ ThrowIfDisposed();
+ SolarMutexGuard aGuard;
+
+ cppcanvas::CanvasSharedPtr pCanvas (
+ cppcanvas::VCLFactory::createCanvas(rxCanvas));
+ if (pCanvas)
+ return cppcanvas::VCLFactory::createBitmap(
+ pCanvas,
+ CreatePreview(rxSlide, rMaximalSize, nSuperSampleFactor))->getUNOBitmap();
+ else
+ return nullptr;
+}
+
+awt::Size SAL_CALL SlideRenderer::calculatePreviewSize (
+ double nSlideAspectRatio,
+ const awt::Size& rMaximalSize)
+{
+ if (rMaximalSize.Width <= 0
+ || rMaximalSize.Height <= 0
+ || nSlideAspectRatio <= 0)
+ {
+ return awt::Size(0,0);
+ }
+
+ const double nWindowAspectRatio (double(rMaximalSize.Width) / double(rMaximalSize.Height));
+ if (nSlideAspectRatio < nWindowAspectRatio)
+ return awt::Size(
+ sal::static_int_cast<sal_Int32>(rMaximalSize.Height * nSlideAspectRatio),
+ rMaximalSize.Height);
+ else
+ return awt::Size(
+ rMaximalSize.Width,
+ sal::static_int_cast<sal_Int32>(rMaximalSize.Width / nSlideAspectRatio));
+}
+
+BitmapEx SlideRenderer::CreatePreview (
+ const Reference<drawing::XDrawPage>& rxSlide,
+ const awt::Size& rMaximalSize,
+ sal_Int16 nSuperSampleFactor)
+{
+ const SdPage* pPage = SdPage::getImplementation(rxSlide);
+ if (pPage == nullptr)
+ throw lang::IllegalArgumentException("SlideRenderer::createPreview() called with invalid slide",
+ static_cast<XWeak*>(this),
+ 0);
+
+ // Determine the size of the current slide and its aspect ratio.
+ Size aPageSize = pPage->GetSize();
+ if (aPageSize.Height() <= 0)
+ throw lang::IllegalArgumentException("SlideRenderer::createPreview() called with invalid size",
+ static_cast<XWeak*>(this),
+ 1);
+
+ // Compare with the aspect ratio of the window (which rMaximalSize
+ // assumed to be) and calculate the size of the preview so that it
+ // a) will have the aspect ratio of the page and
+ // b) will be as large as possible.
+ awt::Size aPreviewSize (calculatePreviewSize(
+ double(aPageSize.Width()) / double(aPageSize.Height()),
+ rMaximalSize));
+ if (aPreviewSize.Width <= 0 || aPreviewSize.Height <= 0)
+ return BitmapEx();
+
+ // Make sure that the super sample factor has a sane value.
+ sal_Int16 nFactor (nSuperSampleFactor);
+ if (nFactor < 1)
+ nFactor = 1;
+ else if (nFactor > 10)
+ nFactor = 10;
+
+ // Create the preview. When the super sample factor n is greater than 1
+ // then a preview is created in size (n*width, n*height) and then scaled
+ // down to (width, height). This is a poor mans antialiasing for the
+ // time being. When we have true antialiasing support this workaround
+ // can be removed.
+ const Image aPreview = maPreviewRenderer.RenderPage (
+ pPage,
+ Size(aPreviewSize.Width*nFactor, aPreviewSize.Height*nFactor),
+ true);
+ if (nFactor == 1)
+ return aPreview.GetBitmapEx();
+ else
+ {
+ BitmapEx aScaledPreview = aPreview.GetBitmapEx();
+ aScaledPreview.Scale(
+ Size(aPreviewSize.Width,aPreviewSize.Height),
+ BmpScaleFlag::BestQuality);
+ return aScaledPreview;
+ }
+}
+
+void SlideRenderer::ThrowIfDisposed()
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("SlideRenderer object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+} // end of namespace ::sd::presenter
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_SlideRenderer_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::presenter::SlideRenderer);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/SlideRenderer.hxx b/sd/source/ui/presenter/SlideRenderer.hxx
new file mode 100644
index 000000000..d39434421
--- /dev/null
+++ b/sd/source/ui/presenter/SlideRenderer.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <PreviewRenderer.hxx>
+#include <com/sun/star/drawing/XSlideRenderer.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::drawing { class XDrawPage; }
+
+namespace sd::presenter {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::XSlideRenderer,
+ css::lang::XInitialization,
+ css::lang::XServiceInfo
+> SlideRendererInterfaceBase;
+
+/** Render single slides into bitmaps.
+*/
+class SlideRenderer final
+ : public SlideRendererInterfaceBase
+{
+public:
+ SlideRenderer ();
+ virtual ~SlideRenderer() override;
+ SlideRenderer(const SlideRenderer&) = delete;
+ SlideRenderer& operator=(const SlideRenderer&) = delete;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize (const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ OUString SAL_CALL getImplementationName() override;
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XSlideRenderer
+
+ virtual css::uno::Reference<css::awt::XBitmap> SAL_CALL createPreview (
+ const css::uno::Reference<css::drawing::XDrawPage>& rxSlide,
+ const css::awt::Size& rMaximumPreviewPixelSize,
+ sal_Int16 nSuperSampleFactor) override;
+
+ virtual css::uno::Reference<css::rendering::XBitmap> SAL_CALL createPreviewForCanvas (
+ const css::uno::Reference<css::drawing::XDrawPage>& rxSlide,
+ const css::awt::Size& rMaximumPreviewPixelSize,
+ sal_Int16 nSuperSampleFactor,
+ const css::uno::Reference<css::rendering::XCanvas>& rxCanvas) override;
+
+ virtual css::awt::Size SAL_CALL calculatePreviewSize (
+ double nSlideAspectRatio,
+ const css::awt::Size& rMaximumPreviewPixelSize) override;
+
+private:
+ PreviewRenderer maPreviewRenderer;
+
+ /// @throws css::uno::RuntimeException
+ BitmapEx CreatePreview (
+ const css::uno::Reference<css::drawing::XDrawPage>& rxSlide,
+ const css::awt::Size& rMaximumPreviewPixelSize,
+ sal_Int16 nSuperSampleFactor);
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/AvahiNetworkService.cxx b/sd/source/ui/remotecontrol/AvahiNetworkService.cxx
new file mode 100644
index 000000000..7708e6eb7
--- /dev/null
+++ b/sd/source/ui/remotecontrol/AvahiNetworkService.cxx
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <config_dbus.h>
+
+#include <iostream>
+#include <limits>
+#include <new>
+#include <assert.h>
+
+#include <avahi-client/client.h>
+#include <avahi-client/publish.h>
+
+#include <avahi-common/alternative.h>
+#include <avahi-common/error.h>
+#include <avahi-common/thread-watch.h>
+#include <comphelper/random.hxx>
+
+#if ENABLE_DBUS
+#include <dbus/dbus.h>
+#endif
+
+#include <sal/log.hxx>
+
+#include "AvahiNetworkService.hxx"
+#include "ZeroconfService.hxx"
+
+using namespace sd;
+
+static AvahiClient *client = nullptr;
+static AvahiThreadedPoll *threaded_poll = nullptr;
+static AvahiEntryGroup *group = nullptr;
+static AvahiNetworkService *avahiService = nullptr;
+
+static bool create_services(AvahiClient *c);
+
+static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) {
+ assert(g == group || group == nullptr);
+ group = g;
+
+ /* Called whenever the entry group state changes */
+
+ switch (state) {
+ case AVAHI_ENTRY_GROUP_ESTABLISHED :
+ /* The entry group has been established successfully */
+ SAL_INFO( "sdremote.wifi", "Service '" << avahiService->getName() << "' successfully established." );
+ break;
+
+ case AVAHI_ENTRY_GROUP_COLLISION : {
+ char *n;
+
+ /* A service name collision with a remote service
+ * happened. Let's pick a new name */
+ n = avahi_alternative_service_name(avahiService->getName().c_str());
+ avahiService->setName(n);
+
+ SAL_INFO( "sdremote.wifi", "Service name collision, renaming service to '" << avahiService->getName() << "'");
+
+ /* And recreate the services */
+ create_services(avahi_entry_group_get_client(g));
+ break;
+ }
+
+ case AVAHI_ENTRY_GROUP_FAILURE :
+
+ SAL_WARN("sdremote.wifi", "Entry group failure: " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
+
+ /* Some kind of failure happened while we were registering our services */
+ avahi_threaded_poll_quit(threaded_poll);
+ break;
+
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
+ case AVAHI_ENTRY_GROUP_REGISTERING:
+ ;
+ }
+}
+
+static bool create_services(AvahiClient *c) {
+ assert(c);
+
+ /* If this is the first time we're called, let's create a new
+ * entry group if necessary */
+ if(!client)
+ return false;
+
+ if (!group)
+ if (!(group = avahi_entry_group_new(c, entry_group_callback, nullptr))) {
+ SAL_WARN("sdremote.wifi", "avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(c)));
+ avahiService->clear();
+ return false;
+ }
+
+ /* If the group is empty (either because it was just created, or
+ * because it was reset previously, add our entries. */
+
+ if (avahi_entry_group_is_empty(group)) {
+ SAL_INFO("sdremote.wifi", "Adding service '" << avahiService->getName() << "'");
+ char r[128];
+ int nRandom = comphelper::rng::uniform_int_distribution(0, std::numeric_limits<int>::max());
+ snprintf(r, sizeof(r), "random=%i", nRandom);
+ int ret = avahi_entry_group_add_service(
+ group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0),
+ avahiService->getName().c_str(), kREG_TYPE, nullptr, nullptr, 1599, "local", r, nullptr
+ );
+ if (ret < 0) {
+
+ if (ret == AVAHI_ERR_COLLISION){
+ /* A service name collision with a local service happened. Let's
+ * pick a new name */
+ char *n = avahi_alternative_service_name(avahiService->getName().c_str());
+ avahiService->setName(n);
+
+ SAL_WARN("sdremote.wifi", "Service name collision, renaming service to '" << avahiService->getName() << "'");
+
+ avahi_entry_group_reset(group);
+
+ return create_services(c);
+ }
+
+ SAL_WARN("sdremote.wifi", "Failed to add _impressremote._tcp service: " << avahi_strerror(ret));
+ avahiService->clear();
+ return false;
+ }
+
+ /* Tell the server to register the service */
+ if ((ret = avahi_entry_group_commit(group)) < 0) {
+ SAL_WARN("sdremote.wifi", "Failed to commit entry group: " << avahi_strerror(ret));
+ avahiService->clear();
+ return false;
+ }
+ }
+
+ return true; //Services we're already created
+}
+
+static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
+ assert(c);
+
+ /* Called whenever the client or server state changes */
+
+ switch (state) {
+ case AVAHI_CLIENT_S_RUNNING:
+ create_services(c);
+ break;
+ case AVAHI_CLIENT_FAILURE:
+ SAL_WARN("sdremote.wifi", "Client failure: " << avahi_strerror(avahi_client_errno(c)));
+ avahiService->clear();
+ break;
+ case AVAHI_CLIENT_S_COLLISION:
+ case AVAHI_CLIENT_S_REGISTERING:
+ if (group)
+ avahi_entry_group_reset(group);
+ break;
+ case AVAHI_CLIENT_CONNECTING:
+ ;
+ }
+}
+
+void AvahiNetworkService::setup() {
+#if ENABLE_DBUS
+ // Sure, without ENABLE_DBUS it probably makes no sense to try to use this Avahi stuff either,
+ // but this is just a stop-gap measure to get this to even compile for now with the probably
+ // pointless combination of configurable options --enable-avahi --enable-dbus --disable-gui.
+
+ // Avahi internally uses D-Bus, which requires the following in order to be
+ // thread-safe (and we potentially access D-Bus from different threads in
+ // different places of the code base):
+ if (!dbus_threads_init_default()) {
+ throw std::bad_alloc();
+ }
+#endif
+
+ int error = 0;
+ avahiService = this;
+ if (!(threaded_poll = avahi_threaded_poll_new())) {
+ SAL_WARN("sdremote.wifi", "avahi_threaded_poll_new '" << avahiService->getName() << "' failed");
+ return;
+ }
+
+ if (!(client = avahi_client_new(avahi_threaded_poll_get(threaded_poll), static_cast<AvahiClientFlags>(0), client_callback, nullptr, &error))) {
+ SAL_WARN("sdremote.wifi", "avahi_client_new failed");
+ return;
+ }
+
+ if(!create_services(client))
+ return;
+
+ /* Finally, start the event loop thread */
+ if (avahi_threaded_poll_start(threaded_poll) < 0) {
+ SAL_WARN("sdremote.wifi", "avahi_threaded_poll_start failed");
+ return;
+ }
+}
+
+void AvahiNetworkService::clear() {
+ /* Call this when the app shuts down */
+ if(threaded_poll)
+ avahi_threaded_poll_stop(threaded_poll);
+ if(client)
+ avahi_client_free(client);
+ if(threaded_poll)
+ avahi_threaded_poll_free(threaded_poll);
+}
diff --git a/sd/source/ui/remotecontrol/AvahiNetworkService.hxx b/sd/source/ui/remotecontrol/AvahiNetworkService.hxx
new file mode 100644
index 000000000..374a27a3a
--- /dev/null
+++ b/sd/source/ui/remotecontrol/AvahiNetworkService.hxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <string>
+#include "ZeroconfService.hxx"
+
+namespace sd {
+
+ class AvahiNetworkService : public ZeroconfService
+ {
+ public:
+ AvahiNetworkService(const std::string& aname = "", unsigned int aport = 1599)
+ : ZeroconfService(aname, aport){}
+
+ void clear() override;
+ void setup() override;
+ };
+}
diff --git a/sd/source/ui/remotecontrol/BluetoothServer.cxx b/sd/source/ui/remotecontrol/BluetoothServer.cxx
new file mode 100644
index 000000000..fc3eeff54
--- /dev/null
+++ b/sd/source/ui/remotecontrol/BluetoothServer.cxx
@@ -0,0 +1,1521 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 "BluetoothServer.hxx"
+
+#include <iostream>
+#include <memory>
+#include <new>
+#include <string_view>
+
+#include <sal/log.hxx>
+
+#ifdef LINUX_BLUETOOTH
+ #include <glib.h>
+ #include <dbus/dbus.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <sys/socket.h>
+ #include <bluetooth/bluetooth.h>
+ #include <bluetooth/rfcomm.h>
+ #include "BluetoothServiceRecord.hxx"
+ #include "BufferedStreamSocket.hxx"
+#endif
+
+#ifdef _WIN32
+ // LO vs WinAPI conflict
+ #undef WB_LEFT
+ #undef WB_RIGHT
+ #include <winsock2.h>
+ #include <ws2bth.h>
+ #include "BufferedStreamSocket.hxx"
+#endif
+
+#ifdef MACOSX
+ #include <iomanip>
+ #include <osl/conditn.hxx>
+ #include <premac.h>
+ #import <CoreFoundation/CoreFoundation.h>
+ #import <IOBluetooth/IOBluetoothUtilities.h>
+ #import <IOBluetooth/objc/IOBluetoothSDPUUID.h>
+ #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h>
+ #include <postmac.h>
+ #import "OSXBluetooth.h"
+ #include "OSXBluetoothWrapper.hxx"
+#endif
+
+#include "Communicator.hxx"
+
+using namespace sd;
+
+#ifdef LINUX_BLUETOOTH
+
+namespace {
+
+struct DBusObject {
+ OString maBusName;
+ OString maPath;
+ OString maInterface;
+
+ DBusObject() { }
+ DBusObject( const char *pBusName, const char *pPath, const char *pInterface )
+ : maBusName( pBusName ), maPath( pPath ), maInterface( pInterface ) { }
+
+ DBusMessage *getMethodCall( const char *pName )
+ {
+ return dbus_message_new_method_call( maBusName.getStr(), maPath.getStr(),
+ maInterface.getStr(), pName );
+ }
+ std::unique_ptr<DBusObject> cloneForInterface( const char *pInterface )
+ {
+ std::unique_ptr<DBusObject> pObject(new DBusObject());
+
+ pObject->maBusName = maBusName;
+ pObject->maPath = maPath;
+ pObject->maInterface = pInterface;
+
+ return pObject;
+ }
+};
+
+}
+
+static std::unique_ptr<DBusObject> getBluez5Adapter(DBusConnection *pConnection);
+
+struct sd::BluetoothServer::Impl {
+ // the glib mainloop running in the thread
+ GMainContext *mpContext;
+ DBusConnection *mpConnection;
+ std::unique_ptr<DBusObject> mpService;
+ enum class BluezVersion { BLUEZ4, BLUEZ5, UNKNOWN };
+ BluezVersion maBluezVersion;
+
+ Impl()
+ : mpContext( g_main_context_new() )
+ , mpConnection( nullptr )
+ , maBluezVersion( BluezVersion::UNKNOWN )
+ { }
+
+ std::unique_ptr<DBusObject> getAdapter()
+ {
+ if (mpService)
+ {
+ return mpService->cloneForInterface( "org.bluez.Adapter" );
+ }
+ else if (spServer->mpImpl->maBluezVersion == BluezVersion::BLUEZ5)
+ {
+ return getBluez5Adapter(mpConnection);
+ }
+ else
+ {
+ return nullptr;
+ }
+ }
+};
+
+static DBusConnection *
+dbusConnectToNameOnBus()
+{
+ DBusError aError;
+ DBusConnection *pConnection;
+
+ dbus_error_init( &aError );
+
+ pConnection = dbus_bus_get( DBUS_BUS_SYSTEM, &aError );
+ if( !pConnection || dbus_error_is_set( &aError ))
+ {
+ SAL_WARN( "sdremote.bluetooth", "failed to get dbus system bus: " << aError.message );
+ dbus_error_free( &aError );
+ return nullptr;
+ }
+
+ return pConnection;
+}
+
+static DBusMessage *
+sendUnrefAndWaitForReply( DBusConnection *pConnection, DBusMessage *pMsg )
+{
+ DBusPendingCall *pPending = nullptr;
+
+ if( !pMsg || !dbus_connection_send_with_reply( pConnection, pMsg, &pPending,
+ -1 /* default timeout */ ) )
+ {
+ SAL_WARN( "sdremote.bluetooth", "Memory allocation failed on message send" );
+ dbus_message_unref( pMsg );
+ return nullptr;
+ }
+ dbus_connection_flush( pConnection );
+ dbus_message_unref( pMsg );
+
+ dbus_pending_call_block( pPending ); // block for reply
+
+ pMsg = dbus_pending_call_steal_reply( pPending );
+ if( !pMsg )
+ SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
+
+ dbus_pending_call_unref( pPending );
+ return pMsg;
+}
+
+static bool
+isBluez5Available(DBusConnection *pConnection)
+{
+ DBusMessage *pMsg;
+
+ // Simplest ways to check whether we have Bluez 5+ is to check
+ // that we can obtain adapters using the new interfaces.
+ // The first two error checks however don't tell us anything as they should
+ // succeed as long as dbus is working correctly.
+ pMsg = DBusObject( "org.bluez", "/", "org.freedesktop.DBus.ObjectManager" ).getMethodCall( "GetManagedObjects" );
+ if (!pMsg)
+ {
+ SAL_INFO("sdremote.bluetooth", "No GetManagedObjects call created");
+ return false;
+ }
+
+ pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
+ if (!pMsg)
+ {
+ SAL_INFO("sdremote.bluetooth", "No reply received");
+ return false;
+ }
+
+ // If dbus is working correctly and we aren't on bluez 5 this is where we
+ // should actually get the error.
+ if (dbus_message_get_error_name( pMsg ))
+ {
+ SAL_INFO( "sdremote.bluetooth", "GetManagedObjects call failed with \""
+ << dbus_message_get_error_name( pMsg )
+ << "\" -- we don't seem to have Bluez 5 available");
+ return false;
+ }
+ SAL_INFO("sdremote.bluetooth", "GetManagedObjects call seems to have succeeded -- we must be on Bluez 5");
+ dbus_message_unref(pMsg);
+ return true;
+}
+
+static std::unique_ptr<DBusObject>
+getBluez5Adapter(DBusConnection *pConnection)
+{
+ DBusMessage *pMsg;
+ // This returns a list of objects where we need to find the first
+ // org.bluez.Adapter1 .
+ pMsg = DBusObject( "org.bluez", "/", "org.freedesktop.DBus.ObjectManager" ).getMethodCall( "GetManagedObjects" );
+ if (!pMsg)
+ return nullptr;
+
+ const gchar* const pInterfaceType = "org.bluez.Adapter1";
+
+ pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
+
+ DBusMessageIter aObjectIterator;
+ if (pMsg && dbus_message_iter_init(pMsg, &aObjectIterator))
+ {
+ if (DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(&aObjectIterator))
+ {
+ DBusMessageIter aObject;
+ dbus_message_iter_recurse(&aObjectIterator, &aObject);
+ do
+ {
+ if (DBUS_TYPE_DICT_ENTRY == dbus_message_iter_get_arg_type(&aObject))
+ {
+ DBusMessageIter aContainerIter;
+ dbus_message_iter_recurse(&aObject, &aContainerIter);
+ char *pPath = nullptr;
+ do
+ {
+ if (DBUS_TYPE_OBJECT_PATH == dbus_message_iter_get_arg_type(&aContainerIter))
+ {
+ dbus_message_iter_get_basic(&aContainerIter, &pPath);
+ SAL_INFO( "sdremote.bluetooth", "Something retrieved: '"
+ << pPath << "' '");
+ }
+ else if (DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(&aContainerIter))
+ {
+ DBusMessageIter aInnerIter;
+ dbus_message_iter_recurse(&aContainerIter, &aInnerIter);
+ do
+ {
+ if (DBUS_TYPE_DICT_ENTRY == dbus_message_iter_get_arg_type(&aInnerIter))
+ {
+ DBusMessageIter aInnerInnerIter;
+ dbus_message_iter_recurse(&aInnerIter, &aInnerInnerIter);
+ do
+ {
+ if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&aInnerInnerIter))
+ {
+ char* pMessage;
+
+ dbus_message_iter_get_basic(&aInnerInnerIter, &pMessage);
+ if (pMessage == std::string_view("org.bluez.Adapter1"))
+ {
+ dbus_message_unref(pMsg);
+ if (pPath)
+ {
+ return std::make_unique<DBusObject>( "org.bluez", pPath, pInterfaceType );
+ }
+ assert(false); // We should already have pPath provided for us.
+ }
+ }
+ }
+ while (dbus_message_iter_next(&aInnerInnerIter));
+ }
+ }
+ while (dbus_message_iter_next(&aInnerIter));
+ }
+ }
+ while (dbus_message_iter_next(&aContainerIter));
+ }
+ }
+ while (dbus_message_iter_next(&aObject));
+ }
+ dbus_message_unref(pMsg);
+ }
+
+ return nullptr;
+}
+
+static DBusObject *
+bluez4GetDefaultService( DBusConnection *pConnection )
+{
+ DBusMessage *pMsg;
+ DBusMessageIter it;
+ const gchar* const pInterfaceType = "org.bluez.Service";
+
+ // org.bluez.manager only exists for bluez 4.
+ // getMethodCall should return NULL if there is any issue e.g. the
+ // if org.bluez.manager doesn't exist.
+ pMsg = DBusObject( "org.bluez", "/", "org.bluez.Manager" ).getMethodCall( "DefaultAdapter" );
+
+ if (!pMsg)
+ {
+ SAL_WARN("sdremote.bluetooth", "Couldn't retrieve DBusObject for DefaultAdapter");
+ return nullptr;
+ }
+
+ SAL_INFO("sdremote.bluetooth", "successfully retrieved org.bluez.Manager.DefaultAdapter, attempting to use.");
+ pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
+
+ if(!pMsg || !dbus_message_iter_init( pMsg, &it ) )
+ {
+ return nullptr;
+ }
+
+ // This works for Bluez 4
+ if( DBUS_TYPE_OBJECT_PATH == dbus_message_iter_get_arg_type( &it ) )
+ {
+ const char *pObjectPath = nullptr;
+ dbus_message_iter_get_basic( &it, &pObjectPath );
+ SAL_INFO( "sdremote.bluetooth", "DefaultAdapter retrieved: '"
+ << pObjectPath << "' '" << pInterfaceType << "'" );
+ dbus_message_unref( pMsg );
+ return new DBusObject( "org.bluez", pObjectPath, pInterfaceType );
+ }
+ // Some form of error, e.g. if we have bluez 5 we get a message that
+ // this method doesn't exist.
+ else if ( DBUS_TYPE_STRING == dbus_message_iter_get_arg_type( &it ) )
+ {
+ const char *pMessage = nullptr;
+ dbus_message_iter_get_basic( &it, &pMessage );
+ SAL_INFO( "sdremote.bluetooth", "Error message: '"
+ << pMessage << "' '" << pInterfaceType << "'" );
+ }
+ else
+ {
+ SAL_INFO( "sdremote.bluetooth", "invalid type of reply to DefaultAdapter: '"
+ << static_cast<char>(dbus_message_iter_get_arg_type( &it )) << "'" );
+ }
+ dbus_message_unref(pMsg);
+ return nullptr;
+}
+
+static bool
+bluez4RegisterServiceRecord( DBusConnection *pConnection, DBusObject *pAdapter,
+ const char *pServiceRecord )
+{
+ DBusMessage *pMsg;
+ DBusMessageIter it;
+
+ pMsg = pAdapter->getMethodCall( "AddRecord" );
+ dbus_message_iter_init_append( pMsg, &it );
+ dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pServiceRecord );
+
+ pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
+
+ if( !pMsg || !dbus_message_iter_init( pMsg, &it ) ||
+ dbus_message_iter_get_arg_type( &it ) != DBUS_TYPE_UINT32 )
+ {
+ SAL_WARN( "sdremote.bluetooth", "SDP registration failed" );
+ return false;
+ }
+
+ // We ignore the uint de-registration handle we get back:
+ // bluez will clean us up automatically on exit
+
+ return true;
+}
+
+static void
+bluezCreateAttachListeningSocket( GMainContext *pContext, GPollFD *pSocketFD )
+{
+ int nSocket;
+
+ pSocketFD->fd = -1;
+
+ if( ( nSocket = socket( AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM ) ) < 0 )
+ {
+ SAL_WARN( "sdremote.bluetooth", "failed to open bluetooth socket with error " << nSocket );
+ return;
+ }
+
+ sockaddr_rc aAddr;
+ // Initialize whole structure. Mainly to appease valgrind, which
+ // doesn't know about the padding at the end of sockaddr_rc which
+ // it will dutifully check for definedness. But also the standard
+ // definition of BDADDR_ANY is unusable in C++ code, so just use
+ // memset to set aAddr.rc_bdaddr to 0.
+ memset( &aAddr, 0, sizeof( aAddr ) );
+ aAddr.rc_family = AF_BLUETOOTH;
+ aAddr.rc_channel = 5;
+
+ int a;
+ if ( ( a = bind( nSocket, reinterpret_cast<sockaddr*>(&aAddr), sizeof(aAddr) ) ) < 0 ) {
+ SAL_WARN( "sdremote.bluetooth", "bind failed with error" << a );
+ close( nSocket );
+ return;
+ }
+
+ if ( ( a = listen( nSocket, 1 ) ) < 0 )
+ {
+ SAL_WARN( "sdremote.bluetooth", "listen failed with error" << a );
+ close( nSocket );
+ return;
+ }
+
+ // set non-blocking behaviour ...
+ if( fcntl( nSocket, F_SETFL, O_NONBLOCK) < 0 )
+ {
+ close( nSocket );
+ return;
+ }
+
+ pSocketFD->fd = nSocket;
+ pSocketFD->events = G_IO_IN | G_IO_PRI;
+ pSocketFD->revents = 0;
+
+ g_main_context_add_poll( pContext, pSocketFD, G_PRIORITY_DEFAULT );
+}
+
+static void
+bluezDetachCloseSocket( GMainContext *pContext, GPollFD *pSocketFD )
+{
+ if( pSocketFD->fd >= 0 )
+ {
+ close( pSocketFD->fd );
+ g_main_context_remove_poll( pContext, pSocketFD );
+ pSocketFD->fd = -1;
+ }
+}
+
+#endif // LINUX_BLUETOOTH
+
+#if defined(MACOSX)
+
+OSXBluetoothWrapper::OSXBluetoothWrapper( IOBluetoothRFCOMMChannel* channel ) :
+ mpChannel(channel),
+ mnMTU(0),
+ mHaveBytes(),
+ mMutex(),
+ mBuffer()
+{
+ // silly enough, can't write more than mnMTU bytes at once
+ mnMTU = [channel getMTU];
+
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::OSXBluetoothWrapper(): mnMTU=" << mnMTU );
+}
+
+sal_Int32 OSXBluetoothWrapper::readLine( OString& aLine )
+{
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine()" );
+
+ while( true )
+ {
+ {
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: entering mutex" );
+ ::osl::MutexGuard aQueueGuard( mMutex );
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: entered mutex" );
+
+#ifdef SAL_LOG_INFO
+ // We should have in the sal logging some standard way to
+ // output char buffers with non-printables escaped.
+ std::ostringstream s;
+ if (mBuffer.size() > 0)
+ {
+ for (unsigned char *p = reinterpret_cast<unsigned char *>(mBuffer.data()); p != reinterpret_cast<unsigned char *>(mBuffer.data()) + mBuffer.size(); p++)
+ {
+ if (*p == '\n')
+ s << "\\n";
+ else if (*p < ' ' || *p >= 0x7F)
+ s << "\\0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(*p) << std::setfill(' ') << std::setw(1) << std::dec;
+ else
+ s << *p;
+ }
+ }
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine mBuffer: \"" << s.str() << "\"" );
+#endif
+
+ // got enough bytes to return a line?
+ std::vector<char>::iterator aIt;
+ if ( (aIt = find( mBuffer.begin(), mBuffer.end(), '\n' ))
+ != mBuffer.end() )
+ {
+ sal_uInt64 aLocation = aIt - mBuffer.begin();
+
+ aLine = OString( &(*mBuffer.begin()), aLocation );
+
+ mBuffer.erase( mBuffer.begin(), aIt + 1 ); // Also delete the empty line
+
+ // yeps
+ SAL_INFO( "sdremote.bluetooth", " returning, got \"" << OStringToOUString( aLine, RTL_TEXTENCODING_UTF8 ) << "\"" );
+ return aLine.getLength() + 1;
+ }
+
+ // nope - wait some more (after releasing the mutex)
+ SAL_INFO( "sdremote.bluetooth", " resetting mHaveBytes" );
+ mHaveBytes.reset();
+ SAL_INFO( "sdremote.bluetooth", " leaving mutex" );
+ }
+
+ SAL_INFO( "sdremote.bluetooth", " waiting for mHaveBytes" );
+ mHaveBytes.wait();
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: got mHaveBytes" );
+ }
+}
+
+sal_Int32 OSXBluetoothWrapper::write( const void* pBuffer, sal_uInt32 n )
+{
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::write(" << pBuffer << ", " << n << ") mpChannel=" << mpChannel );
+
+ char const * ptr = static_cast<char const *>(pBuffer);
+ sal_uInt32 nBytesWritten = 0;
+
+ if (mpChannel == nil)
+ return 0;
+
+ while( nBytesWritten < n )
+ {
+ int toWrite = n - nBytesWritten;
+ toWrite = toWrite <= mnMTU ? toWrite : mnMTU;
+ if ( [mpChannel writeSync:const_cast<char *>(ptr) length:toWrite] != kIOReturnSuccess )
+ {
+ SAL_INFO( "sdremote.bluetooth", " [mpChannel writeSync:" << static_cast<void const *>(ptr) << " length:" << toWrite << "] returned error, total written " << nBytesWritten );
+ return nBytesWritten;
+ }
+ ptr += toWrite;
+ nBytesWritten += toWrite;
+ }
+ SAL_INFO( "sdremote.bluetooth", " total written " << nBytesWritten );
+ return nBytesWritten;
+}
+
+void OSXBluetoothWrapper::appendData(void* pBuffer, size_t len)
+{
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData(" << pBuffer << ", " << len << ")" );
+
+ if( len )
+ {
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData: entering mutex" );
+ ::osl::MutexGuard aQueueGuard( mMutex );
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData: entered mutex" );
+ mBuffer.insert(mBuffer.begin()+mBuffer.size(),
+ static_cast<char*>(pBuffer), static_cast<char *>(pBuffer)+len);
+ SAL_INFO( "sdremote.bluetooth", " setting mHaveBytes" );
+ mHaveBytes.set();
+ SAL_INFO( "sdremote.bluetooth", " leaving mutex" );
+ }
+}
+
+void OSXBluetoothWrapper::channelClosed()
+{
+ SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::channelClosed()" );
+
+ mpChannel = nil;
+}
+
+void incomingCallback( void *userRefCon,
+ IOBluetoothUserNotificationRef,
+ IOBluetoothObjectRef objectRef )
+{
+ SAL_INFO( "sdremote.bluetooth", "incomingCallback()" );
+
+ BluetoothServer* pServer = static_cast<BluetoothServer*>(userRefCon);
+
+ IOBluetoothRFCOMMChannel* channel = [IOBluetoothRFCOMMChannel withRFCOMMChannelRef:reinterpret_cast<IOBluetoothRFCOMMChannelRef>(objectRef)];
+
+ OSXBluetoothWrapper* socket = new OSXBluetoothWrapper( channel);
+ Communicator* pCommunicator = new Communicator( std::unique_ptr<IBluetoothSocket>(socket) );
+ pServer->addCommunicator( pCommunicator );
+
+ ChannelDelegate* delegate = [[ChannelDelegate alloc] initWithCommunicatorAndSocket: pCommunicator socket: socket];
+ [channel setDelegate: delegate];
+ [delegate retain];
+
+ pCommunicator->launch();
+}
+
+void BluetoothServer::addCommunicator( Communicator* pCommunicator )
+{
+ mpCommunicators->push_back( pCommunicator );
+}
+
+#endif // MACOSX
+
+#ifdef LINUX_BLUETOOTH
+
+extern "C" {
+ static gboolean ensureDiscoverable_cb(gpointer)
+ {
+ BluetoothServer::doEnsureDiscoverable();
+ return FALSE; // remove source
+ }
+ static gboolean restoreDiscoverable_cb(gpointer)
+ {
+ BluetoothServer::doRestoreDiscoverable();
+ return FALSE; // remove source
+ }
+}
+
+/*
+ * Bluez 4 uses custom methods for setting properties, whereas Bluez 5+
+ * implements properties using the generic "org.freedesktop.DBus.Properties"
+ * interface -- hence we have a specific Bluez 4 function to deal with the
+ * old style of reading properties.
+ */
+static bool
+getBluez4BooleanProperty( DBusConnection *pConnection, DBusObject *pAdapter,
+ const char *pPropertyName, bool *pBoolean )
+{
+ *pBoolean = false;
+
+ if( !pAdapter )
+ return false;
+
+ DBusMessage *pMsg;
+ pMsg = sendUnrefAndWaitForReply( pConnection,
+ pAdapter->getMethodCall( "GetProperties" ) );
+
+ DBusMessageIter it;
+ if( !pMsg || !dbus_message_iter_init( pMsg, &it ) )
+ {
+ SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
+ return false;
+ }
+
+ if( DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type( &it ) )
+ {
+ SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
+ return false;
+ }
+
+ DBusMessageIter arrayIt;
+ dbus_message_iter_recurse( &it, &arrayIt );
+
+ while( dbus_message_iter_get_arg_type( &arrayIt ) == DBUS_TYPE_DICT_ENTRY )
+ {
+ DBusMessageIter dictIt;
+ dbus_message_iter_recurse( &arrayIt, &dictIt );
+
+ const char *pName = nullptr;
+ if( dbus_message_iter_get_arg_type( &dictIt ) == DBUS_TYPE_STRING )
+ {
+ dbus_message_iter_get_basic( &dictIt, &pName );
+ if( pName != nullptr && !strcmp( pName, pPropertyName ) )
+ {
+ SAL_INFO( "sdremote.bluetooth", "hit " << pPropertyName << " property" );
+ dbus_message_iter_next( &dictIt );
+ dbus_bool_t bBool = false;
+
+ if( dbus_message_iter_get_arg_type( &dictIt ) == DBUS_TYPE_VARIANT )
+ {
+ DBusMessageIter variantIt;
+ dbus_message_iter_recurse( &dictIt, &variantIt );
+
+ if( dbus_message_iter_get_arg_type( &variantIt ) == DBUS_TYPE_BOOLEAN )
+ {
+ dbus_message_iter_get_basic( &variantIt, &bBool );
+ SAL_INFO( "sdremote.bluetooth", "" << pPropertyName << " is " << bBool );
+ *pBoolean = bBool;
+ return true;
+ }
+ else
+ SAL_WARN( "sdremote.bluetooth", "" << pPropertyName << " type " <<
+ dbus_message_iter_get_arg_type( &variantIt ) );
+ }
+ else
+ SAL_WARN( "sdremote.bluetooth", "variant type ? " <<
+ dbus_message_iter_get_arg_type( &dictIt ) );
+ }
+ else
+ {
+ const char *pStr = pName ? pName : "<null>";
+ SAL_INFO( "sdremote.bluetooth", "property '" << pStr << "'" );
+ }
+ }
+ else
+ SAL_WARN( "sdremote.bluetooth", "unexpected property key type "
+ << dbus_message_iter_get_arg_type( &dictIt ) );
+ dbus_message_iter_next( &arrayIt );
+ }
+ dbus_message_unref( pMsg );
+
+ return false;
+}
+
+/*
+ * This gets an org.freedesktop.DBus.Properties boolean
+ * (as opposed to the old Bluez 4 custom properties methods as visible above).
+ */
+static bool
+getDBusBooleanProperty( DBusConnection *pConnection, DBusObject *pAdapter,
+ const char *pPropertyName, bool *pBoolean )
+{
+ assert( pAdapter );
+
+ *pBoolean = false;
+ bool bRet = false;
+
+ std::unique_ptr< DBusObject > pProperties (
+ pAdapter->cloneForInterface( "org.freedesktop.DBus.Properties" ) );
+
+ DBusMessage *pMsg = pProperties->getMethodCall( "Get" );
+
+ DBusMessageIter itIn;
+ dbus_message_iter_init_append( pMsg, &itIn );
+ const char* pInterface = "org.bluez.Adapter1";
+ dbus_message_iter_append_basic( &itIn, DBUS_TYPE_STRING, &pInterface );
+ dbus_message_iter_append_basic( &itIn, DBUS_TYPE_STRING, &pPropertyName );
+ pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
+
+ DBusMessageIter it;
+ if( !pMsg || !dbus_message_iter_init( pMsg, &it ) )
+ {
+ SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
+ return false;
+ }
+
+ if( DBUS_TYPE_VARIANT != dbus_message_iter_get_arg_type( &it ) )
+ {
+ SAL_WARN( "sdremote.bluetooth", "invalid return type" );
+ }
+ else
+ {
+ DBusMessageIter variantIt;
+ dbus_message_iter_recurse( &it, &variantIt );
+
+ if( dbus_message_iter_get_arg_type( &variantIt ) == DBUS_TYPE_BOOLEAN )
+ {
+ dbus_bool_t bBool = false;
+ dbus_message_iter_get_basic( &variantIt, &bBool );
+ SAL_INFO( "sdremote.bluetooth", "" << pPropertyName << " is " << bBool );
+ *pBoolean = bBool;
+ bRet = true;
+ }
+ else
+ {
+ SAL_WARN( "sdremote.bluetooth", "" << pPropertyName << " type " <<
+ dbus_message_iter_get_arg_type( &variantIt ) );
+ }
+
+ const char* pError = dbus_message_get_error_name( pMsg );
+ if ( pError )
+ {
+ SAL_WARN( "sdremote.bluetooth",
+ "Get failed for " << pPropertyName << " on " <<
+ pAdapter->maPath << " with error: " << pError );
+ }
+ }
+ dbus_message_unref( pMsg );
+
+ return bRet;
+}
+
+static void
+setDBusBooleanProperty( DBusConnection *pConnection, DBusObject *pAdapter,
+ const char *pPropertyName, bool bBoolean )
+{
+ assert( pAdapter );
+
+ std::unique_ptr< DBusObject > pProperties(
+ pAdapter->cloneForInterface( "org.freedesktop.DBus.Properties" ) );
+
+ DBusMessage *pMsg = pProperties->getMethodCall( "Set" );
+
+ DBusMessageIter itIn;
+ dbus_message_iter_init_append( pMsg, &itIn );
+ const char* pInterface = "org.bluez.Adapter1";
+ dbus_message_iter_append_basic( &itIn, DBUS_TYPE_STRING, &pInterface );
+ dbus_message_iter_append_basic( &itIn, DBUS_TYPE_STRING, &pPropertyName );
+
+ {
+ DBusMessageIter varIt;
+ dbus_message_iter_open_container( &itIn, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_BOOLEAN_AS_STRING, &varIt );
+ dbus_bool_t bDBusBoolean = bBoolean;
+ dbus_message_iter_append_basic( &varIt, DBUS_TYPE_BOOLEAN, &bDBusBoolean );
+ dbus_message_iter_close_container( &itIn, &varIt );
+ }
+
+ pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
+
+ if( !pMsg )
+ {
+ SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
+ }
+ else
+ {
+ const char* pError = dbus_message_get_error_name( pMsg );
+ if ( pError )
+ {
+ SAL_WARN( "sdremote.bluetooth",
+ "Set failed for " << pPropertyName << " on " <<
+ pAdapter->maPath << " with error: " << pError );
+ }
+ dbus_message_unref( pMsg );
+ }
+}
+
+static bool
+getDiscoverable( DBusConnection *pConnection, DBusObject *pAdapter )
+{
+ if (pAdapter->maInterface == "org.bluez.Adapter") // Bluez 4
+ {
+ bool bDiscoverable;
+ if( getBluez4BooleanProperty(pConnection, pAdapter, "Discoverable", &bDiscoverable ) )
+ return bDiscoverable;
+ }
+ else if (pAdapter->maInterface == "org.bluez.Adapter1") // Bluez 5
+ {
+ bool bDiscoverable;
+ if ( getDBusBooleanProperty(pConnection, pAdapter, "Discoverable", &bDiscoverable ) )
+ return bDiscoverable;
+ }
+ return false;
+}
+
+static void
+setDiscoverable( DBusConnection *pConnection, DBusObject *pAdapter, bool bDiscoverable )
+{
+ SAL_INFO( "sdremote.bluetooth", "setDiscoverable to " << bDiscoverable );
+
+ if (pAdapter->maInterface == "org.bluez.Adapter") // Bluez 4
+ {
+ bool bPowered = false;
+ if( !getBluez4BooleanProperty( pConnection, pAdapter, "Powered", &bPowered ) || !bPowered )
+ return; // nothing to do
+
+ DBusMessage *pMsg;
+ DBusMessageIter it, varIt;
+
+ // set timeout to zero
+ pMsg = pAdapter->getMethodCall( "SetProperty" );
+ dbus_message_iter_init_append( pMsg, &it );
+ const char *pTimeoutStr = "DiscoverableTimeout";
+ dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pTimeoutStr );
+ dbus_message_iter_open_container( &it, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_UINT32_AS_STRING, &varIt );
+ dbus_uint32_t nTimeout = 0;
+ dbus_message_iter_append_basic( &varIt, DBUS_TYPE_UINT32, &nTimeout );
+ dbus_message_iter_close_container( &it, &varIt );
+ dbus_connection_send( pConnection, pMsg, nullptr ); // async send - why not ?
+ dbus_message_unref( pMsg );
+
+ // set discoverable value
+ pMsg = pAdapter->getMethodCall( "SetProperty" );
+ dbus_message_iter_init_append( pMsg, &it );
+ const char *pDiscoverableStr = "Discoverable";
+ dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pDiscoverableStr );
+ dbus_message_iter_open_container( &it, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_BOOLEAN_AS_STRING, &varIt );
+ dbus_bool_t bValue = bDiscoverable;
+ dbus_message_iter_append_basic( &varIt, DBUS_TYPE_BOOLEAN, &bValue );
+ dbus_message_iter_close_container( &it, &varIt ); // async send - why not ?
+ dbus_connection_send( pConnection, pMsg, nullptr );
+ dbus_message_unref( pMsg );
+ }
+ else if (pAdapter->maInterface == "org.bluez.Adapter1") // Bluez 5
+ {
+ setDBusBooleanProperty(pConnection, pAdapter, "Discoverable", bDiscoverable );
+ }
+}
+
+static std::unique_ptr<DBusObject>
+registerWithDefaultAdapter( DBusConnection *pConnection )
+{
+ std::unique_ptr<DBusObject> pService(bluez4GetDefaultService( pConnection ));
+ if( pService )
+ {
+ if( !bluez4RegisterServiceRecord( pConnection, pService.get(),
+ bluetooth_service_record ) )
+ {
+ return nullptr;
+ }
+ }
+
+ return pService;
+}
+
+static void ProfileUnregisterFunction
+(DBusConnection *, void *)
+{
+ // We specifically don't need to do anything here.
+}
+
+static DBusHandlerResult ProfileMessageFunction
+(DBusConnection *pConnection, DBusMessage *pMessage, void *user_data)
+{
+ SAL_INFO("sdremote.bluetooth", "ProfileMessageFunction||" << dbus_message_get_interface(pMessage) << "||" << dbus_message_get_member(pMessage));
+
+ if (dbus_message_get_interface(pMessage) == std::string_view("org.bluez.Profile1"))
+ {
+ if (dbus_message_get_member(pMessage) == std::string_view("Release"))
+ {
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else if (dbus_message_get_member(pMessage) == std::string_view("NewConnection"))
+ {
+ if (!dbus_message_has_signature(pMessage, "oha{sv}"))
+ {
+ SAL_WARN("sdremote.bluetooth", "wrong signature for NewConnection");
+ }
+
+ DBusMessageIter it;
+ if (!dbus_message_iter_init(pMessage, &it))
+ SAL_WARN( "sdremote.bluetooth", "error init dbus" );
+ else
+ {
+ char* pPath;
+ dbus_message_iter_get_basic(&it, &pPath);
+ SAL_INFO("sdremote.bluetooth", "Adapter path:" << pPath);
+
+ if (!dbus_message_iter_next(&it))
+ SAL_WARN("sdremote.bluetooth", "not enough parameters passed");
+
+ // DBUS_TYPE_UNIX_FD == 'h' -- doesn't exist in older versions
+ // of dbus (< 1.3?) hence defined manually for now
+ if ('h' == dbus_message_iter_get_arg_type(&it))
+ {
+
+ int nDescriptor;
+ dbus_message_iter_get_basic(&it, &nDescriptor);
+ std::vector<Communicator*>* pCommunicators = static_cast<std::vector<Communicator*>*>(user_data);
+
+ // Bluez gives us non-blocking sockets, but our code relies
+ // on blocking behaviour.
+ (void)fcntl(nDescriptor, F_SETFL, fcntl(nDescriptor, F_GETFL) & ~O_NONBLOCK);
+
+ SAL_INFO( "sdremote.bluetooth", "connection accepted " << nDescriptor);
+ Communicator* pCommunicator = new Communicator( std::make_unique<BufferedStreamSocket>( nDescriptor ) );
+ pCommunicators->push_back( pCommunicator );
+ pCommunicator->launch();
+ }
+
+ // For some reason an (empty?) reply is expected.
+ DBusMessage* pRet = dbus_message_new_method_return(pMessage);
+ dbus_connection_send(pConnection, pRet, nullptr);
+ dbus_message_unref(pRet);
+
+ // We could read the remote profile version and features here
+ // (i.e. they are provided as part of the DBusMessage),
+ // however for us they are irrelevant (as our protocol handles
+ // equivalent functionality independently of whether we're on
+ // bluetooth or normal network connection).
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ }
+ else if (dbus_message_get_member(pMessage) == std::string_view("RequestDisconnection"))
+ {
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ }
+ SAL_WARN("sdremote.bluetooth", "Couldn't handle message correctly.");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+}
+
+static void
+setupBluez5Profile1(DBusConnection* pConnection, std::vector<Communicator*>* pCommunicators)
+{
+ bool bErr;
+
+ SAL_INFO("sdremote.bluetooth", "Attempting to register our org.bluez.Profile1");
+ static DBusObjectPathVTable aVTable;
+ aVTable.unregister_function = ProfileUnregisterFunction;
+ aVTable.message_function = ProfileMessageFunction;
+
+ // dbus_connection_try_register_object_path could be used but only exists for
+ // dbus >= 1.2 -- we really shouldn't be trying this twice in any case.
+ // (dbus_connection_try_register_object_path also returns an error with more
+ // information which could be useful for debugging purposes.)
+ bErr = !dbus_connection_register_object_path(pConnection, "/org/libreoffice/bluez/profile1", &aVTable, pCommunicators);
+
+ if (bErr)
+ {
+ SAL_WARN("sdremote.bluetooth", "Failed to register Bluez 5 Profile1 callback, bluetooth won't work.");
+ }
+
+ dbus_connection_flush( pConnection );
+}
+
+static void
+unregisterBluez5Profile(DBusConnection* pConnection)
+{
+ DBusMessage* pMsg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ "org.bluez.ProfileManager1", "UnregisterProfile");
+ DBusMessageIter it;
+ dbus_message_iter_init_append(pMsg, &it);
+
+ const char *pPath = "/org/libreoffice/bluez/profile1";
+ dbus_message_iter_append_basic(&it, DBUS_TYPE_OBJECT_PATH, &pPath);
+
+ pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
+
+ if (pMsg)
+ dbus_message_unref(pMsg);
+
+ dbus_connection_unregister_object_path( pConnection, "/org/libreoffice/bluez/profile1");
+
+ dbus_connection_flush(pConnection);
+}
+
+static bool
+registerBluez5Profile(DBusConnection* pConnection, std::vector<Communicator*>* pCommunicators)
+{
+ setupBluez5Profile1(pConnection, pCommunicators);
+
+ DBusMessage *pMsg;
+ DBusMessageIter it;
+
+ pMsg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ "org.bluez.ProfileManager1", "RegisterProfile");
+ dbus_message_iter_init_append(pMsg, &it);
+
+ const char *pPath = "/org/libreoffice/bluez/profile1";
+ dbus_message_iter_append_basic(&it, DBUS_TYPE_OBJECT_PATH, &pPath);
+ const char *pUUID = "spp"; // Bluez translates this to 0x1101 for spp
+ dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &pUUID);
+
+ DBusMessageIter aOptionsIter;
+ dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "{sv}", &aOptionsIter);
+
+ DBusMessageIter aEntry;
+
+ {
+ dbus_message_iter_open_container(&aOptionsIter, DBUS_TYPE_DICT_ENTRY, nullptr, &aEntry);
+
+ const char *pString = "Name";
+ dbus_message_iter_append_basic(&aEntry, DBUS_TYPE_STRING, &pString);
+
+ const char *pValue = "LibreOffice Impress Remote";
+ DBusMessageIter aValue;
+ dbus_message_iter_open_container(&aEntry, DBUS_TYPE_VARIANT, "s", &aValue);
+ dbus_message_iter_append_basic(&aValue, DBUS_TYPE_STRING, &pValue);
+ dbus_message_iter_close_container(&aEntry, &aValue);
+ dbus_message_iter_close_container(&aOptionsIter, &aEntry);
+ }
+
+ dbus_message_iter_close_container(&it, &aOptionsIter);
+
+ // Other properties that we could set (but don't, since they appear
+ // to be useless for us):
+ // "Service": "0x1101" (not needed, but we used to have it in the manually defined profile).
+ // "Role": setting this to "server" breaks things, although we think we're a server?
+ // "Channel": seems to be dealt with automatically (but we used to use 5 in the manual profile).
+
+ bool bSuccess = true;
+
+ pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
+
+ DBusError aError;
+ dbus_error_init(&aError);
+ if (pMsg && dbus_set_error_from_message( &aError, pMsg ))
+ {
+ bSuccess = false;
+ SAL_WARN("sdremote.bluetooth",
+ "Failed to register our Profile1 with bluez ProfileManager "
+ << (aError.message ? aError.message : "<null>"));
+ }
+
+ dbus_error_free(&aError);
+ if (pMsg)
+ dbus_message_unref(pMsg);
+
+ dbus_connection_flush(pConnection);
+
+ return bSuccess;
+}
+
+#endif // LINUX_BLUETOOTH
+
+BluetoothServer::BluetoothServer( std::vector<Communicator*>* pCommunicators )
+ : meWasDiscoverable( UNKNOWN ),
+ mpCommunicators( pCommunicators )
+{
+#ifdef LINUX_BLUETOOTH
+ // D-Bus requires the following in order to be thread-safe (and we
+ // potentially access D-Bus from different threads in different places of
+ // the code base):
+ if (!dbus_threads_init_default()) {
+ throw std::bad_alloc();
+ }
+
+ mpImpl.reset(new BluetoothServer::Impl());
+#endif
+}
+
+BluetoothServer::~BluetoothServer()
+{
+}
+
+void BluetoothServer::ensureDiscoverable()
+{
+#ifdef LINUX_BLUETOOTH
+ // Push it all across into our mainloop
+ if( !spServer )
+ return;
+ GSource *pIdle = g_idle_source_new();
+ g_source_set_callback( pIdle, ensureDiscoverable_cb, nullptr, nullptr );
+ g_source_set_priority( pIdle, G_PRIORITY_DEFAULT );
+ g_source_attach( pIdle, spServer->mpImpl->mpContext );
+ g_source_unref( pIdle );
+#endif
+}
+
+void BluetoothServer::restoreDiscoverable()
+{
+#ifdef LINUX_BLUETOOTH
+ // Push it all across into our mainloop
+ if( !spServer )
+ return;
+ GSource *pIdle = g_idle_source_new();
+ g_source_set_callback( pIdle, restoreDiscoverable_cb, nullptr, nullptr );
+ g_source_set_priority( pIdle, G_PRIORITY_DEFAULT_IDLE );
+ g_source_attach( pIdle, spServer->mpImpl->mpContext );
+ g_source_unref( pIdle );
+#endif
+}
+
+void BluetoothServer::doEnsureDiscoverable()
+{
+#ifdef LINUX_BLUETOOTH
+ if (!spServer->mpImpl->mpConnection ||
+ spServer->meWasDiscoverable != UNKNOWN )
+ return;
+
+ // Find out if we are discoverable already ...
+ std::unique_ptr<DBusObject> pAdapter = spServer->mpImpl->getAdapter();
+ if( !pAdapter )
+ return;
+
+ bool bDiscoverable = getDiscoverable(spServer->mpImpl->mpConnection, pAdapter.get() );
+
+ spServer->meWasDiscoverable = bDiscoverable ? DISCOVERABLE : NOT_DISCOVERABLE;
+ if( !bDiscoverable )
+ setDiscoverable( spServer->mpImpl->mpConnection, pAdapter.get(), true );
+#endif
+}
+
+void BluetoothServer::doRestoreDiscoverable()
+{
+ if( spServer->meWasDiscoverable == NOT_DISCOVERABLE )
+ {
+#ifdef LINUX_BLUETOOTH
+ std::unique_ptr<DBusObject> pAdapter = spServer->mpImpl->getAdapter();
+ if( !pAdapter )
+ return;
+ setDiscoverable( spServer->mpImpl->mpConnection, pAdapter.get(), false );
+#endif
+ }
+ spServer->meWasDiscoverable = UNKNOWN;
+}
+
+// We have to have all our clients shut otherwise we can't
+// re-bind to the same port number it appears.
+void BluetoothServer::cleanupCommunicators()
+{
+ for (auto& rpCommunicator : *mpCommunicators)
+ rpCommunicator->forceClose();
+ // the hope is that all the threads then terminate cleanly and
+ // clean themselves up.
+}
+
+void SAL_CALL BluetoothServer::run()
+{
+ SAL_INFO( "sdremote.bluetooth", "BluetoothServer::run called" );
+ osl::Thread::setName("BluetoothServer");
+#ifdef LINUX_BLUETOOTH
+ DBusConnection *pConnection = dbusConnectToNameOnBus();
+ if( !pConnection )
+ return;
+
+ // For either implementation we need to poll the dbus fd
+ int fd = -1;
+ GPollFD aDBusFD;
+ if( dbus_connection_get_unix_fd( pConnection, &fd ) && fd >= 0 )
+ {
+ aDBusFD.fd = fd;
+ aDBusFD.events = G_IO_IN | G_IO_PRI;
+ g_main_context_add_poll( mpImpl->mpContext, &aDBusFD, G_PRIORITY_DEFAULT );
+ }
+ else
+ SAL_WARN( "sdremote.bluetooth", "failed to poll for incoming dbus signals" );
+
+ if (isBluez5Available(pConnection))
+ {
+ SAL_INFO("sdremote.bluetooth", "Using Bluez 5");
+ registerBluez5Profile(pConnection, mpCommunicators);
+ mpImpl->mpConnection = pConnection;
+ mpImpl->maBluezVersion = Impl::BluezVersion::BLUEZ5;
+
+ // We don't need to listen to adapter changes anymore -- profile
+ // registration is done globally for the entirety of bluez, so we only
+ // need adapters when setting discoverability, which can be done
+ // dynamically without the need to listen for changes.
+
+ // TODO: exit on SD deinit
+ // Probably best to do that in SdModule::~SdModule?
+ while (true)
+ {
+ aDBusFD.revents = 0;
+ g_main_context_iteration( mpImpl->mpContext, true );
+ if( aDBusFD.revents )
+ {
+ dbus_connection_read_write( pConnection, 0 );
+ while (DBUS_DISPATCH_DATA_REMAINS == dbus_connection_get_dispatch_status( pConnection ))
+ dbus_connection_dispatch( pConnection );
+ }
+ if ((false)) break;
+ // silence Clang -Wunreachable-code after loop (TODO: proper
+ // fix?)
+ }
+ unregisterBluez5Profile( pConnection );
+ g_main_context_unref( mpImpl->mpContext );
+ mpImpl->mpConnection = nullptr;
+ mpImpl->mpContext = nullptr;
+ return;
+ }
+
+ // Otherwise we could be on Bluez 4 and continue as usual.
+ mpImpl->maBluezVersion = Impl::BluezVersion::BLUEZ4;
+
+ // Try to setup the default adapter, otherwise wait for add/remove signal
+ mpImpl->mpService = registerWithDefaultAdapter( pConnection );
+ // listen for connection state and power changes - we need to close
+ // and re-create our socket code on suspend / resume, enable/disable
+ DBusError aError;
+ dbus_error_init( &aError );
+ dbus_bus_add_match( pConnection, "type='signal',interface='org.bluez.Manager'", &aError );
+ dbus_connection_flush( pConnection );
+
+ // Try to setup the default adapter, otherwise wait for add/remove signal
+ mpImpl->mpService = registerWithDefaultAdapter( pConnection );
+
+ // poll on our bluetooth socket - if we can.
+ GPollFD aSocketFD;
+ if( mpImpl->mpService )
+ bluezCreateAttachListeningSocket( mpImpl->mpContext, &aSocketFD );
+
+ mpImpl->mpConnection = pConnection;
+
+ while( true )
+ {
+ aDBusFD.revents = 0;
+ aSocketFD.revents = 0;
+ g_main_context_iteration( mpImpl->mpContext, true );
+
+ SAL_INFO( "sdremote.bluetooth", "main-loop spin "
+ << aDBusFD.revents << " " << aSocketFD.revents );
+ if( aDBusFD.revents )
+ {
+ dbus_connection_read_write( pConnection, 0 );
+ DBusMessage *pMsg = dbus_connection_pop_message( pConnection );
+ if( pMsg )
+ {
+ if( dbus_message_is_signal( pMsg, "org.bluez.Manager", "AdapterRemoved" ) )
+ {
+ SAL_WARN( "sdremote.bluetooth", "lost adapter - cleaning up sockets" );
+ bluezDetachCloseSocket( mpImpl->mpContext, &aSocketFD );
+ cleanupCommunicators();
+ }
+ else if( dbus_message_is_signal( pMsg, "org.bluez.Manager", "AdapterAdded" ) ||
+ dbus_message_is_signal( pMsg, "org.bluez.Manager", "DefaultAdapterChanged" ) )
+ {
+ SAL_WARN( "sdremote.bluetooth", "gained adapter - re-generating sockets" );
+ bluezDetachCloseSocket( mpImpl->mpContext, &aSocketFD );
+ cleanupCommunicators();
+ mpImpl->mpService = registerWithDefaultAdapter( pConnection );
+ if( mpImpl->mpService )
+ bluezCreateAttachListeningSocket( mpImpl->mpContext, &aSocketFD );
+ }
+ else
+ SAL_INFO( "sdremote.bluetooth", "unknown incoming dbus message, "
+ " type: " << dbus_message_get_type( pMsg )
+ << " path: '" << dbus_message_get_path( pMsg )
+ << "' interface: '" << dbus_message_get_interface( pMsg )
+ << "' member: '" << dbus_message_get_member( pMsg ) );
+ }
+ dbus_message_unref( pMsg );
+ }
+
+ if( aSocketFD.revents )
+ {
+ sockaddr_rc aRemoteAddr;
+ socklen_t aRemoteAddrLen = sizeof(aRemoteAddr);
+
+ SAL_INFO( "sdremote.bluetooth", "performing accept" );
+ int nClient = accept( aSocketFD.fd, reinterpret_cast<sockaddr*>(&aRemoteAddr), &aRemoteAddrLen);
+ if ( nClient < 0 && errno != EAGAIN )
+ {
+ SAL_WARN( "sdremote.bluetooth", "accept failed with errno " << errno );
+ } else {
+ SAL_INFO( "sdremote.bluetooth", "connection accepted " << nClient );
+ Communicator* pCommunicator = new Communicator( std::make_unique<BufferedStreamSocket>( nClient ) );
+ mpCommunicators->push_back( pCommunicator );
+ pCommunicator->launch();
+ }
+ }
+ if ((false)) break;
+ // silence Clang -Wunreachable-code after loop (TODO: proper fix?)
+ }
+
+ unregisterBluez5Profile( pConnection );
+ g_main_context_unref( mpImpl->mpContext );
+ mpImpl->mpConnection = nullptr;
+ mpImpl->mpContext = nullptr;
+
+#elif defined(_WIN32)
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ if ( WSAStartup(wVersionRequested, &wsaData) )
+ {
+ return; // winsock dll couldn't be loaded
+ }
+
+ int aSocket = socket( AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM );
+ if ( !aSocket )
+ {
+ WSACleanup();
+ return;
+ }
+ SOCKADDR_BTH aAddr;
+ aAddr.addressFamily = AF_BTH;
+ aAddr.btAddr = 0;
+ aAddr.serviceClassId = GUID_NULL;
+ aAddr.port = BT_PORT_ANY; // Select any free socket.
+ if ( bind( aSocket, reinterpret_cast<SOCKADDR*>(&aAddr), sizeof(aAddr) ) == SOCKET_ERROR )
+ {
+ closesocket( aSocket );
+ WSACleanup();
+ return;
+ }
+
+ SOCKADDR_BTH aName;
+ int aNameSize = sizeof(aName);
+ getsockname( aSocket, reinterpret_cast<SOCKADDR*>(&aName), &aNameSize ); // Retrieve the local address and port
+
+ CSADDR_INFO aAddrInfo = {};
+ aAddrInfo.LocalAddr.lpSockaddr = reinterpret_cast<SOCKADDR*>(&aName);
+ aAddrInfo.LocalAddr.iSockaddrLength = sizeof( SOCKADDR_BTH );
+ aAddrInfo.iSocketType = SOCK_STREAM;
+ aAddrInfo.iProtocol = BTHPROTO_RFCOMM;
+
+ // To be used for setting a custom UUID once available.
+// GUID uuid;
+// uuid.Data1 = 0x00001101;
+// memset( &uuid, 0x1000 + UUID*2^96, sizeof( GUID ) );
+// uuid.Data2 = 0;
+// uuid.Data3 = 0x1000;
+// ULONGLONG aData4 = 0x800000805F9B34FB;
+// memcpy( uuid.Data4, &aData4, sizeof(uuid.Data4) );
+
+ WSAQUERYSETW aRecord = {};
+ aRecord.dwSize = sizeof(aRecord);
+ aRecord.lpszServiceInstanceName = const_cast<wchar_t *>(
+ L"LibreOffice Impress Remote Control");
+ aRecord.lpszComment = const_cast<wchar_t *>(
+ L"Remote control of presentations over bluetooth.");
+ aRecord.lpServiceClassId = const_cast<LPGUID>(&SerialPortServiceClass_UUID);
+ aRecord.dwNameSpace = NS_BTH;
+ aRecord.dwNumberOfCsAddrs = 1;
+ aRecord.lpcsaBuffer = &aAddrInfo;
+ if (WSASetServiceW( &aRecord, RNRSERVICE_REGISTER, 0 ) == SOCKET_ERROR)
+ {
+ closesocket( aSocket );
+ WSACleanup();
+ return;
+ }
+
+ if ( listen( aSocket, 1 ) == SOCKET_ERROR )
+ {
+ closesocket( aSocket );
+ WSACleanup();
+ return;
+ }
+
+ SOCKADDR_BTH aRemoteAddr;
+ int aRemoteAddrLen = sizeof(aRemoteAddr);
+ while ( true )
+ {
+ SOCKET socket;
+ if ( (socket = accept(aSocket, reinterpret_cast<sockaddr*>(&aRemoteAddr), &aRemoteAddrLen)) == INVALID_SOCKET )
+ {
+ closesocket( aSocket );
+ WSACleanup();
+ return;
+ } else {
+ Communicator* pCommunicator = new Communicator( std::make_unique<BufferedStreamSocket>( socket) );
+ mpCommunicators->push_back( pCommunicator );
+ pCommunicator->launch();
+ }
+ }
+
+#elif defined(MACOSX)
+ // Build up dictionary at run-time instead of bothering with a
+ // .plist file, using the Objective-C API
+
+ // Compare to BluetoothServiceRecord.hxx
+
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ NSDictionary *dict =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+
+ // Service class ID list
+ [NSArray arrayWithObject:
+ [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16ServiceClassSerialPort]],
+ @"0001 - ServiceClassIDList",
+
+ // Protocol descriptor list
+ [NSArray arrayWithObjects:
+ [NSArray arrayWithObject: [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16L2CAP]],
+ [NSArray arrayWithObjects:
+ [IOBluetoothSDPUUID uuid16: kBluetoothL2CAPPSMRFCOMM],
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt: 1],
+ @"DataElementSize",
+ [NSNumber numberWithInt: 1],
+ @"DataElementType",
+ [NSNumber numberWithInt: 5], // RFCOMM port number, will be replaced if necessary automatically
+ @"DataElementValue",
+ nil],
+ nil],
+ nil],
+ @"0004 - Protocol descriptor list",
+
+ // Browse group list
+ [NSArray arrayWithObject:
+ [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16ServiceClassPublicBrowseGroup]],
+ @"0005 - BrowseGroupList",
+
+ // Language base attribute ID list
+ [NSArray arrayWithObjects:
+ [NSData dataWithBytes: "en" length: 2],
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt: 2],
+ @"DataElementSize",
+ [NSNumber numberWithInt: 1],
+ @"DataElementType",
+ [NSNumber numberWithInt: 0x006a], // encoding
+ @"DataElementValue",
+ nil],
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt: 2],
+ @"DataElementSize",
+ [NSNumber numberWithInt: 1],
+ @"DataElementType",
+ [NSNumber numberWithInt: 0x0100], // offset
+ @"DataElementValue",
+ nil],
+ nil],
+ @"0006 - LanguageBaseAttributeIDList",
+
+ // Bluetooth profile descriptor list
+ [NSArray arrayWithObject:
+ [NSArray arrayWithObjects:
+ [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16ServiceClassSerialPort],
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt: 2],
+ @"DataElementSize",
+ [NSNumber numberWithInt: 1],
+ @"DataElementType",
+ [NSNumber numberWithInt: 0x0100], // version number ?
+ @"DataElementValue",
+ nil],
+ nil]],
+ @"0009 - BluetoothProfileDescriptorList",
+
+ // Attributes pointed to by the LanguageBaseAttributeIDList
+ @"LibreOffice Impress Remote Control",
+ @"0100 - ServiceName",
+ @"The Document Foundation",
+ @"0102 - ProviderName",
+ nil];
+
+ // Create service
+ IOBluetoothSDPServiceRecordRef serviceRecordRef;
+ SAL_WNODEPRECATED_DECLARATIONS_PUSH //TODO: 10.9 IOBluetoothAddServiceDict
+ IOReturn rc = IOBluetoothAddServiceDict(reinterpret_cast<CFDictionaryRef>(dict), &serviceRecordRef);
+ SAL_WNODEPRECATED_DECLARATIONS_POP
+
+ SAL_INFO("sdremote.bluetooth", "IOBluetoothAddServiceDict returned " << rc);
+
+ if (rc == kIOReturnSuccess)
+ {
+ IOBluetoothSDPServiceRecord *serviceRecord =
+ [IOBluetoothSDPServiceRecord withSDPServiceRecordRef: serviceRecordRef];
+
+ BluetoothRFCOMMChannelID channelID;
+ [serviceRecord getRFCOMMChannelID: &channelID];
+
+ BluetoothSDPServiceRecordHandle serviceRecordHandle;
+ [serviceRecord getServiceRecordHandle: &serviceRecordHandle];
+
+ // Register callback for incoming connections
+ IOBluetoothRegisterForFilteredRFCOMMChannelOpenNotifications(
+ incomingCallback,
+ this,
+ channelID,
+ kIOBluetoothUserNotificationChannelDirectionIncoming);
+
+ [serviceRecord release];
+ }
+
+ [pool release];
+
+ (void) mpCommunicators;
+#else
+ (void) mpCommunicators; // avoid warnings about unused member
+#endif
+}
+
+BluetoothServer *sd::BluetoothServer::spServer = nullptr;
+
+void BluetoothServer::setup( std::vector<Communicator*>* pCommunicators )
+{
+ if (spServer)
+ return;
+
+ spServer = new BluetoothServer( pCommunicators );
+ spServer->create();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/BluetoothServer.hxx b/sd/source/ui/remotecontrol/BluetoothServer.hxx
new file mode 100644
index 000000000..9e20bfa51
--- /dev/null
+++ b/sd/source/ui/remotecontrol/BluetoothServer.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <osl/thread.hxx>
+#include <memory>
+#include <vector>
+
+#include <config_dbus.h>
+
+#if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && ENABLE_DBUS && DBUS_HAVE_GLIB
+# define LINUX_BLUETOOTH
+#endif
+
+namespace sd
+{
+ class Communicator;
+
+ class BluetoothServer:
+ public osl::Thread
+ {
+ public:
+ static void setup( std::vector<Communicator*>* pCommunicators );
+
+ /// ensure that Bluetooth discoverability is on
+ static void ensureDiscoverable();
+ /// restore the state of discoverability from before ensureDiscoverable
+ static void restoreDiscoverable();
+
+ // called by C / idle callbacks
+ static void doEnsureDiscoverable();
+ static void doRestoreDiscoverable();
+
+#if defined(MACOSX)
+ void addCommunicator( Communicator* pCommunicator );
+#endif
+ private:
+ explicit BluetoothServer( std::vector<Communicator*>* pCommunicators );
+ virtual ~BluetoothServer() override;
+
+ enum { UNKNOWN, DISCOVERABLE, NOT_DISCOVERABLE } meWasDiscoverable;
+ static BluetoothServer *spServer;
+
+#ifdef LINUX_BLUETOOTH
+ struct Impl;
+ std::unique_ptr<Impl> mpImpl;
+#endif
+ virtual void SAL_CALL run() override;
+
+ void cleanupCommunicators();
+ std::vector<Communicator*>* mpCommunicators;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/BluetoothServer.mm b/sd/source/ui/remotecontrol/BluetoothServer.mm
new file mode 100644
index 000000000..28288ff6f
--- /dev/null
+++ b/sd/source/ui/remotecontrol/BluetoothServer.mm
@@ -0,0 +1 @@
+#include "BluetoothServer.cxx" \ No newline at end of file
diff --git a/sd/source/ui/remotecontrol/BluetoothServiceRecord.hxx b/sd/source/ui/remotecontrol/BluetoothServiceRecord.hxx
new file mode 100644
index 000000000..c1a00fb3b
--- /dev/null
+++ b/sd/source/ui/remotecontrol/BluetoothServiceRecord.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+// FIXME: look into sharing definitions across OS's (i.e. UUID and port ).
+// Look into dynamically determining which ports are available.
+
+// SDP is a Service Description Protocol cf.
+// http://developer.bluetooth.org/TechnologyOverview/Pages/DI.aspx
+// This is an XML representation, an alternative would be a
+// binary SDP record.
+
+// for numbers see:
+// https://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
+
+const char * const bluetooth_service_record =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<record>"
+ "<attribute id=\"0x0001\">" // Service class ID list
+ "<sequence>"
+ "<uuid value=\"0x1101\"/>" // an assigned service class meaning: 'serial port'
+ // we could add our own 'LibreOffice remote' service
+ // class here too in future ...
+ "</sequence>"
+ "</attribute>"
+ "<attribute id=\"0x0004\">" // Protocol Descriptor list
+ "<sequence>"
+ "<sequence>"
+ "<uuid value=\"0x0100\"/>" // L2CAP Protocol descriptor
+ "</sequence>"
+ "<sequence>"
+ "<uuid value=\"0x0003\"/>" // enumeration value of RFCOMM protocol
+ "<uint8 value=\"0x05\"/>" // RFCOMM port number
+ "</sequence>"
+ "</sequence>"
+ "</attribute>"
+ "<attribute id=\"0x0005\">" // Browse Group List
+ "<sequence>"
+ "<uuid value=\"0x1002\"/>" // public browse class
+ "</sequence>"
+ "</attribute>"
+ "<attribute id=\"0x0006\">" // Language Base Attribute ID List
+ "<sequence>"
+ "<uint16 value=\"0x656e\"/>" // code_ISO639
+ "<uint16 value=\"0x006a\"/>" // encoding 0x6a
+ "<uint16 value=\"0x0100\"/>" // base_offset ie. points to below =>
+ "</sequence>"
+ "</attribute>"
+ "<attribute id=\"0x0009\">" // Bluetooth Profile Descriptor List
+ "<sequence>"
+ "<sequence>"
+ "<uuid value=\"0x1101\"/>" // 'serial port' UUID as above
+ "<uint16 value=\"0x0100\"/>"// version number 1.0 ?
+ "</sequence>"
+ "</sequence>"
+ "</attribute>"
+ // Attribute identifiers are pointed to by the Language Base Attribute ID List
+ // id+0 = ServiceName, id+1 = ServiceDescription, id+2=ProviderName
+ "<attribute id=\"0x0100\">"
+ "<text value=\"LibreOffice Impress Remote Control\"/>"
+ "</attribute>"
+ "<attribute id=\"0x0102\">"
+ "<text value=\"The Document Foundation\"/>"
+ "</attribute>"
+ "</record>"
+ ;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/BufferedStreamSocket.cxx b/sd/source/ui/remotecontrol/BufferedStreamSocket.cxx
new file mode 100644
index 000000000..64ad5eb8d
--- /dev/null
+++ b/sd/source/ui/remotecontrol/BufferedStreamSocket.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "BufferedStreamSocket.hxx"
+
+#include <osl/socket.hxx>
+#include <sal/log.hxx>
+#include <algorithm>
+
+#ifdef _WIN32
+ // LO vs WinAPI conflict
+ #undef WB_LEFT
+ #undef WB_RIGHT
+
+ #include <winsock2.h>
+#else
+ #include <sys/socket.h>
+ #include <unistd.h>
+#endif
+using namespace sd;
+using namespace osl;
+
+BufferedStreamSocket::BufferedStreamSocket( const osl::StreamSocket &aSocket ):
+ StreamSocket( aSocket ),
+ aRet( 0 ),
+ aRead( 0 ),
+ mSocket( 0 ),
+ usingCSocket( false )
+{
+}
+
+BufferedStreamSocket::BufferedStreamSocket( int aSocket ):
+ aRet( 0 ),
+ aRead( 0 ),
+ mSocket( aSocket ),
+ usingCSocket( true )
+{
+}
+
+BufferedStreamSocket::~BufferedStreamSocket() {
+ close();
+}
+
+void BufferedStreamSocket::getPeerAddr(osl::SocketAddr& rAddr)
+{
+ assert ( !usingCSocket );
+ StreamSocket::getPeerAddr( rAddr );
+}
+
+sal_Int32 BufferedStreamSocket::write( const void* pBuffer, sal_uInt32 n )
+{
+ if ( !usingCSocket )
+ return StreamSocket::write( pBuffer, n );
+ else
+ return ::send(
+ mSocket,
+#if defined(_WIN32)
+ static_cast<char const *>(pBuffer),
+#else
+ pBuffer,
+#endif
+ static_cast<size_t>(n), 0 );
+}
+
+void BufferedStreamSocket::close()
+{
+ if( usingCSocket && mSocket != -1 )
+ {
+#ifdef _WIN32
+ ::closesocket( mSocket );
+#else
+ ::close( mSocket );
+#endif
+ mSocket = -1;
+ }
+ else
+ ::osl::StreamSocket::close();
+}
+
+sal_Int32 BufferedStreamSocket::readLine( OString& aLine )
+{
+ while ( true )
+ {
+ // Process buffer first in case data already present.
+ std::vector<char>::iterator aIt;
+ if ( (aIt = find( aBuffer.begin(), aBuffer.end(), '\n' ))
+ != aBuffer.end() )
+ {
+ sal_uInt64 aLocation = aIt - aBuffer.begin();
+
+ aLine = OString( &(*aBuffer.begin()), aLocation );
+
+ aBuffer.erase( aBuffer.begin(), aIt + 1 ); // Also delete the empty line
+ aRead -= (aLocation + 1);
+
+ SAL_INFO( "sdremote.bluetooth", "recv line '" << aLine << "'" );
+
+ return aLine.getLength() + 1;
+ }
+
+ // Then try and receive if nothing present
+ aBuffer.resize( aRead + 100 );
+ if ( !usingCSocket)
+ aRet = StreamSocket::recv( &aBuffer[aRead], 100 );
+ else
+ aRet = ::recv( mSocket, &aBuffer[aRead], 100, 0 );
+
+ SAL_INFO( "sdremote.bluetooth", "recv " << aRet << " aBuffer len " << aBuffer.size() );
+ if ( aRet <= 0 )
+ {
+ return 0;
+ }
+ // Prevent buffer from growing massively large.
+ if ( aRead > MAX_LINE_LENGTH )
+ {
+ aBuffer.clear();
+ return 0;
+ }
+ aRead += aRet;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/BufferedStreamSocket.hxx b/sd/source/ui/remotecontrol/BufferedStreamSocket.hxx
new file mode 100644
index 000000000..6abf7ec1b
--- /dev/null
+++ b/sd/source/ui/remotecontrol/BufferedStreamSocket.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include "IBluetoothSocket.hxx"
+#include <osl/socket_decl.hxx>
+#include <vector>
+
+#define MAX_LINE_LENGTH 20000
+
+namespace sd
+{
+
+ /**
+ * [A wrapper for an osl StreamSocket to allow reading lines.]
+ *
+ * Currently wraps either an osl StreamSocket or a standard c socket,
+ * allowing reading and writing for our purposes. Should eventually be
+ * returned to being a StreamSocket wrapper if/when Bluetooth is
+ * integrated into osl Sockets.
+ */
+ class BufferedStreamSocket final :
+ public IBluetoothSocket,
+ private ::osl::StreamSocket
+ {
+ public:
+ /**
+ * Create a BufferedStreamSocket on top of an
+ * osl::StreamSocket.
+ */
+ explicit BufferedStreamSocket( const osl::StreamSocket &aSocket );
+ /**
+ * Create a BufferedStreamSocket on top of a POSIX or WinSock socket.
+ */
+ explicit BufferedStreamSocket( int aSocket );
+ BufferedStreamSocket( const BufferedStreamSocket &aSocket );
+
+ ~BufferedStreamSocket();
+
+ /**
+ * Blocks until a line is read.
+ * Returns whatever the last call of recv returned, i.e. 0 or less
+ * if there was a problem in communications.
+ */
+ virtual sal_Int32 readLine( OString& aLine ) override;
+
+ virtual sal_Int32 write( const void* pBuffer, sal_uInt32 n ) override;
+
+ virtual void close() override;
+
+ void getPeerAddr(osl::SocketAddr&);
+ private:
+ sal_Int32 aRet, aRead;
+ std::vector<char> aBuffer;
+ int mSocket;
+ bool usingCSocket;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/Communicator.cxx b/sd/source/ui/remotecontrol/Communicator.cxx
new file mode 100644
index 000000000..59509ed3c
--- /dev/null
+++ b/sd/source/ui/remotecontrol/Communicator.cxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include <algorithm>
+#include <vector>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/presentation/XPresentation2.hpp>
+#include <com/sun/star/presentation/XPresentationSupplier.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/documentinfo.hxx>
+#include <config_version.h>
+#include <rtl/string.hxx>
+#include <sal/log.hxx>
+
+#include "Communicator.hxx"
+#include "IBluetoothSocket.hxx"
+#include "Listener.hxx"
+#include "Receiver.hxx"
+#include "Transmitter.hxx"
+#include <RemoteServer.hxx>
+
+using namespace sd;
+using namespace com::sun::star;
+using namespace osl;
+
+Communicator::Communicator( std::unique_ptr<IBluetoothSocket> pSocket ):
+ Thread( "CommunicatorThread" ),
+ mpSocket( std::move(pSocket) )
+{
+}
+
+Communicator::~Communicator()
+{
+}
+
+/// Close the underlying socket from another thread to force
+/// an early exit / termination
+void Communicator::forceClose()
+{
+ if( mpSocket )
+ mpSocket->close();
+}
+
+// Run as a thread
+void Communicator::execute()
+{
+ pTransmitter.reset( new Transmitter( mpSocket.get() ) );
+ pTransmitter->create();
+
+ pTransmitter->addMessage( "LO_SERVER_SERVER_PAIRED\n\n",
+ Transmitter::PRIORITY_HIGH );
+
+ pTransmitter->addMessage( "LO_SERVER_INFO\n" LIBO_VERSION_DOTTED "\n\n",
+ Transmitter::PRIORITY_HIGH );
+
+ Receiver aReceiver( pTransmitter.get() );
+ try {
+ uno::Reference< frame::XDesktop2 > xFramesSupplier = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
+ uno::Reference< frame::XFrame > xFrame = xFramesSupplier->getActiveFrame();
+
+ uno::Reference<presentation::XPresentationSupplier> xPS;
+ if( xFrame.is() )
+ xPS.set( xFrame->getController()->getModel(), uno::UNO_QUERY );
+ uno::Reference<presentation::XPresentation2> xPresentation;
+ if( xPS.is() )
+ xPresentation.set( xPS->getPresentation(), uno::UNO_QUERY );
+ if ( xPresentation.is() && xPresentation->isRunning() )
+ {
+ presentationStarted( xPresentation->getController() );
+ OString aBuffer =
+ "slideshow_info\n" +
+ OUStringToOString( ::comphelper::DocumentInfo::getDocumentTitle( xFrame->getController()->getModel() ), RTL_TEXTENCODING_UTF8 ) +
+ "\n\n";
+
+ pTransmitter->addMessage( aBuffer.getStr(), Transmitter::PRIORITY_LOW );
+ }
+ else
+ {
+ pTransmitter->addMessage( "slideshow_finished\n\n",
+ Transmitter::PRIORITY_HIGH );
+ }
+ }
+ catch (uno::RuntimeException &)
+ {
+ }
+
+ sal_uInt64 aRet;
+ std::vector<OString> aCommand;
+ while ( true )
+ {
+ OString aLine;
+ aRet = mpSocket->readLine( aLine );
+ if ( aRet == 0 )
+ {
+ break; // I.e. transmission finished.
+ }
+ if ( aLine.getLength() )
+ {
+ aCommand.push_back( aLine );
+ }
+ else
+ {
+ aReceiver.pushCommand( aCommand );
+ aCommand.clear();
+ }
+ }
+
+ SAL_INFO ("sdremote", "Exiting transmission loop");
+
+ disposeListener();
+
+ pTransmitter->notifyFinished();
+ pTransmitter->join();
+ pTransmitter = nullptr;
+
+ mpSocket->close();
+ mpSocket.reset();
+
+ RemoteServer::removeCommunicator( this );
+}
+
+void Communicator::informListenerDestroyed()
+{
+ if ( pTransmitter )
+ pTransmitter->addMessage( "slideshow_finished\n\n",
+ Transmitter::PRIORITY_HIGH );
+}
+
+void Communicator::presentationStarted( const css::uno::Reference<
+ css::presentation::XSlideShowController > &rController )
+{
+ if ( pTransmitter )
+ {
+ mListener.set( new Listener( this, pTransmitter.get() ) );
+ mListener->init( rController );
+ }
+}
+
+void Communicator::disposeListener()
+{
+ if ( mListener.is() )
+ {
+ mListener->dispose();
+ mListener = nullptr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/Communicator.hxx b/sd/source/ui/remotecontrol/Communicator.hxx
new file mode 100644
index 000000000..f8f23c58c
--- /dev/null
+++ b/sd/source/ui/remotecontrol/Communicator.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <memory>
+
+#include <rtl/ref.hxx>
+#include <salhelper/thread.hxx>
+
+namespace com::sun::star::uno { template <typename > class Reference; }
+namespace com::sun::star::presentation { class XSlideShowController; }
+namespace sd { struct IBluetoothSocket; }
+
+namespace sd
+{
+
+ class Transmitter;
+ class Listener;
+
+ /** Class used for communication with one single client, dealing with all
+ * tasks specific to this client.
+ *
+ * Needs to be created, then started using launch(), disposes itself.
+ */
+ class Communicator : public salhelper::Thread
+ {
+ public:
+ explicit Communicator( std::unique_ptr<IBluetoothSocket> pSocket );
+ virtual ~Communicator() override;
+
+ void presentationStarted( const css::uno::Reference<
+ css::presentation::XSlideShowController > &rController );
+ void informListenerDestroyed();
+ void disposeListener();
+ void forceClose();
+
+ private:
+ void execute() override;
+ std::unique_ptr<IBluetoothSocket> mpSocket;
+
+ std::unique_ptr<Transmitter> pTransmitter;
+ rtl::Reference<Listener> mListener;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.cxx b/sd/source/ui/remotecontrol/DiscoveryService.cxx
new file mode 100644
index 000000000..bdd0b51c8
--- /dev/null
+++ b/sd/source/ui/remotecontrol/DiscoveryService.cxx
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <errno.h>
+#include <string.h>
+#include <iostream>
+
+#include <osl/socket.hxx>
+#include <config_features.h>
+#include <sal/log.hxx>
+
+#include "DiscoveryService.hxx"
+#include "ZeroconfService.hxx"
+
+#ifdef _WIN32
+ // LO vs WinAPI conflict
+ #undef WB_LEFT
+ #undef WB_RIGHT
+
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+
+ #include "WINNetworkService.hxx"
+ typedef int socklen_t;
+#else
+ #include <unistd.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+#endif
+
+#ifdef MACOSX
+ #include <osl/conditn.hxx>
+ #include <premac.h>
+ #import <CoreFoundation/CoreFoundation.h>
+ #include <postmac.h>
+ #import "OSXNetworkService.hxx"
+#endif
+
+#if HAVE_FEATURE_AVAHI
+ #include "AvahiNetworkService.hxx"
+#endif
+
+using namespace osl;
+using namespace sd;
+
+DiscoveryService::DiscoveryService()
+ : mSocket(-1)
+ , zService(nullptr)
+{
+}
+
+DiscoveryService::~DiscoveryService()
+{
+ if (mSocket != -1)
+ {
+#ifdef _WIN32
+ closesocket( mSocket );
+#else
+ close( mSocket );
+#endif
+ }
+
+ if (zService)
+ zService->clear();
+}
+
+void DiscoveryService::setupSockets()
+{
+
+#ifdef MACOSX
+ // Bonjour for OSX
+ zService = new OSXNetworkService();
+ zService->setup();
+#endif
+
+#if HAVE_FEATURE_AVAHI
+ // Avahi for Linux
+ char hostname[1024];
+ hostname[1023] = '\0';
+ gethostname(hostname, 1023);
+
+ zService = new AvahiNetworkService(hostname);
+ zService->setup();
+#endif
+
+#ifdef _WIN32
+ zService = new WINNetworkService();
+ zService->setup();
+#endif
+
+ // Old implementation for backward compatibility matter
+ mSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+ if (mSocket == -1)
+ {
+ SAL_WARN("sd", "DiscoveryService: socket failed: " << errno);
+ return; // would be better to throw, but unsure if caller handles that
+ }
+
+ sockaddr_in aAddr = {};
+ aAddr.sin_family = AF_INET;
+ aAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ aAddr.sin_port = htons( PORT_DISCOVERY );
+
+ int rc = bind( mSocket, reinterpret_cast<sockaddr*>(&aAddr), sizeof(sockaddr_in) );
+
+ if (rc)
+ {
+ SAL_WARN("sd", "DiscoveryService: bind failed: " << errno);
+ return; // would be better to throw, but unsure if caller handles that
+ }
+
+ struct ip_mreq multicastRequest;
+
+ multicastRequest.imr_multiaddr.s_addr = htonl((239U << 24) | 1U); // 239.0.0.1
+ multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ rc = setsockopt( mSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ #ifdef _WIN32
+ reinterpret_cast<const char*>(&multicastRequest),
+ #else
+ &multicastRequest,
+ #endif
+ sizeof(multicastRequest));
+
+ if (rc)
+ {
+ SAL_WARN("sd", "DiscoveryService: setsockopt failed: " << errno);
+ return; // would be better to throw, but unsure if caller handles that
+ }
+}
+
+void SAL_CALL DiscoveryService::run()
+{
+ osl::Thread::setName("DiscoveryService");
+
+ setupSockets();
+
+ // Kept for backward compatibility
+ while ( true )
+ {
+ char aBuffer[BUFFER_SIZE] = {};
+ sockaddr_in aAddr;
+ socklen_t aLen = sizeof( aAddr );
+ if(recvfrom( mSocket, aBuffer, BUFFER_SIZE, 0, reinterpret_cast<sockaddr*>(&aAddr), &aLen ) > 0)
+ {
+ OString aString( aBuffer, strlen( "LOREMOTE_SEARCH" ) );
+ if ( aString == "LOREMOTE_SEARCH" )
+ {
+ OString aStringBuffer = "LOREMOTE_ADVERTISE\n" +
+ OUStringToOString(osl::SocketAddr::getLocalHostname(), RTL_TEXTENCODING_UTF8 ) +
+ "\n\n";
+ if ( sendto( mSocket, aStringBuffer.getStr(),
+ aStringBuffer.getLength(), 0, reinterpret_cast<sockaddr*>(&aAddr),
+ sizeof(aAddr) ) <= 0 )
+ {
+ // Write error or closed socket -- we are done.
+ return;
+ }
+ }
+ }
+ else
+ {
+ // Read error or closed socket -- we are done.
+ return;
+ }
+ }
+}
+
+DiscoveryService *sd::DiscoveryService::spService = nullptr;
+
+void DiscoveryService::setup()
+{
+ if (spService)
+ return;
+
+ spService = new DiscoveryService();
+ spService->create();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.hxx b/sd/source/ui/remotecontrol/DiscoveryService.hxx
new file mode 100644
index 000000000..4b235fe89
--- /dev/null
+++ b/sd/source/ui/remotecontrol/DiscoveryService.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <osl/thread.hxx>
+
+namespace sd { class ZeroconfService; }
+
+namespace sd
+{
+ class DiscoveryService : public osl::Thread
+ {
+ public:
+ static void setup();
+
+ private:
+ DiscoveryService();
+ virtual ~DiscoveryService() override;
+
+ /**
+ * Networking related setup -- must be run within our own thread
+ * to prevent the application blocking (fdo#75328).
+ */
+ void setupSockets();
+
+ static DiscoveryService *spService;
+ virtual void SAL_CALL run() override;
+ int mSocket;
+
+ ZeroconfService * zService;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.mm b/sd/source/ui/remotecontrol/DiscoveryService.mm
new file mode 100644
index 000000000..3cad7cdfb
--- /dev/null
+++ b/sd/source/ui/remotecontrol/DiscoveryService.mm
@@ -0,0 +1 @@
+#include "DiscoveryService.cxx" \ No newline at end of file
diff --git a/sd/source/ui/remotecontrol/IBluetoothSocket.hxx b/sd/source/ui/remotecontrol/IBluetoothSocket.hxx
new file mode 100644
index 000000000..4b75a1e82
--- /dev/null
+++ b/sd/source/ui/remotecontrol/IBluetoothSocket.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/.
+ */
+
+#pragma once
+
+#include <rtl/string.hxx>
+
+namespace sd
+{
+ /** Interface for bluetooth data io
+ */
+ struct IBluetoothSocket
+ {
+ IBluetoothSocket() = default;
+ virtual ~IBluetoothSocket() {}
+ IBluetoothSocket(const IBluetoothSocket&) = delete;
+ IBluetoothSocket& operator=(const IBluetoothSocket&) = delete;
+
+ /** Blocks until a line is read.
+
+ @return whatever the last call of recv returned, i.e. 0 or less
+ if there was a problem in communications.
+ */
+ virtual sal_Int32 readLine(OString& aLine) = 0;
+
+ /** Write a number of bytes
+
+ @return number of bytes actually written
+ */
+ virtual sal_Int32 write( const void* pBuffer, sal_uInt32 n ) = 0;
+
+ virtual void close() {};
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/ImagePreparer.cxx b/sd/source/ui/remotecontrol/ImagePreparer.cxx
new file mode 100644
index 000000000..ba8d2c1f3
--- /dev/null
+++ b/sd/source/ui/remotecontrol/ImagePreparer.cxx
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ImagePreparer.hxx"
+#include "Transmitter.hxx"
+
+#include <comphelper/base64.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <osl/file.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/drawing/GraphicExportFilter.hpp>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/presentation/XSlideShowController.hpp>
+#include <com/sun/star/presentation/XPresentationPage.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+
+using namespace ::sd;
+using namespace ::osl;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+ImagePreparer::ImagePreparer(
+ const uno::Reference<presentation::XSlideShowController>& rxController,
+ Transmitter *aTransmitter )
+ : Timer("sd ImagePreparer"),
+ xController( rxController ),
+ pTransmitter( aTransmitter )
+{
+ SAL_INFO( "sdremote", "ImagePreparer - start" );
+ SetTimeout( 50 );
+ mnSendingSlide = 0;
+ Start();
+}
+
+ImagePreparer::~ImagePreparer()
+{
+ SAL_INFO( "sdremote", "ImagePreparer - stop" );
+ Stop();
+}
+
+void ImagePreparer::Invoke()
+{
+ sal_uInt32 aSlides = xController->getSlideCount();
+ SAL_INFO( "sdremote", "ImagePreparer " << xController->isRunning() <<
+ " sending slide " << mnSendingSlide << " of " << aSlides );
+ if ( xController->isRunning() && // not stopped/disposed of.
+ mnSendingSlide < aSlides )
+ {
+ sendPreview( mnSendingSlide );
+ sendNotes( mnSendingSlide );
+ mnSendingSlide++;
+ Start();
+ }
+ else
+ Stop();
+}
+
+void ImagePreparer::sendPreview( sal_uInt32 aSlideNumber )
+{
+ sal_uInt64 aSize;
+ uno::Sequence<sal_Int8> aImageData = preparePreview( aSlideNumber, 320, 240,
+ aSize );
+ if ( !xController->isRunning() )
+ return;
+
+ OUStringBuffer aStrBuffer;
+ ::comphelper::Base64::encode( aStrBuffer, aImageData );
+
+ OString aEncodedShortString = OUStringToOString(
+ aStrBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
+
+ // Start the writing
+ OString aBuffer = "slide_preview\n" +
+ OString::number(aSlideNumber) +
+ "\n" + aEncodedShortString + "\n\n";
+ pTransmitter->addMessage( aBuffer,
+ Transmitter::PRIORITY_LOW );
+
+}
+
+uno::Sequence<sal_Int8> ImagePreparer::preparePreview(
+ sal_uInt32 aSlideNumber, sal_uInt32 aWidth, sal_uInt32 aHeight,
+ sal_uInt64 &rSize )
+{
+ OUString aFileURL;
+ FileBase::createTempFile( nullptr, nullptr, &aFileURL );
+
+ uno::Reference< drawing::XGraphicExportFilter > xFilter =
+ drawing::GraphicExportFilter::create( ::comphelper::getProcessComponentContext() );
+
+ if ( !xController->isRunning() )
+ return uno::Sequence<sal_Int8>();
+
+ uno::Reference< lang::XComponent > xSourceDoc(
+ xController->getSlideByIndex( aSlideNumber ),
+ uno::UNO_QUERY_THROW );
+
+ xFilter->setSourceDocument( xSourceDoc );
+
+ uno::Sequence< beans::PropertyValue > aFilterData{
+ comphelper::makePropertyValue("PixelWidth", aWidth),
+ comphelper::makePropertyValue("PixelHeight", aHeight),
+ comphelper::makePropertyValue("ColorMode", sal_Int32(0)) // 0: Color, 1: B&W
+ };
+
+ uno::Sequence< beans::PropertyValue > aProps{
+ comphelper::makePropertyValue("MediaType", OUString( "image/png" )),
+ comphelper::makePropertyValue("URL", aFileURL),
+ comphelper::makePropertyValue("FilterData", aFilterData)
+ };
+
+ xFilter->filter( aProps );
+
+ File aFile(aFileURL);
+ if (aFile.open(0) != osl::File::E_None)
+ return uno::Sequence<sal_Int8>();
+
+ sal_uInt64 aRead;
+ rSize = 0;
+ aFile.getSize( rSize );
+ uno::Sequence<sal_Int8> aContents( rSize );
+
+ aFile.read( aContents.getArray(), rSize, aRead );
+ if (aRead != rSize)
+ aContents.realloc(aRead);
+
+ aFile.close();
+ File::remove( aFileURL );
+ return aContents;
+
+}
+
+void ImagePreparer::sendNotes( sal_uInt32 aSlideNumber )
+{
+
+ OString aNotes = prepareNotes( aSlideNumber );
+
+ if ( aNotes.isEmpty() )
+ return;
+
+ if ( !xController->isRunning() )
+ return;
+
+ // Start the writing
+ OString aBuffer =
+ "slide_notes\n" +
+ OString::number( static_cast<sal_Int32>(aSlideNumber) ) +
+ "\n"
+ "<html><body>" +
+ aNotes +
+ "</body></html>"
+ "\n\n";
+ pTransmitter->addMessage( aBuffer,
+ Transmitter::PRIORITY_LOW );
+}
+
+// Code copied from sdremote/source/presenter/PresenterNotesView.cxx
+OString ImagePreparer::prepareNotes( sal_uInt32 aSlideNumber )
+{
+ OUStringBuffer aRet;
+
+ if ( !xController->isRunning() )
+ return "";
+
+ uno::Reference<css::drawing::XDrawPage> aNotesPage;
+ uno::Reference< drawing::XDrawPage > xSourceDoc(
+ xController->getSlideByIndex( aSlideNumber ),
+ uno::UNO_SET_THROW );
+ uno::Reference<presentation::XPresentationPage> xPresentationPage(
+ xSourceDoc, UNO_QUERY);
+ if (xPresentationPage.is())
+ aNotesPage = xPresentationPage->getNotesPage();
+ else
+ return "";
+
+ static constexpr OUStringLiteral sNotesShapeName (
+ u"com.sun.star.presentation.NotesShape" );
+ static constexpr OUStringLiteral sTextShapeName (
+ u"com.sun.star.drawing.TextShape" );
+
+ if (aNotesPage.is())
+ {
+
+ // Iterate over all shapes and find the one that holds the text.
+ sal_Int32 nCount (aNotesPage->getCount());
+ for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
+ {
+
+ uno::Reference<lang::XServiceName> xServiceName (
+ aNotesPage->getByIndex(nIndex), UNO_QUERY);
+ if (xServiceName.is()
+ && xServiceName->getServiceName() == sNotesShapeName)
+ {
+ uno::Reference<text::XTextRange> xText (xServiceName, UNO_QUERY);
+ if (xText.is())
+ {
+ aRet.append(xText->getString());
+ aRet.append("<br/>");
+ }
+ }
+ else
+ {
+ uno::Reference<drawing::XShapeDescriptor> xShapeDescriptor (
+ aNotesPage->getByIndex(nIndex), UNO_QUERY);
+ if (xShapeDescriptor.is())
+ {
+ OUString sType (xShapeDescriptor->getShapeType());
+ if (sType == sNotesShapeName || sType == sTextShapeName)
+ {
+ uno::Reference<text::XTextRange> xText (
+ aNotesPage->getByIndex(nIndex), UNO_QUERY);
+ if (xText.is())
+ {
+ aRet.append(xText->getString());
+ aRet.append("<br/>");
+ }
+ }
+ }
+ }
+ }
+ }
+ // Replace all newlines with <br\> tags
+ for ( sal_Int32 i = 0; i < aRet.getLength(); i++ )
+ {
+ if ( aRet[i] == '\n' )
+ {
+ aRet[i]= '<';
+ aRet.insert( i+1, "br/>" );
+ }
+ }
+ return OUStringToOString(
+ aRet.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/ImagePreparer.hxx b/sd/source/ui/remotecontrol/ImagePreparer.hxx
new file mode 100644
index 000000000..146eba073
--- /dev/null
+++ b/sd/source/ui/remotecontrol/ImagePreparer.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <vcl/timer.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace com::sun::star::presentation { class XSlideShowController; }
+namespace sd { class Transmitter; }
+
+namespace sd
+{
+
+class ImagePreparer : private Timer
+{
+ sal_uInt32 mnSendingSlide;
+public:
+ ImagePreparer( const
+ css::uno::Reference<css::presentation::XSlideShowController>&
+ rxController, sd::Transmitter *aTransmitter );
+ virtual ~ImagePreparer() override;
+
+private:
+ css::uno::Reference<css::presentation::XSlideShowController> xController;
+ Transmitter *pTransmitter;
+
+ virtual void Invoke() override;
+
+ void sendPreview( sal_uInt32 aSlideNumber );
+ css::uno::Sequence<sal_Int8> preparePreview( sal_uInt32 aSlideNumber,
+ sal_uInt32 aWidth, sal_uInt32 aHeight, sal_uInt64 &rSize );
+
+ void sendNotes( sal_uInt32 aSlideNumber );
+ OString prepareNotes( sal_uInt32 aSlideNumber );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/Listener.cxx b/sd/source/ui/remotecontrol/Listener.cxx
new file mode 100644
index 000000000..3753ed9b5
--- /dev/null
+++ b/sd/source/ui/remotecontrol/Listener.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/.
+ */
+
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+
+#include "Communicator.hxx"
+#include "Listener.hxx"
+#include "ImagePreparer.hxx"
+#include "Transmitter.hxx"
+
+#include <com/sun/star/presentation/XSlideShowController.hpp>
+
+using namespace sd;
+using namespace ::com::sun::star::presentation;
+
+Listener::Listener( const ::rtl::Reference<Communicator>& rCommunicator,
+ sd::Transmitter *aTransmitter ):
+ mCommunicator( rCommunicator ),
+ pTransmitter( nullptr )
+{
+ pTransmitter = aTransmitter;
+}
+
+Listener::~Listener()
+{
+}
+
+void Listener::init( const css::uno::Reference< css::presentation::XSlideShowController >& aController)
+{
+ if ( aController.is() )
+ {
+ mController.set( aController );
+ aController->addSlideShowListener( this );
+
+ sal_Int32 aSlides = aController->getSlideCount();
+ sal_Int32 aCurrentSlide = aController->getCurrentSlideIndex();
+ OString aBuffer = "slideshow_started\n" +
+ OString::number( aSlides ) + "\n" +
+ OString::number( aCurrentSlide ) + "\n\n";
+
+ pTransmitter->addMessage( aBuffer,
+ Transmitter::PRIORITY_HIGH );
+
+ {
+ SolarMutexGuard aGuard;
+ /* ImagePreparer* pPreparer = */ new ImagePreparer( aController, pTransmitter );
+ }
+ }
+ else
+ {
+ SAL_INFO( "sdremote", "Listener::init but no controller - so no preview push queued" );
+ }
+}
+
+//----- XAnimationListener ----------------------------------------------------
+
+void SAL_CALL Listener::beginEvent(const css::uno::Reference<
+ css::animations::XAnimationNode >& )
+{}
+
+void SAL_CALL Listener::endEvent( const css::uno::Reference<
+ css::animations::XAnimationNode >& )
+{}
+
+void SAL_CALL Listener::repeat( const css::uno::Reference<
+ css::animations::XAnimationNode >&, ::sal_Int32 )
+{}
+
+//----- XSlideShowListener ----------------------------------------------------
+
+void SAL_CALL Listener::paused()
+{
+}
+
+void SAL_CALL Listener::resumed()
+{
+}
+
+void SAL_CALL Listener::slideEnded (sal_Bool)
+{
+}
+
+void SAL_CALL Listener::hyperLinkClicked (const OUString &)
+{
+}
+
+void SAL_CALL Listener::slideTransitionStarted()
+{
+ sal_Int32 aSlide = mController->getCurrentSlideIndex();
+
+ OString aBuilder = "slide_updated\n" +
+ OString::number( aSlide ) +
+ "\n\n";
+
+ if ( pTransmitter )
+ {
+ pTransmitter->addMessage( aBuilder,
+ Transmitter::PRIORITY_HIGH );
+ }
+}
+
+void SAL_CALL Listener::slideTransitionEnded()
+{
+}
+
+void SAL_CALL Listener::slideAnimationsEnded()
+{
+}
+
+void Listener::disposing(std::unique_lock<std::mutex>&)
+{
+ pTransmitter = nullptr;
+ if ( mController.is() )
+ {
+ mController->removeSlideShowListener( this );
+ mController = nullptr;
+ }
+ mCommunicator->informListenerDestroyed();
+}
+
+void SAL_CALL Listener::disposing (
+ const css::lang::EventObject&)
+{
+ dispose();
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/Listener.hxx b/sd/source/ui/remotecontrol/Listener.hxx
new file mode 100644
index 000000000..58d7483f6
--- /dev/null
+++ b/sd/source/ui/remotecontrol/Listener.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <sal/config.h>
+#include <com/sun/star/presentation/XSlideShowListener.hpp>
+
+#include <rtl/ref.hxx>
+#include <comphelper/compbase.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace com::sun::star::presentation { class XSlideShowController; }
+namespace sd { class Communicator; }
+namespace sd { class Transmitter; }
+
+namespace sd {
+/**
+ * Slide show listener. This class can also be used for anything else that is
+ * specific to the lifetime of one slideshow while a client is connected.
+ */
+class Listener
+ : public comphelper::WeakComponentImplHelper< css::presentation::XSlideShowListener >
+{
+public:
+ Listener( const ::rtl::Reference<Communicator>& rServer, sd::Transmitter *aTransmitter );
+ virtual ~Listener() override;
+ void init( const css::uno::Reference< css::presentation::XSlideShowController >& aController );
+
+ // XAnimationListener
+ virtual void SAL_CALL beginEvent(const css::uno::Reference<
+ css::animations::XAnimationNode >& rNode ) override;
+ virtual void SAL_CALL endEvent( const css::uno::Reference<
+ css::animations::XAnimationNode >& rNode ) override;
+ virtual void SAL_CALL repeat( const css::uno::Reference<
+ css::animations::XAnimationNode >& rNode, ::sal_Int32 Repeat ) override;
+
+ // XSlideShowListener
+ virtual void SAL_CALL paused( ) override;
+ virtual void SAL_CALL resumed( ) override;
+ virtual void SAL_CALL slideTransitionStarted( ) override;
+ virtual void SAL_CALL slideTransitionEnded( ) override;
+ virtual void SAL_CALL slideAnimationsEnded( ) override;
+ virtual void SAL_CALL slideEnded(sal_Bool bReverse) override;
+ virtual void SAL_CALL hyperLinkClicked( const OUString& hyperLink ) override;
+
+ // XEventListener
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+ virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
+
+private:
+ rtl::Reference<Communicator> mCommunicator;
+ sd::Transmitter *pTransmitter;
+ css::uno::Reference< css::presentation::XSlideShowController > mController;
+};
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/OSXBluetooth.h b/sd/source/ui/remotecontrol/OSXBluetooth.h
new file mode 100644
index 000000000..64f095f6c
--- /dev/null
+++ b/sd/source/ui/remotecontrol/OSXBluetooth.h
@@ -0,0 +1,30 @@
+/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#import <IOBluetooth/objc/IOBluetoothRFCOMMChannel.h>
+
+#include "IBluetoothSocket.hxx"
+#include "Communicator.hxx"
+#include "OSXBluetoothWrapper.hxx"
+
+@interface ChannelDelegate : NSObject<IOBluetoothRFCOMMChannelDelegate>
+{
+ sd::Communicator* pCommunicator;
+ sd::OSXBluetoothWrapper* pSocket;
+}
+
+- (id) initWithCommunicatorAndSocket:(sd::Communicator*)communicator socket:(sd::OSXBluetoothWrapper*)socket;
+- (void) rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel data:(void *)dataPointer length:(size_t)dataLength;
+- (void) rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel;
+
+@end
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/OSXBluetooth.mm b/sd/source/ui/remotecontrol/OSXBluetooth.mm
new file mode 100644
index 000000000..8b705c50b
--- /dev/null
+++ b/sd/source/ui/remotecontrol/OSXBluetooth.mm
@@ -0,0 +1,53 @@
+/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <osl/conditn.hxx>
+#include <sal/log.hxx>
+
+#include <premac.h>
+#import <IOBluetooth/objc/IOBluetoothRFCOMMChannel.h>
+#include <postmac.h>
+
+#include "OSXBluetooth.h"
+
+@implementation ChannelDelegate
+
+- (id) initWithCommunicatorAndSocket:(sd::Communicator*)communicator socket:(sd::OSXBluetoothWrapper*)socket
+{
+ pCommunicator = communicator;
+ pSocket = socket;
+ return self;
+}
+
+- (void) rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel data:(void *)dataPointer length:(size_t)dataLength
+{
+ (void) rfcommChannel;
+
+ if ( pSocket )
+ {
+ pSocket->appendData(dataPointer, dataLength);
+ }
+}
+
+- (void) rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel
+{
+ (void) rfcommChannel;
+
+ SAL_INFO( "sdremote.bluetooth", "ChannelDelegate::rfcommChannelClosed()");
+
+ if ( pSocket )
+ {
+ pSocket->channelClosed();
+ }
+ pCommunicator = nullptr;
+ pSocket = nullptr;
+}
+
+@end
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/OSXBluetoothWrapper.hxx b/sd/source/ui/remotecontrol/OSXBluetoothWrapper.hxx
new file mode 100644
index 000000000..26e1349f0
--- /dev/null
+++ b/sd/source/ui/remotecontrol/OSXBluetoothWrapper.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/.
+ */
+
+#pragma once
+
+#include <rtl/string.hxx>
+#include <osl/conditn.hxx>
+#include <osl/mutex.hxx>
+#include <vector>
+
+#include "IBluetoothSocket.hxx"
+
+namespace sd
+{
+ class OSXBluetoothWrapper : public IBluetoothSocket
+ {
+ IOBluetoothRFCOMMChannel* mpChannel;
+ int mnMTU;
+ osl::Condition mHaveBytes;
+ osl::Mutex mMutex;
+ std::vector<char> mBuffer;
+
+ public:
+ OSXBluetoothWrapper( IOBluetoothRFCOMMChannel* channel );
+ virtual sal_Int32 readLine( OString& aLine ) override;
+ virtual sal_Int32 write( const void* pBuffer, sal_uInt32 len ) override;
+ void appendData(void* pBuffer, size_t len );
+ void channelClosed();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/OSXNetworkService.h b/sd/source/ui/remotecontrol/OSXNetworkService.h
new file mode 100644
index 000000000..7298d901b
--- /dev/null
+++ b/sd/source/ui/remotecontrol/OSXNetworkService.h
@@ -0,0 +1,30 @@
+/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <premac.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import <Foundation/NSNetServices.h>
+#import <Foundation/NSRunLoop.h>
+#include <postmac.h>
+
+@interface OSXBonjourService : NSObject <NSNetServiceDelegate>
+{
+ NSNetService* netService;
+}
+
+- (void)publishImpressRemoteServiceOnLocalNetworkWithName:(NSString*)sName;
+
+@end
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/OSXNetworkService.hxx b/sd/source/ui/remotecontrol/OSXNetworkService.hxx
new file mode 100644
index 000000000..78ab13eff
--- /dev/null
+++ b/sd/source/ui/remotecontrol/OSXNetworkService.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+#include <vector>
+#include <iostream>
+
+#include <osl/conditn.hxx>
+#include <premac.h>
+#import <CoreFoundation/CoreFoundation.h>
+#include <postmac.h>
+#import "OSXNetworkService.h"
+
+#include "ZeroconfService.hxx"
+
+namespace sd {
+ class OSXNetworkService : public ZeroconfService
+ {
+ private:
+ OSXBonjourService *osxservice;
+ public:
+ OSXNetworkService(const std::string& aname = "", unsigned int aport = 1599)
+ : ZeroconfService(aname, aport){}
+
+ void clear() override {
+ [osxservice dealloc];
+ }
+ void setup() override {
+ osxservice = [[OSXBonjourService alloc] init];
+ [osxservice publishImpressRemoteServiceOnLocalNetworkWithName: @""];
+ };
+ };
+}
diff --git a/sd/source/ui/remotecontrol/OSXNetworkService.mm b/sd/source/ui/remotecontrol/OSXNetworkService.mm
new file mode 100644
index 000000000..51cbd8c99
--- /dev/null
+++ b/sd/source/ui/remotecontrol/OSXNetworkService.mm
@@ -0,0 +1,43 @@
+/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <osl/conditn.hxx>
+
+#include <premac.h>
+ #import <CoreFoundation/CoreFoundation.h>
+ #import "OSXNetworkService.h"
+#include <postmac.h>
+
+@implementation OSXBonjourService
+
+- (void) publishImpressRemoteServiceOnLocalNetworkWithName:(NSString *)sName
+{
+ netService = [[NSNetService alloc] initWithDomain:@"local" type:@"_impressremote._tcp" name:sName port:1599];
+
+ if (netService != nil)
+ {
+ [netService setDelegate:self];
+ [netService scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+ [netService publish];
+ }
+}
+
+-(void)netService:(NSNetService *)aNetService
+ didNotPublish:(NSDictionary *)dict {
+ NSLog(@"Service %p did not publish: %@", aNetService, dict);
+}
+
+- (void)dealloc {
+ [netService stop];
+ [netService release];
+ [super dealloc];
+}
+
+@end
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/Receiver.cxx b/sd/source/ui/remotecontrol/Receiver.cxx
new file mode 100644
index 000000000..dd92e8e99
--- /dev/null
+++ b/sd/source/ui/remotecontrol/Receiver.cxx
@@ -0,0 +1,207 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 "Receiver.hxx"
+#include <com/sun/star/presentation/XSlideShowController.hpp>
+#include <com/sun/star/presentation/XPresentationSupplier.hpp>
+#include <com/sun/star/presentation/XPresentation2.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <vcl/svapp.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace sd;
+using namespace ::osl;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::beans;
+
+Receiver::Receiver( Transmitter *aTransmitter ) : Timer("sd Receiver")
+{
+ pTransmitter = aTransmitter;
+ SetTimeout( 0 );
+}
+
+Receiver::~Receiver()
+{
+}
+
+// Bounce the commands to the main thread to avoid threading woes
+void Receiver::pushCommand( const std::vector<OString> &rCommand )
+{
+ SolarMutexGuard aGuard;
+ maExecQueue.push_back( rCommand );
+ Start();
+}
+
+void Receiver::Invoke()
+{
+ if( !maExecQueue.empty() )
+ {
+ std::vector< OString > aCommands( maExecQueue.front() );
+ maExecQueue.pop_front();
+ if( !aCommands.empty() )
+ executeCommand( aCommands );
+ Start();
+ }
+ else
+ Stop();
+}
+
+void Receiver::executeCommand( const std::vector<OString> &aCommand )
+{
+ uno::Reference<presentation::XSlideShowController> xSlideShowController;
+ uno::Reference<presentation::XPresentation2> xPresentation;
+ uno::Reference<presentation::XSlideShow> xSlideShow;
+ try {
+ uno::Reference< frame::XDesktop2 > xFramesSupplier = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
+ uno::Reference< frame::XFrame > xFrame ( xFramesSupplier->getActiveFrame(), uno::UNO_SET_THROW );
+ uno::Reference<presentation::XPresentationSupplier> xPS ( xFrame->getController()->getModel(), uno::UNO_QUERY_THROW);
+ xPresentation.set( xPS->getPresentation(), uno::UNO_QUERY_THROW);
+ // Throws an exception if no slideshow running
+ xSlideShowController.set( xPresentation->getController(), uno::UNO_SET_THROW );
+ xSlideShow.set( xSlideShowController->getSlideShow(), uno::UNO_SET_THROW );
+ }
+ catch (uno::RuntimeException &)
+ {
+ }
+
+ if ( aCommand[0] == "transition_next" )
+ {
+ if ( xSlideShowController.is() )
+ xSlideShowController->gotoNextEffect();
+ }
+ else if ( aCommand[0] == "transition_previous" )
+ {
+ if ( xSlideShowController.is() )
+ xSlideShowController->gotoPreviousEffect();
+ }
+ else if ( aCommand[0] == "goto_slide" )
+ {
+ // FIXME: if 0 returned, then not a valid number
+ sal_Int32 aSlide = aCommand[1].toInt32();
+ if ( xSlideShowController.is() &&
+ xSlideShowController->getCurrentSlideIndex() != aSlide )
+ {
+ xSlideShowController->gotoSlideIndex( aSlide );
+ }
+ }
+ else if ( aCommand[0] == "presentation_start" )
+ {
+ if ( xPresentation.is() )
+ xPresentation->start();
+ }
+ else if ( aCommand[0] == "presentation_stop" )
+ {
+ if ( xPresentation.is() )
+ xPresentation->end();
+ }
+ else if ( aCommand[0] == "presentation_blank_screen" )
+ {
+ if ( aCommand.size() > 1 )
+ {
+// aColour = FIXME: get the colour in some format from this string
+// Determine the formatting first.
+ }
+ if ( xSlideShowController.is() )
+ {
+ xSlideShowController->blankScreen( 0 ); // Default is black
+ }
+ }
+ else if (aCommand[0] == "pointer_started" )
+ {
+ // std::cerr << "pointer_started" << std::endl;
+ float x = aCommand[1].toFloat();
+ float y = aCommand[2].toFloat();
+ SolarMutexGuard aSolarGuard;
+
+ const css::geometry::RealPoint2D pos(x,y);
+ // std::cerr << "Pointer at ("<<pos.X<<","<<pos.Y<<")" << std::endl;
+
+ if (xSlideShow.is())
+ {
+ try
+ {
+ // std::cerr << "pointer_coordination in the is" << std::endl;
+ xSlideShow->setProperty(beans::PropertyValue("PointerPosition", -1, Any(pos),
+ beans::PropertyState_DIRECT_VALUE));
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sdremote", "sd::SlideShowImpl::setPointerPosition()");
+ }
+
+ try
+ {
+ xSlideShow->setProperty(beans::PropertyValue("PointerVisible", -1, Any(true),
+ beans::PropertyState_DIRECT_VALUE));
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sdremote", "sd::SlideShowImpl::setPointerMode()");
+ }
+ }
+
+ SAL_INFO( "sdremote", "Pointer started, we display the pointer on screen" );
+ }
+ else if (aCommand[0] == "pointer_dismissed" )
+ {
+ SolarMutexGuard aSolarGuard;
+ if (xSlideShow.is()) try
+ {
+ xSlideShow->setProperty(
+ beans::PropertyValue( "PointerVisible" ,
+ -1,
+ Any( false ),
+ beans::PropertyState_DIRECT_VALUE ) );
+ }
+ catch ( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sdremote", "sd::SlideShowImpl::setPointerMode()" );
+ }
+
+ SAL_INFO( "sdremote", "Pointer dismissed, we hide the pointer on screen" );
+ }
+ else if (aCommand[0] == "pointer_coordination" )
+ {
+ float x = aCommand[1].toFloat();
+ float y = aCommand[2].toFloat();
+
+ SAL_INFO( "sdremote", "Pointer at ("<<x<<","<<y<<")" );
+ const css::geometry::RealPoint2D pos(x,y);
+
+ SolarMutexGuard aSolarGuard;
+ if (xSlideShow.is()) try
+ {
+ xSlideShow->setProperty(
+ beans::PropertyValue( "PointerPosition" ,
+ -1,
+ Any( pos ),
+ beans::PropertyState_DIRECT_VALUE ) );
+ }
+ catch ( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sdremote", "sd::SlideShowImpl::setPointerPosition()" );
+ }
+ }
+ else if ( aCommand[0] == "presentation_resume" )
+ {
+ if ( xSlideShowController.is() )
+ {
+ xSlideShowController->resume();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/Receiver.hxx b/sd/source/ui/remotecontrol/Receiver.hxx
new file mode 100644
index 000000000..d3fadf0da
--- /dev/null
+++ b/sd/source/ui/remotecontrol/Receiver.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <rtl/string.hxx>
+#include <vcl/timer.hxx>
+
+#include <vector>
+#include <deque>
+
+namespace sd { class Transmitter; }
+
+namespace sd
+{
+
+// Timer is protected by the solar mutex => so are we.
+class Receiver : private Timer
+{
+ std::deque< std::vector< OString > > maExecQueue;
+public:
+ explicit Receiver( Transmitter *aTransmitter );
+ virtual ~Receiver() override;
+ virtual void Invoke() override;
+ void pushCommand( const std::vector<OString> &rCommand );
+ static void executeCommand( const std::vector<OString> &aCommand );
+
+private:
+ Transmitter *pTransmitter;
+};
+
+}
diff --git a/sd/source/ui/remotecontrol/Server.cxx b/sd/source/ui/remotecontrol/Server.cxx
new file mode 100644
index 000000000..53bf0352c
--- /dev/null
+++ b/sd/source/ui/remotecontrol/Server.cxx
@@ -0,0 +1,373 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <algorithm>
+#include <vector>
+
+#include <officecfg/Office/Impress.hxx>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/configuration.hxx>
+#include <comphelper/sequence.hxx>
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/socket.hxx>
+
+#include <sddll.hxx>
+
+#include "DiscoveryService.hxx"
+#include "Listener.hxx"
+#include <RemoteServer.hxx>
+#include "BluetoothServer.hxx"
+#include "Communicator.hxx"
+#include "BufferedStreamSocket.hxx"
+
+using namespace sd;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::osl;
+using namespace ::comphelper;
+
+namespace sd {
+ /**
+ * Used to keep track of clients that have attempted to connect, but haven't
+ * yet been approved.
+ */
+ struct ClientInfoInternal:
+ ClientInfo
+ {
+ BufferedStreamSocket *mpStreamSocket;
+ OUString mPin;
+
+ ClientInfoInternal( const OUString& rName,
+ BufferedStreamSocket *pSocket,
+ const OUString& rPin ):
+ ClientInfo( rName, false ),
+ mpStreamSocket( pSocket ),
+ mPin( rPin ) {}
+ };
+}
+
+RemoteServer::RemoteServer() :
+ Thread( "RemoteServerThread" )
+{
+ SAL_INFO( "sdremote", "Instantiated RemoteServer" );
+}
+
+RemoteServer::~RemoteServer()
+{
+}
+
+void RemoteServer::execute()
+{
+ SAL_INFO( "sdremote", "RemoteServer::execute called" );
+ osl::SocketAddr aAddr( "0.0.0.0", PORT );
+ if ( !mSocket.bind( aAddr ) )
+ {
+ SAL_WARN( "sdremote", "bind failed" << mSocket.getErrorAsString() );
+ spServer = nullptr;
+ return;
+ }
+
+ if ( !mSocket.listen(3) )
+ {
+ SAL_WARN( "sdremote", "listen failed" << mSocket.getErrorAsString() );
+ spServer = nullptr;
+ return;
+ }
+ while ( true )
+ {
+ StreamSocket aSocket;
+ SAL_INFO( "sdremote", "waiting on accept" );
+ if ( mSocket.acceptConnection( aSocket ) == osl_Socket_Error )
+ {
+ SAL_WARN( "sdremote", "accept failed" << mSocket.getErrorAsString() );
+ spServer = nullptr;
+ return; // Closed, or other issue.
+ }
+ BufferedStreamSocket *pSocket = new BufferedStreamSocket( aSocket);
+ handleAcceptedConnection( pSocket );
+ }
+ SAL_INFO( "sdremote", "shutting down RemoteServer" );
+ spServer = nullptr; // Object is destroyed when Thread::execute() ends.
+}
+
+void RemoteServer::handleAcceptedConnection( BufferedStreamSocket *pSocket )
+{
+ OString aLine;
+ if ( ! ( pSocket->readLine( aLine)
+ && aLine == "LO_SERVER_CLIENT_PAIR"
+ && pSocket->readLine( aLine ) ) )
+ {
+ SAL_INFO( "sdremote", "client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
+ delete pSocket;
+ return;
+ }
+
+ OString aName( aLine );
+
+ if ( ! pSocket->readLine( aLine ) )
+ {
+ delete pSocket;
+ return;
+ }
+ OString aPin( aLine );
+
+ SocketAddr aClientAddr;
+ pSocket->getPeerAddr( aClientAddr );
+
+ do
+ {
+ // Read off any additional non-empty lines
+ // We know that we at least have the empty termination line to read.
+ if ( ! pSocket->readLine( aLine ) ) {
+ delete pSocket;
+ return;
+ }
+ }
+ while ( aLine.getLength() > 0 );
+
+ MutexGuard aGuard( sDataMutex );
+ std::shared_ptr< ClientInfoInternal > pClient =
+ std::make_shared<ClientInfoInternal>(
+ OStringToOUString( aName, RTL_TEXTENCODING_UTF8 ),
+ pSocket, OStringToOUString( aPin, RTL_TEXTENCODING_UTF8 ) );
+ mAvailableClients.push_back( pClient );
+
+ // Check if we already have this server.
+ Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
+ const Sequence< OUString > aNames = xConfig->getElementNames();
+ for ( const auto& rName : aNames )
+ {
+ if ( rName == pClient->mName )
+ {
+ Reference<XNameAccess> xSetItem( xConfig->getByName(rName), UNO_QUERY );
+ Any axPin(xSetItem->getByName("PIN"));
+ OUString sPin;
+ axPin >>= sPin;
+
+ if ( sPin == pClient->mPin ) {
+ SAL_INFO( "sdremote", "client found on validated list -- connecting" );
+ connectClient( pClient, sPin );
+ return;
+ }
+ }
+ }
+
+ // Pin not found so inform the client.
+ SAL_INFO( "sdremote", "client not found on validated list" );
+ pSocket->write( "LO_SERVER_VALIDATING_PIN\n\n",
+ strlen( "LO_SERVER_VALIDATING_PIN\n\n" ) );
+}
+
+RemoteServer *sd::RemoteServer::spServer = nullptr;
+::osl::Mutex sd::RemoteServer::sDataMutex;
+::std::vector<Communicator*> sd::RemoteServer::sCommunicators;
+
+void RemoteServer::setup()
+{
+ if (spServer)
+ return;
+
+ spServer = new RemoteServer();
+ spServer->launch();
+
+#ifdef ENABLE_SDREMOTE_BLUETOOTH
+ sd::BluetoothServer::setup( &sCommunicators );
+#endif
+}
+
+void RemoteServer::presentationStarted( const css::uno::Reference<
+ css::presentation::XSlideShowController > &rController )
+{
+ if ( !spServer )
+ return;
+ MutexGuard aGuard( sDataMutex );
+ for ( const auto& rpCommunicator : sCommunicators )
+ {
+ rpCommunicator->presentationStarted( rController );
+ }
+}
+void RemoteServer::presentationStopped()
+{
+ if ( !spServer )
+ return;
+ MutexGuard aGuard( sDataMutex );
+ for ( const auto& rpCommunicator : sCommunicators )
+ {
+ rpCommunicator->disposeListener();
+ }
+}
+
+void RemoteServer::removeCommunicator( Communicator const * mCommunicator )
+{
+ if ( !spServer )
+ return;
+ MutexGuard aGuard( sDataMutex );
+ auto aIt = std::find(sCommunicators.begin(), sCommunicators.end(), mCommunicator);
+ if (aIt != sCommunicators.end())
+ sCommunicators.erase( aIt );
+}
+
+std::vector< std::shared_ptr< ClientInfo > > RemoteServer::getClients()
+{
+ SAL_INFO( "sdremote", "RemoteServer::getClients() called" );
+ std::vector< std::shared_ptr< ClientInfo > > aClients;
+ if ( spServer )
+ {
+ MutexGuard aGuard( sDataMutex );
+ aClients.assign( spServer->mAvailableClients.begin(),
+ spServer->mAvailableClients.end() );
+ }
+ else
+ {
+ SAL_INFO( "sdremote", "No remote server instance => no remote clients" );
+ }
+ // We also need to provide authorised clients (no matter whether or not
+ // they are actually available), so that they can be de-authorised if
+ // necessary. We specifically want these to be at the end of the list
+ // since the user is more likely to be trying to connect a new remote
+ // than removing an existing remote.
+ // We can also be sure that pre-authorised clients will not be on the
+ // available clients list, as they get automatically connected if seen.
+ // TODO: we should probably add some sort of extra labelling to mark
+ // authorised AND connected client.
+ Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
+ const Sequence< OUString > aNames = xConfig->getElementNames();
+ std::transform(aNames.begin(), aNames.end(), std::back_inserter(aClients),
+ [](const OUString& rName) -> std::shared_ptr<ClientInfo> {
+ return std::make_shared<ClientInfo>(rName, true); });
+
+ return aClients;
+}
+
+bool RemoteServer::connectClient( const std::shared_ptr< ClientInfo >& pClient, std::u16string_view aPin )
+{
+ SAL_INFO( "sdremote", "RemoteServer::connectClient called" );
+ if ( !spServer )
+ return false;
+
+ ClientInfoInternal* apClient = dynamic_cast< ClientInfoInternal* >( pClient.get() );
+ if ( !apClient )
+ // could happen if we try to "connect" an already authorised client
+ {
+ return false;
+ }
+
+ if ( apClient->mPin == aPin )
+ {
+ // Save in settings first
+ std::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
+ Reference< XNameContainer > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );
+
+ Reference<XSingleServiceFactory> xChildFactory (
+ xConfig, UNO_QUERY);
+ Reference<XNameReplace> xChild( xChildFactory->createInstance(), UNO_QUERY);
+ Any aValue;
+ if (xChild.is())
+ {
+ // Check whether the client is already saved
+ Sequence< OUString > aNames = xConfig->getElementNames();
+ if (comphelper::findValue(aNames, apClient->mName) != -1)
+ xConfig->replaceByName( apClient->mName, Any( xChild ) );
+ else
+ xConfig->insertByName( apClient->mName, Any( xChild ) );
+ aValue <<= apClient->mPin;
+ xChild->replaceByName("PIN", aValue);
+ aChanges->commit();
+ }
+
+ Communicator* pCommunicator = new Communicator( std::unique_ptr<IBluetoothSocket>(apClient->mpStreamSocket) );
+ MutexGuard aGuard( sDataMutex );
+
+ sCommunicators.push_back( pCommunicator );
+
+ auto aIt = std::find(spServer->mAvailableClients.begin(), spServer->mAvailableClients.end(), pClient);
+ if (aIt != spServer->mAvailableClients.end())
+ spServer->mAvailableClients.erase( aIt );
+ pCommunicator->launch();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void RemoteServer::deauthoriseClient( const std::shared_ptr< ClientInfo >& pClient )
+{
+ // TODO: we probably want to forcefully disconnect at this point too?
+ // But possibly via a separate function to allow just disconnecting from
+ // the UI.
+
+ SAL_INFO( "sdremote", "RemoteServer::deauthoriseClient called" );
+
+ if ( !pClient->mbIsAlreadyAuthorised )
+ // We can't remove unauthorised clients from the authorised list...
+ {
+ return;
+ }
+
+ std::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
+ Reference< XNameContainer > const xConfig =
+ officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );
+
+ xConfig->removeByName( pClient->mName );
+ aChanges->commit();
+}
+
+void SdDLL::RegisterRemotes()
+{
+ SAL_INFO( "sdremote", "SdDLL::RegisterRemotes called" );
+
+ // The remote server is likely of no use in headless mode. And as only
+ // one instance of the server can actually own the appropriate ports its
+ // probably best to not even try to do so from our headless instance
+ // (i.e. as to avoid blocking expected usage).
+ // It could perhaps be argued that we would still need the remote
+ // server for tiled rendering of presentations, but even then this
+ // implementation would not be of much use, i.e. would be controlling
+ // the purely imaginary headless presentation -- instead we'd need
+ // to have some sort of mechanism of plugging in our tiled rendering
+ // client to be controlled by the remote server, or provide an
+ // alternative implementation.
+ if ( Application::IsHeadlessModeEnabled() )
+ return;
+
+ if ( !officecfg::Office::Impress::Misc::Start::EnableSdremote::get() )
+ return;
+
+ sd::RemoteServer::setup();
+ sd::DiscoveryService::setup();
+}
+
+void RemoteServer::ensureDiscoverable()
+{
+ // FIXME: we could also enable listening on our WiFi
+ // socket here to significantly reduce the attack surface.
+#ifdef ENABLE_SDREMOTE_BLUETOOTH
+ BluetoothServer::ensureDiscoverable();
+#endif
+}
+
+void RemoteServer::restoreDiscoverable()
+{
+#ifdef ENABLE_SDREMOTE_BLUETOOTH
+ BluetoothServer::restoreDiscoverable();
+#endif
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/Transmitter.cxx b/sd/source/ui/remotecontrol/Transmitter.cxx
new file mode 100644
index 000000000..cca6a3bee
--- /dev/null
+++ b/sd/source/ui/remotecontrol/Transmitter.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include "Transmitter.hxx"
+#include "IBluetoothSocket.hxx"
+#include <sal/log.hxx>
+
+using namespace osl; // Sockets etc.
+using namespace sd;
+
+Transmitter::Transmitter( IBluetoothSocket* aSocket )
+ : pStreamSocket( aSocket ),
+ mFinishRequested( false )
+{
+}
+
+void SAL_CALL Transmitter::run()
+{
+ osl_setThreadName("bluetooth Transmitter");
+
+ while ( true )
+ {
+ mProcessingRequired.wait();
+
+ ::osl::MutexGuard aGuard( mMutex );
+
+ if ( mFinishRequested ) {
+ return;
+ }
+ if ( !mHighPriority.empty() )
+ {
+ OString aMessage( mHighPriority.front() );
+ mHighPriority.pop();
+ SAL_INFO( "sdremote.bluetooth", "write high prio line '" << aMessage << "'" );
+ pStreamSocket->write( aMessage.getStr(), aMessage.getLength() );
+ }
+ else if ( !mLowPriority.empty() )
+ {
+ OString aMessage( mLowPriority.front() );
+ mLowPriority.pop();
+ SAL_INFO( "sdremote.bluetooth", "write normal line '" << aMessage << "'" );
+ pStreamSocket->write( aMessage.getStr(), aMessage.getLength() );
+ }
+
+ if ( mLowPriority.empty() && mHighPriority.empty())
+ {
+ mProcessingRequired.reset();
+ }
+ }
+}
+
+void Transmitter::notifyFinished()
+{
+ ::osl::MutexGuard aGuard( mMutex );
+ mFinishRequested = true;
+ mProcessingRequired.set();
+}
+
+Transmitter::~Transmitter()
+{
+}
+
+void Transmitter::addMessage( const OString& aMessage, const Priority aPriority )
+{
+ ::osl::MutexGuard aGuard( mMutex );
+ switch ( aPriority )
+ {
+ case PRIORITY_LOW:
+ mLowPriority.push( aMessage );
+ break;
+ case PRIORITY_HIGH:
+ mHighPriority.push( aMessage );
+ break;
+ }
+ if ( !mProcessingRequired.check() )
+ {
+ mProcessingRequired.set();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/Transmitter.hxx b/sd/source/ui/remotecontrol/Transmitter.hxx
new file mode 100644
index 000000000..c24f5a5a4
--- /dev/null
+++ b/sd/source/ui/remotecontrol/Transmitter.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <osl/conditn.hxx>
+#include <osl/mutex.hxx>
+#include <osl/thread.hxx>
+#include <rtl/string.hxx>
+
+#include <queue>
+
+namespace sd { struct IBluetoothSocket; }
+
+namespace sd
+{
+
+class Transmitter
+: public osl::Thread
+{
+public:
+ enum Priority { PRIORITY_LOW = 1, PRIORITY_HIGH };
+ explicit Transmitter( ::sd::IBluetoothSocket* aSocket );
+ virtual ~Transmitter() override;
+ void addMessage( const OString& aMessage, const Priority aPriority );
+ void notifyFinished();
+
+private:
+ virtual void SAL_CALL run() override;
+
+ ::sd::IBluetoothSocket* pStreamSocket;
+
+ ::osl::Condition mProcessingRequired;
+
+ ::osl::Mutex mMutex;
+ /**
+ * Used to indicate that we're done and the transmitter loop should exit.
+ * All access must be guarded my `mMutex`.
+ */
+ bool mFinishRequested;
+ /// Queue for low priority messages. All access must be guarded my `mMutex`.
+ std::queue<OString> mLowPriority;
+ /// Queue for high priority messages. All access must be guarded my `mMutex`.
+ std::queue<OString> mHighPriority;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/remotecontrol/WINNetworkService.cxx b/sd/source/ui/remotecontrol/WINNetworkService.cxx
new file mode 100644
index 000000000..bd2decf62
--- /dev/null
+++ b/sd/source/ui/remotecontrol/WINNetworkService.cxx
@@ -0,0 +1,19 @@
+#include <string>
+#include <iostream>
+#include "WINNetworkService.hxx"
+#include <sal/log.hxx>
+
+void sd::WINNetworkService::setup()
+{
+ DNSServiceErrorType err = DNSServiceRegister(&client, 0, 0, nullptr, kREG_TYPE, "local", nullptr, 1599, 1, "", nullptr, this );
+
+ if (kDNSServiceErr_NoError != err)
+ SAL_WARN("sdremote.wifi", "DNSServiceRegister failed: " << err);
+
+ // Fail silently
+}
+
+void sd::WINNetworkService::clear()
+{
+ DNSServiceRefDeallocate(client);
+}
diff --git a/sd/source/ui/remotecontrol/WINNetworkService.hxx b/sd/source/ui/remotecontrol/WINNetworkService.hxx
new file mode 100644
index 000000000..3d096dc0f
--- /dev/null
+++ b/sd/source/ui/remotecontrol/WINNetworkService.hxx
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <string>
+#undef WB_LEFT
+#undef WB_RIGHT
+#include <dns_sd.h>
+#include "ZeroconfService.hxx"
+
+namespace sd{
+ class WINNetworkService : public ZeroconfService
+ {
+ private:
+ DNSServiceRef client;
+
+ public:
+ WINNetworkService(const std::string& aname = "", unsigned int aport = 1599)
+ : ZeroconfService(aname, aport), client(nullptr) {}
+
+ void clear() override;
+ void setup() override;
+
+ };
+}
diff --git a/sd/source/ui/remotecontrol/ZeroconfService.hxx b/sd/source/ui/remotecontrol/ZeroconfService.hxx
new file mode 100644
index 000000000..a595d0b58
--- /dev/null
+++ b/sd/source/ui/remotecontrol/ZeroconfService.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#ifndef ZEROCONF_SERVICE
+#define ZEROCONF_SERVICE
+
+#include <string>
+
+/**
+* The port used by LO's custom remote server discovery protocol.
+*/
+#define PORT_DISCOVERY 1598
+#define BUFFER_SIZE 200
+
+#define kREG_TYPE "_impressremote._tcp"
+
+struct sockaddr_in;
+
+typedef unsigned int uint;
+
+namespace sd{
+
+ class ZeroconfService
+ {
+ protected:
+ std::string name;
+ uint port;
+
+ public:
+ explicit ZeroconfService(const std::string& aname, uint aport)
+ :name(aname), port(aport){}
+ virtual ~ZeroconfService(){}
+
+ const std::string& getName() const {return name;}
+ void setName(const char * n) {name = n;}
+
+ // Clean up the service when closing
+ virtual void clear() = 0;
+ // Bonjour for OSX, Avahi for Linux
+ virtual void setup() = 0;
+ };
+
+}
+#endif
diff --git a/sd/source/ui/sidebar/AllMasterPagesSelector.cxx b/sd/source/ui/sidebar/AllMasterPagesSelector.cxx
new file mode 100644
index 000000000..76e056120
--- /dev/null
+++ b/sd/source/ui/sidebar/AllMasterPagesSelector.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 "AllMasterPagesSelector.hxx"
+#include <ViewShellBase.hxx>
+#include "MasterPageContainer.hxx"
+#include "MasterPageDescriptor.hxx"
+#include <helpids.h>
+
+#include <set>
+
+namespace {
+
+using namespace sd::sidebar;
+
+int GetURLPriority (const SharedMasterPageDescriptor& rpDescriptor)
+{
+ int nPriority (0);
+ switch (rpDescriptor->GetURLClassification())
+ {
+ case MasterPageDescriptor::URLCLASS_USER: nPriority = 0; break;
+ case MasterPageDescriptor::URLCLASS_LAYOUT: nPriority = 1; break;
+ case MasterPageDescriptor::URLCLASS_PRESENTATION: nPriority = 2; break;
+ case MasterPageDescriptor::URLCLASS_OTHER: nPriority = 3; break;
+ case MasterPageDescriptor::URLCLASS_UNKNOWN: nPriority = 4; break;
+ default:
+ case MasterPageDescriptor::URLCLASS_UNDETERMINED: nPriority = 5; break;
+ }
+ return nPriority;
+}
+
+class MasterPageDescriptorOrder
+{
+public:
+ bool operator() (
+ const SharedMasterPageDescriptor& rp1,
+ const SharedMasterPageDescriptor& rp2) const
+ {
+ if (rp1->meOrigin == MasterPageContainer::DEFAULT)
+ return true;
+ else if (rp2->meOrigin == MasterPageContainer::DEFAULT)
+ return false;
+ else if (rp1->GetURLClassification() == rp2->GetURLClassification())
+ return rp1->mnTemplateIndex < rp2->mnTemplateIndex;
+ else
+ return GetURLPriority(rp1) < GetURLPriority(rp2);
+ }
+};
+
+} // end of anonymous namespace
+
+namespace sd::sidebar {
+
+class AllMasterPagesSelector::SortedMasterPageDescriptorList
+ : public ::std::set<SharedMasterPageDescriptor,MasterPageDescriptorOrder>
+{
+public:
+ SortedMasterPageDescriptorList() {}
+};
+
+std::unique_ptr<PanelLayout> AllMasterPagesSelector::Create (
+ weld::Widget* pParent,
+ ViewShellBase& rViewShellBase,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+{
+ SdDrawDocument* pDocument = rViewShellBase.GetDocument();
+ if (pDocument == nullptr)
+ return nullptr;
+
+ auto pContainer = std::make_shared<MasterPageContainer>();
+
+ auto xSelector(std::make_unique<AllMasterPagesSelector>(
+ pParent,
+ *pDocument,
+ rViewShellBase,
+ pContainer,
+ rxSidebar));
+ xSelector->LateInit();
+ xSelector->SetHelpId(HID_SD_TASK_PANE_PREVIEW_ALL);
+
+ return xSelector;
+}
+
+AllMasterPagesSelector::AllMasterPagesSelector (
+ weld::Widget* pParent,
+ SdDrawDocument& rDocument,
+ ViewShellBase& rBase,
+ const std::shared_ptr<MasterPageContainer>& rpContainer,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+ : MasterPagesSelector(pParent, rDocument, rBase, rpContainer, rxSidebar, "modules/simpress/ui/masterpagepanelall.ui", "allvalueset"),
+ mpSortedMasterPages(new SortedMasterPageDescriptorList())
+{
+ MasterPagesSelector::Fill();
+}
+
+AllMasterPagesSelector::~AllMasterPagesSelector()
+{
+}
+
+void AllMasterPagesSelector::Fill (ItemList& rItemList)
+{
+ if (mpSortedMasterPages->empty())
+ UpdateMasterPageList();
+ UpdatePageSet(rItemList);
+}
+
+void AllMasterPagesSelector::NotifyContainerChangeEvent (
+ const MasterPageContainerChangeEvent& rEvent)
+{
+ switch (rEvent.meEventType)
+ {
+ case MasterPageContainerChangeEvent::EventType::CHILD_ADDED:
+ AddItem(rEvent.maChildToken);
+ MasterPagesSelector::Fill();
+ break;
+
+ case MasterPageContainerChangeEvent::EventType::INDEX_CHANGED:
+ mpSortedMasterPages->clear();
+ MasterPagesSelector::Fill();
+ break;
+
+ default:
+ MasterPagesSelector::NotifyContainerChangeEvent(rEvent);
+ break;
+ }
+}
+
+void AllMasterPagesSelector::UpdateMasterPageList()
+{
+ mpSortedMasterPages->clear();
+ int nTokenCount = mpContainer->GetTokenCount();
+ for (int i=0; i<nTokenCount; i++)
+ AddItem(mpContainer->GetTokenForIndex(i));
+}
+
+void AllMasterPagesSelector::AddItem (MasterPageContainer::Token aToken)
+{
+ switch (mpContainer->GetOriginForToken(aToken))
+ {
+ case MasterPageContainer::DEFAULT:
+ case MasterPageContainer::TEMPLATE:
+ // Templates are added only when coming from the
+ // MasterPageContainerFiller so that they have an id which
+ // defines their place in the list. Templates (pre) loaded from
+ // RecentlyUsedMasterPages are ignored (they will be loaded
+ // later by the MasterPageContainerFiller.)
+ if (mpContainer->GetTemplateIndexForToken(aToken) >= 0)
+ mpSortedMasterPages->insert(mpContainer->GetDescriptorForToken(aToken));
+ break;
+
+ default:
+ break;
+ }
+}
+
+void AllMasterPagesSelector::UpdatePageSet (ItemList& rItemList)
+{
+ for (const auto& rxDescriptor : *mpSortedMasterPages)
+ rItemList.push_back(rxDescriptor->maToken);
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/AllMasterPagesSelector.hxx b/sd/source/ui/sidebar/AllMasterPagesSelector.hxx
new file mode 100644
index 000000000..982a2ec52
--- /dev/null
+++ b/sd/source/ui/sidebar/AllMasterPagesSelector.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MasterPagesSelector.hxx"
+
+#include <memory>
+
+namespace sd::sidebar {
+
+/** Show a list of all available master pages so that the user can assign
+ them to the document.
+*/
+class AllMasterPagesSelector
+ : public MasterPagesSelector
+{
+ friend class VclPtrInstance<AllMasterPagesSelector>;
+public:
+ static std::unique_ptr<PanelLayout> Create (
+ weld::Widget* pParent,
+ ViewShellBase& rViewShellBase,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+
+ AllMasterPagesSelector (
+ weld::Widget* pParent,
+ SdDrawDocument& rDocument,
+ ViewShellBase& rBase,
+ const std::shared_ptr<MasterPageContainer>& rpContainer,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+ virtual ~AllMasterPagesSelector() override;
+
+
+ /** Scan the set of templates for the ones whose first master pages are
+ shown by this control and store them in the MasterPageContainer.
+ */
+ virtual void Fill (ItemList& rItemList) override;
+
+protected:
+ virtual void NotifyContainerChangeEvent (const MasterPageContainerChangeEvent& rEvent) override;
+
+private:
+ /** The list of master pages displayed by this class.
+ */
+ class SortedMasterPageDescriptorList;
+ ::std::unique_ptr<SortedMasterPageDescriptorList> mpSortedMasterPages;
+
+ void AddItem (MasterPageContainer::Token aToken);
+
+ /** Add all items in the internal master page list into the given list.
+ */
+ void UpdatePageSet (ItemList& rItemList);
+
+ /** Update the internal list of master pages that are to show in the
+ control.
+ */
+ void UpdateMasterPageList();
+
+ using MasterPagesSelector::Fill;
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/CurrentMasterPagesSelector.cxx b/sd/source/ui/sidebar/CurrentMasterPagesSelector.cxx
new file mode 100644
index 000000000..269099edd
--- /dev/null
+++ b/sd/source/ui/sidebar/CurrentMasterPagesSelector.cxx
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "CurrentMasterPagesSelector.hxx"
+#include "PreviewValueSet.hxx"
+#include <ViewShellBase.hxx>
+#include <DrawViewShell.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include "MasterPageContainer.hxx"
+#include "MasterPageContainerProviders.hxx"
+#include "MasterPageDescriptor.hxx"
+#include <EventMultiplexer.hxx>
+#include <DrawDocShell.hxx>
+#include <osl/diagnose.h>
+
+#include <helpids.h>
+
+#include <set>
+
+using namespace ::com::sun::star;
+
+namespace sd::sidebar {
+
+std::unique_ptr<PanelLayout> CurrentMasterPagesSelector::Create (
+ weld::Widget* pParent,
+ ViewShellBase& rViewShellBase,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+{
+ SdDrawDocument* pDocument = rViewShellBase.GetDocument();
+ if (pDocument == nullptr)
+ return nullptr;
+
+ auto pContainer = std::make_shared<MasterPageContainer>();
+
+ auto xSelector(std::make_unique<CurrentMasterPagesSelector>(
+ pParent,
+ *pDocument,
+ rViewShellBase,
+ pContainer,
+ rxSidebar));
+ xSelector->LateInit();
+ xSelector->SetHelpId( HID_SD_TASK_PANE_PREVIEW_CURRENT );
+
+ return xSelector;
+}
+
+CurrentMasterPagesSelector::CurrentMasterPagesSelector (
+ weld::Widget* pParent,
+ SdDrawDocument& rDocument,
+ ViewShellBase& rBase,
+ const std::shared_ptr<MasterPageContainer>& rpContainer,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+ : MasterPagesSelector (pParent, rDocument, rBase, rpContainer, rxSidebar, "modules/simpress/ui/masterpagepanel.ui", "usedvalueset")
+{
+ Link<sd::tools::EventMultiplexerEvent&,void> aLink (LINK(this,CurrentMasterPagesSelector,EventMultiplexerListener));
+ rBase.GetEventMultiplexer()->AddEventListener(aLink);
+}
+
+CurrentMasterPagesSelector::~CurrentMasterPagesSelector()
+{
+ if (mrDocument.GetDocSh() != nullptr)
+ {
+ EndListening(*mrDocument.GetDocSh());
+ }
+ else
+ {
+ OSL_ASSERT(mrDocument.GetDocSh() != nullptr);
+ }
+
+ Link<sd::tools::EventMultiplexerEvent&,void> aLink (LINK(this,CurrentMasterPagesSelector,EventMultiplexerListener));
+ mrBase.GetEventMultiplexer()->RemoveEventListener(aLink);
+}
+
+void CurrentMasterPagesSelector::LateInit()
+{
+ MasterPagesSelector::LateInit();
+ MasterPagesSelector::Fill();
+ if (mrDocument.GetDocSh() != nullptr)
+ {
+ StartListening(*mrDocument.GetDocSh());
+ }
+ else
+ {
+ OSL_ASSERT(mrDocument.GetDocSh() != nullptr);
+ }
+}
+
+void CurrentMasterPagesSelector::Fill (ItemList& rItemList)
+{
+ sal_uInt16 nPageCount = mrDocument.GetMasterSdPageCount(PageKind::Standard);
+ // Remember the names of the master pages that have been inserted to
+ // avoid double insertion.
+ ::std::set<OUString> aMasterPageNames;
+ for (sal_uInt16 nIndex=0; nIndex<nPageCount; nIndex++)
+ {
+ SdPage* pMasterPage = mrDocument.GetMasterSdPage (nIndex, PageKind::Standard);
+ if (pMasterPage == nullptr)
+ continue;
+
+ // Use the name of the master page to avoid duplicate entries.
+ OUString sName (pMasterPage->GetName());
+ if (!aMasterPageNames.insert(sName).second)
+ continue;
+
+ // Look up the master page in the container and, when it is not yet
+ // in it, insert it.
+ MasterPageContainer::Token aToken = mpContainer->GetTokenForPageObject(pMasterPage);
+ if (aToken == MasterPageContainer::NIL_TOKEN)
+ {
+ SharedMasterPageDescriptor pDescriptor = std::make_shared<MasterPageDescriptor>(
+ MasterPageContainer::MASTERPAGE,
+ nIndex,
+ OUString(),
+ pMasterPage->GetName(),
+ OUString(),
+ pMasterPage->IsPrecious(),
+ std::make_shared<ExistingPageProvider>(pMasterPage),
+ std::make_shared<PagePreviewProvider>());
+ aToken = mpContainer->PutMasterPage(pDescriptor);
+ }
+
+ rItemList.push_back(aToken);
+ }
+}
+
+OUString CurrentMasterPagesSelector::GetContextMenuUIFile() const
+{
+ return "modules/simpress/ui/currentmastermenu.ui";
+}
+
+void CurrentMasterPagesSelector::UpdateSelection()
+{
+ // Iterate over all pages and for the selected ones put the name of
+ // their master page into a set.
+ sal_uInt16 nPageCount = mrDocument.GetSdPageCount(PageKind::Standard);
+ ::std::set<OUString> aNames;
+ sal_uInt16 nIndex;
+ bool bLoop (true);
+ for (nIndex=0; nIndex<nPageCount && bLoop; nIndex++)
+ {
+ SdPage* pPage = mrDocument.GetSdPage (nIndex, PageKind::Standard);
+ if (pPage != nullptr && pPage->IsSelected())
+ {
+ if ( ! pPage->TRG_HasMasterPage())
+ {
+ // One of the pages has no master page. This is an
+ // indicator for that this method is called in the middle of
+ // a document change and that the model is not in a valid
+ // state. Therefore we stop update the selection and wait
+ // for another call to UpdateSelection when the model is
+ // valid again.
+ bLoop = false;
+ }
+ else
+ {
+ SdrPage& rMasterPage (pPage->TRG_GetMasterPage());
+ assert(dynamic_cast<SdPage*>(&rMasterPage));
+ aNames.insert(static_cast<SdPage&>(rMasterPage).GetName());
+ }
+ }
+ }
+
+ // Find the items for the master pages in the set.
+ sal_uInt16 nItemCount (mxPreviewValueSet->GetItemCount());
+ for (nIndex=1; nIndex<=nItemCount && bLoop; nIndex++)
+ {
+ OUString sName (mxPreviewValueSet->GetItemText (nIndex));
+ if (aNames.find(sName) != aNames.end())
+ {
+ mxPreviewValueSet->SelectItem (nIndex);
+ }
+ }
+}
+
+void CurrentMasterPagesSelector::ExecuteCommand(const OString &rIdent)
+{
+ if (rIdent == "delete")
+ {
+ // Check once again that the master page can safely be deleted,
+ // i.e. is not used.
+ SdPage* pMasterPage = GetSelectedMasterPage();
+ if (pMasterPage != nullptr
+ && mrDocument.GetMasterPageUserCount(pMasterPage) == 0)
+ {
+ // Removing the precious flag so that the following call to
+ // RemoveUnnecessaryMasterPages() will remove this master page.
+ pMasterPage->SetPrecious(false);
+ mrDocument.RemoveUnnecessaryMasterPages(pMasterPage);
+ }
+ }
+ else
+ MasterPagesSelector::ExecuteCommand(rIdent);
+}
+
+void CurrentMasterPagesSelector::ProcessPopupMenu(weld::Menu& rMenu)
+{
+ // Disable the delete entry when there is only one master page.
+ if (mrDocument.GetMasterPageUserCount(GetSelectedMasterPage()) > 0)
+ rMenu.set_sensitive("delete", false);
+
+ std::shared_ptr<DrawViewShell> pDrawViewShell (
+ std::dynamic_pointer_cast<DrawViewShell>(mrBase.GetMainViewShell()));
+ if (pDrawViewShell && pDrawViewShell->GetEditMode() == EditMode::MasterPage)
+ {
+ rMenu.set_sensitive("edit", false);
+ }
+
+ MasterPagesSelector::ProcessPopupMenu(rMenu);
+}
+
+IMPL_LINK(CurrentMasterPagesSelector,EventMultiplexerListener,
+ sd::tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ case EventMultiplexerEventId::CurrentPageChanged:
+ case EventMultiplexerEventId::EditModeNormal:
+ case EventMultiplexerEventId::EditModeMaster:
+ case EventMultiplexerEventId::SlideSortedSelection:
+ UpdateSelection();
+ break;
+
+ case EventMultiplexerEventId::PageOrder:
+ // This is tricky. If a master page is removed, moved, or
+ // added we have to wait until both the notes master page
+ // and the standard master page have been removed, moved,
+ // or added. We do this by looking at the number of master
+ // pages which has to be odd in the consistent state (the
+ // handout master page is always present). If the number is
+ // even we ignore the hint.
+ if (mrBase.GetDocument()->GetMasterPageCount()%2 == 1)
+ MasterPagesSelector::Fill();
+ break;
+
+ case EventMultiplexerEventId::ShapeChanged:
+ case EventMultiplexerEventId::ShapeInserted:
+ case EventMultiplexerEventId::ShapeRemoved:
+ InvalidatePreview(static_cast<const SdPage*>(rEvent.mpUserData));
+ break;
+ default: break;
+ }
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/CurrentMasterPagesSelector.hxx b/sd/source/ui/sidebar/CurrentMasterPagesSelector.hxx
new file mode 100644
index 000000000..cd7c27734
--- /dev/null
+++ b/sd/source/ui/sidebar/CurrentMasterPagesSelector.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svl/lstner.hxx>
+
+#include "MasterPagesSelector.hxx"
+
+namespace sd::tools { class EventMultiplexerEvent; }
+
+namespace sd::sidebar {
+
+/** Show the master pages currently used by a SdDrawDocument.
+*/
+class CurrentMasterPagesSelector
+ : public MasterPagesSelector,
+ public SfxListener
+{
+ friend class VclPtrInstance<CurrentMasterPagesSelector>;
+public:
+ static std::unique_ptr<PanelLayout> Create (
+ weld::Widget* pParent,
+ ViewShellBase& rViewShellBase,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+
+ CurrentMasterPagesSelector (
+ weld::Widget* pParent,
+ SdDrawDocument& rDocument,
+ ViewShellBase& rBase,
+ const std::shared_ptr<MasterPageContainer>& rpContainer,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+ virtual ~CurrentMasterPagesSelector() override;
+
+ /** Set the selection so that the master page is selected that is
+ used by the currently selected page of the document in the
+ center pane.
+ */
+ void UpdateSelection();
+
+ /** Copy all master pages that are to be shown into the given list.
+ */
+ virtual void Fill (ItemList& rItemList) override;
+
+ using MasterPagesSelector::Fill;
+
+protected:
+ virtual OUString GetContextMenuUIFile() const override;
+
+ virtual void ProcessPopupMenu(weld::Menu& rMenu) override;
+ virtual void ExecuteCommand(const OString &rIdent) override;
+
+private:
+ virtual void LateInit() override;
+
+ DECL_LINK(EventMultiplexerListener,sd::tools::EventMultiplexerEvent&, void);
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/DocumentHelper.cxx b/sd/source/ui/sidebar/DocumentHelper.cxx
new file mode 100644
index 000000000..00c028868
--- /dev/null
+++ b/sd/source/ui/sidebar/DocumentHelper.cxx
@@ -0,0 +1,536 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "DocumentHelper.hxx"
+
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <sdpage.hxx>
+#include <glob.hxx>
+#include <unmovss.hxx>
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <undoback.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPages.hpp>
+#include <stlpool.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/svdundo.hxx>
+#include <tools/diagnose_ex.h>
+#include <xmloff/autolayout.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd::sidebar {
+
+SdPage* DocumentHelper::CopyMasterPageToLocalDocument (
+ SdDrawDocument& rTargetDocument,
+ SdPage* pMasterPage)
+{
+ SdPage* pNewMasterPage = nullptr;
+
+ do
+ {
+ if (pMasterPage == nullptr)
+ break;
+
+ // Check the presence of the source document.
+ SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
+
+ // When the given master page already belongs to the target document
+ // then there is nothing more to do.
+ if (&rSourceDocument == &rTargetDocument)
+ {
+ pNewMasterPage = pMasterPage;
+ break;
+ }
+
+ // Test if the master pages of both the slide and its notes page are
+ // present. This is not the case when we are called during the
+ // creation of the slide master page because then the notes master
+ // page is not there.
+ sal_uInt16 nSourceMasterPageCount = rSourceDocument.GetMasterPageCount();
+ if (nSourceMasterPageCount%2 == 0)
+ // There should be 1 handout page + n slide masters + n notes
+ // masters = 2*n+1. An even value indicates that a new slide
+ // master but not yet the notes master has been inserted.
+ break;
+ sal_uInt16 nIndex = pMasterPage->GetPageNum();
+ if (nSourceMasterPageCount <= nIndex+1)
+ break;
+ // Get the slide master page.
+ if (pMasterPage != static_cast<SdPage*>(
+ rSourceDocument.GetMasterPage(nIndex)))
+ break;
+ // Get the notes master page.
+ SdPage* pNotesMasterPage = static_cast<SdPage*>(
+ rSourceDocument.GetMasterPage(nIndex+1));
+ if (pNotesMasterPage == nullptr)
+ break;
+
+ // Check if a master page with the same name as that of the given
+ // master page already exists.
+ bool bPageExists (false);
+ sal_uInt16 nMasterPageCount(rTargetDocument.GetMasterSdPageCount(PageKind::Standard));
+ for (sal_uInt16 nMaster=0; nMaster<nMasterPageCount; nMaster++)
+ {
+ SdPage* pCandidate = rTargetDocument.GetMasterSdPage (nMaster, PageKind::Standard);
+ if (pCandidate->GetName() == pMasterPage->GetName())
+ {
+ bPageExists = true;
+ pNewMasterPage = pCandidate;
+ break;
+ }
+ }
+ if (bPageExists)
+ break;
+
+ // Create a new slide (and its notes page.)
+ uno::Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
+ rTargetDocument.getUnoModel(), uno::UNO_QUERY);
+ if ( ! xSlideSupplier.is())
+ break;
+ uno::Reference<drawing::XDrawPages> xSlides =
+ xSlideSupplier->getDrawPages();
+ if ( ! xSlides.is())
+ break;
+ xSlides->insertNewByIndex (xSlides->getCount());
+
+ // Set a layout.
+ SdPage* pSlide = rTargetDocument.GetSdPage(
+ rTargetDocument.GetSdPageCount(PageKind::Standard)-1,
+ PageKind::Standard);
+ if (pSlide == nullptr)
+ break;
+ pSlide->SetAutoLayout(AUTOLAYOUT_TITLE, true);
+
+ // Create a copy of the master page and the associated notes
+ // master page and insert them into our document.
+ pNewMasterPage = AddMasterPage(rTargetDocument, pMasterPage);
+ if (pNewMasterPage==nullptr)
+ break;
+ SdPage* pNewNotesMasterPage
+ = AddMasterPage(rTargetDocument, pNotesMasterPage);
+ if (pNewNotesMasterPage==nullptr)
+ break;
+
+ // Make the connection from the new slide to the master page
+ // (and do the same for the notes page.)
+ rTargetDocument.SetMasterPage (
+ rTargetDocument.GetSdPageCount(PageKind::Standard)-1,
+ pNewMasterPage->GetName(),
+ &rTargetDocument,
+ false, // Connect the new master page with the new slide but
+ // do not modify other (master) pages.
+ true);
+ }
+ while (false);
+
+ // We are not interested in any automatisms for our modified internal
+ // document.
+ rTargetDocument.SetChanged(false);
+
+ return pNewMasterPage;
+}
+
+SdPage* DocumentHelper::GetSlideForMasterPage (SdPage const * pMasterPage)
+{
+ SdPage* pCandidate = nullptr;
+
+ SdDrawDocument* pDocument = nullptr;
+ if (pMasterPage != nullptr)
+ pDocument = dynamic_cast< SdDrawDocument* >(&pMasterPage->getSdrModelFromSdrPage());
+
+ // Iterate over all pages and check if it references the given master
+ // page.
+ if (pDocument!=nullptr && pDocument->GetSdPageCount(PageKind::Standard) > 0)
+ {
+ // In most cases a new slide has just been inserted so start with
+ // the last page.
+ sal_uInt16 nPageIndex (pDocument->GetSdPageCount(PageKind::Standard)-1);
+ bool bFound (false);
+ while ( ! bFound)
+ {
+ pCandidate = pDocument->GetSdPage(
+ nPageIndex,
+ PageKind::Standard);
+ if (pCandidate != nullptr)
+ {
+ if (static_cast<SdPage*>(&pCandidate->TRG_GetMasterPage())
+ == pMasterPage)
+ {
+ bFound = true;
+ break;
+ }
+ }
+
+ if (nPageIndex == 0)
+ break;
+ else
+ nPageIndex --;
+ }
+
+ // If no page was found, that referenced the given master page, reset
+ // the pointer that is returned.
+ if ( ! bFound)
+ pCandidate = nullptr;
+ }
+
+ return pCandidate;
+}
+
+SdPage* DocumentHelper::AddMasterPage (
+ SdDrawDocument& rTargetDocument,
+ SdPage const * pMasterPage)
+{
+ rtl::Reference<SdPage> pClonedMasterPage;
+
+ if (pMasterPage!=nullptr)
+ {
+ try
+ {
+ // Duplicate the master page.
+ pClonedMasterPage = static_cast<SdPage*>(pMasterPage->CloneSdrPage(rTargetDocument).get());
+
+ // Copy the necessary styles.
+ SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
+ ProvideStyles(rSourceDocument, rTargetDocument, pClonedMasterPage.get());
+
+ // Copy the precious flag.
+ pClonedMasterPage->SetPrecious(pMasterPage->IsPrecious());
+
+ // Now that the styles are available we can insert the cloned
+ // master page.
+ rTargetDocument.InsertMasterPage (pClonedMasterPage.get());
+ }
+ catch(const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ pClonedMasterPage = nullptr;
+ }
+ catch(const ::std::exception& e)
+ {
+ pClonedMasterPage = nullptr;
+ SAL_WARN("sd", "caught general exception " << e.what());
+ }
+ catch(...)
+ {
+ pClonedMasterPage = nullptr;
+ SAL_WARN("sd", "caught general exception");
+ }
+ }
+
+ return pClonedMasterPage.get();
+}
+
+void DocumentHelper::ProvideStyles (
+ SdDrawDocument const & rSourceDocument,
+ SdDrawDocument& rTargetDocument,
+ SdPage const * pPage)
+{
+ // Get the layout name of the given page.
+ OUString sLayoutName (pPage->GetLayoutName());
+ sal_Int32 nIndex = sLayoutName.indexOf(SD_LT_SEPARATOR);
+ if( nIndex != -1 )
+ sLayoutName = sLayoutName.copy(0, nIndex);
+
+ // Copy the style sheet from source to target document.
+ SdStyleSheetPool* pSourceStyleSheetPool =
+ static_cast<SdStyleSheetPool*>(rSourceDocument.GetStyleSheetPool());
+ SdStyleSheetPool* pTargetStyleSheetPool =
+ static_cast<SdStyleSheetPool*>(rTargetDocument.GetStyleSheetPool());
+ StyleSheetCopyResultVector aCreatedStyles;
+ pTargetStyleSheetPool->CopyLayoutSheets (
+ sLayoutName,
+ *pSourceStyleSheetPool,
+ aCreatedStyles);
+
+ // Add an undo action for the copied style sheets.
+ if( !aCreatedStyles.empty() )
+ {
+ SfxUndoManager* pUndoManager = rTargetDocument.GetDocSh()->GetUndoManager();
+ if (pUndoManager != nullptr)
+ {
+ pUndoManager->AddUndoAction (
+ std::make_unique<SdMoveStyleSheetsUndoAction>(
+ &rTargetDocument,
+ aCreatedStyles,
+ true));
+ }
+ }
+}
+
+void DocumentHelper::AssignMasterPageToPageList (
+ SdDrawDocument& rTargetDocument,
+ SdPage* pMasterPage,
+ const std::shared_ptr<std::vector<SdPage*> >& rpPageList)
+{
+ if (pMasterPage == nullptr || !pMasterPage->IsMasterPage())
+ return;
+
+ // Make the layout name by stripping out the layout postfix from the
+ // layout name of the given master page.
+ OUString sFullLayoutName(pMasterPage->GetLayoutName());
+ OUString sBaseLayoutName (sFullLayoutName);
+ sal_Int32 nIndex = sBaseLayoutName.indexOf(SD_LT_SEPARATOR);
+ if( nIndex != -1 )
+ sBaseLayoutName = sBaseLayoutName.copy(0, nIndex);
+
+ if (rpPageList->empty())
+ return;
+
+ // Create a second list that contains only the valid pointers to
+ // pages for which an assignment is necessary.
+ ::std::vector<SdPage*> aCleanedList;
+ for (const auto& rpPage : *rpPageList)
+ {
+ OSL_ASSERT(rpPage!=nullptr && &rpPage->getSdrModelFromSdrPage() == &rTargetDocument);
+ if (rpPage != nullptr && rpPage->GetLayoutName() != sFullLayoutName)
+ {
+ aCleanedList.push_back(rpPage);
+ }
+ }
+ if (aCleanedList.empty() )
+ return;
+
+ ViewShellId nViewShellId(-1);
+ if (sd::ViewShell* pViewShell = rTargetDocument.GetDocSh()->GetViewShell())
+ nViewShellId = pViewShell->GetViewShellBase().GetViewShellId();
+ SfxUndoManager* pUndoMgr = rTargetDocument.GetDocSh()->GetUndoManager();
+ if( pUndoMgr )
+ pUndoMgr->EnterListAction(SdResId(STR_UNDO_SET_PRESLAYOUT), OUString(), 0, nViewShellId);
+
+ SdPage* pMasterPageInDocument = ProvideMasterPage(rTargetDocument,pMasterPage,rpPageList);
+ if (pMasterPageInDocument == nullptr)
+ return;
+
+ // Assign the master pages to the given list of pages.
+ for (const auto& rpPage : aCleanedList)
+ {
+ AssignMasterPageToPage (
+ pMasterPageInDocument,
+ sBaseLayoutName,
+ rpPage);
+ }
+
+ if( pUndoMgr )
+ pUndoMgr->LeaveListAction();
+}
+
+SdPage* DocumentHelper::AddMasterPage (
+ SdDrawDocument& rTargetDocument,
+ SdPage const * pMasterPage,
+ sal_uInt16 nInsertionIndex)
+{
+ rtl::Reference<SdPage> pClonedMasterPage;
+
+ if (pMasterPage!=nullptr)
+ {
+ // Duplicate the master page.
+ pClonedMasterPage = static_cast<SdPage*>(pMasterPage->CloneSdrPage(rTargetDocument).get());
+
+ // Copy the precious flag.
+ pClonedMasterPage->SetPrecious(pMasterPage->IsPrecious());
+
+ // Copy the necessary styles.
+ SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
+ ProvideStyles(rSourceDocument, rTargetDocument, pClonedMasterPage.get());
+
+ // Now that the styles are available we can insert the cloned
+ // master page.
+ rTargetDocument.InsertMasterPage (pClonedMasterPage.get(), nInsertionIndex);
+
+ // Adapt the size of the new master page to that of the pages in
+ // the document.
+ Size aNewSize (rTargetDocument.GetSdPage(0, pMasterPage->GetPageKind())->GetSize());
+ ::tools::Rectangle aBorders (
+ pClonedMasterPage->GetLeftBorder(),
+ pClonedMasterPage->GetUpperBorder(),
+ pClonedMasterPage->GetRightBorder(),
+ pClonedMasterPage->GetLowerBorder());
+ pClonedMasterPage->ScaleObjects(aNewSize, aBorders, true);
+ pClonedMasterPage->SetSize(aNewSize);
+ pClonedMasterPage->CreateTitleAndLayout(true);
+ }
+
+ return pClonedMasterPage.get();
+}
+
+/** In here we have to handle three cases:
+ 1. pPage is a normal slide. We can use SetMasterPage to assign the
+ master pages to it.
+ 2. pPage is a master page that is used by at least one slide. We can
+ assign the master page to these slides.
+ 3. pPage is a master page that is currently not used by any slide.
+ We can delete that page and add copies of the given master pages
+ instead.
+
+ For points 2 and 3 where one master page A is assigned to another B we have
+ to keep in mind that the master page that page A has already been
+ inserted into the target document.
+*/
+void DocumentHelper::AssignMasterPageToPage (
+ SdPage const * pMasterPage,
+ std::u16string_view rsBaseLayoutName,
+ SdPage* pPage)
+{
+ // Leave early when the parameters are invalid.
+ if (pPage == nullptr || pMasterPage == nullptr)
+ return;
+
+ SdDrawDocument& rDocument(dynamic_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
+
+ if ( ! pPage->IsMasterPage())
+ {
+ // 1. Remove the background object (so that, if it exists, does
+ // not override the new master page) and assign the master page to
+ // the regular slide.
+ rDocument.GetDocSh()->GetUndoManager()->AddUndoAction(
+ std::make_unique<SdBackgroundObjUndoAction>(
+ rDocument, *pPage, pPage->getSdrPageProperties().GetItemSet()),
+ true);
+ pPage->getSdrPageProperties().PutItem(XFillStyleItem(drawing::FillStyle_NONE));
+
+ rDocument.SetMasterPage (
+ (pPage->GetPageNum()-1)/2,
+ rsBaseLayoutName,
+ &rDocument,
+ false,
+ false);
+ }
+ else
+ {
+ // Find first slide that uses the master page.
+ SdPage* pSlide = nullptr;
+ sal_uInt16 nPageCount = rDocument.GetSdPageCount(PageKind::Standard);
+ for (sal_uInt16 nPage=0; nPage<nPageCount&&pSlide==nullptr; nPage++)
+ {
+ SdrPage* pCandidate = rDocument.GetSdPage(nPage,PageKind::Standard);
+ if (pCandidate != nullptr
+ && pCandidate->TRG_HasMasterPage()
+ && &(pCandidate->TRG_GetMasterPage()) == pPage)
+ {
+ pSlide = static_cast<SdPage*>(pCandidate);
+ }
+ }
+
+ if (pSlide != nullptr)
+ {
+ // 2. Assign the given master pages to the first slide that was
+ // found above that uses the master page.
+ rDocument.SetMasterPage (
+ (pSlide->GetPageNum()-1)/2,
+ rsBaseLayoutName,
+ &rDocument,
+ false,
+ false);
+ }
+ else
+ {
+ // 3. Replace the master page A by a copy of the given master
+ // page B.
+ rDocument.RemoveUnnecessaryMasterPages (
+ pPage);
+ }
+ }
+}
+
+SdPage* DocumentHelper::ProvideMasterPage (
+ SdDrawDocument& rTargetDocument,
+ SdPage* pMasterPage,
+ const std::shared_ptr<std::vector<SdPage*> >& rpPageList)
+{
+ // Make sure that both the master page and its notes master exist
+ // in the source document. If one is missing then return without
+ // making any changes.
+ if (pMasterPage == nullptr)
+ {
+ // The caller should make sure that the master page is valid.
+ OSL_ASSERT(pMasterPage != nullptr);
+ return nullptr;
+ }
+ SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
+ SdPage* pNotesMasterPage = static_cast<SdPage*>(
+ rSourceDocument.GetMasterPage(pMasterPage->GetPageNum()+1));
+ if (pNotesMasterPage == nullptr)
+ {
+ // The model is not in a valid state. Maybe a new master page
+ // is being (not finished yet) created? Return without making
+ // any changes.
+ return nullptr;
+ }
+
+ SdPage* pMasterPageInDocument = nullptr;
+ // Search for a master page with the same name as the given one in
+ // the target document.
+ const OUString sMasterPageLayoutName (pMasterPage->GetLayoutName());
+ for (sal_uInt16 nIndex=0,nCount=rTargetDocument.GetMasterPageCount(); nIndex<nCount; ++nIndex)
+ {
+ SdPage* pCandidate = static_cast<SdPage*>(rTargetDocument.GetMasterPage(nIndex));
+ if (pCandidate && sMasterPageLayoutName == pCandidate->GetLayoutName())
+ {
+ // The requested master page does already exist in the
+ // target document, return it.
+ return pCandidate;
+ }
+ }
+
+ // The given master page does not already belong to the target
+ // document so we have to create copies and insert them into the
+ // target document.
+
+ // Determine the position where the new master pages are inserted.
+ // By default they are inserted at the end. When we assign to a
+ // master page then insert after the last of the (selected) pages.
+ sal_uInt16 nInsertionIndex = rTargetDocument.GetMasterPageCount();
+ if (rpPageList->front()->IsMasterPage())
+ {
+ nInsertionIndex = rpPageList->back()->GetPageNum();
+ }
+
+ // Clone the master page.
+ if (&pMasterPage->getSdrModelFromSdrPage() != &rTargetDocument)
+ {
+ pMasterPageInDocument = AddMasterPage (rTargetDocument, pMasterPage, nInsertionIndex);
+ if( rTargetDocument.IsUndoEnabled() )
+ rTargetDocument.AddUndo(
+ rTargetDocument.GetSdrUndoFactory().CreateUndoNewPage(*pMasterPageInDocument));
+ }
+ else
+ pMasterPageInDocument = pMasterPage;
+
+ // Clone the notes master.
+ if (&pNotesMasterPage->getSdrModelFromSdrPage() != &rTargetDocument)
+ {
+ SdPage* pClonedNotesMasterPage
+ = AddMasterPage (rTargetDocument, pNotesMasterPage, nInsertionIndex+1);
+ if( rTargetDocument.IsUndoEnabled() )
+ rTargetDocument.AddUndo(
+ rTargetDocument.GetSdrUndoFactory().CreateUndoNewPage(*pClonedNotesMasterPage));
+ }
+
+ return pMasterPageInDocument;
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/DocumentHelper.hxx b/sd/source/ui/sidebar/DocumentHelper.hxx
new file mode 100644
index 000000000..61ba5f810
--- /dev/null
+++ b/sd/source/ui/sidebar/DocumentHelper.hxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <sal/types.h>
+
+#include <memory>
+#include <string_view>
+#include <vector>
+
+class SdDrawDocument;
+class SdPage;
+
+namespace sd::sidebar {
+
+/** A collection of methods supporting the handling of master pages.
+*/
+class DocumentHelper
+{
+public:
+ /** Return a copy of the given master page in the given document.
+ */
+ static SdPage* CopyMasterPageToLocalDocument (
+ SdDrawDocument& rTargetDocument,
+ SdPage* pMasterPage);
+
+ /** Return and, when not yet present, create a slide that uses the given
+ master page.
+ */
+ static SdPage* GetSlideForMasterPage (SdPage const * pMasterPage);
+
+ /** Copy the styles used by the given page from the source document to
+ the target document.
+ */
+ static void ProvideStyles (
+ SdDrawDocument const & rSourceDocument,
+ SdDrawDocument& rTargetDocument,
+ SdPage const * pPage);
+
+ /** Assign the given master page to the list of pages.
+ @param rTargetDocument
+ The document that is the owner of the pages in rPageList.
+ @param pMasterPage
+ This master page will usually be a member of the list of all
+ available master pages as provided by the MasterPageContainer.
+ @param rPageList
+ The pages to which to assign the master page. These pages may
+ be slides or master pages themselves.
+ */
+ static void AssignMasterPageToPageList (
+ SdDrawDocument& rTargetDocument,
+ SdPage* pMasterPage,
+ const std::shared_ptr<std::vector<SdPage*> >& rPageList);
+
+private:
+ static SdPage* AddMasterPage (
+ SdDrawDocument& rTargetDocument,
+ SdPage const * pMasterPage);
+ static SdPage* AddMasterPage (
+ SdDrawDocument& rTargetDocument,
+ SdPage const * pMasterPage,
+ sal_uInt16 nInsertionIndex);
+ static SdPage* ProvideMasterPage (
+ SdDrawDocument& rTargetDocument,
+ SdPage* pMasterPage,
+ const std::shared_ptr<std::vector<SdPage*> >& rpPageList);
+
+ /** Assign the given master page to the given page.
+ @param pMasterPage
+ In contrast to AssignMasterPageToPageList() this page is assumed
+ to be in the target document, i.e. the same document that pPage
+ is in. The caller will usually call AddMasterPage() to create a
+ clone of a master page in another document to create it.
+ @param rsBaseLayoutName
+ The layout name of the given master page. It is given so that
+ it has not to be created on every call. It could be generated
+ from the given master page, though.
+ @param pPage
+ The page to which to assign the master page. It can be a slide
+ or a master page itself.
+ */
+ static void AssignMasterPageToPage (
+ SdPage const * pMasterPage,
+ std::u16string_view rsBaseLayoutName,
+ SdPage* pPage);
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/IDisposable.hxx b/sd/source/ui/sidebar/IDisposable.hxx
new file mode 100644
index 000000000..e2c1afe27
--- /dev/null
+++ b/sd/source/ui/sidebar/IDisposable.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+namespace sd::sidebar
+{
+class IDisposable
+{
+public:
+ virtual ~IDisposable();
+};
+
+} // end of namespace ::sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/ISidebarReceiver.hxx b/sd/source/ui/sidebar/ISidebarReceiver.hxx
new file mode 100644
index 000000000..bf51cbe12
--- /dev/null
+++ b/sd/source/ui/sidebar/ISidebarReceiver.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+namespace sd::sidebar
+{
+class ISidebarReceiver
+{
+public:
+ virtual ~ISidebarReceiver();
+};
+
+} // end of namespace ::sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/LayoutMenu.cxx b/sd/source/ui/sidebar/LayoutMenu.cxx
new file mode 100644
index 000000000..23521df0e
--- /dev/null
+++ b/sd/source/ui/sidebar/LayoutMenu.cxx
@@ -0,0 +1,728 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "LayoutMenu.hxx"
+
+#include <app.hrc>
+#include <drawdoc.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <strings.hrc>
+#include <helpids.h>
+#include <pres.hxx>
+#include <sdmod.hxx>
+
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <unokywds.hxx>
+#include <bitmaps.hlst>
+#include <tools/gen.hxx>
+#include <tools/SlotStateListener.hxx>
+#include <DrawController.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <EventMultiplexer.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <sfx2/sidebar/Theme.hxx>
+#include <sal/log.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/stritem.hxx>
+#include <svl/intitem.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/image.hxx>
+#include <xmloff/autolayout.hxx>
+
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XView.hpp>
+#include <com/sun/star/drawing/framework/ResourceId.hpp>
+
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using namespace ::sd::slidesorter;
+using ::sd::framework::FrameworkHelper;
+
+namespace sd::sidebar {
+
+namespace {
+
+struct snew_slide_value_info
+{
+ rtl::OUStringConstExpr msBmpResId;
+ TranslateId mpStrResId;
+ WritingMode meWritingMode;
+ AutoLayout maAutoLayout;
+};
+
+}
+
+constexpr OUStringLiteral EMPTY = u"";
+
+const snew_slide_value_info notes[] =
+{
+ {BMP_SLIDEN_01, STR_AUTOLAYOUT_NOTES, WritingMode_LR_TB,
+ AUTOLAYOUT_NOTES},
+ {EMPTY, {}, WritingMode_LR_TB, AUTOLAYOUT_NONE},
+};
+
+const snew_slide_value_info handout[] =
+{
+ {BMP_SLIDEH_01, STR_AUTOLAYOUT_HANDOUT1, WritingMode_LR_TB,
+ AUTOLAYOUT_HANDOUT1},
+ {BMP_SLIDEH_02, STR_AUTOLAYOUT_HANDOUT2, WritingMode_LR_TB,
+ AUTOLAYOUT_HANDOUT2},
+ {BMP_SLIDEH_03, STR_AUTOLAYOUT_HANDOUT3, WritingMode_LR_TB,
+ AUTOLAYOUT_HANDOUT3},
+ {BMP_SLIDEH_04, STR_AUTOLAYOUT_HANDOUT4, WritingMode_LR_TB,
+ AUTOLAYOUT_HANDOUT4},
+ {BMP_SLIDEH_06, STR_AUTOLAYOUT_HANDOUT6, WritingMode_LR_TB,
+ AUTOLAYOUT_HANDOUT6},
+ {BMP_SLIDEH_09, STR_AUTOLAYOUT_HANDOUT9, WritingMode_LR_TB,
+ AUTOLAYOUT_HANDOUT9},
+ {EMPTY, {}, WritingMode_LR_TB, AUTOLAYOUT_NONE},
+};
+
+const snew_slide_value_info standard[] =
+{
+ {BMP_LAYOUT_EMPTY, STR_AUTOLAYOUT_NONE, WritingMode_LR_TB, AUTOLAYOUT_NONE},
+ {BMP_LAYOUT_HEAD03, STR_AUTOLAYOUT_TITLE, WritingMode_LR_TB, AUTOLAYOUT_TITLE},
+ {BMP_LAYOUT_HEAD02, STR_AUTOLAYOUT_CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_CONTENT},
+ {BMP_LAYOUT_HEAD02A, STR_AUTOLAYOUT_2CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_2CONTENT},
+ {BMP_LAYOUT_HEAD01, STR_AUTOLAYOUT_ONLY_TITLE, WritingMode_LR_TB, AUTOLAYOUT_TITLE_ONLY},
+ {BMP_LAYOUT_TEXTONLY, STR_AUTOLAYOUT_ONLY_TEXT, WritingMode_LR_TB, AUTOLAYOUT_ONLY_TEXT},
+ {BMP_LAYOUT_HEAD03B, STR_AUTOLAYOUT_2CONTENT_CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_2CONTENT_CONTENT},
+ {BMP_LAYOUT_HEAD03C, STR_AUTOLAYOUT_CONTENT_2CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_CONTENT_2CONTENT},
+ {BMP_LAYOUT_HEAD03A, STR_AUTOLAYOUT_2CONTENT_OVER_CONTENT,WritingMode_LR_TB, AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT},
+ {BMP_LAYOUT_HEAD02B, STR_AUTOLAYOUT_CONTENT_OVER_CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT},
+ {BMP_LAYOUT_HEAD04, STR_AUTOLAYOUT_4CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_4CONTENT},
+ {BMP_LAYOUT_HEAD06, STR_AUTOLAYOUT_6CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_6CONTENT},
+
+ // vertical
+ {BMP_LAYOUT_VERTICAL02, STR_AL_VERT_TITLE_TEXT_CHART, WritingMode_TB_RL, AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT},
+ {BMP_LAYOUT_VERTICAL01, STR_AL_VERT_TITLE_VERT_OUTLINE, WritingMode_TB_RL, AUTOLAYOUT_VTITLE_VCONTENT},
+ {BMP_LAYOUT_HEAD02, STR_AL_TITLE_VERT_OUTLINE, WritingMode_TB_RL, AUTOLAYOUT_TITLE_VCONTENT},
+ {BMP_LAYOUT_HEAD02A, STR_AL_TITLE_VERT_OUTLINE_CLIPART, WritingMode_TB_RL, AUTOLAYOUT_TITLE_2VTEXT},
+ {EMPTY, {}, WritingMode_LR_TB, AUTOLAYOUT_NONE}
+};
+
+class LayoutValueSet : public ValueSet
+{
+private:
+ LayoutMenu& mrMenu;
+
+ /** Calculate the number of displayed rows. This depends on the given
+ item size, the given number of columns, and the size of the
+ control. Note that this is not the number of rows managed by the
+ valueset. This number may be larger. In that case a vertical
+ scroll bar is displayed.
+ */
+ int CalculateRowCount(const Size& rItemSize, int nColumnCount);
+
+public:
+ LayoutValueSet(LayoutMenu& rMenu)
+ : ValueSet(nullptr)
+ , mrMenu(rMenu)
+ {
+ }
+
+ virtual void Resize() override;
+
+ virtual bool Command(const CommandEvent& rEvent) override;
+};
+
+LayoutMenu::LayoutMenu (
+ weld::Widget* pParent,
+ ViewShellBase& rViewShellBase,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+ : PanelLayout( pParent, "LayoutPanel", "modules/simpress/ui/layoutpanel.ui" ),
+ mrBase(rViewShellBase),
+ mxLayoutValueSet(new LayoutValueSet(*this)),
+ mxLayoutValueSetWin(new weld::CustomWeld(*m_xBuilder, "layoutvalueset", *mxLayoutValueSet)),
+ mbIsMainViewChangePending(false),
+ mxSidebar(rxSidebar),
+ mbIsDisposed(false)
+{
+ implConstruct( *mrBase.GetDocument()->GetDocSh() );
+ SAL_INFO("sd.ui", "created LayoutMenu at " << this);
+
+ mxLayoutValueSet->SetStyle(mxLayoutValueSet->GetStyle() | WB_ITEMBORDER | WB_FLATVALUESET | WB_TABSTOP);
+
+ mxLayoutValueSet->SetColor(sfx2::sidebar::Theme::GetColor(sfx2::sidebar::Theme::Color_PanelBackground));
+}
+
+void LayoutMenu::implConstruct( DrawDocShell& rDocumentShell )
+{
+ OSL_ENSURE( mrBase.GetDocument()->GetDocSh() == &rDocumentShell,
+ "LayoutMenu::implConstruct: hmm?" );
+ // if this fires, then my assumption that the rDocumentShell parameter to our first ctor is superfluous ...
+ (void) rDocumentShell;
+
+ mxLayoutValueSet->SetStyle (
+ ( mxLayoutValueSet->GetStyle() & ~(WB_ITEMBORDER) )
+ | WB_TABSTOP
+ | WB_MENUSTYLEVALUESET
+ | WB_NO_DIRECTSELECT
+ );
+ mxLayoutValueSet->SetExtraSpacing(2);
+ mxLayoutValueSet->SetSelectHdl (LINK(this, LayoutMenu, ClickHandler));
+ InvalidateContent();
+
+ Link<::sd::tools::EventMultiplexerEvent&,void> aEventListenerLink (LINK(this,LayoutMenu,EventMultiplexerListener));
+ mrBase.GetEventMultiplexer()->AddEventListener(aEventListenerLink);
+
+ mxLayoutValueSet->SetHelpId(HID_SD_TASK_PANE_PREVIEW_LAYOUTS);
+ mxLayoutValueSet->SetAccessibleName(SdResId(STR_TASKPANEL_LAYOUT_MENU_TITLE));
+
+ Link<const OUString&,void> aStateChangeLink (LINK(this,LayoutMenu,StateChangeHandler));
+ mxListener = new ::sd::tools::SlotStateListener(
+ aStateChangeLink,
+ Reference<frame::XDispatchProvider>(mrBase.GetController()->getFrame(), UNO_QUERY),
+ ".uno:VerticalTextState");
+}
+
+LayoutMenu::~LayoutMenu()
+{
+ SAL_INFO("sd.ui", "destroying LayoutMenu at " << this);
+ Dispose();
+ mxLayoutValueSetWin.reset();
+ mxLayoutValueSet.reset();
+}
+
+void LayoutMenu::Dispose()
+{
+ if (mbIsDisposed)
+ return;
+
+ SAL_INFO("sd.ui", "disposing LayoutMenu at " << this);
+
+ mbIsDisposed = true;
+
+ Reference<lang::XComponent> xComponent (mxListener, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+
+ Clear();
+ Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this,LayoutMenu,EventMultiplexerListener));
+ mrBase.GetEventMultiplexer()->RemoveEventListener (aLink);
+}
+
+AutoLayout LayoutMenu::GetSelectedAutoLayout() const
+{
+ AutoLayout aResult = AUTOLAYOUT_NONE;
+
+ if (!mxLayoutValueSet->IsNoSelection() && mxLayoutValueSet->GetSelectedItemId()!=0)
+ {
+ AutoLayout* pLayout = static_cast<AutoLayout*>(mxLayoutValueSet->GetItemData(mxLayoutValueSet->GetSelectedItemId()));
+ if (pLayout != nullptr)
+ aResult = *pLayout;
+ }
+
+ return aResult;
+}
+
+ui::LayoutSize LayoutMenu::GetHeightForWidth (const sal_Int32 nWidth)
+{
+ sal_Int32 nPreferredHeight = 200;
+ if (mxLayoutValueSet->GetItemCount()>0)
+ {
+ Image aImage = mxLayoutValueSet->GetItemImage(mxLayoutValueSet->GetItemId(0));
+ Size aItemSize = mxLayoutValueSet->CalcItemSizePixel(aImage.GetSizePixel());
+ if (nWidth>0 && aItemSize.Width()>0)
+ {
+ aItemSize.AdjustWidth(8 );
+ aItemSize.AdjustHeight(8 );
+ int nColumnCount = nWidth / aItemSize.Width();
+ if (nColumnCount <= 0)
+ nColumnCount = 1;
+ else if (nColumnCount > 4)
+ nColumnCount = 4;
+ int nRowCount = (mxLayoutValueSet->GetItemCount() + nColumnCount-1) / nColumnCount;
+ nPreferredHeight = nRowCount * aItemSize.Height();
+ }
+ }
+ return ui::LayoutSize(nPreferredHeight,nPreferredHeight,nPreferredHeight);
+}
+
+void LayoutValueSet::Resize()
+{
+ Size aWindowSize = GetOutputSizePixel();
+ if (IsVisible() && aWindowSize.Width() > 0)
+ {
+ // Calculate the number of rows and columns.
+ if (GetItemCount() > 0)
+ {
+ Image aImage = GetItemImage(GetItemId(0));
+ Size aItemSize = CalcItemSizePixel (
+ aImage.GetSizePixel());
+ aItemSize.AdjustWidth(8 );
+ aItemSize.AdjustHeight(8 );
+ int nColumnCount = aWindowSize.Width() / aItemSize.Width();
+ if (nColumnCount < 1)
+ nColumnCount = 1;
+ else if (nColumnCount > 4)
+ nColumnCount = 4;
+
+ int nRowCount = CalculateRowCount (aItemSize, nColumnCount);
+
+ SetColCount(nColumnCount);
+ SetLineCount(nRowCount);
+ }
+ }
+
+ ValueSet::Resize();
+}
+
+bool LayoutValueSet::Command(const CommandEvent& rEvent)
+{
+ if (rEvent.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ // As a preparation for the context menu the item under the mouse is
+ // selected.
+ if (rEvent.IsMouseEvent())
+ {
+ sal_uInt16 nIndex = GetItemId(rEvent.GetMousePosPixel());
+ if (nIndex > 0)
+ SelectItem(nIndex);
+ }
+
+ mrMenu.ShowContextMenu(rEvent.IsMouseEvent() ? &rEvent.GetMousePosPixel() : nullptr);
+ return true;
+}
+
+void LayoutMenu::InsertPageWithLayout (AutoLayout aLayout)
+{
+ ViewShell* pViewShell = mrBase.GetMainViewShell().get();
+ if (pViewShell == nullptr)
+ return;
+
+ SfxViewFrame* pViewFrame = mrBase.GetViewFrame();
+ if (pViewFrame == nullptr)
+ return;
+
+ SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher();
+ if (pDispatcher == nullptr)
+ return;
+
+ // Call SID_INSERTPAGE with the right arguments. This is because
+ // the popup menu can not call this slot with arguments directly.
+ SfxRequest aRequest (CreateRequest(SID_INSERTPAGE, aLayout));
+ if (aRequest.GetArgs() != nullptr)
+ {
+ pDispatcher->Execute(
+ SID_INSERTPAGE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ *aRequest.GetArgs());
+ }
+ UpdateSelection();
+}
+
+void LayoutMenu::InvalidateContent()
+{
+ // Throw away the current set and fill the menu anew according to the
+ // current settings (this includes the support for vertical writing.)
+ Fill();
+
+ if (mxSidebar.is())
+ mxSidebar->requestLayout();
+
+ // set selection inside the control during Impress start up
+ UpdateSelection();
+}
+
+int LayoutValueSet::CalculateRowCount (const Size&, int nColumnCount)
+{
+ int nRowCount = 0;
+
+ if (GetItemCount() > 0 && nColumnCount > 0)
+ {
+ nRowCount = (GetItemCount() + nColumnCount - 1) / nColumnCount;
+ if (nRowCount < 1)
+ nRowCount = 1;
+ }
+
+ return nRowCount;
+}
+
+IMPL_LINK_NOARG(LayoutMenu, ClickHandler, ValueSet*, void)
+{
+ AssignLayoutToSelectedSlides( GetSelectedAutoLayout() );
+}
+
+/** The specified layout is assigned to the current page of the view shell
+ in the center pane.
+*/
+void LayoutMenu::AssignLayoutToSelectedSlides (AutoLayout aLayout)
+{
+ using namespace ::sd::slidesorter;
+ using namespace ::sd::slidesorter::controller;
+
+ do
+ {
+ // The view shell in the center pane has to be present.
+ ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
+ if (pMainViewShell == nullptr)
+ break;
+
+ // Determine if the current view is in an invalid master page mode.
+ // The handout view is always in master page mode and therefore not
+ // invalid.
+ bool bMasterPageMode (false);
+ switch (pMainViewShell->GetShellType())
+ {
+ case ViewShell::ST_NOTES:
+ case ViewShell::ST_IMPRESS:
+ {
+ DrawViewShell* pDrawViewShell = static_cast<DrawViewShell*>(pMainViewShell);
+ if (pDrawViewShell->GetEditMode() == EditMode::MasterPage)
+ bMasterPageMode = true;
+ break;
+ }
+ default:
+ break;
+ }
+ if (bMasterPageMode)
+ break;
+
+ // Get a list of all selected slides and call the SID_MODIFYPAGE
+ // slot for all of them.
+ ::sd::slidesorter::SharedPageSelection pPageSelection;
+
+ // Get a list of selected pages.
+ // First we try to obtain this list from a slide sorter. This is
+ // possible only some of the view shells in the center pane. When
+ // no valid slide sorter is available then ask the main view shell
+ // for its current page.
+ SlideSorterViewShell* pSlideSorter = nullptr;
+ switch (pMainViewShell->GetShellType())
+ {
+ case ViewShell::ST_IMPRESS:
+ case ViewShell::ST_NOTES:
+ case ViewShell::ST_SLIDE_SORTER:
+ pSlideSorter = SlideSorterViewShell::GetSlideSorter(mrBase);
+ break;
+ default:
+ break;
+ }
+ if (pSlideSorter != nullptr)
+ {
+ // There is a slide sorter visible so get the list of selected pages from it.
+ pPageSelection = pSlideSorter->GetPageSelection();
+ }
+
+ if( (pSlideSorter == nullptr) || !pPageSelection || pPageSelection->empty() )
+ {
+ // No valid slide sorter available. Ask the main view shell for
+ // its current page.
+ pPageSelection = std::make_shared<::sd::slidesorter::SlideSorterViewShell::PageSelection>();
+ pPageSelection->push_back(pMainViewShell->GetActualPage());
+ }
+
+ if (pPageSelection->empty())
+ break;
+
+ for (const auto& rpPage : *pPageSelection)
+ {
+ if (rpPage == nullptr)
+ continue;
+
+ // Call the SID_ASSIGN_LAYOUT slot with all the necessary parameters.
+ SfxRequest aRequest (mrBase.GetViewFrame(), SID_ASSIGN_LAYOUT);
+ aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATPAGE, (rpPage->GetPageNum()-1)/2));
+ aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATLAYOUT, aLayout));
+ pMainViewShell->ExecuteSlot (aRequest, false);
+ }
+ }
+ while(false);
+}
+
+SfxRequest LayoutMenu::CreateRequest (
+ sal_uInt16 nSlotId,
+ AutoLayout aLayout)
+{
+ SfxRequest aRequest (mrBase.GetViewFrame(), nSlotId);
+
+ do
+ {
+ SdrLayerAdmin& rLayerAdmin (mrBase.GetDocument()->GetLayerAdmin());
+ SdrLayerID aBackground (rLayerAdmin.GetLayerID(sUNO_LayerName_background));
+ SdrLayerID aBackgroundObject (rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects));
+ ViewShell* pViewShell = mrBase.GetMainViewShell().get();
+ if (pViewShell == nullptr)
+ break;
+ SdPage* pPage = pViewShell->GetActualPage();
+ if (pPage == nullptr)
+ break;
+
+ SdrLayerIDSet aVisibleLayers (pPage->TRG_GetMasterPageVisibleLayers());
+
+ aRequest.AppendItem(
+ SfxStringItem (ID_VAL_PAGENAME, OUString()));//pPage->GetName()));
+ aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATLAYOUT, aLayout));
+ aRequest.AppendItem(
+ SfxBoolItem(ID_VAL_ISPAGEBACK, aVisibleLayers.IsSet(aBackground)));
+ aRequest.AppendItem(
+ SfxBoolItem(
+ ID_VAL_ISPAGEOBJ,
+ aVisibleLayers.IsSet(aBackgroundObject)));
+ }
+ while (false);
+
+ return aRequest;
+}
+
+void LayoutMenu::Fill()
+{
+ bool bVertical = SvtCJKOptions::IsVerticalTextEnabled();
+ SdDrawDocument* pDocument = mrBase.GetDocument();
+ bool bRightToLeft = (pDocument!=nullptr
+ && pDocument->GetDefaultWritingMode() == WritingMode_RL_TB);
+
+ // Get URL of the view in the center pane.
+ OUString sCenterPaneViewName;
+ try
+ {
+ Reference<XControllerManager> xControllerManager (
+ Reference<XWeak>(&mrBase.GetDrawController()), UNO_QUERY_THROW);
+ Reference<XResourceId> xPaneId (ResourceId::create(
+ ::comphelper::getProcessComponentContext(),
+ FrameworkHelper::msCenterPaneURL));
+ Reference<XView> xView (FrameworkHelper::Instance(mrBase)->GetView(xPaneId));
+ if (xView.is())
+ sCenterPaneViewName = xView->getResourceId()->getResourceURL();
+ }
+ catch (RuntimeException&)
+ {}
+
+ const snew_slide_value_info* pInfo = nullptr;
+ if (sCenterPaneViewName == framework::FrameworkHelper::msNotesViewURL)
+ {
+ pInfo = notes;
+ }
+ else if (sCenterPaneViewName == framework::FrameworkHelper::msHandoutViewURL)
+ {
+ pInfo = handout;
+ }
+ else if (sCenterPaneViewName == framework::FrameworkHelper::msImpressViewURL
+ || sCenterPaneViewName == framework::FrameworkHelper::msSlideSorterURL)
+ {
+ pInfo = standard;
+ }
+ else
+ {
+ pInfo = nullptr;
+ }
+
+ Clear();
+ for (sal_uInt16 i=1; pInfo!=nullptr && pInfo->mpStrResId; i++, pInfo++)
+ {
+ if ((WritingMode_TB_RL != pInfo->meWritingMode) || bVertical)
+ {
+ Image aImg("private:graphicrepository/" + static_cast<const OUString &>(pInfo->msBmpResId));
+
+ if (bRightToLeft && (WritingMode_TB_RL != pInfo->meWritingMode))
+ { // FIXME: avoid interpolating RTL layouts.
+ BitmapEx aRTL = aImg.GetBitmapEx();
+ aRTL.Mirror(BmpMirrorFlags::Horizontal);
+ aImg = Image(aRTL);
+ }
+
+ mxLayoutValueSet->InsertItem(i, aImg, SdResId(pInfo->mpStrResId));
+ mxLayoutValueSet->SetItemData (i, new AutoLayout(pInfo->maAutoLayout));
+ }
+ }
+}
+
+void LayoutMenu::Clear()
+{
+ for (size_t nId=1; nId<=mxLayoutValueSet->GetItemCount(); nId++)
+ delete static_cast<AutoLayout*>(mxLayoutValueSet->GetItemData(nId));
+ mxLayoutValueSet->Clear();
+}
+
+void LayoutMenu::ShowContextMenu(const Point* pPos)
+{
+ if (SD_MOD()->GetWaterCan())
+ return;
+
+ // Determine the position where to show the menu.
+ Point aMenuPosition;
+ if (pPos)
+ {
+ auto nItemId = mxLayoutValueSet->GetItemId(*pPos);
+ if (nItemId <= 0)
+ return;
+ mxLayoutValueSet->SelectItem(nItemId);
+ aMenuPosition = *pPos;
+ }
+ else
+ {
+ if (mxLayoutValueSet->GetSelectedItemId() == sal_uInt16(-1))
+ return;
+ ::tools::Rectangle aBBox(mxLayoutValueSet->GetItemRect(mxLayoutValueSet->GetSelectedItemId()));
+ aMenuPosition = aBBox.Center();
+ }
+
+ // Setup the menu.
+ ::tools::Rectangle aRect(aMenuPosition, Size(1, 1));
+ weld::Widget* pPopupParent = mxLayoutValueSet->GetDrawingArea();
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "modules/simpress/ui/layoutmenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+
+ // Disable the SID_INSERTPAGE_LAYOUT_MENU item when
+ // the document is read-only.
+ const SfxPoolItem* pItem = nullptr;
+ const SfxItemState aState (
+ mrBase.GetViewFrame()->GetDispatcher()->QueryState(SID_INSERTPAGE, pItem));
+ if (aState == SfxItemState::DISABLED)
+ xMenu->set_sensitive("insert", false);
+
+ // Show the menu.
+ OnMenuItemSelected(xMenu->popup_at_rect(pPopupParent, aRect));
+}
+
+IMPL_LINK_NOARG(LayoutMenu, StateChangeHandler, const OUString&, void)
+{
+ InvalidateContent();
+}
+
+void LayoutMenu::OnMenuItemSelected(std::string_view ident)
+{
+ if (ident.empty())
+ return;
+
+ if (ident == "apply")
+ {
+ AssignLayoutToSelectedSlides(GetSelectedAutoLayout());
+ }
+ else if (ident == "insert")
+ {
+ // Add arguments to this slot and forward it to the main view
+ // shell.
+ InsertPageWithLayout(GetSelectedAutoLayout());
+ }
+}
+
+// Selects an appropriate layout of the slide inside control.
+//
+// Method may be called several times with the same item-id to be selected -
+// only once the actually state of the control will be changed.
+//
+void LayoutMenu::UpdateSelection()
+{
+ bool bItemSelected = false;
+
+ do
+ {
+ // Get current page of main view.
+ ViewShell* pViewShell = mrBase.GetMainViewShell().get();
+ if (pViewShell == nullptr)
+ break;
+
+ SdPage* pCurrentPage = pViewShell->getCurrentPage();
+ if (pCurrentPage == nullptr)
+ break;
+
+ // Get layout of current page.
+ AutoLayout aLayout (pCurrentPage->GetAutoLayout());
+ if (aLayout<AUTOLAYOUT_START || aLayout>AUTOLAYOUT_END)
+ break;
+
+ // Find the entry of the menu for to the layout.
+ const sal_uInt16 nItemCount = mxLayoutValueSet->GetItemCount();
+ for (sal_uInt16 nId=1; nId<=nItemCount; nId++)
+ {
+ if (*static_cast<AutoLayout*>(mxLayoutValueSet->GetItemData(nId)) == aLayout)
+ {
+ // do not set selection twice to the same item
+ if (mxLayoutValueSet->GetSelectedItemId() != nId)
+ {
+ mxLayoutValueSet->SetNoSelection();
+ mxLayoutValueSet->SelectItem(nId);
+ }
+
+ bItemSelected = true; // no need to call SetNoSelection()
+ break;
+ }
+ }
+ }
+ while (false);
+
+ if (!bItemSelected)
+ mxLayoutValueSet->SetNoSelection();
+}
+
+IMPL_LINK(LayoutMenu, EventMultiplexerListener, ::sd::tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ // tdf#89890 During changes of the Layout of the slide when focus is not set inside main area
+ // we do not receive notification EventMultiplexerEventId::CurrentPageChanged, but we receive the following 3 notification types.
+ // => let's make UpdateSelection() also when some shape is changed (during Layout changes)
+ case EventMultiplexerEventId::ShapeChanged:
+ case EventMultiplexerEventId::ShapeInserted:
+ case EventMultiplexerEventId::ShapeRemoved:
+ UpdateSelection();
+ break;
+
+ case EventMultiplexerEventId::CurrentPageChanged:
+ case EventMultiplexerEventId::SlideSortedSelection:
+ UpdateSelection();
+ break;
+
+ case EventMultiplexerEventId::MainViewAdded:
+ mbIsMainViewChangePending = true;
+ break;
+
+ case EventMultiplexerEventId::MainViewRemoved:
+ mxLayoutValueSet->Invalidate(); // redraw without focus
+ break;
+
+ case EventMultiplexerEventId::ConfigurationUpdated:
+ if (mbIsMainViewChangePending)
+ {
+ mbIsMainViewChangePending = false;
+ InvalidateContent();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void LayoutMenu::DataChanged(const DataChangedEvent& rEvent)
+{
+ PanelLayout::DataChanged(rEvent);
+ Fill();
+ mxLayoutValueSet->StyleUpdated();
+ mxLayoutValueSet->SetColor(sfx2::sidebar::Theme::GetColor(sfx2::sidebar::Theme::Color_PanelBackground));
+}
+
+} // end of namespace ::sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/LayoutMenu.hxx b/sd/source/ui/sidebar/LayoutMenu.hxx
new file mode 100644
index 000000000..4cc916858
--- /dev/null
+++ b/sd/source/ui/sidebar/LayoutMenu.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <sfx2/sidebar/ILayoutableWindow.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+
+#include <svtools/valueset.hxx>
+#include <sfx2/request.hxx>
+#include <xmloff/autolayout.hxx>
+
+namespace com::sun::star::frame
+{
+class XStatusListener;
+}
+namespace com::sun::star::ui
+{
+class XSidebar;
+}
+
+namespace sd
+{
+class DrawDocShell;
+class ViewShellBase;
+}
+
+namespace sd::tools
+{
+class EventMultiplexerEvent;
+}
+
+namespace sd::sidebar
+{
+class LayoutValueSet;
+
+class LayoutMenu : public PanelLayout, public sfx2::sidebar::ILayoutableWindow
+{
+public:
+ /** Create a new layout menu. Depending on the given flag it
+ displays its own scroll bar or lets a surrounding window
+ handle that.
+ @param i_pParent
+ the parent node in the control tree
+ @param i_rPanelViewShell
+ the view shell of the task pane.
+ */
+ LayoutMenu(weld::Widget* pParent, ViewShellBase& rViewShellBase,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+ virtual ~LayoutMenu() override;
+
+ void Dispose();
+
+ /** Return a numerical value representing the currently selected
+ layout.
+ */
+ AutoLayout GetSelectedAutoLayout() const;
+
+ // From ILayoutableWindow
+ virtual css::ui::LayoutSize GetHeightForWidth(const sal_Int32 nWidth) override;
+
+ /** Call this method when the set of displayed layouts is not up-to-date
+ anymore. It will re-assemble this set according to the current
+ settings.
+ */
+ void InvalidateContent();
+
+ /** The context menu is requested over this ShowContextMenu() method.
+ */
+ void ShowContextMenu(const Point* pPos);
+
+ /** Call Fill() when switching to or from high contrast mode so that the
+ correct set of icons is displayed.
+ */
+ virtual void DataChanged(const DataChangedEvent& rEvent) override;
+
+private:
+ ViewShellBase& mrBase;
+
+ std::unique_ptr<LayoutValueSet> mxLayoutValueSet;
+ std::unique_ptr<weld::CustomWeld> mxLayoutValueSetWin;
+
+ /** If we are asked for the preferred window size, then use this
+ many columns for the calculation.
+ */
+ css::uno::Reference<css::frame::XStatusListener> mxListener;
+ bool mbIsMainViewChangePending;
+ css::uno::Reference<css::ui::XSidebar> mxSidebar;
+ bool mbIsDisposed;
+
+ /** Fill the value set with the layouts that are applicable to the
+ current main view shell.
+ */
+ void Fill();
+
+ /** Remove all items from the value set.
+ */
+ void Clear();
+
+ /** Assign the given layout to all selected slides of a slide sorter.
+ If no slide sorter is active then this call is ignored. The slide
+ sorter in the center pane is preferred if the choice exists.
+ */
+ void AssignLayoutToSelectedSlides(AutoLayout aLayout);
+
+ /** Insert a new page with the given layout. The page is inserted via
+ the main view shell, i.e. its SID_INSERTPAGE slot is called. If it
+ does not support this slot then inserting a new page does not take
+ place. The new page is inserted after the currently active one (the
+ one returned by ViewShell::GetActualPage().)
+ */
+ void InsertPageWithLayout(AutoLayout aLayout);
+
+ /** Create a request structure that can be used with the SID_INSERTPAGE
+ and SID_MODIFYPAGE slots. The parameters are set so that the given
+ layout is assigned to the current page of the main view shell.
+ @param nSlotId
+ Supported slots are SID_INSERTPAGE and SID_MODIFYPAGE.
+ @param aLayout
+ Layout of the page to insert or to assign.
+ */
+ SfxRequest CreateRequest(sal_uInt16 nSlotId, AutoLayout aLayout);
+
+ /** Select the layout that is used by the current page.
+ */
+ void UpdateSelection();
+
+ // internal ctor
+ void implConstruct(DrawDocShell& rDocumentShell);
+
+ /** When clicked then set the current page of the view in the center pane.
+ */
+ DECL_LINK(ClickHandler, ValueSet*, void);
+ DECL_LINK(StateChangeHandler, const OUString&, void);
+ DECL_LINK(EventMultiplexerListener, ::sd::tools::EventMultiplexerEvent&, void);
+ void OnMenuItemSelected(std::string_view ident);
+};
+
+} // end of namespace ::sd::toolpanel
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageContainer.cxx b/sd/source/ui/sidebar/MasterPageContainer.cxx
new file mode 100644
index 000000000..20d852807
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageContainer.cxx
@@ -0,0 +1,958 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "MasterPageContainer.hxx"
+
+#include "MasterPageContainerProviders.hxx"
+#include "MasterPageDescriptor.hxx"
+#include "MasterPageContainerFiller.hxx"
+#include "MasterPageContainerQueue.hxx"
+#include <PreviewRenderer.hxx>
+#include <tools/SdGlobalResourceContainer.hxx>
+#include <strings.hrc>
+#include <algorithm>
+#include <memory>
+
+#include <unomodel.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <comphelper/processfactory.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <tools/TimerBasedTaskExecution.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/mutex.hxx>
+#include <osl/getglobalmutex.hxx>
+#include <xmloff/autolayout.hxx>
+#include <tools/debug.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+typedef ::std::vector<sd::sidebar::SharedMasterPageDescriptor> MasterPageContainerType;
+
+} // end of anonymous namespace
+
+namespace sd::sidebar {
+
+/** Inner implementation class of the MasterPageContainer.
+*/
+class MasterPageContainer::Implementation
+ : public SdGlobalResource,
+ public MasterPageContainerFiller::ContainerAdapter,
+ public MasterPageContainerQueue::ContainerAdapter
+{
+public:
+ mutable ::osl::Mutex maMutex;
+
+ static std::weak_ptr<Implementation> mpInstance;
+ MasterPageContainerType maContainer;
+
+ static std::shared_ptr<Implementation> Instance();
+
+ void LateInit();
+ void AddChangeListener (const Link<MasterPageContainerChangeEvent&,void>& rLink);
+ void RemoveChangeListener (const Link<MasterPageContainerChangeEvent&,void>& rLink);
+ void UpdatePreviewSizePixel();
+ const Size& GetPreviewSizePixel (PreviewSize eSize) const;
+
+ bool HasToken (Token aToken) const;
+ SharedMasterPageDescriptor GetDescriptor (MasterPageContainer::Token aToken) const;
+ virtual Token PutMasterPage (const SharedMasterPageDescriptor& rDescriptor) override;
+ void InvalidatePreview (Token aToken);
+ Image GetPreviewForToken (
+ Token aToken,
+ PreviewSize ePreviewSize);
+ PreviewState GetPreviewState (Token aToken) const;
+ bool RequestPreview (Token aToken);
+
+ Reference<frame::XModel> GetModel();
+ SdDrawDocument* GetDocument();
+
+ void FireContainerChange (
+ MasterPageContainerChangeEvent::EventType eType,
+ Token aToken);
+
+ virtual bool UpdateDescriptor (
+ const SharedMasterPageDescriptor& rpDescriptor,
+ bool bForcePageObject,
+ bool bForcePreview,
+ bool bSendEvents) override;
+
+ void ReleaseDescriptor (Token aToken);
+
+ /** Called by the MasterPageContainerFiller to notify that all master
+ pages from template documents have been added.
+ */
+ virtual void FillingDone() override;
+
+private:
+ Implementation();
+ virtual ~Implementation() override;
+
+ class Deleter { public:
+ void operator() (Implementation* pObject) { delete pObject; }
+ };
+ friend class Deleter;
+
+ enum class InitializationState { NotInitialized, Initializing, Initialized };
+ InitializationState meInitializationState;
+
+ std::unique_ptr<MasterPageContainerQueue> mpRequestQueue;
+ css::uno::Reference<css::frame::XModel> mxModel;
+ SdDrawDocument* mpDocument;
+ PreviewRenderer maPreviewRenderer;
+ /** Remember whether the first page object has already been used to
+ determine the correct size ratio.
+ */
+ bool mbFirstPageObjectSeen;
+
+ // The widths for the previews contain two pixels for the border that is
+ // painted around the preview.
+ static const int SMALL_PREVIEW_WIDTH = 72 + 2;
+ static const int LARGE_PREVIEW_WIDTH = 2*72 + 2;
+
+ /** This substitution of page preview shows "Preparing preview" and is
+ shown as long as the actual previews are not being present.
+ */
+ Image maLargePreviewBeingCreated;
+ Image maSmallPreviewBeingCreated;
+
+ /** This substitution of page preview is shown when a preview can not be
+ created and thus is not available.
+ */
+ Image maLargePreviewNotAvailable;
+ Image maSmallPreviewNotAvailable;
+
+ ::std::vector<Link<MasterPageContainerChangeEvent&,void>> maChangeListeners;
+
+ // We have to remember the tasks for initialization and filling in case
+ // a MasterPageContainer object is destroyed before these tasks have
+ // been completed.
+ std::weak_ptr<sd::tools::TimerBasedTaskExecution> mpFillerTask;
+
+ Size maSmallPreviewSizePixel;
+ Size maLargePreviewSizePixel;
+
+ Image GetPreviewSubstitution(TranslateId pId, PreviewSize ePreviewSize);
+
+ void CleanContainer();
+};
+
+//===== MasterPageContainer ===================================================
+
+std::weak_ptr<MasterPageContainer::Implementation>
+ MasterPageContainer::Implementation::mpInstance;
+
+std::shared_ptr<MasterPageContainer::Implementation>
+ MasterPageContainer::Implementation::Instance()
+{
+ std::shared_ptr<MasterPageContainer::Implementation> pInstance;
+
+ if (Implementation::mpInstance.expired())
+ {
+ ::osl::GetGlobalMutex aMutexFunctor;
+ ::osl::MutexGuard aGuard (aMutexFunctor());
+ if (Implementation::mpInstance.expired())
+ {
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ pInstance = std::shared_ptr<MasterPageContainer::Implementation>(
+ new MasterPageContainer::Implementation(),
+ MasterPageContainer::Implementation::Deleter());
+ SdGlobalResourceContainer::Instance().AddResource(pInstance);
+ Implementation::mpInstance = pInstance;
+ }
+ else
+ pInstance = std::shared_ptr<MasterPageContainer::Implementation>(
+ Implementation::mpInstance);
+ }
+ else
+ {
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ pInstance = std::shared_ptr<MasterPageContainer::Implementation>(
+ Implementation::mpInstance);
+ }
+
+ DBG_ASSERT(pInstance != nullptr,
+ "MasterPageContainer::Implementation::Instance(): instance is nullptr");
+ return pInstance;
+}
+
+MasterPageContainer::MasterPageContainer()
+ : mpImpl(Implementation::Instance()),
+ mePreviewSize(SMALL)
+{
+ mpImpl->LateInit();
+}
+
+MasterPageContainer::~MasterPageContainer()
+{
+}
+
+void MasterPageContainer::AddChangeListener (const Link<MasterPageContainerChangeEvent&,void>& rLink)
+{
+ mpImpl->AddChangeListener(rLink);
+}
+
+void MasterPageContainer::RemoveChangeListener (const Link<MasterPageContainerChangeEvent&,void>& rLink)
+{
+ mpImpl->RemoveChangeListener(rLink);
+}
+
+void MasterPageContainer::SetPreviewSize (PreviewSize eSize)
+{
+ mePreviewSize = eSize;
+ mpImpl->FireContainerChange(
+ MasterPageContainerChangeEvent::EventType::SIZE_CHANGED,
+ NIL_TOKEN);
+}
+
+Size const & MasterPageContainer::GetPreviewSizePixel() const
+{
+ return mpImpl->GetPreviewSizePixel(mePreviewSize);
+}
+
+MasterPageContainer::Token MasterPageContainer::PutMasterPage (
+ const std::shared_ptr<MasterPageDescriptor>& rDescriptor)
+{
+ return mpImpl->PutMasterPage(rDescriptor);
+}
+
+void MasterPageContainer::AcquireToken (Token aToken)
+{
+ SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
+ if (pDescriptor)
+ {
+ ++pDescriptor->mnUseCount;
+ }
+}
+
+void MasterPageContainer::ReleaseToken (Token aToken)
+{
+ SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
+ if (!pDescriptor)
+ return;
+
+ OSL_ASSERT(pDescriptor->mnUseCount>0);
+ --pDescriptor->mnUseCount;
+ if (pDescriptor->mnUseCount > 0)
+ return;
+
+ switch (pDescriptor->meOrigin)
+ {
+ case DEFAULT:
+ case TEMPLATE:
+ default:
+ break;
+
+ case MASTERPAGE:
+ mpImpl->ReleaseDescriptor(aToken);
+ break;
+ }
+}
+
+int MasterPageContainer::GetTokenCount() const
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ return mpImpl->maContainer.size();
+}
+
+bool MasterPageContainer::HasToken (Token aToken) const
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ return mpImpl->HasToken(aToken);
+}
+
+MasterPageContainer::Token MasterPageContainer::GetTokenForIndex (int nIndex)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ Token aResult (NIL_TOKEN);
+ if (HasToken(nIndex))
+ aResult = mpImpl->maContainer[nIndex]->maToken;
+ return aResult;
+}
+
+MasterPageContainer::Token MasterPageContainer::GetTokenForURL (
+ const OUString& sURL)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ Token aResult (NIL_TOKEN);
+ if (!sURL.isEmpty())
+ {
+ MasterPageContainerType::iterator iEntry (
+ ::std::find_if (
+ mpImpl->maContainer.begin(),
+ mpImpl->maContainer.end(),
+ MasterPageDescriptor::URLComparator(sURL)));
+ if (iEntry != mpImpl->maContainer.end())
+ aResult = (*iEntry)->maToken;
+ }
+ return aResult;
+}
+
+MasterPageContainer::Token MasterPageContainer::GetTokenForStyleName (const OUString& sStyleName)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ Token aResult (NIL_TOKEN);
+ if (!sStyleName.isEmpty())
+ {
+ MasterPageContainerType::iterator iEntry (
+ ::std::find_if (
+ mpImpl->maContainer.begin(),
+ mpImpl->maContainer.end(),
+ MasterPageDescriptor::StyleNameComparator(sStyleName)));
+ if (iEntry != mpImpl->maContainer.end())
+ aResult = (*iEntry)->maToken;
+ }
+ return aResult;
+}
+
+MasterPageContainer::Token MasterPageContainer::GetTokenForPageObject (
+ const SdPage* pPage)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ Token aResult (NIL_TOKEN);
+ if (pPage != nullptr)
+ {
+ MasterPageContainerType::iterator iEntry (
+ ::std::find_if (
+ mpImpl->maContainer.begin(),
+ mpImpl->maContainer.end(),
+ MasterPageDescriptor::PageObjectComparator(pPage)));
+ if (iEntry != mpImpl->maContainer.end())
+ aResult = (*iEntry)->maToken;
+ }
+ return aResult;
+}
+
+OUString MasterPageContainer::GetURLForToken (
+ MasterPageContainer::Token aToken)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
+ if (pDescriptor)
+ return pDescriptor->msURL;
+ else
+ return OUString();
+}
+
+OUString MasterPageContainer::GetPageNameForToken (
+ MasterPageContainer::Token aToken)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
+ if (pDescriptor)
+ return pDescriptor->msPageName;
+ else
+ return OUString();
+}
+
+OUString MasterPageContainer::GetStyleNameForToken (
+ MasterPageContainer::Token aToken)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
+ if (pDescriptor)
+ return pDescriptor->msStyleName;
+ else
+ return OUString();
+}
+
+SdPage* MasterPageContainer::GetPageObjectForToken (
+ MasterPageContainer::Token aToken,
+ bool bLoad)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ SdPage* pPageObject = nullptr;
+ SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
+ if (pDescriptor)
+ {
+ pPageObject = pDescriptor->mpMasterPage;
+ if (pPageObject == nullptr)
+ {
+ // The page object is not (yet) present. Call
+ // UpdateDescriptor() to trigger the PageObjectProvider() to
+ // provide it.
+ if (bLoad)
+ mpImpl->GetModel();
+ if (mpImpl->UpdateDescriptor(pDescriptor,bLoad,false, true))
+ pPageObject = pDescriptor->mpMasterPage;
+ }
+ }
+ return pPageObject;
+}
+
+MasterPageContainer::Origin MasterPageContainer::GetOriginForToken (Token aToken)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
+ if (pDescriptor)
+ return pDescriptor->meOrigin;
+ else
+ return UNKNOWN;
+}
+
+sal_Int32 MasterPageContainer::GetTemplateIndexForToken (Token aToken)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
+ if (pDescriptor)
+ return pDescriptor->mnTemplateIndex;
+ else
+ return -1;
+}
+
+std::shared_ptr<MasterPageDescriptor> MasterPageContainer::GetDescriptorForToken (
+ MasterPageContainer::Token aToken)
+{
+ const ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ return mpImpl->GetDescriptor(aToken);
+}
+
+void MasterPageContainer::InvalidatePreview (MasterPageContainer::Token aToken)
+{
+ mpImpl->InvalidatePreview(aToken);
+}
+
+Image MasterPageContainer::GetPreviewForToken (MasterPageContainer::Token aToken)
+{
+ return mpImpl->GetPreviewForToken(aToken,mePreviewSize);
+}
+
+MasterPageContainer::PreviewState MasterPageContainer::GetPreviewState (Token aToken)
+{
+ return mpImpl->GetPreviewState(aToken);
+}
+
+bool MasterPageContainer::RequestPreview (Token aToken)
+{
+ return mpImpl->RequestPreview(aToken);
+}
+
+//==== Implementation ================================================
+
+MasterPageContainer::Implementation::Implementation()
+ : meInitializationState(InitializationState::NotInitialized),
+ mpDocument(nullptr),
+ mbFirstPageObjectSeen(false)
+{
+ UpdatePreviewSizePixel();
+}
+
+MasterPageContainer::Implementation::~Implementation()
+{
+ // When the initializer or filler tasks are still running then we have
+ // to stop them now in order to prevent them from calling us back.
+ tools::TimerBasedTaskExecution::ReleaseTask(mpFillerTask);
+
+ mpRequestQueue.reset();
+
+ uno::Reference<util::XCloseable> xCloseable (mxModel, uno::UNO_QUERY);
+ if (xCloseable.is())
+ {
+ try
+ {
+ xCloseable->close(true);
+ }
+ catch (const css::util::CloseVetoException&)
+ {
+ }
+ }
+ mxModel = nullptr;
+}
+
+void MasterPageContainer::Implementation::LateInit()
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ if (meInitializationState != InitializationState::NotInitialized)
+ return;
+
+ meInitializationState = InitializationState::Initializing;
+
+ OSL_ASSERT(Instance().get()==this);
+ mpRequestQueue.reset(MasterPageContainerQueue::Create(
+ std::shared_ptr<MasterPageContainerQueue::ContainerAdapter>(Instance())));
+
+ mpFillerTask = ::sd::tools::TimerBasedTaskExecution::Create(
+ std::make_shared<MasterPageContainerFiller>(*this),
+ 5,
+ 50);
+
+ meInitializationState = InitializationState::Initialized;
+}
+
+void MasterPageContainer::Implementation::AddChangeListener (const Link<MasterPageContainerChangeEvent&,void>& rLink)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ ::std::vector<Link<MasterPageContainerChangeEvent&,void>>::iterator iListener (
+ ::std::find(maChangeListeners.begin(),maChangeListeners.end(),rLink));
+ if (iListener == maChangeListeners.end())
+ maChangeListeners.push_back(rLink);
+
+}
+
+void MasterPageContainer::Implementation::RemoveChangeListener (const Link<MasterPageContainerChangeEvent&,void>& rLink)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ ::std::vector<Link<MasterPageContainerChangeEvent&,void>>::iterator iListener (
+ ::std::find(maChangeListeners.begin(),maChangeListeners.end(),rLink));
+ if (iListener != maChangeListeners.end())
+ maChangeListeners.erase(iListener);
+}
+
+void MasterPageContainer::Implementation::UpdatePreviewSizePixel()
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ // The default aspect ratio is 4:3
+ int nWidth (4);
+ int nHeight (3);
+
+ // Search for the first entry with an existing master page.
+ auto iDescriptor = std::find_if(maContainer.begin(), maContainer.end(),
+ [](const SharedMasterPageDescriptor& rxDescriptor) {
+ return rxDescriptor != nullptr && rxDescriptor->mpMasterPage != nullptr;
+ });
+ if (iDescriptor != maContainer.end())
+ {
+ Size aPageSize ((*iDescriptor)->mpMasterPage->GetSize());
+ OSL_ASSERT(!aPageSize.IsEmpty());
+ if (aPageSize.Width() > 0)
+ nWidth = aPageSize.Width();
+ if (aPageSize.Height() > 0)
+ nHeight = aPageSize.Height();
+ mbFirstPageObjectSeen = true;
+ }
+
+ maSmallPreviewSizePixel.setWidth( SMALL_PREVIEW_WIDTH );
+ maLargePreviewSizePixel.setWidth( LARGE_PREVIEW_WIDTH );
+
+ int nNewSmallHeight ((maSmallPreviewSizePixel.Width()-2) * nHeight / nWidth + 2);
+ int nNewLargeHeight ((maLargePreviewSizePixel.Width()-2) * nHeight / nWidth + 2);
+
+ if (nNewSmallHeight!=maSmallPreviewSizePixel.Height()
+ || nNewLargeHeight!=maLargePreviewSizePixel.Height())
+ {
+ maSmallPreviewSizePixel.setHeight( nNewSmallHeight );
+ maLargePreviewSizePixel.setHeight( nNewLargeHeight );
+ FireContainerChange(
+ MasterPageContainerChangeEvent::EventType::SIZE_CHANGED,
+ NIL_TOKEN);
+ }
+}
+
+const Size& MasterPageContainer::Implementation::GetPreviewSizePixel (PreviewSize eSize) const
+{
+ if (eSize == SMALL)
+ return maSmallPreviewSizePixel;
+ else
+ return maLargePreviewSizePixel;
+}
+
+MasterPageContainer::Token MasterPageContainer::Implementation::PutMasterPage (
+ const SharedMasterPageDescriptor& rpDescriptor)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ Token aResult (NIL_TOKEN);
+
+ // Get page object and preview when that is inexpensive.
+ UpdateDescriptor(rpDescriptor,false,false, false);
+
+ // Look up the new MasterPageDescriptor and either insert it or update
+ // an already existing one.
+ MasterPageContainerType::iterator aEntry (
+ ::std::find_if (
+ maContainer.begin(),
+ maContainer.end(),
+ MasterPageDescriptor::AllComparator(rpDescriptor)));
+ if (aEntry == maContainer.end())
+ {
+ // Insert a new MasterPageDescriptor.
+ bool bIgnore(rpDescriptor->mpPageObjectProvider == nullptr
+ && rpDescriptor->msURL.isEmpty());
+
+ if ( ! bIgnore)
+ {
+ CleanContainer();
+
+ aResult = maContainer.size();
+ rpDescriptor->SetToken(aResult);
+
+ // Templates are precious, i.e. we lock them so that they will
+ // not be destroyed when (temporarily) no one references them.
+ // They will only be deleted when the container is destroyed.
+ switch (rpDescriptor->meOrigin)
+ {
+ case TEMPLATE:
+ case DEFAULT:
+ ++rpDescriptor->mnUseCount;
+ break;
+
+ default:
+ break;
+ }
+
+ maContainer.push_back(rpDescriptor);
+ aEntry = maContainer.end()-1;
+
+ FireContainerChange(MasterPageContainerChangeEvent::EventType::CHILD_ADDED,aResult);
+ }
+ }
+ else
+ {
+ // Update an existing MasterPageDescriptor.
+ aResult = (*aEntry)->maToken;
+ std::unique_ptr<std::vector<MasterPageContainerChangeEvent::EventType> > pEventTypes(
+ (*aEntry)->Update(*rpDescriptor));
+ if (pEventTypes != nullptr && !pEventTypes->empty())
+ {
+ // One or more aspects of the descriptor have changed. Send
+ // appropriate events to the listeners.
+ UpdateDescriptor(*aEntry,false,false, true);
+
+ for (const auto& rEventType : *pEventTypes)
+ {
+ FireContainerChange(rEventType, (*aEntry)->maToken);
+ }
+ }
+ }
+
+ return aResult;
+}
+
+bool MasterPageContainer::Implementation::HasToken (Token aToken) const
+{
+ return aToken>=0
+ && o3tl::make_unsigned(aToken)<maContainer.size()
+ && maContainer[aToken];
+}
+
+SharedMasterPageDescriptor MasterPageContainer::Implementation::GetDescriptor (Token aToken) const
+{
+ if (aToken>=0 && o3tl::make_unsigned(aToken)<maContainer.size())
+ return maContainer[aToken];
+ else
+ return SharedMasterPageDescriptor();
+}
+
+void MasterPageContainer::Implementation::InvalidatePreview (Token aToken)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ SharedMasterPageDescriptor pDescriptor (GetDescriptor(aToken));
+ if (pDescriptor)
+ {
+ pDescriptor->maSmallPreview = Image();
+ pDescriptor->maLargePreview = Image();
+ RequestPreview(aToken);
+ }
+}
+
+Image MasterPageContainer::Implementation::GetPreviewForToken (
+ MasterPageContainer::Token aToken,
+ PreviewSize ePreviewSize)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ Image aPreview;
+ PreviewState ePreviewState (GetPreviewState(aToken));
+
+ SharedMasterPageDescriptor pDescriptor = GetDescriptor(aToken);
+
+ // When the preview is missing but inexpensively creatable then do that
+ // now.
+ if (pDescriptor)
+ {
+ if (ePreviewState == PS_CREATABLE)
+ if (UpdateDescriptor(pDescriptor, false,false, true))
+ if (pDescriptor->maLargePreview.GetSizePixel().Width() != 0)
+ ePreviewState = PS_AVAILABLE;
+
+ switch (ePreviewState)
+ {
+ case PS_AVAILABLE:
+ aPreview = pDescriptor->GetPreview(ePreviewSize);
+ break;
+
+ case PS_PREPARING:
+ aPreview = GetPreviewSubstitution(
+ STR_TASKPANEL_PREPARING_PREVIEW_SUBSTITUTION,
+ ePreviewSize);
+ break;
+
+ case PS_CREATABLE:
+ aPreview = GetPreviewSubstitution(
+ STR_TASKPANEL_PREPARING_PREVIEW_SUBSTITUTION,
+ ePreviewSize);
+ break;
+
+ case PS_NOT_AVAILABLE:
+ aPreview = GetPreviewSubstitution(
+ STR_TASKPANEL_NOT_AVAILABLE_SUBSTITUTION,
+ ePreviewSize);
+ if (ePreviewSize == SMALL)
+ pDescriptor->maSmallPreview = aPreview;
+ else
+ pDescriptor->maLargePreview = aPreview;
+ break;
+ }
+ }
+
+ return aPreview;
+}
+
+MasterPageContainer::PreviewState MasterPageContainer::Implementation::GetPreviewState (
+ Token aToken) const
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ PreviewState eState (PS_NOT_AVAILABLE);
+
+ SharedMasterPageDescriptor pDescriptor = GetDescriptor(aToken);
+ if (pDescriptor)
+ {
+ if (pDescriptor->maLargePreview.GetSizePixel().Width() != 0)
+ eState = PS_AVAILABLE;
+ else if (pDescriptor->mpPreviewProvider != nullptr)
+ {
+ // The preview does not exist but can be created. When that is
+ // not expensive then do it at once.
+ if (mpRequestQueue->HasRequest(aToken))
+ eState = PS_PREPARING;
+ else
+ eState = PS_CREATABLE;
+ }
+ else
+ eState = PS_NOT_AVAILABLE;
+ }
+
+ return eState;
+}
+
+bool MasterPageContainer::Implementation::RequestPreview (Token aToken)
+{
+ SharedMasterPageDescriptor pDescriptor = GetDescriptor(aToken);
+ if (pDescriptor)
+ return mpRequestQueue->RequestPreview(pDescriptor);
+ else
+ return false;
+}
+
+Reference<frame::XModel> MasterPageContainer::Implementation::GetModel()
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ if ( ! mxModel.is())
+ {
+ // Create a new model.
+ mxModel.set(
+ ::comphelper::getProcessServiceFactory()->createInstance(
+ "com.sun.star.presentation.PresentationDocument"),
+ uno::UNO_QUERY);
+
+ // Initialize the model.
+ uno::Reference<frame::XLoadable> xLoadable (mxModel,uno::UNO_QUERY);
+ if (xLoadable.is())
+ xLoadable->initNew();
+
+ // Use its tunnel to get a pointer to its core implementation.
+ uno::Reference<lang::XUnoTunnel> xUnoTunnel (mxModel, uno::UNO_QUERY);
+ if (auto pSdXImpressDocument = comphelper::getFromUnoTunnel<SdXImpressDocument>(xUnoTunnel))
+ {
+ mpDocument = pSdXImpressDocument->GetDoc();
+ }
+
+ // Create a default page.
+ uno::Reference<drawing::XDrawPagesSupplier> xSlideSupplier (mxModel, uno::UNO_QUERY);
+ if (xSlideSupplier.is())
+ {
+ uno::Reference<drawing::XDrawPages> xSlides =
+ xSlideSupplier->getDrawPages();
+ if (xSlides.is())
+ {
+ uno::Reference<drawing::XDrawPage> xNewPage (xSlides->insertNewByIndex(0));
+ uno::Reference<beans::XPropertySet> xProperties(xNewPage, uno::UNO_QUERY);
+ if (xProperties.is())
+ xProperties->setPropertyValue(
+ "Layout",
+ Any(sal_Int16(AUTOLAYOUT_TITLE)));
+ }
+ }
+ }
+ return mxModel;
+}
+
+SdDrawDocument* MasterPageContainer::Implementation::GetDocument()
+{
+ GetModel();
+ return mpDocument;
+}
+
+Image MasterPageContainer::Implementation::GetPreviewSubstitution (
+ TranslateId pId,
+ PreviewSize ePreviewSize)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ Image aPreview;
+
+ if (pId == STR_TASKPANEL_PREPARING_PREVIEW_SUBSTITUTION)
+ {
+ Image& rPreview (ePreviewSize==SMALL
+ ? maSmallPreviewBeingCreated
+ : maLargePreviewBeingCreated);
+ if (rPreview.GetSizePixel().Width() == 0)
+ {
+ rPreview = maPreviewRenderer.RenderSubstitution(
+ ePreviewSize==SMALL ? maSmallPreviewSizePixel : maLargePreviewSizePixel,
+ SdResId(STR_TASKPANEL_PREPARING_PREVIEW_SUBSTITUTION));
+ }
+ aPreview = rPreview;
+ }
+ else if (pId == STR_TASKPANEL_NOT_AVAILABLE_SUBSTITUTION)
+ {
+ Image& rPreview (ePreviewSize==SMALL
+ ? maSmallPreviewNotAvailable
+ : maLargePreviewNotAvailable);
+ if (rPreview.GetSizePixel().Width() == 0)
+ {
+ rPreview = maPreviewRenderer.RenderSubstitution(
+ ePreviewSize==SMALL ? maSmallPreviewSizePixel : maLargePreviewSizePixel,
+ SdResId(STR_TASKPANEL_NOT_AVAILABLE_SUBSTITUTION));
+ }
+ aPreview = rPreview;
+ }
+
+ return aPreview;
+}
+
+void MasterPageContainer::Implementation::CleanContainer()
+{
+ // Remove the empty elements at the end of the container. The empty
+ // elements in the middle can not be removed because that would
+ // invalidate the references still held by others.
+ int nIndex (maContainer.size()-1);
+ while (nIndex>=0 && !maContainer[nIndex])
+ --nIndex;
+ maContainer.resize(++nIndex);
+}
+
+void MasterPageContainer::Implementation::FireContainerChange (
+ MasterPageContainerChangeEvent::EventType eType,
+ Token aToken)
+{
+ ::std::vector<Link<MasterPageContainerChangeEvent&,void>> aCopy(maChangeListeners);
+ MasterPageContainerChangeEvent aEvent;
+ aEvent.meEventType = eType;
+ aEvent.maChildToken = aToken;
+ for (const auto& rListener : aCopy)
+ rListener.Call(aEvent);
+}
+
+bool MasterPageContainer::Implementation::UpdateDescriptor (
+ const SharedMasterPageDescriptor& rpDescriptor,
+ bool bForcePageObject,
+ bool bForcePreview,
+ bool bSendEvents)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ // We have to create the page object when the preview provider needs it
+ // and the caller needs the preview.
+ bForcePageObject |= (bForcePreview
+ && rpDescriptor->mpPreviewProvider->NeedsPageObject()
+ && rpDescriptor->mpMasterPage==nullptr);
+
+ // Define a cost threshold so that an update or page object or preview
+ // that is at least this cost are made at once. Updates with higher cost
+ // are scheduled for later.
+ sal_Int32 nCostThreshold (mpRequestQueue->IsEmpty() ? 5 : 0);
+
+ // Update the page object (which may be used for the preview update).
+ if (bForcePageObject)
+ GetDocument();
+ int nPageObjectModified (rpDescriptor->UpdatePageObject(
+ (bForcePageObject ? -1 : nCostThreshold),
+ mpDocument));
+ if (nPageObjectModified == 1 && bSendEvents)
+ FireContainerChange(
+ MasterPageContainerChangeEvent::EventType::DATA_CHANGED,
+ rpDescriptor->maToken);
+ if (nPageObjectModified == -1 && bSendEvents)
+ FireContainerChange(
+ MasterPageContainerChangeEvent::EventType::CHILD_REMOVED,
+ rpDescriptor->maToken);
+ if (nPageObjectModified && ! mbFirstPageObjectSeen)
+ UpdatePreviewSizePixel();
+
+ // Update the preview.
+ bool bPreviewModified (rpDescriptor->UpdatePreview(
+ (bForcePreview ? -1 : nCostThreshold),
+ maSmallPreviewSizePixel,
+ maLargePreviewSizePixel,
+ maPreviewRenderer));
+
+ if (bPreviewModified && bSendEvents)
+ FireContainerChange(
+ MasterPageContainerChangeEvent::EventType::PREVIEW_CHANGED,
+ rpDescriptor->maToken);
+
+ return nPageObjectModified || bPreviewModified;
+}
+
+void MasterPageContainer::Implementation::ReleaseDescriptor (Token aToken)
+{
+ if (aToken>=0 && o3tl::make_unsigned(aToken)<maContainer.size())
+ {
+ maContainer[aToken].reset();
+ }
+}
+
+void MasterPageContainer::Implementation::FillingDone()
+{
+ mpRequestQueue->ProcessAllRequests();
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageContainer.hxx b/sd/source/ui/sidebar/MasterPageContainer.hxx
new file mode 100644
index 000000000..9de4eb6bc
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageContainer.hxx
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/image.hxx>
+
+#include <memory>
+
+class SdPage;
+
+namespace sd::sidebar
+{
+class MasterPageDescriptor;
+class MasterPageContainerChangeEvent;
+
+/** This container manages the master pages used by the MasterPagesSelector
+ controls. It uses internally a singleton implementation object.
+ Therefore, all MasterPageContainer object operator on the same set of
+ master pages. Each MasterPageContainer, however, has its own
+ PreviewSize value and thus can independently switch between large and
+ small previews.
+
+ The container maintains its own document to store master page objects.
+
+ For each master page container stores its URL, preview bitmap, page
+ name, and, if available, the page object.
+
+ Entries are accessed via a Token, which is mostly a numerical index but
+ whose values do not necessarily have to be consecutive.
+*/
+class MasterPageContainer final
+{
+public:
+ typedef int Token;
+ static const Token NIL_TOKEN = -1;
+
+ MasterPageContainer();
+ ~MasterPageContainer();
+
+ void AddChangeListener(const Link<MasterPageContainerChangeEvent&, void>& rLink);
+ void RemoveChangeListener(const Link<MasterPageContainerChangeEvent&, void>& rLink);
+
+ enum PreviewSize
+ {
+ SMALL,
+ LARGE
+ };
+ /** There are two different preview sizes, a small one and a large one.
+ Which one is used by the called container can be changed with this
+ method.
+ When the preview size is changed then all change listeners are
+ notified of this.
+ */
+ void SetPreviewSize(PreviewSize eSize);
+
+ /** Returns the preview size.
+ */
+ PreviewSize GetPreviewSize() const { return mePreviewSize; }
+
+ /** Return the preview size in pixels.
+ */
+ Size const& GetPreviewSizePixel() const;
+
+ enum PreviewState
+ {
+ PS_AVAILABLE,
+ PS_CREATABLE,
+ PS_PREPARING,
+ PS_NOT_AVAILABLE
+ };
+ PreviewState GetPreviewState(Token aToken);
+
+ /** This method is typically called for entries in the container for
+ which GetPreviewState() returns OS_CREATABLE. The creation of the
+ preview is then scheduled to be executed asynchronously at a later
+ point in time. When the preview is available the change listeners
+ will be notified.
+ */
+ bool RequestPreview(Token aToken);
+
+ /** Each entry of the container is either the first page of a template
+ document or is a master page of an Impress document.
+ */
+ enum Origin
+ {
+ MASTERPAGE, // Master page of a document.
+ TEMPLATE, // First page of a template file.
+ DEFAULT, // Empty master page with default style.
+ UNKNOWN
+ };
+
+ /** Put the master page identified and described by the given parameters
+ into the container. When there already is a master page with the
+ given URL, page name, or object pointer (when that is not NULL) then
+ the existing entry is replaced/updated by the given one. Otherwise
+ a new entry is inserted.
+ */
+ Token PutMasterPage(const std::shared_ptr<MasterPageDescriptor>& rDescriptor);
+ void AcquireToken(Token aToken);
+ void ReleaseToken(Token aToken);
+
+ /** This and the GetTokenForIndex() methods can be used to iterate over
+ all members of the container.
+ */
+ int GetTokenCount() const;
+
+ /** Determine whether the container has a member for the given token.
+ */
+ bool HasToken(Token aToken) const;
+
+ /** Return a token for an index in the range
+ 0 <= index < GetTokenCount().
+ */
+ Token GetTokenForIndex(int nIndex);
+
+ Token GetTokenForURL(const OUString& sURL);
+ Token GetTokenForStyleName(const OUString& sStyleName);
+ Token GetTokenForPageObject(const SdPage* pPage);
+
+ OUString GetURLForToken(Token aToken);
+ OUString GetPageNameForToken(Token aToken);
+ OUString GetStyleNameForToken(Token aToken);
+ SdPage* GetPageObjectForToken(Token aToken, bool bLoad);
+ Origin GetOriginForToken(Token aToken);
+ sal_Int32 GetTemplateIndexForToken(Token aToken);
+ std::shared_ptr<MasterPageDescriptor> GetDescriptorForToken(Token aToken);
+
+ void InvalidatePreview(Token aToken);
+
+ /** Return a preview for the specified token. When the preview is not
+ present then the PreviewProvider associated with the token is
+ executed only when that is not expensive. It is the responsibility
+ of the caller to call RequestPreview() to do the same
+ (asynchronously) for expensive PreviewProviders.
+ Call GetPreviewState() to find out if that is necessary.
+ @param aToken
+ This token specifies for which master page to return the preview.
+ Tokens are returned for example by the GetTokenFor...() methods.
+ @return
+ The returned image is the requested preview or a substitution.
+ */
+ Image GetPreviewForToken(Token aToken);
+
+private:
+ class Implementation;
+ std::shared_ptr<Implementation> mpImpl;
+ PreviewSize mePreviewSize;
+};
+
+/** For some changes to the set of master pages in a MasterPageContainer or
+ to the data stored for each master page one or more events are sent to
+ registered listeners.
+ Each event has an event type and a token that tells the listener where
+ the change took place.
+*/
+class MasterPageContainerChangeEvent
+{
+public:
+ enum class EventType
+ {
+ // A master page was added to the container.
+ CHILD_ADDED,
+ // A master page was removed from the container.
+ CHILD_REMOVED,
+ // The preview of a master page has changed.
+ PREVIEW_CHANGED,
+ // The size of a preview has changed.
+ SIZE_CHANGED,
+ // Some of the data stored for a master page has changed.
+ DATA_CHANGED,
+ // The TemplateIndex of a master page has changed.
+ INDEX_CHANGED,
+ } meEventType;
+
+ // Token of the container entry whose data changed or which was added or
+ // removed.
+ MasterPageContainer::Token maChildToken;
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageContainerFiller.cxx b/sd/source/ui/sidebar/MasterPageContainerFiller.cxx
new file mode 100644
index 000000000..3568d9c71
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageContainerFiller.cxx
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "MasterPageContainerFiller.hxx"
+
+#include "MasterPageDescriptor.hxx"
+#include "MasterPageContainerProviders.hxx"
+#include <TemplateScanner.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::sidebar {
+
+MasterPageContainerFiller::MasterPageContainerFiller (ContainerAdapter& rpAdapter)
+ : mrContainerAdapter(rpAdapter),
+ meState(INITIALIZE_TEMPLATE_SCANNER),
+ mpLastAddedEntry(nullptr),
+ mnIndex(1)
+{
+ // Add one entry for the default master page. We use temporarily the
+ // DefaultPagePreviewProvider to prevent the rendering (and the
+ // expensive creation) of the default page. It is replaced later on by
+ // another.
+ SharedMasterPageDescriptor pDescriptor = std::make_shared<MasterPageDescriptor>(
+ MasterPageContainer::DEFAULT,
+ 0,
+ OUString(),
+ OUString(),
+ OUString(),
+ false,
+ std::make_shared<DefaultPageObjectProvider>(),
+ std::make_shared<PagePreviewProvider>());
+ mrContainerAdapter.PutMasterPage(pDescriptor);
+}
+
+MasterPageContainerFiller::~MasterPageContainerFiller()
+{
+}
+
+void MasterPageContainerFiller::RunNextStep()
+{
+ switch (meState)
+ {
+ case INITIALIZE_TEMPLATE_SCANNER:
+ mpScannerTask.reset(new TemplateScanner());
+ meState = SCAN_TEMPLATE;
+ break;
+
+ case SCAN_TEMPLATE:
+ meState = ScanTemplate();
+ break;
+
+ case ADD_TEMPLATE:
+ meState = AddTemplate();
+ break;
+
+ case DONE:
+ case ERROR:
+ default:
+ break;
+ }
+
+ // When the state has just been set to DONE or ERROR then tell the
+ // container that no more templates will be coming and stop the
+ // scanning.
+ switch (meState)
+ {
+ case DONE:
+ case ERROR:
+ if (mpScannerTask != nullptr)
+ {
+ mrContainerAdapter.FillingDone();
+ mpScannerTask.reset();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool MasterPageContainerFiller::HasNextStep()
+{
+ switch (meState)
+ {
+ case DONE:
+ case ERROR:
+ return false;
+
+ default:
+ return true;
+ }
+}
+
+MasterPageContainerFiller::State MasterPageContainerFiller::ScanTemplate()
+{
+ State eState (ERROR);
+
+ if (mpScannerTask != nullptr)
+ {
+ if (mpScannerTask->HasNextStep())
+ {
+ mpScannerTask->RunNextStep();
+ if (mpScannerTask->GetLastAddedEntry() != mpLastAddedEntry)
+ {
+ mpLastAddedEntry = mpScannerTask->GetLastAddedEntry();
+ if (mpLastAddedEntry != nullptr)
+ eState = ADD_TEMPLATE;
+ else
+ eState = SCAN_TEMPLATE;
+ }
+ else
+ eState = SCAN_TEMPLATE;
+ }
+ else
+ eState = DONE;
+ }
+
+ return eState;
+}
+
+MasterPageContainerFiller::State MasterPageContainerFiller::AddTemplate()
+{
+ if (mpLastAddedEntry != nullptr)
+ {
+ SharedMasterPageDescriptor pDescriptor = std::make_shared<MasterPageDescriptor>(
+ MasterPageContainer::TEMPLATE,
+ mnIndex,
+ mpLastAddedEntry->msPath,
+ mpLastAddedEntry->msTitle,
+ OUString(),
+ false,
+ std::make_shared<TemplatePageObjectProvider>(mpLastAddedEntry->msPath),
+ std::make_shared<TemplatePreviewProvider>(mpLastAddedEntry->msPath));
+ // For user supplied templates we use a different preview provider:
+ // The preview in the document shows not only shapes on the master
+ // page but also shapes on the foreground. This is misleading and
+ // therefore these previews are discarded and created directly from
+ // the page objects.
+ if (pDescriptor->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER)
+ pDescriptor->mpPreviewProvider = std::make_shared<PagePreviewProvider>();
+
+ mrContainerAdapter.PutMasterPage(pDescriptor);
+ ++mnIndex;
+ }
+
+ return SCAN_TEMPLATE;
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageContainerFiller.hxx b/sd/source/ui/sidebar/MasterPageContainerFiller.hxx
new file mode 100644
index 000000000..b08452ab6
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageContainerFiller.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include "MasterPageContainer.hxx"
+#include "MasterPageDescriptor.hxx"
+#include <tools/AsynchronousTask.hxx>
+
+namespace sd
+{
+class TemplateScanner;
+class TemplateEntry;
+}
+
+namespace sd::sidebar
+{
+/** Fill a MasterPageContainer with information about the available master
+ pages. These are provided by one default page and from the existing
+ Impress templates. This is done asynchronously.
+*/
+class MasterPageContainerFiller : public ::sd::tools::AsynchronousTask
+{
+public:
+ class ContainerAdapter
+ {
+ public:
+ virtual MasterPageContainer::Token
+ PutMasterPage(const SharedMasterPageDescriptor& rpDescriptor)
+ = 0;
+ /** This method is called when all Impress templates have been added
+ to the container via the PutMasterPage() method.
+ */
+ virtual void FillingDone() = 0;
+
+ protected:
+ ~ContainerAdapter() {}
+ };
+
+ explicit MasterPageContainerFiller(ContainerAdapter& rContainerAdapter);
+ virtual ~MasterPageContainerFiller();
+
+ /** Run the next step of the task. After HasNextStep() returns false
+ this method should ignore further calls.
+ */
+ virtual void RunNextStep() override;
+
+ /** Return <TRUE/> when there is at least one more step to execute.
+ When the task has been executed completely then <FALSE/> is
+ returned.
+ */
+ virtual bool HasNextStep() override;
+
+private:
+ ContainerAdapter& mrContainerAdapter;
+ // Remember what the next step has to do.
+ enum State
+ {
+ INITIALIZE_TEMPLATE_SCANNER,
+ SCAN_TEMPLATE,
+ ADD_TEMPLATE,
+ ERROR,
+ DONE
+ } meState;
+ ::std::unique_ptr<TemplateScanner> mpScannerTask;
+ const TemplateEntry* mpLastAddedEntry;
+ int mnIndex;
+
+ State ScanTemplate();
+ State AddTemplate();
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageContainerProviders.cxx b/sd/source/ui/sidebar/MasterPageContainerProviders.cxx
new file mode 100644
index 000000000..785536daa
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageContainerProviders.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 "MasterPageContainerProviders.hxx"
+
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <PreviewRenderer.hxx>
+#include <svl/eitem.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/thumbnailview.hxx>
+#include <vcl/image.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::sidebar {
+
+//===== PagePreviewProvider ===================================================
+
+PagePreviewProvider::PagePreviewProvider()
+{
+}
+
+Image PagePreviewProvider::operator () (
+ int nWidth,
+ SdPage* pPage,
+ ::sd::PreviewRenderer& rRenderer)
+{
+ Image aPreview;
+
+ if (pPage != nullptr)
+ {
+ // Use the given renderer to create a preview of the given page
+ // object.
+ aPreview = rRenderer.RenderPage(
+ pPage,
+ nWidth);
+ }
+
+ return aPreview;
+}
+
+int PagePreviewProvider::GetCostIndex()
+{
+ return 5;
+}
+
+bool PagePreviewProvider::NeedsPageObject()
+{
+ return true;
+}
+
+//===== TemplatePreviewProvider ===============================================
+
+TemplatePreviewProvider::TemplatePreviewProvider (const OUString& rsURL)
+ : msURL(rsURL)
+{
+}
+
+Image TemplatePreviewProvider::operator() (
+ int,
+ SdPage*,
+ ::sd::PreviewRenderer&)
+{
+ return Image(ThumbnailView::readThumbnail(msURL));
+}
+
+int TemplatePreviewProvider::GetCostIndex()
+{
+ return 10;
+}
+
+bool TemplatePreviewProvider::NeedsPageObject()
+{
+ return false;
+}
+
+//===== TemplatePageObjectProvider =============================================
+
+TemplatePageObjectProvider::TemplatePageObjectProvider (const OUString& rsURL)
+ : msURL(rsURL)
+{
+}
+
+SdPage* TemplatePageObjectProvider::operator() (SdDrawDocument*)
+{
+ SdPage* pPage = nullptr;
+
+ mxDocumentShell = nullptr;
+ try
+ {
+ // Load the template document and return its first page.
+ ::sd::DrawDocShell* pDocumentShell = LoadDocument (msURL);
+ if (pDocumentShell != nullptr)
+ {
+ SdDrawDocument* pDocument = pDocumentShell->GetDoc();
+ if (pDocument != nullptr)
+ {
+ pPage = pDocument->GetMasterSdPage(0, PageKind::Standard);
+ // In order to make the newly loaded master page deletable
+ // when copied into documents it is marked as no "precious".
+ // When it is modified then it is marked as "precious".
+ if (pPage != nullptr)
+ pPage->SetPrecious(false);
+ }
+ }
+ }
+ catch (const uno::RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ pPage = nullptr;
+ }
+
+ return pPage;
+}
+
+::sd::DrawDocShell* TemplatePageObjectProvider::LoadDocument (const OUString& sFileName)
+{
+ SfxApplication* pSfxApp = SfxGetpApp();
+ std::unique_ptr<SfxItemSet> pSet(new SfxAllItemSet (pSfxApp->GetPool()));
+ pSet->Put (SfxBoolItem (SID_TEMPLATE, true));
+ pSet->Put (SfxBoolItem (SID_PREVIEW, true));
+ if (pSfxApp->LoadTemplate (mxDocumentShell, sFileName, std::move(pSet)))
+ {
+ mxDocumentShell = nullptr;
+ }
+ SfxObjectShell* pShell = mxDocumentShell;
+ return dynamic_cast< ::sd::DrawDocShell *>( pShell );
+}
+
+int TemplatePageObjectProvider::GetCostIndex()
+{
+ return 20;
+}
+
+//===== DefaultPageObjectProvider ==============================================
+
+DefaultPageObjectProvider::DefaultPageObjectProvider()
+{
+}
+
+SdPage* DefaultPageObjectProvider::operator () (SdDrawDocument* pContainerDocument)
+{
+ SdPage* pLocalMasterPage = nullptr;
+ if (pContainerDocument != nullptr)
+ {
+ SdPage* pLocalSlide = pContainerDocument->GetSdPage(0, PageKind::Standard);
+ if (pLocalSlide!=nullptr && pLocalSlide->TRG_HasMasterPage())
+ pLocalMasterPage = dynamic_cast<SdPage*>(&pLocalSlide->TRG_GetMasterPage());
+ }
+
+ if (pLocalMasterPage == nullptr)
+ {
+ SAL_WARN( "sd", "can not create master page for slide");
+ }
+
+ return pLocalMasterPage;
+}
+
+int DefaultPageObjectProvider::GetCostIndex()
+{
+ return 15;
+}
+
+//===== ExistingPageProvider ==================================================
+
+ExistingPageProvider::ExistingPageProvider (SdPage* pPage)
+ : mpPage(pPage)
+{
+}
+
+SdPage* ExistingPageProvider::operator() (SdDrawDocument*)
+{
+ return mpPage;
+}
+
+int ExistingPageProvider::GetCostIndex()
+{
+ return 0;
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageContainerProviders.hxx b/sd/source/ui/sidebar/MasterPageContainerProviders.hxx
new file mode 100644
index 000000000..b76076e15
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageContainerProviders.hxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <sfx2/objsh.hxx>
+
+class Image;
+class SdDrawDocument;
+class SdPage;
+namespace sd
+{
+class PreviewRenderer;
+}
+namespace sd
+{
+class DrawDocShell;
+}
+
+namespace sd::sidebar
+{
+/** Interface for a provider of page objects. It is used by the
+ MasterPageDescriptor to create master page objects on demand.
+*/
+class PageObjectProvider
+{
+public:
+ /** Return a master page either by returning an already existing one, by
+ creating a new page, or by loading a document.
+ @param pDocument
+ The document of the MasterPageContainer. It may be used to
+ create new pages.
+ */
+ virtual SdPage* operator()(SdDrawDocument* pDocument) = 0;
+
+ /** An abstract value for the expected cost of providing a master page
+ object.
+ @return
+ A value of 0 represents for the lowest cost, i.e. an almost
+ immediate return. Positive values stand for higher costs.
+ Negative values are not supported.
+ */
+ virtual int GetCostIndex() = 0;
+
+protected:
+ ~PageObjectProvider() {}
+};
+
+class PreviewProvider
+{
+public:
+ /** Create a preview image in the specified width.
+ @param nWidth
+ Requested width of the preview. The calling method can cope
+ with other sizes as well but the resulting image quality is
+ better when the returned image has the requested size.
+ @param pPage
+ Page object for which a preview is requested. This may be NULL
+ when the page object is expensive to get and the PreviewProvider
+ does not need this object (NeedsPageObject() returns false.)
+ @param rRenderer
+ This PreviewRenderer may be used by the PreviewProvider to
+ create a preview image.
+ */
+ virtual Image operator()(int nWidth, SdPage* pPage, ::sd::PreviewRenderer& rRenderer) = 0;
+
+ /** Return a value that indicates how expensive the creation of a
+ preview image is. The higher the returned value the more expensive
+ is the preview creation. Return 0 when the preview is already
+ present and can be returned immediately.
+ */
+ virtual int GetCostIndex() = 0;
+
+ /** Return whether the page object passed is necessary to create a
+ preview.
+ */
+ virtual bool NeedsPageObject() = 0;
+
+protected:
+ ~PreviewProvider() {}
+};
+
+/** Provide previews of existing page objects by rendering them.
+*/
+class PagePreviewProvider : public PreviewProvider
+{
+public:
+ PagePreviewProvider();
+ virtual ~PagePreviewProvider() {}
+ virtual Image operator()(int nWidth, SdPage* pPage, ::sd::PreviewRenderer& rRenderer) override;
+ virtual int GetCostIndex() override;
+ virtual bool NeedsPageObject() override;
+
+private:
+};
+
+/** Provide master page objects for template documents for which only the
+ URL is given.
+*/
+class TemplatePageObjectProvider : public PageObjectProvider
+{
+public:
+ explicit TemplatePageObjectProvider(const OUString& rsURL);
+ virtual ~TemplatePageObjectProvider(){};
+ virtual SdPage* operator()(SdDrawDocument* pDocument) override;
+ virtual int GetCostIndex() override;
+
+private:
+ OUString msURL;
+ SfxObjectShellLock mxDocumentShell;
+ ::sd::DrawDocShell* LoadDocument(const OUString& sFileName);
+};
+
+/** Provide previews for template documents by loading the thumbnails from
+ the documents.
+*/
+class TemplatePreviewProvider : public PreviewProvider
+{
+public:
+ explicit TemplatePreviewProvider(const OUString& rsURL);
+ virtual ~TemplatePreviewProvider(){};
+ virtual Image operator()(int nWidth, SdPage* pPage, ::sd::PreviewRenderer& rRenderer) override;
+ virtual int GetCostIndex() override;
+ virtual bool NeedsPageObject() override;
+
+private:
+ OUString msURL;
+};
+
+/** Create an empty default master page.
+*/
+class DefaultPageObjectProvider : public PageObjectProvider
+{
+public:
+ DefaultPageObjectProvider();
+ virtual ~DefaultPageObjectProvider() {}
+ virtual SdPage* operator()(SdDrawDocument* pDocument) override;
+ virtual int GetCostIndex() override;
+};
+
+/** This implementation of the PageObjectProvider simply returns an already
+ existing master page object.
+*/
+class ExistingPageProvider : public PageObjectProvider
+{
+public:
+ explicit ExistingPageProvider(SdPage* pPage);
+ virtual ~ExistingPageProvider() {}
+ virtual SdPage* operator()(SdDrawDocument* pDocument) override;
+ virtual int GetCostIndex() override;
+
+private:
+ SdPage* mpPage;
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageContainerQueue.cxx b/sd/source/ui/sidebar/MasterPageContainerQueue.cxx
new file mode 100644
index 000000000..229f3d972
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageContainerQueue.cxx
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "MasterPageContainerQueue.hxx"
+#include "MasterPageContainerProviders.hxx"
+
+#include <tools/IdleDetection.hxx>
+
+#include <set>
+
+namespace sd::sidebar {
+
+const sal_Int32 MasterPageContainerQueue::snDelayedCreationTimeout (15);
+const sal_Int32 MasterPageContainerQueue::snDelayedCreationTimeoutWhenNotIdle (100);
+const sal_Int32 MasterPageContainerQueue::snMasterPagePriorityBoost (5);
+const sal_Int32 MasterPageContainerQueue::snWaitForMoreRequestsPriorityThreshold (-10);
+sal_uInt32 MasterPageContainerQueue::snWaitForMoreRequestsCount(15);
+
+//===== MasterPageContainerQueue::PreviewCreationRequest ======================
+
+class MasterPageContainerQueue::PreviewCreationRequest
+{
+public:
+ PreviewCreationRequest (const SharedMasterPageDescriptor& rpDescriptor, int nPriority)
+ : mpDescriptor(rpDescriptor),
+ mnPriority(nPriority)
+ {}
+ SharedMasterPageDescriptor mpDescriptor;
+ int mnPriority;
+ class Compare
+ {
+ public:
+ bool operator() (const PreviewCreationRequest& r1,const PreviewCreationRequest& r2) const
+ {
+ if (r1.mnPriority != r2.mnPriority)
+ {
+ // Prefer requests with higher priority.
+ return r1.mnPriority > r2.mnPriority;
+ }
+ else
+ {
+ // Prefer tokens that have been earlier created (those with lower
+ // value).
+ return r1.mpDescriptor->maToken < r2.mpDescriptor->maToken;
+ }
+ }
+ };
+ class CompareToken
+ {
+ public:
+ MasterPageContainer::Token maToken;
+ explicit CompareToken(MasterPageContainer::Token aToken) : maToken(aToken) {}
+ bool operator() (const PreviewCreationRequest& rRequest) const
+ { return maToken==rRequest.mpDescriptor->maToken; }
+ };
+};
+
+//===== MasterPageContainerQueue::RequestQueue ================================
+
+class MasterPageContainerQueue::RequestQueue
+ : public ::std::set<PreviewCreationRequest,PreviewCreationRequest::Compare>
+{
+public:
+ RequestQueue() {}
+};
+
+//===== MasterPageContainerQueue ==============================================
+
+MasterPageContainerQueue* MasterPageContainerQueue::Create (
+ const std::weak_ptr<ContainerAdapter>& rpContainer)
+{
+ MasterPageContainerQueue* pQueue = new MasterPageContainerQueue(rpContainer);
+ pQueue->LateInit();
+ return pQueue;
+}
+
+MasterPageContainerQueue::MasterPageContainerQueue (
+ const std::weak_ptr<ContainerAdapter>& rpContainer)
+ : mpWeakContainer(rpContainer),
+ mpRequestQueue(new RequestQueue()),
+ maDelayedPreviewCreationTimer("sd MasterPageContainerQueue maDelayedPreviewCreationTimer"),
+ mnRequestsServedCount(0)
+{
+}
+
+MasterPageContainerQueue::~MasterPageContainerQueue()
+{
+ maDelayedPreviewCreationTimer.Stop();
+ while ( ! mpRequestQueue->empty())
+ mpRequestQueue->erase(mpRequestQueue->begin());
+}
+
+void MasterPageContainerQueue::LateInit()
+{
+ // Set up the timer for the delayed creation of preview bitmaps.
+ maDelayedPreviewCreationTimer.SetTimeout (snDelayedCreationTimeout);
+ maDelayedPreviewCreationTimer.SetInvokeHandler(
+ LINK(this,MasterPageContainerQueue,DelayedPreviewCreation) );
+}
+
+bool MasterPageContainerQueue::RequestPreview (const SharedMasterPageDescriptor& rpDescriptor)
+{
+ bool bSuccess (false);
+ if (rpDescriptor
+ && rpDescriptor->maLargePreview.GetSizePixel().Width() == 0)
+ {
+ sal_Int32 nPriority (CalculatePriority(rpDescriptor));
+
+ // Add a new or replace an existing request.
+ RequestQueue::iterator iRequest (::std::find_if(
+ mpRequestQueue->begin(),
+ mpRequestQueue->end(),
+ PreviewCreationRequest::CompareToken(rpDescriptor->maToken)));
+ // When a request for the same token exists then the lowest of the
+ // two priorities is used.
+ if (iRequest != mpRequestQueue->end())
+ if (iRequest->mnPriority < nPriority)
+ {
+ mpRequestQueue->erase(iRequest);
+ iRequest = mpRequestQueue->end();
+ }
+
+ // Add a new request when none exists (or has just been erased).
+ if (iRequest == mpRequestQueue->end())
+ {
+ mpRequestQueue->insert(PreviewCreationRequest(rpDescriptor,nPriority));
+ maDelayedPreviewCreationTimer.Start();
+ bSuccess = true;
+ }
+ }
+ return bSuccess;
+}
+
+sal_Int32 MasterPageContainerQueue::CalculatePriority (
+ const SharedMasterPageDescriptor& rpDescriptor)
+{
+ sal_Int32 nPriority;
+
+ // The cost is used as a starting value.
+ int nCost (0);
+ if (rpDescriptor->mpPreviewProvider != nullptr)
+ {
+ nCost = rpDescriptor->mpPreviewProvider->GetCostIndex();
+ if (rpDescriptor->mpPreviewProvider->NeedsPageObject())
+ if (rpDescriptor->mpPageObjectProvider != nullptr)
+ nCost += rpDescriptor->mpPageObjectProvider->GetCostIndex();
+ }
+
+ // Its negative value is used so that requests with a low cost are
+ // preferred over those with high costs.
+ nPriority = -nCost;
+
+ // Add a term that introduces an order based on the appearance in the
+ // AllMasterPagesSelector.
+ nPriority -= rpDescriptor->maToken / 3;
+
+ // Process requests for the CurrentMasterPagesSelector first.
+ if (rpDescriptor->meOrigin == MasterPageContainer::MASTERPAGE)
+ nPriority += snMasterPagePriorityBoost;
+
+ return nPriority;
+}
+
+IMPL_LINK(MasterPageContainerQueue, DelayedPreviewCreation, Timer*, pTimer, void)
+{
+ bool bIsShowingFullScreenShow (false);
+ bool bWaitForMoreRequests (false);
+
+ do
+ {
+ if (mpRequestQueue->empty())
+ break;
+
+ // First check whether the system is idle.
+ tools::IdleState nIdleState (tools::IdleDetection::GetIdleState(nullptr));
+ if (nIdleState != tools::IdleState::Idle)
+ {
+ if (nIdleState & tools::IdleState::FullScreenShowActive)
+ bIsShowingFullScreenShow = true;
+ break;
+ }
+
+ PreviewCreationRequest aRequest (*mpRequestQueue->begin());
+
+ // Check if the request should really be processed right now.
+ // Reasons to not do it are when its cost is high and not many other
+ // requests have been inserted into the queue that would otherwise
+ // be processed first.
+ if (aRequest.mnPriority < snWaitForMoreRequestsPriorityThreshold
+ && (mnRequestsServedCount+mpRequestQueue->size() < snWaitForMoreRequestsCount))
+ {
+ // Wait for more requests before this one is processed. Note
+ // that the queue processing is not started anew when this
+ // method is left. That is done when the next request is
+ // inserted.
+ bWaitForMoreRequests = true;
+ break;
+ }
+
+ mpRequestQueue->erase(mpRequestQueue->begin());
+
+ if (aRequest.mpDescriptor)
+ {
+ mnRequestsServedCount += 1;
+ if ( ! mpWeakContainer.expired())
+ {
+ std::shared_ptr<ContainerAdapter> pContainer (mpWeakContainer);
+ if (pContainer != nullptr)
+ pContainer->UpdateDescriptor(aRequest.mpDescriptor,false,true,true);
+ }
+ }
+ }
+ while (false);
+
+ if (!mpRequestQueue->empty() && ! bWaitForMoreRequests)
+ {
+ int nTimeout (snDelayedCreationTimeout);
+ if (bIsShowingFullScreenShow)
+ nTimeout = snDelayedCreationTimeoutWhenNotIdle;
+ maDelayedPreviewCreationTimer.SetTimeout(nTimeout);
+ pTimer->Start();
+ }
+}
+
+bool MasterPageContainerQueue::HasRequest (MasterPageContainer::Token aToken) const
+{
+ return std::any_of(
+ mpRequestQueue->begin(),
+ mpRequestQueue->end(),
+ PreviewCreationRequest::CompareToken(aToken));
+}
+
+bool MasterPageContainerQueue::IsEmpty() const
+{
+ return mpRequestQueue->empty();
+}
+
+void MasterPageContainerQueue::ProcessAllRequests()
+{
+ snWaitForMoreRequestsCount = 0;
+ if (!mpRequestQueue->empty())
+ maDelayedPreviewCreationTimer.Start();
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageContainerQueue.hxx b/sd/source/ui/sidebar/MasterPageContainerQueue.hxx
new file mode 100644
index 000000000..6b9b0adca
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageContainerQueue.hxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MasterPageContainer.hxx"
+#include "MasterPageDescriptor.hxx"
+
+#include <vcl/timer.hxx>
+
+#include <memory>
+
+namespace sd::sidebar {
+
+/** The queue stores and processes all requests from a MasterPageContainer
+ for the creation of previews.
+ The order of request processing and its timing is controlled by a
+ heuristic that uses values given with each request and which is
+ controlled by various parameters that are described below.
+*/
+class MasterPageContainerQueue final
+{
+public:
+ class ContainerAdapter {
+ public:
+ virtual bool UpdateDescriptor (
+ const SharedMasterPageDescriptor& rpDescriptor,
+ bool bForcePageObject,
+ bool bForcePreview,
+ bool bSendEvents) = 0;
+
+ protected:
+ ~ContainerAdapter() {}
+ };
+
+ static MasterPageContainerQueue* Create (
+ const std::weak_ptr<ContainerAdapter>& rpContainer);
+ ~MasterPageContainerQueue();
+
+ /** This method is typically called for entries in the container for
+ which GetPreviewState() returns OS_CREATABLE. The creation of the
+ preview is then scheduled to be executed asynchronously at a later
+ point in time. When the preview is available the change listeners
+ will be notified.
+ */
+ bool RequestPreview (const SharedMasterPageDescriptor& rDescriptor);
+
+ /** Return <TRUE/> when there is a request currently in the queue for
+ the given token.
+ */
+ bool HasRequest (MasterPageContainer::Token aToken) const;
+
+ /** Return <TRUE/> when there is at least one request in the queue.
+ */
+ bool IsEmpty() const;
+
+ /** After this call the queue does not wait anymore for requests with
+ higher priority when only a small number of requests with lower
+ priority are present. This method should be called when all
+ templates are inserted into the MasterPageContainer.
+ */
+ void ProcessAllRequests();
+
+private:
+ std::weak_ptr<ContainerAdapter> mpWeakContainer;
+ class PreviewCreationRequest;
+ class RequestQueue;
+ std::unique_ptr<RequestQueue> mpRequestQueue;
+ Timer maDelayedPreviewCreationTimer;
+ sal_uInt32 mnRequestsServedCount;
+
+ // There are a couple of values that define various aspects of the
+ // heuristic that defines the order and timing in which requests for
+ // preview creation are processed.
+
+ /** The time to wait (in milliseconds) between the creation of previews.
+ */
+ static const sal_Int32 snDelayedCreationTimeout;
+
+ /** The time to wait when the system is not idle.
+ */
+ static const sal_Int32 snDelayedCreationTimeoutWhenNotIdle;
+
+ /** Requests for previews of master pages in a document have their
+ priority increased by this value.
+ */
+ static const sal_Int32 snMasterPagePriorityBoost;
+
+ /** When only requests which a priority lower than this threshold exist
+ and not many requests have been made yet then wait with processing
+ them until more requests are present.
+ */
+ static const sal_Int32 snWaitForMoreRequestsPriorityThreshold;
+
+ /** When only requests which a priority lower than a threshold exist
+ and not more requests than this number have been made or already
+ processed then wait with processing them until more requests are
+ present.
+ */
+ static sal_uInt32 snWaitForMoreRequestsCount;
+
+ explicit MasterPageContainerQueue (const std::weak_ptr<ContainerAdapter>& rpContainer);
+ void LateInit();
+
+ /** Calculate the priority that defines the order in which requests
+ are processed.
+ */
+ static sal_Int32 CalculatePriority (const SharedMasterPageDescriptor& rDescriptor);
+
+ DECL_LINK(DelayedPreviewCreation, Timer *, void);
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageDescriptor.cxx b/sd/source/ui/sidebar/MasterPageDescriptor.cxx
new file mode 100644
index 000000000..2c0c23eb7
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageDescriptor.cxx
@@ -0,0 +1,341 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "MasterPageDescriptor.hxx"
+#include "MasterPageContainerProviders.hxx"
+
+#include "DocumentHelper.hxx"
+#include <PreviewRenderer.hxx>
+#include <sdpage.hxx>
+#include <tools/urlobj.hxx>
+#include <sal/log.hxx>
+
+namespace sd::sidebar {
+
+//===== MasterPageDescriptor ==================================================
+
+MasterPageDescriptor::MasterPageDescriptor (
+ MasterPageContainer::Origin eOrigin,
+ const sal_Int32 nTemplateIndex,
+ std::u16string_view rsURL,
+ const OUString& rsPageName,
+ const OUString& rsStyleName,
+ const bool bIsPrecious,
+ const std::shared_ptr<PageObjectProvider>& rpPageObjectProvider,
+ const std::shared_ptr<PreviewProvider>& rpPreviewProvider)
+ : maToken(MasterPageContainer::NIL_TOKEN),
+ meOrigin(eOrigin),
+ msURL(INetURLObject(rsURL).GetMainURL(INetURLObject::DecodeMechanism::Unambiguous)),
+ msPageName(rsPageName),
+ msStyleName(rsStyleName),
+ mbIsPrecious(bIsPrecious),
+ mpMasterPage(nullptr),
+ mpSlide(nullptr),
+ mpPreviewProvider(rpPreviewProvider),
+ mpPageObjectProvider(rpPageObjectProvider),
+ mnTemplateIndex(nTemplateIndex),
+ meURLClassification(URLCLASS_UNDETERMINED),
+ mnUseCount(0)
+{
+}
+
+void MasterPageDescriptor::SetToken (MasterPageContainer::Token aToken)
+{
+ maToken = aToken;
+}
+
+const Image& MasterPageDescriptor::GetPreview (MasterPageContainer::PreviewSize eSize) const
+{
+ if (eSize == MasterPageContainer::SMALL)
+ return maSmallPreview;
+ else
+ return maLargePreview;
+}
+
+::std::unique_ptr<std::vector<MasterPageContainerChangeEvent::EventType> >
+ MasterPageDescriptor::Update (
+ const MasterPageDescriptor& rDescriptor)
+{
+ bool bDataChanged (false);
+ bool bIndexChanged (false);
+ bool bPreviewChanged (false);
+
+ if (meOrigin==MasterPageContainer::UNKNOWN
+ && rDescriptor.meOrigin!=MasterPageContainer::UNKNOWN)
+ {
+ meOrigin = rDescriptor.meOrigin;
+ bIndexChanged = true;
+ }
+
+ if (msURL.isEmpty() && !rDescriptor.msURL.isEmpty())
+ {
+ msURL = rDescriptor.msURL;
+ bDataChanged = true;
+ }
+
+ if (msPageName.isEmpty() && !rDescriptor.msPageName.isEmpty())
+ {
+ msPageName = rDescriptor.msPageName;
+ bDataChanged = true;
+ }
+
+ if (msStyleName.isEmpty() && !rDescriptor.msStyleName.isEmpty())
+ {
+ msStyleName = rDescriptor.msStyleName;
+ bDataChanged = true;
+ }
+
+ if (mpPageObjectProvider == nullptr && rDescriptor.mpPageObjectProvider != nullptr)
+ {
+ mpPageObjectProvider = rDescriptor.mpPageObjectProvider;
+ bDataChanged = true;
+ }
+
+ if (mpPreviewProvider == nullptr && rDescriptor.mpPreviewProvider != nullptr)
+ {
+ mpPreviewProvider = rDescriptor.mpPreviewProvider;
+ bPreviewChanged = true;
+ }
+
+ if (mnTemplateIndex<0 && rDescriptor.mnTemplateIndex>=0)
+ {
+ mnTemplateIndex = rDescriptor.mnTemplateIndex;
+ bIndexChanged = true;
+ }
+
+ // Prepare the list of event types that will be returned.
+ ::std::unique_ptr<std::vector<MasterPageContainerChangeEvent::EventType> > pResult;
+ if (bDataChanged || bIndexChanged || bPreviewChanged)
+ {
+ pResult.reset(new std::vector<MasterPageContainerChangeEvent::EventType>);
+ if (bDataChanged)
+ pResult->push_back(MasterPageContainerChangeEvent::EventType::DATA_CHANGED);
+ if (bIndexChanged)
+ pResult->push_back(MasterPageContainerChangeEvent::EventType::INDEX_CHANGED);
+ if (bPreviewChanged)
+ pResult->push_back(MasterPageContainerChangeEvent::EventType::PREVIEW_CHANGED);
+ }
+
+ return pResult;
+}
+
+int MasterPageDescriptor::UpdatePageObject (
+ sal_Int32 nCostThreshold,
+ SdDrawDocument* pDocument)
+{
+ int nModified = 0;
+
+ // Update the page object when that is not yet known.
+ if (mpMasterPage == nullptr && mpPageObjectProvider != nullptr
+ && (nCostThreshold < 0 || mpPageObjectProvider->GetCostIndex() <= nCostThreshold))
+ {
+ // Note that pDocument may be NULL.
+
+ SdPage* pPage = (*mpPageObjectProvider)(pDocument);
+ if (meOrigin == MasterPageContainer::MASTERPAGE)
+ {
+ mpMasterPage = pPage;
+ if (mpMasterPage != nullptr)
+ mpMasterPage->SetPrecious(mbIsPrecious);
+ }
+ else
+ {
+ // Master pages from templates are copied into the local document.
+ if (pDocument != nullptr)
+ mpMasterPage = DocumentHelper::CopyMasterPageToLocalDocument(*pDocument,pPage);
+ mpSlide = DocumentHelper::GetSlideForMasterPage(mpMasterPage);
+ }
+
+ if (mpMasterPage != nullptr)
+ {
+ // Update page name and style name.
+ if (msPageName.isEmpty())
+ msPageName = mpMasterPage->GetName();
+ msStyleName = mpMasterPage->GetName();
+
+ // Delete an existing substitution. The next request for a preview
+ // will create the real one.
+ maSmallPreview = Image();
+ maLargePreview = Image();
+ mpPreviewProvider = std::make_shared<PagePreviewProvider>();
+ }
+ else
+ {
+ SAL_WARN( "sd", "UpdatePageObject: master page is NULL");
+ return -1;
+ }
+
+ nModified = 1;
+ }
+
+ return nModified;
+}
+
+bool MasterPageDescriptor::UpdatePreview (
+ sal_Int32 nCostThreshold,
+ const Size& rSmallSize,
+ const Size& rLargeSize,
+ ::sd::PreviewRenderer& rRenderer)
+{
+ bool bModified (false);
+
+ // Update the preview when that is not yet known.
+ if (maLargePreview.GetSizePixel().Width() == 0 && mpPreviewProvider != nullptr
+ && (nCostThreshold < 0 || mpPreviewProvider->GetCostIndex() <= nCostThreshold))
+ {
+ SdPage* pPage = mpSlide;
+ if (pPage == nullptr)
+ {
+ pPage = mpMasterPage;
+ }
+ //TODO: Notify LOOL of preview updates.
+ maLargePreview = (*mpPreviewProvider)(
+ rLargeSize.Width(),
+ pPage,
+ rRenderer);
+ if (maLargePreview.GetSizePixel().Width() > 0)
+ {
+ // Create the small preview by scaling the large one down.
+ maSmallPreview = rRenderer.ScaleBitmap(
+ maLargePreview.GetBitmapEx(),
+ rSmallSize.Width());
+ // The large preview may not have the desired width. Scale it
+ // accordingly.
+ if (maLargePreview.GetSizePixel().Width() != rLargeSize.Width())
+ maLargePreview = rRenderer.ScaleBitmap(
+ maLargePreview.GetBitmapEx(),
+ rLargeSize.Width());
+ bModified = true;
+ }
+ }
+
+ return bModified;
+}
+
+MasterPageDescriptor::URLClassification MasterPageDescriptor::GetURLClassification()
+{
+ if (meURLClassification == URLCLASS_UNDETERMINED)
+ {
+ if (msURL.isEmpty())
+ meURLClassification = URLCLASS_UNKNOWN;
+ else if (msURL.indexOf("presnt")>=0)
+ {
+ meURLClassification = URLCLASS_PRESENTATION;
+ }
+ else if (msURL.indexOf("layout")>=0)
+ {
+ meURLClassification = URLCLASS_LAYOUT;
+ }
+ else if (msURL.indexOf("educate")>=0)
+ {
+ meURLClassification = URLCLASS_OTHER;
+ }
+ else
+ {
+ meURLClassification = URLCLASS_USER;
+ }
+ }
+
+ return meURLClassification;
+}
+
+//===== URLComparator =========================================================
+
+MasterPageDescriptor::URLComparator::URLComparator (const OUString& sURL)
+ : msURL(sURL)
+{
+}
+
+bool MasterPageDescriptor::URLComparator::operator() (
+ const SharedMasterPageDescriptor& rDescriptor)
+{
+ if (!rDescriptor)
+ return false;
+ else
+ return rDescriptor->msURL == msURL;
+}
+
+// ===== StyleNameComparator ==================================================
+
+MasterPageDescriptor::StyleNameComparator::StyleNameComparator (const OUString& sStyleName)
+ : msStyleName(sStyleName)
+{
+}
+
+bool MasterPageDescriptor::StyleNameComparator::operator() (
+ const SharedMasterPageDescriptor& rDescriptor)
+{
+ if (!rDescriptor)
+ return false;
+ else
+ return rDescriptor->msStyleName == msStyleName;
+}
+
+//===== PageObjectComparator ==================================================
+
+MasterPageDescriptor::PageObjectComparator::PageObjectComparator (const SdPage* pPageObject)
+ : mpMasterPage(pPageObject)
+{
+}
+
+bool MasterPageDescriptor::PageObjectComparator::operator() (
+ const SharedMasterPageDescriptor& rDescriptor)
+{
+ if (!rDescriptor)
+ return false;
+ else
+ return rDescriptor->mpMasterPage==mpMasterPage;
+}
+
+//===== AllComparator =========================================================
+
+MasterPageDescriptor::AllComparator::AllComparator(const SharedMasterPageDescriptor& rDescriptor)
+ : mpDescriptor(rDescriptor)
+{
+}
+
+bool MasterPageDescriptor::AllComparator::operator() (const SharedMasterPageDescriptor&rDescriptor)
+{
+ if (!rDescriptor)
+ return false;
+ else
+ {
+ // Take URL, page name, style name, and page object into account
+ // when comparing two descriptors. When two descriptors are
+ // identical in any of these values then there are thought of as
+ // equivalent. Only the Origin has to be the same in both
+ // descriptors.
+ return mpDescriptor->meOrigin == rDescriptor->meOrigin
+ && ((!mpDescriptor->msURL.isEmpty() && mpDescriptor->msURL == rDescriptor->msURL)
+ || (!mpDescriptor->msPageName.isEmpty()
+ && mpDescriptor->msPageName == rDescriptor->msPageName)
+ || (!mpDescriptor->msStyleName.isEmpty()
+ && mpDescriptor->msStyleName == rDescriptor->msStyleName)
+ || (mpDescriptor->mpMasterPage != nullptr
+ && mpDescriptor->mpMasterPage == rDescriptor->mpMasterPage)
+ || (mpDescriptor->mpPageObjectProvider != nullptr
+ && rDescriptor->mpPageObjectProvider != nullptr
+ && mpDescriptor->mpPageObjectProvider == rDescriptor->mpPageObjectProvider));
+ }
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageDescriptor.hxx b/sd/source/ui/sidebar/MasterPageDescriptor.hxx
new file mode 100644
index 000000000..62717e528
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageDescriptor.hxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MasterPageContainer.hxx"
+#include <memory>
+
+namespace sd { class PreviewRenderer; }
+class SdDrawDocument;
+
+namespace sd::sidebar {
+
+class PageObjectProvider;
+class PreviewProvider;
+
+class MasterPageDescriptor;
+typedef std::shared_ptr<MasterPageDescriptor> SharedMasterPageDescriptor;
+
+/** A collection of data that is stored for every master page in the
+ MasterpageContainer.
+*/
+class MasterPageDescriptor
+{
+public:
+ MasterPageDescriptor (
+ MasterPageContainer::Origin eOrigin,
+ const sal_Int32 nTemplateIndex,
+ std::u16string_view rURL,
+ const OUString& rPageName,
+ const OUString& rStyleName,
+ const bool bIsPrecious,
+ const std::shared_ptr<PageObjectProvider>& rpPageObjectProvider,
+ const std::shared_ptr<PreviewProvider>& rpPreviewProvider);
+
+ void SetToken (MasterPageContainer::Token aToken);
+
+ /** Update the called MasterPageDescriptor object with values from the
+ given one. Only those values are updated that have default values
+ in the called object and that have non-default values in the given
+ one.
+ @return
+ Returns a list of event types for which event notifications have
+ to be sent to listeners. The list may be empty or NULL.
+ */
+ ::std::unique_ptr<std::vector<MasterPageContainerChangeEvent::EventType> >
+ Update (
+ const MasterPageDescriptor& rDescriptor);
+
+ /** This convenience method returns either a small or a large preview,
+ depending on the given size specifier.
+ Note that the previews are not created when they are not present.
+ @return
+ The returned preview may be empty.
+ */
+ const Image& GetPreview (MasterPageContainer::PreviewSize ePreviewSize) const;
+
+ /** Use the PreviewProvider to get access to a preview of the master
+ page.
+
+ Note that this is only done, when either bForce is <TRUE/> or
+ the PreviewProvider::GetCostIndex() returns 0.
+
+ The small preview is created by scaling the large one, not by
+ calling PreviewProvider::operator() a second time.
+
+ It is the responsibility of the caller to call UpdatePageObject()
+ before calling this method when the PreviewProvider can only work
+ when the master page object is present, i.e. its NeedsPageObject()
+ method returns <TRUE/>.
+
+ @param nCostThreshold
+ When this is zero or positive then the preview is created only
+ when the preview provider has a cost equal to or smaller than
+ this threshold. A negative value forces the preview to be
+ created, regardless of the cost.
+ @param rSmallSize
+ Size of the small preview.
+ @param rLargeSize
+ Size of the large preview.
+ @param rRenderer
+ A PreviewRenderer object that may be used to create a preview.
+ @return
+ When the previews are successfully provided then <TRUE/> is
+ returned.
+ */
+ bool UpdatePreview (
+ sal_Int32 nCostThreshold,
+ const Size& rSmallSize,
+ const Size& rLargeSize,
+ ::sd::PreviewRenderer& rRenderer);
+
+ /** Use the PageObjectProvider to get access to the master page object.
+
+ Note that this is only done, when either bForce is <TRUE/> or the
+ PreviewProvider::GetCostIndex() returns 0.
+
+ @param nCostThreshold
+ When this is zero or positive then the page object is created
+ only when the page object provider has a cost equal to or
+ smaller than this threshold. A negative value forces the
+ page object be created, regardless of the cost.
+ @param pDocument
+ This document of the MasterPageContainer may be used to create
+ a page object with or store one in.
+ @return
+ When the master page object is successfully provided then
+ 1 is returned, on no change then a 0 is provided,
+ on a masterpage-error a -1 is provided.
+ */
+ int UpdatePageObject (
+ sal_Int32 nCostThreshold,
+ SdDrawDocument* pDocument);
+
+ enum URLClassification {
+ URLCLASS_USER,
+ URLCLASS_LAYOUT,
+ URLCLASS_PRESENTATION,
+ URLCLASS_OTHER,
+ URLCLASS_UNKNOWN,
+ URLCLASS_UNDETERMINED
+ };
+
+ URLClassification GetURLClassification();
+
+ /** The Token under which the MasterPageContainer gives access to the
+ object.
+ */
+ MasterPageContainer::Token maToken;
+
+ /** A rough specification of the origin of the master page.
+ */
+ MasterPageContainer::Origin meOrigin;
+
+ /** The URL is not empty for master pages loaded from a template
+ document.
+ */
+ OUString msURL;
+
+ /** Taken from the title of the template file.
+ */
+ OUString msPageName;
+
+ /** Taken from the master page object.
+ */
+ OUString msStyleName;
+
+ const bool mbIsPrecious;
+
+ /** The actual master page.
+ */
+ SdPage* mpMasterPage;
+
+ /** A slide that uses the master page.
+ */
+ SdPage* mpSlide;
+
+ /** A small (the default size) preview of the master page. May be
+ empty. When this smaller preview is not empty then the larger one
+ is not empty, too.
+ */
+ Image maSmallPreview;
+
+ /** A large preview of the master page. May be empty. When this larger
+ preview is not empty then the smaller one is not empty, too.
+ */
+ Image maLargePreview;
+
+ /** The preview provider. May be empty. May be replaced during the
+ lifetime of a MasterPageDescriptor object.
+ */
+ std::shared_ptr<PreviewProvider> mpPreviewProvider;
+
+ /** The master page provider. May be empty. May be replaced during
+ the lifetime of a MasterPageDescriptor object.
+ */
+ std::shared_ptr<PageObjectProvider> mpPageObjectProvider;
+
+ /** This index represents the order in which templates are provided via
+ the TemplateScanner. It defines the order in which the entries in
+ the AllMasterPagesSelector are displayed. The default value is -1.
+ */
+ sal_Int32 mnTemplateIndex;
+
+ URLClassification meURLClassification;
+
+ sal_Int32 mnUseCount;
+
+ class URLComparator { public:
+ OUString msURL;
+ explicit URLComparator (const OUString& sURL);
+ bool operator() (const SharedMasterPageDescriptor& rDescriptor);
+ };
+ class StyleNameComparator { public:
+ OUString msStyleName;
+ explicit StyleNameComparator (const OUString& sStyleName);
+ bool operator() (const SharedMasterPageDescriptor& rDescriptor);
+ };
+ class PageObjectComparator { public:
+ const SdPage* mpMasterPage;
+ explicit PageObjectComparator (const SdPage* pPageObject);
+ bool operator() (const SharedMasterPageDescriptor& rDescriptor);
+ };
+ class AllComparator { public:
+ explicit AllComparator(const SharedMasterPageDescriptor& rDescriptor);
+ bool operator() (const SharedMasterPageDescriptor& rDescriptor);
+ private:
+ SharedMasterPageDescriptor mpDescriptor;
+ };
+
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPageObserver.cxx b/sd/source/ui/sidebar/MasterPageObserver.cxx
new file mode 100644
index 000000000..017a0bcdf
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPageObserver.cxx
@@ -0,0 +1,317 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <MasterPageObserver.hxx>
+
+#include <algorithm>
+#include <iterator>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <set>
+#include <unordered_map>
+#include <memory>
+#include <vector>
+#include <svl/lstner.hxx>
+#include <osl/doublecheckedlocking.h>
+#include <osl/getglobalmutex.hxx>
+#include <tools/debug.hxx>
+
+namespace sd {
+
+class MasterPageObserver::Implementation
+ : public SfxListener
+{
+public:
+ /** The single instance of this class. It is created on demand when
+ Instance() is called for the first time.
+ */
+ static MasterPageObserver* mpInstance;
+
+ /** The master page observer will listen to events of this document and
+ detect changes of the use of master pages.
+ */
+ void RegisterDocument (SdDrawDocument& rDocument);
+
+ /** The master page observer will stop to listen to events of this
+ document.
+ */
+ void UnregisterDocument (SdDrawDocument& rDocument);
+
+ /** Add a listener that is informed of master pages that are newly
+ assigned to slides or become unassigned.
+ @param rEventListener
+ The event listener to call for future events. Call
+ RemoveEventListener() before the listener is destroyed.
+ */
+ void AddEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener);
+
+ /** Remove the given listener from the list of listeners.
+ @param rEventListener
+ After this method returns the given listener is not called back
+ from this object. Passing a listener that has not
+ been registered before is safe and is silently ignored.
+ */
+ void RemoveEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener);
+
+private:
+ ::std::vector<Link<MasterPageObserverEvent&,void>> maListeners;
+
+ struct DrawDocHash {
+ size_t operator()(SdDrawDocument* argument) const
+ { return reinterpret_cast<sal_uIntPtr>(argument); }
+ };
+ typedef std::unordered_map<SdDrawDocument*,
+ MasterPageObserver::MasterPageNameSet,
+ DrawDocHash>
+ MasterPageContainer;
+ MasterPageContainer maUsedMasterPages;
+
+ virtual void Notify(
+ SfxBroadcaster& rBroadcaster,
+ const SfxHint& rHint) override;
+
+ void AnalyzeUsedMasterPages (SdDrawDocument& rDocument);
+
+ void SendEvent (MasterPageObserverEvent& rEvent);
+};
+
+MasterPageObserver* MasterPageObserver::Implementation::mpInstance = nullptr;
+
+//===== MasterPageObserver ====================================================
+
+MasterPageObserver& MasterPageObserver::Instance()
+{
+ if (Implementation::mpInstance == nullptr)
+ {
+ ::osl::GetGlobalMutex aMutexFunctor;
+ ::osl::MutexGuard aGuard (aMutexFunctor());
+ if (Implementation::mpInstance == nullptr)
+ {
+ MasterPageObserver* pInstance = new MasterPageObserver ();
+ SdGlobalResourceContainer::Instance().AddResource (
+ ::std::unique_ptr<SdGlobalResource>(pInstance));
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ Implementation::mpInstance = pInstance;
+ }
+ }
+ else
+ {
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ }
+
+ DBG_ASSERT(Implementation::mpInstance!=nullptr,
+ "MasterPageObserver::Instance(): instance is NULL");
+ return *Implementation::mpInstance;
+}
+
+void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument)
+{
+ mpImpl->RegisterDocument (rDocument);
+}
+
+void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument)
+{
+ mpImpl->UnregisterDocument (rDocument);
+}
+
+void MasterPageObserver::AddEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener)
+{
+
+ mpImpl->AddEventListener (rEventListener);
+}
+
+void MasterPageObserver::RemoveEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener)
+{
+ mpImpl->RemoveEventListener (rEventListener);
+}
+
+MasterPageObserver::MasterPageObserver()
+ : mpImpl (new Implementation)
+{}
+
+MasterPageObserver::~MasterPageObserver()
+{}
+
+//===== MasterPageObserver::Implementation ====================================
+
+void MasterPageObserver::Implementation::RegisterDocument (
+ SdDrawDocument& rDocument)
+{
+ // Gather the names of all the master pages in the given document.
+ MasterPageContainer::mapped_type aMasterPageSet;
+ sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PageKind::Standard);
+ for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
+ {
+ SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PageKind::Standard);
+ if (pMasterPage != nullptr)
+ aMasterPageSet.insert (pMasterPage->GetName());
+ }
+
+ bool bAlreadyExists = maUsedMasterPages.find(&rDocument) != maUsedMasterPages.end();
+ maUsedMasterPages[&rDocument] = aMasterPageSet;
+
+ if (!bAlreadyExists)
+ StartListening (rDocument);
+}
+
+void MasterPageObserver::Implementation::UnregisterDocument (
+ SdDrawDocument& rDocument)
+{
+ EndListening (rDocument);
+
+ MasterPageContainer::iterator aMasterPageDescriptor(maUsedMasterPages.find(&rDocument));
+ if(aMasterPageDescriptor != maUsedMasterPages.end())
+ maUsedMasterPages.erase(aMasterPageDescriptor);
+}
+
+void MasterPageObserver::Implementation::AddEventListener (
+ const Link<MasterPageObserverEvent&,void>& rEventListener)
+{
+ if (::std::find (
+ maListeners.begin(),
+ maListeners.end(),
+ rEventListener) != maListeners.end())
+ return;
+
+ maListeners.push_back (rEventListener);
+
+ // Tell the new listener about all the master pages that are
+ // currently in use.
+ for (const auto& rDocument : maUsedMasterPages)
+ {
+ ::std::set<OUString>::reverse_iterator aNameIterator;
+ for (aNameIterator=rDocument.second.rbegin();
+ aNameIterator!=rDocument.second.rend();
+ ++aNameIterator)
+ {
+ MasterPageObserverEvent aEvent (
+ MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
+ *aNameIterator);
+ SendEvent (aEvent);
+ }
+ }
+}
+
+void MasterPageObserver::Implementation::RemoveEventListener (
+ const Link<MasterPageObserverEvent&,void>& rEventListener)
+{
+ maListeners.erase (
+ ::std::find (
+ maListeners.begin(),
+ maListeners.end(),
+ rEventListener));
+}
+
+void MasterPageObserver::Implementation::Notify(
+ SfxBroadcaster& rBroadcaster,
+ const SfxHint& rHint)
+{
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+
+ switch (pSdrHint->GetKind())
+ {
+ case SdrHintKind::PageOrderChange:
+ // Process the modified set of pages only when the number of
+ // standard and notes master pages are equal. This test
+ // filters out events that are sent in between the insertion
+ // of a new standard master page and a new notes master
+ // page.
+ if (auto pDrawDocument = dynamic_cast<SdDrawDocument *>( &rBroadcaster ))
+ {
+ if (pDrawDocument->GetMasterSdPageCount(PageKind::Standard)
+ == pDrawDocument->GetMasterSdPageCount(PageKind::Notes))
+ {
+ AnalyzeUsedMasterPages (*pDrawDocument);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
+ SdDrawDocument& rDocument)
+{
+ // Create a set of names of the master pages used by the given document.
+ sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PageKind::Standard);
+ ::std::set<OUString> aCurrentMasterPages;
+ for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
+ {
+ SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PageKind::Standard);
+ if (pMasterPage != nullptr)
+ aCurrentMasterPages.insert (pMasterPage->GetName());
+ }
+
+ std::vector<OUString> aNewMasterPages;
+ std::vector<OUString> aRemovedMasterPages;
+ MasterPageContainer::iterator aOldMasterPagesDescriptor (
+ maUsedMasterPages.find(&rDocument));
+ if (aOldMasterPagesDescriptor == maUsedMasterPages.end())
+ return;
+
+ // Send events about the newly used master pages.
+ ::std::set_difference (
+ aCurrentMasterPages.begin(),
+ aCurrentMasterPages.end(),
+ aOldMasterPagesDescriptor->second.begin(),
+ aOldMasterPagesDescriptor->second.end(),
+ std::back_inserter(aNewMasterPages));
+ for (const auto& aNewMasterPage : aNewMasterPages)
+ {
+ MasterPageObserverEvent aEvent (
+ MasterPageObserverEvent::ET_MASTER_PAGE_ADDED,
+ aNewMasterPage);
+ SendEvent (aEvent);
+ }
+
+ // Send events about master pages that are not used any longer.
+ ::std::set_difference (
+ aOldMasterPagesDescriptor->second.begin(),
+ aOldMasterPagesDescriptor->second.end(),
+ aCurrentMasterPages.begin(),
+ aCurrentMasterPages.end(),
+ std::back_inserter(aRemovedMasterPages));
+ for (const auto& aRemovedMasterPage : aRemovedMasterPages)
+ {
+ MasterPageObserverEvent aEvent (
+ MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED,
+ aRemovedMasterPage);
+ SendEvent (aEvent);
+ }
+
+ // Store the new list of master pages.
+ aOldMasterPagesDescriptor->second = aCurrentMasterPages;
+}
+
+void MasterPageObserver::Implementation::SendEvent (
+ MasterPageObserverEvent& rEvent)
+{
+ for (const auto& aLink : maListeners)
+ {
+ aLink.Call(rEvent);
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPagesSelector.cxx b/sd/source/ui/sidebar/MasterPagesSelector.cxx
new file mode 100644
index 000000000..979726910
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPagesSelector.cxx
@@ -0,0 +1,620 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <utility>
+
+#include "MasterPagesSelector.hxx"
+
+#include "MasterPageContainer.hxx"
+#include "DocumentHelper.hxx"
+#include <pres.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <app.hrc>
+
+#include <DrawController.hxx>
+#include <SlideSorterViewShell.hxx>
+#include "PreviewValueSet.hxx"
+#include <ViewShellBase.hxx>
+#include <o3tl/safeint.hxx>
+#include <vcl/image.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sidebar/Theme.hxx>
+#include <memory>
+
+using namespace ::com::sun::star::text;
+
+namespace sd::sidebar {
+
+ /** menu entry that is executed as default action when the left mouse button is
+ clicked over a master page.
+ */
+constexpr OStringLiteral gsDefaultClickAction = "applyselect";
+
+MasterPagesSelector::MasterPagesSelector (
+ weld::Widget* pParent,
+ SdDrawDocument& rDocument,
+ ViewShellBase& rBase,
+ const std::shared_ptr<MasterPageContainer>& rpContainer,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar,
+ const OUString& rUIFileName,
+ const OString& rValueSetName)
+ : PanelLayout( pParent, "MasterPagePanel", rUIFileName ),
+ mpContainer(rpContainer),
+ mxPreviewValueSet(new PreviewValueSet),
+ mxPreviewValueSetWin(new weld::CustomWeld(*m_xBuilder, rValueSetName, *mxPreviewValueSet)),
+ mrDocument(rDocument),
+ mrBase(rBase),
+ mxSidebar(rxSidebar)
+{
+ mxPreviewValueSet->SetSelectHdl (
+ LINK(this, MasterPagesSelector, ClickHandler));
+ mxPreviewValueSet->SetContextMenuHandler (
+ LINK(this, MasterPagesSelector, ContextMenuHandler));
+ mxPreviewValueSet->SetStyle(mxPreviewValueSet->GetStyle() | WB_NO_DIRECTSELECT);
+
+ if (mxPreviewValueSet->GetDrawingArea()->get_ref_device().GetDPIScaleFactor() > 1)
+ mpContainer->SetPreviewSize(MasterPageContainer::LARGE);
+
+ mxPreviewValueSet->SetPreviewSize(mpContainer->GetPreviewSizePixel());
+ mxPreviewValueSet->Show();
+
+ mxPreviewValueSet->SetColor(sfx2::sidebar::Theme::GetColor(sfx2::sidebar::Theme::Color_PanelBackground));
+
+ Link<MasterPageContainerChangeEvent&,void> aChangeListener (LINK(this,MasterPagesSelector,ContainerChangeListener));
+ mpContainer->AddChangeListener(aChangeListener);
+}
+
+MasterPagesSelector::~MasterPagesSelector()
+{
+ Clear();
+ UpdateLocks(ItemList());
+
+ Link<MasterPageContainerChangeEvent&,void> aChangeListener (LINK(this,MasterPagesSelector,ContainerChangeListener));
+ mpContainer->RemoveChangeListener(aChangeListener);
+ mpContainer.reset();
+ mxPreviewValueSetWin.reset();
+ mxPreviewValueSet.reset();
+}
+
+void MasterPagesSelector::LateInit()
+{
+}
+
+sal_Int32 MasterPagesSelector::GetPreferredHeight (sal_Int32 nWidth)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ return mxPreviewValueSet->GetPreferredHeight (nWidth);
+}
+
+void MasterPagesSelector::UpdateLocks (const ItemList& rItemList)
+{
+ ItemList aNewLockList;
+
+ // In here we first lock the master pages in the given list and then
+ // release the locks acquired in a previous call to this method. When
+ // this were done the other way round the lock count of some master
+ // pages might drop temporarily to 0 and would lead to unnecessary
+ // deletion and re-creation of MasterPageDescriptor objects.
+
+ // Lock the master pages in the given list.
+ for (const auto& rItem : rItemList)
+ {
+ mpContainer->AcquireToken(rItem);
+ aNewLockList.push_back(rItem);
+ }
+
+ // Release the previously locked master pages.
+ for (const auto& rPage : maLockedMasterPages)
+ mpContainer->ReleaseToken(rPage);
+
+ maLockedMasterPages.swap(aNewLockList);
+}
+
+void MasterPagesSelector::Fill()
+{
+ ::std::unique_ptr<ItemList> pItemList (new ItemList);
+
+ Fill(*pItemList);
+
+ UpdateLocks(*pItemList);
+ UpdateItemList(std::move(pItemList));
+}
+
+OUString MasterPagesSelector::GetContextMenuUIFile() const
+{
+ return "modules/simpress/ui/mastermenu.ui";
+}
+
+IMPL_LINK_NOARG(MasterPagesSelector, ClickHandler, ValueSet*, void)
+{
+ // We use the framework to assign the clicked-on master page because we
+ // so use the same mechanism as the context menu does (where we do not
+ // have the option to call the assignment method directly.)
+ ExecuteCommand(gsDefaultClickAction);
+}
+
+IMPL_LINK(MasterPagesSelector, ContextMenuHandler, const Point*, pPos, void)
+{
+ if (pPos)
+ {
+ // Here we only prepare the display of the context menu: on right
+ // click the item under the mouse is selected.
+ mxPreviewValueSet->GrabFocus();
+ mxPreviewValueSet->ReleaseMouse();
+
+ sal_uInt16 nIndex = mxPreviewValueSet->GetItemId(*pPos);
+ if (nIndex > 0)
+ mxPreviewValueSet->SelectItem(nIndex);
+ }
+
+ // Now do the actual display of the context menu
+ ShowContextMenu(pPos);
+}
+
+void MasterPagesSelector::ShowContextMenu(const Point* pPos)
+{
+ // Use the currently selected item and show the popup menu in its
+ // center.
+ const sal_uInt16 nIndex = mxPreviewValueSet->GetSelectedItemId();
+ if (nIndex <= 0)
+ return;
+
+ // The position of the upper left corner of the context menu is
+ // taken either from the mouse position (when the command was sent
+ // as reaction to a right click) or in the center of the selected
+ // item (when the command was sent as reaction to Shift+F10.)
+ Point aPosition;
+ if (!pPos)
+ {
+ ::tools::Rectangle aBBox (mxPreviewValueSet->GetItemRect(nIndex));
+ aPosition = aBBox.Center();
+ }
+ else
+ aPosition = *pPos;
+
+ // Setup the menu.
+ weld::Widget* pParent = mxPreviewValueSet->GetDrawingArea();
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pParent, GetContextMenuUIFile()));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+ ProcessPopupMenu(*xMenu);
+ ::tools::Rectangle aRect(aPosition, Size(1,1));
+ // Show the menu.
+ ExecuteCommand(xMenu->popup_at_rect(pParent, aRect));
+}
+
+void MasterPagesSelector::ProcessPopupMenu(weld::Menu& rMenu)
+{
+ // Disable some entries.
+ if (mpContainer->GetPreviewSize() == MasterPageContainer::SMALL)
+ rMenu.set_sensitive("small", false);
+ else
+ rMenu.set_sensitive("large", false);
+}
+
+void MasterPagesSelector::ExecuteCommand(const OString &rIdent)
+{
+ if (rIdent == "applyall")
+ {
+ mrBase.SetBusyState (true);
+ AssignMasterPageToAllSlides (GetSelectedMasterPage());
+ mrBase.SetBusyState (false);
+ }
+ else if (rIdent == "applyselect")
+ {
+ mrBase.SetBusyState (true);
+ AssignMasterPageToSelectedSlides (GetSelectedMasterPage());
+ mrBase.SetBusyState (false);
+ }
+ else if (rIdent == "large")
+ {
+ mrBase.SetBusyState (true);
+ mpContainer->SetPreviewSize(MasterPageContainer::LARGE);
+ mrBase.SetBusyState (false);
+ if (mxSidebar.is())
+ mxSidebar->requestLayout();
+ }
+ else if (rIdent == "small")
+ {
+ mrBase.SetBusyState (true);
+ mpContainer->SetPreviewSize(MasterPageContainer::SMALL);
+ mrBase.SetBusyState (false);
+ if (mxSidebar.is())
+ mxSidebar->requestLayout();
+ }
+ else if (rIdent == "edit")
+ {
+ using namespace ::com::sun::star;
+ uno::Reference<drawing::XDrawPage> xSelectedMaster;
+ SdPage* pMasterPage = GetSelectedMasterPage();
+ assert(pMasterPage); //rhbz#902884
+ if (pMasterPage)
+ xSelectedMaster.set(pMasterPage->getUnoPage(), uno::UNO_QUERY);
+ SfxViewFrame* pViewFrame = mrBase.GetViewFrame();
+ if (pViewFrame != nullptr && xSelectedMaster.is())
+ {
+ SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher();
+ if (pDispatcher != nullptr)
+ {
+ sal_uInt16 nIndex = mxPreviewValueSet->GetSelectedItemId();
+ pDispatcher->Execute(SID_MASTERPAGE, SfxCallMode::SYNCHRON);
+ mxPreviewValueSet->SelectItem (nIndex);
+ mrBase.GetDrawController().setCurrentPage(xSelectedMaster);
+ }
+ }
+ }
+}
+
+IMPL_LINK(MasterPagesSelector, ContainerChangeListener, MasterPageContainerChangeEvent&, rEvent, void)
+{
+ NotifyContainerChangeEvent(rEvent);
+}
+
+SdPage* MasterPagesSelector::GetSelectedMasterPage()
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ SdPage* pMasterPage = nullptr;
+ sal_uInt16 nIndex = mxPreviewValueSet->GetSelectedItemId();
+ UserData* pData = GetUserData(nIndex);
+ if (pData != nullptr)
+ {
+ pMasterPage = mpContainer->GetPageObjectForToken(pData->second, true);
+ }
+ return pMasterPage;
+}
+
+/** Assemble a list of all slides of the document and pass it to
+ AssignMasterPageToPageList().
+*/
+void MasterPagesSelector::AssignMasterPageToAllSlides (SdPage* pMasterPage)
+{
+ if (pMasterPage == nullptr)
+ return;
+
+ sal_uInt16 nPageCount = mrDocument.GetSdPageCount(PageKind::Standard);
+ if (nPageCount == 0)
+ return;
+
+ // Get a list of all pages. As a little optimization we only
+ // include pages that do not already have the given master page
+ // assigned.
+ OUString sFullLayoutName(pMasterPage->GetLayoutName());
+ ::sd::slidesorter::SharedPageSelection pPageList =
+ std::make_shared<::sd::slidesorter::SlideSorterViewShell::PageSelection>();
+ for (sal_uInt16 nPageIndex=0; nPageIndex<nPageCount; nPageIndex++)
+ {
+ SdPage* pPage = mrDocument.GetSdPage (nPageIndex, PageKind::Standard);
+ if (pPage != nullptr && pPage->GetLayoutName() != sFullLayoutName)
+ {
+ pPageList->push_back (pPage);
+ }
+ }
+
+ AssignMasterPageToPageList(pMasterPage, pPageList);
+}
+
+/** Assemble a list of the currently selected slides (selected in a visible
+ slide sorter) and pass it to AssignMasterPageToPageList().
+*/
+void MasterPagesSelector::AssignMasterPageToSelectedSlides (
+ SdPage* pMasterPage)
+{
+ using namespace ::sd::slidesorter;
+ using namespace ::sd::slidesorter::controller;
+
+ if (pMasterPage == nullptr)
+ return;
+
+ // Find a visible slide sorter.
+ SlideSorterViewShell* pSlideSorter = SlideSorterViewShell::GetSlideSorter(mrBase);
+ if (pSlideSorter == nullptr)
+ return;
+
+ // Get a list of selected pages.
+ SharedPageSelection pPageSelection = pSlideSorter->GetPageSelection();
+ if (pPageSelection->empty())
+ return;
+
+ AssignMasterPageToPageList(pMasterPage, pPageSelection);
+
+ // Restore the previous selection.
+ pSlideSorter->SetPageSelection(pPageSelection);
+}
+
+void MasterPagesSelector::AssignMasterPageToPageList (
+ SdPage* pMasterPage,
+ const std::shared_ptr<std::vector<SdPage*>>& rPageList)
+{
+ DocumentHelper::AssignMasterPageToPageList(mrDocument, pMasterPage, rPageList);
+}
+
+void MasterPagesSelector::NotifyContainerChangeEvent (const MasterPageContainerChangeEvent& rEvent)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ switch (rEvent.meEventType)
+ {
+ case MasterPageContainerChangeEvent::EventType::SIZE_CHANGED:
+ mxPreviewValueSet->SetPreviewSize(mpContainer->GetPreviewSizePixel());
+ UpdateAllPreviews();
+ break;
+
+ case MasterPageContainerChangeEvent::EventType::PREVIEW_CHANGED:
+ {
+ int nIndex (GetIndexForToken(rEvent.maChildToken));
+ if (nIndex >= 0)
+ {
+ mxPreviewValueSet->SetItemImage (
+ static_cast<sal_uInt16>(nIndex),
+ mpContainer->GetPreviewForToken(rEvent.maChildToken));
+ mxPreviewValueSet->Invalidate(mxPreviewValueSet->GetItemRect(static_cast<sal_uInt16>(nIndex)));
+ }
+ }
+ break;
+
+ case MasterPageContainerChangeEvent::EventType::DATA_CHANGED:
+ {
+ InvalidateItem(rEvent.maChildToken);
+ Fill();
+ }
+ break;
+
+ case MasterPageContainerChangeEvent::EventType::CHILD_REMOVED:
+ {
+ int nIndex (GetIndexForToken(rEvent.maChildToken));
+ SetItem(nIndex, MasterPageContainer::NIL_TOKEN);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+MasterPagesSelector::UserData* MasterPagesSelector::GetUserData (int nIndex) const
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ if (nIndex>0 && o3tl::make_unsigned(nIndex)<=mxPreviewValueSet->GetItemCount())
+ return static_cast<UserData*>(mxPreviewValueSet->GetItemData(static_cast<sal_uInt16>(nIndex)));
+ else
+ return nullptr;
+}
+
+void MasterPagesSelector::SetUserData (int nIndex, std::unique_ptr<UserData> pData)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ delete GetUserData(nIndex);
+ mxPreviewValueSet->SetItemData(static_cast<sal_uInt16>(nIndex), pData.release());
+}
+
+void MasterPagesSelector::SetItem (
+ sal_uInt16 nIndex,
+ MasterPageContainer::Token aToken)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ RemoveTokenToIndexEntry(nIndex,aToken);
+
+ if (nIndex <= 0)
+ return;
+
+ if (aToken != MasterPageContainer::NIL_TOKEN)
+ {
+ Image aPreview (mpContainer->GetPreviewForToken(aToken));
+ MasterPageContainer::PreviewState eState (mpContainer->GetPreviewState(aToken));
+
+ if (aPreview.GetSizePixel().Width()>0)
+ {
+ if (mxPreviewValueSet->GetItemPos(nIndex) != VALUESET_ITEM_NOTFOUND)
+ {
+ mxPreviewValueSet->SetItemImage(nIndex,aPreview);
+ mxPreviewValueSet->SetItemText(nIndex, mpContainer->GetPageNameForToken(aToken));
+ }
+ else
+ {
+ mxPreviewValueSet->InsertItem (
+ nIndex,
+ aPreview,
+ mpContainer->GetPageNameForToken(aToken),
+ nIndex);
+ }
+ SetUserData(nIndex, std::make_unique<UserData>(nIndex,aToken));
+
+ AddTokenToIndexEntry(nIndex,aToken);
+ }
+
+ if (eState == MasterPageContainer::PS_CREATABLE)
+ mpContainer->RequestPreview(aToken);
+ }
+ else
+ {
+ mxPreviewValueSet->RemoveItem(nIndex);
+ }
+
+}
+
+void MasterPagesSelector::AddTokenToIndexEntry (
+ sal_uInt16 nIndex,
+ MasterPageContainer::Token aToken)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ maTokenToValueSetIndex[aToken] = nIndex;
+}
+
+void MasterPagesSelector::RemoveTokenToIndexEntry (
+ sal_uInt16 nIndex,
+ MasterPageContainer::Token aNewToken)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ UserData* pData = GetUserData(nIndex);
+ if (pData != nullptr)
+ {
+ // Get the token that the index pointed to previously.
+ MasterPageContainer::Token aOldToken (pData->second);
+
+ if (aNewToken != aOldToken
+ && nIndex == GetIndexForToken(aOldToken))
+ {
+ maTokenToValueSetIndex[aOldToken] = 0;
+ }
+ }
+}
+
+void MasterPagesSelector::InvalidatePreview (const SdPage* pPage)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ for (size_t nIndex=1; nIndex<=mxPreviewValueSet->GetItemCount(); nIndex++)
+ {
+ UserData* pData = GetUserData(nIndex);
+ if (pData != nullptr)
+ {
+ MasterPageContainer::Token aToken (pData->second);
+ if (pPage == mpContainer->GetPageObjectForToken(aToken,false))
+ {
+ mpContainer->InvalidatePreview(aToken);
+ mpContainer->RequestPreview(aToken);
+ break;
+ }
+ }
+ }
+}
+
+void MasterPagesSelector::UpdateAllPreviews()
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ for (size_t nIndex=1; nIndex<=mxPreviewValueSet->GetItemCount(); nIndex++)
+ {
+ UserData* pData = GetUserData(nIndex);
+ if (pData != nullptr)
+ {
+ MasterPageContainer::Token aToken (pData->second);
+ mxPreviewValueSet->SetItemImage(
+ nIndex,
+ mpContainer->GetPreviewForToken(aToken));
+ if (mpContainer->GetPreviewState(aToken) == MasterPageContainer::PS_CREATABLE)
+ mpContainer->RequestPreview(aToken);
+ }
+ }
+ mxPreviewValueSet->Rearrange();
+}
+
+void MasterPagesSelector::ClearPageSet()
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ for (size_t nIndex=1; nIndex<=mxPreviewValueSet->GetItemCount(); nIndex++)
+ {
+ UserData* pData = GetUserData(nIndex);
+ delete pData;
+ }
+ mxPreviewValueSet->Clear();
+}
+
+void MasterPagesSelector::SetHelpId( const OString& aId )
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ mxPreviewValueSet->SetHelpId( aId );
+}
+
+sal_Int32 MasterPagesSelector::GetIndexForToken (MasterPageContainer::Token aToken) const
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ TokenToValueSetIndex::const_iterator iIndex (maTokenToValueSetIndex.find(aToken));
+ if (iIndex != maTokenToValueSetIndex.end())
+ return iIndex->second;
+ else
+ return -1;
+}
+
+void MasterPagesSelector::Clear()
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ ClearPageSet();
+}
+
+void MasterPagesSelector::InvalidateItem (MasterPageContainer::Token aToken)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ auto iItem = std::find(maCurrentItemList.begin(), maCurrentItemList.end(), aToken);
+ if (iItem != maCurrentItemList.end())
+ *iItem = MasterPageContainer::NIL_TOKEN;
+}
+
+void MasterPagesSelector::UpdateItemList (::std::unique_ptr<ItemList> && pNewItemList)
+{
+ const ::osl::MutexGuard aGuard (maMutex);
+
+ ItemList::const_iterator iNewItem (pNewItemList->begin());
+ ItemList::const_iterator iCurrentItem (maCurrentItemList.begin());
+ ItemList::const_iterator iNewEnd (pNewItemList->end());
+ ItemList::const_iterator iCurrentEnd (maCurrentItemList.end());
+ sal_uInt16 nIndex (1);
+
+ // Update existing items.
+ for ( ; iNewItem!=iNewEnd && iCurrentItem!=iCurrentEnd; ++iNewItem, ++iCurrentItem,++nIndex)
+ {
+ if (*iNewItem != *iCurrentItem)
+ {
+ SetItem(nIndex,*iNewItem);
+ }
+ }
+
+ // Append new items.
+ for ( ; iNewItem!=iNewEnd; ++iNewItem,++nIndex)
+ {
+ SetItem(nIndex,*iNewItem);
+ }
+
+ // Remove trailing items.
+ for ( ; iCurrentItem!=iCurrentEnd; ++iCurrentItem,++nIndex)
+ {
+ SetItem(nIndex,MasterPageContainer::NIL_TOKEN);
+ }
+
+ maCurrentItemList.swap(*pNewItemList);
+
+ mxPreviewValueSet->Rearrange();
+ if (mxSidebar.is())
+ mxSidebar->requestLayout();
+}
+
+css::ui::LayoutSize MasterPagesSelector::GetHeightForWidth (const sal_Int32 nWidth)
+{
+ const sal_Int32 nHeight (GetPreferredHeight(nWidth));
+ return css::ui::LayoutSize(nHeight,nHeight,nHeight);
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/MasterPagesSelector.hxx b/sd/source/ui/sidebar/MasterPagesSelector.hxx
new file mode 100644
index 000000000..1b6932789
--- /dev/null
+++ b/sd/source/ui/sidebar/MasterPagesSelector.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include "MasterPageContainer.hxx"
+#include "PreviewValueSet.hxx"
+#include <sfx2/sidebar/ILayoutableWindow.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+
+#include <osl/mutex.hxx>
+
+namespace com::sun::star::ui { class XSidebar; }
+class MouseEvent;
+class SdDrawDocument;
+class SdPage;
+
+namespace sd {
+class ViewShellBase;
+}
+
+namespace sd::sidebar {
+
+/** Base class of a menu that lets the user select from a list of
+ templates or designs that are loaded from files.
+*/
+class MasterPagesSelector : public PanelLayout
+ , public sfx2::sidebar::ILayoutableWindow
+{
+public:
+ MasterPagesSelector (
+ weld::Widget* pParent,
+ SdDrawDocument& rDocument,
+ ViewShellBase& rBase,
+ const std::shared_ptr<MasterPageContainer>& rpContainer,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar,
+ const OUString& rUIFileName,
+ const OString& rValueSetName);
+ virtual ~MasterPagesSelector() override;
+
+ virtual void LateInit();
+
+ sal_Int32 GetPreferredHeight (sal_Int32 nWidth);
+
+ /** Make the selector empty. This method clear the value set from any
+ entries. Override this method to add functionality, especially to
+ destroy objects set as data items at the value set.
+ */
+ void ClearPageSet();
+
+ void SetHelpId( const OString& aId );
+
+ /** Mark the preview that belongs to the given index as not up-to-date
+ anymore with respect to page content or preview size.
+ The implementation of this method will either sunchronously or
+ asynchronously call UpdatePreview().
+ @param nIndex
+ Index into the value set control that is used for displaying the
+ previews.
+ */
+ void InvalidatePreview (const SdPage* pPage);
+
+ void UpdateAllPreviews();
+
+ void ShowContextMenu(const Point* pPos);
+
+ // ILayoutableWindow
+ virtual css::ui::LayoutSize GetHeightForWidth (const sal_Int32 nWidth) override;
+
+protected:
+ mutable ::osl::Mutex maMutex;
+ std::shared_ptr<MasterPageContainer> mpContainer;
+
+ std::unique_ptr<PreviewValueSet> mxPreviewValueSet;
+ std::unique_ptr<weld::CustomWeld> mxPreviewValueSetWin;
+
+ SdDrawDocument& mrDocument;
+ ViewShellBase& mrBase;
+
+ SdPage* GetSelectedMasterPage();
+
+ /** Assign the given master page to all slides of the document.
+ @param pMasterPage
+ The master page to assign to all slides.
+ */
+ void AssignMasterPageToAllSlides (SdPage* pMasterPage);
+
+ /** Assign the given master page to all slides that are selected in a
+ slide sorter that is displayed in the lef or center pane. When both
+ panes display a slide sorter then the one in the center pane is
+ used.
+ */
+ void AssignMasterPageToSelectedSlides (SdPage* pMasterPage);
+
+ virtual void AssignMasterPageToPageList (
+ SdPage* pMasterPage,
+ const std::shared_ptr<std::vector<SdPage*>>& rPageList);
+
+ virtual void NotifyContainerChangeEvent (const MasterPageContainerChangeEvent& rEvent);
+
+ typedef ::std::pair<int, MasterPageContainer::Token> UserData;
+ UserData* GetUserData (int nIndex) const;
+ void SetUserData (int nIndex, std::unique_ptr<UserData> pData);
+
+ sal_Int32 GetIndexForToken (MasterPageContainer::Token aToken) const;
+ typedef ::std::vector<MasterPageContainer::Token> ItemList;
+ void UpdateItemList (::std::unique_ptr<ItemList> && pList);
+ void Clear();
+ /** Invalidate the specified item so that on the next Fill() this item
+ is updated.
+ */
+ void InvalidateItem (MasterPageContainer::Token aToken);
+
+ // For every item in the ValueSet we store its associated token. This
+ // allows a faster access and easier change tracking.
+ ItemList maCurrentItemList;
+ typedef ::std::map<MasterPageContainer::Token,sal_Int32> TokenToValueSetIndex;
+ TokenToValueSetIndex maTokenToValueSetIndex;
+
+ ItemList maLockedMasterPages;
+ /** Lock master pages in the given list and release locks that were
+ previously acquired.
+ */
+ void UpdateLocks (const ItemList& rItemList);
+
+ void Fill();
+ virtual void Fill (ItemList& rItemList) = 0;
+
+ /** Give derived classes the opportunity to provide their own context
+ menu. If they do then they probably have to provide their own
+ Execute() and GetState() methods as well.
+ */
+ virtual OUString GetContextMenuUIFile() const;
+
+ virtual void ProcessPopupMenu(weld::Menu& rMenu);
+ virtual void ExecuteCommand(const OString& rIdent);
+
+private:
+ css::uno::Reference<css::ui::XSidebar> mxSidebar;
+
+ /** The offset between ValueSet index and MasterPageContainer::Token
+ last seen. This value is used heuristically to speed up the lookup
+ of an index for a token.
+ */
+ DECL_LINK(ClickHandler, ValueSet*, void);
+ DECL_LINK(ContextMenuHandler, const Point*, void);
+ DECL_LINK(ContainerChangeListener, MasterPageContainerChangeEvent&, void);
+
+ void SetItem (
+ sal_uInt16 nIndex,
+ MasterPageContainer::Token aToken);
+ void AddTokenToIndexEntry (
+ sal_uInt16 nIndex,
+ MasterPageContainer::Token aToken);
+ void RemoveTokenToIndexEntry (
+ sal_uInt16 nIndex,
+ MasterPageContainer::Token aToken);
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/NavigatorWrapper.cxx b/sd/source/ui/sidebar/NavigatorWrapper.cxx
new file mode 100644
index 000000000..95d4a66ae
--- /dev/null
+++ b/sd/source/ui/sidebar/NavigatorWrapper.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 "NavigatorWrapper.hxx"
+#include <ViewShellBase.hxx>
+#include <navigatr.hxx>
+
+namespace sd::sidebar {
+
+NavigatorWrapper::NavigatorWrapper (
+ weld::Widget* pParent,
+ sd::ViewShellBase& rViewShellBase,
+ SfxBindings* pBindings)
+ : SdNavigatorWin(pParent, pBindings, nullptr)
+ , mrViewShellBase(rViewShellBase)
+{
+ SetUpdateRequestFunctor(
+ [this] () { return this->UpdateNavigator(); });
+}
+
+css::ui::LayoutSize NavigatorWrapper::GetHeightForWidth (const sal_Int32)
+{
+ return css::ui::LayoutSize(-1,-1,-1);
+}
+
+void NavigatorWrapper::UpdateNavigator()
+{
+ InitTreeLB(mrViewShellBase.GetDocument());
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/NavigatorWrapper.hxx b/sd/source/ui/sidebar/NavigatorWrapper.hxx
new file mode 100644
index 000000000..6632d796f
--- /dev/null
+++ b/sd/source/ui/sidebar/NavigatorWrapper.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sfx2/sidebar/ILayoutableWindow.hxx>
+#include <navigatr.hxx>
+
+class SfxBindings;
+namespace sd { class ViewShellBase; }
+
+namespace sd::sidebar {
+
+/** Present the navigator as control that can be displayed inside the
+ sidebar.
+ This wrapper has two main responsibilities:
+ - Watch for document changes and update the navigator when one
+ happens.
+ - Forward size changes from sidebar to navigator.
+*/
+class NavigatorWrapper
+ : public SdNavigatorWin,
+ public sfx2::sidebar::ILayoutableWindow
+{
+public:
+ NavigatorWrapper (
+ weld::Widget* pParent,
+ sd::ViewShellBase& rViewShellBase,
+ SfxBindings* pBindings);
+
+ // From ILayoutableWindow
+ virtual css::ui::LayoutSize GetHeightForWidth (const sal_Int32 nWidth) override;
+
+private:
+ ViewShellBase& mrViewShellBase;
+
+ void UpdateNavigator();
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/PageMarginUtils.hxx b/sd/source/ui/sidebar/PageMarginUtils.hxx
new file mode 100644
index 000000000..9a1f83493
--- /dev/null
+++ b/sd/source/ui/sidebar/PageMarginUtils.hxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <cmath>
+#include <tools/long.hxx>
+#define SDPAGE_NO_MARGIN 0
+#define SDPAGE_NARROW_VALUE 635
+#define SDPAGE_MODERATE_LR 955
+#define SDPAGE_NORMAL_VALUE 1000
+#define SDPAGE_WIDE_VALUE1 1270
+#define SDPAGE_WIDE_VALUE2 2540
+#define SDPAGE_WIDE_VALUE3 1590
+#define SDPAGE_UNIT_THRESHOLD 5
+
+namespace sd::sidebar{
+
+bool IsNone( const ::tools::Long nPageLeftMargin, const ::tools::Long nPageRightMargin,
+ const ::tools::Long nPageTopMargin, const ::tools::Long nPageBottomMargin )
+{
+ return( std::abs(nPageLeftMargin - SDPAGE_NO_MARGIN) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageRightMargin - SDPAGE_NO_MARGIN ) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageTopMargin - SDPAGE_NO_MARGIN) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageBottomMargin - SDPAGE_NO_MARGIN) <= SDPAGE_UNIT_THRESHOLD );
+}
+
+void SetNone( ::tools::Long& nPageLeftMargin, ::tools::Long& nPageRightMargin,
+ ::tools::Long& nPageTopMargin, ::tools::Long& nPageBottomMargin )
+{
+ nPageLeftMargin = SDPAGE_NO_MARGIN;
+ nPageRightMargin = SDPAGE_NO_MARGIN;
+ nPageTopMargin = SDPAGE_NO_MARGIN;
+ nPageBottomMargin = SDPAGE_NO_MARGIN;
+}
+
+bool IsNarrow( const ::tools::Long nPageLeftMargin, const ::tools::Long nPageRightMargin,
+ const ::tools::Long nPageTopMargin, const ::tools::Long nPageBottomMargin )
+{
+ return( std::abs(nPageLeftMargin - SDPAGE_NARROW_VALUE) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageRightMargin - SDPAGE_NARROW_VALUE) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageTopMargin - SDPAGE_NARROW_VALUE) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageBottomMargin - SDPAGE_NARROW_VALUE) <= SDPAGE_UNIT_THRESHOLD );
+}
+
+void SetNarrow( ::tools::Long& nPageLeftMargin, ::tools::Long& nPageRightMargin,
+ ::tools::Long& nPageTopMargin, ::tools::Long& nPageBottomMargin )
+{
+ nPageLeftMargin = SDPAGE_NARROW_VALUE;
+ nPageRightMargin = SDPAGE_NARROW_VALUE;
+ nPageTopMargin = SDPAGE_NARROW_VALUE;
+ nPageBottomMargin = SDPAGE_NARROW_VALUE;
+}
+
+bool IsModerate( const ::tools::Long nPageLeftMargin, const ::tools::Long nPageRightMargin,
+ const ::tools::Long nPageTopMargin, const ::tools::Long nPageBottomMargin )
+{
+ return( std::abs(nPageLeftMargin - SDPAGE_MODERATE_LR) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageRightMargin - SDPAGE_MODERATE_LR) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageTopMargin - SDPAGE_WIDE_VALUE1) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageBottomMargin - SDPAGE_WIDE_VALUE1) <= SDPAGE_UNIT_THRESHOLD );
+}
+
+void SetModerate( ::tools::Long& nPageLeftMargin, ::tools::Long& nPageRightMargin,
+ ::tools::Long& nPageTopMargin, ::tools::Long& nPageBottomMargin )
+{
+ nPageLeftMargin = SDPAGE_MODERATE_LR;
+ nPageRightMargin = SDPAGE_MODERATE_LR;
+ nPageTopMargin = SDPAGE_WIDE_VALUE1;
+ nPageBottomMargin = SDPAGE_WIDE_VALUE1;
+}
+
+bool IsNormal075( const ::tools::Long nPageLeftMargin, const ::tools::Long nPageRightMargin,
+ const ::tools::Long nPageTopMargin, const ::tools::Long nPageBottomMargin )
+{
+ return( std::abs(nPageLeftMargin - SDPAGE_NORMAL_VALUE) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageRightMargin - SDPAGE_NORMAL_VALUE) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageTopMargin - SDPAGE_NORMAL_VALUE) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageBottomMargin - SDPAGE_NORMAL_VALUE) <= SDPAGE_UNIT_THRESHOLD );
+}
+
+void SetNormal075( ::tools::Long& nPageLeftMargin, ::tools::Long& nPageRightMargin,
+ ::tools::Long& nPageTopMargin, ::tools::Long& nPageBottomMargin )
+{
+ nPageLeftMargin = SDPAGE_NORMAL_VALUE;
+ nPageRightMargin = SDPAGE_NORMAL_VALUE;
+ nPageTopMargin = SDPAGE_NORMAL_VALUE;
+ nPageBottomMargin = SDPAGE_NORMAL_VALUE;
+}
+
+bool IsNormal100( const ::tools::Long nPageLeftMargin, const ::tools::Long nPageRightMargin,
+ const ::tools::Long nPageTopMargin, const ::tools::Long nPageBottomMargin )
+{
+ return( std::abs(nPageLeftMargin - SDPAGE_WIDE_VALUE1) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageRightMargin - SDPAGE_WIDE_VALUE1) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageTopMargin - SDPAGE_WIDE_VALUE1) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageBottomMargin - SDPAGE_WIDE_VALUE1) <= SDPAGE_UNIT_THRESHOLD );
+}
+
+void SetNormal100( ::tools::Long& nPageLeftMargin, ::tools::Long& nPageRightMargin,
+ ::tools::Long& nPageTopMargin, ::tools::Long& nPageBottomMargin )
+{
+ nPageLeftMargin = SDPAGE_WIDE_VALUE1;
+ nPageRightMargin = SDPAGE_WIDE_VALUE1;
+ nPageTopMargin = SDPAGE_WIDE_VALUE1;
+ nPageBottomMargin = SDPAGE_WIDE_VALUE1;
+}
+
+bool IsNormal125( const ::tools::Long nPageLeftMargin, const ::tools::Long nPageRightMargin,
+ const ::tools::Long nPageTopMargin, const ::tools::Long nPageBottomMargin )
+{
+ return( std::abs(nPageLeftMargin - SDPAGE_WIDE_VALUE3) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageRightMargin - SDPAGE_WIDE_VALUE3) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageTopMargin - SDPAGE_WIDE_VALUE1) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageBottomMargin - SDPAGE_WIDE_VALUE1) <= SDPAGE_UNIT_THRESHOLD );
+}
+
+void SetNormal125( ::tools::Long& nPageLeftMargin, ::tools::Long& nPageRightMargin,
+ ::tools::Long& nPageTopMargin, ::tools::Long& nPageBottomMargin )
+{
+ nPageLeftMargin = SDPAGE_WIDE_VALUE3;
+ nPageRightMargin = SDPAGE_WIDE_VALUE3;
+ nPageTopMargin = SDPAGE_WIDE_VALUE1;
+ nPageBottomMargin = SDPAGE_WIDE_VALUE1;
+}
+
+bool IsWide( const ::tools::Long nPageLeftMargin, const ::tools::Long nPageRightMargin,
+ const ::tools::Long nPageTopMargin, const ::tools::Long nPageBottomMargin )
+{
+ return( std::abs(nPageLeftMargin - SDPAGE_WIDE_VALUE2) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageRightMargin - SDPAGE_WIDE_VALUE2) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageTopMargin - SDPAGE_WIDE_VALUE1) <= SDPAGE_UNIT_THRESHOLD &&
+ std::abs(nPageBottomMargin - SDPAGE_WIDE_VALUE1) <= SDPAGE_UNIT_THRESHOLD );
+}
+
+void SetWide( ::tools::Long& nPageLeftMargin, ::tools::Long& nPageRightMargin,
+ ::tools::Long& nPageTopMargin, ::tools::Long& nPageBottomMargin )
+{
+ nPageLeftMargin = SDPAGE_WIDE_VALUE2;
+ nPageRightMargin = SDPAGE_WIDE_VALUE2;
+ nPageTopMargin = SDPAGE_WIDE_VALUE1;
+ nPageBottomMargin = SDPAGE_WIDE_VALUE1;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/PanelFactory.cxx b/sd/source/ui/sidebar/PanelFactory.cxx
new file mode 100644
index 000000000..c7ca8c25c
--- /dev/null
+++ b/sd/source/ui/sidebar/PanelFactory.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PanelFactory.hxx"
+#include <framework/Pane.hxx>
+#include <ViewShellBase.hxx>
+#include <DrawController.hxx>
+#include "LayoutMenu.hxx"
+#include "CurrentMasterPagesSelector.hxx"
+#include "RecentMasterPagesSelector.hxx"
+#include "AllMasterPagesSelector.hxx"
+#include <CustomAnimationPane.hxx>
+#include "NavigatorWrapper.hxx"
+#include <SlideTransitionPane.hxx>
+#include <TableDesignPane.hxx>
+#include "SlideBackground.hxx"
+
+#include <sfx2/sidebar/SidebarPanelBase.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <vcl/weldutils.hxx>
+
+using namespace css;
+using namespace css::uno;
+using namespace ::sd::framework;
+
+namespace sd::sidebar {
+
+//----- PanelFactory --------------------------------------------------------
+
+PanelFactory::PanelFactory()
+{
+}
+
+PanelFactory::~PanelFactory()
+{
+}
+
+// XUIElementFactory
+
+Reference<ui::XUIElement> SAL_CALL PanelFactory::createUIElement (
+ const OUString& rsUIElementResourceURL,
+ const css::uno::Sequence<css::beans::PropertyValue>& rArguments)
+{
+ // Process arguments.
+ const ::comphelper::NamedValueCollection aArguments (rArguments);
+ Reference<frame::XFrame> xFrame (aArguments.getOrDefault("Frame", Reference<frame::XFrame>()));
+ Reference<awt::XWindow> xParentWindow (aArguments.getOrDefault("ParentWindow", Reference<awt::XWindow>()));
+ Reference<ui::XSidebar> xSidebar (aArguments.getOrDefault("Sidebar", Reference<ui::XSidebar>()));
+
+ // Throw exceptions when the arguments are not as expected.
+ weld::Widget* pParent(nullptr);
+ if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(xParentWindow.get()))
+ pParent = pTunnel->getWidget();
+
+ if (!pParent)
+ throw RuntimeException(
+ "PanelFactory::createUIElement called without ParentWindow");
+ if ( ! xFrame.is())
+ throw RuntimeException(
+ "PanelFactory::createUIElement called without XFrame");
+
+ // Tunnel through the controller to obtain a ViewShellBase.
+ ViewShellBase* pBase = nullptr;
+ auto pController = comphelper::getFromUnoTunnel<sd::DrawController>(xFrame->getController());
+ if (pController != nullptr)
+ pBase = pController->GetViewShellBase();
+ if (pBase == nullptr)
+ throw RuntimeException("can not get ViewShellBase for frame");
+
+ // Get bindings from given arguments.
+ const sal_uInt64 nBindingsValue (aArguments.getOrDefault("SfxBindings", sal_uInt64(0)));
+ SfxBindings* pBindings = reinterpret_cast<SfxBindings*>(nBindingsValue);
+
+ // Create a framework view.
+ std::unique_ptr<PanelLayout> xControl;
+ css::ui::LayoutSize aLayoutSize (-1,-1,-1);
+
+ /** Note that these names have to be identical to (the tail of)
+ the entries in officecfg/registry/data/org/openoffice/Office/Impress.xcu
+ for the TaskPanelFactory.
+ */
+ if (rsUIElementResourceURL.endsWith("/CustomAnimations"))
+ xControl = std::make_unique<CustomAnimationPane>(pParent, *pBase);
+ else if (rsUIElementResourceURL.endsWith("/Layouts"))
+ xControl = std::make_unique<LayoutMenu>(pParent, *pBase, xSidebar);
+ else if (rsUIElementResourceURL.endsWith("/AllMasterPages"))
+ xControl = AllMasterPagesSelector::Create(pParent, *pBase, xSidebar);
+ else if (rsUIElementResourceURL.endsWith("/RecentMasterPages"))
+ xControl = RecentMasterPagesSelector::Create(pParent, *pBase, xSidebar);
+ else if (rsUIElementResourceURL.endsWith("/UsedMasterPages"))
+ xControl = CurrentMasterPagesSelector::Create(pParent, *pBase, xSidebar);
+ else if (rsUIElementResourceURL.endsWith("/SlideTransitions"))
+ xControl = std::make_unique<SlideTransitionPane>(pParent, *pBase);
+ else if (rsUIElementResourceURL.endsWith("/TableDesign"))
+ xControl = std::make_unique<TableDesignPane>(pParent, *pBase);
+ else if (rsUIElementResourceURL.endsWith("/NavigatorPanel"))
+ xControl = std::make_unique<NavigatorWrapper>(pParent, *pBase, pBindings);
+ else if (rsUIElementResourceURL.endsWith("/SlideBackgroundPanel"))
+ xControl = std::make_unique<SlideBackground>(pParent, *pBase, xFrame, pBindings);
+
+ if (!xControl)
+ throw lang::IllegalArgumentException();
+
+ // Create a wrapper around the control that implements the
+ // necessary UNO interfaces.
+ return sfx2::sidebar::SidebarPanelBase::Create(
+ rsUIElementResourceURL,
+ xFrame,
+ std::move(xControl),
+ aLayoutSize);
+}
+
+} // end of namespace sd::sidebar
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_Draw_framework_PanelFactory_get_implementation(css::uno::XComponentContext* /*context*/,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::sidebar::PanelFactory);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/PanelFactory.hxx b/sd/source/ui/sidebar/PanelFactory.hxx
new file mode 100644
index 000000000..77fc17dbc
--- /dev/null
+++ b/sd/source/ui/sidebar/PanelFactory.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <comphelper/compbase.hxx>
+
+#include <com/sun/star/ui/XUIElementFactory.hpp>
+
+namespace sd::sidebar {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::ui::XUIElementFactory
+ > PanelFactoryInterfaceBase;
+
+class PanelFactory final
+ : public PanelFactoryInterfaceBase
+{
+public:
+ explicit PanelFactory ();
+ virtual ~PanelFactory() override;
+ PanelFactory(const PanelFactory&) = delete;
+ PanelFactory& operator=(const PanelFactory&) = delete;
+
+ // XUIElementFactory
+
+ css::uno::Reference<css::ui::XUIElement> SAL_CALL createUIElement (
+ const OUString& rsResourceURL,
+ const css::uno::Sequence<css::beans::PropertyValue>& rArguments) override;
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/PreviewValueSet.cxx b/sd/source/ui/sidebar/PreviewValueSet.cxx
new file mode 100644
index 000000000..f752d60eb
--- /dev/null
+++ b/sd/source/ui/sidebar/PreviewValueSet.cxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PreviewValueSet.hxx"
+#include <vcl/commandevent.hxx>
+
+namespace sd::sidebar {
+
+const int gnBorderWidth(3);
+const int gnBorderHeight(3);
+
+PreviewValueSet::PreviewValueSet()
+ : ValueSet(nullptr)
+ , maPreviewSize(10,10)
+{
+ SetStyle (
+ GetStyle()
+ & ~(WB_ITEMBORDER)// | WB_MENUSTYLEVALUESET)
+ // | WB_FLATVALUESET);
+ );
+}
+
+void PreviewValueSet::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ValueSet::SetDrawingArea(pDrawingArea);
+
+ SetColCount(2);
+ SetExtraSpacing (2);
+}
+
+PreviewValueSet::~PreviewValueSet()
+{
+}
+
+void PreviewValueSet::SetPreviewSize (const Size& rSize)
+{
+ maPreviewSize = rSize;
+}
+
+void PreviewValueSet::SetContextMenuHandler(const Link<const Point*, void>& rLink)
+{
+ maContextMenuHandler = rLink;
+}
+
+bool PreviewValueSet::Command(const CommandEvent& rEvent)
+{
+ if (rEvent.GetCommand() != CommandEventId::ContextMenu)
+ return ValueSet::Command(rEvent);
+ maContextMenuHandler.Call(rEvent.IsMouseEvent() ? &rEvent.GetMousePosPixel() : nullptr);
+ return true;
+}
+
+void PreviewValueSet::Resize()
+{
+ ValueSet::Resize();
+
+ Size aWindowSize (GetOutputSizePixel());
+ if (!aWindowSize.IsEmpty())
+ {
+ Rearrange();
+ }
+}
+
+void PreviewValueSet::Rearrange()
+{
+ sal_uInt16 nNewColumnCount (CalculateColumnCount (
+ GetOutputSizePixel().Width()));
+ sal_uInt16 nNewRowCount (CalculateRowCount (nNewColumnCount));
+
+ SetFormat();
+ SetColCount(nNewColumnCount);
+ SetLineCount(nNewRowCount);
+}
+
+sal_uInt16 PreviewValueSet::CalculateColumnCount (int nWidth) const
+{
+ int nColumnCount = 0;
+ if (nWidth > 0)
+ {
+ nColumnCount = nWidth / (maPreviewSize.Width() + 2*gnBorderWidth);
+ if (nColumnCount < 1)
+ nColumnCount = 1;
+ }
+ return static_cast<sal_uInt16>(nColumnCount);
+}
+
+sal_uInt16 PreviewValueSet::CalculateRowCount (sal_uInt16 nColumnCount) const
+{
+ int nRowCount = 0;
+ int nItemCount = GetItemCount();
+ if (nColumnCount > 0)
+ {
+ nRowCount = (nItemCount+nColumnCount-1) / nColumnCount;
+ if (nRowCount < 1)
+ nRowCount = 1;
+ }
+
+ return static_cast<sal_uInt16>(nRowCount);
+}
+
+sal_Int32 PreviewValueSet::GetPreferredHeight (sal_Int32 nWidth)
+{
+ int nRowCount (CalculateRowCount(CalculateColumnCount(nWidth)));
+ int nItemHeight (maPreviewSize.Height());
+
+ return nRowCount * (nItemHeight + 2*gnBorderHeight);
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/PreviewValueSet.hxx b/sd/source/ui/sidebar/PreviewValueSet.hxx
new file mode 100644
index 000000000..adab3c78a
--- /dev/null
+++ b/sd/source/ui/sidebar/PreviewValueSet.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svtools/valueset.hxx>
+
+namespace sd::sidebar
+{
+/** Adapt the svtools valueset to the needs of the master page controls.
+*/
+class PreviewValueSet : public ValueSet
+{
+public:
+ explicit PreviewValueSet();
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ virtual ~PreviewValueSet() override;
+
+ void SetContextMenuHandler(const Link<const Point*, void>& rLink);
+
+ virtual void Resize() override;
+ virtual bool Command(const CommandEvent& rEvent) override;
+
+ void SetPreviewSize(const Size& rSize);
+
+ sal_Int32 GetPreferredHeight(sal_Int32 nWidth);
+
+ /** Set the number of rows and columns according to the current number
+ of items. Call this method when new items have been inserted.
+ */
+ void Rearrange();
+
+private:
+ Link<const Point*, void> maContextMenuHandler;
+ Size maPreviewSize;
+
+ sal_uInt16 CalculateColumnCount(int nWidth) const;
+ sal_uInt16 CalculateRowCount(sal_uInt16 nColumnCount) const;
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/RecentMasterPagesSelector.cxx b/sd/source/ui/sidebar/RecentMasterPagesSelector.cxx
new file mode 100644
index 000000000..6e5a46c73
--- /dev/null
+++ b/sd/source/ui/sidebar/RecentMasterPagesSelector.cxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "RecentMasterPagesSelector.hxx"
+
+#include <ViewShellBase.hxx>
+#include "RecentlyUsedMasterPages.hxx"
+#include <MasterPageObserver.hxx>
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <helpids.h>
+
+namespace sd::sidebar {
+
+std::unique_ptr<PanelLayout> RecentMasterPagesSelector::Create (
+ weld::Widget* pParent,
+ ViewShellBase& rViewShellBase,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+{
+ SdDrawDocument* pDocument = rViewShellBase.GetDocument();
+ if (pDocument == nullptr)
+ return nullptr;
+
+ auto pContainer = std::make_shared<MasterPageContainer>();
+
+ auto xSelector(std::make_unique<RecentMasterPagesSelector>(
+ pParent,
+ *pDocument,
+ rViewShellBase,
+ pContainer,
+ rxSidebar));
+ xSelector->LateInit();
+ xSelector->SetHelpId(HID_SD_TASK_PANE_PREVIEW_RECENT);
+
+ return xSelector;
+}
+
+RecentMasterPagesSelector::RecentMasterPagesSelector (
+ weld::Widget* pParent,
+ SdDrawDocument& rDocument,
+ ViewShellBase& rBase,
+ const std::shared_ptr<MasterPageContainer>& rpContainer,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+ : MasterPagesSelector (pParent, rDocument, rBase, rpContainer, rxSidebar, "modules/simpress/ui/masterpagepanelrecent.ui", "recentvalueset")
+{
+}
+
+RecentMasterPagesSelector::~RecentMasterPagesSelector()
+{
+ RecentlyUsedMasterPages::Instance().RemoveEventListener (
+ LINK(this,RecentMasterPagesSelector,MasterPageListListener));
+}
+
+void RecentMasterPagesSelector::LateInit()
+{
+ MasterPagesSelector::LateInit();
+
+ MasterPagesSelector::Fill();
+ RecentlyUsedMasterPages::Instance().AddEventListener (
+ LINK(this,RecentMasterPagesSelector,MasterPageListListener));
+}
+
+IMPL_LINK_NOARG(RecentMasterPagesSelector, MasterPageListListener, LinkParamNone*, void)
+{
+ MasterPagesSelector::Fill();
+}
+
+void RecentMasterPagesSelector::Fill (ItemList& rItemList)
+{
+ // Create a set of names of the master pages used by the document.
+ MasterPageObserver::MasterPageNameSet aCurrentNames;
+ sal_uInt16 nMasterPageCount = mrDocument.GetMasterSdPageCount(PageKind::Standard);
+ for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
+ {
+ SdPage* pMasterPage = mrDocument.GetMasterSdPage (nIndex, PageKind::Standard);
+ if (pMasterPage != nullptr)
+ aCurrentNames.insert (pMasterPage->GetName());
+ }
+
+ // Insert the recently used master pages that are currently not used.
+ RecentlyUsedMasterPages& rInstance (RecentlyUsedMasterPages::Instance());
+ int nPageCount = rInstance.GetMasterPageCount();
+ for (int nIndex=0; nIndex<nPageCount; nIndex++)
+ {
+ // Add an entry when a) the page is already known to the
+ // MasterPageContainer, b) the style name is empty, i.e. it has not yet
+ // been loaded (and thus can not be in use) or otherwise c) the
+ // style name is not currently in use.
+ MasterPageContainer::Token aToken (rInstance.GetTokenForIndex(nIndex));
+ if (aToken != MasterPageContainer::NIL_TOKEN)
+ {
+ OUString sStyleName (mpContainer->GetStyleNameForToken(aToken));
+ if (sStyleName.isEmpty()
+ || aCurrentNames.find(sStyleName) == aCurrentNames.end())
+ {
+ rItemList.push_back(aToken);
+ }
+ }
+ }
+}
+
+void RecentMasterPagesSelector::AssignMasterPageToPageList (
+ SdPage* pMasterPage,
+ const std::shared_ptr<std::vector<SdPage*> >& rpPageList)
+{
+ sal_uInt16 nSelectedItemId = mxPreviewValueSet->GetSelectedItemId();
+
+ MasterPagesSelector::AssignMasterPageToPageList(pMasterPage, rpPageList);
+
+ // Restore the selection.
+ if (mxPreviewValueSet->GetItemCount() > 0)
+ {
+ if (mxPreviewValueSet->GetItemCount() >= nSelectedItemId)
+ mxPreviewValueSet->SelectItem(nSelectedItemId);
+ else
+ mxPreviewValueSet->SelectItem(mxPreviewValueSet->GetItemCount());
+ }
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/RecentMasterPagesSelector.hxx b/sd/source/ui/sidebar/RecentMasterPagesSelector.hxx
new file mode 100644
index 000000000..6dbc3a2aa
--- /dev/null
+++ b/sd/source/ui/sidebar/RecentMasterPagesSelector.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MasterPagesSelector.hxx"
+
+namespace sd::sidebar {
+
+/** Show the recently used master pages (that are not currently used).
+*/
+class RecentMasterPagesSelector final
+ : public MasterPagesSelector
+{
+ friend class VclPtrInstance<RecentMasterPagesSelector>;
+public:
+ static std::unique_ptr<PanelLayout> Create (
+ weld::Widget* pParent,
+ ViewShellBase& rViewShellBase,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+
+ RecentMasterPagesSelector (
+ weld::Widget* pParent,
+ SdDrawDocument& rDocument,
+ ViewShellBase& rBase,
+ const std::shared_ptr<MasterPageContainer>& rpContainer,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+ virtual ~RecentMasterPagesSelector() override;
+
+private:
+ DECL_LINK(MasterPageListListener, LinkParamNone*, void);
+ virtual void Fill (ItemList& rItemList) override;
+
+ using sd::sidebar::MasterPagesSelector::Fill;
+
+ /** Forward this call to the base class but save and restore the
+ currently selected item.
+ Assign the given master page to the list of pages.
+ @param pMasterPage
+ This master page will usually be a member of the list of all
+ available master pages as provided by the MasterPageContainer.
+ @param rPageList
+ The pages to which to assign the master page. These pages may
+ be slides or master pages themselves.
+ */
+ virtual void AssignMasterPageToPageList (
+ SdPage* pMasterPage,
+ const std::shared_ptr<std::vector<SdPage*> >& rpPageList) override;
+
+ virtual void LateInit() override;
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/RecentlyUsedMasterPages.cxx b/sd/source/ui/sidebar/RecentlyUsedMasterPages.cxx
new file mode 100644
index 000000000..268658823
--- /dev/null
+++ b/sd/source/ui/sidebar/RecentlyUsedMasterPages.cxx
@@ -0,0 +1,366 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "RecentlyUsedMasterPages.hxx"
+#include "MasterPageContainerProviders.hxx"
+#include <MasterPageObserver.hxx>
+#include "MasterPageDescriptor.hxx"
+#include <tools/ConfigurationAccess.hxx>
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <osl/doublecheckedlocking.h>
+#include <osl/getglobalmutex.hxx>
+
+using namespace ::std;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+OUString GetPathToImpressConfigurationRoot()
+{
+ return "/org.openoffice.Office.Impress/";
+}
+OUString GetPathToSetNode()
+{
+ return "MultiPaneGUI/ToolPanel/RecentlyUsedMasterPages";
+}
+
+} // end of anonymous namespace
+
+namespace sd::sidebar {
+
+RecentlyUsedMasterPages* RecentlyUsedMasterPages::mpInstance = nullptr;
+
+RecentlyUsedMasterPages& RecentlyUsedMasterPages::Instance()
+{
+ if (mpInstance == nullptr)
+ {
+ ::osl::GetGlobalMutex aMutexFunctor;
+ ::osl::MutexGuard aGuard (aMutexFunctor());
+ if (mpInstance == nullptr)
+ {
+ RecentlyUsedMasterPages* pInstance = new RecentlyUsedMasterPages();
+ pInstance->LateInit();
+ SdGlobalResourceContainer::Instance().AddResource (
+ ::std::unique_ptr<SdGlobalResource>(pInstance));
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ mpInstance = pInstance;
+ }
+ }
+ else {
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ }
+
+ return *mpInstance;
+}
+
+constexpr size_t gnMaxListSize(8);
+
+RecentlyUsedMasterPages::RecentlyUsedMasterPages()
+ : mpContainer(std::make_shared<MasterPageContainer>())
+{
+}
+
+RecentlyUsedMasterPages::~RecentlyUsedMasterPages()
+{
+ Link<MasterPageContainerChangeEvent&,void> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
+ mpContainer->RemoveChangeListener(aLink);
+
+ MasterPageObserver::Instance().RemoveEventListener(
+ LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
+}
+
+void RecentlyUsedMasterPages::LateInit()
+{
+ Link<MasterPageContainerChangeEvent&,void> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
+ mpContainer->AddChangeListener(aLink);
+
+ LoadPersistentValues ();
+ MasterPageObserver::Instance().AddEventListener(
+ LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
+}
+
+void RecentlyUsedMasterPages::LoadPersistentValues()
+{
+ try
+ {
+ tools::ConfigurationAccess aConfiguration (
+ GetPathToImpressConfigurationRoot(),
+ tools::ConfigurationAccess::READ_ONLY);
+ Reference<container::XNameAccess> xSet (
+ aConfiguration.GetConfigurationNode(GetPathToSetNode()),
+ UNO_QUERY);
+ if ( ! xSet.is())
+ return;
+
+ static const OUStringLiteral sURLMemberName(u"URL");
+ static const OUStringLiteral sNameMemberName(u"Name");
+ OUString sURL;
+ OUString sName;
+
+ // Read the names and URLs of the master pages.
+ const Sequence<OUString> aKeys (xSet->getElementNames());
+ mvMasterPages.clear();
+ mvMasterPages.reserve(aKeys.getLength());
+ for (const auto& rKey : aKeys)
+ {
+ Reference<container::XNameAccess> xSetItem (
+ xSet->getByName(rKey), UNO_QUERY);
+ if (xSetItem.is())
+ {
+ Any aURL (xSetItem->getByName(sURLMemberName));
+ Any aName (xSetItem->getByName(sNameMemberName));
+ aURL >>= sURL;
+ aName >>= sName;
+ SharedMasterPageDescriptor pDescriptor = std::make_shared<MasterPageDescriptor>(
+ MasterPageContainer::TEMPLATE,
+ -1,
+ sURL,
+ OUString(),
+ sName,
+ false,
+ std::make_shared<TemplatePageObjectProvider>(sURL),
+ std::make_shared<TemplatePreviewProvider>(sURL));
+ // For user supplied templates we use a different
+ // preview provider: The preview in the document shows
+ // not only shapes on the master page but also shapes on
+ // the foreground. This is misleading and therefore
+ // these previews are discarded and created directly
+ // from the page objects.
+ if (pDescriptor->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER)
+ pDescriptor->mpPreviewProvider = std::make_shared<PagePreviewProvider>();
+ MasterPageContainer::Token aToken (mpContainer->PutMasterPage(pDescriptor));
+ mvMasterPages.emplace_back(aToken,sURL,sName);
+ }
+ }
+
+ ResolveList();
+ }
+ catch (Exception&)
+ {
+ // Ignore exception.
+ }
+}
+
+void RecentlyUsedMasterPages::SavePersistentValues()
+{
+ try
+ {
+ tools::ConfigurationAccess aConfiguration (
+ GetPathToImpressConfigurationRoot(),
+ tools::ConfigurationAccess::READ_WRITE);
+ Reference<container::XNameContainer> xSet (
+ aConfiguration.GetConfigurationNode(GetPathToSetNode()),
+ UNO_QUERY);
+ if ( ! xSet.is())
+ return;
+
+ // Clear the set.
+ const Sequence<OUString> aKeys (xSet->getElementNames());
+ for (const auto& rKey : aKeys)
+ xSet->removeByName (rKey);
+
+ // Fill it with the URLs of this object.
+ static const OUStringLiteral sURLMemberName(u"URL");
+ static const OUStringLiteral sNameMemberName(u"Name");
+ Any aValue;
+ Reference<lang::XSingleServiceFactory> xChildFactory (
+ xSet, UNO_QUERY);
+ if ( ! xChildFactory.is())
+ return;
+ sal_Int32 nIndex(0);
+ for (const auto& rDescriptor : mvMasterPages)
+ {
+ // Create new child.
+ OUString sKey = "index_" + OUString::number(nIndex);
+ Reference<container::XNameReplace> xChild(
+ xChildFactory->createInstance(), UNO_QUERY);
+ if (xChild.is())
+ {
+ xSet->insertByName (sKey, Any(xChild));
+
+ aValue <<= rDescriptor.msURL;
+ xChild->replaceByName (sURLMemberName, aValue);
+
+ aValue <<= rDescriptor.msName;
+ xChild->replaceByName (sNameMemberName, aValue);
+ }
+ ++nIndex;
+ }
+
+ // Write the data back to disk.
+ aConfiguration.CommitChanges();
+ }
+ catch (Exception&)
+ {
+ // Ignore exception.
+ }
+}
+
+void RecentlyUsedMasterPages::AddEventListener (const Link<LinkParamNone*,void>& rEventListener)
+{
+ if (::std::find (
+ maListeners.begin(),
+ maListeners.end(),
+ rEventListener) == maListeners.end())
+ {
+ maListeners.push_back (rEventListener);
+ }
+}
+
+void RecentlyUsedMasterPages::RemoveEventListener (const Link<LinkParamNone*,void>& rEventListener)
+{
+ maListeners.erase (
+ ::std::find (
+ maListeners.begin(),
+ maListeners.end(),
+ rEventListener));
+}
+
+int RecentlyUsedMasterPages::GetMasterPageCount() const
+{
+ return mvMasterPages.size();
+}
+
+MasterPageContainer::Token RecentlyUsedMasterPages::GetTokenForIndex (sal_uInt32 nIndex) const
+{
+ if(nIndex<mvMasterPages.size())
+ return mvMasterPages[nIndex].maToken;
+ else
+ return MasterPageContainer::NIL_TOKEN;
+}
+
+void RecentlyUsedMasterPages::SendEvent()
+{
+ for (const auto& aLink : maListeners)
+ {
+ aLink.Call(nullptr);
+ }
+}
+
+IMPL_LINK(RecentlyUsedMasterPages, MasterPageChangeListener,
+ MasterPageObserverEvent&, rEvent, void)
+{
+ switch (rEvent.meType)
+ {
+ case MasterPageObserverEvent::ET_MASTER_PAGE_ADDED:
+ case MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS:
+ AddMasterPage(
+ mpContainer->GetTokenForStyleName(rEvent.mrMasterPageName));
+ break;
+
+ case MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED:
+ // Do not change the list of recently master pages (the deleted
+ // page was recently used) but tell the listeners. They may want
+ // to update their lists.
+ SendEvent();
+ break;
+ }
+}
+
+IMPL_LINK(RecentlyUsedMasterPages, MasterPageContainerChangeListener,
+ MasterPageContainerChangeEvent&, rEvent, void)
+{
+ switch (rEvent.meEventType)
+ {
+ case MasterPageContainerChangeEvent::EventType::CHILD_ADDED:
+ case MasterPageContainerChangeEvent::EventType::CHILD_REMOVED:
+ case MasterPageContainerChangeEvent::EventType::INDEX_CHANGED:
+ ResolveList();
+ break;
+
+ default:
+ // Ignored.
+ break;
+ }
+}
+
+void RecentlyUsedMasterPages::AddMasterPage (
+ MasterPageContainer::Token aToken)
+{
+ // For the page to be inserted the token has to be valid and the page
+ // has to have a valid URL. This excludes master pages that do not come
+ // from template files.
+ if (aToken == MasterPageContainer::NIL_TOKEN
+ || mpContainer->GetURLForToken(aToken).isEmpty())
+ return;
+
+ MasterPageList::iterator aIterator (
+ ::std::find_if(mvMasterPages.begin(),mvMasterPages.end(),
+ Descriptor::TokenComparator(aToken)));
+ if (aIterator != mvMasterPages.end())
+ {
+ // When an entry for the given token already exists then remove
+ // it now and insert it later at the head of the list.
+ mvMasterPages.erase (aIterator);
+ }
+
+ mvMasterPages.insert(mvMasterPages.begin(),
+ Descriptor(
+ aToken,
+ mpContainer->GetURLForToken(aToken),
+ mpContainer->GetStyleNameForToken(aToken)));
+
+ // Shorten list to maximal size.
+ while (mvMasterPages.size() > gnMaxListSize)
+ {
+ mvMasterPages.pop_back ();
+ }
+
+ SavePersistentValues ();
+ SendEvent();
+}
+
+void RecentlyUsedMasterPages::ResolveList()
+{
+ bool bNotify (false);
+
+ for (auto& rDescriptor : mvMasterPages)
+ {
+ if (rDescriptor.maToken == MasterPageContainer::NIL_TOKEN)
+ {
+ MasterPageContainer::Token aToken (mpContainer->GetTokenForURL(rDescriptor.msURL));
+ rDescriptor.maToken = aToken;
+ if (aToken != MasterPageContainer::NIL_TOKEN)
+ bNotify = true;
+ }
+ else
+ {
+ if ( ! mpContainer->HasToken(rDescriptor.maToken))
+ {
+ rDescriptor.maToken = MasterPageContainer::NIL_TOKEN;
+ bNotify = true;
+ }
+ }
+ }
+
+ if (bNotify)
+ SendEvent();
+}
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/RecentlyUsedMasterPages.hxx b/sd/source/ui/sidebar/RecentlyUsedMasterPages.hxx
new file mode 100644
index 000000000..e95e66ccb
--- /dev/null
+++ b/sd/source/ui/sidebar/RecentlyUsedMasterPages.hxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/SdGlobalResourceContainer.hxx>
+#include <tools/link.hxx>
+#include <vector>
+
+#include "MasterPageContainer.hxx"
+
+namespace sd {
+class MasterPageObserverEvent;
+}
+
+namespace sd::sidebar {
+
+/** This singleton holds a list of the most recently used master pages.
+*/
+class RecentlyUsedMasterPages
+ : public SdGlobalResource
+{
+public:
+ /** Return the single instance of this class.
+ */
+ static RecentlyUsedMasterPages& Instance();
+
+ void AddEventListener (const Link<LinkParamNone*,void>& rEventListener);
+ void RemoveEventListener (const Link<LinkParamNone*,void>& rEventListener);
+
+ int GetMasterPageCount() const;
+ MasterPageContainer::Token GetTokenForIndex (sal_uInt32 nIndex) const;
+
+private:
+ class Descriptor
+ {
+ public:
+ OUString msURL;
+ OUString msName;
+ ::sd::sidebar::MasterPageContainer::Token maToken;
+ Descriptor (::sd::sidebar::MasterPageContainer::Token aToken,
+ const OUString& rsURL, const OUString& rsName)
+ : msURL(rsURL),
+ msName(rsName),
+ maToken(aToken)
+ {}
+
+ class TokenComparator
+ {
+ public:
+ explicit TokenComparator(::sd::sidebar::MasterPageContainer::Token aToken)
+ : maToken(aToken) {}
+ bool operator () (const Descriptor& rDescriptor)
+ { return maToken==rDescriptor.maToken; }
+
+ private:
+ ::sd::sidebar::MasterPageContainer::Token maToken;
+ };
+ };
+
+ /** The single instance of this class. It is created on demand when
+ Instance() is called for the first time.
+ */
+ static RecentlyUsedMasterPages* mpInstance;
+
+ ::std::vector<Link<LinkParamNone*,void>> maListeners;
+
+ typedef ::std::vector<Descriptor> MasterPageList;
+ MasterPageList mvMasterPages;
+ std::shared_ptr<MasterPageContainer> mpContainer;
+
+ RecentlyUsedMasterPages();
+ virtual ~RecentlyUsedMasterPages() override;
+
+ /** Call this method after a new object has been created.
+ */
+ void LateInit();
+
+ RecentlyUsedMasterPages (const RecentlyUsedMasterPages&) = delete;
+
+ RecentlyUsedMasterPages& operator= (const RecentlyUsedMasterPages&) = delete;
+
+ void SendEvent();
+ DECL_LINK(MasterPageChangeListener, MasterPageObserverEvent&, void);
+ DECL_LINK(MasterPageContainerChangeListener, MasterPageContainerChangeEvent&, void);
+
+ /** Add a descriptor for the specified master page to the end of the
+ list of most recently used master pages. When the page is already a
+ member of that list the associated descriptor is moved to the end of
+ the list to make it the most recently used entry.
+ */
+ void AddMasterPage(MasterPageContainer::Token aToken);
+
+ /** Load the list of recently used master pages from the registry where
+ it was saved to make it persistent.
+ */
+ void LoadPersistentValues();
+
+ /** Save the list of recently used master pages to the registry to make
+ it persistent.
+ */
+ void SavePersistentValues();
+
+ void ResolveList();
+};
+
+} // end of namespace sd::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/SlideBackground.cxx b/sd/source/ui/sidebar/SlideBackground.cxx
new file mode 100644
index 000000000..742275bab
--- /dev/null
+++ b/sd/source/ui/sidebar/SlideBackground.cxx
@@ -0,0 +1,1286 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/ui/XDeck.hpp>
+#include <com/sun/star/ui/XPanel.hpp>
+#include <com/sun/star/frame/XController2.hpp>
+#include <SlideSorter.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include "SlideBackground.hxx"
+#include <sdresid.hxx>
+#include <ViewShellBase.hxx>
+#include <FrameView.hxx>
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include "PageMarginUtils.hxx"
+#include <strings.hrc>
+#include <pageformatpanel.hrc>
+#include <DrawViewShell.hxx>
+#include <svl/intitem.hxx>
+#include <svx/colorbox.hxx>
+#include <svx/dlgutil.hxx>
+#include <svx/drawitem.hxx>
+#include <svx/itemwin.hxx>
+#include <svx/pageitem.hxx>
+#include <app.hrc>
+#include <editeng/paperinf.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/rulritem.hxx>
+#include <svx/svxids.hrc>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xgrad.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/svdpage.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sidebar/Panel.hxx>
+#include <EventMultiplexer.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/EnumContext.hxx>
+#include <vcl/svapp.hxx>
+
+#include <editeng/sizeitem.hxx>
+#include <comphelper/lok.hxx>
+#include <unomodel.hxx>
+#include <sfx2/lokhelper.hxx>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+
+namespace sd::sidebar {
+
+namespace {
+
+enum eFillStyle
+{
+ NONE,
+ SOLID,
+ GRADIENT,
+ HATCH,
+ BITMAP,
+ PATTERN
+};
+
+}
+
+SlideBackground::SlideBackground(
+ weld::Widget* pParent,
+ ViewShellBase& rBase,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings) :
+ PanelLayout( pParent, "SlideBackgroundPanel", "modules/simpress/ui/sidebarslidebackground.ui" ),
+ mrBase( rBase ),
+ mxPaperSizeBox(new SvxPaperSizeListBox(m_xBuilder->weld_combo_box("paperformat"))),
+ mxPaperOrientation(m_xBuilder->weld_combo_box("orientation")),
+ mxMasterSlide(m_xBuilder->weld_combo_box("masterslide")),
+ mxBackgroundLabel(m_xBuilder->weld_label("label3")),
+ mxFillStyle(m_xBuilder->weld_combo_box("fillstyle")),
+ mxFillLB(new ColorListBox(m_xBuilder->weld_menu_button("fillattr"), [this]{ return GetFrameWeld(); })),
+ mxFillAttr(m_xBuilder->weld_combo_box("fillattr1")),
+ mxFillGrad1(new ColorListBox(m_xBuilder->weld_menu_button("fillattr2"), [this]{ return GetFrameWeld(); })),
+ mxFillGrad2(new ColorListBox(m_xBuilder->weld_menu_button("fillattr3"), [this]{ return GetFrameWeld(); })),
+ mxInsertImage(m_xBuilder->weld_button("button2")),
+ mxDspMasterBackground(m_xBuilder->weld_check_button("displaymasterbackground")),
+ mxDspMasterObjects(m_xBuilder->weld_check_button("displaymasterobjects")),
+ mxCloseMaster(m_xBuilder->weld_button("closemasterslide")),
+ mxEditMaster(m_xBuilder->weld_button("masterslidebutton")),
+ mxMasterLabel(m_xBuilder->weld_label("masterlabel")),
+ mxMarginSelectBox(m_xBuilder->weld_combo_box("marginLB")),
+ mxCustomEntry(m_xBuilder->weld_label("customlabel")),
+ mxMarginLabel(m_xBuilder->weld_label("labelmargin")),
+ maPaperSizeController(SID_ATTR_PAGE_SIZE, *pBindings, *this),
+ maPaperOrientationController(SID_ATTR_PAGE, *pBindings, *this),
+ maPaperMarginLRController(SID_ATTR_PAGE_LRSPACE, *pBindings, *this),
+ maPaperMarginULController(SID_ATTR_PAGE_ULSPACE, *pBindings, *this),
+ maBckColorController(SID_ATTR_PAGE_COLOR, *pBindings, *this),
+ maBckGradientController(SID_ATTR_PAGE_GRADIENT, *pBindings, *this),
+ maBckHatchController(SID_ATTR_PAGE_HATCH, *pBindings, *this),
+ maBckBitmapController(SID_ATTR_PAGE_BITMAP, *pBindings, *this),
+ maBckFillStyleController(SID_ATTR_PAGE_FILLSTYLE, *pBindings, *this),
+ maBckImageController(SID_SELECT_BACKGROUND, *pBindings, *this),
+ maDspBckController(SID_DISPLAY_MASTER_BACKGROUND, *pBindings, *this),
+ maDspObjController(SID_DISPLAY_MASTER_OBJECTS, *pBindings, *this),
+ maMetricController(SID_ATTR_METRIC, *pBindings, *this),
+ maCloseMasterController(SID_CLOSE_MASTER_VIEW, *pBindings, *this),
+ mpPageItem( new SvxPageItem(SID_ATTR_PAGE) ),
+ mbSwitchModeToNormal(false),
+ mbSwitchModeToMaster(false),
+ mxFrame(rxFrame),
+ maDrawOtherContext(vcl::EnumContext::Application::Draw, vcl::EnumContext::Context::DrawPage),
+ maDrawMasterContext(vcl::EnumContext::Application::Draw, vcl::EnumContext::Context::MasterPage),
+ maImpressOtherContext(vcl::EnumContext::Application::Impress, vcl::EnumContext::Context::DrawPage),
+ maImpressMasterContext(vcl::EnumContext::Application::Impress, vcl::EnumContext::Context::MasterPage),
+ maImpressHandoutContext(vcl::EnumContext::Application::Impress, vcl::EnumContext::Context::HandoutPage),
+ maImpressNotesContext(vcl::EnumContext::Application::Impress, vcl::EnumContext::Context::NotesPage),
+ mbTitle(false),
+ mpPageLRMarginItem( new SvxLongLRSpaceItem( 0, 0, SID_ATTR_PAGE_LRSPACE ) ),
+ mpPageULMarginItem( new SvxLongULSpaceItem( 0, 0, SID_ATTR_PAGE_ULSPACE ) ),
+ m_nPageLeftMargin(0),
+ m_nPageRightMargin(0),
+ m_nPageTopMargin(0),
+ m_nPageBottomMargin(0),
+ meFUnit(GetModuleFieldUnit()),
+ mpBindings(pBindings)
+{
+ //let the listbox shrink to any size so the sidebar isn't forced to grow to
+ //the size of the longest master slide name in the document
+ mxMasterSlide->set_size_request(42, -1);
+
+ maCustomEntry = mxCustomEntry->get_label();
+
+ addListener();
+ Initialize();
+}
+
+bool SlideBackground::IsDraw()
+{
+ return ( maContext == maDrawMasterContext ||
+ maContext == maDrawOtherContext );
+}
+
+bool SlideBackground::IsImpress()
+{
+ return ( maContext == maImpressMasterContext ||
+ maContext == maImpressOtherContext ||
+ maContext == maImpressHandoutContext ||
+ maContext == maImpressNotesContext );
+}
+
+FieldUnit SlideBackground::GetCurrentUnit(SfxItemState eState, const SfxPoolItem* pState)
+{
+ FieldUnit eUnit;
+
+ if (pState && eState >= SfxItemState::DEFAULT)
+ eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pState)->GetValue());
+ else
+ eUnit = GetModuleFieldUnit();
+
+ return eUnit;
+}
+
+void SlideBackground::SetMarginsFieldUnit()
+{
+ auto nSelected = mxMarginSelectBox->get_active();
+ mxMarginSelectBox->clear();
+
+ const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
+
+ if (IsInch(meFUnit))
+ {
+ OUString sSuffix = weld::MetricSpinButton::MetricToString(FieldUnit::INCH);
+ for (size_t i = 0; i < SAL_N_ELEMENTS(RID_PAGEFORMATPANEL_MARGINS_INCH); ++i)
+ {
+ OUString sMeasurement = rLocaleData.getNum(RID_PAGEFORMATPANEL_MARGINS_INCH[i].second, 2, true, false) + sSuffix;
+ mxMarginSelectBox->append_text(SdResId(RID_PAGEFORMATPANEL_MARGINS_INCH[i].first).replaceFirst("%1", sMeasurement));
+ }
+ }
+ else
+ {
+ OUString sSuffix = " " + weld::MetricSpinButton::MetricToString(FieldUnit::CM);
+ for (size_t i = 0; i < SAL_N_ELEMENTS(RID_PAGEFORMATPANEL_MARGINS_CM); ++i)
+ {
+ OUString sMeasurement = rLocaleData.getNum(RID_PAGEFORMATPANEL_MARGINS_CM[i].second, 2, true, false) + sSuffix;
+ mxMarginSelectBox->append_text(SdResId(RID_PAGEFORMATPANEL_MARGINS_CM[i].first).replaceFirst("%1", sMeasurement));
+ }
+ }
+
+ mxMarginSelectBox->set_active(nSelected);
+}
+
+void SlideBackground::Initialize()
+{
+ SvxFillTypeBox::Fill(*mxFillStyle);
+
+ SetMarginsFieldUnit();
+
+ mxPaperSizeBox->FillPaperSizeEntries( PaperSizeApp::Draw );
+ mxPaperSizeBox->connect_changed(LINK(this,SlideBackground,PaperSizeModifyHdl));
+ mxPaperOrientation->connect_changed(LINK(this,SlideBackground,PaperSizeModifyHdl));
+ mxEditMaster->connect_clicked(LINK(this, SlideBackground, EditMasterHdl));
+ mxCloseMaster->connect_clicked(LINK(this, SlideBackground, CloseMasterHdl));
+ mxInsertImage->connect_clicked(LINK(this, SlideBackground, SelectBgHdl));
+ meUnit = maPaperSizeController.GetCoreMetric();
+
+ mxMasterSlide->connect_changed(LINK(this, SlideBackground, AssignMasterPage));
+
+ mxFillStyle->connect_changed(LINK(this, SlideBackground, FillStyleModifyHdl));
+ mxFillLB->SetSelectHdl(LINK(this, SlideBackground, FillColorHdl));
+ mxFillGrad1->SetSelectHdl(LINK(this, SlideBackground, FillColorHdl));
+ mxFillGrad2->SetSelectHdl(LINK(this, SlideBackground, FillColorHdl));
+ mxFillAttr->connect_changed(LINK(this, SlideBackground, FillBackgroundHdl));
+
+ ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
+ if (pMainViewShell)
+ {
+ FrameView *pFrameView = pMainViewShell->GetFrameView();
+
+ if ( pFrameView->GetViewShEditMode() == EditMode::Page )
+ {
+ SdPage* mpPage = pMainViewShell->getCurrentPage();
+ populateMasterSlideDropdown();
+
+ OUString aLayoutName( mpPage->GetLayoutName() );
+ aLayoutName = aLayoutName.copy(0,aLayoutName.indexOf(SD_LT_SEPARATOR));
+ mxMasterSlide->set_active_text(aLayoutName);
+ }
+ }
+
+ mxFillStyle->set_active(static_cast< sal_Int32 >(NONE));
+
+ mxDspMasterBackground->connect_toggled(LINK(this, SlideBackground, DspBackground));
+ mxDspMasterObjects->connect_toggled(LINK(this, SlideBackground, DspObjects));
+
+ //margins
+ mxMarginSelectBox->connect_changed(LINK(this, SlideBackground, ModifyMarginHdl));
+
+ Update();
+ UpdateMarginBox();
+}
+
+void SlideBackground::DumpAsPropertyTree(::tools::JsonWriter& rJsonWriter)
+{
+ if (mxPaperSizeBox->get_active() == -1)
+ {
+ mpBindings->Update(SID_ATTR_PAGE_SIZE);
+ }
+
+ PanelLayout::DumpAsPropertyTree(rJsonWriter);
+}
+
+void SlideBackground::HandleContextChange(
+ const vcl::EnumContext& rContext)
+{
+ if (maContext == rContext)
+ return;
+ maContext = rContext;
+
+ if ( IsImpress() )
+ {
+ mxMasterLabel->set_label(SdResId(STR_MASTERSLIDE_LABEL));
+
+ // margin selector is only for Draw
+ mxMarginSelectBox->hide();
+ mxMarginLabel->hide();
+
+ if ( maContext == maImpressMasterContext )
+ {
+ mxCloseMaster->show();
+ mxEditMaster->hide();
+ mxMasterSlide->set_sensitive(false);
+ mxMasterSlide->clear();
+ mxDspMasterBackground->set_sensitive(false);
+ mxDspMasterObjects->set_sensitive(false);
+ mxFillStyle->hide();
+ mxBackgroundLabel->hide();
+ mxInsertImage->show();
+
+ mxFillLB->hide();
+ mxFillAttr->hide();
+ mxFillGrad1->hide();
+ mxFillGrad2->hide();
+ }
+ else if ( maContext == maImpressHandoutContext || maContext == maImpressNotesContext )
+ {
+ mxCloseMaster->hide();
+ mxEditMaster->hide();
+ mxMasterSlide->set_sensitive(false);
+ mxMasterSlide->clear();
+ mxDspMasterBackground->set_sensitive(false);
+ mxDspMasterObjects->set_sensitive(false);
+ mxFillStyle->hide();
+ mxBackgroundLabel->hide();
+ mxInsertImage->hide();
+ }
+ else if (maContext == maImpressOtherContext)
+ {
+ mxCloseMaster->hide();
+ mxEditMaster->show();
+ mxMasterSlide->set_sensitive(true);
+ populateMasterSlideDropdown();
+ mxDspMasterBackground->set_sensitive(true);
+ mxDspMasterObjects->set_sensitive(true);
+ mxFillStyle->show();
+ mxBackgroundLabel->show();
+ mxInsertImage->show();
+ }
+
+ // Need to do a relayouting, otherwise the panel size is not updated after show / hide controls
+ if (m_pPanel)
+ m_pPanel->TriggerDeckLayouting();
+
+ }
+ else if ( IsDraw() )
+ {
+ mxMasterLabel->set_label(SdResId(STR_MASTERPAGE_LABEL));
+ mxDspMasterBackground->hide();
+ mxDspMasterObjects->hide();
+
+ if (maContext == maDrawOtherContext)
+ {
+ mxEditMaster->hide();
+ mxFillStyle->show();
+ mxBackgroundLabel->show();
+ }
+ else if (maContext == maDrawMasterContext)
+ {
+ mxFillStyle->hide();
+ mxBackgroundLabel->hide();
+ }
+ }
+
+ // The Insert Image button in the sidebar issues .uno:SelectBackground,
+ // which when invoked without arguments will open the file-open-dialog
+ // to prompt the user to select a file. This is useless in LOOL.
+ // Hide for now so the user will only be able to use the menu to insert
+ // background image, which prompts the user for file selection in the browser.
+ if (comphelper::LibreOfficeKit::isActive())
+ mxInsertImage->hide();
+}
+
+void SlideBackground::Update()
+{
+ eFillStyle nPos = static_cast<eFillStyle>(mxFillStyle->get_active());
+
+ if(maContext != maImpressOtherContext && maContext != maDrawOtherContext)
+ nPos = NONE;
+
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ if (!pSh)
+ return;
+
+ switch(nPos)
+ {
+ case NONE:
+ {
+ mxFillLB->hide();
+ mxFillAttr->hide();
+ mxFillGrad1->hide();
+ mxFillGrad2->hide();
+ }
+ break;
+ case SOLID:
+ {
+ mxFillAttr->hide();
+ mxFillGrad1->hide();
+ mxFillGrad2->hide();
+ mxFillLB->show();
+ const Color aColor = GetColorSetOrDefault();
+ mxFillLB->SelectEntry(aColor);
+ }
+ break;
+ case GRADIENT:
+ {
+ mxFillLB->hide();
+ mxFillAttr->hide();
+ mxFillGrad1->show();
+ mxFillGrad2->show();
+
+ const XGradient xGradient = GetGradientSetOrDefault();
+ const Color aStartColor = xGradient.GetStartColor();
+ mxFillGrad1->SelectEntry(aStartColor);
+ const Color aEndColor = xGradient.GetEndColor();
+ mxFillGrad2->SelectEntry(aEndColor);
+ }
+ break;
+
+ case HATCH:
+ {
+ mxFillLB->hide();
+ mxFillAttr->show();
+ mxFillAttr->clear();
+ SvxFillAttrBox::Fill(*mxFillAttr, pSh->GetItem(SID_HATCH_LIST)->GetHatchList());
+ mxFillGrad1->hide();
+ mxFillGrad2->hide();
+
+ const OUString aHatchName = GetHatchingSetOrDefault();
+ mxFillAttr->set_active_text( aHatchName );
+ }
+ break;
+
+ case BITMAP:
+ case PATTERN:
+ {
+ mxFillLB->hide();
+ mxFillAttr->show();
+ mxFillAttr->clear();
+ mxFillGrad1->hide();
+ mxFillGrad2->hide();
+ OUString aName;
+ if(nPos == BITMAP)
+ {
+ SvxFillAttrBox::Fill(*mxFillAttr, pSh->GetItem(SID_BITMAP_LIST)->GetBitmapList());
+ aName = GetBitmapSetOrDefault();
+ }
+ else if(nPos == PATTERN)
+ {
+ SvxFillAttrBox::Fill(*mxFillAttr, pSh->GetItem(SID_PATTERN_LIST)->GetPatternList());
+ aName = GetPatternSetOrDefault();
+ }
+ mxFillAttr->set_active_text( aName );
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Need to do a relayouting, otherwise the panel size is not updated after show / hide controls
+ if (m_pPanel)
+ m_pPanel->TriggerDeckLayouting();
+}
+
+void SlideBackground::UpdateMarginBox()
+{
+ m_nPageLeftMargin = mpPageLRMarginItem->GetLeft();
+ m_nPageRightMargin = mpPageLRMarginItem->GetRight();
+ m_nPageTopMargin = mpPageULMarginItem->GetUpper();
+ m_nPageBottomMargin = mpPageULMarginItem->GetLower();
+
+ int nCustomIndex = mxMarginSelectBox->find_text(maCustomEntry);
+
+ if( IsNone(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin) )
+ {
+ mxMarginSelectBox->set_active(0);
+ if (nCustomIndex != -1)
+ mxMarginSelectBox->remove(nCustomIndex);
+ }
+ else if( IsNarrow(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin) )
+ {
+ mxMarginSelectBox->set_active(1);
+ if (nCustomIndex != -1)
+ mxMarginSelectBox->remove(nCustomIndex);
+ }
+ else if( IsModerate(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin) )
+ {
+ mxMarginSelectBox->set_active(2);
+ if (nCustomIndex != -1)
+ mxMarginSelectBox->remove(nCustomIndex);
+ }
+ else if( IsNormal075(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin) )
+ {
+ mxMarginSelectBox->set_active(3);
+ if (nCustomIndex != -1)
+ mxMarginSelectBox->remove(nCustomIndex);
+ }
+ else if( IsNormal100(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin) )
+ {
+ mxMarginSelectBox->set_active(4);
+ if (nCustomIndex != -1)
+ mxMarginSelectBox->remove(nCustomIndex);
+ }
+ else if( IsNormal125(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin) )
+ {
+ mxMarginSelectBox->set_active(5);
+ if (nCustomIndex != -1)
+ mxMarginSelectBox->remove(nCustomIndex);
+ }
+ else if( IsWide(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin) )
+ {
+ mxMarginSelectBox->set_active(6);
+ if (nCustomIndex != -1)
+ mxMarginSelectBox->remove(nCustomIndex);
+ }
+ else
+ {
+ if (nCustomIndex == -1)
+ mxMarginSelectBox->append_text(maCustomEntry);
+ mxMarginSelectBox->set_active_text(maCustomEntry);
+ }
+}
+
+void SlideBackground::SetPanelTitle( const OUString& rTitle )
+{
+ Reference<frame::XController2> xController( mxFrame->getController(), uno::UNO_QUERY);
+ if ( !xController.is() )
+ return;
+
+ Reference<ui::XSidebarProvider> xSidebarProvider = xController->getSidebar();
+ if ( !xSidebarProvider.is() )
+ return;
+
+ Reference<ui::XDecks> xDecks = xSidebarProvider->getDecks();
+ if ( !xDecks.is() )
+ return;
+
+ Reference<ui::XDeck> xDeck ( xDecks->getByName("PropertyDeck"), uno::UNO_QUERY);
+ if ( !xDeck.is() )
+ return;
+
+ Reference<ui::XPanels> xPanels = xDeck->getPanels();
+ if ( !xPanels.is() )
+ return;
+
+ if (xPanels->hasByName("SlideBackgroundPanel"))
+ {
+ Reference<ui::XPanel> xPanel ( xPanels->getByName("SlideBackgroundPanel"), uno::UNO_QUERY);
+ if ( !xPanel.is() )
+ return;
+
+ xPanel->setTitle( rTitle );
+ }
+}
+
+void SlideBackground::addListener()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this, SlideBackground, EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->AddEventListener( aLink );
+}
+
+void SlideBackground::removeListener()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this, SlideBackground, EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
+}
+
+IMPL_LINK(SlideBackground, EventMultiplexerListener,
+ tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ // add more events as per requirement
+ // Master Page change triggers a shape change event. Solves sync problem.
+ case EventMultiplexerEventId::ShapeChanged:
+ populateMasterSlideDropdown();
+ break;
+ case EventMultiplexerEventId::EditModeNormal:
+ mbSwitchModeToNormal = true;
+ break;
+ case EventMultiplexerEventId::EditModeMaster:
+ mbSwitchModeToMaster = true;
+ break;
+ case EventMultiplexerEventId::EditViewSelection:
+ case EventMultiplexerEventId::EndTextEdit:
+ {
+ if ( mbSwitchModeToMaster )
+ {
+ if( IsImpress() )
+ SetPanelTitle(SdResId(STR_MASTERSLIDE_NAME));
+ else
+ SetPanelTitle(SdResId(STR_MASTERPAGE_NAME));
+ mbSwitchModeToMaster = false;
+ }
+ else if ( mbSwitchModeToNormal )
+ {
+ if( IsImpress() )
+ SetPanelTitle(SdResId(STR_SLIDE_NAME));
+ else
+ SetPanelTitle(SdResId(STR_PAGE_NAME));
+ mbSwitchModeToNormal = false;
+ }
+
+ }
+ break;
+ case EventMultiplexerEventId::CurrentPageChanged:
+ {
+ static const sal_uInt16 SidArray[] = {
+ SID_ATTR_PAGE_COLOR,
+ SID_ATTR_PAGE_GRADIENT,
+ SID_ATTR_PAGE_HATCH,
+ SID_ATTR_PAGE_BITMAP,
+ SID_ATTR_PAGE_FILLSTYLE,
+ SID_DISPLAY_MASTER_BACKGROUND,
+ SID_DISPLAY_MASTER_OBJECTS,
+ 0 };
+ updateMasterSlideSelection();
+ GetBindings()->Invalidate( SidArray );
+ }
+ break;
+ case EventMultiplexerEventId::ViewAdded:
+ {
+ if(!mbTitle)
+ {
+ if( IsDraw() )
+ {
+ mxCloseMaster->hide();
+ mxEditMaster->hide();
+ if( maContext == maDrawMasterContext)
+ SetPanelTitle(SdResId(STR_MASTERPAGE_NAME));
+ else
+ SetPanelTitle(SdResId(STR_PAGE_NAME));
+ }
+ else if ( maContext == maImpressOtherContext || maContext == maImpressMasterContext )
+ {
+ if( maContext == maImpressMasterContext )
+ SetPanelTitle(SdResId(STR_MASTERSLIDE_NAME));
+ else
+ SetPanelTitle(SdResId(STR_SLIDE_NAME));
+ }
+ else if ( maContext == maImpressNotesContext )
+ {
+ mxMasterLabel->set_label(SdResId(STR_MASTERSLIDE_LABEL));
+ ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
+
+ if (pMainViewShell)
+ {
+ DrawViewShell* pDrawViewShell = static_cast<DrawViewShell*>(pMainViewShell);
+ if ( pDrawViewShell->GetEditMode() == EditMode::MasterPage)
+ SetPanelTitle(SdResId(STR_MASTERSLIDE_NAME));
+ else // EditMode::Page
+ SetPanelTitle(SdResId(STR_SLIDE_NAME));
+ }
+ }
+ mbTitle = true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void SlideBackground::populateMasterSlideDropdown()
+{
+ mxMasterSlide->clear();
+ ::sd::DrawDocShell* pDocSh = dynamic_cast<::sd::DrawDocShell*>( SfxObjectShell::Current() );
+ SdDrawDocument* pDoc = pDocSh ? pDocSh->GetDoc() : nullptr;
+ sal_uInt16 nCount = pDoc ? pDoc->GetMasterPageCount() : 0;
+ for( sal_uInt16 nLayout = 0; nLayout < nCount; nLayout++ )
+ {
+ SdPage* pMaster = static_cast<SdPage*>(pDoc->GetMasterPage(nLayout));
+ if( pMaster->GetPageKind() == PageKind::Standard)
+ {
+ OUString aLayoutName(pMaster->GetLayoutName());
+ aLayoutName = aLayoutName.copy(0,aLayoutName.indexOf(SD_LT_SEPARATOR));
+ mxMasterSlide->append_text(aLayoutName);
+ }
+ }
+ updateMasterSlideSelection();
+}
+
+void SlideBackground::updateMasterSlideSelection()
+{
+ ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
+ SdPage* pPage = pMainViewShell ? pMainViewShell->getCurrentPage() : nullptr;
+ if (pPage != nullptr && pPage->TRG_HasMasterPage())
+ {
+ SdrPage& rMasterPage (pPage->TRG_GetMasterPage());
+ SdPage* pMasterPage = static_cast<SdPage*>(&rMasterPage);
+ mxMasterSlide->set_active_text(pMasterPage->GetName());
+ }
+}
+
+SlideBackground::~SlideBackground()
+{
+ removeListener();
+
+ mxCustomEntry.reset();
+ mxMarginLabel.reset();
+ mxPaperSizeBox.reset();
+ mxPaperOrientation.reset();
+ mxMasterSlide.reset();
+ mxBackgroundLabel.reset();
+ mxFillAttr.reset();
+ mxFillGrad1.reset();
+ mxFillGrad2.reset();
+ mxFillStyle.reset();
+ mxFillLB.reset();
+ mxInsertImage.reset();
+ mxMarginSelectBox.reset();
+ mxDspMasterBackground.reset();
+ mxDspMasterObjects.reset();
+ mxMasterLabel.reset();
+ mxEditMaster.reset();
+ mxCloseMaster.reset();
+
+ maPaperSizeController.dispose();
+ maPaperOrientationController.dispose();
+ maPaperMarginLRController.dispose();
+ maPaperMarginULController.dispose();
+ maBckColorController.dispose();
+ maBckGradientController.dispose();
+ maBckHatchController.dispose();
+ maBckBitmapController.dispose();
+ maBckFillStyleController.dispose();
+ maBckImageController.dispose();
+ maDspBckController.dispose();
+ maDspObjController.dispose();
+ maMetricController.dispose();
+ maCloseMasterController.dispose();
+
+ mpPageItem.reset();
+ mpColorItem.reset();
+ mpHatchItem.reset();
+ mpBitmapItem.reset();
+ mpPageLRMarginItem.reset();
+ mpPageULMarginItem.reset();
+}
+
+void SlideBackground::ExecuteMarginLRChange(const ::tools::Long mnPageLeftMargin, const ::tools::Long mnPageRightMargin)
+{
+ mpPageLRMarginItem->SetLeft(mnPageLeftMargin);
+ mpPageLRMarginItem->SetRight(mnPageRightMargin);
+ GetBindings()->GetDispatcher()->ExecuteList( SID_ATTR_PAGE_LRSPACE, SfxCallMode::RECORD, { mpPageLRMarginItem.get() } );
+}
+
+void SlideBackground::ExecuteMarginULChange(const ::tools::Long mnPageTopMargin, const ::tools::Long mnPageBottomMargin)
+{
+ mpPageULMarginItem->SetUpper(mnPageTopMargin);
+ mpPageULMarginItem->SetLower(mnPageBottomMargin);
+ GetBindings()->GetDispatcher()->ExecuteList( SID_ATTR_PAGE_ULSPACE, SfxCallMode::RECORD, { mpPageULMarginItem.get() } );
+}
+
+Color const & SlideBackground::GetColorSetOrDefault()
+{
+ // Tango Sky Blue 1, to be consistent w/ area fill panel (b/c COL_AUTO for slides is transparent)
+ if ( !mpColorItem )
+ mpColorItem.reset( new XFillColorItem( OUString(), Color(0x72, 0x9f, 0xcf) ) );
+
+ return mpColorItem->GetColorValue();
+}
+
+XGradient const & SlideBackground::GetGradientSetOrDefault()
+{
+ if( !mpGradientItem )
+ {
+ XGradient aGradient;
+ OUString aGradientName;
+ if (SfxObjectShell* pSh = SfxObjectShell::Current())
+ {
+ const SvxGradientListItem * pGradListItem = pSh->GetItem(SID_GRADIENT_LIST);
+ aGradient = pGradListItem->GetGradientList()->GetGradient(0)->GetGradient();
+ aGradientName = pGradListItem->GetGradientList()->GetGradient(0)->GetName();
+ }
+ mpGradientItem.reset( new XFillGradientItem( aGradientName, aGradient ) );
+ }
+
+ return mpGradientItem->GetGradientValue();
+}
+
+OUString const & SlideBackground::GetHatchingSetOrDefault()
+{
+ if( !mpHatchItem )
+ {
+ XHatch aHatch;
+ OUString aHatchName;
+ if (SfxObjectShell* pSh = SfxObjectShell::Current())
+ {
+ const SvxHatchListItem * pHatchListItem = pSh->GetItem(SID_HATCH_LIST);
+ aHatch = pHatchListItem->GetHatchList()->GetHatch(0)->GetHatch();
+ aHatchName = pHatchListItem->GetHatchList()->GetHatch(0)->GetName();
+ }
+ mpHatchItem.reset( new XFillHatchItem( aHatchName, aHatch ) );
+ }
+
+ return mpHatchItem->GetName();
+}
+
+OUString const & SlideBackground::GetBitmapSetOrDefault()
+{
+ if( !mpBitmapItem || mpBitmapItem->isPattern())
+ {
+ GraphicObject aGraphObj;
+ OUString aBmpName;
+ if (SfxObjectShell* pSh = SfxObjectShell::Current())
+ {
+ const SvxBitmapListItem * pBmpListItem = pSh->GetItem(SID_BITMAP_LIST);
+ aGraphObj = pBmpListItem->GetBitmapList()->GetBitmap(0)->GetGraphicObject();
+ aBmpName = pBmpListItem->GetBitmapList()->GetBitmap(0)->GetName();
+ }
+ mpBitmapItem.reset( new XFillBitmapItem( aBmpName, aGraphObj ) );
+ }
+
+ return mpBitmapItem->GetName();
+}
+
+OUString const & SlideBackground::GetPatternSetOrDefault()
+{
+ if( !mpBitmapItem || !(mpBitmapItem->isPattern()))
+ {
+ GraphicObject aGraphObj;
+ OUString aPtrnName;
+ if (SfxObjectShell* pSh = SfxObjectShell::Current())
+ {
+ const SvxPatternListItem * pPtrnListItem = pSh->GetItem(SID_PATTERN_LIST);
+ aGraphObj = pPtrnListItem->GetPatternList()->GetBitmap(0)->GetGraphicObject();
+ aPtrnName = pPtrnListItem->GetPatternList()->GetBitmap(0)->GetName();
+ }
+ mpBitmapItem.reset( new XFillBitmapItem( aPtrnName, aGraphObj ) );
+ }
+
+ return mpBitmapItem->GetName();
+}
+
+void SlideBackground::NotifyItemUpdate(
+ const sal_uInt16 nSID,
+ const SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ switch(nSID)
+ {
+
+ case SID_ATTR_PAGE_COLOR:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ mxFillStyle->set_active(static_cast< sal_Int32 >(SOLID));
+ mpColorItem.reset(pState ? static_cast< XFillColorItem* >(pState->Clone()) : nullptr);
+ Update();
+ }
+ }
+ break;
+
+ case SID_ATTR_PAGE_HATCH:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ mxFillStyle->set_active(static_cast< sal_Int32 >(HATCH));
+ mpHatchItem.reset(pState ? static_cast < XFillHatchItem* >(pState->Clone()) : nullptr);
+ Update();
+ }
+ }
+ break;
+
+ case SID_ATTR_PAGE_GRADIENT:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ mxFillStyle->set_active(static_cast< sal_Int32>(GRADIENT));
+ mpGradientItem.reset(pState ? static_cast< XFillGradientItem* >(pState->Clone()) : nullptr);
+ Update();
+ }
+ }
+ break;
+ case SID_ATTR_PAGE_BITMAP:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ mpBitmapItem.reset(pState ? static_cast< XFillBitmapItem* >(pState->Clone()) : nullptr);
+ if(mpBitmapItem)
+ {
+ if(mpBitmapItem->isPattern())
+ mxFillStyle->set_active(static_cast< sal_Int32 >(PATTERN));
+ else
+ mxFillStyle->set_active(static_cast< sal_Int32 >(BITMAP));
+ }
+ else
+ mxFillStyle->set_active(static_cast< sal_Int32 >(BITMAP));
+ Update();
+ }
+ }
+ break;
+
+ case SID_ATTR_PAGE_FILLSTYLE:
+ {
+ const XFillStyleItem* pFillStyleItem = nullptr;
+ if (eState >= SfxItemState::DEFAULT)
+ pFillStyleItem = dynamic_cast< const XFillStyleItem* >(pState);
+ if (pFillStyleItem)
+ {
+ css::drawing::FillStyle eXFS = pFillStyleItem->GetValue();
+ switch(eXFS)
+ {
+ case drawing::FillStyle_NONE:
+ mxFillStyle->set_active(static_cast< sal_Int32 >(NONE));
+ break;
+ case drawing::FillStyle_SOLID:
+ mxFillStyle->set_active(static_cast< sal_Int32 >(SOLID));
+ break;
+ case drawing::FillStyle_GRADIENT:
+ mxFillStyle->set_active(static_cast< sal_Int32 >(GRADIENT));
+ break;
+ case drawing::FillStyle_HATCH:
+ mxFillStyle->set_active(static_cast< sal_Int32 >(HATCH));
+ break;
+ case drawing::FillStyle_BITMAP:
+ {
+ if(mpBitmapItem->isPattern())
+ mxFillStyle->set_active(static_cast< sal_Int32 >(PATTERN));
+ else
+ mxFillStyle->set_active(static_cast< sal_Int32 >(BITMAP));
+ }
+ break;
+ default:
+ break;
+ }
+ Update();
+ }
+ }
+ break;
+
+ case SID_ATTR_PAGE_SIZE:
+ {
+ const SvxSizeItem* pSizeItem = nullptr;
+ if (eState >= SfxItemState::DEFAULT)
+ pSizeItem = dynamic_cast<const SvxSizeItem*>(pState);
+ if (pSizeItem)
+ {
+ Size aPaperSize = pSizeItem->GetSize();
+ if (mxPaperOrientation->get_active() == 0)
+ Swap(aPaperSize);
+
+ Paper ePaper = SvxPaperInfo::GetSvxPaper(aPaperSize, meUnit);
+ mxPaperSizeBox->set_active_id( ePaper );
+ }
+ }
+ break;
+
+ case SID_ATTR_PAGE:
+ {
+ const SvxPageItem* pPageItem = nullptr;
+ if (eState >= SfxItemState::DEFAULT)
+ pPageItem = dynamic_cast<const SvxPageItem*>(pState);
+ if (pPageItem)
+ {
+ mpPageItem.reset(pPageItem->Clone());
+ bool bIsLandscape = mpPageItem->IsLandscape();
+ mxPaperOrientation->set_active( bIsLandscape ? 0 : 1 );
+ }
+ }
+ break;
+
+ case SID_ATTR_PAGE_LRSPACE:
+ {
+ const SvxLongLRSpaceItem* pLRItem = nullptr;
+ if (eState >= SfxItemState::DEFAULT)
+ pLRItem = dynamic_cast<const SvxLongLRSpaceItem*>(pState);
+ if (pLRItem)
+ {
+ mpPageLRMarginItem.reset( static_cast<SvxLongLRSpaceItem*>(pState->Clone()) );
+ UpdateMarginBox();
+ }
+ }
+ break;
+
+ case SID_ATTR_PAGE_ULSPACE:
+ {
+ const SvxLongULSpaceItem* pULItem = nullptr;
+ if (eState >= SfxItemState::DEFAULT)
+ pULItem = dynamic_cast<const SvxLongULSpaceItem*>(pState);
+ if (pULItem)
+ {
+ mpPageULMarginItem.reset( static_cast<SvxLongULSpaceItem*>(pState->Clone()) );
+ UpdateMarginBox();
+ }
+ }
+ break;
+
+ case SID_DISPLAY_MASTER_BACKGROUND:
+ {
+ const SfxBoolItem* pBoolItem = nullptr;
+ if (eState >= SfxItemState::DEFAULT)
+ pBoolItem = dynamic_cast< const SfxBoolItem* >(pState);
+ if (pBoolItem)
+ mxDspMasterBackground->set_active(pBoolItem->GetValue());
+ }
+ break;
+ case SID_DISPLAY_MASTER_OBJECTS:
+ {
+ const SfxBoolItem* pBoolItem = nullptr;
+ if (eState >= SfxItemState::DEFAULT)
+ pBoolItem = dynamic_cast< const SfxBoolItem* >(pState);
+ if (pBoolItem)
+ mxDspMasterObjects->set_active(pBoolItem->GetValue());
+ }
+ break;
+ case SID_SELECT_BACKGROUND:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ mxFillStyle->set_active(static_cast< sal_Int32 >(BITMAP));
+ Update();
+ }
+ }
+ break;
+ case SID_ATTR_METRIC:
+ {
+ FieldUnit eFUnit = GetCurrentUnit(eState, pState);
+ if (meFUnit != eFUnit)
+ {
+ meFUnit = eFUnit;
+ SetMarginsFieldUnit();
+ UpdateMarginBox();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+IMPL_LINK_NOARG(SlideBackground, FillStyleModifyHdl, weld::ComboBox&, void)
+{
+ const eFillStyle nPos = static_cast<eFillStyle>(mxFillStyle->get_active());
+ Update();
+
+ switch (nPos)
+ {
+ case NONE:
+ {
+ const XFillStyleItem aXFillStyleItem(drawing::FillStyle_NONE);
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_FILLSTYLE, SfxCallMode::RECORD, { &aXFillStyleItem });
+ }
+ break;
+
+ case SOLID:
+ {
+ if (mpColorItem)
+ {
+ const XFillColorItem aItem( OUString(), mpColorItem->GetColorValue() );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_COLOR, SfxCallMode::RECORD, { &aItem });
+ }
+ }
+ break;
+
+ case GRADIENT:
+ {
+ if (mpGradientItem)
+ {
+ const XFillGradientItem aItem( mpGradientItem->GetName(), mpGradientItem->GetGradientValue() );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_GRADIENT, SfxCallMode::RECORD, { &aItem });
+ }
+ }
+ break;
+
+ case HATCH:
+ {
+ if (mpHatchItem)
+ {
+ const XFillHatchItem aItem( mpHatchItem->GetName(), mpHatchItem->GetHatchValue() );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_HATCH, SfxCallMode::RECORD, { &aItem });
+ }
+ }
+ break;
+
+ case BITMAP:
+ case PATTERN:
+ {
+ if (mpBitmapItem)
+ {
+ const XFillBitmapItem aItem( mpBitmapItem->GetName(), mpBitmapItem->GetGraphicObject() );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_BITMAP, SfxCallMode::RECORD, { &aItem });
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+//TODO mxFillStyle->Selected();
+}
+
+IMPL_LINK_NOARG(SlideBackground, PaperSizeModifyHdl, weld::ComboBox&, void)
+{
+ const Paper ePaper = mxPaperSizeBox->get_active_id();
+ Size aSize(SvxPaperInfo::GetPaperSize(ePaper, meUnit));
+
+ if (mxPaperOrientation->get_active() == 0)
+ Swap(aSize);
+
+ mpPageItem->SetLandscape(mxPaperOrientation->get_active() == 0);
+ const SvxSizeItem aSizeItem(SID_ATTR_PAGE_SIZE, aSize);
+ // Page/slide properties dialog (FuPage::ExecuteDialog and ::ApplyItemSet) misuses
+ // SID_ATTR_PAGE_EXT1 to distinguish between Impress and Draw, as for whether to fit
+ // objects to paper size. Until that is handled somehow better, we do the same here
+ const SfxBoolItem aFitObjs(SID_ATTR_PAGE_EXT1, IsImpress());
+
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_SIZE, SfxCallMode::RECORD,
+ { &aSizeItem, mpPageItem.get(), &aFitObjs });
+
+ // Notify LOK clients of the page size change.
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ if (pViewShell->GetDocId() == mrBase.GetDocId())
+ {
+ SdXImpressDocument* pDoc = comphelper::getFromUnoTunnel<SdXImpressDocument>(pViewShell->GetCurrentDocument());
+ SfxLokHelper::notifyDocumentSizeChangedAllViews(pDoc);
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+IMPL_LINK_NOARG(SlideBackground, FillColorHdl, ColorListBox&, void)
+{
+ const drawing::FillStyle eXFS = static_cast<drawing::FillStyle>(mxFillStyle->get_active());
+ switch(eXFS)
+ {
+ case drawing::FillStyle_SOLID:
+ {
+ XFillColorItem aItem(OUString(), mxFillLB->GetSelectEntryColor());
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_COLOR, SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+ case drawing::FillStyle_GRADIENT:
+ {
+ XGradient aGradient;
+ aGradient.SetStartColor(mxFillGrad1->GetSelectEntryColor());
+ aGradient.SetEndColor(mxFillGrad2->GetSelectEntryColor());
+
+ // the name doesn't really matter, it'll be converted to unique one eventually,
+ // but it has to be non-empty
+ XFillGradientItem aItem("gradient", aGradient);
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_GRADIENT, SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+IMPL_LINK_NOARG(SlideBackground, FillBackgroundHdl, weld::ComboBox&, void)
+{
+ const eFillStyle nFillPos = static_cast<eFillStyle>(mxFillStyle->get_active());
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ if (!pSh)
+ return;
+ switch(nFillPos)
+ {
+
+ case HATCH:
+ {
+ const SvxHatchListItem * pHatchListItem = pSh->GetItem(SID_HATCH_LIST);
+ sal_uInt16 nPos = mxFillAttr->get_active();
+ XHatch aHatch = pHatchListItem->GetHatchList()->GetHatch(nPos)->GetHatch();
+ const OUString aHatchName = pHatchListItem->GetHatchList()->GetHatch(nPos)->GetName();
+
+ XFillHatchItem aItem(aHatchName, aHatch);
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_HATCH, SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+
+ case BITMAP:
+ case PATTERN:
+ {
+ sal_Int16 nPos = mxFillAttr->get_active();
+ GraphicObject aBitmap;
+ OUString aName;
+ if( nFillPos == BITMAP )
+ {
+ SvxBitmapListItem const * pBitmapListItem = pSh->GetItem(SID_BITMAP_LIST);
+ aBitmap = pBitmapListItem->GetBitmapList()->GetBitmap(nPos)->GetGraphicObject();
+ aName = pBitmapListItem->GetBitmapList()->GetBitmap(nPos)->GetName();
+ }
+ else if( nFillPos == PATTERN )
+ {
+ SvxPatternListItem const * pPatternListItem = pSh->GetItem(SID_PATTERN_LIST);
+ aBitmap = pPatternListItem->GetPatternList()->GetBitmap(nPos)->GetGraphicObject();
+ aName = pPatternListItem->GetPatternList()->GetBitmap(nPos)->GetName();
+ }
+ XFillBitmapItem aItem(aName, aBitmap);
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_BITMAP, SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+IMPL_LINK_NOARG(SlideBackground, AssignMasterPage, weld::ComboBox&, void)
+{
+ ::sd::DrawDocShell* pDocSh = dynamic_cast<::sd::DrawDocShell*>( SfxObjectShell::Current() );
+ SdDrawDocument* pDoc = pDocSh ? pDocSh->GetDoc() : nullptr;
+ if (!pDoc)
+ return;
+
+ auto pSSVS = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(mrBase);
+ if (pSSVS == nullptr)
+ return;
+
+ auto& rSSController = pSSVS->GetSlideSorter().GetController();
+ auto& rPageSelector = rSSController.GetPageSelector();
+
+ for( sal_uInt16 nPage = 0; nPage < pDoc->GetSdPageCount(PageKind::Standard); nPage++ )
+ {
+ if (rPageSelector.IsPageSelected(nPage))
+ {
+ OUString aLayoutName(mxMasterSlide->get_active_text());
+ pDoc->SetMasterPage(nPage, aLayoutName, pDoc, false, false);
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SlideBackground, EditMasterHdl, weld::Button&, void)
+{
+ GetBindings()->GetDispatcher()->Execute( SID_SLIDE_MASTER_MODE, SfxCallMode::RECORD );
+}
+
+IMPL_LINK_NOARG(SlideBackground, SelectBgHdl, weld::Button&, void)
+{
+ GetBindings()->GetDispatcher()->Execute( SID_SELECT_BACKGROUND, SfxCallMode::RECORD );
+}
+
+IMPL_LINK_NOARG(SlideBackground, CloseMasterHdl, weld::Button&, void)
+{
+ GetBindings()->GetDispatcher()->Execute( SID_CLOSE_MASTER_VIEW, SfxCallMode::RECORD );
+}
+
+IMPL_LINK_NOARG(SlideBackground, DspBackground, weld::Toggleable&, void)
+{
+ bool IsChecked = mxDspMasterBackground->get_active();
+ const SfxBoolItem aBoolItem(SID_DISPLAY_MASTER_BACKGROUND, IsChecked);
+ GetBindings()->GetDispatcher()->ExecuteList(SID_DISPLAY_MASTER_BACKGROUND, SfxCallMode::RECORD, { &aBoolItem });
+}
+
+IMPL_LINK_NOARG(SlideBackground, DspObjects, weld::Toggleable&, void)
+{
+ bool IsChecked = mxDspMasterObjects->get_active();
+ const SfxBoolItem aBoolItem(SID_DISPLAY_MASTER_OBJECTS,IsChecked);
+ GetBindings()->GetDispatcher()->ExecuteList(SID_DISPLAY_MASTER_OBJECTS, SfxCallMode::RECORD, { &aBoolItem, &aBoolItem });
+}
+
+IMPL_LINK_NOARG( SlideBackground, ModifyMarginHdl, weld::ComboBox&, void )
+{
+ bool bApplyNewPageMargins = true;
+ switch ( mxMarginSelectBox->get_active() )
+ {
+ case 0:
+ SetNone(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin);
+ break;
+ case 1:
+ SetNarrow(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin);
+ break;
+ case 2:
+ SetModerate(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin);
+ break;
+ case 3:
+ SetNormal075(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin);
+ break;
+ case 4:
+ SetNormal100(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin);
+ break;
+ case 5:
+ SetNormal125(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin);
+ break;
+ case 6:
+ SetWide(m_nPageLeftMargin, m_nPageRightMargin, m_nPageTopMargin, m_nPageBottomMargin);
+ break;
+ default:
+ bApplyNewPageMargins = false;
+ break;
+ }
+
+ if(bApplyNewPageMargins)
+ {
+ ExecuteMarginLRChange(m_nPageLeftMargin, m_nPageRightMargin);
+ ExecuteMarginULChange(m_nPageTopMargin, m_nPageBottomMargin);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/sidebar/SlideBackground.hxx b/sd/source/ui/sidebar/SlideBackground.hxx
new file mode 100644
index 000000000..25af0a4af
--- /dev/null
+++ b/sd/source/ui/sidebar/SlideBackground.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <svx/papersizelistbox.hxx>
+#include <sfx2/sidebar/IContextChangeReceiver.hxx>
+#include <vcl/EnumContext.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+
+namespace sd { class ViewShellBase; }
+namespace sd::tools { class EventMultiplexerEvent; }
+
+class ColorListBox;
+class SvxPageItem;
+class SvxLongLRSpaceItem;
+class SvxLongULSpaceItem;
+class XFillColorItem;
+class XGradient;
+class XFillGradientItem;
+class XFillBitmapItem;
+class XFillHatchItem;
+
+namespace sd::sidebar {
+
+class SlideBackground :
+ public PanelLayout,
+ public ::sfx2::sidebar::IContextChangeReceiver,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+ SlideBackground(
+ weld::Widget* pParent,
+ ViewShellBase& rBase,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings );
+ virtual ~SlideBackground() override;
+ SfxBindings* GetBindings() { return mpBindings; }
+ // Window
+ virtual void NotifyItemUpdate(
+ const sal_uInt16 nSID,
+ const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(
+ const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override {};
+
+ virtual void HandleContextChange(
+ const vcl::EnumContext& rContext) override;
+ virtual void DumpAsPropertyTree(::tools::JsonWriter&) override;
+
+private:
+
+ ViewShellBase& mrBase;
+
+ std::unique_ptr<SvxPaperSizeListBox> mxPaperSizeBox;
+ std::unique_ptr<weld::ComboBox> mxPaperOrientation;
+ std::unique_ptr<weld::ComboBox> mxMasterSlide;
+ std::unique_ptr<weld::Label> mxBackgroundLabel;
+ std::unique_ptr<weld::ComboBox> mxFillStyle;
+ std::unique_ptr<ColorListBox> mxFillLB;
+ std::unique_ptr<weld::ComboBox> mxFillAttr;
+ std::unique_ptr<ColorListBox> mxFillGrad1;
+ std::unique_ptr<ColorListBox> mxFillGrad2;
+ std::unique_ptr<weld::Button> mxInsertImage;
+ std::unique_ptr<weld::CheckButton> mxDspMasterBackground;
+ std::unique_ptr<weld::CheckButton> mxDspMasterObjects;
+ std::unique_ptr<weld::Button> mxCloseMaster;
+ std::unique_ptr<weld::Button> mxEditMaster;
+ std::unique_ptr<weld::Label> mxMasterLabel;
+ std::unique_ptr<weld::ComboBox> mxMarginSelectBox;
+ std::unique_ptr<weld::Label> mxCustomEntry;
+ std::unique_ptr<weld::Label> mxMarginLabel;
+
+ ::sfx2::sidebar::ControllerItem maPaperSizeController;
+ ::sfx2::sidebar::ControllerItem maPaperOrientationController;
+ ::sfx2::sidebar::ControllerItem maPaperMarginLRController;
+ ::sfx2::sidebar::ControllerItem maPaperMarginULController;
+ ::sfx2::sidebar::ControllerItem maBckColorController;
+ ::sfx2::sidebar::ControllerItem maBckGradientController;
+ ::sfx2::sidebar::ControllerItem maBckHatchController;
+ ::sfx2::sidebar::ControllerItem maBckBitmapController;
+ ::sfx2::sidebar::ControllerItem maBckFillStyleController;
+ ::sfx2::sidebar::ControllerItem maBckImageController;
+ ::sfx2::sidebar::ControllerItem maDspBckController;
+ ::sfx2::sidebar::ControllerItem maDspObjController;
+ ::sfx2::sidebar::ControllerItem maMetricController;
+ ::sfx2::sidebar::ControllerItem maCloseMasterController;
+
+ std::unique_ptr< SvxPageItem > mpPageItem;
+ std::unique_ptr< XFillColorItem > mpColorItem;
+ std::unique_ptr< XFillGradientItem > mpGradientItem;
+ std::unique_ptr< XFillHatchItem > mpHatchItem;
+ std::unique_ptr< XFillBitmapItem > mpBitmapItem;
+
+ bool mbSwitchModeToNormal;
+ bool mbSwitchModeToMaster;
+
+ css::uno::Reference<css::frame::XFrame> mxFrame;
+ vcl::EnumContext maContext;
+ vcl::EnumContext maDrawOtherContext;
+ vcl::EnumContext maDrawMasterContext;
+ vcl::EnumContext maImpressOtherContext;
+ vcl::EnumContext maImpressMasterContext;
+ vcl::EnumContext maImpressHandoutContext;
+ vcl::EnumContext maImpressNotesContext;
+ bool mbTitle;
+ std::unique_ptr<SvxLongLRSpaceItem> mpPageLRMarginItem;
+ std::unique_ptr<SvxLongULSpaceItem> mpPageULMarginItem;
+ ::tools::Long m_nPageLeftMargin;
+ ::tools::Long m_nPageRightMargin;
+ ::tools::Long m_nPageTopMargin;
+ ::tools::Long m_nPageBottomMargin;
+ FieldUnit meFUnit;
+ OUString maCustomEntry;
+
+ SfxBindings* mpBindings;
+
+ MapUnit meUnit;
+
+ DECL_LINK(FillBackgroundHdl, weld::ComboBox&, void);
+ DECL_LINK(FillStyleModifyHdl, weld::ComboBox&, void);
+ DECL_LINK(PaperSizeModifyHdl, weld::ComboBox&, void);
+ DECL_LINK(FillColorHdl, ColorListBox&, void);
+ DECL_LINK(AssignMasterPage, weld::ComboBox&, void);
+ DECL_LINK(DspBackground, weld::Toggleable&, void);
+ DECL_LINK(DspObjects, weld::Toggleable&, void);
+ DECL_LINK(CloseMasterHdl, weld::Button&, void);
+ DECL_LINK(EditMasterHdl, weld::Button&, void);
+ DECL_LINK(SelectBgHdl, weld::Button&, void);
+ DECL_LINK(EventMultiplexerListener, tools::EventMultiplexerEvent&, void );
+ DECL_LINK( ModifyMarginHdl, weld::ComboBox&, void );
+
+ void Initialize();
+ void Update();
+ void UpdateMarginBox();
+ void SetPanelTitle(const OUString& rTitle);
+ void SetMarginsFieldUnit();
+
+ Color const & GetColorSetOrDefault();
+ XGradient const & GetGradientSetOrDefault();
+ OUString const & GetHatchingSetOrDefault();
+ OUString const & GetBitmapSetOrDefault();
+ OUString const & GetPatternSetOrDefault();
+ bool IsDraw();
+ bool IsImpress();
+ void addListener();
+ void removeListener();
+ void ExecuteMarginLRChange(const ::tools::Long mnPageLeftMargin, const ::tools::Long mnPageRightMargin);
+ void ExecuteMarginULChange(const ::tools::Long mnPageTopMargin, const ::tools::Long mnPageBottomMargin);
+ void populateMasterSlideDropdown();
+ void updateMasterSlideSelection();
+
+ static FieldUnit GetCurrentUnit(SfxItemState eState, const SfxPoolItem* pState);
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/PaneHider.cxx b/sd/source/ui/slideshow/PaneHider.cxx
new file mode 100644
index 000000000..85858c0b6
--- /dev/null
+++ b/sd/source/ui/slideshow/PaneHider.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PaneHider.hxx"
+
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include "slideshowimpl.hxx"
+#include <framework/FrameworkHelper.hxx>
+
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <com/sun/star/drawing/framework/XConfiguration.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::framework::FrameworkHelper;
+using ::com::sun::star::lang::DisposedException;
+
+namespace sd
+{
+PaneHider::PaneHider(const ViewShell& rViewShell, SlideshowImpl* pSlideShow)
+{
+ // Hide the left and right pane windows when a slideshow exists and is
+ // not full screen.
+ if (pSlideShow == nullptr || pSlideShow->isFullScreen())
+ return;
+
+ try
+ {
+ Reference<XControllerManager> xControllerManager(
+ rViewShell.GetViewShellBase().GetController(), UNO_QUERY_THROW);
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (mxConfigurationController.is())
+ {
+ // Get and save the current configuration.
+ mxConfiguration = mxConfigurationController->getRequestedConfiguration();
+ if (mxConfiguration.is())
+ {
+ // Iterate over the resources and deactivate the panes.
+ const Sequence<Reference<XResourceId>> aResources(mxConfiguration->getResources(
+ nullptr, framework::FrameworkHelper::msPaneURLPrefix,
+ AnchorBindingMode_DIRECT));
+ for (const Reference<XResourceId>& xPaneId : aResources)
+ {
+ if (xPaneId->getResourceURL() != FrameworkHelper::msCenterPaneURL)
+ {
+ mxConfigurationController->requestResourceDeactivation(xPaneId);
+ }
+ }
+ }
+ }
+ FrameworkHelper::Instance(rViewShell.GetViewShellBase())->WaitForUpdate();
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+PaneHider::~PaneHider()
+{
+ if (mxConfiguration.is() && mxConfigurationController.is())
+ {
+ try
+ {
+ mxConfigurationController->restoreConfiguration(mxConfiguration);
+ }
+ catch (DisposedException&)
+ {
+ // When the configuration controller is already disposed then
+ // there is no point in restoring the configuration.
+ }
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/PaneHider.hxx b/sd/source/ui/slideshow/PaneHider.hxx
new file mode 100644
index 000000000..a2d3cabb0
--- /dev/null
+++ b/sd/source/ui/slideshow/PaneHider.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfiguration;
+}
+namespace com::sun::star::drawing::framework
+{
+class XConfigurationController;
+}
+
+namespace sd
+{
+class ViewShell;
+class SlideshowImpl;
+
+/** Hide the windows of the side panes and restore the original visibility
+ later. Used by the in-window slide show in order to use the whole frame
+ window for the show.
+*/
+class PaneHider
+{
+public:
+ /** The constructor hides all side panes that belong to the
+ ViewShellBase of the given view shell.
+ */
+ PaneHider(const ViewShell& rViewShell, SlideshowImpl* pSlideShow);
+
+ /** Restore the original visibility of the side panes.
+ */
+ ~PaneHider();
+
+private:
+ /** Remember whether the visibility states of the windows of the panes
+ has been modified and have to be restored.
+ */
+
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxConfiguration;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/SlideShowRestarter.cxx b/sd/source/ui/slideshow/SlideShowRestarter.cxx
new file mode 100644
index 000000000..b8c61ba48
--- /dev/null
+++ b/sd/source/ui/slideshow/SlideShowRestarter.cxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawController.hxx>
+#include <ViewShellBase.hxx>
+#include <slideshow.hxx>
+#include "SlideShowRestarter.hxx"
+
+#include <comphelper/propertyvalue.hxx>
+#include <framework/ConfigurationController.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svxids.hrc>
+#include <vcl/svapp.hxx>
+
+#include <functional>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using ::sd::framework::FrameworkHelper;
+
+namespace sd {
+
+SlideShowRestarter::SlideShowRestarter (
+ const ::rtl::Reference<SlideShow>& rpSlideShow,
+ ViewShellBase* pViewShellBase)
+ : mnEventId(nullptr),
+ mpSlideShow(rpSlideShow),
+ mpViewShellBase(pViewShellBase),
+ mnDisplayCount(Application::GetScreenCount()),
+ mpDispatcher(pViewShellBase->GetViewFrame()->GetDispatcher()),
+ mnCurrentSlideNumber(0)
+{
+}
+
+SlideShowRestarter::~SlideShowRestarter()
+{
+}
+
+void SlideShowRestarter::Restart (bool bForce)
+{
+ // Prevent multiple and concurrently restarts.
+ if (mnEventId != nullptr)
+ return;
+
+ if (bForce)
+ mnDisplayCount = 0;
+
+ // Remember the current slide in order to restore it after the slide
+ // show has been restarted.
+ if (mpSlideShow.is())
+ mnCurrentSlideNumber = mpSlideShow->getCurrentPageNumber();
+
+ // Remember a shared pointer to this object to prevent its destruction
+ // before the whole restarting process has finished.
+ mpSelf = shared_from_this();
+
+ // We do not know in what situation this method was called. So, in
+ // order to be able to cleanly stop the presentation, we do that
+ // asynchronously.
+ mnEventId = Application::PostUserEvent(
+ LINK(this, SlideShowRestarter, EndPresentation));
+}
+
+IMPL_LINK_NOARG(SlideShowRestarter, EndPresentation, void*, void)
+{
+ mnEventId = nullptr;
+ if (!mpSlideShow.is())
+ return;
+
+ if (mnDisplayCount == static_cast<sal_Int32>(Application::GetScreenCount()))
+ return;
+
+ bool bIsExitAfterPresenting = mpSlideShow->IsExitAfterPresenting();
+ mpSlideShow->SetExitAfterPresenting(false);
+ mpSlideShow->end();
+ mpSlideShow->SetExitAfterPresenting(bIsExitAfterPresenting);
+
+ // The following piece of code should not be here because the
+ // slide show should be aware of the existence of the presenter
+ // console (which is displayed in the FullScreenPane). But the
+ // timing has to be right and I did not find a better place for
+ // it.
+
+ // Wait for the full screen pane, which displays the presenter
+ // console, to disappear. Only when it is gone, call
+ // InitiatePresenterStart(), in order to begin the asynchronous
+ // restart of the slide show.
+ if (mpViewShellBase == nullptr)
+ return;
+
+ ::std::shared_ptr<FrameworkHelper> pHelper(
+ FrameworkHelper::Instance(*mpViewShellBase));
+ if (pHelper->GetConfigurationController()->getResource(
+ FrameworkHelper::CreateResourceId(FrameworkHelper::msFullScreenPaneURL)).is())
+ {
+ ::sd::framework::ConfigurationController::Lock aLock (
+ pHelper->GetConfigurationController());
+
+ pHelper->RunOnConfigurationEvent(
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ ::std::bind(&SlideShowRestarter::StartPresentation, shared_from_this()));
+ pHelper->UpdateConfiguration();
+ }
+ else
+ {
+ StartPresentation();
+ }
+}
+
+void SlideShowRestarter::StartPresentation()
+{
+ //rhbz#1091117 crash because we're exiting the application, and this is
+ //being called during the configuration update event on exit. At this point
+ //newly created objects won't get disposed called on them, because the
+ //disposer is doing its last execution of that now.
+ if (mpViewShellBase && mpViewShellBase->GetDrawController().IsDisposing())
+ return;
+
+ if (mpDispatcher == nullptr && mpViewShellBase!=nullptr)
+ mpDispatcher = mpViewShellBase->GetViewFrame()->GetDispatcher();
+
+ // Start the slide show on the saved current slide.
+ if (mpDispatcher != nullptr)
+ {
+ mpDispatcher->Execute(SID_PRESENTATION, SfxCallMode::ASYNCHRON);
+ if (mpSlideShow.is())
+ {
+ Sequence aProperties{ comphelper::makePropertyValue("FirstPage",
+ "page" + OUString::number(mnCurrentSlideNumber+1)) };
+ mpSlideShow->startWithArguments(aProperties);
+ }
+ mpSelf.reset();
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/SlideShowRestarter.hxx b/sd/source/ui/slideshow/SlideShowRestarter.hxx
new file mode 100644
index 000000000..e8e97a600
--- /dev/null
+++ b/sd/source/ui/slideshow/SlideShowRestarter.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ref.hxx>
+#include <tools/link.hxx>
+#include <memory>
+
+namespace sd
+{
+class SlideShow;
+}
+namespace sd
+{
+class ViewShellBase;
+}
+class SfxDispatcher;
+struct ImplSVEvent;
+
+namespace sd
+{
+/** This class is used when a display is removed or added to restart the
+ slide show. This is necessary at least with DirectX because
+ deactivating a display invalidates DirectX resources. Accessing those
+ leads to a crash.
+
+ During a restart a possibly installed presenter extension is given the
+ opportunity to show or hide depending on the number of available displays.
+*/
+class SlideShowRestarter : public std::enable_shared_from_this<SlideShowRestarter>
+{
+public:
+ /** Create a new SlideShowRestarter object.
+ @param rpSlideShow
+ The slide show is used to determine the current slide, which is
+ restored after the restart, and of course to stop and start the
+ slide show.
+ @param pViewShellBase
+ Used to get access to a slot dispatcher.
+ */
+ SlideShowRestarter(const ::rtl::Reference<SlideShow>& rpSlideShow,
+ ViewShellBase* pViewShellBase);
+ virtual ~SlideShowRestarter();
+
+ /** Restarting the slide show is an asynchronous multi step process
+ which is started by calling this method.
+ @param bForce
+ Used to force a re-start, even if the display count is unchanged.
+ */
+ void Restart(bool bForce);
+
+private:
+ ImplSVEvent* mnEventId;
+ ::rtl::Reference<SlideShow> mpSlideShow;
+ ViewShellBase* mpViewShellBase;
+ ::std::shared_ptr<SlideShowRestarter> mpSelf;
+ sal_Int32 mnDisplayCount;
+ SfxDispatcher* mpDispatcher;
+ sal_Int32 mnCurrentSlideNumber;
+
+ DECL_LINK(EndPresentation, void*, void);
+
+ /** Restart the presentation on the slide last shown before the restart
+ was initiated.
+ */
+ void StartPresentation();
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/showwin.cxx b/sd/source/ui/slideshow/showwin.cxx
new file mode 100644
index 000000000..35c0a4027
--- /dev/null
+++ b/sd/source/ui/slideshow/showwin.cxx
@@ -0,0 +1,629 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/awt/Key.hpp>
+
+#include "showwindow.hxx"
+#include "slideshowimpl.hxx"
+
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sfxsids.hrc>
+
+
+#include <slideshow.hxx>
+#include <ViewShell.hxx>
+#include <sdresid.hxx>
+#include <helpids.h>
+#include <strings.hrc>
+
+#include <sal/log.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd {
+
+const sal_uInt64 HIDE_MOUSE_TIMEOUT = 10000;
+const sal_uInt64 SHOW_MOUSE_TIMEOUT = 1000;
+
+ShowWindow::ShowWindow( const ::rtl::Reference< SlideshowImpl >& xController, vcl::Window* pParent )
+: ::sd::Window( pParent )
+, maPauseTimer("sd ShowWindow maPauseTimer")
+, maMouseTimer("sd ShowWindow maMouseTimer")
+, mnPauseTimeout( SLIDE_NO_TIMEOUT )
+, mnRestartPageIndex( PAGE_NO_END )
+, meShowWindowMode(SHOWWINDOWMODE_NORMAL)
+, mbShowNavigatorAfterSpecialMode( false )
+, mbMouseAutoHide(true)
+, mbMouseCursorHidden(false)
+, mnFirstMouseMove(0)
+, mxController( xController )
+{
+ GetOutDev()->SetOutDevViewType( OutDevViewType::SlideShow );
+
+ // Do never mirror the preview window. This explicitly includes right
+ // to left writing environments.
+ EnableRTL (false);
+
+ MapMode aMap(GetMapMode());
+ aMap.SetMapUnit(MapUnit::Map100thMM);
+ SetMapMode(aMap);
+
+ // set HelpId
+ SetHelpId( HID_SD_WIN_PRESENTATION );
+
+ maPauseTimer.SetInvokeHandler( LINK( this, ShowWindow, PauseTimeoutHdl ) );
+ maPauseTimer.SetTimeout( 1000 );
+ maMouseTimer.SetInvokeHandler( LINK( this, ShowWindow, MouseTimeoutHdl ) );
+ maMouseTimer.SetTimeout( HIDE_MOUSE_TIMEOUT );
+
+ maShowBackground = Wallpaper( COL_BLACK );
+ SetBackground(); // avoids that VCL paints any background!
+ GetParent()->Show();
+ AddEventListener( LINK( this, ShowWindow, EventHdl ) );
+}
+
+ShowWindow::~ShowWindow()
+{
+ disposeOnce();
+}
+
+void ShowWindow::dispose()
+{
+ maPauseTimer.Stop();
+ maMouseTimer.Stop();
+ ::sd::Window::dispose();
+}
+
+void ShowWindow::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bReturn = false;
+
+ if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode )
+ {
+ TerminateShow();
+ bReturn = true;
+ }
+ else if( SHOWWINDOWMODE_END == meShowWindowMode )
+ {
+ const int nKeyCode = rKEvt.GetKeyCode().GetCode();
+ switch( nKeyCode )
+ {
+ case KEY_PAGEUP:
+ case KEY_LEFT:
+ case KEY_UP:
+ case KEY_P:
+ case KEY_HOME:
+ case KEY_END:
+ case awt::Key::CONTEXTMENU:
+ // these keys will be handled by the slide show even
+ // while in end mode
+ break;
+ default:
+ TerminateShow();
+ bReturn = true;
+ }
+ }
+ else if( SHOWWINDOWMODE_BLANK == meShowWindowMode )
+ {
+ bool bFakeKeyPress = rKEvt.GetKeyCode().GetFullCode() == 0;
+ // Ignore workaround of https://gitlab.gnome.org/GNOME/gtk/issues/1785
+ // See calls to GtkSalFrame::makeFakeKeyPress (Fixed in GTK 2.34)
+ if (!bFakeKeyPress)
+ RestartShow();
+ bReturn = true;
+ }
+ else if( SHOWWINDOWMODE_PAUSE == meShowWindowMode )
+ {
+ const int nKeyCode = rKEvt.GetKeyCode().GetCode();
+ switch( nKeyCode )
+ {
+ case KEY_ESCAPE:
+ TerminateShow();
+ bReturn = true;
+ break;
+ case KEY_PAGEUP:
+ case KEY_RIGHT:
+ case KEY_UP:
+ case KEY_P:
+ case KEY_HOME:
+ case KEY_END:
+ case awt::Key::CONTEXTMENU:
+ // these keys will be handled by the slide show even
+ // while in end mode
+ break;
+ default:
+ RestartShow();
+ bReturn = true;
+ break;
+ }
+ }
+
+ if( !bReturn )
+ {
+ if( mxController.is() )
+ bReturn = mxController->keyInput(rKEvt);
+
+ if( !bReturn )
+ {
+ if( mpViewShell )
+ {
+ mpViewShell->KeyInput(rKEvt,this);
+ }
+ else
+ {
+ Window::KeyInput(rKEvt);
+ }
+ }
+ }
+
+ if( mpViewShell )
+ mpViewShell->SetActiveWindow( this );
+}
+
+void ShowWindow::MouseButtonDown(const MouseEvent& /*rMEvt*/)
+{
+ if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode )
+ {
+ TerminateShow();
+ }
+ else if( mpViewShell )
+ {
+ mpViewShell->SetActiveWindow( this );
+ }
+}
+
+void ShowWindow::MouseMove(const MouseEvent& /*rMEvt*/)
+{
+ if( mbMouseAutoHide )
+ {
+ if( mbMouseCursorHidden )
+ {
+ if( mnFirstMouseMove )
+ {
+ // if this is not the first mouse move while hidden, see if
+ // enough time has pasted to show mouse pointer again
+ sal_uInt64 nTime = ::tools::Time::GetSystemTicks();
+ if( (nTime - mnFirstMouseMove) >= SHOW_MOUSE_TIMEOUT )
+ {
+ ShowPointer( true );
+ mnFirstMouseMove = 0;
+ mbMouseCursorHidden = false;
+ maMouseTimer.SetTimeout( HIDE_MOUSE_TIMEOUT );
+ maMouseTimer.Start();
+ }
+ }
+ else
+ {
+ // if this is the first mouse move, note current
+ // time and start idle timer to cancel show mouse pointer
+ // again if not enough mouse movement is measured
+ mnFirstMouseMove = ::tools::Time::GetSystemTicks();
+ maMouseTimer.SetTimeout( 2*SHOW_MOUSE_TIMEOUT );
+ maMouseTimer.Start();
+ }
+ }
+ else
+ {
+ // current mousemove restarts the idle timer to hide the mouse
+ maMouseTimer.Start();
+ }
+ }
+
+ if( mpViewShell )
+ mpViewShell->SetActiveWindow( this );
+}
+
+void ShowWindow::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode )
+ {
+ TerminateShow();
+ }
+ else if( (SHOWWINDOWMODE_END == meShowWindowMode) && !rMEvt.IsRight() )
+ {
+ TerminateShow();
+ }
+ else if( (( SHOWWINDOWMODE_BLANK == meShowWindowMode ) || ( SHOWWINDOWMODE_PAUSE == meShowWindowMode ))
+ && !rMEvt.IsRight() )
+ {
+ RestartShow();
+ }
+ else
+ {
+ if( mxController.is() )
+ mxController->mouseButtonUp( rMEvt );
+ }
+}
+
+/**
+ * if FuSlideShow is still available, forward it
+ */
+void ShowWindow::Paint(vcl::RenderContext& /*rRenderContext*/, const ::tools::Rectangle& rRect)
+{
+ if( (meShowWindowMode == SHOWWINDOWMODE_NORMAL) || (meShowWindowMode == SHOWWINDOWMODE_PREVIEW) )
+ {
+ if( mxController.is() )
+ {
+ mxController->paint();
+ }
+ else if(mpViewShell )
+ {
+ mpViewShell->Paint(rRect, this);
+ }
+ }
+ else
+ {
+ GetOutDev()->DrawWallpaper( rRect, maShowBackground );
+
+ if( SHOWWINDOWMODE_END == meShowWindowMode )
+ {
+ DrawEndScene();
+ }
+ else if( SHOWWINDOWMODE_PAUSE == meShowWindowMode )
+ {
+ DrawPauseScene( false );
+ }
+ else if( SHOWWINDOWMODE_BLANK == meShowWindowMode )
+ {
+ // just blank through background color => nothing to be done here
+ }
+ }
+}
+
+void ShowWindow::LoseFocus()
+{
+ Window::LoseFocus();
+
+ if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode)
+ TerminateShow();
+}
+
+void ShowWindow::SetEndMode()
+{
+ if( !(( SHOWWINDOWMODE_NORMAL == meShowWindowMode ) && mpViewShell && mpViewShell->GetView()) )
+ return;
+
+ DeleteWindowFromPaintView();
+ meShowWindowMode = SHOWWINDOWMODE_END;
+ maShowBackground = Wallpaper( COL_BLACK );
+
+ // hide navigator if it is visible
+ if( mpViewShell->GetViewFrame()->GetChildWindow( SID_NAVIGATOR ) )
+ {
+ mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR, false );
+ mbShowNavigatorAfterSpecialMode = true;
+ }
+
+ Invalidate();
+}
+
+bool ShowWindow::SetPauseMode( sal_Int32 nTimeout, Graphic const * pLogo )
+{
+ rtl::Reference< SlideShow > xSlideShow;
+
+ if( mpViewShell )
+ xSlideShow = SlideShow::GetSlideShow( mpViewShell->GetViewShellBase() );
+
+ if( xSlideShow.is() && !nTimeout )
+ {
+ xSlideShow->jumpToPageIndex( 0 );
+ }
+ else if( ( SHOWWINDOWMODE_NORMAL == meShowWindowMode ) && mpViewShell && mpViewShell->GetView() )
+ {
+ DeleteWindowFromPaintView();
+ mnPauseTimeout = nTimeout;
+ mnRestartPageIndex = 0;
+ meShowWindowMode = SHOWWINDOWMODE_PAUSE;
+ maShowBackground = Wallpaper( COL_BLACK );
+
+ // hide navigator if it is visible
+ if( mpViewShell->GetViewFrame()->GetChildWindow( SID_NAVIGATOR ) )
+ {
+ mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR, false );
+ mbShowNavigatorAfterSpecialMode = true;
+ }
+
+ if( pLogo )
+ maLogo = *pLogo;
+
+ Invalidate();
+
+ if( SLIDE_NO_TIMEOUT != mnPauseTimeout )
+ maPauseTimer.Start();
+ }
+
+ return( SHOWWINDOWMODE_PAUSE == meShowWindowMode );
+}
+
+bool ShowWindow::SetBlankMode( sal_Int32 nPageIndexToRestart, const Color& rBlankColor )
+{
+ if( ( SHOWWINDOWMODE_NORMAL == meShowWindowMode ) && mpViewShell && mpViewShell->GetView() )
+ {
+ DeleteWindowFromPaintView();
+ mnRestartPageIndex = nPageIndexToRestart;
+ meShowWindowMode = SHOWWINDOWMODE_BLANK;
+ maShowBackground = Wallpaper( rBlankColor );
+
+ // hide navigator if it is visible
+ if( mpViewShell->GetViewFrame()->GetChildWindow( SID_NAVIGATOR ) )
+ {
+ mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR, false );
+ mbShowNavigatorAfterSpecialMode = true;
+ }
+
+ Invalidate();
+ }
+
+ return( SHOWWINDOWMODE_BLANK == meShowWindowMode );
+}
+
+void ShowWindow::SetPreviewMode()
+{
+ meShowWindowMode = SHOWWINDOWMODE_PREVIEW;
+}
+
+void ShowWindow::TerminateShow()
+{
+ maLogo.Clear();
+ maPauseTimer.Stop();
+ maMouseTimer.Stop();
+ GetOutDev()->Erase();
+ maShowBackground = Wallpaper( COL_BLACK );
+ meShowWindowMode = SHOWWINDOWMODE_NORMAL;
+ mnPauseTimeout = SLIDE_NO_TIMEOUT;
+
+ if( mpViewShell )
+ {
+ // show navigator?
+ if( mbShowNavigatorAfterSpecialMode )
+ {
+ mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR );
+ mbShowNavigatorAfterSpecialMode = false;
+ }
+ }
+
+ if( mxController.is() )
+ mxController->endPresentation();
+
+ mnRestartPageIndex = PAGE_NO_END;
+}
+
+void ShowWindow::RestartShow()
+{
+ RestartShow( mnRestartPageIndex );
+}
+
+void ShowWindow::RestartShow( sal_Int32 nPageIndexToRestart )
+{
+ ShowWindowMode eOldShowWindowMode = meShowWindowMode;
+
+ maLogo.Clear();
+ maPauseTimer.Stop();
+ GetOutDev()->Erase();
+ maShowBackground = Wallpaper( COL_BLACK );
+ meShowWindowMode = SHOWWINDOWMODE_NORMAL;
+ mnPauseTimeout = SLIDE_NO_TIMEOUT;
+
+ if( mpViewShell )
+ {
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( mpViewShell->GetViewShellBase() ) );
+
+ if( xSlideShow.is() )
+ {
+ AddWindowToPaintView();
+
+ if( SHOWWINDOWMODE_BLANK == eOldShowWindowMode || SHOWWINDOWMODE_END == eOldShowWindowMode )
+ {
+ xSlideShow->pause(false);
+ Invalidate();
+ }
+ else
+ {
+ xSlideShow->jumpToPageIndex( nPageIndexToRestart );
+ }
+ }
+ }
+
+ mnRestartPageIndex = PAGE_NO_END;
+
+ // show navigator?
+ if( mbShowNavigatorAfterSpecialMode )
+ {
+ if (mpViewShell)
+ mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR );
+ mbShowNavigatorAfterSpecialMode = false;
+ }
+}
+
+void ShowWindow::DrawPauseScene( bool bTimeoutOnly )
+{
+ const MapMode& rMap = GetMapMode();
+ const Point aOutOrg( PixelToLogic( Point() ) );
+ const Size aOutSize( GetOutDev()->GetOutputSize() );
+ const Size aTextSize(OutputDevice::LogicToLogic(Size(0, 14), MapMode(MapUnit::MapPoint), rMap));
+ const Size aOffset(OutputDevice::LogicToLogic(Size(1000, 1000), MapMode(MapUnit::Map100thMM), rMap));
+ OUString aText( SdResId( STR_PRES_PAUSE ) );
+ bool bDrawn = false;
+
+ vcl::Font aFont( GetSettings().GetStyleSettings().GetMenuFont() );
+ const vcl::Font aOldFont( GetFont() );
+
+ aFont.SetFontSize( aTextSize );
+ aFont.SetColor( COL_WHITE );
+ aFont.SetCharSet( aOldFont.GetCharSet() );
+ aFont.SetLanguage( aOldFont.GetLanguage() );
+
+ if( !bTimeoutOnly && ( maLogo.GetType() != GraphicType::NONE ) )
+ {
+ Size aGrfSize;
+
+ if (maLogo.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ aGrfSize = PixelToLogic( maLogo.GetPrefSize() );
+ else
+ aGrfSize = OutputDevice::LogicToLogic( maLogo.GetPrefSize(), maLogo.GetPrefMapMode(), rMap );
+
+ const Point aGrfPos( std::max( aOutOrg.X() + aOutSize.Width() - aGrfSize.Width() - aOffset.Width(), aOutOrg.X() ),
+ std::max( aOutOrg.Y() + aOutSize.Height() - aGrfSize.Height() - aOffset.Height(), aOutOrg.Y() ) );
+
+ if( maLogo.IsAnimated() )
+ maLogo.StartAnimation(*GetOutDev(), aGrfPos, aGrfSize, reinterpret_cast<sal_IntPtr>(this));
+ else
+ maLogo.Draw(*GetOutDev(), aGrfPos, aGrfSize);
+ }
+
+ if( SLIDE_NO_TIMEOUT != mnPauseTimeout )
+ {
+ MapMode aVMap( rMap );
+ ScopedVclPtrInstance< VirtualDevice > pVDev( *GetOutDev() );
+
+ aVMap.SetOrigin( Point() );
+ pVDev->SetMapMode( aVMap );
+ pVDev->SetBackground( Wallpaper( COL_BLACK ) );
+
+ // set font first, to determine real output height
+ pVDev->SetFont( aFont );
+
+ const Size aVDevSize( aOutSize.Width(), pVDev->GetTextHeight() );
+
+ if( pVDev->SetOutputSize( aVDevSize ) )
+ {
+ // Note: if performance gets an issue here, we can use NumberFormatter directly
+ SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& aLocaleData = aSysLocale.GetLocaleData();
+
+ aText += " ( " + aLocaleData.getDuration( ::tools::Time( 0, 0, mnPauseTimeout ) ) + " )";
+ pVDev->DrawText( Point( aOffset.Width(), 0 ), aText );
+ GetOutDev()->DrawOutDev( Point( aOutOrg.X(), aOffset.Height() ), aVDevSize, Point(), aVDevSize, *pVDev );
+ bDrawn = true;
+ }
+ }
+
+ if( !bDrawn )
+ {
+ SetFont( aFont );
+ GetOutDev()->DrawText( Point( aOutOrg.X() + aOffset.Width(), aOutOrg.Y() + aOffset.Height() ), aText );
+ SetFont( aOldFont );
+ }
+}
+
+void ShowWindow::DrawEndScene()
+{
+ const vcl::Font aOldFont( GetFont() );
+ vcl::Font aFont( GetSettings().GetStyleSettings().GetMenuFont() );
+
+ const Point aOutOrg( PixelToLogic( Point() ) );
+ const Size aTextSize(OutputDevice::LogicToLogic(Size(0, 14), MapMode(MapUnit::MapPoint), GetMapMode()));
+ const OUString aText( SdResId( STR_PRES_SOFTEND ) );
+
+ aFont.SetFontSize( aTextSize );
+ aFont.SetColor( COL_WHITE );
+ aFont.SetCharSet( aOldFont.GetCharSet() );
+ aFont.SetLanguage( aOldFont.GetLanguage() );
+ SetFont( aFont );
+ GetOutDev()->DrawText( Point( aOutOrg.X() + aTextSize.Height(), aOutOrg.Y() + aTextSize.Height() ), aText );
+ SetFont( aOldFont );
+}
+
+IMPL_LINK( ShowWindow, PauseTimeoutHdl, Timer*, pTimer, void )
+{
+ if( !( --mnPauseTimeout ) )
+ RestartShow();
+ else
+ {
+ DrawPauseScene( true );
+ pTimer->Start();
+ }
+}
+
+IMPL_LINK_NOARG(ShowWindow, MouseTimeoutHdl, Timer *, void)
+{
+ if( mbMouseCursorHidden )
+ {
+ // not enough mouse movements since first recording so
+ // cancel show mouse pointer for now
+ mnFirstMouseMove = 0;
+ }
+ else
+ {
+ // mouse has been idle too long, hide pointer
+ ShowPointer( false );
+ mbMouseCursorHidden = true;
+ }
+}
+
+IMPL_LINK( ShowWindow, EventHdl, VclWindowEvent&, rEvent, void )
+{
+ if( mbMouseAutoHide )
+ {
+ if (rEvent.GetId() == VclEventId::WindowShow)
+ {
+ maMouseTimer.SetTimeout( HIDE_MOUSE_TIMEOUT );
+ maMouseTimer.Start();
+ }
+ }
+}
+
+void ShowWindow::DeleteWindowFromPaintView()
+{
+ if( mpViewShell->GetView() )
+ mpViewShell->GetView()->DeleteWindowFromPaintView( GetOutDev() );
+
+ sal_uInt16 nChild = GetChildCount();
+ while( nChild-- )
+ GetChild( nChild )->Show( false );
+}
+
+void ShowWindow::AddWindowToPaintView()
+{
+ if( mpViewShell->GetView() )
+ mpViewShell->GetView()->AddWindowToPaintView( GetOutDev(), nullptr );
+
+ sal_uInt16 nChild = GetChildCount();
+ while( nChild-- )
+ GetChild( nChild )->Show();
+}
+
+// Override the sd::Window's CreateAccessible to create a different accessible object
+css::uno::Reference<css::accessibility::XAccessible>
+ ShowWindow::CreateAccessible()
+{
+ css::uno::Reference< css::accessibility::XAccessible > xAcc = GetAccessible(false);
+ if (xAcc)
+ {
+ return xAcc;
+ }
+ if (mpViewShell != nullptr)
+ {
+ xAcc = mpViewShell->CreateAccessibleDocumentView (this);
+ SetAccessible(xAcc);
+ return xAcc;
+ }
+ else
+ {
+ SAL_WARN("sd", "::sd::Window::CreateAccessible: no view shell");
+ return vcl::Window::CreateAccessible ();
+ }
+}
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/showwindow.hxx b/sd/source/ui/slideshow/showwindow.hxx
new file mode 100644
index 000000000..f0f88228b
--- /dev/null
+++ b/sd/source/ui/slideshow/showwindow.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ref.hxx>
+#include <sal/types.h>
+#include <vcl/timer.hxx>
+#include <vcl/graph.hxx>
+
+#include <Window.hxx>
+
+namespace sd {
+
+class SlideshowImpl;
+
+#define SLIDE_NO_TIMEOUT SAL_MAX_INT32
+
+enum ShowWindowMode
+{
+ SHOWWINDOWMODE_NORMAL = 0,
+ SHOWWINDOWMODE_PAUSE = 1,
+ SHOWWINDOWMODE_END = 2,
+ SHOWWINDOWMODE_BLANK = 3,
+ SHOWWINDOWMODE_PREVIEW = 4
+};
+
+class ShowWindow
+ : public ::sd::Window
+{
+
+public:
+ ShowWindow ( const ::rtl::Reference< ::sd::SlideshowImpl >& xController, vcl::Window* pParent );
+ virtual ~ShowWindow() override;
+ virtual void dispose() override;
+
+ void SetEndMode();
+ bool SetPauseMode( sal_Int32 nTimeoutSec, Graphic const * pLogo = nullptr );
+ bool SetBlankMode( sal_Int32 nPageIndexToRestart, const Color& rBlankColor );
+
+ const Color& GetBlankColor() const { return maShowBackground.GetColor(); }
+
+ void SetPreviewMode();
+
+ void SetMouseAutoHide( bool bMouseAutoHide ) { mbMouseAutoHide = bMouseAutoHide; }
+
+ ShowWindowMode GetShowWindowMode() const { return meShowWindowMode; }
+
+ void RestartShow( sal_Int32 nPageIndexToRestart );
+
+ virtual void LoseFocus() override;
+
+ virtual void KeyInput(const KeyEvent& rKEvt) override;
+ virtual void MouseMove(const MouseEvent& rMEvt) override;
+ virtual void MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect) override;
+ /// Override the sd::Window's CreateAccessible to create a different accessible object
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ CreateAccessible() override;
+
+ void TerminateShow();
+ void RestartShow();
+
+private:
+ void DrawPauseScene( bool bTimeoutOnly );
+ void DrawEndScene();
+
+ void DeleteWindowFromPaintView();
+ void AddWindowToPaintView();
+
+private:
+ Timer maPauseTimer;
+ Timer maMouseTimer;
+ Wallpaper maShowBackground;
+ Graphic maLogo;
+ sal_uLong mnPauseTimeout;
+ sal_Int32 mnRestartPageIndex;
+ ShowWindowMode meShowWindowMode;
+ bool mbShowNavigatorAfterSpecialMode;
+ bool mbMouseAutoHide;
+ bool mbMouseCursorHidden;
+ sal_uInt64 mnFirstMouseMove;
+
+ DECL_LINK( PauseTimeoutHdl, Timer*, void );
+ DECL_LINK(MouseTimeoutHdl, Timer *, void);
+ DECL_LINK( EventHdl, VclWindowEvent&, void );
+
+ ::rtl::Reference< SlideshowImpl > mxController;
+};
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/slideshow.cxx b/sd/source/ui/slideshow/slideshow.cxx
new file mode 100644
index 000000000..fa14c4de6
--- /dev/null
+++ b/sd/source/ui/slideshow/slideshow.cxx
@@ -0,0 +1,1191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/util/URL.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdlayer.hxx>
+#include <svl/itemprop.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sfxsids.hrc>
+
+#include <framework/FrameworkHelper.hxx>
+#include <comphelper/extract.hxx>
+
+#include <FrameView.hxx>
+#include <createpresentation.hxx>
+#include <unomodel.hxx>
+#include <slideshow.hxx>
+#include "slideshowimpl.hxx"
+#include <sdattr.hrc>
+#include <sdmod.hxx>
+#include <FactoryIds.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include "SlideShowRestarter.hxx"
+#include <DrawController.hxx>
+#include <PresentationViewShell.hxx>
+#include <customshowlist.hxx>
+#include <unopage.hxx>
+#include <sdpage.hxx>
+#include <cusshow.hxx>
+#include <optsitem.hxx>
+#include <strings.hrc>
+#include <sdresid.hxx>
+
+using ::com::sun::star::presentation::XSlideShowController;
+using ::sd::framework::FrameworkHelper;
+using ::com::sun::star::awt::XWindow;
+using namespace ::sd;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace {
+ /** This local version of the work window overrides DataChanged() so that it
+ can restart the slide show when a display is added or removed.
+ */
+ class FullScreenWorkWindow : public WorkWindow
+ {
+ public:
+ FullScreenWorkWindow (
+ const ::rtl::Reference<SlideShow>& rpSlideShow,
+ ViewShellBase* pViewShellBase)
+ : WorkWindow(nullptr, WB_HIDE | WB_CLIPCHILDREN),
+ mpRestarter(std::make_shared<SlideShowRestarter>(rpSlideShow, pViewShellBase))
+ {}
+
+ void Restart(bool bForce)
+ {
+ mpRestarter->Restart(bForce);
+ }
+
+ virtual void DataChanged (const DataChangedEvent& rEvent) override
+ {
+ if (rEvent.GetType() == DataChangedEventType::DISPLAY)
+ Restart(false);
+ }
+
+ private:
+ ::std::shared_ptr<SlideShowRestarter> mpRestarter;
+ };
+}
+
+static const SfxItemPropertyMapEntry* ImplGetPresentationPropertyMap()
+{
+ // NOTE: First member must be sorted
+ static const SfxItemPropertyMapEntry aPresentationPropertyMap_Impl[] =
+ {
+ { u"AllowAnimations", ATTR_PRESENT_ANIMATION_ALLOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"CustomShow", ATTR_PRESENT_CUSTOMSHOW, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"Display", ATTR_PRESENT_DISPLAY, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"FirstPage", ATTR_PRESENT_DIANAME, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"IsAlwaysOnTop", ATTR_PRESENT_ALWAYS_ON_TOP, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsAutomatic", ATTR_PRESENT_MANUEL, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsEndless", ATTR_PRESENT_ENDLESS, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsFullScreen", ATTR_PRESENT_FULLSCREEN, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsShowAll", ATTR_PRESENT_ALL, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsMouseVisible", ATTR_PRESENT_MOUSE, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsShowLogo", ATTR_PRESENT_SHOW_PAUSELOGO, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"IsTransitionOnClick", ATTR_PRESENT_CHANGE_PAGE, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"Pause", ATTR_PRESENT_PAUSE_TIMEOUT, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"StartWithNavigator", ATTR_PRESENT_NAVIGATOR, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"UsePen", ATTR_PRESENT_PEN, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aPresentationPropertyMap_Impl;
+}
+
+
+SlideShow::SlideShow( SdDrawDocument* pDoc )
+: maPropSet(ImplGetPresentationPropertyMap(), SdrObject::GetGlobalDrawObjectItemPool())
+, mbIsInStartup(false)
+, mpDoc( pDoc )
+, mpCurrentViewShellBase( nullptr )
+, mpFullScreenViewShellBase( nullptr )
+, mpFullScreenFrameView( nullptr )
+, mnInPlaceConfigEvent( nullptr )
+{
+}
+
+void SlideShow::ThrowIfDisposed() const
+{
+ if( mpDoc == nullptr )
+ throw DisposedException();
+}
+
+/// used by the model to create a slideshow for it
+rtl::Reference< SlideShow > SlideShow::Create( SdDrawDocument* pDoc )
+{
+ return new SlideShow( pDoc );
+}
+
+rtl::Reference< SlideShow > SlideShow::GetSlideShow( SdDrawDocument const * pDocument )
+{
+ rtl::Reference< SlideShow > xRet;
+
+ if( pDocument )
+ xRet = GetSlideShow( *pDocument );
+
+ return xRet;
+}
+
+rtl::Reference< SlideShow > SlideShow::GetSlideShow( SdDrawDocument const & rDocument )
+{
+ return rtl::Reference< SlideShow >(
+ dynamic_cast< SlideShow* >( rDocument.getPresentation().get() ) );
+}
+
+rtl::Reference< SlideShow > SlideShow::GetSlideShow( ViewShellBase const & rBase )
+{
+ return GetSlideShow( rBase.GetDocument() );
+}
+
+css::uno::Reference< css::presentation::XSlideShowController > SlideShow::GetSlideShowController(ViewShellBase const & rBase )
+{
+ rtl::Reference< SlideShow > xSlideShow( GetSlideShow( rBase ) );
+
+ Reference< XSlideShowController > xRet;
+ if( xSlideShow.is() )
+ xRet = xSlideShow->getController();
+
+ return xRet;
+}
+
+bool SlideShow::StartPreview( ViewShellBase const & rBase,
+ const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage,
+ const css::uno::Reference< css::animations::XAnimationNode >& xAnimationNode )
+{
+ rtl::Reference< SlideShow > xSlideShow( GetSlideShow( rBase ) );
+ if( !xSlideShow.is() )
+ return false;
+
+ xSlideShow->startPreview( xDrawPage, xAnimationNode );
+ return true;
+}
+
+void SlideShow::Stop( ViewShellBase const & rBase )
+{
+ rtl::Reference< SlideShow > xSlideShow( GetSlideShow( rBase ) );
+ if( xSlideShow.is() )
+ xSlideShow->end();
+}
+
+bool SlideShow::IsRunning( ViewShellBase const & rBase )
+{
+ rtl::Reference< SlideShow > xSlideShow( GetSlideShow( rBase ) );
+ return xSlideShow.is() && xSlideShow->isRunning();
+}
+
+bool SlideShow::IsRunning( const ViewShell& rViewShell )
+{
+ rtl::Reference< SlideShow > xSlideShow( GetSlideShow( rViewShell.GetViewShellBase() ) );
+ return xSlideShow.is() && xSlideShow->isRunning() && (xSlideShow->mxController->getViewShell() == &rViewShell);
+}
+
+void SlideShow::CreateController( ViewShell* pViewSh, ::sd::View* pView, vcl::Window* pParentWindow )
+{
+ SAL_INFO_IF( !mxController.is(), "sd.slideshow", "sd::SlideShow::CreateController(), clean up old controller first!" );
+
+ Reference< XPresentation2 > xThis( this );
+
+ rtl::Reference<SlideshowImpl> xController (
+ new SlideshowImpl(xThis, pViewSh, pView, mpDoc, pParentWindow));
+
+ // Reset mbIsInStartup. From here mxController.is() is used to prevent
+ // multiple slide show instances for one document.
+ mxController = xController;
+ mbIsInStartup = false;
+
+}
+
+// XServiceInfo
+OUString SAL_CALL SlideShow::getImplementationName( )
+{
+ return "com.sun.star.comp.sd.SlideShow";
+}
+
+sal_Bool SAL_CALL SlideShow::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+Sequence< OUString > SAL_CALL SlideShow::getSupportedServiceNames( )
+{
+ return { "com.sun.star.presentation.Presentation" };
+}
+
+// XPropertySet
+Reference< XPropertySetInfo > SAL_CALL SlideShow::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static Reference< XPropertySetInfo > xInfo = maPropSet.getPropertySetInfo();
+ return xInfo;
+ }
+
+void SAL_CALL SlideShow::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ThrowIfDisposed();
+
+ sd::PresentationSettings& rPresSettings = mpDoc->getPresentationSettings();
+
+ const SfxItemPropertyMapEntry* pEntry = maPropSet.getPropertyMapEntry(aPropertyName);
+
+ if( pEntry && ((pEntry->nFlags & PropertyAttribute::READONLY) != 0) )
+ throw PropertyVetoException();
+
+ bool bValuesChanged = false;
+ bool bIllegalArgument = true;
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case ATTR_PRESENT_ALL:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( rPresSettings.mbAll != bVal )
+ {
+ rPresSettings.mbAll = bVal;
+ bValuesChanged = true;
+ if( bVal )
+ rPresSettings.mbCustomShow = false;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_CHANGE_PAGE:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( bVal == rPresSettings.mbLockedPages )
+ {
+ bValuesChanged = true;
+ rPresSettings.mbLockedPages = !bVal;
+ }
+ }
+ break;
+ }
+
+ case ATTR_PRESENT_ANIMATION_ALLOWED:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if(rPresSettings.mbAnimationAllowed != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbAnimationAllowed = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_CUSTOMSHOW:
+ {
+ OUString aShowName;
+ if( aValue >>= aShowName )
+ {
+ bIllegalArgument = false;
+
+ SdCustomShowList* pCustomShowList = mpDoc->GetCustomShowList();
+ if(pCustomShowList)
+ {
+ SdCustomShow* pCustomShow;
+ for( pCustomShow = pCustomShowList->First(); pCustomShow != nullptr; pCustomShow = pCustomShowList->Next() )
+ {
+ if( pCustomShow->GetName() == aShowName )
+ break;
+ }
+
+ rPresSettings.mbCustomShow = true;
+ bValuesChanged = true;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_ENDLESS:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( rPresSettings.mbEndless != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbEndless = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_FULLSCREEN:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+ if( rPresSettings.mbFullScreen != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbFullScreen = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_DIANAME:
+ {
+ OUString aPresPage;
+ aValue >>= aPresPage;
+ bIllegalArgument = false;
+ if( (rPresSettings.maPresPage != aPresPage) || !rPresSettings.mbCustomShow || !rPresSettings.mbAll )
+ {
+ bValuesChanged = true;
+ rPresSettings.maPresPage = getUiNameFromPageApiNameImpl(aPresPage);
+ rPresSettings.mbCustomShow = false;
+ rPresSettings.mbAll = false;
+ }
+ break;
+ }
+ case ATTR_PRESENT_MANUEL:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( rPresSettings.mbManual != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbManual = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_MOUSE:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+ if( rPresSettings.mbMouseVisible != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbMouseVisible = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_ALWAYS_ON_TOP:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( rPresSettings.mbAlwaysOnTop != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbAlwaysOnTop = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_NAVIGATOR:
+ bIllegalArgument = false;
+ //ignored, but exists in some older documents
+ break;
+ case ATTR_PRESENT_PEN:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if(rPresSettings.mbMouseAsPen != bVal)
+ {
+ bValuesChanged = true;
+ rPresSettings.mbMouseAsPen = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_PAUSE_TIMEOUT:
+ {
+ sal_Int32 nValue = 0;
+ if( (aValue >>= nValue) && (nValue >= 0) )
+ {
+ bIllegalArgument = false;
+ if( rPresSettings.mnPauseTimeout != nValue )
+ {
+ bValuesChanged = true;
+ rPresSettings.mnPauseTimeout = nValue;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_SHOW_PAUSELOGO:
+ {
+ bool bVal = false;
+
+ if( aValue >>= bVal )
+ {
+ bIllegalArgument = false;
+
+ if( rPresSettings.mbShowPauseLogo != bVal )
+ {
+ bValuesChanged = true;
+ rPresSettings.mbShowPauseLogo = bVal;
+ }
+ }
+ break;
+ }
+ case ATTR_PRESENT_DISPLAY:
+ {
+ sal_Int32 nDisplay = 0;
+ if( aValue >>= nDisplay )
+ {
+ bIllegalArgument = false;
+
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ pOptions->SetDisplay( nDisplay );
+
+ FullScreenWorkWindow *pWin = dynamic_cast<FullScreenWorkWindow *>(GetWorkWindow());
+ if( !pWin )
+ return;
+ pWin->Restart(true);
+ }
+ break;
+ }
+
+ default:
+ throw UnknownPropertyException( OUString::number(pEntry ? pEntry->nWID : -1), static_cast<cppu::OWeakObject*>(this));
+ }
+
+ if( bIllegalArgument )
+ throw IllegalArgumentException();
+
+ if( bValuesChanged )
+ mpDoc->SetChanged();
+}
+
+Any SAL_CALL SlideShow::getPropertyValue( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+ ThrowIfDisposed();
+
+ const sd::PresentationSettings& rPresSettings = mpDoc->getPresentationSettings();
+
+ const SfxItemPropertyMapEntry* pEntry = maPropSet.getPropertyMapEntry(PropertyName);
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case ATTR_PRESENT_ALL:
+ return Any( !rPresSettings.mbCustomShow && rPresSettings.mbAll );
+ case ATTR_PRESENT_CHANGE_PAGE:
+ return Any( !rPresSettings.mbLockedPages );
+ case ATTR_PRESENT_ANIMATION_ALLOWED:
+ return Any( rPresSettings.mbAnimationAllowed );
+ case ATTR_PRESENT_CUSTOMSHOW:
+ {
+ SdCustomShowList* pList = mpDoc->GetCustomShowList();
+ SdCustomShow* pShow = (pList && rPresSettings.mbCustomShow) ? pList->GetCurObject() : nullptr;
+ OUString aShowName;
+
+ if(pShow)
+ aShowName = pShow->GetName();
+
+ return Any( aShowName );
+ }
+ case ATTR_PRESENT_ENDLESS:
+ return Any( rPresSettings.mbEndless );
+ case ATTR_PRESENT_FULLSCREEN:
+ return Any( rPresSettings.mbFullScreen );
+ case ATTR_PRESENT_DIANAME:
+ {
+ OUString aSlideName;
+
+ if( !rPresSettings.mbCustomShow && !rPresSettings.mbAll )
+ aSlideName = getPageApiNameFromUiName( rPresSettings.maPresPage );
+
+ return Any( aSlideName );
+ }
+ case ATTR_PRESENT_MANUEL:
+ return Any( rPresSettings.mbManual );
+ case ATTR_PRESENT_MOUSE:
+ return Any( rPresSettings.mbMouseVisible );
+ case ATTR_PRESENT_ALWAYS_ON_TOP:
+ return Any( rPresSettings.mbAlwaysOnTop );
+ case ATTR_PRESENT_NAVIGATOR:
+ return Any( false );
+ case ATTR_PRESENT_PEN:
+ return Any( rPresSettings.mbMouseAsPen );
+ case ATTR_PRESENT_PAUSE_TIMEOUT:
+ return Any( rPresSettings.mnPauseTimeout );
+ case ATTR_PRESENT_SHOW_PAUSELOGO:
+ return Any( rPresSettings.mbShowPauseLogo );
+ case ATTR_PRESENT_DISPLAY:
+ {
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ return Any(pOptions->GetDisplay());
+ }
+
+ default:
+ throw UnknownPropertyException( OUString::number(pEntry ? pEntry->nWID : -1), static_cast<cppu::OWeakObject*>(this));
+ }
+}
+
+void SAL_CALL SlideShow::addPropertyChangeListener( const OUString& , const Reference< XPropertyChangeListener >& )
+{
+}
+
+void SAL_CALL SlideShow::removePropertyChangeListener( const OUString& , const Reference< XPropertyChangeListener >& )
+{
+}
+
+void SAL_CALL SlideShow::addVetoableChangeListener( const OUString& , const Reference< XVetoableChangeListener >& )
+{
+}
+
+void SAL_CALL SlideShow::removeVetoableChangeListener( const OUString& , const Reference< XVetoableChangeListener >& )
+{
+}
+
+// XPresentation
+
+void SAL_CALL SlideShow::start()
+{
+ const Sequence< PropertyValue > aArguments;
+ startWithArguments( aArguments );
+}
+
+WorkWindow *SlideShow::GetWorkWindow()
+{
+ if( !mpFullScreenViewShellBase )
+ return nullptr;
+
+ PresentationViewShell* pShell = dynamic_cast<PresentationViewShell*>(mpFullScreenViewShellBase->GetMainViewShell().get());
+
+ if( !pShell || !pShell->GetViewFrame() )
+ return nullptr;
+
+ return dynamic_cast<WorkWindow*>(pShell->GetViewFrame()->GetFrame().GetWindow().GetParent());
+}
+
+bool SlideShow::IsExitAfterPresenting() const
+{
+ SolarMutexGuard aGuard;
+ ThrowIfDisposed();
+ return mpDoc->IsExitAfterPresenting();
+}
+
+void SlideShow::SetExitAfterPresenting(bool bExit)
+{
+ SolarMutexGuard aGuard;
+ ThrowIfDisposed();
+ mpDoc->SetExitAfterPresenting(bExit);
+}
+
+void SAL_CALL SlideShow::end()
+{
+ SolarMutexGuard aGuard;
+
+ // The mbIsInStartup flag should have been reset during the start of the
+ // slide show. Reset it here just in case that something has horribly
+ // gone wrong.
+ assert(!mbIsInStartup);
+
+ rtl::Reference< SlideshowImpl > xController( mxController );
+ if( !xController.is() )
+ return;
+
+ mxController.clear();
+
+ if( mpFullScreenFrameView )
+ {
+ delete mpFullScreenFrameView;
+ mpFullScreenFrameView = nullptr;
+ }
+
+ ViewShellBase* pFullScreenViewShellBase = mpFullScreenViewShellBase;
+ mpFullScreenViewShellBase = nullptr;
+
+ // dispose before fullscreen window changes screens
+ // (potentially). If this needs to be moved behind
+ // pWorkWindow->StartPresentationMode() again, read issue
+ // pWorkWindow->i94007 & implement the solution outlined
+ // there.
+ xController->dispose();
+
+ if( pFullScreenViewShellBase )
+ {
+ PresentationViewShell* pShell = dynamic_cast<PresentationViewShell*>(pFullScreenViewShellBase->GetMainViewShell().get());
+
+ if( pShell && pShell->GetViewFrame() )
+ {
+ WorkWindow* pWorkWindow = dynamic_cast<WorkWindow*>(pShell->GetViewFrame()->GetFrame().GetWindow().GetParent());
+ if( pWorkWindow )
+ {
+ pWorkWindow->StartPresentationMode( (mxController.is() && mxController->maPresSettings.mbAlwaysOnTop)
+ ? PresentationFlags::HideAllApps : PresentationFlags::NONE );
+ }
+ }
+ }
+
+ if( pFullScreenViewShellBase )
+ {
+ PresentationViewShell* pShell = nullptr;
+ {
+ // Get the shell pointer in its own scope to be sure that
+ // the shared_ptr to the shell is released before DoClose()
+ // is called.
+ ::std::shared_ptr<ViewShell> pSharedView (pFullScreenViewShellBase->GetMainViewShell());
+ pShell = dynamic_cast<PresentationViewShell*>(pSharedView.get());
+ }
+ if( pShell && pShell->GetViewFrame() )
+ pShell->GetViewFrame()->DoClose();
+ }
+ else if( mpCurrentViewShellBase )
+ {
+ ViewShell* pViewShell = mpCurrentViewShellBase->GetMainViewShell().get();
+
+ if( pViewShell )
+ {
+ FrameView* pFrameView = pViewShell->GetFrameView();
+
+ if( pFrameView && (pFrameView->GetPresentationViewShellId() != SID_VIEWSHELL0) )
+ {
+ ViewShell::ShellType ePreviousType (pFrameView->GetPreviousViewShellType());
+ pFrameView->SetPreviousViewShellType(ViewShell::ST_NONE);
+
+ pFrameView->SetPresentationViewShellId(SID_VIEWSHELL0);
+ pFrameView->SetPreviousViewShellType(pViewShell->GetShellType());
+
+ framework::FrameworkHelper::Instance(*mpCurrentViewShellBase)->RequestView(
+ framework::FrameworkHelper::GetViewURL(ePreviousType),
+ framework::FrameworkHelper::msCenterPaneURL);
+
+ pViewShell->GetViewFrame()->GetBindings().InvalidateAll( true );
+ }
+ }
+ }
+
+ if( mpCurrentViewShellBase )
+ {
+ if (ViewShell* const pViewShell = mpCurrentViewShellBase->GetMainViewShell().get())
+ {
+ // invalidate the view shell so the presentation slot will be re-enabled
+ // and the rehearsing will be updated
+ pViewShell->Invalidate();
+
+ if( xController->meAnimationMode ==ANIMATIONMODE_SHOW )
+ {
+ // switch to the previously visible Slide
+ DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>( pViewShell );
+ if( pDrawViewShell )
+ pDrawViewShell->SwitchPage( static_cast<sal_uInt16>(xController->getRestoreSlide()) );
+ else
+ {
+ Reference<XDrawView> xDrawView (
+ Reference<XWeak>(&mpCurrentViewShellBase->GetDrawController()), UNO_QUERY);
+ if (xDrawView.is())
+ xDrawView->setCurrentPage(
+ Reference<XDrawPage>(
+ mpDoc->GetSdPage(xController->getRestoreSlide(), PageKind::Standard)->getUnoPage(),
+ UNO_QUERY));
+ }
+ }
+
+ if( pViewShell->GetDoc()->IsExitAfterPresenting() )
+ {
+ pViewShell->GetDoc()->SetExitAfterPresenting( false );
+
+ Reference<frame::XDispatchProvider> xProvider(pViewShell->GetViewShellBase().GetController()->getFrame(),
+ UNO_QUERY);
+ if( xProvider.is() )
+ {
+ util::URL aURL;
+ aURL.Complete = ".uno:CloseFrame";
+
+ uno::Reference< frame::XDispatch > xDispatch(
+ xProvider->queryDispatch(
+ aURL, OUString(), 0));
+ if( xDispatch.is() )
+ {
+ xDispatch->dispatch(aURL,
+ uno::Sequence< beans::PropertyValue >());
+ }
+ }
+ }
+
+ // In case mbMouseAsPen was set, a new layer DrawnInSlideshow might have been generated
+ // during slideshow, which is not known to FrameView yet.
+ if (any2bool(getPropertyValue("UsePen"))
+ && pViewShell->GetDoc()->GetLayerAdmin().GetLayer("DrawnInSlideshow"))
+ {
+ SdrLayerIDSet aDocLayerIDSet;
+ pViewShell->GetDoc()->GetLayerAdmin().getVisibleLayersODF(aDocLayerIDSet);
+ if (pViewShell->GetFrameView()->GetVisibleLayers() != aDocLayerIDSet)
+ {
+ pViewShell->GetFrameView()->SetVisibleLayers(aDocLayerIDSet);
+ }
+ pViewShell->GetDoc()->GetLayerAdmin().getPrintableLayersODF(aDocLayerIDSet);
+ if (pViewShell->GetFrameView()->GetPrintableLayers() != aDocLayerIDSet)
+ {
+ pViewShell->GetFrameView()->SetPrintableLayers(aDocLayerIDSet);
+ }
+ pViewShell->GetDoc()->GetLayerAdmin().getLockedLayersODF(aDocLayerIDSet);
+ if (pViewShell->GetFrameView()->GetLockedLayers() != aDocLayerIDSet)
+ {
+ pViewShell->GetFrameView()->SetLockedLayers(aDocLayerIDSet);
+ }
+ pViewShell->InvalidateWindows();
+ }
+
+ // Fire the acc focus event when focus is switched back. The above method
+ // mpCurrentViewShellBase->GetWindow()->GrabFocus() will set focus to WorkWindow
+ // instead of the sd::window, so here call Shell's method to fire the focus event
+ pViewShell->SwitchActiveViewFireFocus();
+ }
+ }
+ mpCurrentViewShellBase = nullptr;
+}
+
+void SAL_CALL SlideShow::rehearseTimings()
+{
+ Sequence< PropertyValue > aArguments{ comphelper::makePropertyValue("RehearseTimings", true) };
+ startWithArguments( aArguments );
+}
+
+// XPresentation2
+
+void SAL_CALL SlideShow::startWithArguments(const Sequence< PropertyValue >& rArguments)
+{
+ SolarMutexGuard aGuard;
+ ThrowIfDisposed();
+
+ // Stop a running show before starting a new one.
+ if( mxController.is() )
+ {
+ assert(!mbIsInStartup);
+ end();
+ }
+ else if (mbIsInStartup)
+ {
+ // We are already somewhere in process of starting a slide show but
+ // have not yet got to the point where mxController is set. There
+ // is not yet a slide show to end so return silently.
+ return;
+ }
+
+ // Prevent multiple instance of the SlideShow class for one document.
+ mbIsInStartup = true;
+
+ mxCurrentSettings = std::make_shared<PresentationSettingsEx>( mpDoc->getPresentationSettings() );
+ mxCurrentSettings->SetArguments( rArguments );
+
+ // if there is no view shell base set, use the current one or the first using this document
+ if( mpCurrentViewShellBase == nullptr )
+ {
+ // first check current
+ ::sd::ViewShellBase* pBase = ::sd::ViewShellBase::GetViewShellBase( SfxViewFrame::Current() );
+ if( pBase && pBase->GetDocument() == mpDoc )
+ {
+ mpCurrentViewShellBase = pBase;
+ }
+ else
+ {
+ // current is not ours, so get first from ours
+ mpCurrentViewShellBase = ::sd::ViewShellBase::GetViewShellBase( SfxViewFrame::GetFirst( mpDoc->GetDocSh() ) );
+ }
+ }
+
+ // #i118456# make sure TextEdit changes get pushed to model.
+ // mpDrawView is tested against NULL above already.
+ if(mpCurrentViewShellBase)
+ {
+ ViewShell* pViewShell = mpCurrentViewShellBase->GetMainViewShell().get();
+
+ if(pViewShell && pViewShell->GetView())
+ {
+ pViewShell->GetView()->SdrEndTextEdit();
+ }
+ }
+
+ // Start either a full-screen or an in-place show.
+ if(mxCurrentSettings->mbFullScreen && !mxCurrentSettings->mbPreview)
+ StartFullscreenPresentation();
+ else
+ StartInPlacePresentation();
+
+}
+
+sal_Bool SAL_CALL SlideShow::isRunning( )
+{
+ SolarMutexGuard aGuard;
+ return mxController.is() && mxController->isRunning();
+}
+
+Reference< XSlideShowController > SAL_CALL SlideShow::getController( )
+{
+ ThrowIfDisposed();
+
+ return mxController;
+}
+
+// XComponent
+
+void SlideShow::disposing(std::unique_lock<std::mutex>&)
+{
+ SolarMutexGuard aGuard;
+
+ if( mnInPlaceConfigEvent )
+ {
+ Application::RemoveUserEvent( mnInPlaceConfigEvent );
+ mnInPlaceConfigEvent = nullptr;
+ }
+
+ if( mxController.is() )
+ {
+ mxController->dispose();
+ mxController.clear();
+ }
+
+ mpCurrentViewShellBase = nullptr;
+ mpFullScreenViewShellBase = nullptr;
+ mpDoc = nullptr;
+}
+
+void SlideShow::startPreview( const Reference< XDrawPage >& xDrawPage, const Reference< XAnimationNode >& xAnimationNode )
+{
+ Sequence< PropertyValue > aArguments{
+ comphelper::makePropertyValue("Preview", true),
+ comphelper::makePropertyValue("FirstPage", xDrawPage),
+ comphelper::makePropertyValue("AnimationNode", xAnimationNode),
+ comphelper::makePropertyValue("ParentWindow", Reference< XWindow >()),
+ };
+
+ startWithArguments( aArguments );
+}
+
+OutputDevice* SlideShow::getShowWindow()
+{
+ return mxController.is() ? mxController->mpShowWindow->GetOutDev() : nullptr;
+}
+
+int SlideShow::getAnimationMode() const
+{
+ return mxController.is() ? mxController->meAnimationMode : ANIMATIONMODE_SHOW;
+}
+
+void SlideShow::jumpToPageIndex( sal_Int32 nPageIndex )
+{
+ if( mxController.is() )
+ mxController->displaySlideIndex( nPageIndex );
+}
+
+void SlideShow::jumpToPageNumber( sal_Int32 nPageNumber )
+{
+ if( mxController.is() )
+ mxController->displaySlideNumber( nPageNumber );
+}
+
+sal_Int32 SlideShow::getCurrentPageNumber() const
+{
+ return mxController.is() ? mxController->getCurrentSlideNumber() : 0;
+}
+
+void SlideShow::jumpToBookmark( const OUString& sBookmark )
+{
+ if( mxController.is() )
+ mxController->jumpToBookmark( sBookmark );
+}
+
+bool SlideShow::isFullScreen() const
+{
+ return mxController.is() && mxController->maPresSettings.mbFullScreen;
+}
+
+void SlideShow::resize( const Size &rSize )
+{
+ if( mxController.is() )
+ mxController->resize( rSize );
+}
+
+bool SlideShow::activate( ViewShellBase& rBase )
+{
+ if( (mpFullScreenViewShellBase == &rBase) && !mxController.is() )
+ {
+ ::std::shared_ptr<PresentationViewShell> pShell = std::dynamic_pointer_cast<PresentationViewShell>(rBase.GetMainViewShell());
+ if (pShell != nullptr)
+ {
+ pShell->FinishInitialization( mpFullScreenFrameView );
+ mpFullScreenFrameView = nullptr;
+
+ CreateController( pShell.get(), pShell->GetView(), rBase.GetViewWindow() );
+
+ if (!mxController->startShow(mxCurrentSettings.get()))
+ return false;
+
+ pShell->Resize();
+ // Defer the sd::ShowWindow's GrabFocus to here. so that the accessible event can be fired correctly.
+ pShell->GetActiveWindow()->GrabFocus();
+ }
+ }
+
+ if( mxController.is() )
+ mxController->activate();
+
+ return true;
+}
+
+void SlideShow::deactivate()
+{
+ mxController->deactivate();
+}
+
+bool SlideShow::keyInput(const KeyEvent& rKEvt)
+{
+ return mxController.is() && mxController->keyInput(rKEvt);
+}
+
+void SlideShow::paint()
+{
+ if( mxController.is() )
+ mxController->paint();
+}
+
+void SlideShow::pause( bool bPause )
+{
+ if( mxController.is() )
+ {
+ if( bPause )
+ mxController->pause();
+ else
+ mxController->resume();
+ }
+}
+
+bool SlideShow::swipe(const CommandSwipeData& rSwipeData)
+{
+ return mxController.is() && mxController->swipe(rSwipeData);
+}
+
+bool SlideShow::longpress(const CommandLongPressData& rLongPressData)
+{
+ return mxController.is() && mxController->longpress(rLongPressData);
+}
+
+void SlideShow::StartInPlacePresentationConfigurationCallback()
+{
+ if( mnInPlaceConfigEvent != nullptr )
+ Application::RemoveUserEvent( mnInPlaceConfigEvent );
+
+ mnInPlaceConfigEvent = Application::PostUserEvent( LINK( this, SlideShow, StartInPlacePresentationConfigurationHdl ) );
+}
+
+IMPL_LINK_NOARG(SlideShow, StartInPlacePresentationConfigurationHdl, void*, void)
+{
+ mnInPlaceConfigEvent = nullptr;
+ StartInPlacePresentation();
+}
+
+void SlideShow::StartInPlacePresentation()
+{
+ if( mpCurrentViewShellBase )
+ {
+ // Save the current view shell type so that it can be restored after the
+ // show has ended. If there already is a saved shell type then that is
+ // not overwritten.
+
+ ViewShell::ShellType eShell = ViewShell::ST_NONE;
+
+ ::std::shared_ptr<FrameworkHelper> pHelper(FrameworkHelper::Instance(*mpCurrentViewShellBase));
+ ::std::shared_ptr<ViewShell> pMainViewShell(pHelper->GetViewShell(FrameworkHelper::msCenterPaneURL));
+
+ if( pMainViewShell )
+ eShell = pMainViewShell->GetShellType();
+
+ if( eShell != ViewShell::ST_IMPRESS )
+ {
+ // Switch temporary to a DrawViewShell which supports the in-place presentation.
+
+ if( pMainViewShell )
+ {
+ FrameView* pFrameView = pMainViewShell->GetFrameView();
+ pFrameView->SetPresentationViewShellId(SID_VIEWSHELL1);
+ pFrameView->SetPreviousViewShellType (pMainViewShell->GetShellType());
+ pFrameView->SetPageKind (PageKind::Standard);
+ }
+
+ pHelper->RequestView( FrameworkHelper::msImpressViewURL, FrameworkHelper::msCenterPaneURL );
+ pHelper->RunOnConfigurationEvent(
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ [this] (bool const) { return this->StartInPlacePresentationConfigurationCallback(); } );
+ return;
+ }
+ else
+ {
+ vcl::Window* pParentWindow = mxCurrentSettings->mpParentWindow;
+ if( pParentWindow == nullptr )
+ pParentWindow = mpCurrentViewShellBase->GetViewWindow();
+
+ CreateController( pMainViewShell.get(), pMainViewShell->GetView(), pParentWindow );
+ }
+ }
+ else if( mxCurrentSettings->mpParentWindow )
+ {
+ // no current view shell, but parent window
+ CreateController( nullptr, nullptr, mxCurrentSettings->mpParentWindow );
+ }
+
+ if( !mxController.is() )
+ return;
+
+ bool bSuccess = false;
+ if( mxCurrentSettings && mxCurrentSettings->mbPreview )
+ {
+ bSuccess = mxController->startPreview(mxCurrentSettings->mxStartPage, mxCurrentSettings->mxAnimationNode, mxCurrentSettings->mpParentWindow );
+ }
+ else
+ {
+ bSuccess = mxController->startShow(mxCurrentSettings.get());
+ }
+
+ if( !bSuccess )
+ end();
+ else
+ {
+ if( mpCurrentViewShellBase && ( !mxCurrentSettings || ( mxCurrentSettings && !mxCurrentSettings->mbPreview ) ) )
+ mpCurrentViewShellBase->GetWindow()->GrabFocus();
+ }
+}
+
+void SlideShow::StartFullscreenPresentation( )
+{
+ // Create the top level window in which the PresentationViewShell(Base)
+ // will be created. This is done here explicitly so that we can make it
+ // fullscreen.
+ const sal_Int32 nDisplay (GetDisplay());
+ VclPtr<WorkWindow> pWorkWindow = VclPtr<FullScreenWorkWindow>::Create(this, mpCurrentViewShellBase);
+ pWorkWindow->SetBackground(Wallpaper(COL_BLACK));
+ OUString Title(SdResId(STR_FULLSCREEN_SLIDESHOW));
+ Title = Title.replaceFirst("%s",
+ mpCurrentViewShellBase->GetDocShell()->GetTitle(SFX_TITLE_DETECT));
+ pWorkWindow->SetText(Title);
+ pWorkWindow->StartPresentationMode( true, mpDoc->getPresentationSettings().mbAlwaysOnTop ? PresentationFlags::HideAllApps : PresentationFlags::NONE, nDisplay);
+ // pWorkWindow->ShowFullScreenMode(sal_False, nDisplay);
+
+ if (!pWorkWindow->IsVisible())
+ return;
+
+ // Initialize the new presentation view shell with a copy of the
+ // frame view of the current view shell. This avoids that
+ // changes made by the presentation have an effect on the other
+ // view shells.
+ FrameView* pOriginalFrameView = nullptr;
+ ::std::shared_ptr<ViewShell> xShell(mpCurrentViewShellBase->GetMainViewShell());
+ if (xShell)
+ pOriginalFrameView = xShell->GetFrameView();
+
+ delete mpFullScreenFrameView;
+ mpFullScreenFrameView = new FrameView(mpDoc, pOriginalFrameView);
+
+ // The new frame is created hidden. To make it visible and activate the
+ // new view shell--a prerequisite to process slot calls and initialize
+ // its panes--a GrabFocus() has to be called later on.
+ SfxFrame* pNewFrame = SfxFrame::CreateHidden( *mpDoc->GetDocSh(), *pWorkWindow, PRESENTATION_FACTORY_ID );
+ pNewFrame->SetPresentationMode(true);
+
+ mpFullScreenViewShellBase = static_cast<ViewShellBase*>(pNewFrame->GetCurrentViewFrame()->GetViewShell());
+ if(mpFullScreenViewShellBase != nullptr)
+ {
+ // The following GrabFocus() is responsible for activating the
+ // new view shell. Without it the screen remains blank (under
+ // Windows and some Linux variants.)
+ mpFullScreenViewShellBase->GetWindow()->GrabFocus();
+ }
+}
+
+/// convert configuration setting display concept to real screens
+sal_Int32 SlideShow::GetDisplay()
+{
+ sal_Int32 nDisplay = 0;
+
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ if( pOptions )
+ nDisplay = pOptions->GetDisplay();
+
+ if( nDisplay < 0 )
+ nDisplay = -1;
+ else if( nDisplay == 0)
+ nDisplay = static_cast<sal_Int32>(Application::GetDisplayExternalScreen());
+ else
+ nDisplay--;
+
+ SAL_INFO("sd", "Presenting on real screen " << nDisplay);
+
+ return nDisplay;
+}
+
+bool SlideShow::dependsOn( ViewShellBase const * pViewShellBase )
+{
+ return mxController.is() && (pViewShellBase == mpCurrentViewShellBase) && mpFullScreenViewShellBase;
+}
+
+Reference< presentation::XPresentation2 > CreatePresentation( const SdDrawDocument& rDocument )
+{
+ return Reference< presentation::XPresentation2 >( SlideShow::Create( const_cast< SdDrawDocument* >( &rDocument ) ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/slideshowimpl.cxx b/sd/source/ui/slideshow/slideshowimpl.cxx
new file mode 100644
index 000000000..89a8ac95f
--- /dev/null
+++ b/sd/source/ui/slideshow/slideshowimpl.cxx
@@ -0,0 +1,3349 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+
+#include <config_features.h>
+
+#include <com/sun/star/frame/theAutoRecovery.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/document/XEventsSupplier.hpp>
+#include <com/sun/star/drawing/XMasterPageTarget.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/presentation/SlideShow.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+#include <officecfg/Office/Common.hxx>
+#include <svl/stritem.hxx>
+#include <svl/urihelper.hxx>
+#include <basic/sbstar.hxx>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <sfx2/infobar.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/f3dchild.hxx>
+#include <svx/imapdlg.hxx>
+#include <svx/fontwork.hxx>
+#include <svx/SvxColorChildWindow.hxx>
+#include <svx/bmpmask.hxx>
+#include <svx/srchdlg.hxx>
+#include <svx/hyperdlg.hxx>
+#include <svx/svxids.hrc>
+#include <AnimationChildWindow.hxx>
+#include <notifydocumentevent.hxx>
+#include "slideshowimpl.hxx"
+#include "slideshowviewimpl.hxx"
+#include "PaneHider.hxx"
+
+#include <bitmaps.hlst>
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/weldutils.hxx>
+
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/help.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <rtl/ref.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <svtools/colrdlg.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShellBase.hxx>
+#include <PresentationViewShell.hxx>
+#include <RemoteServer.hxx>
+#include <customshowlist.hxx>
+#include <unopage.hxx>
+#include <sdpage.hxx>
+#include <sdmod.hxx>
+#include <app.hrc>
+#include <cusshow.hxx>
+#include <optsitem.hxx>
+
+#define CM_SLIDES 21
+
+using ::com::sun::star::animations::XAnimationNode;
+using ::com::sun::star::animations::XAnimationListener;
+using ::com::sun::star::awt::XWindow;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::beans;
+
+namespace sd
+{
+/** Slots, which will be disabled in the slide show and are managed by Sfx.
+ Have to be sorted in the order of the SIDs */
+sal_uInt16 const pAllowed[] =
+{
+ SID_OPENDOC , // 5501 ///< that internally jumps work
+ SID_JUMPTOMARK , // 5598
+ SID_OPENHYPERLINK , // 6676
+ SID_PRESENTATION_END // 27218
+};
+
+class AnimationSlideController
+{
+public:
+ enum Mode { ALL, FROM, CUSTOM, PREVIEW };
+
+public:
+ AnimationSlideController( Reference< XIndexAccess > const & xSlides, Mode eMode );
+
+ void setStartSlideNumber( sal_Int32 nSlideNumber ) { mnStartSlideNumber = nSlideNumber; }
+ sal_Int32 getStartSlideIndex() const;
+
+ sal_Int32 getCurrentSlideNumber() const;
+ sal_Int32 getCurrentSlideIndex() const;
+
+ sal_Int32 getSlideIndexCount() const { return maSlideNumbers.size(); }
+ sal_Int32 getSlideNumberCount() const { return mnSlideCount; }
+
+ sal_Int32 getSlideNumber( sal_Int32 nSlideIndex ) const;
+
+ void insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible = true );
+ void setPreviewNode( const Reference< XAnimationNode >& xPreviewNode );
+
+ bool jumpToSlideIndex( sal_Int32 nNewSlideIndex );
+ bool jumpToSlideNumber( sal_Int32 nNewSlideIndex );
+
+ bool nextSlide();
+ bool previousSlide();
+
+ void displayCurrentSlide( const Reference< XSlideShow >& xShow,
+ const Reference< XDrawPagesSupplier>& xDrawPages,
+ const bool bSkipAllMainSequenceEffects );
+
+ sal_Int32 getNextSlideIndex() const;
+ sal_Int32 getPreviousSlideIndex() const;
+
+ bool isVisibleSlideNumber( sal_Int32 nSlideNumber ) const;
+
+ Reference< XDrawPage > getSlideByNumber( sal_Int32 nSlideNumber ) const;
+
+ sal_Int32 getNextSlideNumber() const;
+
+ bool hasSlides() const { return !maSlideNumbers.empty(); }
+
+private:
+ bool getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode );
+ sal_Int32 findSlideIndex( sal_Int32 nSlideNumber ) const;
+
+ bool isValidIndex( sal_Int32 nIndex ) const { return (nIndex >= 0) && (o3tl::make_unsigned(nIndex) < maSlideNumbers.size()); }
+ bool isValidSlideNumber( sal_Int32 nSlideNumber ) const { return (nSlideNumber >= 0) && (nSlideNumber < mnSlideCount); }
+
+private:
+ Mode meMode;
+ sal_Int32 mnStartSlideNumber;
+ std::vector< sal_Int32 > maSlideNumbers;
+ std::vector< bool > maSlideVisible;
+ std::vector< bool > maSlideVisited;
+ Reference< XAnimationNode > mxPreviewNode;
+ sal_Int32 mnSlideCount;
+ sal_Int32 mnCurrentSlideIndex;
+ sal_Int32 mnHiddenSlideNumber;
+ Reference< XIndexAccess > mxSlides;
+};
+
+Reference< XDrawPage > AnimationSlideController::getSlideByNumber( sal_Int32 nSlideNumber ) const
+{
+ Reference< XDrawPage > xSlide;
+ if( mxSlides.is() && (nSlideNumber >= 0) && (nSlideNumber < mxSlides->getCount()) )
+ mxSlides->getByIndex( nSlideNumber ) >>= xSlide;
+ return xSlide;
+}
+
+bool AnimationSlideController::isVisibleSlideNumber( sal_Int32 nSlideNumber ) const
+{
+ sal_Int32 nIndex = findSlideIndex( nSlideNumber );
+
+ if( nIndex != -1 )
+ return maSlideVisible[ nIndex ];
+ else
+ return false;
+}
+
+void AnimationSlideController::setPreviewNode( const Reference< XAnimationNode >& xPreviewNode )
+{
+ mxPreviewNode = xPreviewNode;
+}
+
+AnimationSlideController::AnimationSlideController( Reference< XIndexAccess > const & xSlides, Mode eMode )
+: meMode( eMode )
+, mnStartSlideNumber(-1)
+, mnSlideCount( 0 )
+, mnCurrentSlideIndex(0)
+, mnHiddenSlideNumber( -1 )
+, mxSlides( xSlides )
+{
+ if( mxSlides.is() )
+ mnSlideCount = xSlides->getCount();
+}
+
+sal_Int32 AnimationSlideController::getStartSlideIndex() const
+{
+ if( mnStartSlideNumber >= 0 )
+ {
+ sal_Int32 nIndex;
+ const sal_Int32 nCount = maSlideNumbers.size();
+
+ for( nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ if( maSlideNumbers[nIndex] == mnStartSlideNumber )
+ return nIndex;
+ }
+ }
+
+ return 0;
+}
+
+sal_Int32 AnimationSlideController::getCurrentSlideNumber() const
+{
+ if( mnHiddenSlideNumber != -1 )
+ return mnHiddenSlideNumber;
+ else if( !maSlideNumbers.empty() )
+ return maSlideNumbers[mnCurrentSlideIndex];
+ else
+ return 0;
+}
+
+sal_Int32 AnimationSlideController::getCurrentSlideIndex() const
+{
+ if( mnHiddenSlideNumber != -1 )
+ return -1;
+ else
+ return mnCurrentSlideIndex;
+}
+
+bool AnimationSlideController::jumpToSlideIndex( sal_Int32 nNewSlideIndex )
+{
+ if( isValidIndex( nNewSlideIndex ) )
+ {
+ mnCurrentSlideIndex = nNewSlideIndex;
+ mnHiddenSlideNumber = -1;
+ maSlideVisited[mnCurrentSlideIndex] = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool AnimationSlideController::jumpToSlideNumber( sal_Int32 nNewSlideNumber )
+{
+ sal_Int32 nIndex = findSlideIndex( nNewSlideNumber );
+ if( isValidIndex( nIndex ) )
+ {
+ return jumpToSlideIndex( nIndex );
+ }
+ else if( (nNewSlideNumber >= 0) && (nNewSlideNumber < mnSlideCount) )
+ {
+ // jump to a hidden slide
+ mnHiddenSlideNumber = nNewSlideNumber;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+sal_Int32 AnimationSlideController::getSlideNumber( sal_Int32 nSlideIndex ) const
+{
+ if( isValidIndex( nSlideIndex ) )
+ return maSlideNumbers[nSlideIndex];
+ else
+ return -1;
+}
+
+void AnimationSlideController::insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible /* = true */ )
+{
+ DBG_ASSERT( isValidSlideNumber( nSlideNumber ), "sd::AnimationSlideController::insertSlideNumber(), illegal index" );
+ if( isValidSlideNumber( nSlideNumber ) )
+ {
+ maSlideNumbers.push_back( nSlideNumber );
+ maSlideVisible.push_back( bVisible );
+ maSlideVisited.push_back( false );
+ }
+}
+
+bool AnimationSlideController::getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode )
+{
+ if( isValidSlideNumber( nSlideNumber ) ) try
+ {
+ xSlide.set( mxSlides->getByIndex(nSlideNumber), UNO_QUERY_THROW );
+
+ if( meMode == PREVIEW )
+ {
+ xAnimNode = mxPreviewNode;
+ }
+ else
+ {
+ Reference< animations::XAnimationNodeSupplier > xAnimNodeSupplier( xSlide, UNO_QUERY_THROW );
+ xAnimNode = xAnimNodeSupplier->getAnimationNode();
+ }
+
+ return true;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::AnimationSlideController::getSlideAPI()" );
+ }
+
+ return false;
+}
+
+sal_Int32 AnimationSlideController::findSlideIndex( sal_Int32 nSlideNumber ) const
+{
+ sal_Int32 nIndex;
+ const sal_Int32 nCount = maSlideNumbers.size();
+
+ for( nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ if( maSlideNumbers[nIndex] == nSlideNumber )
+ return nIndex;
+ }
+
+ return -1;
+}
+
+sal_Int32 AnimationSlideController::getNextSlideIndex() const
+{
+ switch( meMode )
+ {
+ case ALL:
+ {
+ sal_Int32 nNewSlideIndex = mnCurrentSlideIndex + 1;
+ if( isValidIndex( nNewSlideIndex ) )
+ {
+ // if the current slide is not excluded, make sure the
+ // next slide is also not excluded.
+ // if the current slide is excluded, we want to go
+ // to the next slide, even if this is also excluded.
+ if( maSlideVisible[mnCurrentSlideIndex] )
+ {
+ while( isValidIndex( nNewSlideIndex ) )
+ {
+ if( maSlideVisible[nNewSlideIndex] )
+ break;
+
+ nNewSlideIndex++;
+ }
+ }
+ }
+ return isValidIndex( nNewSlideIndex ) ? nNewSlideIndex : -1;
+ }
+
+ case FROM:
+ case CUSTOM:
+ return mnHiddenSlideNumber == -1 ? mnCurrentSlideIndex + 1 : mnCurrentSlideIndex;
+
+ default:
+ case PREVIEW:
+ return -1;
+
+ }
+}
+
+sal_Int32 AnimationSlideController::getNextSlideNumber() const
+{
+ sal_Int32 nNextSlideIndex = getNextSlideIndex();
+ if( isValidIndex( nNextSlideIndex ) )
+ {
+ return maSlideNumbers[nNextSlideIndex];
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+bool AnimationSlideController::nextSlide()
+{
+ return jumpToSlideIndex( getNextSlideIndex() );
+}
+
+sal_Int32 AnimationSlideController::getPreviousSlideIndex() const
+{
+ sal_Int32 nNewSlideIndex = mnCurrentSlideIndex - 1;
+
+ switch( meMode )
+ {
+ case ALL:
+ {
+ // make sure the previous slide is visible
+ // or was already visited
+ while( isValidIndex( nNewSlideIndex ) )
+ {
+ if( maSlideVisible[nNewSlideIndex] || maSlideVisited[nNewSlideIndex] )
+ break;
+
+ nNewSlideIndex--;
+ }
+
+ break;
+ }
+
+ case PREVIEW:
+ return -1;
+
+ default:
+ break;
+ }
+
+ return nNewSlideIndex;
+}
+
+bool AnimationSlideController::previousSlide()
+{
+ return jumpToSlideIndex( getPreviousSlideIndex() );
+}
+
+void AnimationSlideController::displayCurrentSlide( const Reference< XSlideShow >& xShow,
+ const Reference< XDrawPagesSupplier>& xDrawPages,
+ const bool bSkipAllMainSequenceEffects )
+{
+ const sal_Int32 nCurrentSlideNumber = getCurrentSlideNumber();
+
+ if( !(xShow.is() && (nCurrentSlideNumber != -1 )) )
+ return;
+
+ Reference< XDrawPage > xSlide;
+ Reference< XAnimationNode > xAnimNode;
+ ::std::vector<PropertyValue> aProperties;
+
+ const sal_Int32 nNextSlideNumber = getNextSlideNumber();
+ if( getSlideAPI( nNextSlideNumber, xSlide, xAnimNode ) )
+ {
+ Sequence< Any > aValue{ Any(xSlide), Any(xAnimNode) };
+ aProperties.emplace_back( "Prefetch" ,
+ -1,
+ Any(aValue),
+ PropertyState_DIRECT_VALUE);
+ }
+ if (bSkipAllMainSequenceEffects)
+ {
+ // Add one property that prevents the slide transition from being
+ // shown (to speed up the transition to the previous slide) and
+ // one to show all main sequence effects so that the user can
+ // continue to undo effects.
+ aProperties.emplace_back( "SkipAllMainSequenceEffects",
+ -1,
+ Any(true),
+ PropertyState_DIRECT_VALUE);
+ aProperties.emplace_back("SkipSlideTransition",
+ -1,
+ Any(true),
+ PropertyState_DIRECT_VALUE);
+ }
+
+ if( getSlideAPI( nCurrentSlideNumber, xSlide, xAnimNode ) )
+ xShow->displaySlide( xSlide, xDrawPages, xAnimNode, comphelper::containerToSequence(aProperties) );
+}
+
+constexpr OUStringLiteral gsOnClick( u"OnClick" );
+constexpr OUStringLiteral gsBookmark( u"Bookmark" );
+constexpr OUStringLiteral gsVerb( u"Verb" );
+
+SlideshowImpl::SlideshowImpl( const Reference< XPresentation2 >& xPresentation, ViewShell* pViewSh, ::sd::View* pView, SdDrawDocument* pDoc, vcl::Window* pParentWindow )
+: mxModel(pDoc->getUnoModel(),UNO_QUERY_THROW)
+, maUpdateTimer("SlideShowImpl maUpdateTimer")
+, maInputFreezeTimer("SlideShowImpl maInputFreezeTimer")
+, maDeactivateTimer("SlideShowImpl maDeactivateTimer")
+, mpView(pView)
+, mpViewShell(pViewSh)
+, mpDocSh(pDoc->GetDocSh())
+, mpDoc(pDoc)
+, mpParentWindow(pParentWindow)
+, mpShowWindow(nullptr)
+, mnRestoreSlide(0)
+, maPresSize( -1, -1 )
+, meAnimationMode(ANIMATIONMODE_SHOW)
+, mpOldActiveWindow(nullptr)
+, mnChildMask( 0 )
+, mbDisposed(false)
+, mbAutoSaveWasOn(false)
+, mbRehearseTimings(false)
+, mbIsPaused(false)
+, mbWasPaused(false)
+, mbInputFreeze(false)
+, mbActive(false)
+, maPresSettings( pDoc->getPresentationSettings() )
+, mnUserPaintColor( 0x80ff0000L )
+, mbUsePen(false)
+, mdUserPaintStrokeWidth ( 150.0 )
+, mnEndShowEvent(nullptr)
+, mnContextMenuEvent(nullptr)
+, mxPresentation( xPresentation )
+{
+ if( mpViewShell )
+ mpOldActiveWindow = mpViewShell->GetActiveWindow();
+
+ maUpdateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, updateHdl));
+ // Priority must not be too high or we'll starve input handling etc.
+ maUpdateTimer.SetPriority(TaskPriority::REPAINT);
+
+ maDeactivateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, deactivateHdl));
+ maDeactivateTimer.SetTimeout( 20 );
+
+ maInputFreezeTimer.SetInvokeHandler( LINK( this, SlideshowImpl, ReadyForNextInputHdl ) );
+ maInputFreezeTimer.SetTimeout( 20 );
+
+ // no autosave during show
+ if( officecfg::Office::Common::Save::Document::AutoSave::get() )
+ mbAutoSaveWasOn = true;
+
+ Application::AddEventListener( LINK( this, SlideshowImpl, EventListenerHdl ) );
+
+ mbUsePen = maPresSettings.mbMouseAsPen;
+
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
+ if( pOptions )
+ {
+ mnUserPaintColor = pOptions->GetPresentationPenColor();
+ mdUserPaintStrokeWidth = pOptions->GetPresentationPenWidth();
+ }
+}
+
+SlideshowImpl::~SlideshowImpl()
+{
+ SdModule *pModule = SD_MOD();
+ //rhbz#806663 SlideshowImpl can outlive SdModule
+ SdOptions* pOptions = pModule ?
+ pModule->GetSdOptions(DocumentType::Impress) : nullptr;
+ if( pOptions )
+ {
+ pOptions->SetPresentationPenColor(mnUserPaintColor);
+ pOptions->SetPresentationPenWidth(mdUserPaintStrokeWidth);
+ }
+
+ Application::RemoveEventListener( LINK( this, SlideshowImpl, EventListenerHdl ) );
+
+ maDeactivateTimer.Stop();
+
+ if( !mbDisposed )
+ {
+ OSL_FAIL("SlideshowImpl::~SlideshowImpl(), component was not disposed!");
+ std::unique_lock g(m_aMutex);
+ disposing(g);
+ }
+}
+
+void SlideshowImpl::disposing(std::unique_lock<std::mutex>&)
+{
+#ifdef ENABLE_SDREMOTE
+ RemoteServer::presentationStopped();
+#endif
+ if( mxShow.is() && mpDoc )
+ NotifyDocumentEvent(
+ *mpDoc,
+ "OnEndPresentation" );
+
+ if( mbAutoSaveWasOn )
+ setAutoSaveState( true );
+
+ if( mnEndShowEvent )
+ Application::RemoveUserEvent( mnEndShowEvent );
+ if( mnContextMenuEvent )
+ Application::RemoveUserEvent( mnContextMenuEvent );
+
+ maInputFreezeTimer.Stop();
+
+ SolarMutexGuard aSolarGuard;
+
+ if( !mxShow.is() )
+ return;
+
+ if( mxPresentation.is() )
+ mxPresentation->end();
+
+ maUpdateTimer.Stop();
+
+ removeShapeEvents();
+
+ if( mxListenerProxy.is() )
+ mxListenerProxy->removeAsSlideShowListener();
+
+ try
+ {
+ if( mxView.is() )
+ mxShow->removeView( mxView );
+
+ Reference< XComponent > xComponent( mxShow, UNO_QUERY );
+ if( xComponent.is() )
+ xComponent->dispose();
+
+ if( mxView.is() )
+ mxView->dispose();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stop()" );
+ }
+
+ mxShow.clear();
+ mxView.clear();
+ mxListenerProxy.clear();
+ mpSlideController.reset();
+
+ // take DrawView from presentation window, but give the old window back
+ if( mpShowWindow && mpView )
+ mpView->DeleteWindowFromPaintView( mpShowWindow->GetOutDev() );
+
+ if( mpView )
+ mpView->SetAnimationPause( false );
+
+ if( mpViewShell )
+ {
+ mpViewShell->SetActiveWindow(mpOldActiveWindow);
+ if (mpShowWindow)
+ mpShowWindow->SetViewShell( nullptr );
+ }
+
+ if( mpView )
+ mpView->InvalidateAllWin();
+
+ if( maPresSettings.mbFullScreen )
+ {
+#if HAVE_FEATURE_SCRIPTING
+ // restore StarBASICErrorHdl
+ StarBASIC::SetGlobalErrorHdl(maStarBASICGlobalErrorHdl);
+ maStarBASICGlobalErrorHdl = Link<StarBASIC*,bool>();
+#endif
+ }
+ else
+ {
+ if( mpShowWindow )
+ mpShowWindow->Hide();
+ }
+
+ if( meAnimationMode == ANIMATIONMODE_SHOW )
+ {
+ mpDocSh->SetSlotFilter();
+ mpDocSh->ApplySlotFilter();
+
+ Help::EnableContextHelp();
+ Help::EnableExtHelp();
+
+ showChildWindows();
+ mnChildMask = 0;
+ }
+
+ // show current window again
+ if( mpViewShell && dynamic_cast< PresentationViewShell *>( mpViewShell ) == nullptr)
+ {
+ if( meAnimationMode == ANIMATIONMODE_SHOW )
+ {
+ mpViewShell->GetViewShellBase().ShowUIControls (true);
+ mpPaneHider.reset();
+ }
+ else if( meAnimationMode == ANIMATIONMODE_PREVIEW )
+ {
+ mpViewShell->ShowUIControls(true);
+ }
+ }
+
+ if( mpShowWindow )
+ mpShowWindow->Hide();
+ mpShowWindow.disposeAndClear();
+
+ if ( mpViewShell )
+ {
+ if( meAnimationMode == ANIMATIONMODE_SHOW )
+ {
+ ::sd::Window* pActWin = mpViewShell->GetActiveWindow();
+
+ if (pActWin)
+ {
+ Size aVisSizePixel = pActWin->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = pActWin->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ mpViewShell->VisAreaChanged(aVisAreaWin);
+ if (mpView)
+ mpView->VisAreaChanged(pActWin->GetOutDev());
+ pActWin->GrabFocus();
+ }
+ }
+
+ // restart the custom show dialog if he started us
+ if( mpViewShell->IsStartShowWithDialog() && getDispatcher() )
+ {
+ mpViewShell->SetStartShowWithDialog( false );
+ getDispatcher()->Execute( SID_CUSTOMSHOW_DLG, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+
+ mpViewShell->GetViewShellBase().UpdateBorder(true);
+ }
+
+ if( mpShowWindow )
+ {
+ mpShowWindow.disposeAndClear();
+ }
+
+ setActiveXToolbarsVisible( true );
+
+ mbDisposed = true;
+}
+
+bool SlideshowImpl::startPreview(
+ const Reference< XDrawPage >& xDrawPage,
+ const Reference< XAnimationNode >& xAnimationNode,
+ vcl::Window * pParent )
+{
+ bool bRet = false;
+
+ try
+ {
+ const Reference<lang::XServiceInfo> xServiceInfo( xDrawPage, UNO_QUERY );
+ if (xServiceInfo.is()) {
+ const Sequence<OUString> supportedServices(
+ xServiceInfo->getSupportedServiceNames() );
+ if (comphelper::findValue(supportedServices, "com.sun.star.drawing.MasterPage") != -1) {
+ OSL_FAIL("sd::SlideshowImpl::startPreview() "
+ "not allowed on master page!");
+ return false;
+ }
+ }
+
+ mxPreviewDrawPage = xDrawPage;
+ mxPreviewAnimationNode = xAnimationNode;
+ meAnimationMode = ANIMATIONMODE_PREVIEW;
+
+ maPresSettings.mbAll = false;
+ maPresSettings.mbEndless = false;
+ maPresSettings.mbCustomShow = false;
+ maPresSettings.mbManual = false;
+ maPresSettings.mbMouseVisible = false;
+ maPresSettings.mbMouseAsPen = false;
+ maPresSettings.mbLockedPages = false;
+ maPresSettings.mbAlwaysOnTop = false;
+ maPresSettings.mbFullScreen = false;
+ maPresSettings.mbAnimationAllowed = true;
+ maPresSettings.mnPauseTimeout = 0;
+ maPresSettings.mbShowPauseLogo = false;
+
+ Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
+ mpSlideController = std::make_shared<AnimationSlideController>( xSlides, AnimationSlideController::PREVIEW );
+
+ sal_Int32 nSlideNumber = 0;
+ Reference< XPropertySet > xSet( mxPreviewDrawPage, UNO_QUERY_THROW );
+ xSet->getPropertyValue( "Number" ) >>= nSlideNumber;
+ mpSlideController->insertSlideNumber( nSlideNumber-1 );
+ mpSlideController->setPreviewNode( xAnimationNode );
+
+ mpShowWindow = VclPtr<ShowWindow>::Create( this, ((pParent == nullptr) && mpViewShell) ? mpParentWindow.get() : pParent );
+ if( mpViewShell )
+ {
+ mpViewShell->SetActiveWindow( mpShowWindow );
+ mpShowWindow->SetViewShell (mpViewShell);
+ mpViewShell->ShowUIControls (false);
+ }
+
+ if( mpView )
+ {
+ mpView->AddWindowToPaintView( mpShowWindow->GetOutDev(), nullptr );
+ mpView->SetAnimationPause( true );
+ }
+
+ // call resize handler
+ if( pParent )
+ {
+ maPresSize = pParent->GetSizePixel();
+ }
+ else if( mpViewShell )
+ {
+ ::tools::Rectangle aContentRect (mpViewShell->GetViewShellBase().getClientRectangle());
+ if (AllSettings::GetLayoutRTL())
+ {
+ aContentRect.SetLeft( aContentRect.Right() );
+ aContentRect.AdjustRight(aContentRect.Right() );
+ }
+ maPresSize = aContentRect.GetSize();
+ mpShowWindow->SetPosPixel( aContentRect.TopLeft() );
+ }
+ else
+ {
+ OSL_FAIL("sd::SlideshowImpl::startPreview(), I need either a parent window or a viewshell!");
+ }
+ resize( maPresSize );
+
+ sal_Int32 nPropertyCount = 1;
+ if( mxPreviewAnimationNode.is() )
+ nPropertyCount++;
+
+ Sequence< beans::PropertyValue > aProperties(nPropertyCount);
+ auto pProperties = aProperties.getArray();
+ pProperties[0].Name = "AutomaticAdvancement";
+ pProperties[0].Value <<= 1.0; // one second timeout
+
+ if( mxPreviewAnimationNode.is() )
+ {
+ pProperties[1].Name = "NoSlideTransitions";
+ pProperties[1].Value <<= true;
+ }
+
+ bRet = startShowImpl( aProperties );
+
+ if( mpShowWindow != nullptr && meAnimationMode == ANIMATIONMODE_PREVIEW )
+ mpShowWindow->SetPreviewMode();
+
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startPreview()" );
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+bool SlideshowImpl::startShow( PresentationSettingsEx const * pPresSettings )
+{
+ const rtl::Reference<SlideshowImpl> xKeepAlive(this);
+
+ DBG_ASSERT( !mxShow.is(), "sd::SlideshowImpl::startShow(), called twice!" );
+ if( mxShow.is() )
+ return true;
+ DBG_ASSERT( mpParentWindow!=nullptr, "sd::SlideshowImpl::startShow() called without parent window" );
+ if (mpParentWindow == nullptr)
+ return false;
+
+ // Autoplay (pps/ppsx)
+ if (mpViewShell->GetDoc()->IsStartWithPresentation()){
+ mpViewShell->GetDoc()->SetExitAfterPresenting(true);
+ }
+
+ bool bRet = false;
+
+ try
+ {
+ if( pPresSettings )
+ {
+ maPresSettings = *pPresSettings;
+ mbRehearseTimings = pPresSettings->mbRehearseTimings;
+ }
+
+ OUString aPresSlide( maPresSettings.maPresPage );
+ SdPage* pStartPage = mpViewShell->GetActualPage();
+ bool bStartWithActualSlide = pStartPage;
+
+ // times should be measured?
+ if( mbRehearseTimings )
+ {
+ maPresSettings.mbEndless = false;
+ maPresSettings.mbManual = true;
+ maPresSettings.mbMouseVisible = true;
+ maPresSettings.mbMouseAsPen = false;
+ maPresSettings.mnPauseTimeout = 0;
+ maPresSettings.mbShowPauseLogo = false;
+ }
+
+ if( pStartPage )
+ {
+ if( pStartPage->GetPageKind() == PageKind::Notes )
+ {
+ // we are in notes page mode, so get
+ // the corresponding draw page
+ const sal_uInt16 nPgNum = ( pStartPage->GetPageNum() - 2 ) >> 1;
+ pStartPage = mpDoc->GetSdPage( nPgNum, PageKind::Standard );
+ }
+ }
+
+ if( bStartWithActualSlide )
+ {
+ if ( aPresSlide.isEmpty())
+ {
+ // no preset slide yet, so pick current on one
+ aPresSlide = pStartPage->GetName();
+ // if the starting slide is hidden, we can't set slide controller to ALL mode
+ maPresSettings.mbAll = !pStartPage->IsExcluded();
+ }
+
+ if( meAnimationMode != ANIMATIONMODE_SHOW )
+ {
+ if( pStartPage->GetPageKind() == PageKind::Standard )
+ {
+ maPresSettings.mbAll = false;
+ }
+ }
+ }
+
+ // build page list
+ createSlideList( maPresSettings.mbAll, aPresSlide );
+
+ // remember Slide number from where the show was started
+ if( pStartPage )
+ mnRestoreSlide = ( pStartPage->GetPageNum() - 1 ) / 2;
+
+ if( mpSlideController->hasSlides() )
+ {
+ // hide child windows
+ hideChildWindows();
+
+ mpShowWindow = VclPtr<ShowWindow>::Create( this, mpParentWindow );
+ mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible );
+ mpViewShell->SetActiveWindow( mpShowWindow );
+ mpShowWindow->SetViewShell (mpViewShell);
+ mpViewShell->GetViewShellBase().ShowUIControls (false);
+ // Hide the side panes for in-place presentations.
+ if ( ! maPresSettings.mbFullScreen)
+ mpPaneHider.reset(new PaneHider(*mpViewShell,this));
+
+ // these Slots are forbidden in other views for this document
+ if( mpDocSh )
+ {
+ mpDocSh->SetSlotFilter( true, pAllowed );
+ mpDocSh->ApplySlotFilter();
+ }
+
+ Help::DisableContextHelp();
+ Help::DisableExtHelp();
+
+ if( maPresSettings.mbFullScreen )
+ {
+#if HAVE_FEATURE_SCRIPTING
+ // disable basic ide error handling
+ maStarBASICGlobalErrorHdl = StarBASIC::GetGlobalErrorHdl();
+ StarBASIC::SetGlobalErrorHdl( Link<StarBASIC*,bool>() );
+#endif
+ }
+
+ // call resize handler
+ maPresSize = mpParentWindow->GetSizePixel();
+ if (!maPresSettings.mbFullScreen)
+ {
+ const ::tools::Rectangle& aClientRect = mpViewShell->GetViewShellBase().getClientRectangle();
+ maPresSize = aClientRect.GetSize();
+ mpShowWindow->SetPosPixel( aClientRect.TopLeft() );
+ resize( maPresSize );
+ }
+
+ // #i41824#
+ // Note: In FullScreen Mode the OS (window manager) sends a resize to
+ // the WorkWindow once it actually resized it to full size. The
+ // WorkWindow propagates the resize to the DrawViewShell which calls
+ // resize() at the SlideShow (this). Calling resize here results in a
+ // temporary display of a black window in the window's default size
+
+ if( mpView )
+ {
+ mpView->AddWindowToPaintView( mpShowWindow->GetOutDev(), nullptr );
+ mpView->SetAnimationPause( true );
+ }
+
+ SfxBindings* pBindings = getBindings();
+ if( pBindings )
+ {
+ pBindings->Invalidate( SID_PRESENTATION );
+ pBindings->Invalidate( SID_REHEARSE_TIMINGS );
+ }
+
+ // Defer the sd::ShowWindow's GrabFocus to SlideShow::activate. so that the accessible event can be fired correctly.
+ //mpShowWindow->GrabFocus();
+
+ std::vector<beans::PropertyValue> aProperties;
+ aProperties.reserve( 4 );
+
+ aProperties.emplace_back( "AdvanceOnClick" ,
+ -1, Any( !maPresSettings.mbLockedPages ),
+ beans::PropertyState_DIRECT_VALUE );
+
+ aProperties.emplace_back( "ImageAnimationsAllowed" ,
+ -1, Any( maPresSettings.mbAnimationAllowed ),
+ beans::PropertyState_DIRECT_VALUE );
+
+ const bool bZOrderEnabled(
+ SD_MOD()->GetSdOptions( mpDoc->GetDocumentType() )->IsSlideshowRespectZOrder() );
+ aProperties.emplace_back( "DisableAnimationZOrder" ,
+ -1, Any( !bZOrderEnabled ),
+ beans::PropertyState_DIRECT_VALUE );
+
+ aProperties.emplace_back( "ForceManualAdvance" ,
+ -1, Any( maPresSettings.mbManual ),
+ beans::PropertyState_DIRECT_VALUE );
+
+ if( mbUsePen )
+ {
+ aProperties.emplace_back( "UserPaintColor" ,
+ // User paint color is black by default.
+ -1, Any( mnUserPaintColor ),
+ beans::PropertyState_DIRECT_VALUE );
+
+ aProperties.emplace_back( "UserPaintStrokeWidth" ,
+ // User paint color is black by default.
+ -1, Any( mdUserPaintStrokeWidth ),
+ beans::PropertyState_DIRECT_VALUE );
+ }
+
+ if (mbRehearseTimings) {
+ aProperties.emplace_back( "RehearseTimings" ,
+ -1, Any(true), beans::PropertyState_DIRECT_VALUE );
+ }
+
+ bRet = startShowImpl( Sequence<beans::PropertyValue>(
+ aProperties.data(), aProperties.size() ) );
+
+ }
+
+ setActiveXToolbarsVisible( false );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShow()" );
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+bool SlideshowImpl::startShowImpl( const Sequence< beans::PropertyValue >& aProperties )
+{
+ try
+ {
+ mxShow.set( createSlideShow(), UNO_SET_THROW );
+
+ mxView = new SlideShowView(
+ *mpShowWindow,
+ mpDoc,
+ meAnimationMode,
+ this,
+ maPresSettings.mbFullScreen);
+
+ // try add wait symbol to properties:
+ const Reference<rendering::XSpriteCanvas> xSpriteCanvas(
+ mxView->getCanvas() );
+ if (xSpriteCanvas.is())
+ {
+ BitmapEx waitSymbolBitmap(BMP_WAIT_ICON);
+ const Reference<rendering::XBitmap> xBitmap(
+ vcl::unotools::xBitmapFromBitmapEx( waitSymbolBitmap ) );
+ if (xBitmap.is())
+ {
+ mxShow->setProperty(
+ beans::PropertyValue( "WaitSymbolBitmap" ,
+ -1,
+ Any( xBitmap ),
+ beans::PropertyState_DIRECT_VALUE ) );
+ }
+
+ BitmapEx pointerSymbolBitmap(BMP_POINTER_ICON);
+ const Reference<rendering::XBitmap> xPointerBitmap(
+ vcl::unotools::xBitmapFromBitmapEx( pointerSymbolBitmap ) );
+ if (xPointerBitmap.is())
+ {
+ mxShow->setProperty(
+ beans::PropertyValue( "PointerSymbolBitmap" ,
+ -1,
+ Any( xPointerBitmap ),
+ beans::PropertyState_DIRECT_VALUE ) );
+ }
+ }
+
+ for( const auto& rProp : aProperties )
+ mxShow->setProperty( rProp );
+
+ mxShow->addView( mxView );
+
+ mxListenerProxy.set( new SlideShowListenerProxy( this, mxShow ) );
+ mxListenerProxy->addAsSlideShowListener();
+
+ NotifyDocumentEvent(
+ *mpDoc,
+ "OnStartPresentation");
+ displaySlideIndex( mpSlideController->getStartSlideIndex() );
+
+ return true;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShowImpl()" );
+ return false;
+ }
+}
+
+/** called only by the slideshow view when the first paint event occurs.
+ This actually starts the slideshow. */
+void SlideshowImpl::onFirstPaint()
+{
+ if( mpShowWindow )
+ {
+ /*
+ mpShowWindow->SetBackground( Wallpaper( COL_BLACK ) );
+ mpShowWindow->Erase();
+ mpShowWindow->SetBackground();
+ */
+ }
+
+ SolarMutexGuard aSolarGuard;
+ maUpdateTimer.SetTimeout( sal_uLong(100) );
+ maUpdateTimer.Start();
+}
+
+void SlideshowImpl::paint()
+{
+ if( mxView.is() ) try
+ {
+ awt::PaintEvent aEvt;
+ // aEvt.UpdateRect = TODO
+ mxView->paint( aEvt );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::paint()" );
+ }
+}
+
+void SAL_CALL SlideshowImpl::addSlideShowListener( const Reference< XSlideShowListener >& xListener )
+{
+ if( mxListenerProxy.is() )
+ mxListenerProxy->addSlideShowListener( xListener );
+}
+
+void SAL_CALL SlideshowImpl::removeSlideShowListener( const Reference< XSlideShowListener >& xListener )
+{
+ if( mxListenerProxy.is() )
+ mxListenerProxy->removeSlideShowListener( xListener );
+}
+
+void SlideshowImpl::slideEnded(const bool bReverse)
+{
+ if (bReverse)
+ gotoPreviousSlide(true);
+ else
+ gotoNextSlide();
+}
+
+bool SlideshowImpl::swipe(const CommandSwipeData &rSwipeData)
+{
+ if (mbUsePen || mnContextMenuEvent)
+ return false;
+ double nVelocityX = rSwipeData.getVelocityX();
+ // tdf#108475 make it swipe only if some reasonable movement was involved
+ if (fabs(nVelocityX) < 50)
+ return false;
+ if (nVelocityX > 0)
+ {
+ gotoPreviousSlide();
+ }
+ else
+ {
+ gotoNextEffect();
+ }
+ //a swipe is followed by a mouse up, tell the view to ignore that mouse up as we've reacted
+ //to the swipe instead
+ mxView->ignoreNextMouseReleased();
+ return true;
+}
+
+bool SlideshowImpl::longpress(const CommandLongPressData &rLongPressData)
+{
+ if (mnContextMenuEvent)
+ return false;
+
+ maPopupMousePos = Point(rLongPressData.getX(), rLongPressData.getY());
+ mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
+
+ return true;
+}
+
+void SlideshowImpl::removeShapeEvents()
+{
+ if( !(mxShow.is() && mxListenerProxy.is()) )
+ return;
+
+ try
+ {
+ for( const auto& rEntry : maShapeEventMap )
+ {
+ mxListenerProxy->removeShapeEventListener( rEntry.first );
+ mxShow->setShapeCursor( rEntry.first, awt::SystemPointer::ARROW );
+ }
+
+ maShapeEventMap.clear();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::removeShapeEvents()" );
+ }
+}
+
+void SlideshowImpl::registerShapeEvents(sal_Int32 nSlideNumber)
+{
+ if( nSlideNumber < 0 )
+ return;
+
+ try
+ {
+ Reference< XDrawPagesSupplier > xDrawPages( mxModel, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xPages( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
+
+ Reference< XShapes > xDrawPage;
+ xPages->getByIndex(nSlideNumber) >>= xDrawPage;
+
+ if( xDrawPage.is() )
+ {
+ Reference< XMasterPageTarget > xMasterPageTarget( xDrawPage, UNO_QUERY );
+ if( xMasterPageTarget.is() )
+ {
+ Reference< XShapes > xMasterPage = xMasterPageTarget->getMasterPage();
+ if( xMasterPage.is() )
+ registerShapeEvents( xMasterPage );
+ }
+ registerShapeEvents( xDrawPage );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" );
+ }
+}
+
+void SlideshowImpl::registerShapeEvents( Reference< XShapes > const & xShapes )
+{
+ try
+ {
+ const sal_Int32 nShapeCount = xShapes->getCount();
+ sal_Int32 nShape;
+ for( nShape = 0; nShape < nShapeCount; nShape++ )
+ {
+ Reference< XShape > xShape;
+ xShapes->getByIndex( nShape ) >>= xShape;
+
+ if( xShape.is() && xShape->getShapeType() == "com.sun.star.drawing.GroupShape" )
+ {
+ Reference< XShapes > xSubShapes( xShape, UNO_QUERY );
+ if( xSubShapes.is() )
+ registerShapeEvents( xSubShapes );
+ }
+
+ Reference< XPropertySet > xSet( xShape, UNO_QUERY );
+ if( !xSet.is() )
+ continue;
+
+ Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
+ if( !xSetInfo.is() || !xSetInfo->hasPropertyByName( gsOnClick ) )
+ continue;
+
+ WrappedShapeEventImplPtr pEvent = std::make_shared<WrappedShapeEventImpl>();
+ xSet->getPropertyValue( gsOnClick ) >>= pEvent->meClickAction;
+
+ switch( pEvent->meClickAction )
+ {
+ case ClickAction_PREVPAGE:
+ case ClickAction_NEXTPAGE:
+ case ClickAction_FIRSTPAGE:
+ case ClickAction_LASTPAGE:
+ case ClickAction_STOPPRESENTATION:
+ break;
+ case ClickAction_BOOKMARK:
+ if( xSetInfo->hasPropertyByName( gsBookmark ) )
+ xSet->getPropertyValue( gsBookmark ) >>= pEvent->maStrBookmark;
+ if( getSlideNumberForBookmark( pEvent->maStrBookmark ) == -1 )
+ continue;
+ break;
+ case ClickAction_DOCUMENT:
+ case ClickAction_SOUND:
+ case ClickAction_PROGRAM:
+ case ClickAction_MACRO:
+ if( xSetInfo->hasPropertyByName( gsBookmark ) )
+ xSet->getPropertyValue( gsBookmark ) >>= pEvent->maStrBookmark;
+ break;
+ case ClickAction_VERB:
+ if( xSetInfo->hasPropertyByName( gsVerb ) )
+ xSet->getPropertyValue( gsVerb ) >>= pEvent->mnVerb;
+ break;
+ default:
+ continue; // skip all others
+ }
+
+ maShapeEventMap[ xShape ] = pEvent;
+
+ if( mxListenerProxy.is() )
+ mxListenerProxy->addShapeEventListener( xShape );
+ mxShow->setShapeCursor( xShape, awt::SystemPointer::REFHAND );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" );
+ }
+}
+
+void SlideshowImpl::displayCurrentSlide (const bool bSkipAllMainSequenceEffects)
+{
+ stopSound();
+ removeShapeEvents();
+
+ if( mpSlideController && mxShow.is() )
+ {
+ Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(),
+ UNO_QUERY_THROW );
+ mpSlideController->displayCurrentSlide( mxShow, xDrawPages, bSkipAllMainSequenceEffects );
+ registerShapeEvents(mpSlideController->getCurrentSlideNumber());
+ update();
+
+ }
+ // send out page change event and notify to update all acc info for current page
+ if (mpViewShell)
+ {
+ sal_Int32 currentPageIndex = getCurrentSlideIndex();
+ mpViewShell->fireSwitchCurrentPage(currentPageIndex);
+ mpViewShell->NotifyAccUpdate();
+ }
+}
+
+void SlideshowImpl::endPresentation()
+{
+ if( maPresSettings.mbMouseAsPen)
+ {
+ Reference< XMultiServiceFactory > xDocFactory(mpDoc->getUnoModel(), UNO_QUERY );
+ if( xDocFactory.is() )
+ mxShow->registerUserPaintPolygons(xDocFactory);
+ }
+
+ if( !mnEndShowEvent )
+ mnEndShowEvent = Application::PostUserEvent( LINK(this, SlideshowImpl, endPresentationHdl) );
+}
+
+IMPL_LINK_NOARG(SlideshowImpl, endPresentationHdl, void*, void)
+{
+ mnEndShowEvent = nullptr;
+
+ stopSound();
+
+ if( mxPresentation.is() )
+ mxPresentation->end();
+}
+
+void SAL_CALL SlideshowImpl::pause()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbIsPaused )
+ return;
+
+ try
+ {
+ mbIsPaused = true;
+ if( mxShow.is() )
+ {
+ mxShow->pause(true);
+
+ if( mxListenerProxy.is() )
+ mxListenerProxy->paused();
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::pause()" );
+ }
+}
+
+void SAL_CALL SlideshowImpl::resume()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbIsPaused ) try
+ {
+ if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK || mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
+ {
+ mpShowWindow->RestartShow();
+ }
+ else
+ {
+ mbIsPaused = false;
+ if( mxShow.is() )
+ {
+ mxShow->pause(false);
+ update();
+
+ if( mxListenerProxy.is() )
+ mxListenerProxy->resumed();
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resume()" );
+ }
+#ifdef ENABLE_SDREMOTE
+ RemoteServer::presentationStarted( this );
+#endif
+}
+
+sal_Bool SAL_CALL SlideshowImpl::isPaused()
+{
+ SolarMutexGuard aSolarGuard;
+ return mbIsPaused;
+}
+
+void SAL_CALL SlideshowImpl::blankScreen( sal_Int32 nColor )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mpShowWindow && mpSlideController )
+ {
+ if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), Color(ColorTransparency, nColor) ) )
+ {
+ pause();
+ }
+ }
+}
+
+// XShapeEventListener
+
+void SlideshowImpl::click( const Reference< XShape >& xShape )
+{
+ SolarMutexGuard aSolarGuard;
+
+ WrappedShapeEventImplPtr pEvent = maShapeEventMap[xShape];
+ if( !pEvent )
+ return;
+
+ switch( pEvent->meClickAction )
+ {
+ case ClickAction_PREVPAGE: gotoPreviousSlide(); break;
+ case ClickAction_NEXTPAGE: gotoNextSlide(); break;
+ case ClickAction_FIRSTPAGE: gotoFirstSlide(); break;
+ case ClickAction_LASTPAGE: gotoLastSlide(); break;
+ case ClickAction_STOPPRESENTATION: endPresentation(); break;
+ case ClickAction_BOOKMARK:
+ {
+ gotoBookmark( pEvent->maStrBookmark );
+ }
+ break;
+ case ClickAction_SOUND:
+ {
+#if HAVE_FEATURE_AVMEDIA
+ try
+ {
+ mxPlayer.set(avmedia::MediaWindow::createPlayer(pEvent->maStrBookmark, ""/*TODO?*/), uno::UNO_SET_THROW );
+ mxPlayer->start();
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::click()" );
+ }
+#endif
+ }
+ break;
+
+ case ClickAction_DOCUMENT:
+ {
+ OUString aBookmark( pEvent->maStrBookmark );
+
+ sal_Int32 nPos = aBookmark.indexOf( '#' );
+ if( nPos >= 0 )
+ {
+ OUString aURL( aBookmark.copy( 0, nPos+1 ) );
+ OUString aName( aBookmark.copy( nPos+1 ) );
+ aURL += getUiNameFromPageApiNameImpl( aName );
+ aBookmark = aURL;
+ }
+
+ mpDocSh->OpenBookmark( aBookmark );
+ }
+ break;
+
+ case ClickAction_PROGRAM:
+ {
+ INetURLObject aURL(
+ ::URIHelper::SmartRel2Abs(
+ INetURLObject(mpDocSh->GetMedium()->GetBaseURL()),
+ pEvent->maStrBookmark, ::URIHelper::GetMaybeFileHdl(), true,
+ false, INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::Unambiguous ) );
+
+ if( INetProtocol::File == aURL.GetProtocol() )
+ {
+ SfxStringItem aUrl( SID_FILE_NAME, aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ SfxBoolItem aBrowsing( SID_BROWSE, true );
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ {
+ SfxUnoFrameItem aDocFrame(SID_FILLFRAME, pViewFrm->GetFrame().GetFrameInterface());
+ pViewFrm->GetDispatcher()->ExecuteList( SID_OPENDOC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aUrl, &aBrowsing }, { &aDocFrame } );
+ }
+ }
+ }
+ break;
+
+#if HAVE_FEATURE_SCRIPTING
+ case presentation::ClickAction_MACRO:
+ {
+ const OUString aMacro( pEvent->maStrBookmark );
+
+ if ( SfxApplication::IsXScriptURL( aMacro ) )
+ {
+ Any aRet;
+ Sequence< sal_Int16 > aOutArgsIndex;
+ Sequence< Any > aOutArgs;
+ Sequence< Any >* pInArgs = new Sequence< Any >(0);
+ mpDocSh->CallXScript( aMacro, *pInArgs, aRet, aOutArgsIndex, aOutArgs);
+ }
+ else
+ {
+ // aMacro has the following syntax:
+ // "Macroname.Modulname.Libname.Documentname" or
+ // "Macroname.Modulname.Libname.Applicationname"
+ sal_Int32 nIdx{ 0 };
+ const std::u16string_view aMacroName = o3tl::getToken(aMacro, 0, '.', nIdx);
+ const std::u16string_view aModulName = o3tl::getToken(aMacro, 0, '.', nIdx);
+
+ // todo: is the limitation still given that only
+ // Modulname+Macroname can be used here?
+ OUString aExecMacro = OUString::Concat(aModulName) + "." + aMacroName;
+ mpDocSh->GetBasic()->Call(aExecMacro);
+ }
+ }
+ break;
+#endif
+
+ case ClickAction_VERB:
+ {
+ // todo, better do it async?
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
+ SdrOle2Obj* pOleObject = dynamic_cast< SdrOle2Obj* >(pObj);
+ if (pOleObject && mpViewShell )
+ mpViewShell->ActivateObject(pOleObject, pEvent->mnVerb);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+sal_Int32 SlideshowImpl::getSlideNumberForBookmark( const OUString& rStrBookmark )
+{
+ bool bIsMasterPage;
+ OUString aBookmark = getUiNameFromPageApiNameImpl( rStrBookmark );
+ sal_uInt16 nPgNum = mpDoc->GetPageByName( aBookmark, bIsMasterPage );
+
+ if( nPgNum == SDRPAGE_NOTFOUND )
+ {
+ // Is the bookmark an object?
+ SdrObject* pObj = mpDoc->GetObj( aBookmark );
+
+ if( pObj )
+ {
+ nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum();
+ bIsMasterPage = pObj->getSdrPageFromSdrObject()->IsMasterPage();
+ }
+ }
+
+ if( (nPgNum == SDRPAGE_NOTFOUND) || bIsMasterPage || static_cast<SdPage*>(mpDoc->GetPage(nPgNum))->GetPageKind() != PageKind::Standard )
+ return -1;
+
+ return ( nPgNum - 1) >> 1;
+}
+
+void SlideshowImpl::hyperLinkClicked( OUString const& aHyperLink )
+{
+ OUString aBookmark( aHyperLink );
+
+ sal_Int32 nPos = aBookmark.indexOf( '#' );
+ if( nPos >= 0 )
+ {
+ OUString aURL( aBookmark.copy( 0, nPos+1 ) );
+ OUString aName( aBookmark.copy( nPos+1 ) );
+ aURL += getUiNameFromPageApiNameImpl( aName );
+ aBookmark = aURL;
+ }
+
+ mpDocSh->OpenBookmark( aBookmark );
+}
+
+void SlideshowImpl::displaySlideNumber( sal_Int32 nSlideNumber )
+{
+ if( mpSlideController )
+ {
+ if( mpSlideController->jumpToSlideNumber( nSlideNumber ) )
+ {
+ displayCurrentSlide();
+ }
+ }
+}
+
+/** nSlideIndex == -1 displays current slide again */
+void SlideshowImpl::displaySlideIndex( sal_Int32 nSlideIndex )
+{
+ if( mpSlideController )
+ {
+ if( (nSlideIndex == -1) || mpSlideController->jumpToSlideIndex( nSlideIndex ) )
+ {
+ displayCurrentSlide();
+ }
+ }
+}
+
+void SlideshowImpl::jumpToBookmark( const OUString& sBookmark )
+{
+ sal_Int32 nSlideNumber = getSlideNumberForBookmark( sBookmark );
+ if( nSlideNumber != -1 )
+ displaySlideNumber( nSlideNumber );
+}
+
+sal_Int32 SlideshowImpl::getCurrentSlideNumber() const
+{
+ return mpSlideController ? mpSlideController->getCurrentSlideNumber() : -1;
+}
+
+sal_Bool SAL_CALL SlideshowImpl::isEndless()
+{
+ SolarMutexGuard aSolarGuard;
+ return maPresSettings.mbEndless;
+}
+
+void SlideshowImpl::update()
+{
+ startUpdateTimer();
+}
+
+void SlideshowImpl::startUpdateTimer()
+{
+ SolarMutexGuard aSolarGuard;
+ maUpdateTimer.SetTimeout( 0 );
+ maUpdateTimer.Start();
+}
+
+/** this timer is called 20ms after a new slide was displayed.
+ This is used to unfreeze user input that was disabled after
+ slide change to skip input that was buffered during slide
+ transition preparation */
+IMPL_LINK_NOARG(SlideshowImpl, ReadyForNextInputHdl, Timer *, void)
+{
+ mbInputFreeze = false;
+}
+
+/** if I catch someone someday who calls this method by hand
+ and not by using the timer, I will personally punish this
+ person seriously, even if this person is me.
+*/
+IMPL_LINK_NOARG(SlideshowImpl, updateHdl, Timer *, void)
+{
+ updateSlideShow();
+}
+
+void SlideshowImpl::updateSlideShow()
+{
+ // prevent me from deletion when recursing (App::EnableYieldMode does)
+ const rtl::Reference<SlideshowImpl> xKeepAlive(this);
+
+ Reference< XSlideShow > xShow( mxShow );
+ if ( ! xShow.is())
+ return;
+
+ try
+ {
+ double fUpdate = 0.0;
+ if( !xShow->update(fUpdate) )
+ fUpdate = -1.0;
+
+ if (mxShow.is() && (fUpdate >= 0.0))
+ {
+ if (::basegfx::fTools::equalZero(fUpdate))
+ {
+ // Make sure idle tasks don't starve when we don't have to wait.
+ // Don't process any events generated after invoking the function.
+ Application::Reschedule(/*bHandleAllCurrentEvents=*/true);
+ }
+ else
+ {
+ // Avoid busy loop when the previous call to update()
+ // returns a small positive number but not 0 (which is
+ // handled above). Also, make sure that calls to update()
+ // have a minimum frequency.
+ // => Allow up to 60 frames per second. Call at least once
+ // every 4 seconds.
+ const static sal_Int32 nMaximumFrameCount (60);
+ const static double nMinimumTimeout (1.0 / nMaximumFrameCount);
+ const static double nMaximumTimeout (4.0);
+ fUpdate = std::clamp(fUpdate, nMinimumTimeout, nMaximumTimeout);
+
+ // Make sure that the maximum frame count has not been set
+ // too high (only then conversion to milliseconds and long
+ // integer may lead to zero value.)
+ OSL_ASSERT(static_cast<sal_uLong>(fUpdate * 1000.0) > 0);
+ }
+
+ // Use our high resolution timers for the asynchronous callback.
+ maUpdateTimer.SetTimeout(static_cast<sal_uLong>(fUpdate * 1000.0));
+ maUpdateTimer.Start();
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::updateSlideShow()" );
+ }
+}
+
+bool SlideshowImpl::keyInput(const KeyEvent& rKEvt)
+{
+ if( !mxShow.is() || mbInputFreeze )
+ return false;
+
+ bool bRet = true;
+
+ try
+ {
+ const int nKeyCode = rKEvt.GetKeyCode().GetCode();
+ switch( nKeyCode )
+ {
+ case awt::Key::CONTEXTMENU:
+ if( !mnContextMenuEvent )
+ {
+ if( mpShowWindow )
+ maPopupMousePos = mpShowWindow->GetPointerState().maPos;
+ mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
+ }
+ break;
+
+ // cancel show
+ case KEY_ESCAPE:
+ case KEY_SUBTRACT:
+ // in case the user cancels the presentation, switch to current slide
+ // in edit mode
+ if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
+ {
+ if( mpSlideController->getCurrentSlideNumber() != -1 )
+ mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
+ }
+ endPresentation();
+ break;
+
+ // advance show
+ case KEY_PAGEDOWN:
+ if(rKEvt.GetKeyCode().IsMod2())
+ {
+ gotoNextSlide();
+ break;
+ }
+ [[fallthrough]];
+ case KEY_SPACE:
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ gotoNextEffect();
+ break;
+
+ case KEY_RETURN:
+ {
+ if( !maCharBuffer.isEmpty() )
+ {
+ if( mpSlideController )
+ {
+ if( mpSlideController->jumpToSlideNumber( maCharBuffer.toInt32() - 1 ) )
+ displayCurrentSlide();
+ }
+ maCharBuffer.clear();
+ }
+ else
+ {
+ gotoNextEffect();
+ }
+ }
+ break;
+
+ // numeric: add to buffer
+ case KEY_0:
+ case KEY_1:
+ case KEY_2:
+ case KEY_3:
+ case KEY_4:
+ case KEY_5:
+ case KEY_6:
+ case KEY_7:
+ case KEY_8:
+ case KEY_9:
+ maCharBuffer += OUStringChar( rKEvt.GetCharCode() );
+ break;
+
+ case KEY_PAGEUP:
+ if(rKEvt.GetKeyCode().IsMod2())
+ {
+ gotoPreviousSlide();
+ break;
+ }
+ [[fallthrough]];
+ case KEY_LEFT:
+ case KEY_UP:
+ case KEY_BACKSPACE:
+ gotoPreviousEffect();
+ break;
+
+ case KEY_P:
+ setUsePen( !mbUsePen );
+ break;
+
+ // tdf#149351 Ctrl+A disables pointer as pen mode
+ case KEY_A:
+ if(rKEvt.GetKeyCode().IsMod1())
+ {
+ setUsePen( false );
+ break;
+ }
+ break;
+
+ case KEY_E:
+ setEraseAllInk( true );
+ updateSlideShow();
+ break;
+
+ case KEY_HOME:
+ gotoFirstSlide();
+ break;
+
+ case KEY_END:
+ gotoLastSlide();
+ break;
+
+ case KEY_B:
+ case KEY_W:
+ case KEY_POINT:
+ case KEY_COMMA:
+ {
+ blankScreen( ((nKeyCode == KEY_W ) || (nKeyCode == KEY_COMMA)) ? 0x00ffffff : 0x00000000 );
+ }
+ break;
+
+ default:
+ bRet = false;
+ break;
+ }
+ }
+ catch( Exception& )
+ {
+ bRet = false;
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::keyInput()" );
+ }
+
+ return bRet;
+}
+
+IMPL_LINK( SlideshowImpl, EventListenerHdl, VclSimpleEvent&, rSimpleEvent, void )
+{
+ if( !mxShow.is() || mbInputFreeze )
+ return;
+
+ if( !((rSimpleEvent.GetId() == VclEventId::WindowCommand) && static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData()) )
+ return;
+
+ const CommandEvent& rEvent = *static_cast<const CommandEvent*>(static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData());
+
+ if( rEvent.GetCommand() != CommandEventId::Media )
+ return;
+
+ CommandMediaData* pMediaData = rEvent.GetMediaData();
+ pMediaData->SetPassThroughToOS(false);
+ switch (pMediaData->GetMediaId())
+ {
+#if defined( MACOSX )
+ case MediaCommand::Menu:
+ if( !mnContextMenuEvent )
+ {
+ if( mpShowWindow )
+ maPopupMousePos = mpShowWindow->GetPointerState().maPos;
+ mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
+ }
+ break;
+ case MediaCommand::VolumeDown:
+ gotoPreviousSlide();
+ break;
+ case MediaCommand::VolumeUp:
+ gotoNextEffect();
+ break;
+#endif
+ case MediaCommand::NextTrack:
+ gotoNextEffect();
+ break;
+ case MediaCommand::Pause:
+ if( !mbIsPaused )
+ blankScreen(0);
+ break;
+ case MediaCommand::Play:
+ if( mbIsPaused )
+ resume();
+ break;
+
+ case MediaCommand::PlayPause:
+ if( mbIsPaused )
+ resume();
+ else
+ blankScreen(0);
+ break;
+ case MediaCommand::PreviousTrack:
+ gotoPreviousSlide();
+ break;
+ case MediaCommand::NextTrackHold:
+ gotoLastSlide();
+ break;
+
+ case MediaCommand::Rewind:
+ gotoFirstSlide();
+ break;
+ case MediaCommand::Stop:
+ // in case the user cancels the presentation, switch to current slide
+ // in edit mode
+ if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
+ {
+ if( mpSlideController->getCurrentSlideNumber() != -1 )
+ mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
+ }
+ endPresentation();
+ break;
+ default:
+ pMediaData->SetPassThroughToOS(true);
+ break;
+ }
+}
+
+void SlideshowImpl::mouseButtonUp(const MouseEvent& rMEvt)
+{
+ if( rMEvt.IsRight() && !mnContextMenuEvent )
+ {
+ maPopupMousePos = rMEvt.GetPosPixel();
+ mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
+ }
+}
+
+IMPL_LINK_NOARG(SlideshowImpl, ContextMenuHdl, void*, void)
+{
+ mnContextMenuEvent = nullptr;
+
+ if (mpSlideController == nullptr)
+ return;
+
+ mbWasPaused = mbIsPaused;
+ if( !mbWasPaused )
+ pause();
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/simpress/ui/slidecontextmenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+ OUString sNextImage(BMP_MENU_NEXT), sPrevImage(BMP_MENU_PREV);
+ xMenu->insert(0, "next", SdResId(RID_SVXSTR_MENU_NEXT), &sNextImage, nullptr, nullptr, TRISTATE_INDET);
+ xMenu->insert(1, "prev", SdResId(RID_SVXSTR_MENU_PREV), &sPrevImage, nullptr, nullptr, TRISTATE_INDET);
+
+ // Adding button to display if in Pen mode
+ xMenu->set_active("pen", mbUsePen);
+
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ xMenu->set_visible("next", mpSlideController->getNextSlideIndex() != -1);
+ xMenu->set_visible("prev", (mpSlideController->getPreviousSlideIndex() != -1 ) || (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK));
+ xMenu->set_visible("edit", mpViewShell->GetDoc()->IsStartWithPresentation());
+
+ std::unique_ptr<weld::Menu> xPageMenu(xBuilder->weld_menu("gotomenu"));
+ OUString sFirstImage(BMP_MENU_FIRST), sLastImage(BMP_MENU_LAST);
+ xPageMenu->insert(0, "first", SdResId(RID_SVXSTR_MENU_FIRST), &sFirstImage, nullptr, nullptr, TRISTATE_INDET);
+ xPageMenu->insert(1, "last", SdResId(RID_SVXSTR_MENU_LAST), &sLastImage, nullptr, nullptr, TRISTATE_INDET);
+
+ // populate slide goto list
+ const sal_Int32 nPageNumberCount = mpSlideController->getSlideNumberCount();
+ if( nPageNumberCount <= 1 )
+ {
+ xMenu->set_visible("goto", false);
+ }
+ else
+ {
+ sal_Int32 nCurrentSlideNumber = mpSlideController->getCurrentSlideNumber();
+ if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ nCurrentSlideNumber = -1;
+
+ xPageMenu->set_visible("first", mpSlideController->getSlideNumber(0) != nCurrentSlideNumber);
+ xPageMenu->set_visible("last", mpSlideController->getSlideNumber(mpSlideController->getSlideIndexCount() - 1) != nCurrentSlideNumber);
+
+ sal_Int32 nPageNumber;
+
+ for( nPageNumber = 0; nPageNumber < nPageNumberCount; nPageNumber++ )
+ {
+ if( mpSlideController->isVisibleSlideNumber( nPageNumber ) )
+ {
+ SdPage* pPage = mpDoc->GetSdPage(static_cast<sal_uInt16>(nPageNumber), PageKind::Standard);
+ if (pPage)
+ {
+ OUString sId(OUString::number(CM_SLIDES + nPageNumber));
+ xPageMenu->append_check(sId, pPage->GetName());
+ if (nPageNumber == nCurrentSlideNumber)
+ xPageMenu->set_active(sId.toUtf8(), true);
+ }
+ }
+ }
+ }
+
+ std::unique_ptr<weld::Menu> xBlankMenu(xBuilder->weld_menu("screenmenu"));
+
+ if (mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK)
+ {
+ xBlankMenu->set_active((mpShowWindow->GetBlankColor() == COL_WHITE) ? "white" : "black", true);
+ }
+
+ std::unique_ptr<weld::Menu> xWidthMenu(xBuilder->weld_menu("widthmenu"));
+
+ // populate color width list
+ sal_Int32 nIterator;
+ double nWidth;
+
+ nWidth = 4.0;
+ for( nIterator = 1; nIterator < 6; nIterator++)
+ {
+ switch(nIterator)
+ {
+ case 1:
+ nWidth = 4.0;
+ break;
+ case 2:
+ nWidth = 100.0;
+ break;
+ case 3:
+ nWidth = 150.0;
+ break;
+ case 4:
+ nWidth = 200.0;
+ break;
+ case 5:
+ nWidth = 400.0;
+ break;
+ default:
+ break;
+ }
+
+ if (nWidth == mdUserPaintStrokeWidth)
+ xWidthMenu->set_active(OString::number(nWidth), true);
+ }
+
+ ::tools::Rectangle aRect(maPopupMousePos, Size(1,1));
+ weld::Window* pParent = weld::GetPopupParent(*mpShowWindow, aRect);
+ ContextMenuSelectHdl(xMenu->popup_at_rect(pParent, aRect));
+
+ if( mxView.is() )
+ mxView->ignoreNextMouseReleased();
+
+ if( !mbWasPaused )
+ resume();
+}
+
+void SlideshowImpl::ContextMenuSelectHdl(std::string_view rMenuId)
+{
+ if (rMenuId == "prev")
+ {
+ gotoPreviousSlide();
+ mbWasPaused = false;
+ }
+ else if(rMenuId == "next")
+ {
+ gotoNextSlide();
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "first")
+ {
+ gotoFirstSlide();
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "last")
+ {
+ gotoLastSlide();
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "black" || rMenuId == "white")
+ {
+ const Color aBlankColor(rMenuId == "white" ? COL_WHITE : COL_BLACK);
+ if( mbWasPaused )
+ {
+ if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK )
+ {
+ if( mpShowWindow->GetBlankColor() == aBlankColor )
+ {
+ mbWasPaused = false;
+ mpShowWindow->RestartShow();
+ return;
+ }
+ }
+ mpShowWindow->RestartShow();
+ }
+ if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), aBlankColor ) )
+ {
+ pause();
+ mbWasPaused = true;
+ }
+ }
+ else if (rMenuId == "color")
+ {
+ //Open a color picker based on SvColorDialog
+ ::Color aColor( ColorTransparency, mnUserPaintColor );
+ SvColorDialog aColorDlg;
+ aColorDlg.SetColor( aColor );
+
+ if (aColorDlg.Execute(mpShowWindow->GetFrameWeld()))
+ {
+ aColor = aColorDlg.GetColor();
+ setPenColor(sal_Int32(aColor));
+ }
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "4")
+ {
+ setPenWidth(4.0);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "100")
+ {
+ setPenWidth(100.0);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "150")
+ {
+ setPenWidth(150.0);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "200")
+ {
+ setPenWidth(200.0);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "400")
+ {
+ setPenWidth(400.0);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "erase")
+ {
+ setEraseAllInk(true);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "pen")
+ {
+ setUsePen(!mbUsePen);
+ mbWasPaused = false;
+ }
+ else if (rMenuId == "edit")
+ {
+ // When in autoplay mode (pps/ppsx), offer editing of the presentation
+ // Turn autostart off, else Impress will close when exiting the Presentation
+ mpViewShell->GetDoc()->SetExitAfterPresenting(false);
+ if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
+ {
+ if( mpSlideController->getCurrentSlideNumber() != -1 )
+ {
+ mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
+ }
+ }
+ endPresentation();
+ }
+ else if (rMenuId == "end")
+ {
+ // in case the user cancels the presentation, switch to current slide
+ // in edit mode
+ if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
+ {
+ if( mpSlideController->getCurrentSlideNumber() != -1 )
+ {
+ mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
+ }
+ }
+ endPresentation();
+ }
+ else if (!rMenuId.empty())
+ {
+ sal_Int32 nPageNumber = o3tl::toInt32(rMenuId) - CM_SLIDES;
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ {
+ mpShowWindow->RestartShow( nPageNumber );
+ }
+ else if( nPageNumber != mpSlideController->getCurrentSlideNumber() )
+ {
+ displaySlideNumber( nPageNumber );
+ }
+ mbWasPaused = false;
+ }
+}
+
+Reference< XSlideShow > SlideshowImpl::createSlideShow()
+{
+ Reference< XSlideShow > xShow;
+
+ try
+ {
+ Reference< uno::XComponentContext > xContext =
+ ::comphelper::getProcessComponentContext();
+
+ xShow.set( presentation::SlideShow::create(xContext), UNO_SET_THROW );
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::createSlideShow()" );
+ }
+
+ return xShow;
+}
+
+void SlideshowImpl::createSlideList( bool bAll, std::u16string_view rPresSlide )
+{
+ const sal_uInt16 nSlideCount = mpDoc->GetSdPageCount( PageKind::Standard );
+
+ if( !nSlideCount )
+ return;
+
+ SdCustomShow* pCustomShow;
+
+ if( mpDoc->GetCustomShowList() && maPresSettings.mbCustomShow )
+ pCustomShow = mpDoc->GetCustomShowList()->GetCurObject();
+ else
+ pCustomShow = nullptr;
+
+ // create animation slide controller
+ AnimationSlideController::Mode eMode =
+ ( pCustomShow && !pCustomShow->PagesVector().empty() ) ? AnimationSlideController::CUSTOM :
+ (bAll ? AnimationSlideController::ALL : AnimationSlideController::FROM);
+
+ Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
+ mpSlideController = std::make_shared<AnimationSlideController>( xSlides, eMode );
+
+ if( eMode != AnimationSlideController::CUSTOM )
+ {
+ sal_Int32 nFirstVisibleSlide = 0;
+
+ // normal presentation
+ if( !rPresSlide.empty() )
+ {
+ sal_Int32 nSlide;
+ bool bTakeNextAvailable = false;
+
+ for( nSlide = 0, nFirstVisibleSlide = -1;
+ ( nSlide < nSlideCount ) && ( -1 == nFirstVisibleSlide ); nSlide++ )
+ {
+ SdPage* pTestSlide = mpDoc->GetSdPage( static_cast<sal_uInt16>(nSlide), PageKind::Standard );
+
+ if( pTestSlide->GetName() == rPresSlide )
+ {
+ if( pTestSlide->IsExcluded() )
+ bTakeNextAvailable = true;
+ else
+ nFirstVisibleSlide = nSlide;
+ }
+ else if( bTakeNextAvailable && !pTestSlide->IsExcluded() )
+ nFirstVisibleSlide = nSlide;
+ }
+
+ if( -1 == nFirstVisibleSlide )
+ nFirstVisibleSlide = 0;
+ }
+
+ for( sal_Int32 i = 0; i < nSlideCount; i++ )
+ {
+ bool bVisible = ! mpDoc->GetSdPage( static_cast<sal_uInt16>(i), PageKind::Standard )->IsExcluded();
+ if( bVisible || (eMode == AnimationSlideController::ALL) )
+ mpSlideController->insertSlideNumber( i, bVisible );
+ }
+
+ mpSlideController->setStartSlideNumber( nFirstVisibleSlide );
+ }
+ else
+ {
+ if( meAnimationMode != ANIMATIONMODE_SHOW && !rPresSlide.empty() )
+ {
+ sal_Int32 nSlide;
+ for( nSlide = 0; nSlide < nSlideCount; nSlide++ )
+ if( rPresSlide == mpDoc->GetSdPage( static_cast<sal_uInt16>(nSlide), PageKind::Standard )->GetName() )
+ break;
+
+ if( nSlide < nSlideCount )
+ mpSlideController->insertSlideNumber( static_cast<sal_uInt16>(nSlide) );
+ }
+
+ for( const auto& rpPage : pCustomShow->PagesVector() )
+ {
+ const sal_uInt16 nSdSlide = ( rpPage->GetPageNum() - 1 ) / 2;
+
+ if( ! mpDoc->GetSdPage( nSdSlide, PageKind::Standard )->IsExcluded())
+ mpSlideController->insertSlideNumber( nSdSlide );
+ }
+ }
+}
+
+typedef sal_uInt16 (*FncGetChildWindowId)();
+
+const FncGetChildWindowId aShowChildren[] =
+{
+ &AnimationChildWindow::GetChildWindowId,
+ &Svx3DChildWindow::GetChildWindowId,
+ &SvxFontWorkChildWindow::GetChildWindowId,
+ &SvxColorChildWindow::GetChildWindowId,
+ &SvxSearchDialogWrapper::GetChildWindowId,
+ &SvxBmpMaskChildWindow::GetChildWindowId,
+ &SvxIMapDlgChildWindow::GetChildWindowId,
+ &SvxHlinkDlgWrapper::GetChildWindowId,
+ &SfxInfoBarContainerChild::GetChildWindowId
+};
+
+void SlideshowImpl::hideChildWindows()
+{
+ mnChildMask = 0;
+
+ if( ANIMATIONMODE_SHOW != meAnimationMode )
+ return;
+
+ SfxViewFrame* pViewFrame = getViewFrame();
+
+ if( !pViewFrame )
+ return;
+
+ for( sal_uLong i = 0; i < SAL_N_ELEMENTS( aShowChildren ); i++ )
+ {
+ const sal_uInt16 nId = ( *aShowChildren[ i ] )();
+
+ if( pViewFrame->GetChildWindow( nId ) )
+ {
+ pViewFrame->SetChildWindow( nId, false );
+ mnChildMask |= ::tools::ULong(1) << i;
+ }
+ }
+}
+
+void SlideshowImpl::showChildWindows()
+{
+ if( ANIMATIONMODE_SHOW == meAnimationMode )
+ {
+ SfxViewFrame* pViewFrame = getViewFrame();
+ if( pViewFrame )
+ {
+ for( sal_uLong i = 0; i < SAL_N_ELEMENTS(aShowChildren); i++ )
+ {
+ if( mnChildMask & ( ::tools::ULong(1) << i ) )
+ pViewFrame->SetChildWindow( ( *aShowChildren[ i ] )(), true );
+ }
+ }
+ }
+}
+
+SfxViewFrame* SlideshowImpl::getViewFrame() const
+{
+ return mpViewShell ? mpViewShell->GetViewFrame() : nullptr;
+}
+
+SfxDispatcher* SlideshowImpl::getDispatcher() const
+{
+ return (mpViewShell && mpViewShell->GetViewFrame()) ? mpViewShell->GetViewFrame()->GetDispatcher() : nullptr;
+}
+
+SfxBindings* SlideshowImpl::getBindings() const
+{
+ return (mpViewShell && mpViewShell->GetViewFrame()) ? &mpViewShell->GetViewFrame()->GetBindings() : nullptr;
+}
+
+void SlideshowImpl::resize( const Size& rSize )
+{
+ maPresSize = rSize;
+
+ if(mpShowWindow)
+ {
+ mpShowWindow->SetSizePixel( maPresSize );
+ mpShowWindow->Show();
+ }
+
+ if( mxView.is() ) try
+ {
+ awt::WindowEvent aEvt;
+ mxView->windowResized(aEvt);
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resize()" );
+ }
+}
+
+void SlideshowImpl::setActiveXToolbarsVisible( bool bVisible )
+{
+ // in case of ActiveX control the toolbars should not be visible if slide show runs in window mode
+ // actually it runs always in window mode in case of ActiveX control
+ if ( !(!maPresSettings.mbFullScreen && mpDocSh && mpDocSh->GetMedium()) )
+ return;
+
+ const SfxBoolItem* pItem = SfxItemSet::GetItem<SfxBoolItem>(mpDocSh->GetMedium()->GetItemSet(), SID_VIEWONLY, false);
+ if ( !(pItem && pItem->GetValue()) )
+ return;
+
+ // this is a plugin/activex mode, no toolbars should be visible during slide show
+ // after the end of slide show they should be visible again
+ SfxViewFrame* pViewFrame = getViewFrame();
+ if( !pViewFrame )
+ return;
+
+ try
+ {
+ Reference< frame::XLayoutManager > xLayoutManager;
+ Reference< beans::XPropertySet > xFrameProps( pViewFrame->GetFrame().GetFrameInterface(), UNO_QUERY_THROW );
+ if ( ( xFrameProps->getPropertyValue( "LayoutManager" )
+ >>= xLayoutManager )
+ && xLayoutManager.is() )
+ {
+ xLayoutManager->setVisible( bVisible );
+ }
+ }
+ catch( uno::Exception& )
+ {}
+}
+
+void SAL_CALL SlideshowImpl::activate()
+{
+ SolarMutexGuard aSolarGuard;
+
+ maDeactivateTimer.Stop();
+
+ if( mbActive || !mxShow.is() )
+ return;
+
+ mbActive = true;
+
+ if( ANIMATIONMODE_SHOW == meAnimationMode )
+ {
+ if( mbAutoSaveWasOn )
+ setAutoSaveState( false );
+
+ if( mpShowWindow )
+ {
+ SfxViewFrame* pViewFrame = getViewFrame();
+ SfxDispatcher* pDispatcher = pViewFrame ? pViewFrame->GetDispatcher() : nullptr;
+
+ hideChildWindows();
+
+ if( pDispatcher )
+ {
+ // filter all forbidden slots
+ pDispatcher->SetSlotFilter( SfxSlotFilterState::ENABLED, pAllowed );
+ }
+
+ if( getBindings() )
+ getBindings()->InvalidateAll(true);
+
+ mpShowWindow->GrabFocus();
+ }
+ }
+
+ resume();
+}
+
+void SAL_CALL SlideshowImpl::deactivate()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbActive && mxShow.is() )
+ {
+ maDeactivateTimer.Start();
+ }
+}
+
+IMPL_LINK_NOARG(SlideshowImpl, deactivateHdl, Timer *, void)
+{
+ if( !(mbActive && mxShow.is()) )
+ return;
+
+ mbActive = false;
+
+ pause();
+
+ if( ANIMATIONMODE_SHOW == meAnimationMode )
+ {
+ if( mbAutoSaveWasOn )
+ setAutoSaveState( true );
+
+ if( mpShowWindow )
+ {
+ showChildWindows();
+ }
+ }
+}
+
+sal_Bool SAL_CALL SlideshowImpl::isActive()
+{
+ SolarMutexGuard aSolarGuard;
+ return mbActive;
+}
+
+void SlideshowImpl::setAutoSaveState( bool bOn)
+{
+ try
+ {
+ uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+
+ uno::Reference< util::XURLTransformer > xParser(util::URLTransformer::create(xContext));
+ util::URL aURL;
+ aURL.Complete = "vnd.sun.star.autorecovery:/setAutoSaveState";
+ xParser->parseStrict(aURL);
+
+ Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue("AutoSaveState", bOn) };
+
+ uno::Reference< frame::XDispatch > xAutoSave = frame::theAutoRecovery::get(xContext);
+ xAutoSave->dispatch(aURL, aArgs);
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setAutoSaveState()");
+ }
+}
+
+Reference< XDrawPage > SAL_CALL SlideshowImpl::getCurrentSlide()
+{
+ SolarMutexGuard aSolarGuard;
+
+ Reference< XDrawPage > xSlide;
+ if( mxShow.is() && mpSlideController )
+ {
+ sal_Int32 nSlide = getCurrentSlideNumber();
+ if( (nSlide >= 0) && (nSlide < mpSlideController->getSlideNumberCount() ) )
+ xSlide = mpSlideController->getSlideByNumber( nSlide );
+ }
+
+ return xSlide;
+}
+
+sal_Int32 SAL_CALL SlideshowImpl::getNextSlideIndex()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mxShow.is() )
+ {
+ return mpSlideController->getNextSlideIndex();
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+sal_Int32 SAL_CALL SlideshowImpl::getCurrentSlideIndex()
+{
+ return mpSlideController ? mpSlideController->getCurrentSlideIndex() : -1;
+}
+
+// css::presentation::XSlideShowController:
+
+::sal_Int32 SAL_CALL SlideshowImpl::getSlideCount()
+{
+ return mpSlideController ? mpSlideController->getSlideIndexCount() : 0;
+}
+
+Reference< XDrawPage > SAL_CALL SlideshowImpl::getSlideByIndex(::sal_Int32 Index)
+{
+ if ((mpSlideController == nullptr) || (Index < 0)
+ || (Index >= mpSlideController->getSlideIndexCount()))
+ throw IndexOutOfBoundsException();
+
+ return mpSlideController->getSlideByNumber( mpSlideController->getSlideNumber( Index ) );
+}
+
+sal_Bool SAL_CALL SlideshowImpl::getAlwaysOnTop()
+{
+ SolarMutexGuard aSolarGuard;
+ return maPresSettings.mbAlwaysOnTop;
+}
+
+void SAL_CALL SlideshowImpl::setAlwaysOnTop( sal_Bool bAlways )
+{
+ SolarMutexGuard aSolarGuard;
+ if( maPresSettings.mbAlwaysOnTop != bool(bAlways) )
+ {
+ maPresSettings.mbAlwaysOnTop = bAlways;
+ // todo, can this be changed while running?
+ }
+}
+
+sal_Bool SAL_CALL SlideshowImpl::isFullScreen()
+{
+ SolarMutexGuard aSolarGuard;
+ return maPresSettings.mbFullScreen;
+}
+
+sal_Bool SAL_CALL SlideshowImpl::getMouseVisible()
+{
+ SolarMutexGuard aSolarGuard;
+ return maPresSettings.mbMouseVisible;
+}
+
+void SAL_CALL SlideshowImpl::setMouseVisible( sal_Bool bVisible )
+{
+ SolarMutexGuard aSolarGuard;
+ if( maPresSettings.mbMouseVisible != bool(bVisible) )
+ {
+ maPresSettings.mbMouseVisible = bVisible;
+ if( mpShowWindow )
+ mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible );
+ }
+}
+
+sal_Bool SAL_CALL SlideshowImpl::getUsePen()
+{
+ SolarMutexGuard aSolarGuard;
+ return mbUsePen;
+}
+
+void SAL_CALL SlideshowImpl::setUsePen( sal_Bool bMouseAsPen )
+{
+ SolarMutexGuard aSolarGuard;
+ mbUsePen = bMouseAsPen;
+ if( !mxShow.is() )
+ return;
+
+ try
+ {
+ // For Pencolor;
+ Any aValue;
+ if( mbUsePen )
+ aValue <<= mnUserPaintColor;
+ beans::PropertyValue aPenProp;
+ aPenProp.Name = "UserPaintColor";
+ aPenProp.Value = aValue;
+ mxShow->setProperty( aPenProp );
+
+ //for StrokeWidth :
+ if( mbUsePen )
+ {
+ beans::PropertyValue aPenPropWidth;
+ aPenPropWidth.Name = "UserPaintStrokeWidth";
+ aPenPropWidth.Value <<= mdUserPaintStrokeWidth;
+ mxShow->setProperty( aPenPropWidth );
+
+ // for Pen Mode
+ beans::PropertyValue aPenPropSwitchPenMode;
+ aPenPropSwitchPenMode.Name = "SwitchPenMode";
+ aPenPropSwitchPenMode.Value <<= true;
+ mxShow->setProperty( aPenPropSwitchPenMode );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setUsePen()" );
+ }
+}
+
+double SAL_CALL SlideshowImpl::getPenWidth()
+{
+ SolarMutexGuard aSolarGuard;
+ return mdUserPaintStrokeWidth;
+}
+
+void SAL_CALL SlideshowImpl::setPenWidth( double dStrokeWidth )
+{
+ SolarMutexGuard aSolarGuard;
+ mdUserPaintStrokeWidth = dStrokeWidth;
+ setUsePen( true ); // enable pen mode, update color and width
+}
+
+sal_Int32 SAL_CALL SlideshowImpl::getPenColor()
+{
+ SolarMutexGuard aSolarGuard;
+ return mnUserPaintColor;
+}
+
+void SAL_CALL SlideshowImpl::setPenColor( sal_Int32 nColor )
+{
+ SolarMutexGuard aSolarGuard;
+ mnUserPaintColor = nColor;
+ setUsePen( true ); // enable pen mode, update color
+}
+
+void SAL_CALL SlideshowImpl::setEraseAllInk(sal_Bool bEraseAllInk)
+{
+ if( !bEraseAllInk )
+ return;
+
+ SolarMutexGuard aSolarGuard;
+ if( !mxShow.is() )
+ return;
+
+ try
+ {
+ beans::PropertyValue aPenPropEraseAllInk;
+ aPenPropEraseAllInk.Name = "EraseAllInk";
+ aPenPropEraseAllInk.Value <<= bEraseAllInk;
+ mxShow->setProperty( aPenPropEraseAllInk );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd.slideshow", "sd::SlideshowImpl::setEraseAllInk()" );
+ }
+}
+
+// XSlideShowController Methods
+sal_Bool SAL_CALL SlideshowImpl::isRunning( )
+{
+ SolarMutexGuard aSolarGuard;
+ return mxShow.is();
+}
+
+void SAL_CALL SlideshowImpl::gotoNextEffect( )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !(mxShow.is() && mpSlideController && mpShowWindow) )
+ return;
+
+ if( mbIsPaused )
+ resume();
+
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ if( eMode == SHOWWINDOWMODE_END )
+ {
+ endPresentation();
+ }
+ else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ {
+ mpShowWindow->RestartShow();
+ }
+ else
+ {
+ mxShow->nextEffect();
+ update();
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoPreviousEffect( )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !(mxShow.is() && mpSlideController && mpShowWindow) )
+ return;
+
+ if( mbIsPaused )
+ resume();
+
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ {
+ mpShowWindow->RestartShow();
+ }
+ else
+ {
+ mxShow->previousEffect();
+ update();
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoFirstSlide( )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !(mpShowWindow && mpSlideController) )
+ return;
+
+ if( mbIsPaused )
+ resume();
+
+ if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
+ {
+ if( mpSlideController->getSlideIndexCount() )
+ mpShowWindow->RestartShow( 0);
+ }
+ else
+ {
+ displaySlideIndex( 0 );
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoNextSlide( )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbIsPaused )
+ resume();
+
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ {
+ mpShowWindow->RestartShow();
+ }
+ else
+ {
+ // if this is a show, ignore user inputs and
+ // start 20ms timer to reenable inputs to filter
+ // buffered inputs during slide transition
+ if( meAnimationMode == ANIMATIONMODE_SHOW )
+ {
+ mbInputFreeze = true;
+ maInputFreezeTimer.Start();
+ }
+
+ if( mpSlideController )
+ {
+ if( mpSlideController->nextSlide() )
+ {
+ displayCurrentSlide();
+ }
+ else
+ {
+ stopSound();
+
+ if( meAnimationMode == ANIMATIONMODE_PREVIEW )
+ {
+ endPresentation();
+ }
+ else if( maPresSettings.mbEndless )
+ {
+ if( maPresSettings.mnPauseTimeout )
+ {
+ if( mpShowWindow )
+ {
+ if ( maPresSettings.mbShowPauseLogo )
+ {
+ Graphic aGraphic(SfxApplication::GetApplicationLogo(360));
+ mpShowWindow->SetPauseMode( maPresSettings.mnPauseTimeout, &aGraphic );
+ }
+ else
+ mpShowWindow->SetPauseMode( maPresSettings.mnPauseTimeout );
+ }
+ }
+ else
+ {
+ displaySlideIndex( 0 );
+ }
+ }
+ else
+ {
+ if( mpShowWindow )
+ {
+ mpShowWindow->SetEndMode();
+ if( !mpViewShell->GetDoc()->IsStartWithPresentation() )
+ pause();
+ }
+ }
+ }
+ }
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoPreviousSlide( )
+{
+ gotoPreviousSlide(false);
+}
+
+void SlideshowImpl::gotoPreviousSlide (const bool bSkipAllMainSequenceEffects)
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !(mxShow.is() && mpSlideController) )
+ return;
+
+ try
+ {
+ if( mbIsPaused )
+ resume();
+
+ const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
+ if( eMode == SHOWWINDOWMODE_END )
+ {
+ mpShowWindow->RestartShow( mpSlideController->getCurrentSlideIndex() );
+ }
+ else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
+ {
+ mpShowWindow->RestartShow();
+ }
+ else
+ {
+ if( mpSlideController->previousSlide())
+ displayCurrentSlide(bSkipAllMainSequenceEffects);
+ else if (bSkipAllMainSequenceEffects)
+ {
+ // We could not go to the previous slide (probably because
+ // the current slide is already the first one). We still
+ // have to call displayCurrentSlide because the calling
+ // slideshow can not determine whether there is a previous
+ // slide or not and has already prepared for a slide change.
+ // This slide change has to be completed now, even when
+ // changing to the same slide.
+ // Note that in this special case we do NOT pass
+ // bSkipAllMainSequenceEffects because we display the same
+ // slide as before and do not want to show all its effects.
+ displayCurrentSlide();
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::gotoPreviousSlide()" );
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoLastSlide()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !mpSlideController )
+ return;
+
+ if( mbIsPaused )
+ resume();
+
+ const sal_Int32 nLastSlideIndex = mpSlideController->getSlideIndexCount() - 1;
+ if( nLastSlideIndex >= 0 )
+ {
+ if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
+ {
+ mpShowWindow->RestartShow( nLastSlideIndex );
+ }
+ else
+ {
+ displaySlideIndex( nLastSlideIndex );
+ }
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoBookmark( const OUString& rBookmark )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbIsPaused )
+ resume();
+
+ sal_Int32 nSlideNumber = getSlideNumberForBookmark( rBookmark );
+ if( nSlideNumber != -1 )
+ displaySlideNumber( nSlideNumber );
+}
+
+void SAL_CALL SlideshowImpl::gotoSlide( const Reference< XDrawPage >& xSlide )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( !(mpSlideController && xSlide.is()) )
+ return;
+
+ if( mbIsPaused )
+ resume();
+
+ const sal_Int32 nSlideCount = mpSlideController->getSlideNumberCount();
+ for( sal_Int32 nSlide = 0; nSlide < nSlideCount; nSlide++ )
+ {
+ if( mpSlideController->getSlideByNumber( nSlide ) == xSlide )
+ {
+ displaySlideNumber( nSlide );
+ }
+ }
+}
+
+void SAL_CALL SlideshowImpl::gotoSlideIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( mbIsPaused )
+ resume();
+
+ displaySlideIndex( nIndex );
+}
+
+void SAL_CALL SlideshowImpl::stopSound( )
+{
+ SolarMutexGuard aSolarGuard;
+
+ try
+ {
+ if( mxPlayer.is() )
+ {
+ mxPlayer->stop();
+ mxPlayer.clear();
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stopSound()" );
+ }
+}
+
+// XIndexAccess
+
+::sal_Int32 SAL_CALL SlideshowImpl::getCount( )
+{
+ return getSlideCount();
+}
+
+css::uno::Any SAL_CALL SlideshowImpl::getByIndex( ::sal_Int32 Index )
+{
+ return Any( getSlideByIndex( Index ) );
+}
+
+css::uno::Type SAL_CALL SlideshowImpl::getElementType( )
+{
+ return cppu::UnoType<XDrawPage>::get();
+}
+
+sal_Bool SAL_CALL SlideshowImpl::hasElements( )
+{
+ return getSlideCount() != 0;
+}
+
+Reference< XSlideShow > SAL_CALL SlideshowImpl::getSlideShow()
+{
+ return mxShow;
+}
+
+PresentationSettingsEx::PresentationSettingsEx( const PresentationSettingsEx& r )
+: PresentationSettings( r )
+, mbRehearseTimings(r.mbRehearseTimings)
+, mbPreview(r.mbPreview)
+, mpParentWindow( nullptr )
+{
+}
+
+PresentationSettingsEx::PresentationSettingsEx( PresentationSettings const & r )
+: PresentationSettings( r )
+, mbRehearseTimings(false)
+, mbPreview(false)
+, mpParentWindow(nullptr)
+{
+}
+
+void PresentationSettingsEx::SetArguments( const Sequence< PropertyValue >& rArguments )
+{
+ for( const PropertyValue& rValue : rArguments )
+ {
+ SetPropertyValue( rValue.Name, rValue.Value );
+ }
+}
+
+void PresentationSettingsEx::SetPropertyValue( std::u16string_view rProperty, const Any& rValue )
+{
+ if ( rProperty == u"RehearseTimings" )
+ {
+ if( rValue >>= mbRehearseTimings )
+ return;
+ }
+ else if ( rProperty == u"Preview" )
+ {
+ if( rValue >>= mbPreview )
+ return;
+ }
+ else if ( rProperty == u"AnimationNode" )
+ {
+ if( rValue >>= mxAnimationNode )
+ return;
+ }
+ else if ( rProperty == u"ParentWindow" )
+ {
+ Reference< XWindow > xWindow;
+ if( rValue >>= xWindow )
+ {
+ mpParentWindow = xWindow.is() ? VCLUnoHelper::GetWindow( xWindow )
+ : nullptr;
+ return;
+ }
+ }
+ else if ( rProperty == u"AllowAnimations" )
+ {
+ if( rValue >>= mbAnimationAllowed )
+ return;
+ }
+ else if ( rProperty == u"FirstPage" )
+ {
+ OUString aPresPage;
+ if( rValue >>= aPresPage )
+ {
+ maPresPage = getUiNameFromPageApiNameImpl(aPresPage);
+ mbCustomShow = false;
+ mbAll = false;
+ return;
+ }
+ else
+ {
+ if( rValue >>= mxStartPage )
+ return;
+ }
+ }
+ else if ( rProperty == u"IsAlwaysOnTop" )
+ {
+ if( rValue >>= mbAlwaysOnTop )
+ return;
+ }
+ else if ( rProperty == u"IsAutomatic" )
+ {
+ if( rValue >>= mbManual )
+ return;
+ }
+ else if ( rProperty == u"IsEndless" )
+ {
+ if( rValue >>= mbEndless )
+ return;
+ }
+ else if ( rProperty == u"IsFullScreen" )
+ {
+ if( rValue >>= mbFullScreen )
+ return;
+ }
+ else if ( rProperty == u"IsMouseVisible" )
+ {
+ if( rValue >>= mbMouseVisible )
+ return;
+ }
+ else if ( rProperty == u"Pause" )
+ {
+ sal_Int32 nPause = -1;
+ if( (rValue >>= nPause) && (nPause >= 0) )
+ {
+ mnPauseTimeout = nPause;
+ return;
+ }
+ }
+ else if ( rProperty == u"UsePen" )
+ {
+ if( rValue >>= mbMouseAsPen )
+ return;
+ }
+ throw IllegalArgumentException();
+}
+
+// XAnimationListener
+
+SlideShowListenerProxy::SlideShowListenerProxy( const rtl::Reference< SlideshowImpl >& xController, const css::uno::Reference< css::presentation::XSlideShow >& xSlideShow )
+: maListeners( m_aMutex )
+, mxController( xController )
+, mxSlideShow( xSlideShow )
+{
+}
+
+SlideShowListenerProxy::~SlideShowListenerProxy()
+{
+}
+
+void SlideShowListenerProxy::addAsSlideShowListener()
+{
+ if( mxSlideShow.is() )
+ {
+ Reference< XSlideShowListener > xSlideShowListener( this );
+ mxSlideShow->addSlideShowListener( xSlideShowListener );
+ }
+}
+
+void SlideShowListenerProxy::removeAsSlideShowListener()
+{
+ if( mxSlideShow.is() )
+ {
+ Reference< XSlideShowListener > xSlideShowListener( this );
+ mxSlideShow->removeSlideShowListener( xSlideShowListener );
+ }
+}
+
+void SlideShowListenerProxy::addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape )
+{
+ if( mxSlideShow.is() )
+ {
+ Reference< XShapeEventListener > xListener( this );
+ mxSlideShow->addShapeEventListener( xListener, xShape );
+ }
+}
+
+void SlideShowListenerProxy::removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape )
+{
+ if( mxSlideShow.is() )
+ {
+ Reference< XShapeEventListener > xListener( this );
+ mxSlideShow->removeShapeEventListener( xListener, xShape );
+ }
+}
+
+void SlideShowListenerProxy::addSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& xListener )
+{
+ maListeners.addInterface(xListener);
+}
+
+void SlideShowListenerProxy::removeSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& xListener )
+{
+ maListeners.removeInterface(xListener);
+}
+
+void SAL_CALL SlideShowListenerProxy::beginEvent( const Reference< XAnimationNode >& xNode )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if( maListeners.getLength() >= 0 )
+ {
+ maListeners.forEach(
+ [&] (Reference<XAnimationListener> const& xListener) {
+ return xListener->beginEvent(xNode);
+ } );
+ }
+}
+
+void SAL_CALL SlideShowListenerProxy::endEvent( const Reference< XAnimationNode >& xNode )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if( maListeners.getLength() >= 0 )
+ {
+ maListeners.forEach(
+ [&] (Reference<XAnimationListener> const& xListener) {
+ return xListener->endEvent(xNode);
+ } );
+ }
+}
+
+void SAL_CALL SlideShowListenerProxy::repeat( const Reference< XAnimationNode >& xNode, ::sal_Int32 nRepeat )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if( maListeners.getLength() >= 0 )
+ {
+ maListeners.forEach(
+ [&] (Reference<XAnimationListener> const& xListener) {
+ return xListener->repeat(xNode, nRepeat);
+ } );
+ }
+}
+
+// css::presentation::XSlideShowListener:
+
+void SAL_CALL SlideShowListenerProxy::paused( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ maListeners.forEach(
+ [](uno::Reference<presentation::XSlideShowListener> const& xListener)
+ {
+ xListener->paused();
+ });
+}
+
+void SAL_CALL SlideShowListenerProxy::resumed( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ maListeners.forEach(
+ [](uno::Reference<presentation::XSlideShowListener> const& xListener)
+ {
+ xListener->resumed();
+ });
+}
+
+void SAL_CALL SlideShowListenerProxy::slideTransitionStarted( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ maListeners.forEach(
+ [](uno::Reference<presentation::XSlideShowListener> const& xListener)
+ {
+ xListener->slideTransitionStarted();
+ });
+}
+
+void SAL_CALL SlideShowListenerProxy::slideTransitionEnded( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ maListeners.forEach(
+ [](uno::Reference<presentation::XSlideShowListener> const& xListener)
+ {
+ xListener->slideTransitionEnded ();
+ });
+}
+
+void SAL_CALL SlideShowListenerProxy::slideAnimationsEnded( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ maListeners.forEach(
+ [](uno::Reference<presentation::XSlideShowListener> const& xListener)
+ {
+ xListener->slideAnimationsEnded ();
+ });
+}
+
+void SlideShowListenerProxy::slideEnded(sal_Bool bReverse)
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if( maListeners.getLength() >= 0 )
+ {
+ maListeners.forEach(
+ [&] (Reference<XSlideShowListener> const& xListener) {
+ return xListener->slideEnded(bReverse);
+ } );
+ }
+ }
+
+ {
+ SolarMutexGuard aSolarGuard;
+ if( mxController.is() )
+ mxController->slideEnded(bReverse);
+ }
+}
+
+void SlideShowListenerProxy::hyperLinkClicked( OUString const& aHyperLink )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if( maListeners.getLength() >= 0 )
+ {
+ maListeners.forEach(
+ [&] (Reference<XSlideShowListener> const& xListener) {
+ return xListener->hyperLinkClicked(aHyperLink);
+ } );
+ }
+ }
+
+ {
+ SolarMutexGuard aSolarGuard;
+ if( mxController.is() )
+ mxController->hyperLinkClicked(aHyperLink);
+ }
+}
+
+// XEventListener
+
+void SAL_CALL SlideShowListenerProxy::disposing( const css::lang::EventObject& aDisposeEvent )
+{
+ maListeners.disposeAndClear( aDisposeEvent );
+ mxController.clear();
+ mxSlideShow.clear();
+}
+
+// XShapeEventListener
+
+void SAL_CALL SlideShowListenerProxy::click( const Reference< XShape >& xShape, const css::awt::MouseEvent& /*aOriginalEvent*/ )
+{
+ SolarMutexGuard aSolarGuard;
+ if( mxController.is() )
+ mxController->click(xShape );
+}
+
+} // namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/slideshowimpl.hxx b/sd/source/ui/slideshow/slideshowimpl.hxx
new file mode 100644
index 000000000..eeec8a3fd
--- /dev/null
+++ b/sd/source/ui/slideshow/slideshowimpl.hxx
@@ -0,0 +1,342 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <sal/config.h>
+#include <comphelper/compbase.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <com/sun/star/presentation/ClickAction.hpp>
+#include <com/sun/star/presentation/XSlideShowListener.hpp>
+#include <com/sun/star/presentation/XSlideShowController.hpp>
+#include <com/sun/star/presentation/XShapeEventListener.hpp>
+
+#include <drawdoc.hxx>
+
+#include "showwindow.hxx"
+
+#include <slideshow.hxx>
+
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::media { class XPlayer; }
+namespace sd { class DrawDocShell; }
+namespace sd { class ViewShell; }
+
+class SfxBindings;
+class SfxDispatcher;
+class SfxViewFrame;
+class StarBASIC;
+
+namespace sd
+{
+class SlideShowView;
+class AnimationSlideController;
+class PaneHider;
+
+struct PresentationSettingsEx : public PresentationSettings
+{
+ bool mbRehearseTimings;
+ bool mbPreview;
+ VclPtr<vcl::Window> mpParentWindow;
+ css::uno::Reference< css::drawing::XDrawPage > mxStartPage;
+ css::uno::Reference< css::animations::XAnimationNode > mxAnimationNode;
+
+ PresentationSettingsEx( const PresentationSettingsEx& );
+ explicit PresentationSettingsEx( PresentationSettings const & );
+
+ /// @throws css::lang::IllegalArgumentException
+ void SetArguments( const css::uno::Sequence< css::beans::PropertyValue >& rArguments );
+
+ /// @throws css::lang::IllegalArgumentException
+ void SetPropertyValue( std::u16string_view rProperty, const css::uno::Any& rValue );
+};
+
+struct WrappedShapeEventImpl
+{
+ css::presentation::ClickAction meClickAction;
+ sal_Int32 mnVerb;
+ OUString maStrBookmark;
+ WrappedShapeEventImpl() : meClickAction( css::presentation::ClickAction_NONE ), mnVerb( 0 ) {};
+};
+
+typedef std::shared_ptr< WrappedShapeEventImpl > WrappedShapeEventImplPtr;
+
+class SlideShowListenerProxy : private ::cppu::BaseMutex,
+ public ::cppu::WeakImplHelper< css::presentation::XSlideShowListener, css::presentation::XShapeEventListener >
+{
+public:
+ SlideShowListenerProxy( const rtl::Reference< SlideshowImpl >& xController, const css::uno::Reference< css::presentation::XSlideShow >& xSlideShow );
+ virtual ~SlideShowListenerProxy() override;
+
+ void addAsSlideShowListener();
+ void removeAsSlideShowListener();
+
+ void addSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& Listener );
+ void removeSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& Listener );
+
+ void addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape );
+ void removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape );
+
+ // css::animations::XAnimationListener
+ virtual void SAL_CALL beginEvent( const css::uno::Reference< css::animations::XAnimationNode >& Node ) override;
+ virtual void SAL_CALL endEvent( const css::uno::Reference< css::animations::XAnimationNode >& Node ) override;
+ virtual void SAL_CALL repeat( const css::uno::Reference< css::animations::XAnimationNode >& Node, ::sal_Int32 Repeat ) override;
+
+ // css::presentation::XSlideShowListener:
+ virtual void SAL_CALL paused() override;
+ virtual void SAL_CALL resumed() override;
+ virtual void SAL_CALL slideTransitionStarted() override;
+ virtual void SAL_CALL slideTransitionEnded() override;
+ virtual void SAL_CALL slideAnimationsEnded() override;
+ virtual void SAL_CALL slideEnded(sal_Bool bReverse) override;
+ virtual void SAL_CALL hyperLinkClicked(const OUString & hyperLink) override;
+
+ // css::lang::XEventListener:
+ virtual void SAL_CALL disposing(const css::lang::EventObject & Source) override;
+
+ // css::presentation::XShapeEventListener:
+ virtual void SAL_CALL click(const css::uno::Reference< css::drawing::XShape > & xShape, const css::awt::MouseEvent & aOriginalEvent) override;
+
+private:
+ ::comphelper::OInterfaceContainerHelper3<css::presentation::XSlideShowListener> maListeners;
+ rtl::Reference< SlideshowImpl > mxController;
+ css::uno::Reference< css::presentation::XSlideShow > mxSlideShow;
+};
+
+typedef comphelper::WeakComponentImplHelper< css::presentation::XSlideShowController, css::container::XIndexAccess > SlideshowImplBase;
+
+class SlideshowImpl final : public SlideshowImplBase
+{
+friend class SlideShow;
+friend class SlideShowView;
+
+public:
+ explicit SlideshowImpl( const css::uno::Reference< css::presentation::XPresentation2 >& xPresentation, ViewShell* pViewSh, ::sd::View* pView, SdDrawDocument* pDoc, vcl::Window* pParentWindow);
+
+ // css::presentation::XSlideShowController:
+ virtual sal_Bool SAL_CALL getAlwaysOnTop() override;
+ virtual void SAL_CALL setAlwaysOnTop( sal_Bool _alwaysontop ) override;
+ virtual sal_Bool SAL_CALL getMouseVisible() override;
+ virtual void SAL_CALL setMouseVisible( sal_Bool _mousevisible ) override;
+ virtual sal_Bool SAL_CALL getUsePen() override;
+ virtual void SAL_CALL setUsePen( sal_Bool _usepen ) override;
+ virtual ::sal_Int32 SAL_CALL getPenColor() override;
+ virtual void SAL_CALL setPenColor( ::sal_Int32 _pencolor ) override;
+ virtual double SAL_CALL getPenWidth() override;
+ virtual void SAL_CALL setPenWidth( double dStrokeWidth ) override;
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setEraseAllInk( sal_Bool bEraseAllInk ) override;
+ virtual sal_Bool SAL_CALL isRunning( ) override;
+ virtual ::sal_Int32 SAL_CALL getSlideCount( ) override;
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getSlideByIndex( ::sal_Int32 Index ) override;
+ virtual void SAL_CALL addSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& Listener ) override;
+ virtual void SAL_CALL removeSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& Listener ) override;
+ virtual void SAL_CALL gotoNextEffect( ) override;
+ virtual void SAL_CALL gotoPreviousEffect( ) override;
+ virtual void SAL_CALL gotoFirstSlide( ) override;
+ virtual void SAL_CALL gotoNextSlide( ) override;
+ virtual void SAL_CALL gotoPreviousSlide( ) override;
+ virtual void SAL_CALL gotoLastSlide( ) override;
+ virtual void SAL_CALL gotoBookmark( const OUString& Bookmark ) override;
+ virtual void SAL_CALL gotoSlide( const css::uno::Reference< css::drawing::XDrawPage >& Page ) override;
+ virtual void SAL_CALL gotoSlideIndex( ::sal_Int32 Index ) override;
+ virtual void SAL_CALL stopSound( ) override;
+ virtual void SAL_CALL pause( ) override;
+ virtual void SAL_CALL resume( ) override;
+ virtual sal_Bool SAL_CALL isPaused( ) override;
+ virtual void SAL_CALL blankScreen( ::sal_Int32 Color ) override;
+ virtual void SAL_CALL activate( ) override;
+ virtual void SAL_CALL deactivate( ) override;
+ virtual sal_Bool SAL_CALL isActive( ) override;
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getCurrentSlide( ) override;
+ virtual ::sal_Int32 SAL_CALL getCurrentSlideIndex( ) override;
+ virtual ::sal_Int32 SAL_CALL getNextSlideIndex( ) override;
+ virtual sal_Bool SAL_CALL isEndless( ) override;
+ virtual sal_Bool SAL_CALL isFullScreen( ) override;
+ virtual css::uno::Reference< css::presentation::XSlideShow > SAL_CALL getSlideShow( ) override;
+
+ // XIndexAccess
+ virtual ::sal_Int32 SAL_CALL getCount( ) override;
+ virtual css::uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override;
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // will be called from the SlideShowListenerProxy when this event is fired from the XSlideShow
+ void slideEnded(const bool bReverse);
+ /// @throws css::uno::RuntimeException
+ void hyperLinkClicked(const OUString & hyperLink);
+ void click(const css::uno::Reference< css::drawing::XShape > & xShape);
+ bool swipe(const CommandSwipeData &rSwipeData);
+ bool longpress(const CommandLongPressData& rLongPressData);
+
+ /// ends the presentation async
+ void endPresentation();
+
+ ViewShell* getViewShell() const { return mpViewShell; }
+
+ void paint();
+ bool keyInput(const KeyEvent& rKEvt);
+ void mouseButtonUp(const MouseEvent& rMEvt);
+
+private:
+ SlideshowImpl(SlideshowImpl const &) = delete;
+ void operator =(SlideshowImpl const &) = delete;
+
+ virtual ~SlideshowImpl() override;
+
+ // override WeakComponentImplHelperBase::disposing()
+ // This function is called upon disposing the component,
+ // if your component needs special work when it becomes
+ // disposed, do it here.
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // internal
+ bool startShow( PresentationSettingsEx const * pPresSettings );
+ bool startPreview(
+ const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage,
+ const css::uno::Reference< css::animations::XAnimationNode >& xAnimationNode,
+ vcl::Window* pParent );
+
+ /** forces an async call to update in the main thread */
+ void startUpdateTimer();
+
+ void update();
+
+ void createSlideList( bool bAll, std::u16string_view rPresSlide );
+
+ void displayCurrentSlide (const bool bSkipAllMainSequenceEffects = false);
+
+ void displaySlideNumber( sal_Int32 nSlide );
+ void displaySlideIndex( sal_Int32 nIndex );
+ sal_Int32 getCurrentSlideNumber() const;
+ bool isInputFreezed() const { return mbInputFreeze; }
+
+ void jumpToBookmark( const OUString& sBookmark );
+
+ void hideChildWindows();
+ void showChildWindows();
+
+ void resize( const Size& rSize );
+
+ void setActiveXToolbarsVisible( bool bVisible );
+
+ DECL_LINK( updateHdl, Timer *, void );
+ DECL_LINK( ReadyForNextInputHdl, Timer *, void );
+ DECL_LINK( endPresentationHdl, void*, void );
+ void ContextMenuSelectHdl(std::string_view rIdent);
+ DECL_LINK( ContextMenuHdl, void*, void );
+ DECL_LINK( deactivateHdl, Timer *, void );
+ DECL_LINK( EventListenerHdl, VclSimpleEvent&, void );
+
+ /** called only by the slideshow view when the first paint event occurs.
+ This actually starts the slideshow. */
+ void onFirstPaint();
+
+ ::tools::Long getRestoreSlide() const { return mnRestoreSlide; }
+
+private:
+ bool startShowImpl(
+ const css::uno::Sequence< css::beans::PropertyValue >& aProperties );
+
+ SfxViewFrame* getViewFrame() const;
+ SfxDispatcher* getDispatcher() const;
+ SfxBindings* getBindings() const;
+
+ sal_Int32 getSlideNumberForBookmark( const OUString& rStrBookmark );
+
+ void removeShapeEvents();
+ void registerShapeEvents( sal_Int32 nSlideNumber );
+ /// @throws css::uno::Exception
+ void registerShapeEvents( css::uno::Reference< css::drawing::XShapes > const & xShapes );
+
+ static css::uno::Reference< css::presentation::XSlideShow > createSlideShow();
+
+ static void setAutoSaveState( bool bOn );
+ void gotoPreviousSlide (const bool bSkipAllMainSequenceEffects);
+
+ /** Called by our maUpdateTimer's updateHdl handler this method is
+ responsible to call the slideshow update() method and, depending on
+ its return value, wait for a certain amount of time before another
+ call to update() is scheduled.
+ */
+ void updateSlideShow();
+
+ css::uno::Reference< css::presentation::XSlideShow > mxShow;
+ rtl::Reference<sd::SlideShowView> mxView;
+ css::uno::Reference< css::frame::XModel > mxModel;
+
+ Timer maUpdateTimer;
+ Timer maInputFreezeTimer;
+ Timer maDeactivateTimer;
+
+ ::sd::View* mpView;
+ ViewShell* mpViewShell;
+ DrawDocShell* mpDocSh;
+ SdDrawDocument* mpDoc;
+
+ VclPtr<vcl::Window> mpParentWindow;
+ VclPtr<sd::ShowWindow> mpShowWindow;
+
+ std::shared_ptr< AnimationSlideController > mpSlideController;
+
+ ::tools::Long mnRestoreSlide;
+ Point maPopupMousePos;
+ Size maPresSize;
+ AnimationMode meAnimationMode;
+ OUString maCharBuffer;
+ VclPtr< ::sd::Window> mpOldActiveWindow;
+ Link<StarBASIC*,bool> maStarBASICGlobalErrorHdl;
+ ::tools::ULong mnChildMask;
+ bool mbDisposed;
+ bool mbAutoSaveWasOn;
+ bool mbRehearseTimings;
+ bool mbIsPaused;
+ bool mbWasPaused; // used to cache pause state during context menu
+ bool mbInputFreeze;
+ bool mbActive;
+
+ PresentationSettings maPresSettings;
+ sal_Int32 mnUserPaintColor;
+
+ bool mbUsePen;
+ double mdUserPaintStrokeWidth;
+
+ std::map< css::uno::Reference< css::drawing::XShape >, WrappedShapeEventImplPtr >
+ maShapeEventMap;
+
+ css::uno::Reference< css::drawing::XDrawPage > mxPreviewDrawPage;
+ css::uno::Reference< css::animations::XAnimationNode > mxPreviewAnimationNode;
+
+ css::uno::Reference< css::media::XPlayer > mxPlayer;
+
+ ::std::unique_ptr<PaneHider> mpPaneHider;
+
+ ImplSVEvent * mnEndShowEvent;
+ ImplSVEvent * mnContextMenuEvent;
+
+ css::uno::Reference< css::presentation::XPresentation2 > mxPresentation;
+ ::rtl::Reference< SlideShowListenerProxy > mxListenerProxy;
+};
+
+} // namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/slideshowviewimpl.cxx b/sd/source/ui/slideshow/slideshowviewimpl.cxx
new file mode 100644
index 000000000..d6addc3f8
--- /dev/null
+++ b/sd/source/ui/slideshow/slideshowviewimpl.cxx
@@ -0,0 +1,626 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "slideshowviewimpl.hxx"
+#include "slideshowimpl.hxx"
+#include <sdpage.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/awt/Pointer.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/awt/XWindowPeer.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <basegfx/utils/canvastools.hxx>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/processfactory.hxx>
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::WeakReference;
+using ::com::sun::star::uno::Exception;
+
+using namespace ::com::sun::star;
+
+namespace sd
+{
+
+void SlideShowViewMouseListeners::notify( std::unique_lock<std::mutex>& rGuard, const WrappedMouseEvent& rEvent )
+{
+ forEach(rGuard,
+ [&rEvent] (const Reference<css::awt::XMouseListener>& rListener)
+ {
+ switch( rEvent.meType )
+ {
+ case WrappedMouseEvent::PRESSED:
+ rListener->mousePressed( rEvent.maEvent );
+ break;
+
+ case WrappedMouseEvent::RELEASED:
+ rListener->mouseReleased( rEvent.maEvent );
+ break;
+
+ case WrappedMouseEvent::ENTERED:
+ rListener->mouseEntered( rEvent.maEvent );
+ break;
+
+ case WrappedMouseEvent::EXITED:
+ rListener->mouseExited( rEvent.maEvent );
+ break;
+ }
+ });
+}
+
+
+void SlideShowViewMouseMotionListeners::notify( std::unique_lock<std::mutex>& rGuard,const WrappedMouseMotionEvent& rEvent )
+{
+ forEach(rGuard,
+ [&rEvent] (const Reference< awt::XMouseMotionListener >& rListener)
+ {
+ switch( rEvent.meType )
+ {
+ case WrappedMouseMotionEvent::DRAGGED:
+ rListener->mouseDragged( rEvent.maEvent );
+ break;
+
+ case WrappedMouseMotionEvent::MOVED:
+ rListener->mouseMoved( rEvent.maEvent );
+ break;
+ }
+ });
+}
+
+// SlideShowView
+SlideShowView::SlideShowView( ShowWindow& rOutputWindow,
+ SdDrawDocument* pDoc,
+ AnimationMode eAnimationMode,
+ SlideshowImpl* pSlideShow,
+ bool bFullScreen )
+: mpCanvas( ::cppcanvas::VCLFactory::createSpriteCanvas( rOutputWindow ) ),
+ mxWindow( VCLUnoHelper::GetInterface( &rOutputWindow ), uno::UNO_SET_THROW ),
+ mxWindowPeer( mxWindow, uno::UNO_QUERY_THROW ),
+ mpSlideShow( pSlideShow ),
+ mrOutputWindow( rOutputWindow ),
+ mpDoc( pDoc ),
+ mbIsMouseMotionListener( false ),
+ meAnimationMode( eAnimationMode ),
+ mbFirstPaint( true ),
+ mbMousePressedEaten( false )
+{
+ mxWindow->addWindowListener( this );
+ mxWindow->addMouseListener( this );
+
+ mxPointer = awt::Pointer::create( ::comphelper::getProcessComponentContext() );
+
+ getTransformation();
+
+ // #i48939# only switch on kind of hacky scroll optimization, when
+ // running fullscreen. this minimizes the probability that other
+ // windows partially cover the show.
+ if( bFullScreen )
+ {
+ try
+ {
+ Reference< beans::XPropertySet > xCanvasProps( getCanvas(),
+ uno::UNO_QUERY_THROW );
+ xCanvasProps->setPropertyValue("UnsafeScrolling",
+ uno::Any( true ) );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+
+ mTranslationOffset.Width = 0;
+ mTranslationOffset.Height = 0;
+}
+
+// Dispose all internal references
+void SlideShowView::disposing(std::unique_lock<std::mutex>& rGuard)
+{
+ mpSlideShow = nullptr;
+
+ // deregister listeners
+ if( mxWindow.is() )
+ {
+ mxWindow->removeWindowListener( this );
+ mxWindow->removeMouseListener( this );
+
+ if( mbIsMouseMotionListener )
+ mxWindow->removeMouseMotionListener( this );
+ }
+
+ mpCanvas.reset();
+ mxWindow.clear();
+
+ // clear all listener containers
+ disposingImpl(rGuard);
+}
+
+// Disposing our broadcaster
+void SAL_CALL SlideShowView::disposing( const lang::EventObject& )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ disposingImpl(aGuard);
+}
+
+// Disposing our broadcaster
+void SlideShowView::disposingImpl(std::unique_lock<std::mutex>& rGuard)
+{
+ // notify all listeners that _we_ are going down (send a disposing()),
+ // then delete listener containers:
+ lang::EventObject const evt( static_cast<OWeakObject *>(this) );
+ if (!maViewListeners.empty())
+ {
+ auto tmp = std::move(maViewListeners);
+ rGuard.unlock();
+ for( const auto& rxListener : tmp )
+ {
+ Reference< util::XModifyListener > xListener( rxListener );
+ if( xListener.is() )
+ xListener->disposing( evt );
+ }
+ rGuard.lock();
+ }
+ if (maPaintListeners.getLength(rGuard))
+ {
+ maPaintListeners.disposeAndClear( rGuard, evt );
+ rGuard.lock();
+ }
+ if (maMouseListeners.getLength(rGuard))
+ {
+ maMouseListeners.disposeAndClear( rGuard, evt );
+ rGuard.lock();
+ }
+ if (maMouseMotionListeners.getLength(rGuard))
+ {
+ maMouseMotionListeners.disposeAndClear( rGuard, evt );
+ rGuard.lock();
+ }
+}
+
+void SlideShowView::paint( const awt::PaintEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( mbFirstPaint )
+ {
+ mbFirstPaint = false;
+ SlideshowImpl* pSlideShow = mpSlideShow;
+ aGuard.unlock();
+ if( pSlideShow )
+ pSlideShow->onFirstPaint();
+ }
+ else
+ {
+ // Change event source, to enable listeners to match event
+ // with view
+ awt::PaintEvent aEvent( e );
+ aEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+ maPaintListeners.notifyEach( aGuard, &css::awt::XPaintListener::windowPaint, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+ }
+}
+
+// XSlideShowView methods
+Reference< rendering::XSpriteCanvas > SAL_CALL SlideShowView::getCanvas( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ return mpCanvas ? mpCanvas->getUNOSpriteCanvas() : Reference< rendering::XSpriteCanvas >();
+}
+
+void SAL_CALL SlideShowView::clear()
+{
+ // paint background in black
+ std::unique_lock aGuard( m_aMutex );
+ SolarMutexGuard aSolarGuard;
+
+ // fill the bounds rectangle in black
+
+ const Size aWindowSize( mrOutputWindow.GetSizePixel() );
+
+ ::basegfx::B2DPolygon aPoly( ::basegfx::utils::createPolygonFromRect(
+ ::basegfx::B2DRectangle(0.0,0.0,
+ aWindowSize.Width(),
+ aWindowSize.Height() ) ) );
+ ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
+ ::cppcanvas::BaseGfxFactory::createPolyPolygon( mpCanvas, aPoly ) );
+
+ if( pPolyPoly )
+ {
+ pPolyPoly->setRGBAFillColor( 0x000000FFU );
+ pPolyPoly->draw();
+ }
+}
+
+geometry::IntegerSize2D SAL_CALL SlideShowView::getTranslationOffset( )
+{
+ return mTranslationOffset;
+}
+
+geometry::AffineMatrix2D SAL_CALL SlideShowView::getTransformation( )
+{
+ std::unique_lock aGuard( m_aMutex );
+ SolarMutexGuard aSolarGuard;
+
+ const Size& rTmpSize( mrOutputWindow.GetSizePixel() );
+
+ if (rTmpSize.IsEmpty())
+ {
+ return geometry::AffineMatrix2D (1,0,0,0,1,0);
+ }
+
+ const Size aWindowSize( mrOutputWindow.GetSizePixel() );
+ Size aOutputSize( aWindowSize );
+
+ if( meAnimationMode != ANIMATIONMODE_SHOW )
+ {
+ aOutputSize.setWidth( static_cast<::tools::Long>( aOutputSize.Width() / 1.03 ) );
+ aOutputSize.setHeight( static_cast<::tools::Long>( aOutputSize.Height() / 1.03 ) );
+ }
+
+ SdPage* pP = mpDoc->GetSdPage( 0, PageKind::Standard );
+ Size aPageSize( pP->GetSize() );
+
+ const double page_ratio = static_cast<double>(aPageSize.Width()) / static_cast<double>(aPageSize.Height());
+ const double output_ratio = static_cast<double>(aOutputSize.Width()) / static_cast<double>(aOutputSize.Height());
+
+ if( page_ratio > output_ratio )
+ {
+ aOutputSize.setHeight( ( aOutputSize.Width() * aPageSize.Height() ) / aPageSize.Width() );
+ }
+ else if( page_ratio < output_ratio )
+ {
+ aOutputSize.setWidth( ( aOutputSize.Height() * aPageSize.Width() ) / aPageSize.Height() );
+ }
+
+ Point aOutputOffset( ( aWindowSize.Width() - aOutputSize.Width() ) >> 1,
+ ( aWindowSize.Height() - aOutputSize.Height() ) >> 1 );
+
+ // Reduce available width by one, as the slides might actually
+ // render one pixel wider and higher as aPageSize below specifies
+ // (when shapes of page size have visible border lines)
+ aOutputSize.AdjustWidth( -1 );
+ aOutputSize.AdjustHeight( -1 );
+
+ // Record mTranslationOffset
+ mTranslationOffset.Height = aOutputOffset.Y();
+ mTranslationOffset.Width = aOutputOffset.X();
+
+ // scale presentation into available window rect (minus 10%); center in the window
+ const basegfx::B2DHomMatrix aMatrix(basegfx::utils::createScaleTranslateB2DHomMatrix(
+ aOutputSize.Width(), aOutputSize.Height(), aOutputOffset.X(), aOutputOffset.Y()));
+
+ geometry::AffineMatrix2D aRes;
+
+ return ::basegfx::unotools::affineMatrixFromHomMatrix( aRes, aMatrix );
+}
+
+void SAL_CALL SlideShowView::addTransformationChangedListener( const Reference< util::XModifyListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (m_bDisposed)
+ return;
+ WeakReference< util::XModifyListener > xWeak( xListener );
+ if( std::find( maViewListeners.begin(), maViewListeners.end(), xWeak ) == maViewListeners.end() )
+ maViewListeners.push_back( xWeak );
+}
+
+void SAL_CALL SlideShowView::removeTransformationChangedListener( const Reference< util::XModifyListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (m_bDisposed)
+ return;
+ WeakReference< util::XModifyListener > xWeak( xListener );
+ auto aIter( std::find( maViewListeners.begin(), maViewListeners.end(), xWeak ) );
+ if( aIter != maViewListeners.end() )
+ maViewListeners.erase( aIter );
+}
+
+void SAL_CALL SlideShowView::addPaintListener( const Reference< awt::XPaintListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (!m_bDisposed)
+ maPaintListeners.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL SlideShowView::removePaintListener( const Reference< awt::XPaintListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (!m_bDisposed)
+ maPaintListeners.removeInterface( aGuard, xListener );
+}
+
+void SAL_CALL SlideShowView::addMouseListener( const Reference< awt::XMouseListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (!m_bDisposed)
+ maMouseListeners.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL SlideShowView::removeMouseListener( const Reference< awt::XMouseListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (!m_bDisposed)
+ maMouseListeners.removeInterface( aGuard, xListener );
+}
+
+void SAL_CALL SlideShowView::addMouseMotionListener( const Reference< awt::XMouseMotionListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (m_bDisposed)
+ return;
+
+ if( !mbIsMouseMotionListener && mxWindow.is() )
+ {
+ // delay motion event registration, until we really
+ // need it
+ mbIsMouseMotionListener = true;
+ mxWindow->addMouseMotionListener( this );
+ }
+
+ maMouseMotionListeners.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL SlideShowView::removeMouseMotionListener( const Reference< awt::XMouseMotionListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (!m_bDisposed)
+ maMouseMotionListeners.removeInterface( aGuard, xListener );
+
+ // TODO(P1): Might be nice to deregister for mouse motion
+ // events, when the last listener is gone.
+}
+
+void SAL_CALL SlideShowView::setMouseCursor( sal_Int16 nPointerShape )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ // forward to window
+ if( mxPointer.is() )
+ mxPointer->setType( nPointerShape );
+
+ if( mxWindowPeer.is() )
+ mxWindowPeer->setPointer( mxPointer );
+}
+
+awt::Rectangle SAL_CALL SlideShowView::getCanvasArea( )
+{
+ awt::Rectangle aRectangle;
+
+ if( mxWindow.is() )
+ return mxWindow->getPosSize();
+
+ aRectangle.X = aRectangle.Y = aRectangle.Width = aRectangle.Height = 0;
+
+ return aRectangle;
+}
+
+void SlideShowView::updateimpl( std::unique_lock<std::mutex>& rGuard, SlideshowImpl* pSlideShow )
+{
+ if( !pSlideShow )
+ return;
+
+ ::rtl::Reference< SlideshowImpl > xKeepAlive( pSlideShow );
+
+ if( mbFirstPaint )
+ {
+ mbFirstPaint = false;
+ SlideshowImpl* pTmpSlideShow = mpSlideShow;
+ rGuard.unlock();
+ if( pTmpSlideShow )
+ pTmpSlideShow->onFirstPaint();
+ } else
+ rGuard.unlock();
+
+ pSlideShow->startUpdateTimer();
+}
+
+// XWindowListener methods
+void SAL_CALL SlideShowView::windowResized( const awt::WindowEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if (m_bDisposed)
+ return;
+
+ if (!maViewListeners.empty())
+ {
+ // Change event source, to enable listeners to match event
+ // with view
+ awt::WindowEvent aEvent( e );
+ aEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+ auto aIter( maViewListeners.begin() );
+ while( aIter != maViewListeners.end() )
+ {
+ Reference< util::XModifyListener > xListener( *aIter );
+ if( xListener.is() )
+ {
+ aGuard.unlock();
+ xListener->modified( aEvent );
+ aGuard.lock();
+ ++aIter;
+ }
+ else
+ {
+ aIter = maViewListeners.erase( aIter );
+ }
+ }
+ }
+
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+}
+
+void SAL_CALL SlideShowView::windowMoved( const awt::WindowEvent& )
+{
+ // ignored
+}
+
+void SAL_CALL SlideShowView::windowShown( const lang::EventObject& )
+{
+ // ignored
+}
+
+void SAL_CALL SlideShowView::windowHidden( const lang::EventObject& )
+{
+ // ignored
+}
+
+// XMouseListener implementation
+void SAL_CALL SlideShowView::mousePressed( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ if( mpSlideShow && mpSlideShow->isInputFreezed() )
+ {
+ mbMousePressedEaten = true;
+ }
+ else
+ {
+ mbMousePressedEaten = false;
+
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseEvent aEvent;
+ aEvent.meType = WrappedMouseEvent::PRESSED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+ }
+}
+
+void SAL_CALL SlideShowView::mouseReleased( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ if( mbMousePressedEaten )
+ {
+ // if mouse button down was ignored, also ignore mouse button up
+ mbMousePressedEaten = false;
+ }
+ else if( mpSlideShow && !mpSlideShow->isInputFreezed() )
+ {
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseEvent aEvent;
+ aEvent.meType = WrappedMouseEvent::RELEASED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+ }
+}
+
+void SAL_CALL SlideShowView::mouseEntered( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseEvent aEvent;
+ aEvent.meType = WrappedMouseEvent::ENTERED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+}
+
+void SAL_CALL SlideShowView::mouseExited( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseEvent aEvent;
+ aEvent.meType = WrappedMouseEvent::EXITED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+}
+
+// XMouseMotionListener implementation
+void SAL_CALL SlideShowView::mouseDragged( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseMotionEvent aEvent;
+ aEvent.meType = WrappedMouseMotionEvent::DRAGGED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseMotionListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+}
+
+void SAL_CALL SlideShowView::mouseMoved( const awt::MouseEvent& e )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ return;
+
+ // Change event source, to enable listeners to match event
+ // with view
+ WrappedMouseMotionEvent aEvent;
+ aEvent.meType = WrappedMouseMotionEvent::MOVED;
+ aEvent.maEvent = e;
+ aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+
+ maMouseMotionListeners.notify( aGuard, aEvent );
+ updateimpl( aGuard, mpSlideShow ); // warning: clears guard!
+}
+
+} // namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slideshow/slideshowviewimpl.hxx b/sd/source/ui/slideshow/slideshowviewimpl.hxx
new file mode 100644
index 000000000..3a5018be4
--- /dev/null
+++ b/sd/source/ui/slideshow/slideshowviewimpl.hxx
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <comphelper/compbase.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+#include <com/sun/star/awt/XPaintListener.hpp>
+#include <com/sun/star/presentation/XSlideShowView.hpp>
+#include <cppcanvas/spritecanvas.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <slideshow.hxx>
+
+namespace com::sun::star::awt { class XPointer; }
+namespace com::sun::star::awt { class XWindow; }
+namespace com::sun::star::awt { class XWindowPeer; }
+namespace com::sun::star::awt { struct WindowEvent; }
+namespace com::sun::star::rendering { class XSpriteCanvas; }
+class SdDrawDocument;
+
+namespace sd
+{
+
+struct WrappedMouseEvent : public css::lang::EventObject
+{
+ enum EventType
+ {
+ PRESSED,
+ RELEASED,
+ ENTERED,
+ EXITED
+ };
+
+ EventType meType;
+ css::awt::MouseEvent maEvent;
+};
+
+struct WrappedMouseMotionEvent : public css::lang::EventObject
+{
+ enum EventType
+ {
+ DRAGGED,
+ MOVED
+ };
+
+ EventType meType;
+ css::awt::MouseEvent maEvent;
+};
+
+// SlideShowViewPaintListeners
+typedef ::comphelper::OInterfaceContainerHelper4< css::awt::XPaintListener > SlideShowViewPaintListeners;
+
+
+// SlideShowViewMouseListeners
+typedef ::comphelper::OInterfaceContainerHelper4< css::awt::XMouseListener > SlideShowViewMouseListeners_Base;
+
+class SlideShowViewMouseListeners : public SlideShowViewMouseListeners_Base
+{
+public:
+ void notify(std::unique_lock<std::mutex>& rGuard, const WrappedMouseEvent& rEvent);
+};
+
+
+// SlideShowViewMouseMotionListeners
+typedef ::comphelper::OInterfaceContainerHelper4< css::awt::XMouseMotionListener > SlideShowViewMouseMotionListeners_Base;
+
+class SlideShowViewMouseMotionListeners : public SlideShowViewMouseMotionListeners_Base
+{
+public:
+ void notify( std::unique_lock<std::mutex>& rGuard, const WrappedMouseMotionEvent& rEvent );
+};
+
+// SlideShowView
+class ShowWindow;
+class SlideshowImpl;
+
+typedef comphelper::WeakComponentImplHelper< css::presentation::XSlideShowView,
+ css::awt::XWindowListener,
+ css::awt::XMouseListener,
+ css::awt::XMouseMotionListener > SlideShowView_Base;
+
+class SlideShowView final : public SlideShowView_Base
+{
+public:
+ SlideShowView( ShowWindow& rOutputWindow,
+ SdDrawDocument* pDoc,
+ AnimationMode eAnimationMode,
+ SlideshowImpl* pSlideShow,
+ bool bFullScreen );
+
+ void ignoreNextMouseReleased() { mbMousePressedEaten = true; }
+
+ /// Dispose all internal references
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ /// Disposing our broadcaster
+ virtual void SAL_CALL disposing( const css::lang::EventObject& ) override;
+
+ /// @throws css::uno::RuntimeException
+ void paint( const css::awt::PaintEvent& e );
+
+ // XSlideShowView methods
+ virtual css::uno::Reference< css::rendering::XSpriteCanvas > SAL_CALL getCanvas( ) override;
+ virtual void SAL_CALL clear( ) override;
+ virtual css::geometry::AffineMatrix2D SAL_CALL getTransformation( ) override;
+ virtual css::geometry::IntegerSize2D SAL_CALL getTranslationOffset( ) override;
+ virtual void SAL_CALL addTransformationChangedListener( const css::uno::Reference< css::util::XModifyListener >& xListener ) override;
+ virtual void SAL_CALL removeTransformationChangedListener( const css::uno::Reference< css::util::XModifyListener >& xListener ) override;
+ virtual void SAL_CALL addPaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+ virtual void SAL_CALL removePaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+ virtual void SAL_CALL addMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL addMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL setMouseCursor( sal_Int16 nPointerShape ) override;
+ virtual css::awt::Rectangle SAL_CALL getCanvasArea( ) override;
+
+ // XWindowListener methods
+ virtual void SAL_CALL windowResized( const css::awt::WindowEvent& e ) override;
+ virtual void SAL_CALL windowMoved( const css::awt::WindowEvent& e ) override;
+ virtual void SAL_CALL windowShown( const css::lang::EventObject& e ) override;
+ virtual void SAL_CALL windowHidden( const css::lang::EventObject& e ) override;
+
+ // XMouseListener implementation
+ virtual void SAL_CALL mousePressed( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseReleased( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseEntered( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseExited( const css::awt::MouseEvent& e ) override;
+
+ // XMouseMotionListener implementation
+ virtual void SAL_CALL mouseDragged( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseMoved( const css::awt::MouseEvent& e ) override;
+
+protected:
+ virtual ~SlideShowView() override {}
+
+private:
+ void updateimpl( std::unique_lock<std::mutex>& rGuard, SlideshowImpl* pSlideShow );
+
+ void disposingImpl( std::unique_lock<std::mutex>& );
+
+ ::cppcanvas::SpriteCanvasSharedPtr mpCanvas;
+ css::uno::Reference< css::awt::XWindow > mxWindow;
+ css::uno::Reference< css::awt::XWindowPeer > mxWindowPeer;
+ css::uno::Reference< css::awt::XPointer > mxPointer;
+ SlideshowImpl* mpSlideShow;
+ ShowWindow& mrOutputWindow;
+ std::vector< css::uno::WeakReference< css::util::XModifyListener > >
+ maViewListeners;
+ SlideShowViewPaintListeners maPaintListeners;
+ SlideShowViewMouseListeners maMouseListeners;
+ SlideShowViewMouseMotionListeners maMouseMotionListeners;
+ SdDrawDocument* mpDoc;
+ bool mbIsMouseMotionListener;
+ AnimationMode meAnimationMode;
+ bool mbFirstPaint;
+ bool mbMousePressedEaten;
+ css::geometry::IntegerSize2D mTranslationOffset;
+};
+
+} // namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx
new file mode 100644
index 000000000..87c727408
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx
@@ -0,0 +1,550 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <unordered_map>
+#include "SlsBitmapCache.hxx"
+#include "SlsCacheCompactor.hxx"
+#include "SlsBitmapCompressor.hxx"
+#include "SlsCacheConfiguration.hxx"
+
+#include <sal/log.hxx>
+
+// Define the default value for the maximal cache size that is used for
+// previews that are currently not visible. The visible previews are all
+// held in memory at all times. This default is used only when the
+// configuration does not have a value.
+const sal_Int32 MAXIMAL_CACHE_SIZE = 4*1024L*1024L;
+
+using namespace ::com::sun::star::uno;
+
+namespace sd::slidesorter::cache {
+
+class BitmapCache::CacheEntry
+{
+public:
+ CacheEntry(const BitmapEx& rBitmap, sal_Int32 nLastAccessTime, bool bIsPrecious);
+ CacheEntry(sal_Int32 nLastAccessTime, bool bIsPrecious);
+ inline void Recycle (const CacheEntry& rEntry);
+ inline sal_Int32 GetMemorySize() const;
+ void Compress (const std::shared_ptr<BitmapCompressor>& rpCompressor);
+ inline void Decompress();
+
+ bool IsUpToDate() const { return mbIsUpToDate; }
+ void SetUpToDate (bool bIsUpToDate) { mbIsUpToDate = bIsUpToDate; }
+ sal_Int32 GetAccessTime() const { return mnLastAccessTime; }
+ void SetAccessTime (sal_Int32 nAccessTime) { mnLastAccessTime = nAccessTime; }
+
+ const BitmapEx& GetPreview() const { return maPreview; }
+ inline void SetPreview (const BitmapEx& rPreview);
+ bool HasPreview() const;
+
+ const BitmapEx& GetMarkedPreview() const { return maMarkedPreview; }
+ inline void SetMarkedPreview (const BitmapEx& rMarkePreview);
+
+ bool HasReplacement() const { return (mpReplacement != nullptr); }
+ inline bool HasLosslessReplacement() const;
+ void Invalidate() { mpReplacement.reset(); mpCompressor.reset(); mbIsUpToDate = false; }
+ bool IsPrecious() const { return mbIsPrecious; }
+ void SetPrecious (bool bIsPrecious) { mbIsPrecious = bIsPrecious; }
+
+private:
+ BitmapEx maPreview;
+ BitmapEx maMarkedPreview;
+ std::shared_ptr<BitmapReplacement> mpReplacement;
+ std::shared_ptr<BitmapCompressor> mpCompressor;
+ bool mbIsUpToDate;
+ sal_Int32 mnLastAccessTime;
+ // When this flag is set then the bitmap is not modified by a cache
+ // compactor.
+ bool mbIsPrecious;
+};
+
+namespace {
+
+class CacheHash {
+public:
+ size_t operator()(const BitmapCache::CacheKey& p) const
+ { return reinterpret_cast<size_t>(p); }
+};
+
+}
+
+class BitmapCache::CacheBitmapContainer
+ : public std::unordered_map<CacheKey, CacheEntry, CacheHash>
+{
+public:
+ CacheBitmapContainer() {}
+};
+
+namespace {
+
+typedef ::std::vector<
+ ::std::pair< ::sd::slidesorter::cache::BitmapCache::CacheKey,
+ ::sd::slidesorter::cache::BitmapCache::CacheEntry>
+ > SortableBitmapContainer;
+
+ /** Compare elements of the bitmap cache according to their last access
+ time.
+ */
+ class AccessTimeComparator
+ {
+ public:
+ bool operator () (
+ const SortableBitmapContainer::value_type& e1,
+ const SortableBitmapContainer::value_type& e2)
+ {
+ return e1.second.GetAccessTime() < e2.second.GetAccessTime();
+ }
+ };
+
+} // end of anonymous namespace
+
+//===== BitmapCache =========================================================
+
+BitmapCache::BitmapCache ()
+ : mpBitmapContainer(new CacheBitmapContainer()),
+ mnNormalCacheSize(0),
+ mnPreciousCacheSize(0),
+ mnCurrentAccessTime(0),
+ mnMaximalNormalCacheSize(MAXIMAL_CACHE_SIZE),
+ mbIsFull(false)
+{
+ Any aCacheSize (CacheConfiguration::Instance()->GetValue("CacheSize"));
+ if (aCacheSize.has<sal_Int32>())
+ aCacheSize >>= mnMaximalNormalCacheSize;
+
+ mpCacheCompactor = CacheCompactor::Create(*this,mnMaximalNormalCacheSize);
+}
+
+BitmapCache::~BitmapCache()
+{
+ Clear();
+}
+
+void BitmapCache::Clear()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ mpBitmapContainer->clear();
+ mnNormalCacheSize = 0;
+ mnPreciousCacheSize = 0;
+ mnCurrentAccessTime = 0;
+}
+
+bool BitmapCache::HasBitmap (const CacheKey& rKey)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
+ return (iEntry != mpBitmapContainer->end()
+ && (iEntry->second.HasPreview() || iEntry->second.HasReplacement()));
+}
+
+bool BitmapCache::BitmapIsUpToDate (const CacheKey& rKey)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ bool bIsUpToDate = false;
+ CacheBitmapContainer::iterator aIterator (mpBitmapContainer->find(rKey));
+ if (aIterator != mpBitmapContainer->end())
+ bIsUpToDate = aIterator->second.IsUpToDate();
+
+ return bIsUpToDate;
+}
+
+BitmapEx BitmapCache::GetBitmap (const CacheKey& rKey)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
+ if (iEntry == mpBitmapContainer->end())
+ {
+ // Create an empty bitmap for the given key that acts as placeholder
+ // until we are given the real one. Mark it as not being up to date.
+ SetBitmap(rKey, BitmapEx(), false);
+ iEntry = mpBitmapContainer->find(rKey);
+ iEntry->second.SetUpToDate(false);
+ }
+ else
+ {
+ iEntry->second.SetAccessTime(mnCurrentAccessTime++);
+
+ // Maybe we have to decompress the preview.
+ if ( ! iEntry->second.HasPreview() && iEntry->second.HasReplacement())
+ {
+ UpdateCacheSize(iEntry->second, REMOVE);
+ iEntry->second.Decompress();
+ UpdateCacheSize(iEntry->second, ADD);
+ }
+ }
+ return iEntry->second.GetPreview();
+}
+
+BitmapEx BitmapCache::GetMarkedBitmap (const CacheKey& rKey)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
+ if (iEntry != mpBitmapContainer->end())
+ {
+ iEntry->second.SetAccessTime(mnCurrentAccessTime++);
+ return iEntry->second.GetMarkedPreview();
+ }
+ else
+ return BitmapEx();
+}
+
+void BitmapCache::ReleaseBitmap (const CacheKey& rKey)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ CacheBitmapContainer::iterator aIterator (mpBitmapContainer->find(rKey));
+ if (aIterator != mpBitmapContainer->end())
+ {
+ UpdateCacheSize(aIterator->second, REMOVE);
+ mpBitmapContainer->erase(aIterator);
+ }
+}
+
+bool BitmapCache::InvalidateBitmap (const CacheKey& rKey)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
+ if (iEntry != mpBitmapContainer->end())
+ {
+ iEntry->second.SetUpToDate(false);
+
+ // When there is a preview then we release the replacement. The
+ // preview itself is kept until a new one is created.
+ if (iEntry->second.HasPreview())
+ {
+ UpdateCacheSize(iEntry->second, REMOVE);
+ iEntry->second.Invalidate();
+ UpdateCacheSize(iEntry->second, ADD);
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+void BitmapCache::InvalidateCache()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ for (auto& rEntry : *mpBitmapContainer)
+ {
+ rEntry.second.Invalidate();
+ }
+ ReCalculateTotalCacheSize();
+}
+
+void BitmapCache::SetBitmap (
+ const CacheKey& rKey,
+ const BitmapEx& rPreview,
+ bool bIsPrecious)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
+ if (iEntry != mpBitmapContainer->end())
+ {
+ UpdateCacheSize(iEntry->second, REMOVE);
+ iEntry->second.SetPreview(rPreview);
+ iEntry->second.SetUpToDate(true);
+ iEntry->second.SetAccessTime(mnCurrentAccessTime++);
+ }
+ else
+ {
+ iEntry = mpBitmapContainer->emplace(
+ rKey,
+ CacheEntry(rPreview, mnCurrentAccessTime++, bIsPrecious)
+ ).first;
+ }
+
+ if (iEntry != mpBitmapContainer->end())
+ UpdateCacheSize(iEntry->second, ADD);
+}
+
+void BitmapCache::SetMarkedBitmap (
+ const CacheKey& rKey,
+ const BitmapEx& rPreview)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
+ if (iEntry != mpBitmapContainer->end())
+ {
+ UpdateCacheSize(iEntry->second, REMOVE);
+ iEntry->second.SetMarkedPreview(rPreview);
+ iEntry->second.SetAccessTime(mnCurrentAccessTime++);
+ UpdateCacheSize(iEntry->second, ADD);
+ }
+}
+
+void BitmapCache::SetPrecious (const CacheKey& rKey, bool bIsPrecious)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
+ if (iEntry != mpBitmapContainer->end())
+ {
+ if (iEntry->second.IsPrecious() != bIsPrecious)
+ {
+ UpdateCacheSize(iEntry->second, REMOVE);
+ iEntry->second.SetPrecious(bIsPrecious);
+ UpdateCacheSize(iEntry->second, ADD);
+ }
+ }
+ else if (bIsPrecious)
+ {
+ iEntry = mpBitmapContainer->emplace(
+ rKey,
+ CacheEntry(BitmapEx(), mnCurrentAccessTime++, bIsPrecious)
+ ).first;
+ UpdateCacheSize(iEntry->second, ADD);
+ }
+}
+
+void BitmapCache::ReCalculateTotalCacheSize()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ mnNormalCacheSize = 0;
+ mnPreciousCacheSize = 0;
+ for (const auto& rEntry : *mpBitmapContainer)
+ {
+ if (rEntry.second.IsPrecious())
+ mnPreciousCacheSize += rEntry.second.GetMemorySize();
+ else
+ mnNormalCacheSize += rEntry.second.GetMemorySize();
+ }
+ mbIsFull = (mnNormalCacheSize >= mnMaximalNormalCacheSize);
+
+ SAL_INFO("sd.sls", __func__ << ": cache size is " << mnNormalCacheSize << "/" << mnPreciousCacheSize);
+}
+
+void BitmapCache::Recycle (const BitmapCache& rCache)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ for (const auto& rOtherEntry : *rCache.mpBitmapContainer)
+ {
+ CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rOtherEntry.first));
+ if (iEntry == mpBitmapContainer->end())
+ {
+ iEntry = mpBitmapContainer->emplace(
+ rOtherEntry.first,
+ CacheEntry(mnCurrentAccessTime++, true)
+ ).first;
+ UpdateCacheSize(iEntry->second, ADD);
+ }
+ if (iEntry != mpBitmapContainer->end())
+ {
+ UpdateCacheSize(iEntry->second, REMOVE);
+ iEntry->second.Recycle(rOtherEntry.second);
+ UpdateCacheSize(iEntry->second, ADD);
+ }
+ }
+}
+
+BitmapCache::CacheIndex BitmapCache::GetCacheIndex() const
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Create a copy of the bitmap container.
+ SortableBitmapContainer aSortedContainer;
+ aSortedContainer.reserve(mpBitmapContainer->size());
+
+ // Copy the relevant entries.
+ for (const auto& rEntry : *mpBitmapContainer)
+ {
+ if ( rEntry.second.IsPrecious())
+ continue;
+
+ if ( ! rEntry.second.HasPreview())
+ continue;
+
+ aSortedContainer.emplace_back(rEntry.first, rEntry.second);
+ }
+
+ // Sort the remaining entries.
+ ::std::sort(aSortedContainer.begin(), aSortedContainer.end(), AccessTimeComparator());
+
+ // Return a list with the keys of the sorted entries.
+ CacheIndex aIndex;
+ aIndex.reserve(aSortedContainer.size());
+ for (const auto& rIndexEntry : aSortedContainer)
+ aIndex.push_back(rIndexEntry.first);
+ return aIndex;
+}
+
+void BitmapCache::Compress (
+ const CacheKey& rKey,
+ const std::shared_ptr<BitmapCompressor>& rpCompressor)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
+ if (iEntry != mpBitmapContainer->end() && iEntry->second.HasPreview())
+ {
+ UpdateCacheSize(iEntry->second, REMOVE);
+ iEntry->second.Compress(rpCompressor);
+ UpdateCacheSize(iEntry->second, ADD);
+ }
+}
+
+void BitmapCache::UpdateCacheSize (const CacheEntry& rEntry, CacheOperation eOperation)
+{
+ sal_Int32 nEntrySize (rEntry.GetMemorySize());
+ sal_Int32& rCacheSize (rEntry.IsPrecious() ? mnPreciousCacheSize : mnNormalCacheSize);
+ switch (eOperation)
+ {
+ case ADD:
+ rCacheSize += nEntrySize;
+ if ( ! rEntry.IsPrecious() && mnNormalCacheSize>mnMaximalNormalCacheSize)
+ {
+ mbIsFull = true;
+ SAL_INFO("sd.sls", __func__ << ": cache size is " << mnNormalCacheSize << " > " << mnMaximalNormalCacheSize);
+ mpCacheCompactor->RequestCompaction();
+ }
+ break;
+
+ case REMOVE:
+ rCacheSize -= nEntrySize;
+ if (mnNormalCacheSize < mnMaximalNormalCacheSize)
+ mbIsFull = false;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
+
+//===== CacheEntry ============================================================
+
+BitmapCache::CacheEntry::CacheEntry(
+ sal_Int32 nLastAccessTime,
+ bool bIsPrecious)
+ : mbIsUpToDate(true),
+ mnLastAccessTime(nLastAccessTime),
+ mbIsPrecious(bIsPrecious)
+{
+}
+
+BitmapCache::CacheEntry::CacheEntry(
+ const BitmapEx& rPreview,
+ sal_Int32 nLastAccessTime,
+ bool bIsPrecious)
+ : maPreview(rPreview),
+ mbIsUpToDate(true),
+ mnLastAccessTime(nLastAccessTime),
+ mbIsPrecious(bIsPrecious)
+{
+}
+
+inline void BitmapCache::CacheEntry::Recycle (const CacheEntry& rEntry)
+{
+ if ((rEntry.HasPreview() || rEntry.HasLosslessReplacement())
+ && ! (HasPreview() || HasLosslessReplacement()))
+ {
+ maPreview = rEntry.maPreview;
+ maMarkedPreview = rEntry.maMarkedPreview;
+ mpReplacement = rEntry.mpReplacement;
+ mpCompressor = rEntry.mpCompressor;
+ mnLastAccessTime = rEntry.mnLastAccessTime;
+ mbIsUpToDate = rEntry.mbIsUpToDate;
+ }
+}
+
+inline sal_Int32 BitmapCache::CacheEntry::GetMemorySize() const
+{
+ sal_Int32 nSize (0);
+ nSize += maPreview.GetSizeBytes();
+ nSize += maMarkedPreview.GetSizeBytes();
+ if (mpReplacement != nullptr)
+ nSize += mpReplacement->GetMemorySize();
+ return nSize;
+}
+
+void BitmapCache::CacheEntry::Compress (const std::shared_ptr<BitmapCompressor>& rpCompressor)
+{
+ if ( maPreview.IsEmpty())
+ return;
+
+ if (mpReplacement == nullptr)
+ {
+ mpReplacement = rpCompressor->Compress(maPreview);
+
+#ifdef DEBUG_SD_SLSBITMAPCACHE
+ sal_uInt32 nOldSize (maPreview.GetSizeBytes());
+ sal_uInt32 nNewSize (mpReplacement.get()!=NULL ? mpReplacement->GetMemorySize() : 0);
+ if (nOldSize == 0)
+ nOldSize = 1;
+ sal_Int32 nRatio (100L * nNewSize / nOldSize);
+ SAL_INFO("sd.sls", __func__ << ": compressing bitmap for " << %x << " from " << nOldSize << " to " << nNewSize << " bytes (" << nRatio << "%)");
+#endif
+
+ mpCompressor = rpCompressor;
+ }
+
+ maPreview.SetEmpty();
+ maMarkedPreview.SetEmpty();
+}
+
+inline void BitmapCache::CacheEntry::Decompress()
+{
+ if (mpReplacement != nullptr && mpCompressor != nullptr && maPreview.IsEmpty())
+ {
+ maPreview = mpCompressor->Decompress(*mpReplacement);
+ maMarkedPreview.SetEmpty();
+ if ( ! mpCompressor->IsLossless())
+ mbIsUpToDate = false;
+ }
+}
+
+inline void BitmapCache::CacheEntry::SetPreview (const BitmapEx& rPreview)
+{
+ maPreview = rPreview;
+ maMarkedPreview.SetEmpty();
+ mpReplacement.reset();
+ mpCompressor.reset();
+}
+
+bool BitmapCache::CacheEntry::HasPreview() const
+{
+ return ! maPreview.IsEmpty();
+}
+
+inline void BitmapCache::CacheEntry::SetMarkedPreview (const BitmapEx& rMarkedPreview)
+{
+ maMarkedPreview = rMarkedPreview;
+}
+
+inline bool BitmapCache::CacheEntry::HasLosslessReplacement() const
+{
+ return mpReplacement != nullptr && mpCompressor != nullptr && mpCompressor->IsLossless();
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx
new file mode 100644
index 000000000..98b0bcb53
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/bitmapex.hxx>
+#include <osl/mutex.hxx>
+#include <memory>
+
+class SdrPage;
+
+namespace sd::slidesorter::cache
+{
+class CacheCompactor;
+class BitmapCompressor;
+
+/** This low level cache is the actual bitmap container. It supports a
+ precious flag for every preview bitmap and keeps track of total sizes
+ for all previews with/without this flag. The precious flag is used by
+ compaction algorithms to determine which previews may be compressed or
+ even discarded and which have to remain in their original form. The
+ precious flag is usually set for the visible previews.
+
+ Additionally to the actual preview there is an optional marked preview.
+ This is used for slides excluded from the slide show which have a preview
+ that shows a mark (some sort of bitmap overlay) to that effect.
+*/
+class BitmapCache
+{
+public:
+ /** The key for looking up preview bitmaps is a pointer to an SdrPage
+ object. The prior use of PageObjectViewObjectContact objects (which
+ ultimately use them) turned out to be less suitable because their
+ life time is shorter then that of the page objects. Frequent
+ destruction and re-creation of the preview bitmaps was the result.
+ */
+ typedef const SdrPage* CacheKey;
+ class CacheEntry;
+ class CacheBitmapContainer;
+ typedef ::std::vector<CacheKey> CacheIndex;
+
+ /** Create a new cache for bitmap objects.
+ The default value from the configuration is used.
+ When that does not exist then an internal default value is
+ used.
+ */
+ explicit BitmapCache();
+
+ /** The destructor clears the cache and releases all bitmaps still in it.
+ */
+ ~BitmapCache();
+
+ /** Remove all preview bitmaps from the cache. After this call the
+ cache is empty.
+ */
+ void Clear();
+
+ /** Return <TRUE/> when the cache is full, i.e. the cache compactor had
+ to be run.
+ */
+ bool IsFull() const { return mbIsFull; }
+
+ /** Return the memory size that is occupied by all non-precious bitmaps
+ in the cache.
+ */
+ sal_Int32 GetSize() const { return mnNormalCacheSize; }
+
+ /** Return <TRUE/> when a preview bitmap exists for the given key.
+ */
+ bool HasBitmap(const CacheKey& rKey);
+
+ /** Return <TRUE/> when a preview bitmap exists for the given key and
+ when it is up-to-date.
+ */
+ bool BitmapIsUpToDate(const CacheKey& rKey);
+
+ /** Return the preview bitmap for the given contact object.
+ */
+ BitmapEx GetBitmap(const CacheKey& rKey);
+
+ /** Return the marked preview bitmap for the given contact object.
+ */
+ BitmapEx GetMarkedBitmap(const CacheKey& rKey);
+
+ /** Release the reference to the preview bitmap that is associated with
+ the given key.
+ */
+ void ReleaseBitmap(const CacheKey& rKey);
+
+ /** Mark the specified preview bitmap as not being up-to-date
+ anymore.
+ @return
+ When the key references a page in the cache then
+ return <TRUE/>. When the key is not known then <FALSE/>
+ is returned.
+ */
+ bool InvalidateBitmap(const CacheKey& rKey);
+
+ /** Mark all preview bitmaps as not being up-to-date anymore.
+ */
+ void InvalidateCache();
+
+ /** Add or replace a bitmap for the given key.
+ */
+ void SetBitmap(const CacheKey& rKey, const BitmapEx& rPreview, bool bIsPrecious);
+
+ /** Add or replace a marked bitmap for the given key.
+ */
+ void SetMarkedBitmap(const CacheKey& rKey, const BitmapEx& rPreview);
+
+ /** Mark the specified preview bitmap as precious, i.e. that it must not
+ be compressed or otherwise removed from the cache.
+ */
+ void SetPrecious(const CacheKey& rKey, bool bIsPrecious);
+
+ /** Calculate the cache size. This should rarely be necessary because
+ the cache size is tracked with each modification of preview
+ bitmaps.
+ */
+ void ReCalculateTotalCacheSize();
+
+ /** Use the previews in the given cache to initialize missing previews.
+ */
+ void Recycle(const BitmapCache& rCache);
+
+ /** Return a list of sorted cache keys that represent an index into (a
+ part of) the cache. The entries of the index are sorted according
+ to last access times with the least recently access time first.
+ Entries with the precious flag set are omitted.
+ Entries with that have no preview bitmaps are omitted.
+ */
+ CacheIndex GetCacheIndex() const;
+
+ /** Compress the specified preview bitmap with the given bitmap
+ compressor. A reference to the compressor is stored for later
+ decompression.
+ */
+ void Compress(const CacheKey& rKey, const std::shared_ptr<BitmapCompressor>& rpCompressor);
+
+private:
+ mutable ::osl::Mutex maMutex;
+
+ std::unique_ptr<CacheBitmapContainer> mpBitmapContainer;
+
+ /** Total size of bytes that are occupied by bitmaps in the cache for
+ whom the slides are currently not inside the visible area.
+ */
+ sal_Int32 mnNormalCacheSize;
+
+ /** Total size of bytes that are occupied by bitmaps in the cache for
+ whom the slides are currently visible.
+ */
+ sal_Int32 mnPreciousCacheSize;
+
+ /** At the moment the access time is not an actual time or date value
+ but a counter that is increased with every access. It thus defines
+ the same ordering as a true time.
+ */
+ sal_Int32 mnCurrentAccessTime;
+
+ /** The maximal cache size for the off-screen preview bitmaps. When
+ mnNormalCacheSize grows larger than this value then the
+ mpCacheCompactor member is used to reduce the cache size.
+ */
+ sal_Int32 mnMaximalNormalCacheSize;
+
+ /** The cache compactor is used to reduce the number of bytes used by
+ off-screen preview bitmaps.
+ */
+ ::std::unique_ptr<CacheCompactor> mpCacheCompactor;
+
+ /** This flag stores if the cache is or recently was full, i.e. the
+ cache compactor has or had to be run in order to reduce the cache
+ size to the allowed value.
+ */
+ bool mbIsFull;
+
+ /** Update mnNormalCacheSize or mnPreciousCacheSize according to the
+ precious flag of the specified preview bitmap and the specified
+ operation.
+ */
+ enum CacheOperation
+ {
+ ADD,
+ REMOVE
+ };
+ void UpdateCacheSize(const CacheEntry& rKey, CacheOperation eOperation);
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx
new file mode 100644
index 000000000..d4da935dd
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlsBitmapCompressor.hxx"
+
+#include <tools/stream.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/filter/PngImageReader.hxx>
+#include <vcl/pngwrite.hxx>
+
+namespace sd::slidesorter::cache {
+
+//===== NoBitmapCompression ===================================================
+
+/** This dummy replacement simply stores a shared pointer to the original
+ preview bitmap.
+*/
+class NoBitmapCompression::DummyReplacement
+ : public BitmapReplacement
+{
+public:
+ BitmapEx maPreview;
+
+ explicit DummyReplacement (const BitmapEx& rPreview) : maPreview(rPreview) { }
+ virtual ~DummyReplacement() {}
+ virtual sal_Int32 GetMemorySize() const override { return maPreview.GetSizeBytes(); }
+};
+
+std::shared_ptr<BitmapReplacement> NoBitmapCompression::Compress (const BitmapEx& rBitmap) const
+{
+ return std::make_shared<DummyReplacement>(rBitmap);
+}
+
+BitmapEx NoBitmapCompression::Decompress (const BitmapReplacement& rBitmapData) const
+{
+ return dynamic_cast<const DummyReplacement&>(rBitmapData).maPreview;
+}
+
+bool NoBitmapCompression::IsLossless() const
+{
+ return true;
+}
+
+//===== CompressionByDeletion =================================================
+
+std::shared_ptr<BitmapReplacement> CompressionByDeletion::Compress (const BitmapEx& ) const
+{
+ return std::shared_ptr<BitmapReplacement>();
+}
+
+BitmapEx CompressionByDeletion::Decompress (const BitmapReplacement& ) const
+{
+ // Return a NULL pointer. This will eventually lead to a request for
+ // the creation of a new one.
+ return BitmapEx();
+}
+
+bool CompressionByDeletion::IsLossless() const
+{
+ return false;
+}
+
+//===== ResolutionReduction ===================================================
+
+/** Store a scaled down bitmap together with the original size.
+*/
+class ResolutionReduction::ResolutionReducedReplacement : public BitmapReplacement
+{
+public:
+ BitmapEx maPreview;
+ Size maOriginalSize;
+
+ virtual ~ResolutionReducedReplacement();
+ virtual sal_Int32 GetMemorySize() const override;
+};
+
+ResolutionReduction::ResolutionReducedReplacement::~ResolutionReducedReplacement()
+{
+}
+
+sal_Int32 ResolutionReduction::ResolutionReducedReplacement::GetMemorySize() const
+{
+ return maPreview.GetSizeBytes();
+}
+
+std::shared_ptr<BitmapReplacement> ResolutionReduction::Compress (
+ const BitmapEx& rBitmap) const
+{
+ auto pResult = std::make_shared<ResolutionReducedReplacement>();
+ pResult->maPreview = rBitmap;
+ Size aSize (rBitmap.GetSizePixel());
+ pResult->maOriginalSize = aSize;
+ if (aSize.Width()>0 && aSize.Width()<mnWidth)
+ {
+ int nHeight = aSize.Height() * mnWidth / aSize.Width() ;
+ pResult->maPreview.Scale(Size(mnWidth,nHeight));
+ }
+
+ return pResult;
+}
+
+BitmapEx ResolutionReduction::Decompress (const BitmapReplacement& rBitmapData) const
+{
+ BitmapEx aResult;
+
+ const ResolutionReducedReplacement* pData (
+ dynamic_cast<const ResolutionReducedReplacement*>(&rBitmapData));
+
+ if ( pData && ! pData->maPreview.IsEmpty())
+ {
+ aResult = pData->maPreview;
+ if (pData->maOriginalSize.Width() > mnWidth)
+ aResult.Scale(pData->maOriginalSize);
+ }
+
+ return aResult;
+}
+
+bool ResolutionReduction::IsLossless() const
+{
+ return false;
+}
+
+//===== PNGCompression ========================================================
+
+class PngCompression::PngReplacement : public BitmapReplacement
+{
+public:
+ void* mpData;
+ sal_Int32 mnDataSize;
+ PngReplacement()
+ : mpData(nullptr),
+ mnDataSize(0)
+ {}
+ virtual ~PngReplacement()
+ {
+ delete [] static_cast<char*>(mpData);
+ }
+ virtual sal_Int32 GetMemorySize() const override
+ {
+ return mnDataSize;
+ }
+};
+
+std::shared_ptr<BitmapReplacement> PngCompression::Compress (const BitmapEx& rBitmap) const
+{
+ vcl::PNGWriter aWriter(rBitmap);
+ SvMemoryStream aStream (32768, 32768);
+ aWriter.Write(aStream);
+
+ auto pResult = std::make_shared<PngReplacement>();
+ pResult->mnDataSize = aStream.Tell();
+ pResult->mpData = new char[pResult->mnDataSize];
+ memcpy(pResult->mpData, aStream.GetData(), pResult->mnDataSize);
+
+ return pResult;
+}
+
+BitmapEx PngCompression::Decompress (
+ const BitmapReplacement& rBitmapData) const
+{
+ BitmapEx aResult;
+ const PngReplacement* pData (dynamic_cast<const PngReplacement*>(&rBitmapData));
+ if (pData != nullptr)
+ {
+ SvMemoryStream aStream (pData->mpData, pData->mnDataSize, StreamMode::READ);
+ vcl::PngImageReader aReader (aStream);
+ aResult = aReader.read().GetBitmap();
+ }
+
+ return aResult;
+}
+
+bool PngCompression::IsLossless() const
+{
+ return true;
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx
new file mode 100644
index 000000000..4754bead9
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <memory>
+
+class BitmapEx;
+
+namespace sd::slidesorter::cache
+{
+class BitmapReplacement;
+
+/** This interface class provides the minimal method set for classes that
+ implement the compression and decompression of preview bitmaps.
+*/
+class BitmapCompressor
+{
+public:
+ /** Compress the given bitmap into a replacement format that is specific
+ to the compressor class.
+ */
+ virtual std::shared_ptr<BitmapReplacement> Compress(const BitmapEx& rBitmap) const = 0;
+
+ /** Decompress the given replacement data into a preview bitmap.
+ Depending on the compression technique the returned bitmap may
+ differ from the original bitmap given to the Compress() method. It
+ may even of the wrong size or empty or the NULL pointer. It is the
+ task of the caller to create a new preview bitmap if the returned
+ one is not as desired.
+ */
+ virtual BitmapEx Decompress(const BitmapReplacement& rBitmapData) const = 0;
+
+ /** Return whether the compression and decompression is lossless. This
+ value is used by the caller of Decompress() to decide whether to use
+ the returned bitmap as is or if a new preview has to be created.
+ */
+ virtual bool IsLossless() const = 0;
+
+protected:
+ ~BitmapCompressor() {}
+};
+
+/** Interface for preview bitmap replacements. Each bitmap
+ compressor/decompressor has to provide an implementation that is
+ suitable to store the compressed bitmaps.
+*/
+class BitmapReplacement
+{
+public:
+ virtual sal_Int32 GetMemorySize() const { return 0; }
+
+protected:
+ ~BitmapReplacement() {}
+};
+
+/** This is one trivial bitmap compressor. It stores bitmaps unmodified
+ instead of compressing them.
+ This compressor is lossless.
+*/
+class NoBitmapCompression : public BitmapCompressor
+{
+ class DummyReplacement;
+
+public:
+ virtual ~NoBitmapCompression() {}
+ virtual std::shared_ptr<BitmapReplacement> Compress(const BitmapEx& rpBitmap) const override;
+ virtual BitmapEx Decompress(const BitmapReplacement& rBitmapData) const override;
+ virtual bool IsLossless() const override;
+};
+
+/** This is another trivial bitmap compressor. Instead of compressing a
+ bitmap, it throws the bitmap away. Its Decompress() method returns a
+ NULL pointer. The caller has to create a new preview bitmap instead.
+ This compressor clearly is not lossless.
+*/
+class CompressionByDeletion : public BitmapCompressor
+{
+public:
+ virtual ~CompressionByDeletion() {}
+ virtual std::shared_ptr<BitmapReplacement> Compress(const BitmapEx& rBitmap) const override;
+ virtual BitmapEx Decompress(const BitmapReplacement& rBitmapData) const override;
+ virtual bool IsLossless() const override;
+};
+
+/** Compress a preview bitmap by reducing its resolution. While the aspect
+ ratio is maintained the horizontal resolution is scaled down to 100
+ pixels.
+ This compressor is not lossless.
+*/
+class ResolutionReduction : public BitmapCompressor
+{
+ class ResolutionReducedReplacement;
+ static const sal_Int32 mnWidth = 100;
+
+public:
+ virtual ~ResolutionReduction() {}
+ virtual std::shared_ptr<BitmapReplacement> Compress(const BitmapEx& rpBitmap) const override;
+ /** Scale the replacement bitmap up to the original size.
+ */
+ virtual BitmapEx Decompress(const BitmapReplacement& rBitmapData) const override;
+ virtual bool IsLossless() const override;
+};
+
+/** Compress preview bitmaps using the PNG format.
+ This compressor is lossless.
+*/
+class PngCompression : public BitmapCompressor
+{
+ class PngReplacement;
+
+public:
+ virtual ~PngCompression() {}
+ virtual std::shared_ptr<BitmapReplacement> Compress(const BitmapEx& rBitmap) const override;
+ virtual BitmapEx Decompress(const BitmapReplacement& rBitmapData) const override;
+ virtual bool IsLossless() const override;
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx
new file mode 100644
index 000000000..a9182c2a2
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.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 "SlsBitmapFactory.hxx"
+
+#include <PreviewRenderer.hxx>
+#include <sdpage.hxx>
+#include <vcl/bitmapex.hxx>
+
+namespace sd::slidesorter::view {
+class SlideSorterView;
+class PageObjectViewObjectContact;
+}
+
+namespace sd::slidesorter::cache {
+
+BitmapFactory::BitmapFactory()
+ : maRenderer(false)
+{
+}
+
+BitmapFactory::~BitmapFactory()
+{
+}
+
+BitmapEx BitmapFactory::CreateBitmap (
+ const SdPage& rPage,
+ const Size& rPixelSize,
+ const bool bDoSuperSampling)
+{
+ Size aSize (rPixelSize);
+ if (bDoSuperSampling)
+ {
+ // Supersampling factor
+ int aSuperSamplingFactor = 2;
+ aSize.setWidth( aSize.Width() * aSuperSamplingFactor );
+ aSize.setHeight( aSize.Height() * aSuperSamplingFactor );
+ }
+
+ BitmapEx aPreview (maRenderer.RenderPage (
+ &rPage,
+ aSize,
+ true,
+ false).GetBitmapEx());
+ if (bDoSuperSampling)
+ {
+ aPreview.Scale(rPixelSize, BmpScaleFlag::BestQuality);
+ }
+
+ return aPreview;
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx
new file mode 100644
index 000000000..c1733b825
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <PreviewRenderer.hxx>
+
+class SdPage;
+class Size;
+
+namespace sd::slidesorter::cache
+{
+/** This factory class creates preview bitmaps for page objects. It is
+ merely an adapter for the PreviewRenderer.
+*/
+class BitmapFactory
+{
+public:
+ BitmapFactory();
+ ~BitmapFactory();
+
+ BitmapEx CreateBitmap(const SdPage& rPage, const Size& rPixelSize, const bool bDoSuperSampling);
+
+private:
+ PreviewRenderer maRenderer;
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx
new file mode 100644
index 000000000..79ab9fab2
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "SlsCacheCompactor.hxx"
+
+#include "SlsBitmapCompressor.hxx"
+#include "SlsBitmapCache.hxx"
+#include "SlsCacheConfiguration.hxx"
+
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/uno/Any.hxx>
+
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+/** This is a trivial implementation of the CacheCompactor interface class.
+ It ignores calls to RequestCompaction() and thus will never decrease the
+ total size of off-screen preview bitmaps.
+*/
+class NoCacheCompaction
+ : public ::sd::slidesorter::cache::CacheCompactor
+{
+public:
+ NoCacheCompaction (
+ ::sd::slidesorter::cache::BitmapCache& rCache,
+ sal_Int32 nMaximalCacheSize)
+ : CacheCompactor(rCache, nMaximalCacheSize)
+ {}
+
+ virtual void RequestCompaction() override { /* Ignored */ };
+
+protected:
+ virtual void Run() override { /* Do nothing */ };
+};
+
+/** This implementation of the CacheCompactor interface class uses one of
+ several bitmap compression algorithms to reduce the number of the bytes
+ of the off-screen previews in the bitmap cache. See the documentation
+ of CacheCompactor::Create() for more details on configuration properties
+ that control the choice of compression algorithm.
+*/
+class CacheCompactionByCompression
+ : public ::sd::slidesorter::cache::CacheCompactor
+{
+public:
+ CacheCompactionByCompression (
+ ::sd::slidesorter::cache::BitmapCache& rCache,
+ sal_Int32 nMaximalCacheSize,
+ const std::shared_ptr< ::sd::slidesorter::cache::BitmapCompressor>& rpCompressor);
+
+protected:
+ virtual void Run() override;
+
+private:
+ std::shared_ptr< ::sd::slidesorter::cache::BitmapCompressor> mpCompressor;
+};
+
+} // end of anonymous namespace
+
+namespace sd::slidesorter::cache {
+
+::std::unique_ptr<CacheCompactor> CacheCompactor::Create (
+ BitmapCache& rCache,
+ sal_Int32 nMaximalCacheSize)
+{
+ static const char sNone[] = "None";
+
+ std::shared_ptr<BitmapCompressor> pCompressor;
+ OUString sCompressionPolicy("PNGCompression");
+ Any aCompressionPolicy (CacheConfiguration::Instance()->GetValue("CompressionPolicy"));
+ if (aCompressionPolicy.has<OUString>())
+ aCompressionPolicy >>= sCompressionPolicy;
+ if (sCompressionPolicy == sNone)
+ pCompressor = std::make_shared<NoBitmapCompression>();
+ else if (sCompressionPolicy == "Erase")
+ pCompressor = std::make_shared<CompressionByDeletion>();
+ else if (sCompressionPolicy == "ResolutionReduction")
+ pCompressor = std::make_shared<ResolutionReduction>();
+ else
+ pCompressor = std::make_shared<PngCompression>();
+
+ ::std::unique_ptr<CacheCompactor> pCompactor;
+ OUString sCompactionPolicy("Compress");
+ Any aCompactionPolicy (CacheConfiguration::Instance()->GetValue("CompactionPolicy"));
+ if (aCompactionPolicy.has<OUString>())
+ aCompactionPolicy >>= sCompactionPolicy;
+ if (sCompactionPolicy == sNone)
+ pCompactor.reset(new NoCacheCompaction(rCache,nMaximalCacheSize));
+ else
+ pCompactor.reset(new CacheCompactionByCompression(rCache,nMaximalCacheSize,pCompressor));
+
+ return pCompactor;
+}
+
+void CacheCompactor::RequestCompaction()
+{
+ if ( ! mbIsCompactionRunning && ! maCompactionTimer.IsActive())
+ maCompactionTimer.Start();
+}
+
+CacheCompactor::CacheCompactor(
+ BitmapCache& rCache,
+ sal_Int32 nMaximalCacheSize)
+ : mrCache(rCache),
+ mnMaximalCacheSize(nMaximalCacheSize),
+ maCompactionTimer("sd CacheCompactor maCompactionTimer"),
+ mbIsCompactionRunning(false)
+{
+ maCompactionTimer.SetTimeout(100);
+ maCompactionTimer.SetInvokeHandler(LINK(this,CacheCompactor,CompactionCallback));
+}
+
+IMPL_LINK_NOARG(CacheCompactor, CompactionCallback, Timer *, void)
+{
+ mbIsCompactionRunning = true;
+
+ try
+ {
+ Run();
+ }
+ catch (const css::uno::RuntimeException&)
+ {
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+
+ mbIsCompactionRunning = false;
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+namespace {
+
+//===== CacheCompactionByCompression ==========================================
+
+CacheCompactionByCompression::CacheCompactionByCompression (
+ ::sd::slidesorter::cache::BitmapCache& rCache,
+ sal_Int32 nMaximalCacheSize,
+ const std::shared_ptr< ::sd::slidesorter::cache::BitmapCompressor>& rpCompressor)
+ : CacheCompactor(rCache,nMaximalCacheSize),
+ mpCompressor(rpCompressor)
+{
+}
+
+void CacheCompactionByCompression::Run()
+{
+ if (mrCache.GetSize() <= mnMaximalCacheSize)
+ return;
+
+ SAL_INFO("sd.sls", __func__ << ": bitmap cache uses too much space: " << mrCache.GetSize() << " > " << mnMaximalCacheSize);
+
+ ::sd::slidesorter::cache::BitmapCache::CacheIndex aIndex (
+ mrCache.GetCacheIndex());
+ for (const auto& rpIndex : aIndex)
+ {
+ if (rpIndex == nullptr)
+ continue;
+
+ mrCache.Compress(rpIndex, mpCompressor);
+ if (mrCache.GetSize() < mnMaximalCacheSize)
+ break;
+ }
+ mrCache.ReCalculateTotalCacheSize();
+ SAL_INFO("sd.sls", __func__ << ": there are now " << mrCache.GetSize() << " bytes occupied");
+}
+
+} // end of anonymous namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx
new file mode 100644
index 000000000..d694ae1a1
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <vcl/timer.hxx>
+#include <memory>
+
+namespace sd::slidesorter::cache {
+
+class BitmapCache;
+
+/** This is an interface class whose implementations are created via the
+ Create() factory method.
+*/
+class CacheCompactor
+{
+public:
+ virtual ~CacheCompactor() {};
+
+ /** Create a new instance of the CacheCompactor interface class. The
+ type of compaction algorithm used depends on values from the
+ configuration: the SlideSorter/PreviewCache/CompactionPolicy
+ property of the Impress.xcs file currently supports the values
+ "None" and "Compress". With the later the CompressionPolicy
+ property is evaluated which implementation of the BitmapCompress
+ interface class to use as bitmap compressor.
+ @param rCache
+ The bitmap cache on which to operate.
+ @param nMaximalCacheSize
+ The total number of bytes the off-screen bitmaps in the cache
+ may have. When the Run() method is (indirectly) called the
+ compactor tries to reduce that summed size of off-screen bitmaps
+ under this number. However, it is not guaranteed that this
+ works in all cases.
+ */
+ static ::std::unique_ptr<CacheCompactor> Create (
+ BitmapCache& rCache,
+ sal_Int32 nMaximalCacheSize);
+
+ /** Request a compaction of the off-screen previews in the bitmap
+ cache. This calls via a timer the Run() method.
+ */
+ virtual void RequestCompaction();
+
+protected:
+ BitmapCache& mrCache;
+ sal_Int32 mnMaximalCacheSize;
+
+ CacheCompactor(
+ BitmapCache& rCache,
+ sal_Int32 nMaximalCacheSize);
+
+ /** This method actually tries to reduce the total number of bytes used
+ by the off-screen preview bitmaps.
+ */
+ virtual void Run() = 0;
+
+private:
+ /** This timer is used to collect calls to RequestCompaction() and
+ eventually call Run().
+ */
+ Timer maCompactionTimer;
+ bool mbIsCompactionRunning;
+ DECL_LINK(CompactionCallback, Timer *, void);
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx
new file mode 100644
index 000000000..fd08c7627
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlsCacheConfiguration.hxx"
+#include <vcl/svapp.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::slidesorter::cache {
+
+namespace
+{
+ typedef std::shared_ptr<CacheConfiguration> CacheConfigSharedPtr;
+ CacheConfigSharedPtr& theInstance()
+ {
+ static CacheConfigSharedPtr SINGLETON;
+ return SINGLETON;
+ }
+}
+
+std::weak_ptr<CacheConfiguration> CacheConfiguration::mpWeakInstance;
+
+std::shared_ptr<CacheConfiguration> CacheConfiguration::Instance()
+{
+ SolarMutexGuard aSolarGuard;
+ CacheConfigSharedPtr &rInstancePtr = theInstance();
+ if (!rInstancePtr)
+ {
+ // Maybe somebody else kept a previously created instance alive.
+ if ( ! mpWeakInstance.expired())
+ rInstancePtr = std::shared_ptr<CacheConfiguration>(mpWeakInstance);
+ if (!rInstancePtr)
+ {
+ // We have to create a new instance.
+ rInstancePtr.reset(new CacheConfiguration());
+ mpWeakInstance = rInstancePtr;
+ // Prepare to release this instance in the near future.
+ rInstancePtr->m_ReleaseTimer.SetInvokeHandler(
+ LINK(rInstancePtr.get(),CacheConfiguration,TimerCallback));
+ rInstancePtr->m_ReleaseTimer.SetTimeout(5000 /* 5s */);
+ rInstancePtr->m_ReleaseTimer.Start();
+ }
+ }
+ return rInstancePtr;
+}
+
+CacheConfiguration::CacheConfiguration()
+ : m_ReleaseTimer("sd::CacheConfiguration maReleaseTimer")
+{
+ // Get the cache size from configuration.
+ try
+ {
+ // Obtain access to the configuration.
+ Reference<lang::XMultiServiceFactory> xProvider =
+ configuration::theDefaultProvider::get( ::comphelper::getProcessComponentContext() );
+
+ // Obtain access to Impress configuration.
+ Sequence<Any> aCreationArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", Any(OUString("/org.openoffice.Office.Impress/"))},
+ {"depth", Any(sal_Int32(-1))}
+ }));
+
+ Reference<XInterface> xRoot (xProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aCreationArguments));
+ if ( ! xRoot.is())
+ return;
+ Reference<container::XHierarchicalNameAccess> xHierarchy (xRoot, UNO_QUERY);
+ if ( ! xHierarchy.is())
+ return;
+
+ // Get the node for the slide sorter preview cache.
+ mxCacheNode.set( xHierarchy->getByHierarchicalName("MultiPaneGUI/SlideSorter/PreviewCache"), UNO_QUERY);
+ }
+ catch (RuntimeException &)
+ {
+ }
+ catch (Exception &)
+ {
+ }
+}
+
+Any CacheConfiguration::GetValue (const OUString& rName)
+{
+ Any aResult;
+
+ if (mxCacheNode != nullptr)
+ {
+ try
+ {
+ aResult = mxCacheNode->getByName(rName);
+ }
+ catch (Exception &)
+ {
+ }
+ }
+
+ return aResult;
+}
+
+IMPL_STATIC_LINK_NOARG(CacheConfiguration, TimerCallback, Timer *, void)
+{
+ CacheConfigSharedPtr &rInstancePtr = theInstance();
+ // Release our reference to the instance.
+ rInstancePtr.reset();
+ // note: if there are no other references to the instance, m_ReleaseTimer
+ // will be deleted now
+}
+
+void CacheConfiguration::Shutdown()
+{
+ CacheConfigSharedPtr &rInstancePtr = theInstance();
+ rInstancePtr.reset();
+ assert(mpWeakInstance.expired()); // ensure m_ReleaseTimer is destroyed
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx
new file mode 100644
index 000000000..d53bcd713
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Any.hxx>
+#include <vcl/timer.hxx>
+#include <memory>
+
+namespace com::sun::star::container
+{
+class XNameAccess;
+}
+
+namespace sd::slidesorter::cache
+{
+/** A very simple and easy-to-use access to configuration entries regarding
+ the slide sorter cache.
+*/
+class CacheConfiguration
+{
+public:
+ /** Return an instance to this class. The reference is released after 5
+ seconds. Subsequent calls to this function will create a new
+ instance.
+ */
+ static std::shared_ptr<CacheConfiguration> Instance();
+
+ static void Shutdown();
+
+ /** Look up the specified value in
+ MultiPaneGUI/SlideSorter/PreviewCache. When the specified value
+ does not exist then an empty Any is returned.
+ */
+ css::uno::Any GetValue(const OUString& rName);
+
+private:
+ /** When a caller holds a reference after we have released ours we use
+ this weak pointer to avoid creating a new instance.
+ */
+ static std::weak_ptr<CacheConfiguration> mpWeakInstance;
+ Timer m_ReleaseTimer;
+ css::uno::Reference<css::container::XNameAccess> mxCacheNode;
+
+ CacheConfiguration();
+
+ DECL_STATIC_LINK(CacheConfiguration, TimerCallback, Timer*, void);
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx
new file mode 100644
index 000000000..6275754fa
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx
@@ -0,0 +1,278 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlsGenericPageCache.hxx"
+
+#include "SlsQueueProcessor.hxx"
+#include "SlsRequestPriorityClass.hxx"
+#include "SlsRequestFactory.hxx"
+#include "SlsBitmapCache.hxx"
+#include <cache/SlsPageCacheManager.hxx>
+#include <tools/debug.hxx>
+
+namespace sd::slidesorter::cache {
+
+GenericPageCache::GenericPageCache (
+ const Size& rPreviewSize,
+ const bool bDoSuperSampling,
+ const SharedCacheContext& rpCacheContext)
+ : maRequestQueue(rpCacheContext),
+ mpCacheContext(rpCacheContext),
+ maPreviewSize(rPreviewSize),
+ mbDoSuperSampling(bDoSuperSampling)
+{
+ // A large size may indicate an error of the caller. After all we
+ // are creating previews.
+ DBG_ASSERT (maPreviewSize.Width()<1000 && maPreviewSize.Height()<1000,
+ "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. "
+ "This may indicate an error.");
+}
+
+GenericPageCache::~GenericPageCache()
+{
+ if (mpQueueProcessor != nullptr)
+ mpQueueProcessor->Stop();
+ maRequestQueue.Clear();
+ mpQueueProcessor.reset();
+
+ if (mpBitmapCache != nullptr)
+ PageCacheManager::Instance()->ReleaseCache(mpBitmapCache);
+ mpBitmapCache.reset();
+}
+
+void GenericPageCache::ProvideCacheAndProcessor()
+{
+ if (mpBitmapCache == nullptr)
+ mpBitmapCache = PageCacheManager::Instance()->GetCache(
+ mpCacheContext->GetModel(),
+ maPreviewSize);
+
+ if (mpQueueProcessor == nullptr)
+ mpQueueProcessor.reset(new QueueProcessor(
+ maRequestQueue,
+ mpBitmapCache,
+ maPreviewSize,
+ mbDoSuperSampling,
+ mpCacheContext));
+}
+
+void GenericPageCache::ChangePreviewSize (
+ const Size& rPreviewSize,
+ const bool bDoSuperSampling)
+{
+ if (rPreviewSize==maPreviewSize && bDoSuperSampling==mbDoSuperSampling)
+ return;
+
+ // A large size may indicate an error of the caller. After all we
+ // are creating previews.
+ DBG_ASSERT (maPreviewSize.Width()<1000 && maPreviewSize.Height()<1000,
+ "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. "
+ "This may indicate an error.");
+
+ if (mpBitmapCache != nullptr)
+ {
+ mpBitmapCache = PageCacheManager::Instance()->ChangeSize(
+ mpBitmapCache, maPreviewSize, rPreviewSize);
+ if (mpQueueProcessor != nullptr)
+ {
+ mpQueueProcessor->SetPreviewSize(rPreviewSize, bDoSuperSampling);
+ mpQueueProcessor->SetBitmapCache(mpBitmapCache);
+ }
+ }
+ maPreviewSize = rPreviewSize;
+ mbDoSuperSampling = bDoSuperSampling;
+}
+
+BitmapEx GenericPageCache::GetPreviewBitmap (
+ const CacheKey aKey,
+ const bool bResize)
+{
+ assert(aKey != nullptr);
+
+ BitmapEx aPreview;
+ bool bMayBeUpToDate = true;
+ ProvideCacheAndProcessor();
+ const SdrPage* pPage = mpCacheContext->GetPage(aKey);
+ if (mpBitmapCache->HasBitmap(pPage))
+ {
+ aPreview = mpBitmapCache->GetBitmap(pPage);
+ const Size aBitmapSize (aPreview.GetSizePixel());
+ if (aBitmapSize != maPreviewSize)
+ {
+ // Scale the bitmap to the desired size when that is possible,
+ // i.e. the bitmap is not empty.
+ if (bResize && !aBitmapSize.IsEmpty())
+ {
+ aPreview.Scale(maPreviewSize);
+ }
+ bMayBeUpToDate = false;
+ }
+ else
+ bMayBeUpToDate = true;
+ }
+ else
+ bMayBeUpToDate = false;
+
+ // Request the creation of a correctly sized preview bitmap. We do this
+ // even when the size of the bitmap in the cache is correct because its
+ // content may be not up-to-date anymore.
+ RequestPreviewBitmap(aKey, bMayBeUpToDate);
+
+ return aPreview;
+}
+
+BitmapEx GenericPageCache::GetMarkedPreviewBitmap (
+ const CacheKey aKey)
+{
+ assert(aKey != nullptr);
+
+ ProvideCacheAndProcessor();
+ const SdrPage* pPage = mpCacheContext->GetPage(aKey);
+ BitmapEx aMarkedPreview (mpBitmapCache->GetMarkedBitmap(pPage));
+
+ return aMarkedPreview;
+}
+
+void GenericPageCache::SetMarkedPreviewBitmap (
+ const CacheKey aKey,
+ const BitmapEx& rMarkedBitmap)
+{
+ assert(aKey != nullptr);
+
+ ProvideCacheAndProcessor();
+ const SdrPage* pPage = mpCacheContext->GetPage(aKey);
+ mpBitmapCache->SetMarkedBitmap(pPage, rMarkedBitmap);
+}
+
+void GenericPageCache::RequestPreviewBitmap (
+ const CacheKey aKey,
+ const bool bMayBeUpToDate)
+{
+ assert(aKey != nullptr);
+
+ const SdrPage* pPage = mpCacheContext->GetPage(aKey);
+
+ ProvideCacheAndProcessor();
+
+ // Determine if the available bitmap is up to date.
+ bool bIsUpToDate = false;
+ if (bMayBeUpToDate)
+ bIsUpToDate = mpBitmapCache->BitmapIsUpToDate (pPage);
+ if (bIsUpToDate)
+ {
+ const BitmapEx aPreview (mpBitmapCache->GetBitmap(pPage));
+ if (aPreview.IsEmpty() || aPreview.GetSizePixel()!=maPreviewSize)
+ bIsUpToDate = false;
+ }
+
+ if ( bIsUpToDate)
+ return;
+
+ // No, the bitmap is not up-to-date. Request a new one.
+ RequestPriorityClass ePriorityClass (NOT_VISIBLE);
+ if (mpCacheContext->IsVisible(aKey))
+ {
+ if (mpBitmapCache->HasBitmap(pPage))
+ ePriorityClass = VISIBLE_OUTDATED_PREVIEW;
+ else
+ ePriorityClass = VISIBLE_NO_PREVIEW;
+ }
+ maRequestQueue.AddRequest(aKey, ePriorityClass);
+ mpQueueProcessor->Start(ePriorityClass);
+}
+
+bool GenericPageCache::InvalidatePreviewBitmap (const CacheKey aKey)
+{
+ // Invalidate the page in all caches that reference it, not just this one.
+ std::shared_ptr<cache::PageCacheManager> pCacheManager (
+ cache::PageCacheManager::Instance());
+ if (pCacheManager)
+ return pCacheManager->InvalidatePreviewBitmap(
+ mpCacheContext->GetModel(),
+ aKey);
+ else if (mpBitmapCache != nullptr)
+ return mpBitmapCache->InvalidateBitmap(mpCacheContext->GetPage(aKey));
+ else
+ return false;
+}
+
+void GenericPageCache::InvalidateCache ()
+{
+ if (!mpBitmapCache)
+ return;
+
+ // When the cache is being invalidated then it makes no sense to
+ // continue creating preview bitmaps. However, this may be
+ // re-started below.
+ mpQueueProcessor->Stop();
+ maRequestQueue.Clear();
+
+ // Mark the previews in the cache as not being up-to-date anymore.
+ // Depending on the given bUpdateCache flag we start to create new
+ // preview bitmaps.
+ mpBitmapCache->InvalidateCache();
+ RequestFactory()(maRequestQueue, mpCacheContext);
+}
+
+void GenericPageCache::SetPreciousFlag (
+ const CacheKey aKey,
+ const bool bIsPrecious)
+{
+ ProvideCacheAndProcessor();
+
+ // Change the request priority class according to the new precious flag.
+ if (bIsPrecious)
+ {
+ if (mpBitmapCache->HasBitmap(mpCacheContext->GetPage(aKey)))
+ maRequestQueue.ChangeClass(aKey,VISIBLE_OUTDATED_PREVIEW);
+ else
+ maRequestQueue.ChangeClass(aKey,VISIBLE_NO_PREVIEW);
+ }
+ else
+ {
+ if (mpBitmapCache->IsFull())
+ {
+ // When the bitmap cache is full then requests for slides that
+ // are not visible are removed.
+ maRequestQueue.RemoveRequest(aKey);
+ }
+ else
+ maRequestQueue.ChangeClass(aKey,NOT_VISIBLE);
+ }
+
+ mpBitmapCache->SetPrecious(mpCacheContext->GetPage(aKey), bIsPrecious);
+}
+
+void GenericPageCache::Pause()
+{
+ ProvideCacheAndProcessor();
+ if (mpQueueProcessor != nullptr)
+ mpQueueProcessor->Pause();
+}
+
+void GenericPageCache::Resume()
+{
+ ProvideCacheAndProcessor();
+ if (mpQueueProcessor != nullptr)
+ mpQueueProcessor->Resume();
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx
new file mode 100644
index 000000000..900d40268
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "SlsRequestQueue.hxx"
+#include <memory>
+
+#include <vcl/bitmapex.hxx>
+
+namespace sd::slidesorter::cache {
+
+class BitmapCache;
+class QueueProcessor;
+
+/** This basically is the implementation class for the PageCache class.
+*/
+class GenericPageCache
+{
+public:
+ /** The page cache is created with a reference to the SlideSorter and
+ thus has access to both view and model. This allows the cache to
+ fill itself with requests for all pages or just the visible ones.
+ @param rPreviewSize
+ The size of the previews is expected in pixel values.
+ @param bDoSuperSampling
+ When <TRUE/> the previews are rendered larger and then scaled
+ down to the requested size to improve image quality.
+ */
+ GenericPageCache (
+ const Size& rPreviewSize,
+ const bool bDoSuperSampling,
+ const SharedCacheContext& rpCacheContext);
+
+ ~GenericPageCache();
+
+ /** Change the size of the preview bitmaps. This may be caused by a
+ resize of the slide sorter window or a change of the number of
+ columns.
+ */
+ void ChangePreviewSize (
+ const Size& rPreviewSize,
+ const bool bDoSuperSampling);
+
+ /** Request a preview bitmap for the specified page object in the
+ specified size. The returned bitmap may be a preview of the preview,
+ i.e. either a scaled (up or down) version of a previous preview (of
+ the wrong size) or an empty bitmap. In this case a request for the
+ generation of a new preview is created and inserted into the request
+ queue. When the preview is available the page shape will be told to
+ paint itself again. When it then calls this method again if
+ receives the correctly sized preview bitmap.
+ @param rRequestData
+ This data is used to determine the preview.
+ @param bResize
+ When <TRUE/> then when the available bitmap has not the
+ requested size, it is scaled before it is returned. When
+ <FALSE/> then the bitmap is returned in the wrong size and it is
+ the task of the caller to scale it.
+ @return
+ Returns a bitmap that is either empty, contains a scaled (up or
+ down) version or is the requested bitmap.
+ */
+ BitmapEx GetPreviewBitmap (
+ const CacheKey aKey,
+ const bool bResize);
+ BitmapEx GetMarkedPreviewBitmap (
+ const CacheKey aKey);
+ void SetMarkedPreviewBitmap (
+ const CacheKey aKey,
+ const BitmapEx& rMarkedBitmap);
+
+ /** When the requested preview bitmap does not yet exist or is not
+ up-to-date then the rendering of one is scheduled. Otherwise this
+ method does nothing.
+ @param rRequestData
+ This data is used to determine the preview.
+ @param bMayBeUpToDate
+ This flag helps the method to determine whether an existing
+ preview that matches the request is up to date. If the caller
+ knows that it is not then by passing <FALSE/> he tells us that we
+ do not have to check the up-to-date flag a second time. If
+ unsure use <TRUE/>.
+ */
+ void RequestPreviewBitmap (
+ const CacheKey aKey,
+ const bool bMayBeUpToDate);
+
+ /** Tell the cache to replace the bitmap associated with the given
+ request data with a new one that reflects recent changes in the
+ content of the page object.
+ @return
+ When the key is known then return <TRUE/>.
+ */
+ bool InvalidatePreviewBitmap (const CacheKey aKey);
+
+ /** Call this method when all preview bitmaps have to be generated anew.
+ This is the case when the size of the page objects on the screen has
+ changed or when the model has changed.
+ */
+ void InvalidateCache ();
+
+ /** With the precious flag you can control whether a bitmap can be
+ removed from the cache or reduced in size to make room for other
+ bitmaps or is so precious that it will not be touched. A typical
+ use is to set the precious flag for the visible pages.
+ */
+ void SetPreciousFlag (const CacheKey aKey, const bool bIsPrecious);
+
+ void Pause();
+ void Resume();
+
+private:
+ std::shared_ptr<BitmapCache> mpBitmapCache;
+
+ RequestQueue maRequestQueue;
+
+ std::unique_ptr<QueueProcessor> mpQueueProcessor;
+
+ SharedCacheContext mpCacheContext;
+
+ /** The current size of preview bitmaps.
+ */
+ Size maPreviewSize;
+
+ bool mbDoSuperSampling;
+
+ /** Both bitmap cache and queue processor are created on demand by this
+ method.
+ */
+ void ProvideCacheAndProcessor();
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsPageCache.cxx b/sd/source/ui/slidesorter/cache/SlsPageCache.cxx
new file mode 100644
index 000000000..82b1b8ae4
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsPageCache.cxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/gen.hxx>
+#include "SlsGenericPageCache.hxx"
+#include <cache/SlsPageCache.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd::slidesorter::cache {
+
+//===== PageCache =============================================================
+
+PageCache::PageCache (
+ const Size& rPreviewSize,
+ const bool bDoSuperSampling,
+ const SharedCacheContext& rpCacheContext)
+ : mpImplementation(
+ new GenericPageCache(
+ rPreviewSize,
+ bDoSuperSampling,
+ rpCacheContext))
+{
+}
+
+PageCache::~PageCache()
+{
+}
+
+void PageCache::ChangeSize (
+ const Size& rPreviewSize,
+ const bool bDoSuperSampling)
+{
+ mpImplementation->ChangePreviewSize(rPreviewSize, bDoSuperSampling);
+}
+
+BitmapEx PageCache::GetPreviewBitmap (
+ const CacheKey aKey,
+ const bool bResize)
+{
+ return mpImplementation->GetPreviewBitmap(aKey, bResize);
+}
+
+BitmapEx PageCache::GetMarkedPreviewBitmap (
+ const CacheKey aKey)
+{
+ return mpImplementation->GetMarkedPreviewBitmap(aKey);
+}
+
+void PageCache::SetMarkedPreviewBitmap (
+ const CacheKey aKey,
+ const BitmapEx& rMarkedBitmap)
+{
+ mpImplementation->SetMarkedPreviewBitmap(aKey, rMarkedBitmap);
+}
+
+void PageCache::RequestPreviewBitmap (const CacheKey aKey)
+{
+ return mpImplementation->RequestPreviewBitmap(aKey, true);
+}
+
+void PageCache::InvalidatePreviewBitmap (
+ const CacheKey aKey)
+{
+ if (mpImplementation->InvalidatePreviewBitmap(aKey))
+ RequestPreviewBitmap(aKey);
+}
+
+void PageCache::InvalidateCache()
+{
+ mpImplementation->InvalidateCache();
+}
+
+void PageCache::SetPreciousFlag (
+ const CacheKey aKey,
+ const bool bIsPrecious)
+{
+ mpImplementation->SetPreciousFlag(aKey, bIsPrecious);
+}
+
+void PageCache::Pause()
+{
+ mpImplementation->Pause();
+}
+
+void PageCache::Resume()
+{
+ mpImplementation->Resume();
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx b/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx
new file mode 100644
index 000000000..45afd93c9
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx
@@ -0,0 +1,420 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cache/SlsPageCacheManager.hxx>
+
+#include "SlsBitmapCache.hxx"
+
+#include <deque>
+#include <map>
+#include <memory>
+#include <unordered_map>
+
+namespace {
+
+/** Collection of data that is stored for all active preview caches.
+*/
+class CacheDescriptor
+{
+public:
+ ::sd::slidesorter::cache::PageCacheManager::DocumentKey mpDocument;
+ Size maPreviewSize;
+
+ CacheDescriptor(
+ ::sd::slidesorter::cache::PageCacheManager::DocumentKey const & pDocument,
+ const Size& rPreviewSize)
+ :mpDocument(pDocument),maPreviewSize(rPreviewSize)
+ {}
+ /// Test for equality with respect to all members.
+ class Equal {public: bool operator() (
+ const CacheDescriptor& rDescriptor1, const CacheDescriptor& rDescriptor2) const {
+ return rDescriptor1.mpDocument==rDescriptor2.mpDocument
+ && rDescriptor1.maPreviewSize==rDescriptor2.maPreviewSize;
+ } };
+ /// Hash function that takes all members into account.
+ class Hash {public: size_t operator() (const CacheDescriptor& rDescriptor) const {
+ return reinterpret_cast<size_t>(rDescriptor.mpDocument.get()) + rDescriptor.maPreviewSize.Width();
+ } };
+};
+
+/** Collection of data that is stored for the inactive, recently used
+ caches.
+*/
+class RecentlyUsedCacheDescriptor
+{
+public:
+ Size maPreviewSize;
+ std::shared_ptr< ::sd::slidesorter::cache::BitmapCache> mpCache;
+
+ RecentlyUsedCacheDescriptor(
+ const Size& rPreviewSize,
+ const std::shared_ptr< ::sd::slidesorter::cache::BitmapCache>& rpCache)
+ :maPreviewSize(rPreviewSize),mpCache(rpCache)
+ {}
+};
+
+/** The list of recently used caches is organized as queue. When elements
+ are added the list is shortened to the maximally allowed number of
+ elements by removing the least recently used elements.
+*/
+typedef ::std::deque<RecentlyUsedCacheDescriptor> RecentlyUsedQueue;
+
+/** Compare the caches by preview size. Those that match the given size
+ come first, then, regardless of the given size, the largest ones before
+ the smaller ones.
+*/
+class BestFittingCacheComparer
+{
+public:
+ explicit BestFittingCacheComparer (const Size& rPreferredSize)
+ : maPreferredSize(rPreferredSize)
+ {}
+ bool operator()(const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement1,
+ const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement2)
+ {
+ if (rElement2.first == maPreferredSize)
+ return false;
+ else if (rElement1.first == maPreferredSize)
+ return true;
+ else
+ return (rElement1.first.Width()*rElement1.first.Height()
+ > rElement2.first.Width()*rElement2.first.Height());
+ }
+
+private:
+ Size maPreferredSize;
+};
+
+} // end of anonymous namespace
+
+namespace sd::slidesorter::cache {
+
+/** Container for the active caches.
+*/
+class PageCacheManager::PageCacheContainer
+ : public std::unordered_map<CacheDescriptor,
+ std::shared_ptr<BitmapCache>,
+ CacheDescriptor::Hash,
+ CacheDescriptor::Equal>
+{
+public:
+ PageCacheContainer() {}
+
+ /** Compare entries in the cache container with respect to the cache
+ address only.
+ */
+ class CompareWithCache { public:
+ explicit CompareWithCache(const std::shared_ptr<BitmapCache>& rpCache)
+ : mpCache(rpCache) {}
+ bool operator () (const PageCacheContainer::value_type& rValue) const
+ { return rValue.second == mpCache; }
+ private:
+ std::shared_ptr<BitmapCache> mpCache;
+ };
+};
+
+/** The recently used caches are stored in one queue for each document.
+*/
+class PageCacheManager::RecentlyUsedPageCaches
+{
+public:
+ typedef DocumentKey key_type;
+ typedef RecentlyUsedQueue mapped_type;
+ typedef std::map<key_type,mapped_type>::iterator iterator;
+private:
+ std::map<key_type,mapped_type> maMap;
+public:
+ RecentlyUsedPageCaches () {};
+
+ iterator end() { return maMap.end(); }
+ void clear() { maMap.clear(); }
+ iterator find(const key_type& key) { return maMap.find(key); }
+ template<class... Args>
+ std::pair<iterator,bool> emplace(Args&&... args) { return maMap.emplace(std::forward<Args>(args)...); }
+};
+
+class PageCacheManager::Deleter
+{
+public:
+ void operator() (PageCacheManager* pObject) { delete pObject; }
+};
+
+//===== PageCacheManager ====================================================
+
+std::weak_ptr<PageCacheManager> PageCacheManager::mpInstance;
+
+std::shared_ptr<PageCacheManager> PageCacheManager::Instance()
+{
+ std::shared_ptr<PageCacheManager> pInstance;
+
+ ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
+
+ pInstance = mpInstance.lock();
+ if (pInstance == nullptr)
+ {
+ pInstance = std::shared_ptr<PageCacheManager>(
+ new PageCacheManager(),
+ PageCacheManager::Deleter());
+ mpInstance = pInstance;
+ }
+
+ return pInstance;
+}
+
+PageCacheManager::PageCacheManager()
+ : mpPageCaches(new PageCacheContainer()),
+ mpRecentlyUsedPageCaches(new RecentlyUsedPageCaches())
+{
+}
+
+PageCacheManager::~PageCacheManager()
+{
+}
+
+std::shared_ptr<BitmapCache> PageCacheManager::GetCache (
+ const DocumentKey& pDocument,
+ const Size& rPreviewSize)
+{
+ std::shared_ptr<BitmapCache> pResult;
+
+ // Look for the cache in the list of active caches.
+ CacheDescriptor aKey (pDocument, rPreviewSize);
+ PageCacheContainer::iterator iCache (mpPageCaches->find(aKey));
+ if (iCache != mpPageCaches->end())
+ pResult = iCache->second;
+
+ // Look for the cache in the list of recently used caches.
+ if (pResult == nullptr)
+ pResult = GetRecentlyUsedCache(pDocument, rPreviewSize);
+
+ // Create the cache when no suitable one does exist.
+ if (pResult == nullptr)
+ pResult = std::make_shared<BitmapCache>();
+
+ // The cache may be newly created and thus empty or is old and may
+ // contain previews that are not up-to-date. Recycle previews from
+ // other caches to fill in the holes.
+ Recycle(pResult, pDocument,rPreviewSize);
+
+ // Put the new (or old) cache into the container.
+ mpPageCaches->emplace(aKey, pResult);
+
+ return pResult;
+}
+
+void PageCacheManager::Recycle (
+ const std::shared_ptr<BitmapCache>& rpCache,
+ const DocumentKey& pDocument,
+ const Size& rPreviewSize)
+{
+ BestFittingPageCaches aCaches;
+
+ // Add bitmap caches from active caches.
+ for (auto& rActiveCache : *mpPageCaches)
+ {
+ if (rActiveCache.first.mpDocument == pDocument)
+ aCaches.emplace_back(
+ rActiveCache.first.maPreviewSize, rActiveCache.second);
+ }
+
+ // Add bitmap caches from recently used caches.
+ RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
+ if (iQueue != mpRecentlyUsedPageCaches->end())
+ {
+ for (const auto& rRecentCache : iQueue->second)
+ aCaches.emplace_back(
+ rRecentCache.maPreviewSize, rRecentCache.mpCache);
+ }
+
+ ::std::sort(aCaches.begin(), aCaches.end(), BestFittingCacheComparer(rPreviewSize));
+
+ for (const auto& rBestCache : aCaches)
+ {
+ rpCache->Recycle(*rBestCache.second);
+ }
+}
+
+void PageCacheManager::ReleaseCache (const std::shared_ptr<BitmapCache>& rpCache)
+{
+ PageCacheContainer::iterator iCache (::std::find_if(
+ mpPageCaches->begin(),
+ mpPageCaches->end(),
+ PageCacheContainer::CompareWithCache(rpCache)));
+
+ if (iCache != mpPageCaches->end())
+ {
+ assert(iCache->second == rpCache);
+
+ PutRecentlyUsedCache(iCache->first.mpDocument,iCache->first.maPreviewSize,rpCache);
+
+ mpPageCaches->erase(iCache);
+ }
+}
+
+std::shared_ptr<BitmapCache> PageCacheManager::ChangeSize (
+ const std::shared_ptr<BitmapCache>& rpCache,
+ const Size&,
+ const Size& rNewPreviewSize)
+{
+ std::shared_ptr<BitmapCache> pResult;
+
+ if (rpCache != nullptr)
+ {
+ // Look up the given cache in the list of active caches.
+ PageCacheContainer::iterator iCacheToChange (::std::find_if(
+ mpPageCaches->begin(),
+ mpPageCaches->end(),
+ PageCacheContainer::CompareWithCache(rpCache)));
+ if (iCacheToChange != mpPageCaches->end())
+ {
+ assert(iCacheToChange->second == rpCache);
+
+ // Now, we can change the preview size of the existing one by
+ // removing the cache from the list and re-insert it with the
+ // updated size.
+ const ::sd::slidesorter::cache::PageCacheManager::DocumentKey aKey (
+ iCacheToChange->first.mpDocument);
+ mpPageCaches->erase(iCacheToChange);
+ mpPageCaches->emplace(
+ CacheDescriptor(aKey,rNewPreviewSize),
+ rpCache);
+
+ pResult = rpCache;
+ }
+ else
+ {
+ assert(iCacheToChange != mpPageCaches->end());
+ }
+ }
+
+ return pResult;
+}
+
+bool PageCacheManager::InvalidatePreviewBitmap (
+ const DocumentKey& pDocument,
+ const SdrPage* pKey)
+{
+ bool bHasChanged (false);
+
+ if (pDocument!=nullptr)
+ {
+ // Iterate over all caches that are currently in use and invalidate
+ // the previews in those that belong to the document.
+ for (auto& rCache : *mpPageCaches)
+ if (rCache.first.mpDocument == pDocument)
+ bHasChanged |= rCache.second->InvalidateBitmap(pKey);
+
+ // Invalidate the previews in the recently used caches belonging to
+ // the given document.
+ RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
+ if (iQueue != mpRecentlyUsedPageCaches->end())
+ {
+ for (const auto& rCache2 : iQueue->second)
+ bHasChanged |= rCache2.mpCache->InvalidateBitmap(pKey);
+ }
+ }
+
+ return bHasChanged;
+}
+
+void PageCacheManager::InvalidateAllPreviewBitmaps (const DocumentKey& pDocument)
+{
+ if (pDocument == nullptr)
+ return;
+
+ // Iterate over all caches that are currently in use and invalidate the
+ // previews in those that belong to the document.
+ for (auto& rCache : *mpPageCaches)
+ if (rCache.first.mpDocument == pDocument)
+ rCache.second->InvalidateCache();
+
+ // Invalidate the previews in the recently used caches belonging to the
+ // given document.
+ RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
+ if (iQueue != mpRecentlyUsedPageCaches->end())
+ {
+ for (const auto& rCache2 : iQueue->second)
+ rCache2.mpCache->InvalidateCache();
+ }
+}
+
+void PageCacheManager::InvalidateAllCaches()
+{
+ // Iterate over all caches that are currently in use and invalidate
+ // them.
+ for (auto& rCache : *mpPageCaches)
+ rCache.second->InvalidateCache();
+
+ // Remove all recently used caches, there is not much sense in storing
+ // invalidated and unused caches.
+ mpRecentlyUsedPageCaches->clear();
+}
+
+void PageCacheManager::ReleasePreviewBitmap (const SdrPage* pPage)
+{
+ for (auto& rCache : *mpPageCaches)
+ rCache.second->ReleaseBitmap(pPage);
+}
+
+std::shared_ptr<BitmapCache> PageCacheManager::GetRecentlyUsedCache (
+ const DocumentKey& pDocument,
+ const Size& rPreviewSize)
+{
+ std::shared_ptr<BitmapCache> pCache;
+
+ // Look for the cache in the list of recently used caches.
+ RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
+ if (iQueue != mpRecentlyUsedPageCaches->end())
+ {
+ RecentlyUsedQueue::iterator iCache = std::find_if(iQueue->second.begin(), iQueue->second.end(),
+ [&rPreviewSize](const RecentlyUsedCacheDescriptor& rCache) { return rCache.maPreviewSize == rPreviewSize; });
+ if (iCache != iQueue->second.end())
+ {
+ pCache = iCache->mpCache;
+ iQueue->second.erase(iCache);
+ }
+ }
+
+ return pCache;
+}
+
+void PageCacheManager::PutRecentlyUsedCache(
+ DocumentKey const & pDocument,
+ const Size& rPreviewSize,
+ const std::shared_ptr<BitmapCache>& rpCache)
+{
+ // Look up the list of recently used caches for the given document.
+ RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
+ if (iQueue == mpRecentlyUsedPageCaches->end())
+ iQueue = mpRecentlyUsedPageCaches->emplace(
+ pDocument, RecentlyUsedQueue()
+ ).first;
+
+ if (iQueue != mpRecentlyUsedPageCaches->end())
+ {
+ iQueue->second.push_front(RecentlyUsedCacheDescriptor(rPreviewSize,rpCache));
+ // Shorten the list of recently used caches to the allowed maximal length.
+ while (iQueue->second.size() > mnMaximalRecentlyCacheCount)
+ iQueue->second.pop_back();
+ }
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx
new file mode 100644
index 000000000..077c48709
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlsQueueProcessor.hxx"
+#include "SlsRequestQueue.hxx"
+#include "SlsBitmapCache.hxx"
+
+#include <sdpage.hxx>
+#include <comphelper/profilezone.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace sd::slidesorter::cache {
+
+//===== QueueProcessor ======================================================
+
+QueueProcessor::QueueProcessor (
+ RequestQueue& rQueue,
+ const std::shared_ptr<BitmapCache>& rpCache,
+ const Size& rPreviewSize,
+ const bool bDoSuperSampling,
+ const SharedCacheContext& rpCacheContext)
+ : maTimer("sd::QueueProcessor maTimer"),
+ maPreviewSize(rPreviewSize),
+ mbDoSuperSampling(bDoSuperSampling),
+ mpCacheContext(rpCacheContext),
+ mrQueue(rQueue),
+ mpCache(rpCache),
+ mbIsPaused(false)
+{
+ maTimer.SetInvokeHandler (LINK(this,QueueProcessor,ProcessRequestHdl));
+ maTimer.SetTimeout (10);
+}
+
+QueueProcessor::~QueueProcessor()
+{
+}
+
+void QueueProcessor::Start (int nPriorityClass)
+{
+ if (mbIsPaused)
+ return;
+ if ( ! maTimer.IsActive())
+ {
+ if (nPriorityClass == 0)
+ maTimer.SetTimeout (10);
+ else
+ maTimer.SetTimeout (100);
+ maTimer.Start();
+ }
+}
+
+void QueueProcessor::Stop()
+{
+ if (maTimer.IsActive())
+ maTimer.Stop();
+}
+
+void QueueProcessor::Pause()
+{
+ mbIsPaused = true;
+}
+
+void QueueProcessor::Resume()
+{
+ mbIsPaused = false;
+ if ( ! mrQueue.IsEmpty())
+ Start(mrQueue.GetFrontPriorityClass());
+}
+
+void QueueProcessor::SetPreviewSize (
+ const Size& rPreviewSize,
+ const bool bDoSuperSampling)
+{
+ maPreviewSize = rPreviewSize;
+ mbDoSuperSampling = bDoSuperSampling;
+}
+
+IMPL_LINK_NOARG(QueueProcessor, ProcessRequestHdl, Timer *, void)
+{
+ ProcessRequests();
+}
+
+void QueueProcessor::ProcessRequests()
+{
+ assert(mpCacheContext);
+
+ // Never process more than one request at a time in order to prevent the
+ // lock up of the edit view.
+ if ( ! mrQueue.IsEmpty()
+ && ! mbIsPaused
+ && mpCacheContext->IsIdle())
+ {
+ CacheKey aKey = nullptr;
+ RequestPriorityClass ePriorityClass (NOT_VISIBLE);
+ {
+ ::osl::MutexGuard aGuard (mrQueue.GetMutex());
+
+ if ( ! mrQueue.IsEmpty())
+ {
+ // Get the request with the highest priority from the queue.
+ ePriorityClass = mrQueue.GetFrontPriorityClass();
+ aKey = mrQueue.GetFront();
+ mrQueue.PopFront();
+ }
+ }
+
+ if (aKey != nullptr)
+ ProcessOneRequest(aKey, ePriorityClass);
+ }
+
+ // Schedule the processing of the next element(s).
+ {
+ ::osl::MutexGuard aGuard (mrQueue.GetMutex());
+ if ( ! mrQueue.IsEmpty())
+ Start(mrQueue.GetFrontPriorityClass());
+ else
+ {
+ comphelper::ProfileZone aZone("QueueProcessor finished processing all elements");
+ }
+ }
+}
+
+void QueueProcessor::ProcessOneRequest (
+ CacheKey aKey,
+ const RequestPriorityClass ePriorityClass)
+{
+ try
+ {
+ std::scoped_lock aGuard (maMutex);
+
+ // Create a new preview bitmap and store it in the cache.
+ if (mpCache != nullptr && mpCacheContext)
+ {
+ const SdPage* pSdPage = dynamic_cast<const SdPage*>(mpCacheContext->GetPage(aKey));
+ if (pSdPage != nullptr)
+ {
+ const BitmapEx aPreview (
+ maBitmapFactory.CreateBitmap(*pSdPage, maPreviewSize, mbDoSuperSampling));
+ mpCache->SetBitmap (pSdPage, aPreview, ePriorityClass!=NOT_VISIBLE);
+
+ // Initiate a repaint of the new preview.
+ mpCacheContext->NotifyPreviewCreation(aKey);
+ }
+ }
+ }
+ catch (css::uno::Exception &)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "QueueProcessor");
+ }
+}
+
+void QueueProcessor::SetBitmapCache (
+ const std::shared_ptr<BitmapCache>& rpCache)
+{
+ mpCache = rpCache;
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx
new file mode 100644
index 000000000..0035bcbce
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <cache/SlsCacheContext.hxx>
+#include "SlsRequestPriorityClass.hxx"
+#include "SlsBitmapFactory.hxx"
+
+#include <vcl/timer.hxx>
+#include <mutex>
+
+namespace sd::slidesorter::cache {
+
+class BitmapCache;
+class RequestQueue;
+
+/** This queue processor is timer based, i.e. when an entry is added to the
+ queue and the processor is started with Start() in the base class a
+ timer is started that eventually calls ProcessRequest(). This is
+ repeated until the queue is empty or Stop() is called.
+*/
+class QueueProcessor final
+{
+public:
+ QueueProcessor (
+ RequestQueue& rQueue,
+ const std::shared_ptr<BitmapCache>& rpCache,
+ const Size& rPreviewSize,
+ const bool bDoSuperSampling,
+ const SharedCacheContext& rpCacheContext);
+ ~QueueProcessor();
+
+ /** Start the processor. This implementation is timer based and waits
+ a defined amount of time that depends on the given argument before
+ the next entry in the queue is processed.
+ @param nPriorityClass
+ A priority class of 0 tells the processor that a high priority
+ request is waiting in the queue. The time to wait is thus
+ shorter then that for a low priority request (denoted by a value
+ of 1.) When the timer is already running it is not modified.
+ */
+ void Start (int nPriorityClass);
+ void Stop();
+ void Pause();
+ void Resume();
+
+ void SetPreviewSize (
+ const Size& rSize,
+ const bool bDoSuperSampling);
+
+ /** Use this method when the page cache is (maybe) using a different
+ BitmapCache. This is usually necessary after calling
+ PageCacheManager::ChangeSize().
+ */
+ void SetBitmapCache (const std::shared_ptr<BitmapCache>& rpCache);
+
+private:
+ /** This mutex is used to guard the queue processor. Be careful not to
+ mix its use with that of the solar mutex.
+ */
+ std::mutex maMutex;
+
+ Timer maTimer;
+ DECL_LINK(ProcessRequestHdl, Timer *, void);
+ Size maPreviewSize;
+ bool mbDoSuperSampling;
+ SharedCacheContext mpCacheContext;
+ RequestQueue& mrQueue;
+ std::shared_ptr<BitmapCache> mpCache;
+ BitmapFactory maBitmapFactory;
+ bool mbIsPaused;
+
+ void ProcessRequests();
+ void ProcessOneRequest (
+ CacheKey aKey,
+ const RequestPriorityClass ePriorityClass);
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx b/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx
new file mode 100644
index 000000000..6fc6cabc9
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlsRequestFactory.hxx"
+#include "SlsRequestQueue.hxx"
+
+namespace sd::slidesorter::cache {
+
+void RequestFactory::operator()(
+ RequestQueue& rRequestQueue,
+ const SharedCacheContext& rpCacheContext)
+{
+ std::shared_ptr<std::vector<CacheKey> > aKeys;
+
+ // Add the requests for the visible pages.
+ aKeys = rpCacheContext->GetEntryList(true);
+ if (aKeys != nullptr)
+ {
+ for (const auto& rKey : *aKeys)
+ rRequestQueue.AddRequest(rKey, VISIBLE_NO_PREVIEW);
+ }
+
+ // Add the requests for the non-visible pages.
+ aKeys = rpCacheContext->GetEntryList(false);
+ if (aKeys != nullptr)
+ {
+ for (const auto& rKey : *aKeys)
+ rRequestQueue.AddRequest(rKey, NOT_VISIBLE);
+ }
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx b/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx
new file mode 100644
index 000000000..3f4207725
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cache/SlsCacheContext.hxx>
+
+namespace sd::slidesorter::cache
+{
+class RequestQueue;
+
+class RequestFactory
+{
+public:
+ void operator()(RequestQueue& rRequestQueue, const SharedCacheContext& rpCacheContext);
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx b/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx
new file mode 100644
index 000000000..2c84ecbcf
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+namespace sd::slidesorter::cache
+{
+/** Each request for a preview creation has a priority. This enum defines
+ the available priorities. The special values MIN_CLASS and MAX_CLASS
+ are/can be used for validation and have to be kept up-to-date.
+*/
+enum RequestPriorityClass
+{
+ MIN_CLASS = 0,
+
+ // The slide is visible. A preview does not yet exist.
+ VISIBLE_NO_PREVIEW = MIN_CLASS,
+ // The slide is visible. A preview exists but is not up-to-date anymore.
+ VISIBLE_OUTDATED_PREVIEW,
+ // The slide is not visible.
+ NOT_VISIBLE,
+
+ MAX_CLASS = NOT_VISIBLE
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx b/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx
new file mode 100644
index 000000000..931c1a8f6
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx
@@ -0,0 +1,275 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlsRequestQueue.hxx"
+
+#include <sal/log.hxx>
+
+#include <svx/svdpage.hxx>
+
+#include <set>
+
+namespace sd::slidesorter::cache {
+
+namespace {
+
+/** This class extends the actual request data with additional information
+ that is used by the priority queues.
+*/
+class Request
+{
+public:
+ Request (
+ CacheKey aKey, sal_Int32 nPriority, RequestPriorityClass eClass)
+ : maKey(aKey), mnPriorityInClass(nPriority), meClass(eClass)
+ {}
+ /** Sort requests according to priority classes and then to priorities.
+ */
+ class Comparator { public:
+ bool operator() (const Request& rRequest1, const Request& rRequest2)
+ const
+ {
+ if (rRequest1.meClass == rRequest2.meClass)
+ {
+ if (rRequest1.mnPriorityInClass == rRequest2.mnPriorityInClass)
+ {
+ return rRequest1.maKey < rRequest2.maKey;
+ }
+ return rRequest1.mnPriorityInClass > rRequest2.mnPriorityInClass;
+ }
+ return rRequest1.meClass < rRequest2.meClass;
+ }
+ };
+ /** Request data is compared arbitrarily by their addresses in memory.
+ This just establishes an order so that the STL containers are happy.
+ The order is not semantically interpreted.
+ */
+ class DataComparator
+ {
+ public:
+ explicit DataComparator (const CacheKey aKey)
+ : maKey(aKey)
+ {
+ }
+ bool operator() (const Request& rRequest) const
+ {
+ return maKey == rRequest.maKey;
+ }
+ private:
+ const CacheKey maKey;
+ };
+
+ CacheKey maKey;
+ sal_Int32 mnPriorityInClass;
+ RequestPriorityClass meClass;
+};
+
+}
+
+class RequestQueue::Container
+ : public ::std::set<
+ Request,
+ Request::Comparator>
+{
+};
+
+//===== GenericRequestQueue =================================================
+
+RequestQueue::RequestQueue (const SharedCacheContext& rpCacheContext)
+ : mpRequestQueue(new Container),
+ mpCacheContext(rpCacheContext),
+ mnMinimumPriority(0),
+ mnMaximumPriority(1)
+{
+}
+
+RequestQueue::~RequestQueue()
+{
+ Clear();
+}
+
+void RequestQueue::AddRequest (
+ CacheKey aKey,
+ RequestPriorityClass eRequestClass)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ assert(eRequestClass>=MIN_CLASS && eRequestClass<=MAX_CLASS);
+
+ // If the request is already a member of the queue then remove it so
+ // that the following insertion will use the new prioritization.
+#if OSL_DEBUG_LEVEL >=2
+ bool bRemoved =
+#endif
+ RemoveRequest(aKey);
+
+ // The priority of the request inside its priority class is defined by
+ // the page number. This ensures a strict top-to-bottom, left-to-right
+ // order.
+ sal_Int32 nPriority (mpCacheContext->GetPriority(aKey));
+ Request aRequest (aKey, nPriority, eRequestClass);
+
+ std::pair<Container::iterator,bool> ret = mpRequestQueue->insert(aRequest);
+ bool bInserted = ret.second;
+
+ if (bInserted)
+ {
+ SdrPage *pPage = const_cast<SdrPage*>(aRequest.maKey);
+ pPage->AddPageUser(*this);
+ }
+
+#if OSL_DEBUG_LEVEL >=2
+ SAL_INFO("sd.sls", __func__ << ": " << (bRemoved?"replaced":"added")
+ << " request for page " << ((aKey->GetPageNum()-1)/2)
+ << " with priority class " << static_cast<int>(eRequestClass));
+#endif
+}
+
+void RequestQueue::PageInDestruction(const SdrPage& rPage)
+{
+ //remove any requests pending for this page which is going away now
+ RemoveRequest(&rPage);
+}
+
+#if OSL_DEBUG_LEVEL >=2
+bool
+#else
+void
+#endif
+RequestQueue::RemoveRequest(
+ CacheKey aKey)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+#if OSL_DEBUG_LEVEL >=2
+ bool bIsRemoved = false;
+#endif
+ while(true)
+ {
+ Container::const_iterator aRequestIterator = ::std::find_if (
+ mpRequestQueue->begin(),
+ mpRequestQueue->end(),
+ Request::DataComparator(aKey));
+ if (aRequestIterator != mpRequestQueue->end())
+ {
+ if (aRequestIterator->mnPriorityInClass == mnMinimumPriority+1)
+ mnMinimumPriority++;
+ else if (aRequestIterator->mnPriorityInClass == mnMaximumPriority-1)
+ mnMaximumPriority--;
+
+ SdrPage *pPage = const_cast<SdrPage*>(aRequestIterator->maKey);
+ pPage->RemovePageUser(*this);
+ mpRequestQueue->erase(aRequestIterator);
+#if OSL_DEBUG_LEVEL >=2
+ bIsRemoved = true;
+#endif
+ }
+ else
+ break;
+ }
+#if OSL_DEBUG_LEVEL >=2
+ return bIsRemoved;
+#endif
+
+}
+
+void RequestQueue::ChangeClass (
+ CacheKey aKey,
+ RequestPriorityClass eNewRequestClass)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ assert(eNewRequestClass>=MIN_CLASS && eNewRequestClass<=MAX_CLASS);
+
+ Container::const_iterator iRequest (
+ ::std::find_if (
+ mpRequestQueue->begin(),
+ mpRequestQueue->end(),
+ Request::DataComparator(aKey)));
+ if (iRequest!=mpRequestQueue->end() && iRequest->meClass!=eNewRequestClass)
+ {
+ AddRequest(aKey, eNewRequestClass);
+ }
+}
+
+CacheKey RequestQueue::GetFront()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ if (mpRequestQueue->empty())
+ throw css::uno::RuntimeException("RequestQueue::GetFront(): queue is empty",
+ nullptr);
+
+ return mpRequestQueue->begin()->maKey;
+}
+
+RequestPriorityClass RequestQueue::GetFrontPriorityClass()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ if (mpRequestQueue->empty())
+ throw css::uno::RuntimeException("RequestQueue::GetFrontPriorityClass(): queue is empty",
+ nullptr);
+
+ return mpRequestQueue->begin()->meClass;
+}
+
+void RequestQueue::PopFront()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ if ( mpRequestQueue->empty())
+ return;
+
+ Container::const_iterator aIter(mpRequestQueue->begin());
+ SdrPage *pPage = const_cast<SdrPage*>(aIter->maKey);
+ pPage->RemovePageUser(*this);
+ mpRequestQueue->erase(aIter);
+
+ // Reset the priority counter if possible.
+ if (mpRequestQueue->empty())
+ {
+ mnMinimumPriority = 0;
+ mnMaximumPriority = 1;
+ }
+}
+
+bool RequestQueue::IsEmpty()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ return mpRequestQueue->empty();
+}
+
+void RequestQueue::Clear()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ for (const auto& rItem : *mpRequestQueue)
+ {
+ SdrPage *pPage = const_cast<SdrPage*>(rItem.maKey);
+ pPage->RemovePageUser(*this);
+ }
+
+ mpRequestQueue->clear();
+ mnMinimumPriority = 0;
+ mnMaximumPriority = 1;
+}
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx b/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx
new file mode 100644
index 000000000..618ba5801
--- /dev/null
+++ b/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "SlsRequestPriorityClass.hxx"
+#include <cache/SlsCacheContext.hxx>
+#include <osl/mutex.hxx>
+#include <svx/sdrpageuser.hxx>
+
+#include <memory>
+
+namespace sd::slidesorter::cache
+{
+/** The request queue stores requests that are described by the Request
+ sorted according to priority class and then priority.
+*/
+class RequestQueue : public sdr::PageUser
+{
+public:
+ explicit RequestQueue(const SharedCacheContext& rpCacheContext);
+ virtual ~RequestQueue();
+
+ /** Insert a request with highest or lowest priority in its priority
+ class. When the request is already present then it is first
+ removed. This effect is then a re-prioritization.
+ @param aKey
+ The request.
+ @param eRequestClass
+ The priority class in which to insert the request with highest
+ or lowest priority.
+ @param bInsertWithHighestPriority
+ When this flag is <TRUE/> the request is inserted with highest
+ priority in its class. When <FALSE/> the request is inserted
+ with lowest priority.
+ */
+ void AddRequest(CacheKey aKey, RequestPriorityClass eRequestClass);
+
+ /** Remove the specified request from the queue.
+ @param aKey
+ It is OK when the specified request is not a member of the
+ queue.
+ */
+#if OSL_DEBUG_LEVEL >= 2
+ bool
+#else
+ void
+#endif
+ RemoveRequest(CacheKey aKey);
+
+ /** Change the priority class of the specified request.
+ */
+ void ChangeClass(CacheKey aKey, RequestPriorityClass eNewRequestClass);
+
+ /** Get the request with the highest priority int the highest priority class.
+ */
+ CacheKey GetFront();
+
+ // For debugging.
+ RequestPriorityClass GetFrontPriorityClass();
+
+ /** Really a synonym for RemoveRequest(GetFront());
+ */
+ void PopFront();
+
+ /** Returns <TRUE/> when there is no element in the queue.
+ */
+ bool IsEmpty();
+
+ /** Remove all requests from the queue. This resets the minimum and
+ maximum priorities to their default values.
+ */
+ void Clear();
+
+ /** Return the mutex that guards the access to the priority queue.
+ */
+ ::osl::Mutex& GetMutex() { return maMutex; }
+
+ /** Ensure we don't hand out a page deleted before anyone got a
+ chance to process it
+ */
+ virtual void PageInDestruction(const SdrPage& rPage) override;
+
+private:
+ ::osl::Mutex maMutex;
+ class Container;
+ std::unique_ptr<Container> mpRequestQueue;
+ SharedCacheContext mpCacheContext;
+
+ /** A lower bound of the lowest priority of all elements in the queues.
+ The start value is 0. It is assigned and then decreased every time
+ when an element is inserted or marked as the request with lowest
+ priority.
+ */
+ int mnMinimumPriority;
+ /** An upper bound of the highest priority of all elements in the queues.
+ The start value is 1. It is assigned and then increased every time
+ when an element is inserted or marked as the request with highest
+ priority.
+ */
+ int mnMaximumPriority;
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlideSorterController.cxx b/sd/source/ui/slidesorter/controller/SlideSorterController.cxx
new file mode 100644
index 000000000..5c851f183
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlideSorterController.cxx
@@ -0,0 +1,910 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <controller/SlideSorterController.hxx>
+
+#include <SlideSorter.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsSelectionFunction.hxx>
+#include <controller/SlsProperties.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include "SlsListener.hxx"
+#include <controller/SlsFocusManager.hxx>
+#include <controller/SlsAnimator.hxx>
+#include <controller/SlsClipboard.hxx>
+#include <controller/SlsInsertionIndicatorHandler.hxx>
+#include <controller/SlsScrollBarManager.hxx>
+#include <controller/SlsSelectionManager.hxx>
+#include <controller/SlsSlotManager.hxx>
+#include <controller/SlsVisibleAreaManager.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <view/SlsPageObjectLayouter.hxx>
+#include <view/SlsTheme.hxx>
+#include <view/SlsToolTip.hxx>
+#include <cache/SlsPageCache.hxx>
+#include <cache/SlsPageCacheManager.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <drawdoc.hxx>
+#include <ViewShellBase.hxx>
+#include <Window.hxx>
+#include <FrameView.hxx>
+#include <sdpage.hxx>
+
+#include <app.hrc>
+#include <sdmod.hxx>
+#include <ViewShellHint.hxx>
+#include <AccessibleSlideSorterView.hxx>
+#include <AccessibleSlideSorterObject.hxx>
+
+#include <vcl/window.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <tools/debug.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::sd::slidesorter::model;
+using namespace ::sd::slidesorter::view;
+using namespace ::sd::slidesorter::controller;
+using namespace ::basegfx;
+
+namespace sd::slidesorter::controller {
+
+SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mrModel(mrSlideSorter.GetModel()),
+ mrView(mrSlideSorter.GetView()),
+ mpInsertionIndicatorHandler(std::make_shared<InsertionIndicatorHandler>(rSlideSorter)),
+ mpAnimator(std::make_shared<Animator>(rSlideSorter)),
+ mpVisibleAreaManager(new VisibleAreaManager(rSlideSorter)),
+ mnModelChangeLockCount(0),
+ mbIsForcedRearrangePending(false),
+ mbContextMenuOpen(false),
+ mbPostModelChangePending(false),
+ mnCurrentPageBeforeSwitch(0),
+ mpEditModeChangeMasterPage(nullptr),
+ mnPaintEntranceCount(0)
+{
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ OSL_ASSERT(pWindow);
+ if (!pWindow)
+ return;
+
+ // The whole background is painted by the view and controls.
+ vcl::Window* pParentWindow = pWindow->GetParent();
+ OSL_ASSERT(pParentWindow!=nullptr);
+ pParentWindow->SetBackground (Wallpaper());
+
+ // Connect the view with the window that has been created by our base
+ // class.
+ pWindow->SetBackground(Wallpaper());
+ pWindow->SetCenterAllowed(false);
+ pWindow->SetMapMode(MapMode(MapUnit::MapPixel));
+ pWindow->SetViewSize(mrView.GetModelArea().GetSize());
+}
+
+void SlideSorterController::Init()
+{
+ mpCurrentSlideManager = std::make_shared<CurrentSlideManager>(mrSlideSorter);
+ mpPageSelector.reset(new PageSelector(mrSlideSorter));
+ mpFocusManager.reset(new FocusManager(mrSlideSorter));
+ mpSlotManager = std::make_shared<SlotManager>(mrSlideSorter);
+ mpScrollBarManager.reset(new ScrollBarManager(mrSlideSorter));
+ mpSelectionManager = std::make_shared<SelectionManager>(mrSlideSorter);
+ mpClipboard.reset(new Clipboard(mrSlideSorter));
+
+ // Create the selection function.
+ SfxRequest aRequest (
+ SID_OBJECT_SELECT,
+ SfxCallMode::SLOT,
+ mrModel.GetDocument()->GetItemPool());
+ mrSlideSorter.SetCurrentFunction(CreateSelectionFunction(aRequest));
+
+ mpListener = new Listener(mrSlideSorter);
+
+ mpPageSelector->GetCoreSelection();
+ GetSelectionManager()->SelectionHasChanged();
+}
+
+SlideSorterController::~SlideSorterController()
+{
+ try
+ {
+ uno::Reference<lang::XComponent> xComponent = mpListener;
+ if (xComponent.is())
+ xComponent->dispose();
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideSorterController::~SlideSorterController()" );
+ }
+
+ // dispose should have been called by now so that nothing is to be done
+ // to shut down cleanly.
+}
+
+void SlideSorterController::Dispose()
+{
+ mpInsertionIndicatorHandler->End(Animator::AM_Immediate);
+ mpClipboard.reset();
+ mpSelectionManager.reset();
+ mpAnimator->Dispose();
+}
+
+model::SharedPageDescriptor SlideSorterController::GetPageAt (
+ const Point& aWindowPosition)
+{
+ sal_Int32 nHitPageIndex (mrView.GetPageIndexAtPoint(aWindowPosition));
+ model::SharedPageDescriptor pDescriptorAtPoint;
+ if (nHitPageIndex >= 0)
+ {
+ pDescriptorAtPoint = mrModel.GetPageDescriptor(nHitPageIndex);
+
+ // Depending on a property we may have to check that the mouse is no
+ // just over the page object but over the preview area.
+ if (pDescriptorAtPoint
+ && ! pDescriptorAtPoint->HasState(PageDescriptor::ST_Selected))
+ {
+ // Make sure that the mouse is over the preview area.
+ if ( ! mrView.GetLayouter().GetPageObjectLayouter()->GetBoundingBox(
+ pDescriptorAtPoint,
+ view::PageObjectLayouter::Part::Preview,
+ view::PageObjectLayouter::WindowCoordinateSystem).Contains(aWindowPosition))
+ {
+ pDescriptorAtPoint.reset();
+ }
+ }
+ }
+
+ return pDescriptorAtPoint;
+}
+
+PageSelector& SlideSorterController::GetPageSelector()
+{
+ OSL_ASSERT(mpPageSelector != nullptr);
+ return *mpPageSelector;
+}
+
+FocusManager& SlideSorterController::GetFocusManager()
+{
+ OSL_ASSERT(mpFocusManager != nullptr);
+ return *mpFocusManager;
+}
+
+Clipboard& SlideSorterController::GetClipboard()
+{
+ OSL_ASSERT(mpClipboard != nullptr);
+ return *mpClipboard;
+}
+
+ScrollBarManager& SlideSorterController::GetScrollBarManager()
+{
+ OSL_ASSERT(mpScrollBarManager != nullptr);
+ return *mpScrollBarManager;
+}
+
+std::shared_ptr<CurrentSlideManager> const & SlideSorterController::GetCurrentSlideManager() const
+{
+ OSL_ASSERT(mpCurrentSlideManager != nullptr);
+ return mpCurrentSlideManager;
+}
+
+std::shared_ptr<SlotManager> const & SlideSorterController::GetSlotManager() const
+{
+ OSL_ASSERT(mpSlotManager != nullptr);
+ return mpSlotManager;
+}
+
+std::shared_ptr<SelectionManager> const & SlideSorterController::GetSelectionManager() const
+{
+ OSL_ASSERT(mpSelectionManager != nullptr);
+ return mpSelectionManager;
+}
+
+std::shared_ptr<InsertionIndicatorHandler> const &
+ SlideSorterController::GetInsertionIndicatorHandler() const
+{
+ OSL_ASSERT(mpInsertionIndicatorHandler != nullptr);
+ return mpInsertionIndicatorHandler;
+}
+
+void SlideSorterController::Paint (
+ const ::tools::Rectangle& rBBox,
+ vcl::Window* pWindow)
+{
+ if (mnPaintEntranceCount != 0)
+ return;
+
+ ++mnPaintEntranceCount;
+
+ try
+ {
+ mrView.CompleteRedraw(pWindow->GetOutDev(), vcl::Region(rBBox));
+ }
+ catch (const Exception&)
+ {
+ // Ignore all exceptions.
+ }
+
+ --mnPaintEntranceCount;
+}
+
+void SlideSorterController::FuTemporary (SfxRequest& rRequest)
+{
+ mpSlotManager->FuTemporary (rRequest);
+}
+
+void SlideSorterController::FuPermanent (SfxRequest &rRequest)
+{
+ mpSlotManager->FuPermanent (rRequest);
+}
+
+void SlideSorterController::FuSupport (SfxRequest &rRequest)
+{
+ mpSlotManager->FuSupport (rRequest);
+}
+
+bool SlideSorterController::Command (
+ const CommandEvent& rEvent,
+ ::sd::Window* pWindow)
+{
+ bool bEventHasBeenHandled = false;
+
+ if (pWindow == nullptr)
+ return false;
+
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (pViewShell == nullptr)
+ return false;
+
+ switch (rEvent.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ SdPage* pPage = nullptr;
+ OUString aPopupId;
+
+ model::PageEnumeration aSelectedPages (
+ PageEnumerationProvider::CreateSelectedPagesEnumeration(mrModel));
+ if (aSelectedPages.HasMoreElements())
+ pPage = aSelectedPages.GetNextElement()->GetPage();
+
+ if (mrModel.GetEditMode() == EditMode::Page)
+ {
+ if (pPage != nullptr)
+ aPopupId = "pagepane";
+ else
+ aPopupId = "pagepanenosel";
+ }
+ else if (pPage != nullptr)
+ aPopupId = "pagepanemaster";
+ else
+ aPopupId = "pagepanenoselmaster";
+
+ std::unique_ptr<InsertionIndicatorHandler::ForceShowContext, o3tl::default_delete<InsertionIndicatorHandler::ForceShowContext>> xContext;
+ if (pPage == nullptr)
+ {
+ // When there is no selection, then we show the insertion
+ // indicator so that the user knows where a page insertion
+ // would take place.
+ mpInsertionIndicatorHandler->Start(false);
+ mpInsertionIndicatorHandler->UpdateIndicatorIcon(SD_MOD()->pTransferClip);
+ mpInsertionIndicatorHandler->UpdatePosition(
+ pWindow->PixelToLogic(rEvent.GetMousePosPixel()),
+ InsertionIndicatorHandler::MoveMode);
+ xContext.reset(new InsertionIndicatorHandler::ForceShowContext(
+ mpInsertionIndicatorHandler));
+ }
+
+ pWindow->ReleaseMouse();
+
+ Point aMenuLocation (0,0);
+ if (!rEvent.IsMouseEvent())
+ {
+ // The event is not a mouse event. Use the center of the
+ // focused page as top left position of the context menu.
+ model::SharedPageDescriptor pDescriptor (
+ GetFocusManager().GetFocusedPageDescriptor());
+ if (pDescriptor)
+ {
+ ::tools::Rectangle aBBox (
+ mrView.GetLayouter().GetPageObjectLayouter()->GetBoundingBox (
+ pDescriptor,
+ PageObjectLayouter::Part::PageObject,
+ PageObjectLayouter::ModelCoordinateSystem));
+ aMenuLocation = aBBox.Center();
+ }
+ }
+
+ if (SfxDispatcher* pDispatcher = pViewShell->GetDispatcher())
+ {
+ mbContextMenuOpen = true;
+ if (!rEvent.IsMouseEvent())
+ pDispatcher->ExecutePopup(aPopupId, pWindow, &aMenuLocation);
+ else
+ pDispatcher->ExecutePopup(aPopupId, pWindow);
+ mbContextMenuOpen = false;
+ mrSlideSorter.GetView().UpdatePageUnderMouse();
+ ::rtl::Reference<SelectionFunction> pFunction(GetCurrentSelectionFunction());
+ if (pFunction.is())
+ pFunction->ResetMouseAnchor();
+ }
+ if (pPage == nullptr)
+ {
+ // Remember the position of the insertion indicator before
+ // it is hidden, so that a pending slide insertion slot call
+ // finds the right place to insert a new slide.
+ GetSelectionManager()->SetInsertionPosition(
+ GetInsertionIndicatorHandler()->GetInsertionPageIndex());
+ }
+ xContext.reset();
+ bEventHasBeenHandled = true;
+ }
+ break;
+
+ case CommandEventId::Wheel:
+ {
+ const CommandWheelData* pData = rEvent.GetWheelData();
+ if (pData == nullptr)
+ return false;
+ if (pData->IsMod1())
+ {
+ // We do not support zooming with control+mouse wheel.
+ return false;
+ }
+ // Determine whether to scroll horizontally or vertically. This
+ // depends on the orientation of the scroll bar and the
+ // IsHoriz() flag of the event.
+ if ((mrSlideSorter.GetView().GetOrientation()==view::Layouter::HORIZONTAL)
+ == pData->IsHorz())
+ {
+ GetScrollBarManager().Scroll(
+ ScrollBarManager::Orientation_Vertical,
+ -pData->GetNotchDelta());
+ }
+ else
+ {
+ GetScrollBarManager().Scroll(
+ ScrollBarManager::Orientation_Horizontal,
+ -pData->GetNotchDelta());
+ }
+ mrSlideSorter.GetView().UpdatePageUnderMouse(rEvent.GetMousePosPixel());
+
+ bEventHasBeenHandled = true;
+ }
+ break;
+
+ default: break;
+ }
+
+ return bEventHasBeenHandled;
+}
+
+void SlideSorterController::LockModelChange()
+{
+ mnModelChangeLockCount += 1;
+}
+
+void SlideSorterController::UnlockModelChange()
+{
+ mnModelChangeLockCount -= 1;
+ if (mnModelChangeLockCount==0 && mbPostModelChangePending)
+ {
+ PostModelChange();
+ }
+}
+
+void SlideSorterController::PreModelChange()
+{
+ // Prevent PreModelChange to execute more than once per model lock.
+ if (mbPostModelChangePending)
+ return;
+
+ if (mrSlideSorter.GetViewShell() != nullptr)
+ mrSlideSorter.GetViewShell()->Broadcast(
+ ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START));
+
+ GetCurrentSlideManager()->PrepareModelChange();
+
+ if (mrSlideSorter.GetContentWindow())
+ mrView.PreModelChange();
+
+ mbPostModelChangePending = true;
+}
+
+void SlideSorterController::PostModelChange()
+{
+ mbPostModelChangePending = false;
+ mrModel.Resync();
+
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (pWindow)
+ {
+ GetCurrentSlideManager()->HandleModelChange();
+
+ mrView.PostModelChange ();
+
+ pWindow->SetViewOrigin (Point (0,0));
+ pWindow->SetViewSize (mrView.GetModelArea().GetSize());
+
+ // The visibility of the scroll bars may have to be changed. Then
+ // the size of the view has to change, too. Let Rearrange() handle
+ // that.
+ Rearrange(mbIsForcedRearrangePending);
+ }
+
+ if (mrSlideSorter.GetViewShell() != nullptr)
+ mrSlideSorter.GetViewShell()->Broadcast(
+ ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END));
+}
+
+void SlideSorterController::HandleModelChange()
+{
+ // Ignore this call when the document is not in a valid state, i.e. has
+ // not the same number of regular and notes pages.
+ bool bIsDocumentValid = (mrModel.GetDocument()->GetPageCount() % 2 == 1);
+
+ if (bIsDocumentValid)
+ {
+ ModelChangeLock aLock (*this);
+ PreModelChange();
+ }
+}
+
+IMPL_LINK(SlideSorterController, ApplicationEventHandler, VclSimpleEvent&, rEvent, void)
+{
+ auto windowEvent = dynamic_cast<VclWindowEvent *>(&rEvent);
+ if (windowEvent != nullptr) {
+ WindowEventHandler(*windowEvent);
+ }
+}
+IMPL_LINK(SlideSorterController, WindowEventHandler, VclWindowEvent&, rEvent, void)
+{
+ vcl::Window* pWindow = rEvent.GetWindow();
+ sd::Window *pActiveWindow (mrSlideSorter.GetContentWindow().get());
+ switch (rEvent.GetId())
+ {
+ case VclEventId::WindowActivate:
+ case VclEventId::WindowShow:
+ if (pActiveWindow && pWindow == pActiveWindow->GetParent())
+ mrView.RequestRepaint();
+ break;
+
+ case VclEventId::WindowHide:
+ if (pActiveWindow && pWindow == pActiveWindow->GetParent())
+ mrView.SetPageUnderMouse(SharedPageDescriptor());
+ break;
+
+ case VclEventId::WindowGetFocus:
+ if (pActiveWindow)
+ if (pWindow == pActiveWindow)
+ GetFocusManager().ShowFocus(false);
+ break;
+
+ case VclEventId::WindowLoseFocus:
+ if (pActiveWindow && pWindow == pActiveWindow)
+ {
+ GetFocusManager().HideFocus();
+ mrView.GetToolTip().Hide();
+
+ //don't scroll back to the selected slide when we lose
+ //focus due to a temporary active context menu
+ if (!mbContextMenuOpen)
+ {
+ // Select the current slide so that it is properly
+ // visualized when the focus is moved to the edit view.
+ GetPageSelector().SelectPage(GetCurrentSlideManager()->GetCurrentSlide());
+ }
+ }
+ break;
+
+ case VclEventId::ApplicationDataChanged:
+ {
+ // Invalidate the preview cache.
+ cache::PageCacheManager::Instance()->InvalidateAllCaches();
+
+ // Update the draw mode.
+ DrawModeFlags nDrawMode (Application::GetSettings().GetStyleSettings().GetHighContrastMode()
+ ? sd::OUTPUT_DRAWMODE_CONTRAST
+ : sd::OUTPUT_DRAWMODE_COLOR);
+ if (mrSlideSorter.GetViewShell() != nullptr)
+ mrSlideSorter.GetViewShell()->GetFrameView()->SetDrawMode(nDrawMode);
+ if (pActiveWindow != nullptr)
+ pActiveWindow->GetOutDev()->SetDrawMode(nDrawMode);
+ mrView.HandleDrawModeChange();
+
+ // When the system font has changed a layout has to be done.
+ mrView.Resize();
+
+ // Update theme colors.
+ mrSlideSorter.GetProperties()->HandleDataChangeEvent();
+ mrSlideSorter.GetTheme()->Update(mrSlideSorter.GetProperties());
+ mrView.HandleDataChangeEvent();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void SlideSorterController::GetCtrlState (SfxItemSet& rSet)
+{
+ if (rSet.GetItemState(SID_RELOAD) != SfxItemState::UNKNOWN)
+ {
+ // let SFx en-/disable "last version"
+ SfxViewFrame* pSlideViewFrame = SfxViewFrame::Current();
+ DBG_ASSERT(pSlideViewFrame!=nullptr,
+ "SlideSorterController::GetCtrlState: ViewFrame not found");
+ if (pSlideViewFrame)
+ {
+ pSlideViewFrame->GetSlotState (SID_RELOAD, nullptr, &rSet);
+ }
+ else // MI says: no MDIFrame --> disable
+ {
+ rSet.DisableItem(SID_RELOAD);
+ }
+ }
+
+ // Output quality.
+ if (rSet.GetItemState(SID_OUTPUT_QUALITY_COLOR)==SfxItemState::DEFAULT
+ ||rSet.GetItemState(SID_OUTPUT_QUALITY_GRAYSCALE)==SfxItemState::DEFAULT
+ ||rSet.GetItemState(SID_OUTPUT_QUALITY_BLACKWHITE)==SfxItemState::DEFAULT
+ ||rSet.GetItemState(SID_OUTPUT_QUALITY_CONTRAST)==SfxItemState::DEFAULT)
+ {
+ if (mrSlideSorter.GetContentWindow())
+ {
+ DrawModeFlags nMode = mrSlideSorter.GetContentWindow()->GetOutDev()->GetDrawMode();
+ sal_uInt16 nQuality = 0;
+
+ if (nMode == sd::OUTPUT_DRAWMODE_COLOR) {
+ nQuality = 0;
+ } else if (nMode == sd::OUTPUT_DRAWMODE_GRAYSCALE) {
+ nQuality = 1;
+ } else if (nMode == sd::OUTPUT_DRAWMODE_BLACKWHITE) {
+ nQuality = 2;
+ } else if (nMode == sd::OUTPUT_DRAWMODE_CONTRAST) {
+ nQuality = 3;
+ }
+
+ rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_COLOR, nQuality==0));
+ rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_GRAYSCALE, nQuality==1));
+ rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_BLACKWHITE, nQuality==2));
+ rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_CONTRAST, nQuality==3));
+ }
+ }
+
+ if (rSet.GetItemState(SID_MAIL_SCROLLBODY_PAGEDOWN) == SfxItemState::DEFAULT)
+ {
+ rSet.Put (SfxBoolItem( SID_MAIL_SCROLLBODY_PAGEDOWN, true));
+ }
+}
+
+void SlideSorterController::GetStatusBarState (SfxItemSet& rSet)
+{
+ mpSlotManager->GetStatusBarState (rSet);
+}
+
+void SlideSorterController::ExecCtrl (SfxRequest& rRequest)
+{
+ mpSlotManager->ExecCtrl (rRequest);
+}
+
+void SlideSorterController::GetAttrState (SfxItemSet& rSet)
+{
+ mpSlotManager->GetAttrState (rSet);
+}
+
+void SlideSorterController::UpdateAllPages()
+{
+ // Do a redraw.
+ mrSlideSorter.GetContentWindow()->Invalidate();
+}
+
+void SlideSorterController::Resize (const ::tools::Rectangle& rAvailableSpace)
+{
+ if (maTotalWindowArea != rAvailableSpace)
+ {
+ maTotalWindowArea = rAvailableSpace;
+ Rearrange(true);
+ }
+}
+
+void SlideSorterController::Rearrange (bool bForce)
+{
+ if (maTotalWindowArea.IsEmpty())
+ return;
+
+ if (mnModelChangeLockCount>0)
+ {
+ mbIsForcedRearrangePending |= bForce;
+ return;
+ }
+ else
+ mbIsForcedRearrangePending = false;
+
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (!pWindow)
+ return;
+
+ if (bForce)
+ mrView.UpdateOrientation();
+
+ // Place the scroll bars.
+ ::tools::Rectangle aNewContentArea = GetScrollBarManager().PlaceScrollBars(
+ maTotalWindowArea,
+ mrView.GetOrientation() != view::Layouter::VERTICAL,
+ mrView.GetOrientation() != view::Layouter::HORIZONTAL);
+
+ bool bSizeHasChanged (false);
+ // Only when bForce is not true we have to test for a size change in
+ // order to determine whether the window and the view have to be resized.
+ if ( ! bForce)
+ {
+ ::tools::Rectangle aCurrentContentArea (pWindow->GetPosPixel(), pWindow->GetOutputSizePixel());
+ bSizeHasChanged = (aNewContentArea != aCurrentContentArea);
+ }
+ if (bForce || bSizeHasChanged)
+ {
+ // The browser window gets the remaining space.
+ pWindow->SetPosSizePixel (aNewContentArea.TopLeft(), aNewContentArea.GetSize());
+ mrView.Resize();
+ }
+
+ // Adapt the scroll bars to the new zoom factor of the browser
+ // window and the arrangement of the page objects.
+ GetScrollBarManager().UpdateScrollBars(!bForce);
+
+ // Keep the current slide in the visible area.
+ GetVisibleAreaManager().RequestCurrentSlideVisible();
+
+ mrView.RequestRepaint();
+}
+
+rtl::Reference<FuPoor> SlideSorterController::CreateSelectionFunction (SfxRequest& rRequest)
+{
+ rtl::Reference<FuPoor> xFunc( SelectionFunction::Create(mrSlideSorter, rRequest) );
+ return xFunc;
+}
+
+::rtl::Reference<SelectionFunction> SlideSorterController::GetCurrentSelectionFunction() const
+{
+ rtl::Reference<FuPoor> pFunction (mrSlideSorter.GetViewShell()->GetCurrentFunction());
+ return ::rtl::Reference<SelectionFunction>(dynamic_cast<SelectionFunction*>(pFunction.get()));
+}
+
+void SlideSorterController::PrepareEditModeChange()
+{
+ // Before we throw away the page descriptors we prepare for selecting
+ // descriptors in the other mode and for restoring the current
+ // selection when switching back to the current mode.
+ if (mrModel.GetEditMode() != EditMode::Page)
+ return;
+
+ maSelectionBeforeSwitch.clear();
+
+ // Search for the first selected page and determine the master page
+ // used by its page object. It will be selected after the switch.
+ // In the same loop the current selection is stored.
+ PageEnumeration aSelectedPages (
+ PageEnumerationProvider::CreateSelectedPagesEnumeration(mrModel));
+ while (aSelectedPages.HasMoreElements())
+ {
+ SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ SdPage* pPage = pDescriptor->GetPage();
+ // Remember the master page of the first selected descriptor.
+ if (pPage!=nullptr && mpEditModeChangeMasterPage==nullptr)
+ mpEditModeChangeMasterPage = &static_cast<SdPage&>(
+ pPage->TRG_GetMasterPage());
+
+ maSelectionBeforeSwitch.push_back(pPage);
+ }
+
+ // Remember the current page.
+ if (mrSlideSorter.GetViewShell() != nullptr)
+ mnCurrentPageBeforeSwitch = (mrSlideSorter.GetViewShell()->GetViewShellBase()
+ .GetMainViewShell()->GetActualPage()->GetPageNum()-1)/2;
+}
+
+void SlideSorterController::ChangeEditMode (EditMode eEditMode)
+{
+ if (mrModel.GetEditMode() != eEditMode)
+ {
+ ModelChangeLock aLock (*this);
+ PreModelChange();
+ // Do the actual edit mode switching.
+ bool bResult = mrModel.SetEditMode(eEditMode);
+ if (bResult)
+ HandleModelChange();
+ }
+}
+
+void SlideSorterController::FinishEditModeChange()
+{
+ if (mrModel.GetEditMode() == EditMode::MasterPage)
+ {
+ mpPageSelector->DeselectAllPages();
+
+ // Search for the master page that was determined in
+ // PrepareEditModeChange() and make it the current page.
+ PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
+ while (aAllPages.HasMoreElements())
+ {
+ SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
+ if (pDescriptor->GetPage() == mpEditModeChangeMasterPage)
+ {
+ GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor);
+ mpPageSelector->SelectPage(pDescriptor);
+ break;
+ }
+ }
+ }
+ else
+ {
+ PageSelector::BroadcastLock aBroadcastLock (*mpPageSelector);
+
+ SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(mnCurrentPageBeforeSwitch));
+ GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor);
+
+ // Restore the selection.
+ mpPageSelector->DeselectAllPages();
+ for (const auto& rpPage : maSelectionBeforeSwitch)
+ {
+ mpPageSelector->SelectPage(rpPage);
+ }
+ maSelectionBeforeSwitch.clear( );
+ }
+ mpEditModeChangeMasterPage = nullptr;
+}
+
+void SlideSorterController::PageNameHasChanged (int nPageIndex, const OUString& rsOldName)
+{
+ // Request a repaint for the page object whose name has changed.
+ model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
+ if (pDescriptor)
+ mrView.RequestRepaint(pDescriptor);
+
+ // Get a pointer to the corresponding accessible object and notify
+ // that of the name change.
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if ( ! pWindow)
+ return;
+
+ css::uno::Reference< css::accessibility::XAccessible >
+ xAccessible (pWindow->GetAccessible(false));
+ if ( ! xAccessible.is())
+ return;
+
+ // Now comes a small hack. We assume that the accessible object is
+ // an instantiation of AccessibleSlideSorterView and cast it to that
+ // class. The cleaner alternative to this cast would be a new member
+ // in which we would store the last AccessibleSlideSorterView object
+ // created by SlideSorterViewShell::CreateAccessibleDocumentView().
+ // But then there is no guaranty that the accessible object obtained
+ // from the window really is that instance last created by
+ // CreateAccessibleDocumentView().
+ // However, the dynamic cast together with the check of the result
+ // being NULL should be safe enough.
+ ::accessibility::AccessibleSlideSorterView* pAccessibleView
+ = dynamic_cast< ::accessibility::AccessibleSlideSorterView*>(xAccessible.get());
+ if (pAccessibleView == nullptr)
+ return;
+
+ ::accessibility::AccessibleSlideSorterObject* pChild
+ = pAccessibleView->GetAccessibleChildImplementation(nPageIndex);
+ if (pChild == nullptr || pChild->GetPage() == nullptr)
+ return;
+
+ OUString sNewName (pChild->GetPage()->GetName());
+ pChild->FireAccessibleEvent(
+ css::accessibility::AccessibleEventId::NAME_CHANGED,
+ Any(rsOldName),
+ Any(sNewName));
+}
+
+void SlideSorterController::SetDocumentSlides (const Reference<container::XIndexAccess>& rxSlides)
+{
+ if (mrModel.GetDocumentSlides() != rxSlides)
+ {
+ ModelChangeLock aLock (*this);
+ PreModelChange();
+
+ mrModel.SetDocumentSlides(rxSlides);
+ }
+}
+
+VisibleAreaManager& SlideSorterController::GetVisibleAreaManager() const
+{
+ OSL_ASSERT(mpVisibleAreaManager);
+ return *mpVisibleAreaManager;
+}
+
+void SlideSorterController::CheckForMasterPageAssignment()
+{
+ if (mrModel.GetPageCount()%2==0)
+ return;
+ PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
+ while (aAllPages.HasMoreElements())
+ {
+ SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
+ if (pDescriptor->UpdateMasterPage())
+ {
+ mrView.GetPreviewCache()->InvalidatePreviewBitmap (
+ pDescriptor->GetPage());
+ }
+ }
+}
+
+void SlideSorterController::CheckForSlideTransitionAssignment()
+{
+ if (mrModel.GetPageCount()%2==0)
+ return;
+ PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
+ while (aAllPages.HasMoreElements())
+ {
+ SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
+ if (pDescriptor->UpdateTransitionFlag())
+ {
+ mrView.GetPreviewCache()->InvalidatePreviewBitmap (
+ pDescriptor->GetPage());
+ }
+ }
+}
+
+//===== SlideSorterController::ModelChangeLock ================================
+
+SlideSorterController::ModelChangeLock::ModelChangeLock (
+ SlideSorterController& rController)
+ : mpController(&rController)
+{
+ mpController->LockModelChange();
+}
+
+SlideSorterController::ModelChangeLock::~ModelChangeLock() COVERITY_NOEXCEPT_FALSE
+{
+ Release();
+}
+
+void SlideSorterController::ModelChangeLock::Release()
+{
+ if (mpController != nullptr)
+ {
+ mpController->UnlockModelChange();
+ mpController = nullptr;
+ }
+}
+
+} // end of namespace ::sd::slidesorter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx b/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx
new file mode 100644
index 000000000..31978baf7
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/safeint.hxx>
+
+#include <controller/SlsAnimationFunction.hxx>
+
+namespace sd::slidesorter::controller {
+
+//===== AnimationBezierFunction ===============================================
+
+AnimationBezierFunction::AnimationBezierFunction (
+ const double nX1,
+ const double nY1)
+ : mnX1(nX1),
+ mnY1(nY1),
+ mnX2(1-nY1),
+ mnY2(1-nX1)
+{
+}
+
+::basegfx::B2DPoint AnimationBezierFunction::operator() (const double nT)
+{
+ return ::basegfx::B2DPoint(
+ EvaluateComponent(nT, mnX1, mnX2),
+ EvaluateComponent(nT, mnY1, mnY2));
+}
+
+double AnimationBezierFunction::EvaluateComponent (
+ const double nT,
+ const double nV1,
+ const double nV2)
+{
+ const double nS (1-nT);
+
+ // While the control point values 1 and 2 are explicitly given the start
+ // and end values are implicitly given.
+ const double nV0 (0);
+ const double nV3 (1);
+
+ const double nV01 (nS*nV0 + nT*nV1);
+ const double nV12 (nS*nV1 + nT*nV2);
+ const double nV23 (nS*nV2 + nT*nV3);
+
+ const double nV012 (nS*nV01 + nT*nV12);
+ const double nV123 (nS*nV12 + nT*nV23);
+
+ const double nV0123 (nS*nV012 + nT*nV123);
+
+ return nV0123;
+}
+
+//===== AnimationParametricFunction ===========================================
+
+AnimationParametricFunction::AnimationParametricFunction (const ParametricFunction& rFunction)
+{
+ const sal_Int32 nSampleCount (64);
+
+ // Sample the given parametric function.
+ ::std::vector<basegfx::B2DPoint> aPoints;
+ aPoints.reserve(nSampleCount);
+ for (sal_Int32 nIndex=0; nIndex<nSampleCount; ++nIndex)
+ {
+ const double nT (nIndex/double(nSampleCount-1));
+ aPoints.emplace_back(rFunction(nT));
+ }
+
+ // Interpolate at evenly spaced points.
+ maY.clear();
+ maY.reserve(nSampleCount);
+ double nX0 (aPoints[0].getX());
+ double nY0 (aPoints[0].getY());
+ double nX1 (aPoints[1].getX());
+ double nY1 (aPoints[1].getY());
+ sal_Int32 nIndex (1);
+ for (sal_Int32 nIndex2=0; nIndex2<nSampleCount; ++nIndex2)
+ {
+ const double nX (nIndex2 / double(nSampleCount-1));
+ while (nX > nX1 && nIndex<nSampleCount)
+ {
+ nX0 = nX1;
+ nY0 = nY1;
+ nX1 = aPoints[nIndex].getX();
+ nY1 = aPoints[nIndex].getY();
+ ++nIndex;
+ }
+ const double nU ((nX-nX1) / (nX0 - nX1));
+ const double nY (nY0*nU + nY1*(1-nU));
+ maY.push_back(nY);
+ }
+}
+
+double AnimationParametricFunction::operator() (const double nX)
+{
+ const sal_Int32 nIndex0 (static_cast<sal_Int32>(nX * maY.size()));
+ const double nX0 (nIndex0 / double(maY.size()-1));
+ const sal_uInt32 nIndex1 (nIndex0 + 1);
+ const double nX1 (nIndex1 / double(maY.size()-1));
+
+ if (nIndex0<=0)
+ return maY[0];
+ else if (o3tl::make_unsigned(nIndex0)>=maY.size() || nIndex1>=maY.size())
+ return maY[maY.size()-1];
+
+ const double nU ((nX-nX1) / (nX0 - nX1));
+ return maY[nIndex0]*nU + maY[nIndex1]*(1-nU);
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsAnimator.cxx b/sd/source/ui/slidesorter/controller/SlsAnimator.cxx
new file mode 100644
index 000000000..b400ec4dc
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsAnimator.cxx
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <controller/SlsAnimator.hxx>
+#include <view/SlideSorterView.hxx>
+#include <osl/diagnose.h>
+
+namespace sd::slidesorter::controller {
+
+/** Handle one animation function by using a timer for frequent calls to
+ the animations operator().
+*/
+class Animator::Animation
+{
+public:
+ Animation (
+ const Animator::AnimationFunctor& rAnimation,
+ const double nStartOffset,
+ const double nDuration,
+ const double nGlobalTime,
+ const Animator::AnimationId nAnimationId,
+ const Animator::FinishFunctor& rFinishFunctor);
+ /** Run next animation step. If animation has reached its end it is
+ expired.
+ */
+ bool Run (const double nGlobalTime);
+
+ /** Typically called when an animation has finished, but also from
+ Animator::Disposed(). The finish functor is called and the
+ animation is marked as expired to prevent another run.
+ */
+ void Expire();
+ bool IsExpired() const { return mbIsExpired;}
+
+ Animator::AnimationFunctor maAnimation;
+ Animator::FinishFunctor maFinishFunctor;
+ const Animator::AnimationId mnAnimationId;
+ const double mnDuration;
+ const double mnEnd;
+ const double mnGlobalTimeAtStart;
+ bool mbIsExpired;
+};
+
+Animator::Animator (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ maIdle("sd slidesorter controller Animator"),
+ mbIsDisposed(false),
+ mnNextAnimationId(0)
+{
+ maIdle.SetPriority(TaskPriority::REPAINT);
+ maIdle.SetInvokeHandler(LINK(this,Animator,TimeoutHandler));
+}
+
+Animator::~Animator()
+{
+ if ( ! mbIsDisposed)
+ {
+ OSL_ASSERT(mbIsDisposed);
+ Dispose();
+ }
+}
+
+void Animator::Dispose()
+{
+ mbIsDisposed = true;
+
+ AnimationList aCopy (maAnimations);
+ for (const auto& rxAnimation : aCopy)
+ rxAnimation->Expire();
+
+ maIdle.Stop();
+ if (mpDrawLock)
+ {
+ mpDrawLock->Dispose();
+ mpDrawLock.reset();
+ }
+}
+
+Animator::AnimationId Animator::AddAnimation (
+ const AnimationFunctor& rAnimation,
+ const FinishFunctor& rFinishFunctor)
+{
+ // When the animator is already disposed then ignore this call
+ // silently (well, we show an assertion, but do not throw an exception.)
+ OSL_ASSERT( ! mbIsDisposed);
+ if (mbIsDisposed)
+ return -1;
+
+ std::shared_ptr<Animation> pAnimation =
+ std::make_shared<Animation>(
+ rAnimation,
+ 0,
+ 300 / 1000.0,
+ maElapsedTime.getElapsedTime(),
+ ++mnNextAnimationId,
+ rFinishFunctor);
+ maAnimations.push_back(pAnimation);
+
+ RequestNextFrame();
+
+ return pAnimation->mnAnimationId;
+}
+
+void Animator::RemoveAnimation (const Animator::AnimationId nId)
+{
+ OSL_ASSERT( ! mbIsDisposed);
+
+ const AnimationList::iterator iAnimation (::std::find_if(
+ maAnimations.begin(),
+ maAnimations.end(),
+ [nId] (std::shared_ptr<Animation> const& pAnim)
+ { return nId == pAnim->mnAnimationId; }));
+ if (iAnimation != maAnimations.end())
+ {
+ OSL_ASSERT((*iAnimation)->mnAnimationId == nId);
+ (*iAnimation)->Expire();
+ maAnimations.erase(iAnimation);
+ }
+
+ if (maAnimations.empty())
+ {
+ // Reset the animation id when we can.
+ mnNextAnimationId = 0;
+
+ // No more animations => we do not have to suppress painting
+ // anymore.
+ mpDrawLock.reset();
+ }
+}
+
+void Animator::RemoveAllAnimations()
+{
+ for (auto const& it : maAnimations)
+ {
+ it->Expire();
+ }
+ maAnimations.clear();
+ mnNextAnimationId = 0;
+
+ // No more animations => we do not have to suppress painting
+ // anymore.
+ mpDrawLock.reset();
+}
+
+bool Animator::ProcessAnimations (const double nTime)
+{
+ bool bExpired (false);
+
+ OSL_ASSERT( ! mbIsDisposed);
+ if (mbIsDisposed)
+ return bExpired;
+
+ AnimationList aCopy (maAnimations);
+ for (const auto& rxAnimation : aCopy)
+ {
+ bExpired |= rxAnimation->Run(nTime);
+ }
+
+ return bExpired;
+}
+
+void Animator::CleanUpAnimationList()
+{
+ OSL_ASSERT( ! mbIsDisposed);
+ if (mbIsDisposed)
+ return;
+
+ AnimationList aActiveAnimations;
+
+ for (const auto& rxAnimation : maAnimations)
+ {
+ if ( ! rxAnimation->IsExpired())
+ aActiveAnimations.push_back(rxAnimation);
+ }
+
+ maAnimations.swap(aActiveAnimations);
+}
+
+void Animator::RequestNextFrame ()
+{
+ if ( ! maIdle.IsActive())
+ {
+ // Prevent redraws except for the ones in TimeoutHandler. While the
+ // Animator is active it will schedule repaints regularly. Repaints
+ // in between would only lead to visual artifacts.
+ mpDrawLock.reset(new view::SlideSorterView::DrawLock(mrSlideSorter));
+ maIdle.Start();
+ }
+}
+
+IMPL_LINK_NOARG(Animator, TimeoutHandler, Timer *, void)
+{
+ if (mbIsDisposed)
+ return;
+
+ if (ProcessAnimations(maElapsedTime.getElapsedTime()))
+ CleanUpAnimationList();
+
+ // Unlock the draw lock. This should lead to a repaint.
+ mpDrawLock.reset();
+
+ if (!maAnimations.empty())
+ RequestNextFrame();
+}
+
+//===== Animator::Animation ===================================================
+
+Animator::Animation::Animation (
+ const Animator::AnimationFunctor& rAnimation,
+ const double nStartOffset,
+ const double nDuration,
+ const double nGlobalTime,
+ const Animator::AnimationId nId,
+ const Animator::FinishFunctor& rFinishFunctor)
+ : maAnimation(rAnimation),
+ maFinishFunctor(rFinishFunctor),
+ mnAnimationId(nId),
+ mnDuration(nDuration),
+ mnEnd(nGlobalTime + nDuration + nStartOffset),
+ mnGlobalTimeAtStart(nGlobalTime + nStartOffset),
+ mbIsExpired(false)
+{
+ Run(nGlobalTime);
+}
+
+bool Animator::Animation::Run (const double nGlobalTime)
+{
+ if ( ! mbIsExpired)
+ {
+ if (mnDuration > 0)
+ {
+ if (nGlobalTime >= mnEnd)
+ {
+ maAnimation(1.0);
+ Expire();
+ }
+ else if (nGlobalTime >= mnGlobalTimeAtStart)
+ {
+ maAnimation((nGlobalTime - mnGlobalTimeAtStart) / mnDuration);
+ }
+ }
+ else if (mnDuration < 0)
+ {
+ // Animations without end have to be expired by their owner.
+ maAnimation(nGlobalTime);
+ }
+ }
+
+ return mbIsExpired;
+}
+
+void Animator::Animation::Expire()
+{
+ if ( ! mbIsExpired)
+ {
+ mbIsExpired = true;
+ if (maFinishFunctor)
+ maFinishFunctor();
+ }
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx
new file mode 100644
index 000000000..160077e64
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx
@@ -0,0 +1,918 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <controller/SlsClipboard.hxx>
+
+#include <SlideSorterViewShell.hxx>
+#include <SlideSorter.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <view/SlideSorterView.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsInsertionIndicatorHandler.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsSelectionFunction.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <controller/SlsFocusManager.hxx>
+#include <controller/SlsSelectionManager.hxx>
+#include <controller/SlsTransferableData.hxx>
+#include <controller/SlsSelectionObserver.hxx>
+#include <controller/SlsVisibleAreaManager.hxx>
+#include <cache/SlsPageCache.hxx>
+
+#include <ViewShellBase.hxx>
+#include <DrawViewShell.hxx>
+#include <Window.hxx>
+#include <fupoor.hxx>
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <sdxfer.hxx>
+#include <sdmod.hxx>
+#include <ins_paste.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <sdpage.hxx>
+#include <sdtreelb.hxx>
+
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/docfile.hxx>
+#include <svx/svxids.hrc>
+#include <tools/urlobj.hxx>
+#include <rtl/ustring.hxx>
+#include <vcl/svapp.hxx>
+
+namespace sd::slidesorter::controller {
+
+namespace {
+/** Temporarily deactivate slide tracking of the VisibleAreaManager.
+ This is used as a workaround to avoid unwanted repositioning of
+ the visible area when the selection of slides is copied to the
+ clipboard (cloning of slides leads to model change notifications
+ for the original model.)
+*/
+class TemporarySlideTrackingDeactivator
+{
+public:
+ explicit TemporarySlideTrackingDeactivator (SlideSorterController& rController)
+ : mrController(rController),
+ mbIsCurrentSlideTrackingActive (
+ mrController.GetVisibleAreaManager().IsCurrentSlideTrackingActive())
+ {
+ if (mbIsCurrentSlideTrackingActive)
+ mrController.GetVisibleAreaManager().DeactivateCurrentSlideTracking();
+ }
+ ~TemporarySlideTrackingDeactivator()
+ {
+ if (mbIsCurrentSlideTrackingActive)
+ mrController.GetVisibleAreaManager().ActivateCurrentSlideTracking();
+ }
+
+private:
+ SlideSorterController& mrController;
+ const bool mbIsCurrentSlideTrackingActive;
+};
+} // end of anonymous namespace
+
+class Clipboard::UndoContext
+{
+public:
+ UndoContext (
+ SdDrawDocument* pDocument,
+ const std::shared_ptr<ViewShell>& rpMainViewShell)
+ : mpDocument(pDocument),
+ mpMainViewShell(rpMainViewShell)
+ {
+ if (mpDocument!=nullptr && mpDocument->IsUndoEnabled())
+ {
+ if (mpMainViewShell && mpMainViewShell->GetShellType() == ViewShell::ST_DRAW)
+ mpDocument->BegUndo(SdResId(STRING_DRAG_AND_DROP_PAGES));
+ else
+ mpDocument->BegUndo(SdResId(STRING_DRAG_AND_DROP_SLIDES));
+ }
+ }
+
+ ~UndoContext()
+ {
+ if (mpDocument!=nullptr && mpDocument->IsUndoEnabled())
+ mpDocument->EndUndo();
+ if (mpMainViewShell && mpMainViewShell->GetViewFrame()!=nullptr)
+ {
+ SfxBindings& rBindings = mpMainViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_UNDO);
+ rBindings.Invalidate(SID_REDO);
+ }
+ }
+private:
+ SdDrawDocument* mpDocument;
+ std::shared_ptr<ViewShell> mpMainViewShell;
+};
+
+Clipboard::Clipboard (SlideSorter& rSlideSorter)
+ : ViewClipboard(rSlideSorter.GetView()),
+ mrSlideSorter(rSlideSorter),
+ mrController(mrSlideSorter.GetController()),
+ mnDragFinishedUserEventId(nullptr)
+{
+}
+
+Clipboard::~Clipboard()
+{
+ if (mnDragFinishedUserEventId != nullptr)
+ Application::RemoveUserEvent(mnDragFinishedUserEventId);
+}
+
+/** With the current implementation the forwarded calls to the current
+ function will come back eventually to call the local Do(Cut|Copy|Paste)
+ methods. A shortcut is possible but would be an unclean hack.
+*/
+void Clipboard::HandleSlotCall (SfxRequest& rRequest)
+{
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ rtl::Reference<FuPoor> xFunc;
+ if (pViewShell != nullptr)
+ xFunc = pViewShell->GetCurrentFunction();
+ switch (rRequest.GetSlot())
+ {
+ case SID_CUT:
+ if (mrSlideSorter.GetModel().GetEditMode() != EditMode::MasterPage)
+ {
+ if(xFunc.is())
+ xFunc->DoCut();
+ else
+ DoCut();
+ }
+ rRequest.Done();
+ break;
+
+ case SID_COPY:
+ if (mrSlideSorter.GetModel().GetEditMode() != EditMode::MasterPage)
+ {
+ if(xFunc.is())
+ xFunc->DoCopy();
+ else
+ DoCopy();
+ }
+ rRequest.Done();
+ break;
+
+ case SID_PASTE:
+ // Prevent redraws while inserting pages from the clipboard
+ // because the intermediate inconsistent state might lead to
+ // a crash.
+ if (mrSlideSorter.GetModel().GetEditMode() != EditMode::MasterPage)
+ {
+ view::SlideSorterView::DrawLock aLock (mrSlideSorter);
+ SelectionObserver::Context aContext (mrSlideSorter);
+ if(xFunc.is())
+ xFunc->DoPaste();
+ else
+ DoPaste();
+ }
+ rRequest.Done();
+ break;
+
+ case SID_DELETE:
+ DoDelete();
+ rRequest.Done();
+ break;
+ }
+}
+
+void Clipboard::DoCut ()
+{
+ if (mrSlideSorter.GetModel().GetPageCount() > 1)
+ {
+ DoCopy();
+ DoDelete();
+ }
+}
+
+void Clipboard::DoDelete()
+{
+ if (mrSlideSorter.GetModel().GetPageCount() > 1)
+ {
+ mrController.GetSelectionManager()->DeleteSelectedPages();
+ }
+}
+
+void Clipboard::DoCopy ()
+{
+ CreateSlideTransferable( nullptr, false );
+}
+
+void Clipboard::DoPaste ()
+{
+ SdTransferable* pClipTransferable = SD_MOD()->pTransferClip;
+
+ if (pClipTransferable==nullptr || !pClipTransferable->IsPageTransferable())
+ return;
+
+ sal_Int32 nInsertPosition = GetInsertionPosition();
+
+ if (nInsertPosition >= 0)
+ {
+ // Paste the pages from the clipboard.
+ sal_Int32 nInsertPageCount = PasteTransferable(nInsertPosition);
+ // Select the pasted pages and make the first of them the
+ // current page.
+ mrSlideSorter.GetContentWindow()->GrabFocus();
+ SelectPageRange(nInsertPosition, nInsertPageCount);
+ }
+}
+
+sal_Int32 Clipboard::GetInsertionPosition ()
+{
+ sal_Int32 nInsertPosition = -1;
+
+ // Determine the insertion position:
+ // a) When the insertion indicator is visible, then at that position.
+ // b) When the focus indicator is visible, then before or after the
+ // focused page, depending on user input to a dialog.
+ // c) When there is a selection but no focus, then after the
+ // selection.
+ // d) After the last page when there is no selection and no focus.
+
+ std::shared_ptr<controller::InsertionIndicatorHandler> pInsertionIndicatorHandler (
+ mrController.GetInsertionIndicatorHandler());
+ if (pInsertionIndicatorHandler->IsActive())
+ {
+ // Use the insertion index of an active insertion indicator.
+ nInsertPosition = pInsertionIndicatorHandler->GetInsertionPageIndex();
+ }
+ else if (mrController.GetSelectionManager()->GetInsertionPosition() >= 0)
+ {
+ // Use the insertion index of an insertion indicator that has been
+ // deactivated a short while ago.
+ nInsertPosition = mrController.GetSelectionManager()->GetInsertionPosition();
+ }
+ else if (mrController.GetFocusManager().IsFocusShowing())
+ {
+ // Use the focus to determine the insertion position.
+ vcl::Window* pWin = mrSlideSorter.GetContentWindow();
+ SdInsertPasteDlg aDialog(pWin ? pWin->GetFrameWeld() : nullptr);
+ if (aDialog.run() == RET_OK)
+ {
+ nInsertPosition = mrController.GetFocusManager().GetFocusedPageIndex();
+ if (!aDialog.IsInsertBefore())
+ nInsertPosition ++;
+ }
+ }
+
+ return nInsertPosition;
+}
+
+sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition)
+{
+ SdTransferable* pClipTransferable = SD_MOD()->pTransferClip;
+ model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
+ bool bMergeMasterPages = !pClipTransferable->HasSourceDoc (rModel.GetDocument());
+ sal_uInt16 nInsertIndex (rModel.GetCoreIndex(nInsertPosition));
+ sal_Int32 nInsertPageCount (0);
+ if (pClipTransferable->HasPageBookmarks())
+ {
+ const std::vector<OUString> &rBookmarkList = pClipTransferable->GetPageBookmarks();
+ const SolarMutexGuard aGuard;
+
+ nInsertPageCount = static_cast<sal_uInt16>(rBookmarkList.size());
+ rModel.GetDocument()->InsertBookmarkAsPage(
+ rBookmarkList,
+ nullptr,
+ false,
+ false,
+ nInsertIndex,
+ false,
+ pClipTransferable->GetPageDocShell(),
+ true,
+ bMergeMasterPages,
+ false);
+ }
+ else
+ {
+ SfxObjectShell* pShell = pClipTransferable->GetDocShell().get();
+ DrawDocShell* pDataDocSh = static_cast<DrawDocShell*>(pShell);
+ SdDrawDocument* pDataDoc = pDataDocSh->GetDoc();
+
+ if (pDataDoc!=nullptr
+ && pDataDoc->GetSdPageCount(PageKind::Standard))
+ {
+ const SolarMutexGuard aGuard;
+
+ bMergeMasterPages = (pDataDoc != rModel.GetDocument());
+ nInsertPageCount = pDataDoc->GetSdPageCount( PageKind::Standard );
+ rModel.GetDocument()->InsertBookmarkAsPage(
+ std::vector<OUString>(),
+ nullptr,
+ false,
+ false,
+ nInsertIndex,
+ false,
+ pDataDocSh,
+ true,
+ bMergeMasterPages,
+ false);
+ }
+ }
+ mrController.HandleModelChange();
+ return nInsertPageCount;
+}
+
+void Clipboard::SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount)
+{
+ // Select the newly inserted pages. That are the nInsertPageCount pages
+ // after the nInsertIndex position.
+ PageSelector& rSelector (mrController.GetPageSelector());
+ rSelector.DeselectAllPages();
+ for (sal_Int32 i=0; i<nPageCount; i++)
+ {
+ model::SharedPageDescriptor pDescriptor (
+ mrSlideSorter.GetModel().GetPageDescriptor(nFirstIndex + i));
+ if (pDescriptor)
+ {
+ rSelector.SelectPage(pDescriptor);
+ // The first page of the new selection is made the current page.
+ if (i == 0)
+ {
+ mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor);
+ }
+ }
+ }
+}
+
+void Clipboard::CreateSlideTransferable (
+ vcl::Window* pWindow,
+ bool bDrag)
+{
+ std::vector<OUString> aBookmarkList;
+
+ // Insert all selected pages into a bookmark list and remember them in
+ // maPagesToRemove for possible later removal.
+ model::PageEnumeration aSelectedPages
+ (model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ SdDrawDocument* const pDocument = mrSlideSorter.GetModel().GetDocument();
+ DrawDocShell* const pDataDocSh = pDocument->GetDocSh();
+
+ sal_Int32 nUniqueID = 0;
+ while (aSelectedPages.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+
+ //ensure that the slides have unique names
+ const OUString sOrigName = pDescriptor->GetPage()->GetName();
+ if ( pDataDocSh && !pDataDocSh->IsPageNameUnique( sOrigName ) )
+ {
+ OUString sUniqueName;
+ bool bUnique = false;
+ while ( !bUnique )
+ {
+ sUniqueName = sOrigName + "_clipboard" + OUString::number(nUniqueID++);
+ bUnique = pDataDocSh->IsNewPageNameValid( sUniqueName );
+ if ( bUnique )
+ pDescriptor->GetPage()->SetName(sUniqueName);
+ }
+ }
+
+ aBookmarkList.push_back(pDescriptor->GetPage()->GetName());
+ maPagesToRemove.push_back (pDescriptor->GetPage());
+ }
+
+ // Create a small set of representatives of the selection for which
+ // previews are included into the transferable so that an insertion
+ // indicator can be rendered.
+ aSelectedPages.Rewind();
+ ::std::vector<TransferableData::Representative> aRepresentatives;
+ aRepresentatives.reserve(3);
+ std::shared_ptr<cache::PageCache> pPreviewCache (
+ mrSlideSorter.GetView().GetPreviewCache());
+ while (aSelectedPages.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ if ( ! pDescriptor || pDescriptor->GetPage()==nullptr)
+ continue;
+ BitmapEx aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false));
+ aRepresentatives.emplace_back(
+ aPreview,
+ pDescriptor->HasState(model::PageDescriptor::ST_Excluded));
+ if (aRepresentatives.size() >= 3)
+ break;
+ }
+
+ if (aBookmarkList.empty())
+ return;
+
+ mrSlideSorter.GetView().BrkAction();
+ rtl::Reference<SdTransferable> pTransferable = TransferableData::CreateTransferable (
+ pDocument,
+ dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()),
+ std::move(aRepresentatives));
+
+ if (bDrag)
+ SD_MOD()->pTransferDrag = pTransferable.get();
+ else
+ SD_MOD()->pTransferClip = pTransferable.get();
+
+ pDocument->CreatingDataObj (pTransferable.get());
+ pTransferable->SetWorkDocument(pDocument->AllocSdDrawDocument());
+ std::unique_ptr<TransferableObjectDescriptor> pObjDesc(new TransferableObjectDescriptor);
+ pTransferable->GetWorkDocument()->GetDocSh()
+ ->FillTransferableObjectDescriptor (*pObjDesc);
+
+ if (pDataDocSh != nullptr)
+ pObjDesc->maDisplayName = pDataDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+
+ vcl::Window* pActionWindow = pWindow;
+ if (pActionWindow == nullptr)
+ {
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (pViewShell != nullptr)
+ pActionWindow = pViewShell->GetActiveWindow();
+ }
+
+ assert(pActionWindow);
+
+ pTransferable->SetStartPos (pActionWindow->PixelToLogic(
+ pActionWindow->GetPointerPosPixel()));
+ pTransferable->SetObjectDescriptor (std::move(pObjDesc));
+
+ {
+ TemporarySlideTrackingDeactivator aDeactivator (mrController);
+ pTransferable->SetPageBookmarks (std::move(aBookmarkList), !bDrag);
+ }
+
+ if (bDrag)
+ {
+ pTransferable->SetView (&mrSlideSorter.GetView());
+ pTransferable->StartDrag (pActionWindow, DND_ACTION_COPY | DND_ACTION_MOVE);
+ }
+ else
+ pTransferable->CopyToClipboard (pActionWindow);
+
+ pDocument->CreatingDataObj(nullptr);
+}
+
+std::shared_ptr<SdTransferable::UserData> Clipboard::CreateTransferableUserData (SdTransferable* pTransferable)
+{
+ do
+ {
+ SdPageObjsTLV::SdPageObjsTransferable* pTreeListBoxTransferable
+ = dynamic_cast<SdPageObjsTLV::SdPageObjsTransferable*>(pTransferable);
+ if (pTreeListBoxTransferable == nullptr)
+ break;
+
+ // Find view shell for the document of the transferable.
+ ::sd::ViewShell* pViewShell
+ = SdPageObjsTLV::GetViewShellForDocShell(pTreeListBoxTransferable->GetDocShell());
+ if (pViewShell == nullptr)
+ break;
+
+ // Find slide sorter for the document of the transferable.
+ SlideSorterViewShell* pSlideSorterViewShell
+ = SlideSorterViewShell::GetSlideSorter(pViewShell->GetViewShellBase());
+ if (pSlideSorterViewShell == nullptr)
+ break;
+ SlideSorter& rSlideSorter (pSlideSorterViewShell->GetSlideSorter());
+
+ // Get bookmark from transferable.
+ TransferableDataHelper aDataHelper (pTransferable);
+ INetBookmark aINetBookmark;
+ if ( ! aDataHelper.GetINetBookmark(SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark))
+ break;
+ const OUString sURL (aINetBookmark.GetURL());
+ const sal_Int32 nIndex (sURL.indexOf('#'));
+ if (nIndex == -1)
+ break;
+ OUString sBookmark (sURL.copy(nIndex+1));
+
+ // Make sure that the bookmark points to a page.
+ SdDrawDocument* pTransferableDocument = rSlideSorter.GetModel().GetDocument();
+ if (pTransferableDocument == nullptr)
+ break;
+ bool bIsMasterPage = false;
+ const sal_uInt16 nPageIndex (pTransferableDocument->GetPageByName(sBookmark, bIsMasterPage));
+ if (nPageIndex == SDRPAGE_NOTFOUND)
+ break;
+
+ // Create preview.
+ ::std::vector<TransferableData::Representative> aRepresentatives;
+ aRepresentatives.reserve(1);
+ std::shared_ptr<cache::PageCache> pPreviewCache (
+ rSlideSorter.GetView().GetPreviewCache());
+ model::SharedPageDescriptor pDescriptor (rSlideSorter.GetModel().GetPageDescriptor((nPageIndex-1)/2));
+ if ( ! pDescriptor || pDescriptor->GetPage()==nullptr)
+ break;
+ BitmapEx aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false));
+ aRepresentatives.emplace_back(
+ aPreview,
+ pDescriptor->HasState(model::PageDescriptor::ST_Excluded));
+
+ // Remember the page in maPagesToRemove so that it can be removed
+ // when drag and drop action is "move".
+ Clipboard& rOtherClipboard (pSlideSorterViewShell->GetSlideSorter().GetController().GetClipboard());
+ rOtherClipboard.maPagesToRemove.clear();
+ rOtherClipboard.maPagesToRemove.push_back(pDescriptor->GetPage());
+
+ // Create the new transferable.
+ std::shared_ptr<SdTransferable::UserData> pNewTransferable =
+ std::make_shared<TransferableData>(
+ pSlideSorterViewShell,
+ std::move(aRepresentatives));
+ pTransferable->SetWorkDocument(pTreeListBoxTransferable->GetSourceDoc()->AllocSdDrawDocument());
+ // pTransferable->SetView(&mrSlideSorter.GetView());
+
+ // Set page bookmark list.
+ std::vector<OUString> aPageBookmarks { sBookmark };
+ pTransferable->SetPageBookmarks(std::move(aPageBookmarks), false);
+
+ // Replace the view referenced by the transferable with the
+ // corresponding slide sorter view.
+ pTransferable->SetView(&pSlideSorterViewShell->GetSlideSorter().GetView());
+
+ return pNewTransferable;
+ }
+ while (false);
+
+ return std::shared_ptr<SdTransferable::UserData>();
+}
+
+void Clipboard::StartDrag (
+ const Point& rPosition,
+ vcl::Window* pWindow)
+{
+ maPagesToRemove.clear();
+ CreateSlideTransferable(pWindow, true);
+
+ mrController.GetInsertionIndicatorHandler()->UpdatePosition(
+ rPosition,
+ InsertionIndicatorHandler::UnknownMode);
+}
+
+void Clipboard::DragFinished (sal_Int8 nDropAction)
+{
+ if (mnDragFinishedUserEventId == nullptr)
+ {
+ mnDragFinishedUserEventId = Application::PostUserEvent(
+ LINK(this, Clipboard, ProcessDragFinished),
+ reinterpret_cast<void*>(nDropAction));
+ }
+}
+
+IMPL_LINK(Clipboard, ProcessDragFinished, void*, pUserData, void)
+{
+ const sal_Int8 nDropAction (static_cast<sal_Int8>(reinterpret_cast<sal_IntPtr>(pUserData)));
+
+ mnDragFinishedUserEventId = nullptr;
+
+ // Hide the substitution display and insertion indicator.
+ ::rtl::Reference<SelectionFunction> pFunction (mrController.GetCurrentSelectionFunction());
+ if (pFunction.is())
+ pFunction->NotifyDragFinished();
+
+ PageSelector& rSelector (mrController.GetPageSelector());
+ if ((nDropAction & DND_ACTION_MOVE) != 0
+ && ! maPagesToRemove.empty())
+ {
+ // Remove the pages that have been moved to another place (possibly
+ // in the same document.)
+ rSelector.DeselectAllPages();
+ for (const auto& rpDraggedPage : maPagesToRemove)
+ {
+ rSelector.SelectPage(rpDraggedPage);
+ }
+ mrController.GetSelectionManager()->DeleteSelectedPages();
+ }
+ mxUndoContext.reset();
+ mxSelectionObserverContext.reset();
+}
+
+sal_Int8 Clipboard::AcceptDrop (
+ const AcceptDropEvent& rEvent,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer)
+{
+ sal_Int8 nAction (DND_ACTION_NONE);
+
+ const Clipboard::DropType eDropType (IsDropAccepted());
+
+ switch (eDropType)
+ {
+ case DT_PAGE:
+ case DT_PAGE_FROM_NAVIGATOR:
+ {
+ // Accept a drop.
+ nAction = rEvent.mnAction;
+
+ // Use the copy action when the drop action is the default, i.e. not
+ // explicitly set to move or link, and when the source and
+ // target models are not the same.
+ SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
+ if (pDragTransferable != nullptr
+ && pDragTransferable->IsPageTransferable()
+ && ((rEvent.maDragEvent.DropAction
+ & css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT) != 0)
+ && (mrSlideSorter.GetModel().GetDocument()->GetDocSh()
+ != pDragTransferable->GetPageDocShell()))
+ {
+ nAction = DND_ACTION_COPY;
+ }
+ else if (IsInsertionTrivial(pDragTransferable, nAction))
+ {
+ nAction = DND_ACTION_NONE;
+ }
+
+ // Show the insertion marker and the substitution for a drop.
+ SelectionFunction* pSelectionFunction = dynamic_cast<SelectionFunction*>(
+ mrSlideSorter.GetViewShell()->GetCurrentFunction().get());
+ if (pSelectionFunction != nullptr)
+ pSelectionFunction->MouseDragged(rEvent, nAction);
+
+ // Scroll the window when the mouse reaches the window border.
+ // mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel);
+ }
+ break;
+
+ case DT_SHAPE:
+ nAction = ExecuteOrAcceptShapeDrop(
+ DC_ACCEPT,
+ rEvent.maPosPixel,
+ &rEvent,
+ rTargetHelper,
+ pTargetWindow,
+ nPage,
+ nLayer);
+ break;
+
+ default:
+ case DT_NONE:
+ nAction = DND_ACTION_NONE;
+ break;
+ }
+
+ return nAction;
+}
+
+sal_Int8 Clipboard::ExecuteDrop (
+ const ExecuteDropEvent& rEvent,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer)
+{
+ sal_Int8 nResult = DND_ACTION_NONE;
+ mxUndoContext.reset();
+ const Clipboard::DropType eDropType (IsDropAccepted());
+
+ switch (eDropType)
+ {
+ case DT_PAGE:
+ case DT_PAGE_FROM_NAVIGATOR:
+ {
+ SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
+ const Point aEventModelPosition (
+ pTargetWindow->PixelToLogic (rEvent.maPosPixel));
+ const sal_Int32 nXOffset (std::abs (pDragTransferable->GetStartPos().X()
+ - aEventModelPosition.X()));
+ const sal_Int32 nYOffset (std::abs (pDragTransferable->GetStartPos().Y()
+ - aEventModelPosition.Y()));
+ bool bContinue =
+ ( pDragTransferable->GetView() != &mrSlideSorter.GetView() )
+ || ( nXOffset >= 2 && nYOffset >= 2 );
+
+ std::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler(
+ mrController.GetInsertionIndicatorHandler());
+ // Get insertion position and then turn off the insertion indicator.
+ pInsertionIndicatorHandler->UpdatePosition(aEventModelPosition, rEvent.mnAction);
+ // sal_uInt16 nIndex = DetermineInsertPosition(*pDragTransferable);
+
+ // Do not process the insertion when it is trivial,
+ // i.e. would insert pages at their original place.
+ if (IsInsertionTrivial(pDragTransferable, rEvent.mnAction))
+ bContinue = false;
+
+ // Tell the insertion indicator handler to hide before the model
+ // is modified. Doing it later may result in page objects whose
+ // animation state is not properly reset because they are then
+ // in another run then before the model change.
+ pInsertionIndicatorHandler->End(Animator::AM_Immediate);
+
+ if (bContinue)
+ {
+ SlideSorterController::ModelChangeLock aModelChangeLock (mrController);
+
+ // Handle a general drop operation.
+ mxUndoContext.reset(new UndoContext (
+ mrSlideSorter.GetModel().GetDocument(),
+ mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell()));
+ mxSelectionObserverContext.reset(new SelectionObserver::Context(mrSlideSorter));
+
+ if (rEvent.mnAction == DND_ACTION_MOVE)
+ {
+ SdDrawDocument* pDoc = mrSlideSorter.GetModel().GetDocument();
+ const bool bDoesMakePageObjectsNamesUnique = pDoc->DoesMakePageObjectsNamesUnique();
+ pDoc->DoMakePageObjectsNamesUnique(false);
+ HandlePageDrop(*pDragTransferable);
+ pDoc->DoMakePageObjectsNamesUnique(bDoesMakePageObjectsNamesUnique);
+ }
+ else
+ HandlePageDrop(*pDragTransferable);
+
+ nResult = rEvent.mnAction;
+
+ // We leave the undo context alive for when moving or
+ // copying inside one view then the actions in
+ // NotifyDragFinished should be covered as well as
+ // well as the ones above.
+ }
+
+ // When the pages originated in another slide sorter then
+ // only that is notified automatically about the drag
+ // operation being finished. Because the target slide sorter
+ // has be notified, too, add a callback for that.
+ std::shared_ptr<TransferableData> pSlideSorterTransferable (
+ TransferableData::GetFromTransferable(pDragTransferable));
+ assert(pSlideSorterTransferable);
+ if (pSlideSorterTransferable
+ && pSlideSorterTransferable->GetSourceViewShell() != mrSlideSorter.GetViewShell())
+ {
+ DragFinished(nResult);
+ }
+
+ // Notify the receiving selection function that drag-and-drop is
+ // finished and the substitution handler can be released.
+ ::rtl::Reference<SelectionFunction> pFunction (
+ mrController.GetCurrentSelectionFunction());
+ if (pFunction.is())
+ pFunction->NotifyDragFinished();
+ }
+ break;
+
+ case DT_SHAPE:
+ nResult = ExecuteOrAcceptShapeDrop(
+ DC_EXECUTE,
+ rEvent.maPosPixel,
+ &rEvent,
+ rTargetHelper,
+ pTargetWindow,
+ nPage,
+ nLayer);
+ break;
+
+ default:
+ case DT_NONE:
+ break;
+ }
+
+ return nResult;
+}
+
+bool Clipboard::IsInsertionTrivial (
+ SdTransferable const * pTransferable,
+ const sal_Int8 nDndAction) const
+{
+ std::shared_ptr<TransferableData> pSlideSorterTransferable (
+ TransferableData::GetFromTransferable(pTransferable));
+ if (pSlideSorterTransferable
+ && pSlideSorterTransferable->GetSourceViewShell() != mrSlideSorter.GetViewShell())
+ return false;
+ return mrController.GetInsertionIndicatorHandler()->IsInsertionTrivial(nDndAction);
+}
+
+void Clipboard::Abort()
+{
+ if (mxSelectionObserverContext)
+ {
+ mxSelectionObserverContext->Abort();
+ mxSelectionObserverContext.reset();
+ }
+}
+
+sal_uInt16 Clipboard::DetermineInsertPosition ()
+{
+ // Tell the model to move the dragged pages behind the one with the
+ // index nInsertionIndex which first has to be transformed into an index
+ // understandable by the document.
+ const sal_Int32 nInsertionIndex (
+ mrController.GetInsertionIndicatorHandler()->GetInsertionPageIndex());
+
+ // Convert to insertion index to that of an SdModel.
+ if (nInsertionIndex >= 0)
+ return mrSlideSorter.GetModel().GetCoreIndex(nInsertionIndex);
+ else
+ return 0;
+}
+
+Clipboard::DropType Clipboard::IsDropAccepted() const
+{
+ const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
+ if (pDragTransferable == nullptr)
+ return DT_NONE;
+
+ if (pDragTransferable->IsPageTransferable())
+ {
+ if (mrSlideSorter.GetModel().GetEditMode() != EditMode::MasterPage)
+ return DT_PAGE;
+ else
+ return DT_NONE;
+ }
+
+ const SdPageObjsTLV::SdPageObjsTransferable* pPageObjsTransferable
+ = dynamic_cast<const SdPageObjsTLV::SdPageObjsTransferable*>(pDragTransferable);
+ if (pPageObjsTransferable != nullptr)
+ return DT_PAGE_FROM_NAVIGATOR;
+
+ return DT_SHAPE;
+}
+
+sal_Int8 Clipboard::ExecuteOrAcceptShapeDrop (
+ DropCommand eCommand,
+ const Point& rPosition,
+ const void* pDropEvent,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer)
+{
+ sal_Int8 nResult = 0;
+
+ // The dropping of a shape is accepted or executed only when there is
+ // DrawViewShell available to which we can forward this call. This has
+ // technical reasons: The actual code to accept or execute a shape drop
+ // is implemented in the ViewShell class and uses the page view of the
+ // main edit view. This is not possible without a DrawViewShell.
+ std::shared_ptr<DrawViewShell> pDrawViewShell;
+ if (mrSlideSorter.GetViewShell() != nullptr)
+ pDrawViewShell = std::dynamic_pointer_cast<DrawViewShell>(
+ mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell());
+ if (pDrawViewShell != nullptr
+ && (pDrawViewShell->GetShellType() == ViewShell::ST_IMPRESS
+ || pDrawViewShell->GetShellType() == ViewShell::ST_DRAW))
+ {
+ // The drop is only accepted or executed when it takes place over a
+ // page object. Therefore we replace a missing page number by the
+ // number of the page under the mouse.
+ if (nPage == SDRPAGE_NOTFOUND)
+ {
+ model::SharedPageDescriptor pDescriptor (
+ mrSlideSorter.GetModel().GetPageDescriptor(
+ mrSlideSorter.GetView().GetPageIndexAtPoint(rPosition)));
+ if (pDescriptor)
+ nPage = pDescriptor->GetPageIndex();
+ }
+
+ // Now comes the code that is different for the Execute and Accept:
+ // We simply forward the call to the AcceptDrop() or ExecuteDrop()
+ // methods of the DrawViewShell in the center pane.
+ if (nPage != SDRPAGE_NOTFOUND)
+ switch (eCommand)
+ {
+ case DC_ACCEPT:
+ nResult = pDrawViewShell->AcceptDrop(
+ *static_cast<const AcceptDropEvent*>(pDropEvent),
+ rTargetHelper,
+ pTargetWindow,
+ nPage,
+ nLayer);
+ break;
+
+ case DC_EXECUTE:
+ nResult = pDrawViewShell->ExecuteDrop(
+ *static_cast<const ExecuteDropEvent*>(pDropEvent),
+ rTargetHelper,
+ pTargetWindow,
+ nPage,
+ nLayer);
+ break;
+ }
+ }
+
+ return nResult;
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx
new file mode 100644
index 000000000..9203c06e8
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <SlideSorter.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <controller/SlsFocusManager.hxx>
+#include <view/SlideSorterView.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShell.hxx>
+#include <DrawViewShell.hxx>
+#include <sdpage.hxx>
+#include <FrameView.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <osl/diagnose.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+using namespace ::sd::slidesorter::model;
+
+namespace sd::slidesorter::controller {
+
+CurrentSlideManager::CurrentSlideManager (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mnCurrentSlideIndex(-1),
+ maSwitchPageDelayTimer("sd CurrentSlideManager maSwitchPageDelayTimer")
+{
+ maSwitchPageDelayTimer.SetTimeout(100);
+ maSwitchPageDelayTimer.SetInvokeHandler(LINK(this,CurrentSlideManager,SwitchPageCallback));
+}
+
+CurrentSlideManager::~CurrentSlideManager()
+{
+}
+
+void CurrentSlideManager::NotifyCurrentSlideChange (const SdPage* pPage)
+{
+ if (pPage != nullptr)
+ NotifyCurrentSlideChange(
+ mrSlideSorter.GetModel().GetIndex(
+ Reference<drawing::XDrawPage>(
+ const_cast<SdPage*>(pPage)->getUnoPage(),
+ UNO_QUERY)));
+ else
+ NotifyCurrentSlideChange(-1);
+}
+
+void CurrentSlideManager::NotifyCurrentSlideChange (const sal_Int32 nSlideIndex)
+{
+ if (mnCurrentSlideIndex == nSlideIndex)
+ return;
+
+ PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter.GetController().GetPageSelector());
+
+ mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
+
+ ReleaseCurrentSlide();
+ AcquireCurrentSlide(nSlideIndex);
+
+ // Update the selection.
+ if (mpCurrentSlide)
+ {
+ mrSlideSorter.GetController().GetPageSelector().SelectPage(mpCurrentSlide);
+ mrSlideSorter.GetController().GetFocusManager().SetFocusedPage(mpCurrentSlide);
+ }
+}
+
+void CurrentSlideManager::ReleaseCurrentSlide()
+{
+ if (mpCurrentSlide)
+ mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, false);
+
+ mpCurrentSlide.reset();
+ mnCurrentSlideIndex = -1;
+}
+
+void CurrentSlideManager::AcquireCurrentSlide (const sal_Int32 nSlideIndex)
+{
+ mnCurrentSlideIndex = nSlideIndex;
+
+ // if current slide valid
+ if (mnCurrentSlideIndex >= 0 && mnCurrentSlideIndex<mrSlideSorter.GetModel().GetPageCount())
+ {
+ // Get a descriptor for the XDrawPage reference. Note that the
+ // given XDrawPage may or may not be member of the slide sorter
+ // document.
+ mpCurrentSlide = mrSlideSorter.GetModel().GetPageDescriptor(mnCurrentSlideIndex);
+ if (mpCurrentSlide)
+ mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, true);
+ }
+}
+
+void CurrentSlideManager::SwitchCurrentSlide (
+ const sal_Int32 nSlideIndex)
+{
+ SwitchCurrentSlide(mrSlideSorter.GetModel().GetPageDescriptor(nSlideIndex), true/*bUpdateSelection*/);
+}
+
+void CurrentSlideManager::SwitchCurrentSlide (
+ const SharedPageDescriptor& rpDescriptor,
+ const bool bUpdateSelection)
+{
+ if (!rpDescriptor || mpCurrentSlide==rpDescriptor)
+ return;
+
+ ReleaseCurrentSlide();
+ AcquireCurrentSlide((rpDescriptor->GetPage()->GetPageNum()-1)/2);
+
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (pViewShell != nullptr && pViewShell->IsMainViewShell())
+ {
+ // The slide sorter is the main view.
+ FrameView* pFrameView = pViewShell->GetFrameView();
+ if (pFrameView != nullptr)
+ pFrameView->SetSelectedPage(sal::static_int_cast<sal_uInt16>(mnCurrentSlideIndex));
+ mrSlideSorter.GetController().GetPageSelector().SetCoreSelection();
+ }
+
+ // We do not tell the XController/ViewShellBase about the new
+ // slide right away. This is done asynchronously after a short
+ // delay to allow for more slide switches in the slide sorter.
+ // This goes under the assumption that slide switching inside
+ // the slide sorter is fast (no expensive redraw of the new page
+ // (unless the preview of the new slide is not yet preset)) and
+ // that slide switching in the edit view is slow (all shapes of
+ // the new slide have to be repainted.)
+ maSwitchPageDelayTimer.Start();
+
+ // We have to store the (index of the) new current slide at
+ // the tab control because there are other asynchronous
+ // notifications of the slide switching that otherwise
+ // overwrite the correct value.
+ SetCurrentSlideAtTabControl(mpCurrentSlide);
+
+ if (bUpdateSelection)
+ {
+ mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
+ mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
+ }
+ mrSlideSorter.GetController().GetFocusManager().SetFocusedPage(rpDescriptor);
+}
+
+void CurrentSlideManager::SetCurrentSlideAtViewShellBase (const SharedPageDescriptor& rpDescriptor)
+{
+ OSL_ASSERT(rpDescriptor);
+
+ ViewShellBase* pBase = mrSlideSorter.GetViewShellBase();
+ if (pBase != nullptr)
+ {
+ DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(
+ pBase->GetMainViewShell().get());
+ if (pDrawViewShell != nullptr)
+ {
+ sal_uInt16 nPageNumber = (rpDescriptor->GetPage()->GetPageNum()-1)/2;
+ pDrawViewShell->SwitchPage(nPageNumber);
+ TabControl& rPageTabControl = pDrawViewShell->GetPageTabControl();
+ rPageTabControl.SetCurPageId(rPageTabControl.GetPageId(nPageNumber));
+ }
+ }
+}
+
+void CurrentSlideManager::SetCurrentSlideAtTabControl (const SharedPageDescriptor& rpDescriptor)
+{
+ OSL_ASSERT(rpDescriptor);
+
+ ViewShellBase* pBase = mrSlideSorter.GetViewShellBase();
+ if (pBase != nullptr)
+ {
+ std::shared_ptr<DrawViewShell> pDrawViewShell (
+ std::dynamic_pointer_cast<DrawViewShell>(pBase->GetMainViewShell()));
+ if (pDrawViewShell)
+ {
+ sal_uInt16 nPageNumber = (rpDescriptor->GetPage()->GetPageNum()-1)/2;
+ TabControl& rPageTabControl = pDrawViewShell->GetPageTabControl();
+ rPageTabControl.SetCurPageId(rPageTabControl.GetPageId(nPageNumber));
+ }
+ }
+}
+
+void CurrentSlideManager::SetCurrentSlideAtXController (const SharedPageDescriptor& rpDescriptor)
+{
+ OSL_ASSERT(rpDescriptor);
+
+ try
+ {
+ Reference<beans::XPropertySet> xSet (mrSlideSorter.GetXController(), UNO_QUERY);
+ if (xSet.is())
+ {
+ Any aPage;
+ aPage <<= rpDescriptor->GetPage()->getUnoPage();
+ xSet->setPropertyValue( "CurrentPage", aPage );
+ }
+ }
+ catch (const Exception&)
+ {
+ // We have not been able to set the current page at the main view.
+ // This is sad but still leaves us in a valid state. Therefore,
+ // this exception is silently ignored.
+ }
+}
+
+void CurrentSlideManager::PrepareModelChange()
+{
+ mpCurrentSlide.reset();
+}
+
+void CurrentSlideManager::HandleModelChange()
+{
+ if (mnCurrentSlideIndex >= 0)
+ {
+ mpCurrentSlide = mrSlideSorter.GetModel().GetPageDescriptor(mnCurrentSlideIndex);
+ if (mpCurrentSlide)
+ mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, true);
+ }
+}
+
+IMPL_LINK_NOARG(CurrentSlideManager, SwitchPageCallback, Timer *, void)
+{
+ if (mpCurrentSlide)
+ {
+ // Set current page. At the moment we have to do this in two
+ // different ways. The UNO way is the preferable one but, alas,
+ // it does not work always correctly (after some kinds of model
+ // changes). Therefore, we call DrawViewShell::SwitchPage(),
+ // too.
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (pViewShell==nullptr || ! pViewShell->IsMainViewShell())
+ SetCurrentSlideAtViewShellBase(mpCurrentSlide);
+ SetCurrentSlideAtXController(mpCurrentSlide);
+ }
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx
new file mode 100644
index 000000000..f447c5656
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlsDragAndDropContext.hxx"
+
+#include <SlideSorter.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsInsertionIndicatorHandler.hxx>
+#include <controller/SlsScrollBarManager.hxx>
+#include <controller/SlsProperties.hxx>
+#include <controller/SlsClipboard.hxx>
+#include <controller/SlsTransferableData.hxx>
+#include <Window.hxx>
+#include <sdtreelb.hxx>
+#include <sdmod.hxx>
+
+namespace sd::slidesorter::controller {
+
+DragAndDropContext::DragAndDropContext (SlideSorter& rSlideSorter)
+ : mpTargetSlideSorter(&rSlideSorter),
+ mnInsertionIndex(-1)
+{
+ // No Drag-and-Drop for master pages.
+ if (rSlideSorter.GetModel().GetEditMode() != EditMode::Page)
+ return;
+
+ // For properly handling transferables created by the navigator we
+ // need additional information. For this a user data object is
+ // created that contains the necessary information.
+ SdTransferable* pTransferable = SD_MOD()->pTransferDrag;
+ SdPageObjsTLV::SdPageObjsTransferable* pTreeListBoxTransferable
+ = dynamic_cast<SdPageObjsTLV::SdPageObjsTransferable*>(pTransferable);
+ if (pTreeListBoxTransferable!=nullptr && !TransferableData::GetFromTransferable(pTransferable))
+ {
+ pTransferable->AddUserData(
+ sd::slidesorter::controller::Clipboard::CreateTransferableUserData(pTransferable));
+ }
+
+ rSlideSorter.GetController().GetInsertionIndicatorHandler()->UpdateIndicatorIcon(pTransferable);
+}
+
+DragAndDropContext::~DragAndDropContext() COVERITY_NOEXCEPT_FALSE
+{
+ SetTargetSlideSorter();
+}
+
+void DragAndDropContext::Dispose()
+{
+ mnInsertionIndex = -1;
+}
+
+void DragAndDropContext::UpdatePosition (
+ const Point& rMousePosition,
+ const InsertionIndicatorHandler::Mode eMode,
+ const bool bAllowAutoScroll)
+{
+ if (mpTargetSlideSorter == nullptr)
+ return;
+
+ if (mpTargetSlideSorter->GetProperties()->IsUIReadOnly())
+ return;
+
+ // Convert window coordinates into model coordinates (we need the
+ // window coordinates for auto-scrolling because that remains
+ // constant while scrolling.)
+ sd::Window *pWindow = mpTargetSlideSorter->GetContentWindow().get();
+ const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition));
+ std::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler (
+ mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler());
+
+ bool bDoAutoScroll = bAllowAutoScroll
+ && mpTargetSlideSorter->GetController().GetScrollBarManager().AutoScroll(
+ rMousePosition,
+ [this, eMode, rMousePosition] () {
+ return this->UpdatePosition(rMousePosition, eMode, false);
+ });
+
+ if (!bDoAutoScroll)
+ {
+ pInsertionIndicatorHandler->UpdatePosition(aMouseModelPosition, eMode);
+
+ // Remember the new insertion index.
+ mnInsertionIndex = pInsertionIndicatorHandler->GetInsertionPageIndex();
+ if (pInsertionIndicatorHandler->IsInsertionTrivial(mnInsertionIndex, eMode))
+ mnInsertionIndex = -1;
+ }
+}
+
+void DragAndDropContext::SetTargetSlideSorter()
+{
+ if (mpTargetSlideSorter != nullptr)
+ {
+ mpTargetSlideSorter->GetController().GetScrollBarManager().StopAutoScroll();
+ mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()->End(
+ Animator::AM_Animated);
+ }
+
+ mpTargetSlideSorter = nullptr;
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx
new file mode 100644
index 000000000..cbeb11f8b
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <controller/SlsInsertionIndicatorHandler.hxx>
+
+class Point;
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+
+namespace sd::slidesorter::controller
+{
+/** A DragAndDropContext object handles an active drag and drop operation.
+ When the mouse is moved from one slide sorter window to another the
+ target SlideSorter object is exchanged accordingly.
+*/
+class DragAndDropContext
+{
+public:
+ /** Create a substitution display of the currently selected pages or,
+ when provided, the pages in the transferable.
+ */
+ explicit DragAndDropContext(SlideSorter& rSlideSorter);
+ ~DragAndDropContext() COVERITY_NOEXCEPT_FALSE;
+
+ /** Call this method (for example as reaction to ESC key press) to avoid
+ processing (ie moving or inserting) the substitution when the called
+ DragAndDropContext object is destroyed.
+ */
+ void Dispose();
+
+ /** Move the substitution display by the distance the mouse has
+ travelled since the last call to this method or to
+ CreateSubstitution(). The given point becomes the new anchor.
+ */
+ void UpdatePosition(const Point& rMousePosition, const InsertionIndicatorHandler::Mode eMode,
+ const bool bAllowAutoScroll);
+
+ void SetTargetSlideSorter();
+
+private:
+ SlideSorter* mpTargetSlideSorter;
+ sal_Int32 mnInsertionIndex;
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx b/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx
new file mode 100644
index 000000000..59027f5a8
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <controller/SlsFocusManager.hxx>
+
+#include <SlideSorter.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <controller/SlsVisibleAreaManager.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <osl/diagnose.h>
+
+#include <Window.hxx>
+#include <sdpage.hxx>
+
+namespace sd::slidesorter::controller {
+
+FocusManager::FocusManager (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mnPageIndex(0),
+ mbPageIsFocused(false)
+{
+ if (mrSlideSorter.GetModel().GetPageCount() > 0)
+ mnPageIndex = 0;
+}
+
+FocusManager::~FocusManager()
+{
+}
+
+void FocusManager::MoveFocus (FocusMoveDirection eDirection)
+{
+ if (!(mnPageIndex >= 0 && mbPageIsFocused))
+ return;
+
+ HideFocusIndicator (GetFocusedPageDescriptor());
+
+ const sal_Int32 nColumnCount (mrSlideSorter.GetView().GetLayouter().GetColumnCount());
+ const sal_Int32 nPageCount (mrSlideSorter.GetModel().GetPageCount());
+ switch (eDirection)
+ {
+ case FocusMoveDirection::Left:
+ if (mnPageIndex > 0)
+ mnPageIndex -= 1;
+ break;
+
+ case FocusMoveDirection::Right:
+ if (mnPageIndex < nPageCount-1)
+ mnPageIndex += 1;
+ break;
+
+ case FocusMoveDirection::Up:
+ {
+ const sal_Int32 nCandidate (mnPageIndex - nColumnCount);
+ if (nCandidate >= 0)
+ {
+ // Move the focus the previous row.
+ mnPageIndex = nCandidate;
+ }
+ }
+ break;
+
+ case FocusMoveDirection::Down:
+ {
+ const sal_Int32 nCandidate (mnPageIndex + nColumnCount);
+ if (nCandidate < nPageCount)
+ {
+ // Move the focus to the next row.
+ mnPageIndex = nCandidate;
+ }
+ }
+ break;
+ }
+
+ if (mnPageIndex < 0)
+ {
+ OSL_ASSERT(mnPageIndex>=0);
+ mnPageIndex = 0;
+ }
+ else if (mnPageIndex >= nPageCount)
+ {
+ OSL_ASSERT(mnPageIndex<nPageCount);
+ mnPageIndex = nPageCount - 1;
+ }
+
+ if (mbPageIsFocused)
+ {
+ ShowFocusIndicator(GetFocusedPageDescriptor(), true);
+ }
+}
+
+void FocusManager::ShowFocus (const bool bScrollToFocus)
+{
+ mbPageIsFocused = true;
+ ShowFocusIndicator(GetFocusedPageDescriptor(), bScrollToFocus);
+}
+
+void FocusManager::HideFocus()
+{
+ mbPageIsFocused = false;
+ HideFocusIndicator(GetFocusedPageDescriptor());
+}
+
+bool FocusManager::ToggleFocus()
+{
+ if (mnPageIndex >= 0)
+ {
+ if (mbPageIsFocused)
+ HideFocus ();
+ else
+ ShowFocus ();
+ }
+ return mbPageIsFocused;
+}
+
+bool FocusManager::HasFocus() const
+{
+ return mrSlideSorter.GetContentWindow()->HasFocus();
+}
+
+model::SharedPageDescriptor FocusManager::GetFocusedPageDescriptor() const
+{
+ return mrSlideSorter.GetModel().GetPageDescriptor(mnPageIndex);
+}
+
+bool FocusManager::SetFocusedPage (const model::SharedPageDescriptor& rpDescriptor)
+{
+ if (rpDescriptor)
+ {
+ FocusHider aFocusHider (*this);
+ mnPageIndex = (rpDescriptor->GetPage()->GetPageNum()-1)/2;
+ return true;
+ }
+ return false;
+}
+
+void FocusManager::SetFocusedPage (sal_Int32 nPageIndex)
+{
+ FocusHider aFocusHider (*this);
+ mnPageIndex = nPageIndex;
+}
+
+bool FocusManager::SetFocusedPageToCurrentPage()
+{
+ return SetFocusedPage(mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide());
+}
+
+bool FocusManager::IsFocusShowing() const
+{
+ return HasFocus() && mbPageIsFocused;
+}
+
+void FocusManager::HideFocusIndicator (const model::SharedPageDescriptor& rpDescriptor)
+{
+ if (rpDescriptor)
+ {
+ mrSlideSorter.GetView().SetState(rpDescriptor, model::PageDescriptor::ST_Focused, false);
+
+ // Hide focus should also fire the focus event, Currently, only accessibility add the focus listener
+ NotifyFocusChangeListeners();
+ }
+}
+
+void FocusManager::ShowFocusIndicator (
+ const model::SharedPageDescriptor& rpDescriptor,
+ const bool bScrollToFocus)
+{
+ if (!rpDescriptor)
+ return;
+
+ mrSlideSorter.GetView().SetState(rpDescriptor, model::PageDescriptor::ST_Focused, true);
+
+ if (bScrollToFocus)
+ {
+ // Scroll the focused page object into the visible area and repaint
+ // it, so that the focus indicator becomes visible.
+ mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor,true);
+ }
+ mrSlideSorter.GetView().RequestRepaint(rpDescriptor);
+
+ NotifyFocusChangeListeners();
+}
+
+void FocusManager::AddFocusChangeListener (const Link<LinkParamNone*,void>& rListener)
+{
+ if (::std::find (maFocusChangeListeners.begin(), maFocusChangeListeners.end(), rListener)
+ == maFocusChangeListeners.end())
+ {
+ maFocusChangeListeners.push_back (rListener);
+ }
+}
+
+void FocusManager::RemoveFocusChangeListener (const Link<LinkParamNone*,void>& rListener)
+{
+ maFocusChangeListeners.erase (
+ ::std::find (maFocusChangeListeners.begin(), maFocusChangeListeners.end(), rListener));
+}
+
+void FocusManager::NotifyFocusChangeListeners() const
+{
+ // Create a copy of the listener list to be safe when that is modified.
+ ::std::vector<Link<LinkParamNone*,void>> aListeners (maFocusChangeListeners);
+
+ // Tell the selection change listeners that the selection has changed.
+ for (const auto& rListener : aListeners)
+ {
+ rListener.Call(nullptr);
+ }
+}
+
+FocusManager::FocusHider::FocusHider (FocusManager& rManager)
+: mbFocusVisible(rManager.IsFocusShowing())
+, mrManager(rManager)
+{
+ mrManager.HideFocus();
+}
+
+FocusManager::FocusHider::~FocusHider() COVERITY_NOEXCEPT_FALSE
+{
+ if (mbFocusVisible)
+ mrManager.ShowFocus();
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx b/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx
new file mode 100644
index 000000000..ff1a05ef1
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <controller/SlsInsertionIndicatorHandler.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <view/SlsInsertAnimator.hxx>
+#include <view/SlsInsertionIndicatorOverlay.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <osl/diagnose.h>
+
+#include <SlideSorter.hxx>
+
+using namespace ::com::sun::star::datatransfer::dnd::DNDConstants;
+
+namespace sd::slidesorter::controller {
+
+InsertionIndicatorHandler::InsertionIndicatorHandler (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mpInsertionIndicatorOverlay(std::make_shared<view::InsertionIndicatorOverlay>(rSlideSorter)),
+ meMode(MoveMode),
+ mbIsInsertionTrivial(false),
+ mbIsActive(false),
+ mbIsReadOnly(mrSlideSorter.GetModel().IsReadOnly()),
+ mbIsOverSourceView(true),
+ maIconSize(0,0),
+ mbIsForcedShow(false)
+{
+}
+
+InsertionIndicatorHandler::~InsertionIndicatorHandler() COVERITY_NOEXCEPT_FALSE
+{
+}
+
+void InsertionIndicatorHandler::Start (const bool bIsOverSourceView)
+{
+ if (mbIsActive)
+ {
+ OSL_ASSERT(!mbIsActive);
+ }
+
+ mbIsReadOnly = mrSlideSorter.GetModel().IsReadOnly();
+ if (mbIsReadOnly)
+ return;
+
+ mbIsActive = true;
+ mbIsOverSourceView = bIsOverSourceView;
+}
+
+void InsertionIndicatorHandler::End (const controller::Animator::AnimationMode eMode)
+{
+ if (mbIsForcedShow || ! mbIsActive || mbIsReadOnly)
+ return;
+
+ GetInsertAnimator()->Reset(eMode);
+
+ mbIsActive = false;
+ // maInsertPosition = view::InsertPosition();
+ meMode = UnknownMode;
+
+ mpInsertionIndicatorOverlay->Hide();
+ mpInsertionIndicatorOverlay = std::make_shared<view::InsertionIndicatorOverlay>(mrSlideSorter);
+}
+
+void InsertionIndicatorHandler::ForceShow()
+{
+ mbIsForcedShow = true;
+}
+
+void InsertionIndicatorHandler::ForceEnd()
+{
+ mbIsForcedShow = false;
+ End(Animator::AM_Immediate);
+}
+
+void InsertionIndicatorHandler::UpdateIndicatorIcon (const SdTransferable* pTransferable)
+{
+ mpInsertionIndicatorOverlay->Create(pTransferable);
+ maIconSize = mpInsertionIndicatorOverlay->GetSize();
+}
+
+InsertionIndicatorHandler::Mode InsertionIndicatorHandler::GetModeFromDndAction (
+ const sal_Int8 nDndAction)
+{
+ if ((nDndAction & ACTION_MOVE) != 0)
+ return MoveMode;
+ else if ((nDndAction & ACTION_COPY) != 0)
+ return CopyMode;
+ else
+ return UnknownMode;
+}
+
+void InsertionIndicatorHandler::UpdatePosition (
+ const Point& rMouseModelPosition,
+ const Mode eMode)
+{
+ if ( ! mbIsActive)
+ return;
+
+ if (mbIsReadOnly)
+ return;
+
+ SetPosition(rMouseModelPosition, eMode);
+}
+
+void InsertionIndicatorHandler::UpdatePosition (
+ const Point& rMouseModelPosition,
+ const sal_Int8 nDndAction)
+{
+ UpdatePosition(rMouseModelPosition, GetModeFromDndAction(nDndAction));
+}
+
+sal_Int32 InsertionIndicatorHandler::GetInsertionPageIndex() const
+{
+ if (mbIsReadOnly)
+ return -1;
+ else
+ return maInsertPosition.GetIndex();
+}
+
+void InsertionIndicatorHandler::SetPosition (
+ const Point& rPoint,
+ const Mode eMode)
+{
+ view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter());
+
+ const view::InsertPosition aInsertPosition (rLayouter.GetInsertPosition(
+ rPoint,
+ maIconSize,
+ mrSlideSorter.GetModel()));
+
+ if (maInsertPosition == aInsertPosition && meMode == eMode)
+ return;
+
+ maInsertPosition = aInsertPosition;
+ meMode = eMode;
+ mbIsInsertionTrivial = IsInsertionTrivial(maInsertPosition.GetIndex(), eMode);
+ if (maInsertPosition.GetIndex()>=0 && ! mbIsInsertionTrivial)
+ {
+ mpInsertionIndicatorOverlay->SetLocation(maInsertPosition.GetLocation());
+
+ GetInsertAnimator()->SetInsertPosition(maInsertPosition);
+ mpInsertionIndicatorOverlay->Show();
+ }
+ else
+ {
+ GetInsertAnimator()->Reset(Animator::AM_Animated);
+ mpInsertionIndicatorOverlay->Hide();
+ }
+}
+
+std::shared_ptr<view::InsertAnimator> const & InsertionIndicatorHandler::GetInsertAnimator()
+{
+ if ( ! mpInsertAnimator)
+ mpInsertAnimator = std::make_shared<view::InsertAnimator>(mrSlideSorter);
+ return mpInsertAnimator;
+}
+
+bool InsertionIndicatorHandler::IsInsertionTrivial (
+ const sal_Int32 nInsertionIndex,
+ const Mode eMode) const
+{
+ if (eMode == CopyMode)
+ return false;
+ else if (eMode == UnknownMode)
+ return true;
+
+ if ( ! mbIsOverSourceView)
+ return false;
+
+ // Iterate over all selected pages and check whether there are
+ // holes. While we do this we remember the indices of the first and
+ // last selected page as preparation for the next step.
+ sal_Int32 nCurrentIndex = -1;
+ sal_Int32 nFirstIndex = -1;
+ sal_Int32 nLastIndex = -1;
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ while (aSelectedPages.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+
+ // Get the page number and compare it to the last one.
+ const sal_Int32 nPageNumber (pDescriptor->GetPageIndex());
+ if (nCurrentIndex>=0 && nPageNumber>(nCurrentIndex+1))
+ return false;
+ else
+ nCurrentIndex = nPageNumber;
+
+ // Remember indices of the first and last page of the selection.
+ if (nFirstIndex == -1)
+ nFirstIndex = nPageNumber;
+ nLastIndex = nPageNumber;
+ }
+
+ // When we come here then the selection has no holes. We still have
+ // to check that the insertion position is not directly in front or
+ // directly behind the selection and thus moving the selection there
+ // would not change the model.
+ return nInsertionIndex >= nFirstIndex && nInsertionIndex <= (nLastIndex+1);
+}
+
+bool InsertionIndicatorHandler::IsInsertionTrivial (const sal_Int8 nDndAction)
+{
+ return IsInsertionTrivial(GetInsertionPageIndex(), GetModeFromDndAction(nDndAction));
+}
+
+//===== InsertionIndicatorHandler::ForceShowContext ===========================
+
+InsertionIndicatorHandler::ForceShowContext::ForceShowContext (
+ const std::shared_ptr<InsertionIndicatorHandler>& rpHandler)
+ : mpHandler(rpHandler)
+{
+ mpHandler->ForceShow();
+}
+
+InsertionIndicatorHandler::ForceShowContext::~ForceShowContext() COVERITY_NOEXCEPT_FALSE
+{
+ mpHandler->ForceEnd();
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsListener.cxx b/sd/source/ui/slidesorter/controller/SlsListener.cxx
new file mode 100644
index 000000000..000f42da2
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsListener.cxx
@@ -0,0 +1,597 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlsListener.hxx"
+
+#include <SlideSorter.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellHint.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <controller/SlsSelectionManager.hxx>
+#include <controller/SlsSelectionObserver.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <view/SlideSorterView.hxx>
+#include <cache/SlsPageCache.hxx>
+#include <cache/SlsPageCacheManager.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <DrawDocShell.hxx>
+#include <svx/svdpage.hxx>
+
+#include <ViewShellBase.hxx>
+#include <EventMultiplexer.hxx>
+#include <com/sun/star/document/XEventBroadcaster.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/FrameActionEvent.hpp>
+#include <com/sun/star/frame/FrameAction.hpp>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+namespace sd::slidesorter::controller {
+
+Listener::Listener (
+ SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mrController(mrSlideSorter.GetController()),
+ mpBase(mrSlideSorter.GetViewShellBase()),
+ mbListeningToDocument (false),
+ mbListeningToUNODocument (false),
+ mbListeningToController (false),
+ mbListeningToFrame (false),
+ mbIsMainViewChangePending(false)
+{
+ StartListening(*mrSlideSorter.GetModel().GetDocument());
+ StartListening(*mrSlideSorter.GetModel().GetDocument()->GetDocSh());
+ mbListeningToDocument = true;
+
+ // Connect to the UNO document.
+ Reference<document::XEventBroadcaster> xBroadcaster (
+ mrSlideSorter.GetModel().GetDocument()->getUnoModel(), uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ {
+ xBroadcaster->addEventListener (this);
+ mbListeningToUNODocument = true;
+ }
+
+ // Listen for disposing events from the document.
+ Reference<XComponent> xComponent (xBroadcaster, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener (
+ Reference<lang::XEventListener>(
+ static_cast<XWeak*>(this), UNO_QUERY));
+
+ // Connect to the frame to listen for controllers being exchanged.
+ bool bIsMainViewShell (false);
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (pViewShell != nullptr)
+ bIsMainViewShell = pViewShell->IsMainViewShell();
+ if ( ! bIsMainViewShell)
+ {
+ // Listen to changes of certain properties.
+ Reference<frame::XFrame> xFrame;
+ Reference<frame::XController> xController (mrSlideSorter.GetXController());
+ if (xController.is())
+ xFrame = xController->getFrame();
+ mxFrameWeak = xFrame;
+ if (xFrame.is())
+ {
+ xFrame->addFrameActionListener(Reference<frame::XFrameActionListener>(this));
+ mbListeningToFrame = true;
+ }
+
+ // Connect to the current controller.
+ ConnectToController ();
+ }
+
+ // Listen for hints of the MainViewShell as well. If that is not yet
+ // present then the EventMultiplexer will tell us when it is available.
+ if (mpBase != nullptr)
+ {
+ ViewShell* pMainViewShell = mpBase->GetMainViewShell().get();
+ if (pMainViewShell != nullptr
+ && pMainViewShell!=pViewShell)
+ {
+ StartListening(*pMainViewShell);
+ }
+
+ Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this, Listener, EventMultiplexerCallback));
+ mpBase->GetEventMultiplexer()->AddEventListener(aLink);
+ }
+}
+
+Listener::~Listener()
+{
+ DBG_ASSERT( !mbListeningToDocument && !mbListeningToUNODocument && !mbListeningToFrame,
+ "sd::Listener::~Listener(), disposing() was not called, ask DBO!" );
+}
+
+void Listener::ReleaseListeners()
+{
+ if (mbListeningToDocument)
+ {
+ EndListening(*mrSlideSorter.GetModel().GetDocument()->GetDocSh());
+ EndListening(*mrSlideSorter.GetModel().GetDocument());
+ mbListeningToDocument = false;
+ }
+
+ if (mbListeningToUNODocument)
+ {
+ Reference<document::XEventBroadcaster> xBroadcaster (
+ mrSlideSorter.GetModel().GetDocument()->getUnoModel(), UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeEventListener (this);
+
+ // Remove the dispose listener.
+ Reference<XComponent> xComponent (xBroadcaster, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener (
+ Reference<lang::XEventListener>(
+ static_cast<XWeak*>(this), UNO_QUERY));
+
+ mbListeningToUNODocument = false;
+ }
+
+ if (mbListeningToFrame)
+ {
+ // Listen to changes of certain properties.
+ Reference<frame::XFrame> xFrame (mxFrameWeak);
+ if (xFrame.is())
+ {
+ xFrame->removeFrameActionListener(Reference<frame::XFrameActionListener>(this));
+ mbListeningToFrame = false;
+ }
+ }
+
+ DisconnectFromController ();
+
+ if (mpBase != nullptr)
+ {
+ Link<sd::tools::EventMultiplexerEvent&,void> aLink (LINK(this, Listener, EventMultiplexerCallback));
+ mpBase->GetEventMultiplexer()->RemoveEventListener(aLink);
+ }
+}
+
+void Listener::ConnectToController()
+{
+ ViewShell* pShell = mrSlideSorter.GetViewShell();
+
+ // Register at the controller of the main view shell (if we are that not
+ // ourself).
+ if (pShell!=nullptr && pShell->IsMainViewShell())
+ return;
+
+ Reference<frame::XController> xController (mrSlideSorter.GetXController());
+
+ // Listen to changes of certain properties.
+ Reference<beans::XPropertySet> xSet (xController, UNO_QUERY);
+ if (xSet.is())
+ {
+ try
+ {
+ xSet->addPropertyChangeListener("CurrentPage", this);
+ }
+ catch (beans::UnknownPropertyException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ try
+ {
+ xSet->addPropertyChangeListener("IsMasterPageMode", this);
+ }
+ catch (beans::UnknownPropertyException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ }
+
+ // Listen for disposing events.
+ if (xController.is())
+ {
+ xController->addEventListener (
+ Reference<lang::XEventListener>(static_cast<XWeak*>(this), UNO_QUERY));
+
+ mxControllerWeak = xController;
+ mbListeningToController = true;
+ }
+}
+
+void Listener::DisconnectFromController()
+{
+ if (!mbListeningToController)
+ return;
+
+ Reference<frame::XController> xController = mxControllerWeak;
+ Reference<beans::XPropertySet> xSet (xController, UNO_QUERY);
+ try
+ {
+ // Remove the property listener.
+ if (xSet.is())
+ {
+ xSet->removePropertyChangeListener( "CurrentPage", this );
+ xSet->removePropertyChangeListener( "IsMasterPageMode", this);
+ }
+
+ // Remove the dispose listener.
+ if (xController.is())
+ xController->removeEventListener (
+ Reference<lang::XEventListener>(
+ static_cast<XWeak*>(this), UNO_QUERY));
+ }
+ catch (beans::UnknownPropertyException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+
+ mbListeningToController = false;
+ mxControllerWeak = Reference<frame::XController>();
+}
+
+void Listener::Notify (
+ SfxBroadcaster& rBroadcaster,
+ const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ switch (pSdrHint->GetKind())
+ {
+ case SdrHintKind::ModelCleared:
+ if (&rBroadcaster == mrSlideSorter.GetModel().GetDocument())
+ { // rhbz#965646 stop listening to dying document
+ EndListening(rBroadcaster);
+ return;
+ }
+ break;
+ case SdrHintKind::PageOrderChange:
+ if (&rBroadcaster == mrSlideSorter.GetModel().GetDocument())
+ HandleModelChange(pSdrHint->GetPage());
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (rHint.GetId() == SfxHintId::DocChanged)
+ {
+ mrController.CheckForMasterPageAssignment();
+ mrController.CheckForSlideTransitionAssignment();
+ }
+ else if (auto pViewShellHint = dynamic_cast<const ViewShellHint*>(&rHint))
+ {
+ switch (pViewShellHint->GetHintId())
+ {
+ case ViewShellHint::HINT_PAGE_RESIZE_START:
+ // Initiate a model change but do nothing (well, not much)
+ // until we are told that all slides have been resized.
+ mpModelChangeLock.reset(new SlideSorterController::ModelChangeLock(mrController),
+ o3tl::default_delete<SlideSorterController::ModelChangeLock>());
+ mrController.HandleModelChange();
+ break;
+
+ case ViewShellHint::HINT_PAGE_RESIZE_END:
+ // All slides have been resized. The model has to be updated.
+ mpModelChangeLock.reset();
+ break;
+
+ case ViewShellHint::HINT_CHANGE_EDIT_MODE_START:
+ mrController.PrepareEditModeChange();
+ break;
+
+ case ViewShellHint::HINT_CHANGE_EDIT_MODE_END:
+ mrController.FinishEditModeChange();
+ break;
+
+ case ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START:
+ mpModelChangeLock.reset(new SlideSorterController::ModelChangeLock(mrController),
+ o3tl::default_delete<SlideSorterController::ModelChangeLock>());
+ break;
+
+ case ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END:
+ mpModelChangeLock.reset();
+ break;
+ }
+ }
+}
+
+IMPL_LINK(Listener, EventMultiplexerCallback, ::sd::tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ case EventMultiplexerEventId::MainViewRemoved:
+ {
+ if (mpBase != nullptr)
+ {
+ ViewShell* pMainViewShell = mpBase->GetMainViewShell().get();
+ if (pMainViewShell != nullptr)
+ EndListening(*pMainViewShell);
+ }
+ }
+ break;
+
+ case EventMultiplexerEventId::MainViewAdded:
+ mbIsMainViewChangePending = true;
+ break;
+
+ case EventMultiplexerEventId::ConfigurationUpdated:
+ if (mbIsMainViewChangePending && mpBase != nullptr)
+ {
+ mbIsMainViewChangePending = false;
+ ViewShell* pMainViewShell = mpBase->GetMainViewShell().get();
+ if (pMainViewShell != nullptr
+ && pMainViewShell!=mrSlideSorter.GetViewShell())
+ {
+ StartListening (*pMainViewShell);
+ }
+ }
+ break;
+
+ case EventMultiplexerEventId::ControllerAttached:
+ {
+ ConnectToController();
+ // mrController.GetPageSelector().GetCoreSelection();
+ UpdateEditMode();
+ }
+ break;
+
+ case EventMultiplexerEventId::ControllerDetached:
+ DisconnectFromController();
+ break;
+
+ case EventMultiplexerEventId::ShapeChanged:
+ case EventMultiplexerEventId::ShapeInserted:
+ case EventMultiplexerEventId::ShapeRemoved:
+ HandleShapeModification(static_cast<const SdrPage*>(rEvent.mpUserData));
+ break;
+
+ case EventMultiplexerEventId::EndTextEdit:
+ if (rEvent.mpUserData != nullptr)
+ {
+ const SdrObject* pObject = static_cast<const SdrObject*>(rEvent.mpUserData);
+ HandleShapeModification(pObject->getSdrPageFromSdrObject());
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+//===== lang::XEventListener ================================================
+
+void SAL_CALL Listener::disposing (
+ const lang::EventObject& rEventObject)
+{
+ if ((mbListeningToDocument || mbListeningToUNODocument)
+ && mrSlideSorter.GetModel().GetDocument()!=nullptr
+ && rEventObject.Source
+ == mrSlideSorter.GetModel().GetDocument()->getUnoModel())
+ {
+ mbListeningToDocument = false;
+ mbListeningToUNODocument = false;
+ }
+ else if (mbListeningToController)
+ {
+ Reference<frame::XController> xController (mxControllerWeak);
+ if (rEventObject.Source == xController)
+ {
+ mbListeningToController = false;
+ }
+ }
+}
+
+//===== document::XEventListener ============================================
+
+void SAL_CALL Listener::notifyEvent (
+ const document::EventObject& )
+{
+}
+
+//===== beans::XPropertySetListener =========================================
+
+void SAL_CALL Listener::propertyChange (
+ const PropertyChangeEvent& rEvent)
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("SlideSorterController object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+
+ if (rEvent.PropertyName == "CurrentPage")
+ {
+ Any aCurrentPage = rEvent.NewValue;
+ Reference<beans::XPropertySet> xPageSet (aCurrentPage, UNO_QUERY);
+ if (xPageSet.is())
+ {
+ try
+ {
+ Any aPageNumber = xPageSet->getPropertyValue ("Number");
+ sal_Int32 nCurrentPage = 0;
+ aPageNumber >>= nCurrentPage;
+ // The selection is already set but we call SelectPage()
+ // nevertheless in order to make the new current page the
+ // last recently selected page of the PageSelector. This is
+ // used when making the selection visible.
+ mrController.GetCurrentSlideManager()->NotifyCurrentSlideChange(nCurrentPage-1);
+ mrController.GetPageSelector().SelectPage(nCurrentPage-1);
+ }
+ catch (beans::UnknownPropertyException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ catch (lang::DisposedException&)
+ {
+ // Something is already disposed. There is not much we can
+ // do, except not to crash.
+ }
+ }
+ }
+ else if (rEvent.PropertyName == "IsMasterPageMode")
+ {
+ bool bIsMasterPageMode = false;
+ rEvent.NewValue >>= bIsMasterPageMode;
+ mrController.ChangeEditMode (
+ bIsMasterPageMode ? EditMode::MasterPage : EditMode::Page);
+ }
+}
+
+//===== frame::XFrameActionListener ==========================================
+
+void SAL_CALL Listener::frameAction (const frame::FrameActionEvent& rEvent)
+{
+ switch (rEvent.Action)
+ {
+ case frame::FrameAction_COMPONENT_DETACHING:
+ DisconnectFromController();
+ break;
+
+ case frame::FrameAction_COMPONENT_REATTACHED:
+ {
+ ConnectToController();
+ mrController.GetPageSelector().GetCoreSelection();
+ UpdateEditMode();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+//===== accessibility::XAccessibleEventListener ==============================
+
+void SAL_CALL Listener::notifyEvent (
+ const AccessibleEventObject& )
+{
+}
+
+void Listener::disposing(std::unique_lock<std::mutex>&)
+{
+ ReleaseListeners();
+}
+
+void Listener::UpdateEditMode()
+{
+ // When there is a new controller then the edit mode may have changed at
+ // the same time.
+ Reference<frame::XController> xController (mxControllerWeak);
+ Reference<beans::XPropertySet> xSet (xController, UNO_QUERY);
+ bool bIsMasterPageMode = false;
+ if (xSet != nullptr)
+ {
+ try
+ {
+ Any aValue (xSet->getPropertyValue( "IsMasterPageMode" ));
+ aValue >>= bIsMasterPageMode;
+ }
+ catch (beans::UnknownPropertyException&)
+ {
+ // When the property is not supported then the master page mode
+ // is not supported, too.
+ bIsMasterPageMode = false;
+ }
+ }
+ mrController.ChangeEditMode (
+ bIsMasterPageMode ? EditMode::MasterPage : EditMode::Page);
+}
+
+void Listener::HandleModelChange (const SdrPage* pPage)
+{
+ // Notify model and selection observer about the page. The return value
+ // of the model call acts as filter as to which events to pass to the
+ // selection observer.
+ if (mrSlideSorter.GetModel().NotifyPageEvent(pPage))
+ {
+ // The page of the hint belongs (or belonged) to the model.
+
+ // Tell the cache manager that the preview bitmaps for a deleted
+ // page can be removed from all caches.
+ if (pPage!=nullptr && ! pPage->IsInserted())
+ cache::PageCacheManager::Instance()->ReleasePreviewBitmap(pPage);
+
+ mrController.GetSelectionManager()->GetSelectionObserver()->NotifyPageEvent(pPage);
+ }
+
+ // Tell the controller about the model change only when the document is
+ // in a sane state, not just in the middle of a larger change.
+ SdDrawDocument* pDocument (mrSlideSorter.GetModel().GetDocument());
+ if (pDocument != nullptr
+ && pDocument->GetMasterSdPageCount(PageKind::Standard) == pDocument->GetMasterSdPageCount(PageKind::Notes))
+ {
+ // A model change can make updates of some text fields necessary
+ // (like page numbers and page count.) Invalidate all previews in
+ // the cache to cope with this. Doing this on demand would be a
+ // nice optimization.
+ cache::PageCacheManager::Instance()->InvalidateAllPreviewBitmaps(pDocument->getUnoModel());
+
+ mrController.HandleModelChange();
+ }
+}
+
+void Listener::HandleShapeModification (const SdrPage* pPage)
+{
+ if (pPage == nullptr)
+ return;
+
+ // Invalidate the preview of the page (in all slide sorters that display
+ // it.)
+ std::shared_ptr<cache::PageCacheManager> pCacheManager (cache::PageCacheManager::Instance());
+ if ( ! pCacheManager)
+ return;
+ SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
+ if (pDocument == nullptr)
+ {
+ OSL_ASSERT(pDocument!=nullptr);
+ return;
+ }
+ pCacheManager->InvalidatePreviewBitmap(pDocument->getUnoModel(), pPage);
+ mrSlideSorter.GetView().GetPreviewCache()->RequestPreviewBitmap(pPage);
+
+ // When the page is a master page then invalidate the previews of all
+ // pages that are linked to this master page.
+ if (!pPage->IsMasterPage())
+ return;
+
+ for (sal_uInt16 nIndex=0,nCount=pDocument->GetSdPageCount(PageKind::Standard);
+ nIndex<nCount;
+ ++nIndex)
+ {
+ const SdPage* pCandidate = pDocument->GetSdPage(nIndex, PageKind::Standard);
+ if (pCandidate!=nullptr && pCandidate->TRG_HasMasterPage())
+ {
+ if (&pCandidate->TRG_GetMasterPage() == pPage)
+ pCacheManager->InvalidatePreviewBitmap(pDocument->getUnoModel(), pCandidate);
+ }
+ else
+ {
+ OSL_ASSERT(pCandidate!=nullptr && pCandidate->TRG_HasMasterPage());
+ }
+ }
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsListener.hxx b/sd/source/ui/slidesorter/controller/SlsListener.hxx
new file mode 100644
index 000000000..eff02cf19
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsListener.hxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <controller/SlideSorterController.hxx>
+#include <com/sun/star/document/XEventListener.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
+#include <com/sun/star/frame/XFrameActionListener.hpp>
+#include <comphelper/compbase.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <svl/lstner.hxx>
+#include <tools/link.hxx>
+#include <memory>
+
+class SdrPage;
+
+namespace sd {
+class ViewShellBase;
+}
+
+namespace sd::tools { class EventMultiplexerEvent; }
+namespace sd::slidesorter { class SlideSorter; }
+
+namespace sd::slidesorter::controller {
+
+typedef comphelper::WeakComponentImplHelper<
+ css::document::XEventListener,
+ css::beans::XPropertyChangeListener,
+ css::accessibility::XAccessibleEventListener,
+ css::frame::XFrameActionListener
+ > ListenerInterfaceBase;
+
+/** Listen for events of various types and sources and react to them. This
+ class is a part of the controller.
+
+ When the view shell in the center pane is replaced by another the
+ associated controller is replaced as well. Therefore we have to
+ register at the frame and on certain FrameActionEvents to stop listening
+ to the old controller and register as listener at the new one.
+*/
+class Listener
+ : public ListenerInterfaceBase,
+ public SfxListener
+{
+public:
+ explicit Listener (SlideSorter& rSlideSorter);
+ virtual ~Listener() override;
+
+ /** Connect to the current controller of the view shell as listener.
+ This method is called once during initialization and every time a
+ FrameActionEvent signals the current controller being exchanged.
+ When the connection is successful then the flag
+ mbListeningToController is set to <TRUE/>.
+ */
+ void ConnectToController();
+
+ /** Disconnect from the current controller of the view shell as
+ listener. This method is called once during initialization and
+ every time a FrameActionEvent signals the current controller being
+ exchanged. When this method terminates then mbListeningToController
+ is <FALSE/>.
+ */
+ void DisconnectFromController();
+
+ virtual void Notify (
+ SfxBroadcaster& rBroadcaster,
+ const SfxHint& rHint) override;
+
+ //===== 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;
+
+ //===== beans::XPropertySetListener =====================================
+ virtual void SAL_CALL
+ propertyChange (
+ const css::beans::PropertyChangeEvent& rEvent) override;
+
+ //===== accessibility::XAccessibleEventListener ==========================
+ virtual void SAL_CALL
+ notifyEvent (
+ const css::accessibility::AccessibleEventObject&
+ rEvent) override;
+
+ //===== frame::XFrameActionListener ======================================
+ /** For certain actions the listener connects to a new controller of the
+ frame it is listening to. This usually happens when the view shell
+ in the center pane is replaced by another view shell.
+ */
+ virtual void SAL_CALL
+ frameAction (const css::frame::FrameActionEvent& rEvent) override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+private:
+ SlideSorter& mrSlideSorter;
+ SlideSorterController& mrController;
+ ViewShellBase* mpBase;
+
+ /// Remember whether we are listening to the document.
+ bool mbListeningToDocument;
+ /// Remember whether we are listening to the UNO document.
+ bool mbListeningToUNODocument;
+ /// Remember whether we are listening to the UNO controller.
+ bool mbListeningToController;
+ /// Remember whether we are listening to the frame.
+ bool mbListeningToFrame;
+ bool mbIsMainViewChangePending;
+
+ css::uno::WeakReference< css::frame::XController> mxControllerWeak;
+ css::uno::WeakReference< css::frame::XFrame> mxFrameWeak;
+
+ /** This object is used to lock the model between some
+ events. It is references counted in order to cope with events that
+ are expected but never sent.
+ */
+ std::shared_ptr<SlideSorterController::ModelChangeLock> mpModelChangeLock;
+
+ void ReleaseListeners();
+
+ /** Called when the edit mode has changed. Update model accordingly.
+ */
+ void UpdateEditMode();
+
+ /** Handle a change in the order of slides or when the set of slides has
+ changed, i.e. a slide has been created.
+ */
+ void HandleModelChange (const SdrPage* pPage);
+
+ /** Handle a modification to a shape on the given page. When this is a
+ regular page then update its preview. When it is a master page then
+ additionally update the previews of all pages linked to it.
+ */
+ void HandleShapeModification (const SdrPage* pPage);
+
+ DECL_LINK(EventMultiplexerCallback, tools::EventMultiplexerEvent&, void);
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx b/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx
new file mode 100644
index 000000000..21affcf2f
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx
@@ -0,0 +1,386 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <controller/SlsPageSelector.hxx>
+
+#include <SlideSorter.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsSelectionManager.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <controller/SlsVisibleAreaManager.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <view/SlideSorterView.hxx>
+#include <osl/diagnose.h>
+
+#include <sdpage.hxx>
+#include <tools/debug.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::sd::slidesorter::model;
+using namespace ::sd::slidesorter::view;
+
+namespace sd::slidesorter::controller {
+
+PageSelector::PageSelector (SlideSorter& rSlideSorter)
+ : mrModel(rSlideSorter.GetModel()),
+ mrSlideSorter(rSlideSorter),
+ mrController(mrSlideSorter.GetController()),
+ mnSelectedPageCount(0),
+ mnBroadcastDisableLevel(0),
+ mbSelectionChangeBroadcastPending(false),
+ mnUpdateLockCount(0),
+ mbIsUpdateCurrentPagePending(true)
+{
+ CountSelectedPages ();
+}
+
+void PageSelector::SelectAllPages()
+{
+ VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
+ PageSelector::UpdateLock aLock (*this);
+
+ int nPageCount = mrModel.GetPageCount();
+ for (int nPageIndex=0; nPageIndex<nPageCount; nPageIndex++)
+ SelectPage(nPageIndex);
+}
+
+void PageSelector::DeselectAllPages()
+{
+ VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
+ PageSelector::UpdateLock aLock (*this);
+
+ int nPageCount = mrModel.GetPageCount();
+ for (int nPageIndex=0; nPageIndex<nPageCount; nPageIndex++)
+ DeselectPage(nPageIndex);
+
+ DBG_ASSERT (mnSelectedPageCount==0,
+ "PageSelector::DeselectAllPages: the selected pages counter is not 0");
+ mnSelectedPageCount = 0;
+ mpSelectionAnchor.reset();
+}
+
+void PageSelector::GetCoreSelection()
+{
+ PageSelector::UpdateLock aLock (*this);
+
+ bool bSelectionHasChanged (true);
+ mnSelectedPageCount = 0;
+ model::PageEnumeration aAllPages (
+ model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
+ while (aAllPages.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
+ if (pDescriptor->GetCoreSelection())
+ {
+ mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(pDescriptor);
+ mrSlideSorter.GetView().RequestRepaint(pDescriptor);
+ bSelectionHasChanged = true;
+ }
+
+ if (pDescriptor->HasState(PageDescriptor::ST_Selected))
+ mnSelectedPageCount++;
+ }
+
+ if (bSelectionHasChanged)
+ {
+ if (mnBroadcastDisableLevel > 0)
+ mbSelectionChangeBroadcastPending = true;
+ else
+ mrController.GetSelectionManager()->SelectionHasChanged();
+ }
+}
+
+void PageSelector::SetCoreSelection()
+{
+ model::PageEnumeration aAllPages (
+ model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
+ while (aAllPages.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
+ pDescriptor->SetCoreSelection();
+ }
+}
+
+void PageSelector::SelectPage (int nPageIndex)
+{
+ SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
+ if (pDescriptor)
+ SelectPage(pDescriptor);
+}
+
+void PageSelector::SelectPage (const SdPage* pPage)
+{
+ const sal_Int32 nPageIndex (mrModel.GetIndex(pPage));
+ SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
+ if (pDescriptor && pDescriptor->GetPage()==pPage)
+ SelectPage(pDescriptor);
+}
+
+void PageSelector::SelectPage (const SharedPageDescriptor& rpDescriptor)
+{
+ if (!rpDescriptor
+ || !mrSlideSorter.GetView().SetState(rpDescriptor, PageDescriptor::ST_Selected, true))
+ return;
+
+ ++mnSelectedPageCount;
+ mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor,true);
+ mrSlideSorter.GetView().RequestRepaint(rpDescriptor);
+
+ mpMostRecentlySelectedPage = rpDescriptor;
+ if (mpSelectionAnchor == nullptr)
+ mpSelectionAnchor = rpDescriptor;
+
+ if (mnBroadcastDisableLevel > 0)
+ mbSelectionChangeBroadcastPending = true;
+ else
+ mrController.GetSelectionManager()->SelectionHasChanged();
+ UpdateCurrentPage();
+
+ CheckConsistency();
+}
+
+void PageSelector::DeselectPage (int nPageIndex)
+{
+ model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
+ if (pDescriptor)
+ DeselectPage(pDescriptor);
+}
+
+void PageSelector::DeselectPage (
+ const SharedPageDescriptor& rpDescriptor,
+ const bool bUpdateCurrentPage)
+{
+ if (!rpDescriptor
+ || !mrSlideSorter.GetView().SetState(rpDescriptor, PageDescriptor::ST_Selected, false))
+ return;
+
+ --mnSelectedPageCount;
+ mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor);
+ mrSlideSorter.GetView().RequestRepaint(rpDescriptor);
+ if (mpMostRecentlySelectedPage == rpDescriptor)
+ mpMostRecentlySelectedPage.reset();
+ if (mnBroadcastDisableLevel > 0)
+ mbSelectionChangeBroadcastPending = true;
+ else
+ mrController.GetSelectionManager()->SelectionHasChanged();
+ if (bUpdateCurrentPage)
+ UpdateCurrentPage();
+
+ CheckConsistency();
+}
+
+void PageSelector::CheckConsistency() const
+{
+ int nSelectionCount (0);
+ for (int nPageIndex=0,nPageCount=mrModel.GetPageCount(); nPageIndex<nPageCount; nPageIndex++)
+ {
+ SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
+ assert(pDescriptor);
+ if (pDescriptor->HasState(PageDescriptor::ST_Selected))
+ ++nSelectionCount;
+ }
+ if (nSelectionCount!=mnSelectedPageCount)
+ {
+ // #i120020# The former call to assert(..) internally calls
+ // SlideSorterModel::GetPageDescriptor which will crash in this situation
+ // (only in non-pro code). All what is wanted there is to assert it (the
+ // error is already detected), so do this directly.
+ OSL_ENSURE(false, "PageSelector: Consistency error (!)");
+ }
+}
+
+bool PageSelector::IsPageSelected(int nPageIndex)
+{
+ SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
+ if (pDescriptor)
+ return pDescriptor->HasState(PageDescriptor::ST_Selected);
+ else
+ return false;
+}
+
+bool PageSelector::IsPageVisible(int nPageIndex)
+{
+ SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
+ if (pDescriptor)
+ return pDescriptor->HasState(PageDescriptor::ST_Visible);
+ else
+ return false;
+}
+
+int PageSelector::GetPageCount() const
+{
+ return mrModel.GetPageCount();
+}
+
+void PageSelector::CountSelectedPages()
+{
+ mnSelectedPageCount = 0;
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrModel));
+ while (aSelectedPages.HasMoreElements())
+ {
+ mnSelectedPageCount++;
+ aSelectedPages.GetNextElement();
+ }
+}
+
+void PageSelector::EnableBroadcasting()
+{
+ if (mnBroadcastDisableLevel > 0)
+ mnBroadcastDisableLevel --;
+ if (mnBroadcastDisableLevel==0 && mbSelectionChangeBroadcastPending)
+ {
+ mrController.GetSelectionManager()->SelectionHasChanged();
+ mbSelectionChangeBroadcastPending = false;
+ }
+}
+
+void PageSelector::DisableBroadcasting()
+{
+ mnBroadcastDisableLevel ++;
+}
+
+std::shared_ptr<PageSelector::PageSelection> PageSelector::GetPageSelection() const
+{
+ auto pSelection = std::make_shared<PageSelection>();
+ pSelection->reserve(GetSelectedPageCount());
+
+ int nPageCount = GetPageCount();
+ for (int nIndex=0; nIndex<nPageCount; nIndex++)
+ {
+ SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex));
+ if (pDescriptor && pDescriptor->HasState(PageDescriptor::ST_Selected))
+ pSelection->push_back(pDescriptor->GetPage());
+ }
+
+ return pSelection;
+}
+
+void PageSelector::SetPageSelection (
+ const std::shared_ptr<PageSelection>& rpSelection,
+ const bool bUpdateCurrentPage)
+{
+ for (const auto& rpPage : *rpSelection)
+ SelectPage(rpPage);
+ if (bUpdateCurrentPage)
+ UpdateCurrentPage();
+}
+
+void PageSelector::UpdateCurrentPage (const bool bUpdateOnlyWhenPending)
+{
+ if (mnUpdateLockCount > 0)
+ {
+ mbIsUpdateCurrentPagePending = true;
+ return;
+ }
+
+ if ( ! mbIsUpdateCurrentPagePending && bUpdateOnlyWhenPending)
+ return;
+
+ mbIsUpdateCurrentPagePending = false;
+
+ // Make the first selected page the current page.
+ SharedPageDescriptor pCurrentPageDescriptor;
+ const sal_Int32 nPageCount (GetPageCount());
+ for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex)
+ {
+ SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex));
+ if ( ! pDescriptor)
+ continue;
+ if (pDescriptor->HasState(PageDescriptor::ST_Selected))
+ {
+ pCurrentPageDescriptor = pDescriptor;
+ break;
+ }
+ }
+
+ if (!pCurrentPageDescriptor)
+ return;
+
+ // Switching the current slide normally sets also the
+ // selection to just the new current slide. To prevent that,
+ // we store (and at the end of this scope restore) the current
+ // selection.
+ std::shared_ptr<PageSelection> pSelection (GetPageSelection());
+
+ mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pCurrentPageDescriptor);
+
+ // Restore the selection and prevent a recursive call to
+ // UpdateCurrentPage().
+ SetPageSelection(pSelection, false);
+}
+
+//===== PageSelector::UpdateLock ==============================================
+
+PageSelector::UpdateLock::UpdateLock (SlideSorter const & rSlideSorter)
+ : mpSelector(&rSlideSorter.GetController().GetPageSelector())
+{
+ ++mpSelector->mnUpdateLockCount;
+}
+
+PageSelector::UpdateLock::UpdateLock (PageSelector& rSelector)
+ : mpSelector(&rSelector)
+{
+ ++mpSelector->mnUpdateLockCount;
+}
+
+PageSelector::UpdateLock::~UpdateLock()
+{
+ Release();
+}
+
+void PageSelector::UpdateLock::Release()
+{
+ if (mpSelector != nullptr)
+ {
+ --mpSelector->mnUpdateLockCount;
+ OSL_ASSERT(mpSelector->mnUpdateLockCount >= 0);
+ if (mpSelector->mnUpdateLockCount == 0)
+ mpSelector->UpdateCurrentPage(true);
+
+ mpSelector = nullptr;
+ }
+}
+
+//===== PageSelector::BroadcastLock ==============================================
+
+PageSelector::BroadcastLock::BroadcastLock (SlideSorter const & rSlideSorter)
+ : mrSelector(rSlideSorter.GetController().GetPageSelector())
+{
+ mrSelector.DisableBroadcasting();
+}
+
+PageSelector::BroadcastLock::BroadcastLock (PageSelector& rSelector)
+ : mrSelector(rSelector)
+{
+ mrSelector.DisableBroadcasting();
+}
+
+PageSelector::BroadcastLock::~BroadcastLock()
+{
+ mrSelector.EnableBroadcasting();
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsProperties.cxx b/sd/source/ui/slidesorter/controller/SlsProperties.cxx
new file mode 100644
index 000000000..f1152a373
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsProperties.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <controller/SlsProperties.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+namespace sd::slidesorter::controller {
+
+Properties::Properties()
+ : mbIsHighlightCurrentSlide(false),
+ mbIsShowSelection(true),
+ mbIsShowFocus(true),
+ mbIsCenterSelection(false),
+ mbIsSmoothSelectionScrolling(true),
+ mbIsSuspendPreviewUpdatesDuringFullScreenPresentation(true),
+ maBackgroundColor(Application::GetSettings().GetStyleSettings().GetWindowColor()),
+ maTextColor(Application::GetSettings().GetStyleSettings().GetActiveTextColor()),
+ maSelectionColor(Application::GetSettings().GetStyleSettings().GetHighlightColor()),
+ maHighlightColor(Application::GetSettings().GetStyleSettings().GetMenuHighlightColor()),
+ mbIsUIReadOnly(false)
+{
+}
+
+void Properties::HandleDataChangeEvent()
+{
+ maBackgroundColor = Application::GetSettings().GetStyleSettings().GetWindowColor();
+ maTextColor = Application::GetSettings().GetStyleSettings().GetActiveTextColor();
+ maSelectionColor = Application::GetSettings().GetStyleSettings().GetHighlightColor();
+ maHighlightColor = Application::GetSettings().GetStyleSettings().GetMenuHighlightColor();
+}
+
+void Properties::SetHighlightCurrentSlide (const bool bIsHighlightCurrentSlide)
+{
+ mbIsHighlightCurrentSlide = bIsHighlightCurrentSlide;
+}
+
+void Properties::SetShowSelection (const bool bIsShowSelection)
+{
+ mbIsShowSelection = bIsShowSelection;
+}
+
+void Properties::SetShowFocus (const bool bIsShowFocus)
+{
+ mbIsShowFocus = bIsShowFocus;
+}
+
+void Properties::SetCenterSelection (const bool bIsCenterSelection)
+{
+ mbIsCenterSelection = bIsCenterSelection;
+}
+
+void Properties::SetSmoothSelectionScrolling (const bool bIsSmoothSelectionScrolling)
+{
+ mbIsSmoothSelectionScrolling = bIsSmoothSelectionScrolling;
+}
+
+void Properties::SetSuspendPreviewUpdatesDuringFullScreenPresentation (const bool bFlag)
+{
+ mbIsSuspendPreviewUpdatesDuringFullScreenPresentation = bFlag;
+}
+
+void Properties::SetBackgroundColor (const Color& rColor)
+{
+ maBackgroundColor = rColor;
+}
+
+void Properties::SetTextColor (const Color& rColor)
+{
+ maTextColor = rColor;
+}
+
+void Properties::SetSelectionColor (const Color& rColor)
+{
+ maSelectionColor = rColor;
+}
+
+void Properties::SetHighlightColor (const Color& rColor)
+{
+ maHighlightColor = rColor;
+}
+
+void Properties::SetUIReadOnly (const bool bIsUIReadOnly)
+{
+ mbIsUIReadOnly = bIsUIReadOnly;
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx b/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx
new file mode 100644
index 000000000..83192414f
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx
@@ -0,0 +1,608 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <controller/SlsScrollBarManager.hxx>
+
+#include <SlideSorter.hxx>
+#include <ViewShell.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsVisibleAreaManager.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <Window.hxx>
+#include <sdpage.hxx>
+#include <osl/diagnose.h>
+
+#include <vcl/scrbar.hxx>
+
+namespace sd::slidesorter::controller {
+
+constexpr double gnHorizontalScrollFactor(0.15);
+constexpr double gnVerticalScrollFactor(0.25);
+
+ScrollBarManager::ScrollBarManager (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mpHorizontalScrollBar(mrSlideSorter.GetHorizontalScrollBar()),
+ mpVerticalScrollBar(mrSlideSorter.GetVerticalScrollBar()),
+ mnHorizontalPosition (0),
+ mnVerticalPosition (0),
+ maScrollBorder (20,20),
+ mpScrollBarFiller(mrSlideSorter.GetScrollBarFiller()),
+ maAutoScrollTimer("sd ScrollBarManager maAutoScrollTimer"),
+ maAutoScrollOffset(0,0),
+ mbIsAutoScrollActive(false),
+ mpContentWindow(mrSlideSorter.GetContentWindow())
+{
+ // Hide the scroll bars by default to prevent display errors while
+ // switching between view shells: In the short time between initiating
+ // such a switch and the final rearrangement of UI controls the scroll
+ // bars and the filler where displayed in the upper left corner of the
+ // ViewTabBar.
+ mpHorizontalScrollBar->Hide();
+ mpVerticalScrollBar->Hide();
+ mpScrollBarFiller->Hide();
+
+ maAutoScrollTimer.SetTimeout(25);
+ maAutoScrollTimer.SetInvokeHandler (
+ LINK(this, ScrollBarManager, AutoScrollTimeoutHandler));
+}
+
+ScrollBarManager::~ScrollBarManager()
+{
+}
+
+void ScrollBarManager::Connect()
+{
+ if (mpVerticalScrollBar != nullptr)
+ {
+ mpVerticalScrollBar->SetScrollHdl (
+ LINK(this, ScrollBarManager, VerticalScrollBarHandler));
+ }
+ if (mpHorizontalScrollBar != nullptr)
+ {
+ mpHorizontalScrollBar->SetScrollHdl(
+ LINK(this, ScrollBarManager, HorizontalScrollBarHandler));
+ }
+}
+
+void ScrollBarManager::Disconnect()
+{
+ if (mpVerticalScrollBar != nullptr)
+ {
+ mpVerticalScrollBar->SetScrollHdl( Link<ScrollBar*,void>() );
+ }
+ if (mpHorizontalScrollBar != nullptr)
+ {
+ mpHorizontalScrollBar->SetScrollHdl( Link<ScrollBar*,void>() );
+ }
+}
+
+/** Placing the scroll bars is an iterative process. The visibility of one
+ scroll bar affects the remaining size and thus may lead to the other
+ scroll bar becoming visible.
+
+ First we determine the visibility of the horizontal scroll bar. After
+ that we do the same for the vertical scroll bar. To have an initial
+ value for the required size we call the layouter before that. When one
+ of the two scroll bars is made visible then the size of the browser
+ window changes and a second call to the layouter becomes necessary.
+ That call is made anyway after this method returns.
+*/
+::tools::Rectangle ScrollBarManager::PlaceScrollBars (
+ const ::tools::Rectangle& rAvailableArea,
+ const bool bIsHorizontalScrollBarAllowed,
+ const bool bIsVerticalScrollBarAllowed)
+{
+ ::tools::Rectangle aRemainingSpace (DetermineScrollBarVisibilities(
+ rAvailableArea,
+ bIsHorizontalScrollBarAllowed,
+ bIsVerticalScrollBarAllowed));
+
+ if (mpHorizontalScrollBar!=nullptr && mpHorizontalScrollBar->IsVisible())
+ PlaceHorizontalScrollBar (rAvailableArea);
+
+ if (mpVerticalScrollBar!=nullptr && mpVerticalScrollBar->IsVisible())
+ PlaceVerticalScrollBar (rAvailableArea);
+
+ if (mpScrollBarFiller!=nullptr && mpScrollBarFiller->IsVisible())
+ PlaceFiller (rAvailableArea);
+
+ return aRemainingSpace;
+}
+
+void ScrollBarManager::PlaceHorizontalScrollBar (const ::tools::Rectangle& aAvailableArea)
+{
+ // Save the current relative position.
+ mnHorizontalPosition = double(mpHorizontalScrollBar->GetThumbPos())
+ / double(mpHorizontalScrollBar->GetRange().Len());
+
+ // Place the scroll bar.
+ Size aScrollBarSize (mpHorizontalScrollBar->GetSizePixel());
+ mpHorizontalScrollBar->SetPosSizePixel (
+ Point(aAvailableArea.Left(),
+ aAvailableArea.Bottom()-aScrollBarSize.Height()+1),
+ Size (aAvailableArea.GetWidth() - GetVerticalScrollBarWidth(),
+ aScrollBarSize.Height()));
+
+ // Restore the relative position.
+ mpHorizontalScrollBar->SetThumbPos(
+ static_cast<::tools::Long>(0.5 + mnHorizontalPosition * mpHorizontalScrollBar->GetRange().Len()));
+}
+
+void ScrollBarManager::PlaceVerticalScrollBar (const ::tools::Rectangle& aArea)
+{
+ const sal_Int32 nThumbPosition (mpVerticalScrollBar->GetThumbPos());
+
+ // Place the scroll bar.
+ Size aScrollBarSize (mpVerticalScrollBar->GetSizePixel());
+ Point aPosition (aArea.Right()-aScrollBarSize.Width()+1, aArea.Top());
+ Size aSize (aScrollBarSize.Width(), aArea.GetHeight() - GetHorizontalScrollBarHeight());
+ mpVerticalScrollBar->SetPosSizePixel(aPosition, aSize);
+
+ // Restore the position.
+ mpVerticalScrollBar->SetThumbPos(static_cast<::tools::Long>(nThumbPosition));
+ mnVerticalPosition = nThumbPosition / double(mpVerticalScrollBar->GetRange().Len());
+}
+
+void ScrollBarManager::PlaceFiller (const ::tools::Rectangle& aArea)
+{
+ mpScrollBarFiller->SetPosSizePixel(
+ Point(
+ aArea.Right()-mpVerticalScrollBar->GetSizePixel().Width()+1,
+ aArea.Bottom()-mpHorizontalScrollBar->GetSizePixel().Height()+1),
+ Size (
+ mpVerticalScrollBar->GetSizePixel().Width(),
+ mpHorizontalScrollBar->GetSizePixel().Height()));
+}
+
+void ScrollBarManager::UpdateScrollBars(bool bUseScrolling)
+{
+ ::tools::Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea());
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ Size aWindowModelSize (pWindow->PixelToLogic(pWindow->GetSizePixel()));
+
+ // The horizontal scroll bar is only shown when the window is
+ // horizontally smaller than the view.
+ if (mpHorizontalScrollBar != nullptr && mpHorizontalScrollBar->IsVisible())
+ {
+ mpHorizontalScrollBar->Show();
+ mpHorizontalScrollBar->SetRange (
+ Range(aModelArea.Left(), aModelArea.Right()));
+ mnHorizontalPosition =
+ double(mpHorizontalScrollBar->GetThumbPos())
+ / double(mpHorizontalScrollBar->GetRange().Len());
+
+ mpHorizontalScrollBar->SetVisibleSize (aWindowModelSize.Width());
+
+ const ::tools::Long nWidth (mpContentWindow->PixelToLogic(
+ mpContentWindow->GetSizePixel()).Width());
+ // Make the line size about 10% of the visible width.
+ mpHorizontalScrollBar->SetLineSize (nWidth / 10);
+ // Make the page size about 90% of the visible width.
+ mpHorizontalScrollBar->SetPageSize ((nWidth * 9) / 10);
+ }
+ else
+ {
+ mnHorizontalPosition = 0;
+ }
+
+ // The vertical scroll bar is always shown.
+ if (mpVerticalScrollBar != nullptr && mpVerticalScrollBar->IsVisible())
+ {
+ mpVerticalScrollBar->SetRange (
+ Range(aModelArea.Top(), aModelArea.Bottom()));
+ mnVerticalPosition =
+ double(mpVerticalScrollBar->GetThumbPos())
+ / double(mpVerticalScrollBar->GetRange().Len());
+
+ mpVerticalScrollBar->SetVisibleSize (aWindowModelSize.Height());
+
+ const ::tools::Long nHeight (mpContentWindow->PixelToLogic(
+ mpContentWindow->GetSizePixel()).Height());
+ // Make the line size about 10% of the visible height.
+ mpVerticalScrollBar->SetLineSize (nHeight / 10);
+ // Make the page size about 90% of the visible height.
+ mpVerticalScrollBar->SetPageSize ((nHeight * 9) / 10);
+ }
+ else
+ {
+ mnVerticalPosition = 0;
+ }
+
+ double nEps (::std::numeric_limits<double>::epsilon());
+ if (fabs(mnHorizontalPosition-pWindow->GetVisibleX()) > nEps
+ || fabs(mnVerticalPosition-pWindow->GetVisibleY()) > nEps)
+ {
+ mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
+ if (bUseScrolling)
+ pWindow->SetVisibleXY(mnHorizontalPosition, mnVerticalPosition);
+ else
+ SetWindowOrigin(mnHorizontalPosition, mnVerticalPosition);
+ }
+}
+
+IMPL_LINK(ScrollBarManager, VerticalScrollBarHandler, ScrollBar*, pScrollBar, void)
+{
+ if (pScrollBar!=nullptr
+ && pScrollBar==mpVerticalScrollBar.get()
+ && pScrollBar->IsVisible()
+ && mrSlideSorter.GetContentWindow())
+ {
+ double nRelativePosition = double(pScrollBar->GetThumbPos())
+ / double(pScrollBar->GetRange().Len());
+ mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
+ mrSlideSorter.GetContentWindow()->SetVisibleXY(-1, nRelativePosition);
+ mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking();
+ }
+}
+
+IMPL_LINK(ScrollBarManager, HorizontalScrollBarHandler, ScrollBar*, pScrollBar, void)
+{
+ if (pScrollBar!=nullptr
+ && pScrollBar==mpHorizontalScrollBar.get()
+ && pScrollBar->IsVisible()
+ && mrSlideSorter.GetContentWindow())
+ {
+ double nRelativePosition = double(pScrollBar->GetThumbPos())
+ / double(pScrollBar->GetRange().Len());
+ mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
+ mrSlideSorter.GetContentWindow()->SetVisibleXY(nRelativePosition, -1);
+ mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking();
+ }
+}
+
+void ScrollBarManager::SetWindowOrigin (
+ double nHorizontalPosition,
+ double nVerticalPosition)
+{
+ mnHorizontalPosition = nHorizontalPosition;
+ mnVerticalPosition = nVerticalPosition;
+
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ Size aViewSize (pWindow->GetViewSize());
+ Point aOrigin (
+ static_cast<::tools::Long>(mnHorizontalPosition * aViewSize.Width()),
+ static_cast<::tools::Long>(mnVerticalPosition * aViewSize.Height()));
+
+ pWindow->SetWinViewPos (aOrigin);
+ pWindow->UpdateMapMode ();
+ pWindow->Invalidate ();
+}
+
+/** Determining the visibility of the scroll bars is quite complicated. The
+ visibility of one influences that of the other because showing a scroll
+ bar makes the available space smaller and may lead to the need of
+ displaying the other.
+ To solve this we test all four combinations of showing or hiding each
+ scroll bar and use the best one. The best one is that combination that
+ a) shows the least number of scroll bars with preference of showing the
+ vertical over showing the horizontal and
+ b) when not showing a scroll bar the area used by the page objects fits
+ into the available area in the scroll bars orientation.
+*/
+::tools::Rectangle ScrollBarManager::DetermineScrollBarVisibilities (
+ const ::tools::Rectangle& rAvailableArea,
+ const bool bIsHorizontalScrollBarAllowed,
+ const bool bIsVerticalScrollBarAllowed)
+{
+ // Test which combination of scroll bars is the best.
+ bool bShowHorizontal = false;
+ bool bShowVertical = false;
+ if (mrSlideSorter.GetModel().GetPageCount() == 0)
+ {
+ // No pages => no scroll bars.
+ }
+ else if (TestScrollBarVisibilities(false, false, rAvailableArea))
+ {
+ // Nothing to be done.
+ }
+ else if (bIsHorizontalScrollBarAllowed
+ && TestScrollBarVisibilities(true, false, rAvailableArea))
+ {
+ bShowHorizontal = true;
+ }
+ else if (bIsVerticalScrollBarAllowed
+ && TestScrollBarVisibilities(false, true, rAvailableArea))
+ {
+ bShowVertical = true;
+ }
+ else
+ {
+ bShowHorizontal = true;
+ bShowVertical = true;
+ }
+
+ // Make the visibility of the scroll bars permanent.
+ mpVerticalScrollBar->Show(bShowVertical);
+ mpHorizontalScrollBar->Show(bShowHorizontal);
+ mpScrollBarFiller->Show(bShowVertical && bShowHorizontal);
+
+ // Adapt the remaining space accordingly.
+ ::tools::Rectangle aRemainingSpace (rAvailableArea);
+ if (bShowVertical)
+ aRemainingSpace.AdjustRight( -(mpVerticalScrollBar->GetSizePixel().Width()) );
+ if (bShowHorizontal)
+ aRemainingSpace.AdjustBottom( -(mpHorizontalScrollBar->GetSizePixel().Height()) );
+
+ return aRemainingSpace;
+}
+
+bool ScrollBarManager::TestScrollBarVisibilities (
+ bool bHorizontalScrollBarVisible,
+ bool bVerticalScrollBarVisible,
+ const ::tools::Rectangle& rAvailableArea)
+{
+ model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
+
+ // Adapt the available size by subtracting the sizes of the scroll bars
+ // visible in this combination.
+ Size aBrowserSize (rAvailableArea.GetSize());
+ if (bHorizontalScrollBarVisible)
+ aBrowserSize.AdjustHeight( -(mpHorizontalScrollBar->GetSizePixel().Height()) );
+ if (bVerticalScrollBarVisible)
+ aBrowserSize.AdjustWidth( -(mpVerticalScrollBar->GetSizePixel().Width()) );
+
+ // Tell the view to rearrange its page objects and check whether the
+ // page objects can be shown without clipping.
+ bool bRearrangeSuccess (mrSlideSorter.GetView().GetLayouter().Rearrange (
+ mrSlideSorter.GetView().GetOrientation(),
+ aBrowserSize,
+ rModel.GetPageDescriptor(0)->GetPage()->GetSize(),
+ rModel.GetPageCount()));
+
+ if (bRearrangeSuccess)
+ {
+ Size aPageSize = mrSlideSorter.GetView().GetLayouter().GetTotalBoundingBox().GetSize();
+ Size aWindowModelSize = mpContentWindow->PixelToLogic(aBrowserSize);
+
+ // The content may be clipped, i.e. not fully visible, in one
+ // direction only when the scroll bar is visible in that direction.
+ if (aPageSize.Width() > aWindowModelSize.Width())
+ if ( ! bHorizontalScrollBarVisible)
+ return false;
+ if (aPageSize.Height() > aWindowModelSize.Height())
+ if ( ! bVerticalScrollBarVisible)
+ return false;
+
+ return true;
+ }
+ else
+ return false;
+}
+
+void ScrollBarManager::SetTopLeft(const Point& rNewTopLeft)
+{
+ if (( ! mpVerticalScrollBar
+ || mpVerticalScrollBar->GetThumbPos() == rNewTopLeft.Y())
+ && ( ! mpHorizontalScrollBar
+ || mpHorizontalScrollBar->GetThumbPos() == rNewTopLeft.X()))
+ return;
+
+ // Flush pending repaints before scrolling to avoid temporary artifacts.
+ mrSlideSorter.GetContentWindow()->PaintImmediately();
+
+ if (mpVerticalScrollBar)
+ {
+ mpVerticalScrollBar->SetThumbPos(rNewTopLeft.Y());
+ mnVerticalPosition = rNewTopLeft.Y() / double(mpVerticalScrollBar->GetRange().Len());
+ }
+ if (mpHorizontalScrollBar)
+ {
+ mpHorizontalScrollBar->SetThumbPos(rNewTopLeft.X());
+ mnHorizontalPosition = rNewTopLeft.X() / double(mpHorizontalScrollBar->GetRange().Len());
+ }
+
+ mrSlideSorter.GetContentWindow()->SetVisibleXY(mnHorizontalPosition, mnVerticalPosition);
+ mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
+}
+
+int ScrollBarManager::GetVerticalScrollBarWidth() const
+{
+ if (mpVerticalScrollBar != nullptr && mpVerticalScrollBar->IsVisible())
+ return mpVerticalScrollBar->GetSizePixel().Width();
+ else
+ return 0;
+}
+
+int ScrollBarManager::GetHorizontalScrollBarHeight() const
+{
+ if (mpHorizontalScrollBar != nullptr && mpHorizontalScrollBar->IsVisible())
+ return mpHorizontalScrollBar->GetSizePixel().Height();
+ else
+ return 0;
+}
+
+void ScrollBarManager::CalcAutoScrollOffset (const Point& rMouseWindowPosition)
+{
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+
+ int nDx = 0;
+ int nDy = 0;
+
+ Size aWindowSize = pWindow->GetOutputSizePixel();
+ ::tools::Rectangle aWindowArea (pWindow->GetPosPixel(), aWindowSize);
+ ::tools::Rectangle aViewPixelArea (
+ pWindow->LogicToPixel(mrSlideSorter.GetView().GetModelArea()));
+
+ if (aWindowSize.Width() > maScrollBorder.Width() * 3
+ && mpHorizontalScrollBar != nullptr
+ && mpHorizontalScrollBar->IsVisible())
+ {
+ if (rMouseWindowPosition.X() < maScrollBorder.Width()
+ && aWindowArea.Left() > aViewPixelArea.Left())
+ {
+ nDx = -1 + static_cast<int>(gnHorizontalScrollFactor
+ * (rMouseWindowPosition.X() - maScrollBorder.Width()));
+ }
+
+ if (rMouseWindowPosition.X() >= (aWindowSize.Width() - maScrollBorder.Width())
+ && aWindowArea.Right() < aViewPixelArea.Right())
+ {
+ nDx = 1 + static_cast<int>(gnHorizontalScrollFactor
+ * (rMouseWindowPosition.X() - aWindowSize.Width()
+ + maScrollBorder.Width()));
+ }
+ }
+
+ if (aWindowSize.Height() > maScrollBorder.Height() * 3
+ && aWindowSize.Height() < aViewPixelArea.GetHeight())
+ {
+ if (rMouseWindowPosition.Y() < maScrollBorder.Height()
+ && aWindowArea.Top() > aViewPixelArea.Top())
+ {
+ nDy = -1 + static_cast<int>(gnVerticalScrollFactor
+ * (rMouseWindowPosition.Y() - maScrollBorder.Height()));
+ }
+
+ if (rMouseWindowPosition.Y() >= (aWindowSize.Height() - maScrollBorder.Height())
+ && aWindowArea.Bottom() < aViewPixelArea.Bottom())
+ {
+ nDy = 1 + static_cast<int>(gnVerticalScrollFactor
+ * (rMouseWindowPosition.Y() - aWindowSize.Height()
+ + maScrollBorder.Height()));
+ }
+ }
+
+ maAutoScrollOffset = Size(nDx,nDy);
+}
+
+bool ScrollBarManager::AutoScroll (
+ const Point& rMouseWindowPosition,
+ const ::std::function<void ()>& rAutoScrollFunctor)
+{
+ maAutoScrollFunctor = rAutoScrollFunctor;
+ CalcAutoScrollOffset(rMouseWindowPosition);
+ bool bResult (true);
+ if ( ! mbIsAutoScrollActive)
+ bResult = RepeatAutoScroll();
+
+ return bResult;
+}
+
+void ScrollBarManager::StopAutoScroll()
+{
+ maAutoScrollTimer.Stop();
+ mbIsAutoScrollActive = false;
+}
+
+bool ScrollBarManager::RepeatAutoScroll()
+{
+ if (maAutoScrollOffset != Size(0,0))
+ {
+ if (mrSlideSorter.GetViewShell() != nullptr)
+ {
+ mrSlideSorter.GetViewShell()->Scroll(
+ maAutoScrollOffset.Width(),
+ maAutoScrollOffset.Height());
+ mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
+
+ if (maAutoScrollFunctor)
+ maAutoScrollFunctor();
+
+ mbIsAutoScrollActive = true;
+ maAutoScrollTimer.Start();
+
+ return true;
+ }
+ }
+
+ clearAutoScrollFunctor();
+ mbIsAutoScrollActive = false;
+ return false;
+}
+
+void ScrollBarManager::clearAutoScrollFunctor()
+{
+ maAutoScrollFunctor = ::std::function<void ()>();
+}
+
+IMPL_LINK_NOARG(ScrollBarManager, AutoScrollTimeoutHandler, Timer *, void)
+{
+ RepeatAutoScroll();
+}
+
+void ScrollBarManager::Scroll(
+ const Orientation eOrientation,
+ const sal_Int32 nDistance)
+{
+ bool bIsVertical (false);
+ switch (eOrientation)
+ {
+ case Orientation_Horizontal: bIsVertical = false; break;
+ case Orientation_Vertical: bIsVertical = true; break;
+ default:
+ OSL_ASSERT(eOrientation==Orientation_Horizontal || eOrientation==Orientation_Vertical);
+ return;
+ }
+
+ Point aNewTopLeft (
+ mpHorizontalScrollBar ? mpHorizontalScrollBar->GetThumbPos() : 0,
+ mpVerticalScrollBar ? mpVerticalScrollBar->GetThumbPos() : 0);
+
+ view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter());
+
+ // Calculate estimate of new location.
+ if (bIsVertical)
+ aNewTopLeft.AdjustY(nDistance * rLayouter.GetPageObjectSize().Height() );
+ else
+ aNewTopLeft.AdjustX(nDistance * rLayouter.GetPageObjectSize().Width() );
+
+ // Adapt location to show whole slides.
+ if (bIsVertical)
+ if (nDistance > 0)
+ {
+ const sal_Int32 nIndex (rLayouter.GetIndexAtPoint(
+ Point(aNewTopLeft.X(), aNewTopLeft.Y()+mpVerticalScrollBar->GetVisibleSize()),
+ true));
+ aNewTopLeft.setY( rLayouter.GetPageObjectBox(nIndex,true).Bottom()
+ - mpVerticalScrollBar->GetVisibleSize() );
+ }
+ else
+ {
+ const sal_Int32 nIndex (rLayouter.GetIndexAtPoint(
+ Point(aNewTopLeft.X(), aNewTopLeft.Y()),
+ true));
+ aNewTopLeft.setY( rLayouter.GetPageObjectBox(nIndex,true).Top() );
+ }
+ else
+ if (nDistance > 0)
+ {
+ const sal_Int32 nIndex (rLayouter.GetIndexAtPoint(
+ Point(aNewTopLeft.X()+mpVerticalScrollBar->GetVisibleSize(), aNewTopLeft.Y()),
+ true));
+ aNewTopLeft.setX( rLayouter.GetPageObjectBox(nIndex,true).Right()
+ - mpVerticalScrollBar->GetVisibleSize() );
+ }
+ else
+ {
+ const sal_Int32 nIndex (rLayouter.GetIndexAtPoint(
+ Point(aNewTopLeft.X(), aNewTopLeft.Y()),
+ true));
+ aNewTopLeft.setX( rLayouter.GetPageObjectBox(nIndex,true).Left() );
+ }
+
+ mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking();
+ SetTopLeft(aNewTopLeft);
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx
new file mode 100644
index 000000000..c710a4c1b
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx
@@ -0,0 +1,1485 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+
+#include <controller/SlsSelectionFunction.hxx>
+
+#include <SlideSorter.hxx>
+#include <SlideSorterViewShell.hxx>
+#include "SlsDragAndDropContext.hxx"
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsFocusManager.hxx>
+#include <controller/SlsScrollBarManager.hxx>
+#include <controller/SlsClipboard.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <controller/SlsInsertionIndicatorHandler.hxx>
+#include <controller/SlsSelectionManager.hxx>
+#include <controller/SlsProperties.hxx>
+#include <controller/SlsVisibleAreaManager.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <osl/diagnose.h>
+#include <Window.hxx>
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <sdxfer.hxx>
+#include <ViewShell.hxx>
+#include <FrameView.hxx>
+#include <app.hrc>
+#include <o3tl/deleter.hxx>
+#include <sfx2/dispatch.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <optional>
+#include <sdmod.hxx>
+
+namespace {
+const sal_uInt32 SINGLE_CLICK (0x00000001);
+const sal_uInt32 DOUBLE_CLICK (0x00000002);
+const sal_uInt32 LEFT_BUTTON (0x00000010);
+const sal_uInt32 RIGHT_BUTTON (0x00000020);
+const sal_uInt32 MIDDLE_BUTTON (0x00000040);
+const sal_uInt32 BUTTON_DOWN (0x00000100);
+const sal_uInt32 BUTTON_UP (0x00000200);
+const sal_uInt32 MOUSE_MOTION (0x00000400);
+const sal_uInt32 MOUSE_DRAG (0x00000800);
+// The rest leaves the lower 16 bit untouched so that it can be used with
+// key codes.
+const sal_uInt32 OVER_SELECTED_PAGE (0x00010000);
+const sal_uInt32 OVER_UNSELECTED_PAGE (0x00020000);
+const sal_uInt32 SHIFT_MODIFIER (0x00200000);
+const sal_uInt32 CONTROL_MODIFIER (0x00400000);
+
+// Some absent events are defined so they can be expressed explicitly.
+const sal_uInt32 NO_MODIFIER (0x00000000);
+const sal_uInt32 NOT_OVER_PAGE (0x00000000);
+
+// Masks
+const sal_uInt32 MODIFIER_MASK (SHIFT_MODIFIER | CONTROL_MODIFIER);
+
+} // end of anonymous namespace
+
+// Define some macros to make the following switch statement more readable.
+#define ANY_MODIFIER(code) \
+ code|NO_MODIFIER: \
+ case code|SHIFT_MODIFIER: \
+ case code|CONTROL_MODIFIER
+
+namespace sd::slidesorter::controller {
+
+//===== SelectionFunction::EventDescriptor ====================================
+
+class SelectionFunction::EventDescriptor
+{
+public:
+ Point maMousePosition;
+ Point maMouseModelPosition;
+ model::SharedPageDescriptor mpHitDescriptor;
+ SdrPage* mpHitPage;
+ sal_uInt32 mnEventCode;
+ InsertionIndicatorHandler::Mode meDragMode;
+ bool mbIsLeaving;
+
+ EventDescriptor (
+ sal_uInt32 nEventType,
+ const MouseEvent& rEvent,
+ SlideSorter const & rSlideSorter);
+ EventDescriptor (
+ sal_uInt32 nEventType,
+ const AcceptDropEvent& rEvent,
+ const sal_Int8 nDragAction,
+ SlideSorter const & rSlideSorter);
+
+private:
+ /** Compute a numerical code that describes a mouse event and that can
+ be used for fast look up of the appropriate reaction.
+ */
+ sal_uInt32 EncodeMouseEvent (const MouseEvent& rEvent) const;
+
+ /** Compute a numerical code that describes the current state like
+ whether the selection rectangle is visible or whether the page under
+ the mouse or the one that has the focus is selected.
+ */
+ sal_uInt32 EncodeState() const;
+};
+
+//===== SelectionFunction::ModeHandler ========================================
+
+class SelectionFunction::ModeHandler
+{
+public:
+ ModeHandler (
+ SlideSorter& rSlideSorter,
+ SelectionFunction& rSelectionFunction,
+ const bool bIsMouseOverIndicatorAllowed);
+ virtual ~ModeHandler() COVERITY_NOEXCEPT_FALSE;
+
+ virtual Mode GetMode() const = 0;
+ virtual void Abort() = 0;
+ virtual void ProcessEvent (EventDescriptor& rDescriptor);
+
+ /** Set the selection to exactly the specified page and also set it as
+ the current page.
+ */
+ void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor);
+
+ /// Deselect all pages.
+ void DeselectAllPages();
+ void SelectOnePage (const model::SharedPageDescriptor& rpDescriptor);
+
+ /** When the view on which this selection function is working is the
+ main view then the view is switched to the regular editing view.
+ */
+ void SwitchView (const model::SharedPageDescriptor& rpDescriptor);
+
+ void StartDrag (
+ const Point& rMousePosition);
+
+ bool IsMouseOverIndicatorAllowed() const { return mbIsMouseOverIndicatorAllowed;}
+
+protected:
+ SlideSorter& mrSlideSorter;
+ SelectionFunction& mrSelectionFunction;
+
+ virtual bool ProcessButtonDownEvent (EventDescriptor& rDescriptor);
+ virtual bool ProcessButtonUpEvent (EventDescriptor& rDescriptor);
+ virtual bool ProcessMotionEvent (EventDescriptor& rDescriptor);
+ virtual bool ProcessDragEvent (EventDescriptor& rDescriptor);
+ virtual bool HandleUnprocessedEvent (EventDescriptor& rDescriptor);
+
+ void ReprocessEvent (EventDescriptor& rDescriptor);
+
+private:
+ const bool mbIsMouseOverIndicatorAllowed;
+};
+
+namespace {
+
+/** This is the default handler for processing events. It activates the
+ multi selection or drag-and-drop when the right conditions are met.
+*/
+class NormalModeHandler : public SelectionFunction::ModeHandler
+{
+public:
+ NormalModeHandler (
+ SlideSorter& rSlideSorter,
+ SelectionFunction& rSelectionFunction);
+
+ virtual SelectionFunction::Mode GetMode() const override;
+ virtual void Abort() override;
+
+ void ResetButtonDownLocation();
+
+protected:
+ virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
+ virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
+ virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
+ virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
+
+private:
+ ::std::optional<Point> maButtonDownLocation;
+
+ /** Select all pages between and including the selection anchor and the
+ specified page.
+ */
+ void RangeSelect (const model::SharedPageDescriptor& rpDescriptor);
+};
+
+/** Handle events during a multi selection, which typically is started by
+ pressing the left mouse button when not over a page.
+*/
+class MultiSelectionModeHandler : public SelectionFunction::ModeHandler
+{
+public:
+ /** Start a rectangle selection at the given position.
+ */
+ MultiSelectionModeHandler (
+ SlideSorter& rSlideSorter,
+ SelectionFunction& rSelectionFunction,
+ const Point& rMouseModelPosition,
+ const sal_uInt32 nEventCode);
+
+ virtual ~MultiSelectionModeHandler() override;
+
+ virtual SelectionFunction::Mode GetMode() const override;
+ virtual void Abort() override;
+ virtual void ProcessEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
+
+ enum SelectionMode { SM_Normal, SM_Add, SM_Toggle };
+
+ void SetSelectionMode (const SelectionMode eSelectionMode);
+ void SetSelectionModeFromModifier (const sal_uInt32 nEventCode);
+
+protected:
+ virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
+ virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
+ virtual bool HandleUnprocessedEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
+
+private:
+ SelectionMode meSelectionMode;
+ Point maSecondCorner;
+ PointerStyle maSavedPointer;
+ bool mbAutoScrollInstalled;
+ sal_Int32 mnAnchorIndex;
+ sal_Int32 mnSecondIndex;
+
+ void UpdateModelPosition (const Point& rMouseModelPosition);
+ void UpdateSelection();
+
+ /** Update the rectangle selection so that the given position becomes
+ the new second point of the selection rectangle.
+ */
+ void UpdatePosition (
+ const Point& rMousePosition,
+ const bool bAllowAutoScroll);
+
+ void UpdateSelectionState (
+ const model::SharedPageDescriptor& rpDescriptor,
+ const bool bIsInSelection) const;
+};
+
+/** Handle events during drag-and-drop.
+*/
+class DragAndDropModeHandler : public SelectionFunction::ModeHandler
+{
+public:
+ DragAndDropModeHandler (
+ SlideSorter& rSlideSorter,
+ SelectionFunction& rSelectionFunction,
+ const Point& rMousePosition,
+ vcl::Window* pWindow);
+ virtual ~DragAndDropModeHandler() override;
+
+ virtual SelectionFunction::Mode GetMode() const override;
+ virtual void Abort() override;
+
+protected:
+ virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
+ virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
+
+private:
+ std::unique_ptr<DragAndDropContext, o3tl::default_delete<DragAndDropContext>> mpDragAndDropContext;
+};
+
+}
+
+//===== SelectionFunction =====================================================
+
+
+SelectionFunction::SelectionFunction (
+ SlideSorter& rSlideSorter,
+ SfxRequest& rRequest)
+ : FuPoor (
+ rSlideSorter.GetViewShell(),
+ rSlideSorter.GetContentWindow(),
+ &rSlideSorter.GetView(),
+ rSlideSorter.GetModel().GetDocument(),
+ rRequest),
+ mrSlideSorter(rSlideSorter),
+ mrController(mrSlideSorter.GetController()),
+ mnShiftKeySelectionAnchor(-1),
+ mpModeHandler(std::make_shared<NormalModeHandler>(rSlideSorter, *this))
+{
+}
+
+SelectionFunction::~SelectionFunction()
+{
+ mpModeHandler.reset();
+}
+
+rtl::Reference<FuPoor> SelectionFunction::Create(
+ SlideSorter& rSlideSorter,
+ SfxRequest& rRequest)
+{
+ rtl::Reference<FuPoor> xFunc( new SelectionFunction( rSlideSorter, rRequest ) );
+ return xFunc;
+}
+
+bool SelectionFunction::MouseButtonDown (const MouseEvent& rEvent)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode (rEvent.GetButtons());
+ aMDPos = rEvent.GetPosPixel();
+
+ // mpWindow->CaptureMouse();
+
+ ProcessMouseEvent(BUTTON_DOWN, rEvent);
+
+ return true;
+}
+
+bool SelectionFunction::MouseMove (const MouseEvent& rEvent)
+{
+ ProcessMouseEvent(MOUSE_MOTION, rEvent);
+ return true;
+}
+
+bool SelectionFunction::MouseButtonUp (const MouseEvent& rEvent)
+{
+ mrController.GetScrollBarManager().StopAutoScroll ();
+
+ ProcessMouseEvent(BUTTON_UP, rEvent);
+
+ return true;
+}
+
+void SelectionFunction::NotifyDragFinished()
+{
+ SwitchToNormalMode();
+}
+
+bool SelectionFunction::KeyInput (const KeyEvent& rEvent)
+{
+ view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter);
+ PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter);
+ PageSelector::UpdateLock aLock (mrSlideSorter);
+ FocusManager& rFocusManager (mrController.GetFocusManager());
+ bool bResult = false;
+
+ const vcl::KeyCode& rCode (rEvent.GetKeyCode());
+ switch (rCode.GetCode())
+ {
+ case KEY_RETURN:
+ {
+ model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (rFocusManager.HasFocus() && pDescriptor && pViewShell!=nullptr)
+ {
+ // The Return key triggers different functions depending on
+ // whether the slide sorter is the main view or displayed in
+ // the right pane.
+ if (pViewShell->IsMainViewShell())
+ {
+ mpModeHandler->SetCurrentPage(pDescriptor);
+ mpModeHandler->SwitchView(pDescriptor);
+ }
+ else if (pViewShell->GetDispatcher() != nullptr)
+ {
+ pViewShell->GetDispatcher()->Execute(
+ SID_INSERTPAGE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+ bResult = true;
+ }
+ break;
+ }
+
+ case KEY_TAB:
+ if ( ! rFocusManager.IsFocusShowing())
+ {
+ rFocusManager.ShowFocus();
+ bResult = true;
+ }
+ break;
+
+ case KEY_ESCAPE:
+ // When there is an active multiselection or drag-and-drop
+ // operation then stop that.
+ mpModeHandler->Abort();
+ SwitchToNormalMode();
+ bResult = true;
+ break;
+
+ case KEY_SPACE:
+ {
+ // Toggle the selection state.
+ model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
+ if (pDescriptor && rCode.IsMod1())
+ {
+ if (pDescriptor->HasState(model::PageDescriptor::ST_Selected))
+ mrController.GetPageSelector().DeselectPage(pDescriptor, false);
+ else
+ mrController.GetPageSelector().SelectPage(pDescriptor);
+ }
+ bResult = true;
+ }
+ break;
+
+ // Move the focus indicator left.
+ case KEY_LEFT:
+ MoveFocus(FocusManager::FocusMoveDirection::Left, rCode.IsShift(), rCode.IsMod1());
+ bResult = true;
+ break;
+
+ // Move the focus indicator right.
+ case KEY_RIGHT:
+ MoveFocus(FocusManager::FocusMoveDirection::Right, rCode.IsShift(), rCode.IsMod1());
+ bResult = true;
+ break;
+
+ // Move the focus indicator up.
+ case KEY_UP:
+ MoveFocus(FocusManager::FocusMoveDirection::Up, rCode.IsShift(), rCode.IsMod1());
+ bResult = true;
+ break;
+
+ // Move the focus indicator down.
+ case KEY_DOWN:
+ MoveFocus(FocusManager::FocusMoveDirection::Down, rCode.IsShift(), rCode.IsMod1());
+ bResult = true;
+ break;
+
+ // Go to previous page. No wrap around.
+ case KEY_PAGEUP:
+ GotoNextPage(-1);
+ bResult = true;
+ break;
+
+ // Go to next page. No wrap around...
+ case KEY_PAGEDOWN:
+ GotoNextPage(+1);
+ bResult = true;
+ break;
+
+ case KEY_HOME:
+ GotoPage(0);
+ bResult = true;
+ break;
+
+ case KEY_END:
+ GotoPage(mrSlideSorter.GetModel().GetPageCount()-1);
+ bResult = true;
+ break;
+
+ case KEY_DELETE:
+ case KEY_BACKSPACE:
+ {
+ if (mrSlideSorter.GetProperties()->IsUIReadOnly())
+ break;
+
+ mrController.GetSelectionManager()->DeleteSelectedPages(rCode.GetCode()==KEY_DELETE);
+
+ mnShiftKeySelectionAnchor = -1;
+ bResult = true;
+ }
+ break;
+
+ case KEY_F10:
+ if (rCode.IsShift())
+ {
+ mpModeHandler->SelectOnePage(
+ mrSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor());
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ( ! bResult)
+ bResult = FuPoor::KeyInput(rEvent);
+
+ return bResult;
+}
+
+void SelectionFunction::MoveFocus (
+ const FocusManager::FocusMoveDirection eDirection,
+ const bool bIsShiftDown,
+ const bool bIsControlDown)
+{
+ // Remember the anchor of shift key multi selection.
+ if (bIsShiftDown)
+ {
+ if (mnShiftKeySelectionAnchor<0)
+ {
+ model::SharedPageDescriptor pFocusedDescriptor (
+ mrController.GetFocusManager().GetFocusedPageDescriptor());
+ mnShiftKeySelectionAnchor = pFocusedDescriptor->GetPageIndex();
+ }
+ }
+ else if ( ! bIsControlDown)
+ ResetShiftKeySelectionAnchor();
+
+ mrController.GetFocusManager().MoveFocus(eDirection);
+
+ PageSelector& rSelector (mrController.GetPageSelector());
+ model::SharedPageDescriptor pFocusedDescriptor (
+ mrController.GetFocusManager().GetFocusedPageDescriptor());
+ if (bIsShiftDown)
+ {
+ // When shift is pressed then select all pages in the range between
+ // the currently and the previously focused pages, including them.
+ if (pFocusedDescriptor)
+ {
+ sal_Int32 nPageRangeEnd (pFocusedDescriptor->GetPageIndex());
+ model::PageEnumeration aPages (
+ model::PageEnumerationProvider::CreateAllPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ while (aPages.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aPages.GetNextElement());
+ if (pDescriptor)
+ {
+ const sal_Int32 nPageIndex(pDescriptor->GetPageIndex());
+ if ((nPageIndex>=mnShiftKeySelectionAnchor && nPageIndex<=nPageRangeEnd)
+ || (nPageIndex<=mnShiftKeySelectionAnchor && nPageIndex>=nPageRangeEnd))
+ {
+ rSelector.SelectPage(pDescriptor);
+ }
+ else
+ {
+ rSelector.DeselectPage(pDescriptor);
+ }
+ }
+ }
+ }
+ }
+ else if (bIsControlDown)
+ {
+ // When control is pressed then do not alter the selection or the
+ // current page, just move the focus.
+ }
+ else
+ {
+ // Without shift just select the focused page.
+ mpModeHandler->SelectOnePage(pFocusedDescriptor);
+ }
+}
+
+void SelectionFunction::DoCut()
+{
+ if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
+ {
+ mrController.GetClipboard().DoCut();
+ }
+}
+
+void SelectionFunction::DoCopy()
+{
+ mrController.GetClipboard().DoCopy();
+}
+
+void SelectionFunction::DoPaste()
+{
+ if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
+ {
+ mrController.GetClipboard().DoPaste();
+ }
+}
+
+bool SelectionFunction::cancel()
+{
+ mrController.GetFocusManager().ToggleFocus();
+ return true;
+}
+
+void SelectionFunction::GotoNextPage (int nOffset)
+{
+ model::SharedPageDescriptor pDescriptor
+ = mrController.GetCurrentSlideManager()->GetCurrentSlide();
+ if (pDescriptor)
+ {
+ SdPage* pPage = pDescriptor->GetPage();
+ OSL_ASSERT(pPage!=nullptr);
+ sal_Int32 nIndex = (pPage->GetPageNum()-1) / 2;
+ GotoPage(nIndex + nOffset);
+ }
+ ResetShiftKeySelectionAnchor();
+}
+
+void SelectionFunction::GotoPage (int nIndex)
+{
+ sal_uInt16 nPageCount = static_cast<sal_uInt16>(mrSlideSorter.GetModel().GetPageCount());
+
+ if (nIndex >= nPageCount)
+ nIndex = nPageCount - 1;
+ if (nIndex < 0)
+ nIndex = 0;
+
+ mrController.GetFocusManager().SetFocusedPage(nIndex);
+ model::SharedPageDescriptor pNextPageDescriptor (
+ mrSlideSorter.GetModel().GetPageDescriptor (nIndex));
+ if (pNextPageDescriptor)
+ mpModeHandler->SetCurrentPage(pNextPageDescriptor);
+ else
+ {
+ OSL_ASSERT(pNextPageDescriptor);
+ }
+ ResetShiftKeySelectionAnchor();
+}
+
+void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent)
+{
+ // #95491# remember button state for creation of own MouseEvents
+ SetMouseButtonCode (rEvent.GetButtons());
+
+ EventDescriptor aEventDescriptor (nEventType, rEvent, mrSlideSorter);
+ ProcessEvent(aEventDescriptor);
+}
+
+void SelectionFunction::MouseDragged (
+ const AcceptDropEvent& rEvent,
+ const sal_Int8 nDragAction)
+{
+ EventDescriptor aEventDescriptor (MOUSE_DRAG, rEvent, nDragAction, mrSlideSorter);
+ ProcessEvent(aEventDescriptor);
+}
+
+void SelectionFunction::ProcessEvent (EventDescriptor& rDescriptor)
+{
+ // The call to ProcessEvent may switch to another mode handler.
+ // Prevent the untimely destruction of the called handler by acquiring a
+ // temporary reference here.
+ std::shared_ptr<ModeHandler> pModeHandler (mpModeHandler);
+ pModeHandler->ProcessEvent(rDescriptor);
+}
+
+static bool Match (
+ const sal_uInt32 nEventCode,
+ const sal_uInt32 nPositivePattern)
+{
+ return (nEventCode & nPositivePattern)==nPositivePattern;
+}
+
+void SelectionFunction::SwitchToNormalMode()
+{
+ if (mpModeHandler->GetMode() != NormalMode)
+ SwitchMode(std::make_shared<NormalModeHandler>(mrSlideSorter, *this));
+}
+
+void SelectionFunction::SwitchToDragAndDropMode (const Point& rMousePosition)
+{
+ if (mpModeHandler->GetMode() == DragAndDropMode)
+ return;
+
+ SwitchMode(std::make_shared<DragAndDropModeHandler>(mrSlideSorter, *this, rMousePosition, mpWindow));
+}
+
+void SelectionFunction::SwitchToMultiSelectionMode (
+ const Point& rMousePosition,
+ const sal_uInt32 nEventCode)
+{
+ if (mpModeHandler->GetMode() != MultiSelectionMode)
+ SwitchMode(std::make_shared<MultiSelectionModeHandler>(mrSlideSorter, *this, rMousePosition, nEventCode));
+}
+
+void SelectionFunction::SwitchMode (const std::shared_ptr<ModeHandler>& rpHandler)
+{
+ // Not all modes allow mouse over indicator.
+ if (mpModeHandler->IsMouseOverIndicatorAllowed() != rpHandler->IsMouseOverIndicatorAllowed())
+ {
+ if ( ! rpHandler->IsMouseOverIndicatorAllowed())
+ {
+ mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor());
+ }
+ else
+ mrSlideSorter.GetView().UpdatePageUnderMouse();
+ }
+
+ mpModeHandler = rpHandler;
+}
+
+void SelectionFunction::ResetShiftKeySelectionAnchor()
+{
+ mnShiftKeySelectionAnchor = -1;
+}
+
+void SelectionFunction::ResetMouseAnchor()
+{
+ if (mpModeHandler && mpModeHandler->GetMode() == NormalMode)
+ {
+ std::shared_ptr<NormalModeHandler> pHandler (
+ std::dynamic_pointer_cast<NormalModeHandler>(mpModeHandler));
+ if (pHandler)
+ pHandler->ResetButtonDownLocation();
+ }
+}
+
+//===== EventDescriptor =======================================================
+
+SelectionFunction::EventDescriptor::EventDescriptor (
+ const sal_uInt32 nEventType,
+ const MouseEvent& rEvent,
+ SlideSorter const & rSlideSorter)
+ : maMousePosition(rEvent.GetPosPixel()),
+ mpHitPage(),
+ mnEventCode(nEventType),
+ meDragMode(InsertionIndicatorHandler::MoveMode),
+ mbIsLeaving(false)
+{
+ maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition);
+ mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition);
+ if (mpHitDescriptor)
+ {
+ mpHitPage = mpHitDescriptor->GetPage();
+ }
+
+ mnEventCode |= EncodeMouseEvent(rEvent);
+ mnEventCode |= EncodeState();
+
+ // Detect the mouse leaving the window. When not button is pressed then
+ // we can call IsLeaveWindow at the event. Otherwise we have to make an
+ // explicit test.
+ mbIsLeaving = rEvent.IsLeaveWindow()
+ || ! ::tools::Rectangle(Point(0,0),
+ rSlideSorter.GetContentWindow()->GetOutputSizePixel()).Contains(maMousePosition);
+}
+
+SelectionFunction::EventDescriptor::EventDescriptor (
+ const sal_uInt32 nEventType,
+ const AcceptDropEvent& rEvent,
+ const sal_Int8 nDragAction,
+ SlideSorter const & rSlideSorter)
+ : maMousePosition(rEvent.maPosPixel),
+ mpHitPage(),
+ mnEventCode(nEventType),
+ meDragMode(InsertionIndicatorHandler::GetModeFromDndAction(nDragAction)),
+ mbIsLeaving(false)
+{
+ maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition);
+ mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition);
+ if (mpHitDescriptor)
+ {
+ mpHitPage = mpHitDescriptor->GetPage();
+ }
+
+ mnEventCode |= EncodeState();
+
+ // Detect the mouse leaving the window. When not button is pressed then
+ // we can call IsLeaveWindow at the event. Otherwise we have to make an
+ // explicit test.
+ mbIsLeaving = rEvent.mbLeaving
+ || ! ::tools::Rectangle(Point(0,0),
+ rSlideSorter.GetContentWindow()->GetOutputSizePixel()).Contains(maMousePosition);
+}
+
+sal_uInt32 SelectionFunction::EventDescriptor::EncodeMouseEvent (
+ const MouseEvent& rEvent) const
+{
+ // Initialize with the type of mouse event.
+ sal_uInt32 nEventCode (mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION));
+
+ // Detect the affected button.
+ switch (rEvent.GetButtons())
+ {
+ case MOUSE_LEFT: nEventCode |= LEFT_BUTTON; break;
+ case MOUSE_RIGHT: nEventCode |= RIGHT_BUTTON; break;
+ case MOUSE_MIDDLE: nEventCode |= MIDDLE_BUTTON; break;
+ }
+
+ // Detect the number of clicks.
+ switch (rEvent.GetClicks())
+ {
+ case 1: nEventCode |= SINGLE_CLICK; break;
+ case 2: nEventCode |= DOUBLE_CLICK; break;
+ }
+
+ // Detect pressed modifier keys.
+ if (rEvent.IsShift())
+ nEventCode |= SHIFT_MODIFIER;
+ if (rEvent.IsMod1())
+ nEventCode |= CONTROL_MODIFIER;
+
+ return nEventCode;
+}
+
+sal_uInt32 SelectionFunction::EventDescriptor::EncodeState() const
+{
+ sal_uInt32 nEventCode (0);
+
+ // Detect whether the event has happened over a page object.
+ if (mpHitPage!=nullptr && mpHitDescriptor)
+ {
+ if (mpHitDescriptor->HasState(model::PageDescriptor::ST_Selected))
+ nEventCode |= OVER_SELECTED_PAGE;
+ else
+ nEventCode |= OVER_UNSELECTED_PAGE;
+ }
+
+ return nEventCode;
+}
+
+//===== SelectionFunction::ModeHandler ========================================
+
+SelectionFunction::ModeHandler::ModeHandler (
+ SlideSorter& rSlideSorter,
+ SelectionFunction& rSelectionFunction,
+ const bool bIsMouseOverIndicatorAllowed)
+ : mrSlideSorter(rSlideSorter),
+ mrSelectionFunction(rSelectionFunction),
+ mbIsMouseOverIndicatorAllowed(bIsMouseOverIndicatorAllowed)
+{
+}
+
+SelectionFunction::ModeHandler::~ModeHandler() COVERITY_NOEXCEPT_FALSE
+{
+}
+
+void SelectionFunction::ModeHandler::ReprocessEvent (EventDescriptor& rDescriptor)
+{
+ mrSelectionFunction.ProcessEvent(rDescriptor);
+}
+
+void SelectionFunction::ModeHandler::ProcessEvent (
+ SelectionFunction::EventDescriptor& rDescriptor)
+{
+ PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter);
+ PageSelector::UpdateLock aUpdateLock (mrSlideSorter);
+
+ bool bIsProcessed (false);
+ switch (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION | MOUSE_DRAG))
+ {
+ case BUTTON_DOWN:
+ bIsProcessed = ProcessButtonDownEvent(rDescriptor);
+ break;
+
+ case BUTTON_UP:
+ bIsProcessed = ProcessButtonUpEvent(rDescriptor);
+ break;
+
+ case MOUSE_MOTION:
+ bIsProcessed = ProcessMotionEvent(rDescriptor);
+ break;
+
+ case MOUSE_DRAG:
+ bIsProcessed = ProcessDragEvent(rDescriptor);
+ break;
+ }
+
+ if ( ! bIsProcessed)
+ HandleUnprocessedEvent(rDescriptor);
+}
+
+bool SelectionFunction::ModeHandler::ProcessButtonDownEvent (EventDescriptor&)
+{
+ return false;
+}
+
+bool SelectionFunction::ModeHandler::ProcessButtonUpEvent (EventDescriptor&)
+{
+ mrSelectionFunction.SwitchToNormalMode();
+ return false;
+}
+
+bool SelectionFunction::ModeHandler::ProcessMotionEvent (EventDescriptor& rDescriptor)
+{
+ if (mbIsMouseOverIndicatorAllowed)
+ mrSlideSorter.GetView().UpdatePageUnderMouse(rDescriptor.maMousePosition);
+
+ if (rDescriptor.mbIsLeaving)
+ {
+ mrSelectionFunction.SwitchToNormalMode();
+ mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor());
+
+ return true;
+ }
+ else
+ return false;
+}
+
+bool SelectionFunction::ModeHandler::ProcessDragEvent (EventDescriptor&)
+{
+ return false;
+}
+
+bool SelectionFunction::ModeHandler::HandleUnprocessedEvent (EventDescriptor&)
+{
+ return false;
+}
+
+void SelectionFunction::ModeHandler::SetCurrentPage (
+ const model::SharedPageDescriptor& rpDescriptor)
+{
+ SelectOnePage(rpDescriptor);
+ mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor);
+}
+
+void SelectionFunction::ModeHandler::DeselectAllPages()
+{
+ mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
+ mrSelectionFunction.ResetShiftKeySelectionAnchor();
+}
+
+void SelectionFunction::ModeHandler::SelectOnePage (
+ const model::SharedPageDescriptor& rpDescriptor)
+{
+ DeselectAllPages();
+ mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
+}
+
+void SelectionFunction::ModeHandler::SwitchView (const model::SharedPageDescriptor& rpDescriptor)
+{
+ // Switch to the draw view. This is done only when the current
+ // view is the main view.
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (pViewShell==nullptr || !pViewShell->IsMainViewShell())
+ return;
+
+ if (rpDescriptor && rpDescriptor->GetPage()!=nullptr)
+ {
+ mrSlideSorter.GetModel().GetDocument()->SetSelected(rpDescriptor->GetPage(), true);
+ pViewShell->GetFrameView()->SetSelectedPage(
+ (rpDescriptor->GetPage()->GetPageNum()-1)/2);
+ }
+ if (mrSlideSorter.GetViewShellBase() != nullptr)
+ framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView(
+ framework::FrameworkHelper::msImpressViewURL,
+ framework::FrameworkHelper::msCenterPaneURL);
+}
+
+void SelectionFunction::ModeHandler::StartDrag (
+ const Point& rMousePosition)
+{
+ // Do not start a drag-and-drop operation when one is already active.
+ // (when dragging pages from one document into another, pressing a
+ // modifier key can trigger a MouseMotion event in the originating
+ // window (focus still in there). Together with the mouse button pressed
+ // (drag-and-drop is active) this triggers the start of drag-and-drop.)
+ if (SD_MOD()->pTransferDrag != nullptr)
+ return;
+
+ if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
+ {
+ mrSelectionFunction.SwitchToDragAndDropMode(rMousePosition);
+ }
+}
+
+//===== NormalModeHandler =====================================================
+
+NormalModeHandler::NormalModeHandler (
+ SlideSorter& rSlideSorter,
+ SelectionFunction& rSelectionFunction)
+ : ModeHandler(rSlideSorter, rSelectionFunction, true)
+{
+}
+
+SelectionFunction::Mode NormalModeHandler::GetMode() const
+{
+ return SelectionFunction::NormalMode;
+}
+
+void NormalModeHandler::Abort()
+{
+}
+
+bool NormalModeHandler::ProcessButtonDownEvent (
+ SelectionFunction::EventDescriptor& rDescriptor)
+{
+ // Remember the location where the left button is pressed. With
+ // that we can filter away motion events that are caused by key
+ // presses. We also can tune the minimal motion distance that
+ // triggers a drag-and-drop operation.
+ if ((rDescriptor.mnEventCode & BUTTON_DOWN) != 0)
+ maButtonDownLocation = rDescriptor.maMousePosition;
+
+ switch (rDescriptor.mnEventCode)
+ {
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
+ SetCurrentPage(rDescriptor.mpHitDescriptor);
+ break;
+
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
+ break;
+
+ case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_SELECTED_PAGE:
+ case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_UNSELECTED_PAGE:
+ // A double click always shows the selected slide in the center
+ // pane in an edit view.
+ SetCurrentPage(rDescriptor.mpHitDescriptor);
+ SwitchView(rDescriptor.mpHitDescriptor);
+ break;
+
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER:
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER:
+ // Range selection with the shift modifier.
+ RangeSelect(rDescriptor.mpHitDescriptor);
+ break;
+
+ // Right button for context menu.
+ case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
+ // Single right click and shift+F10 select as preparation to
+ // show the context menu. Change the selection only when the
+ // page under the mouse is not selected. In this case the
+ // selection is set to this single page. Otherwise the
+ // selection is not modified.
+ SetCurrentPage(rDescriptor.mpHitDescriptor);
+ break;
+
+ case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
+ // Do not change the selection. Just adjust the insertion indicator.
+ break;
+
+ case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE:
+ // Remember the current selection so that when a multi selection
+ // is started, we can restore the previous selection.
+ mrSlideSorter.GetModel().SaveCurrentSelection();
+ DeselectAllPages();
+ break;
+
+ case ANY_MODIFIER(BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE):
+ // Remember the current selection so that when a multi selection
+ // is started, we can restore the previous selection.
+ mrSlideSorter.GetModel().SaveCurrentSelection();
+ DeselectAllPages();
+ break;
+
+ case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | NOT_OVER_PAGE:
+ {
+ // Insert a new slide:
+ // First of all we need to set the insertion indicator which sets the
+ // position where the new slide will be inserted.
+ std::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler
+ = mrSlideSorter.GetController().GetInsertionIndicatorHandler();
+
+ pInsertionIndicatorHandler->Start(false);
+ pInsertionIndicatorHandler->UpdatePosition(
+ rDescriptor.maMousePosition,
+ InsertionIndicatorHandler::MoveMode);
+
+ mrSlideSorter.GetController().GetSelectionManager()->SetInsertionPosition(
+ pInsertionIndicatorHandler->GetInsertionPageIndex());
+
+ mrSlideSorter.GetViewShell()->GetDispatcher()->Execute(
+ SID_INSERTPAGE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+
+ pInsertionIndicatorHandler->End(Animator::AM_Immediate);
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool NormalModeHandler::ProcessButtonUpEvent (
+ SelectionFunction::EventDescriptor& rDescriptor)
+{
+ bool bIsProcessed (true);
+ switch (rDescriptor.mnEventCode)
+ {
+ case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
+ SetCurrentPage(rDescriptor.mpHitDescriptor);
+ break;
+
+ // Multi selection with the control modifier.
+ case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER:
+ mrSlideSorter.GetController().GetPageSelector().DeselectPage(
+ rDescriptor.mpHitDescriptor);
+ break;
+
+ case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER:
+ mrSlideSorter.GetController().GetPageSelector().SelectPage(
+ rDescriptor.mpHitDescriptor);
+ mrSlideSorter.GetView().SetPageUnderMouse(rDescriptor.mpHitDescriptor);
+ break;
+ case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE:
+ break;
+
+ default:
+ bIsProcessed = false;
+ break;
+ }
+ mrSelectionFunction.SwitchToNormalMode();
+ return bIsProcessed;
+}
+
+bool NormalModeHandler::ProcessMotionEvent (
+ SelectionFunction::EventDescriptor& rDescriptor)
+{
+ if (ModeHandler::ProcessMotionEvent(rDescriptor))
+ return true;
+
+ bool bIsProcessed (true);
+ switch (rDescriptor.mnEventCode)
+ {
+ // A mouse motion without visible substitution starts that.
+ case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE):
+ case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE):
+ {
+ if (maButtonDownLocation)
+ {
+ const sal_Int32 nDistance(std::max(
+ std::abs(maButtonDownLocation->X() - rDescriptor.maMousePosition.X()),
+ std::abs(maButtonDownLocation->Y() - rDescriptor.maMousePosition.Y())));
+ if (nDistance > 3)
+ StartDrag(rDescriptor.maMousePosition);
+ }
+ break;
+ }
+
+ // A mouse motion not over a page starts a rectangle selection.
+ case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE):
+ mrSelectionFunction.SwitchToMultiSelectionMode(
+ rDescriptor.maMouseModelPosition,
+ rDescriptor.mnEventCode);
+ break;
+
+ default:
+ bIsProcessed = false;
+ break;
+ }
+ return bIsProcessed;
+}
+
+bool NormalModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor)
+{
+ mrSelectionFunction.SwitchToDragAndDropMode(rDescriptor.maMousePosition);
+ ReprocessEvent(rDescriptor);
+ return true;
+}
+
+void NormalModeHandler::RangeSelect (const model::SharedPageDescriptor& rpDescriptor)
+{
+ PageSelector::UpdateLock aLock (mrSlideSorter);
+ PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector());
+
+ model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor());
+ DeselectAllPages();
+
+ if (!pAnchor)
+ return;
+
+ // Select all pages between the anchor and the given one, including
+ // the two.
+ const sal_uInt16 nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2);
+ const sal_uInt16 nOtherIndex ((rpDescriptor->GetPage()->GetPageNum()-1) / 2);
+
+ // Iterate over all pages in the range. Start with the anchor
+ // page. This way the PageSelector will recognize it again as
+ // anchor (the first selected page after a DeselectAllPages()
+ // becomes the anchor.)
+ const sal_uInt16 nStep ((nAnchorIndex < nOtherIndex) ? +1 : -1);
+ sal_uInt16 nIndex (nAnchorIndex);
+ while (true)
+ {
+ rSelector.SelectPage(nIndex);
+ if (nIndex == nOtherIndex)
+ break;
+ nIndex = nIndex + nStep;
+ }
+}
+
+void NormalModeHandler::ResetButtonDownLocation()
+{
+ maButtonDownLocation = ::std::optional<Point>();
+}
+
+//===== MultiSelectionModeHandler =============================================
+
+MultiSelectionModeHandler::MultiSelectionModeHandler (
+ SlideSorter& rSlideSorter,
+ SelectionFunction& rSelectionFunction,
+ const Point& rMouseModelPosition,
+ const sal_uInt32 nEventCode)
+ : ModeHandler(rSlideSorter, rSelectionFunction, false),
+ meSelectionMode(SM_Normal),
+ maSecondCorner(rMouseModelPosition),
+ maSavedPointer(mrSlideSorter.GetContentWindow()->GetPointer()),
+ mbAutoScrollInstalled(false),
+ mnAnchorIndex(-1),
+ mnSecondIndex(-1)
+{
+
+ mrSlideSorter.GetContentWindow()->SetPointer(PointerStyle::Text);
+ SetSelectionModeFromModifier(nEventCode);
+}
+
+MultiSelectionModeHandler::~MultiSelectionModeHandler()
+{
+ if (mbAutoScrollInstalled)
+ {
+ //a call to this handler's MultiSelectionModeHandler::UpdatePosition
+ //may be still waiting to be called back
+ mrSlideSorter.GetController().GetScrollBarManager().clearAutoScrollFunctor();
+ }
+ mrSlideSorter.GetContentWindow()->SetPointer(maSavedPointer);
+}
+
+SelectionFunction::Mode MultiSelectionModeHandler::GetMode() const
+{
+ return SelectionFunction::MultiSelectionMode;
+}
+
+void MultiSelectionModeHandler::Abort()
+{
+ mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection());
+}
+
+void MultiSelectionModeHandler::ProcessEvent (
+ SelectionFunction::EventDescriptor& rDescriptor)
+{
+ // During a multi selection we do not want sudden jumps of the
+ // visible area caused by moving newly selected pages into view.
+ // Therefore disable that temporarily. The disabled object is
+ // released at the end of the event processing, after the focus and
+ // current slide have been updated.
+ VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
+
+ ModeHandler::ProcessEvent(rDescriptor);
+}
+
+bool MultiSelectionModeHandler::ProcessButtonUpEvent (
+ SelectionFunction::EventDescriptor& rDescriptor)
+{
+ if (mbAutoScrollInstalled)
+ {
+ //a call to this handler's MultiSelectionModeHandler::UpdatePosition
+ //may be still waiting to be called back
+ mrSlideSorter.GetController().GetScrollBarManager().clearAutoScrollFunctor();
+ mbAutoScrollInstalled = false;
+ }
+
+ if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK))
+ {
+ mrSelectionFunction.SwitchToNormalMode();
+ return true;
+ }
+ else
+ return false;
+}
+
+bool MultiSelectionModeHandler::ProcessMotionEvent (
+ SelectionFunction::EventDescriptor& rDescriptor)
+{
+ // The selection rectangle is visible. Handle events accordingly.
+ if (Match(rDescriptor.mnEventCode, MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK))
+ {
+ SetSelectionModeFromModifier(rDescriptor.mnEventCode);
+ UpdatePosition(rDescriptor.maMousePosition, true);
+ return true;
+ }
+ else
+ return false;
+}
+
+bool MultiSelectionModeHandler::HandleUnprocessedEvent (
+ SelectionFunction::EventDescriptor& rDescriptor)
+{
+ if ( ! ModeHandler::HandleUnprocessedEvent(rDescriptor))
+ {
+ // If the event has not been processed then stop multi selection.
+ mrSelectionFunction.SwitchToNormalMode();
+ ReprocessEvent(rDescriptor);
+ }
+ return true;
+}
+
+void MultiSelectionModeHandler::UpdatePosition (
+ const Point& rMousePosition,
+ const bool bAllowAutoScroll)
+{
+ VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
+
+ // Convert window coordinates into model coordinates (we need the
+ // window coordinates for auto-scrolling because that remains
+ // constant while scrolling.)
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition));
+
+ bool bDoAutoScroll = bAllowAutoScroll && mrSlideSorter.GetController().GetScrollBarManager().AutoScroll(
+ rMousePosition,
+ [this, &rMousePosition] () { return this->UpdatePosition(rMousePosition, false); });
+
+ if (!bDoAutoScroll)
+ UpdateModelPosition(aMouseModelPosition);
+
+ mbAutoScrollInstalled |= bDoAutoScroll;
+}
+
+void MultiSelectionModeHandler::SetSelectionModeFromModifier (
+ const sal_uInt32 nEventCode)
+{
+ switch (nEventCode & MODIFIER_MASK)
+ {
+ case NO_MODIFIER:
+ SetSelectionMode(SM_Normal);
+ break;
+
+ case SHIFT_MODIFIER:
+ SetSelectionMode(SM_Add);
+ break;
+
+ case CONTROL_MODIFIER:
+ SetSelectionMode(SM_Toggle);
+ break;
+ }
+}
+
+void MultiSelectionModeHandler::SetSelectionMode (const SelectionMode eSelectionMode)
+{
+ if (meSelectionMode != eSelectionMode)
+ {
+ meSelectionMode = eSelectionMode;
+ UpdateSelection();
+ }
+}
+
+void MultiSelectionModeHandler::UpdateSelectionState (
+ const model::SharedPageDescriptor& rpDescriptor,
+ const bool bIsInSelection) const
+{
+ // Determine whether the page was selected before the rectangle
+ // selection was started.
+ const bool bWasSelected (rpDescriptor->HasState(model::PageDescriptor::ST_WasSelected));
+
+ // Combine the two selection states depending on the selection mode.
+ bool bSelect (false);
+ switch(meSelectionMode)
+ {
+ case SM_Normal:
+ bSelect = bIsInSelection;
+ break;
+
+ case SM_Add:
+ bSelect = bIsInSelection || bWasSelected;
+ break;
+
+ case SM_Toggle:
+ if (bIsInSelection)
+ bSelect = !bWasSelected;
+ else
+ bSelect = bWasSelected;
+ break;
+ }
+
+ // Set the new selection state.
+ if (bSelect)
+ mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
+ else
+ mrSlideSorter.GetController().GetPageSelector().DeselectPage(rpDescriptor);
+}
+
+void MultiSelectionModeHandler::UpdateModelPosition (const Point& rMouseModelPosition)
+{
+ maSecondCorner = rMouseModelPosition;
+ UpdateSelection();
+}
+
+void MultiSelectionModeHandler::UpdateSelection()
+{
+ view::SlideSorterView::DrawLock aLock (mrSlideSorter);
+
+ model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
+ const sal_Int32 nPageCount (rModel.GetPageCount());
+
+ const sal_Int32 nIndexUnderMouse (
+ mrSlideSorter.GetView().GetLayouter().GetIndexAtPoint (
+ maSecondCorner,
+ false,
+ false));
+ if (nIndexUnderMouse < 0 || nIndexUnderMouse >= nPageCount)
+ return;
+
+ if (mnAnchorIndex < 0)
+ mnAnchorIndex = nIndexUnderMouse;
+ mnSecondIndex = nIndexUnderMouse;
+
+ Range aRange (mnAnchorIndex, mnSecondIndex);
+ aRange.Justify();
+
+ for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex)
+ {
+ UpdateSelectionState(rModel.GetPageDescriptor(nIndex), aRange.Contains(nIndex));
+ }
+}
+
+//===== DragAndDropModeHandler ================================================
+
+DragAndDropModeHandler::DragAndDropModeHandler (
+ SlideSorter& rSlideSorter,
+ SelectionFunction& rSelectionFunction,
+ const Point& rMousePosition,
+ vcl::Window* pWindow)
+ : ModeHandler(rSlideSorter, rSelectionFunction, false)
+{
+ SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
+ if (pDragTransferable==nullptr && mrSlideSorter.GetViewShell() != nullptr)
+ {
+ SlideSorterViewShell* pSlideSorterViewShell
+ = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
+ if (pSlideSorterViewShell != nullptr)
+ pSlideSorterViewShell->StartDrag(rMousePosition, pWindow);
+ pDragTransferable = SD_MOD()->pTransferDrag;
+ }
+
+ mpDragAndDropContext.reset(new DragAndDropContext(mrSlideSorter));
+ mrSlideSorter.GetController().GetInsertionIndicatorHandler()->Start(
+ pDragTransferable != nullptr
+ && pDragTransferable->GetView()==&mrSlideSorter.GetView());
+}
+
+DragAndDropModeHandler::~DragAndDropModeHandler()
+{
+ if (mpDragAndDropContext)
+ {
+ // Disconnect the substitution handler from this selection function.
+ mpDragAndDropContext->SetTargetSlideSorter();
+ mpDragAndDropContext.reset();
+ }
+ mrSlideSorter.GetController().GetInsertionIndicatorHandler()->End(Animator::AM_Animated);
+}
+
+SelectionFunction::Mode DragAndDropModeHandler::GetMode() const
+{
+ return SelectionFunction::DragAndDropMode;
+}
+
+void DragAndDropModeHandler::Abort()
+{
+ mrSlideSorter.GetController().GetClipboard().Abort();
+ if (mpDragAndDropContext)
+ mpDragAndDropContext->Dispose();
+ // mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection());
+}
+
+bool DragAndDropModeHandler::ProcessButtonUpEvent (
+ SelectionFunction::EventDescriptor& rDescriptor)
+{
+ if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON))
+ {
+ // The following Process() call may lead to the destruction
+ // of rDescriptor.mpHitDescriptor so release our reference to it.
+ rDescriptor.mpHitDescriptor.reset();
+ mrSelectionFunction.SwitchToNormalMode();
+ return true;
+ }
+ else
+ return false;
+}
+
+bool DragAndDropModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor)
+{
+ OSL_ASSERT(mpDragAndDropContext);
+
+ if (rDescriptor.mbIsLeaving)
+ {
+ mrSelectionFunction.SwitchToNormalMode();
+ }
+ else if (mpDragAndDropContext)
+ {
+ mpDragAndDropContext->UpdatePosition(
+ rDescriptor.maMousePosition,
+ rDescriptor.meDragMode, true);
+ }
+
+ return true;
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx
new file mode 100644
index 000000000..e1f75b21c
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <controller/SlsSelectionManager.hxx>
+
+#include <SlideSorter.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <controller/SlsFocusManager.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsSelectionObserver.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <view/SlideSorterView.hxx>
+#include <tools/diagnose_ex.h>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <drawview.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <svx/svxids.hrc>
+#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+
+
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <app.hrc>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::uno;
+using namespace ::sd::slidesorter::model;
+using namespace ::sd::slidesorter::view;
+using namespace ::sd::slidesorter::controller;
+
+namespace sd::slidesorter::controller {
+
+SelectionManager::SelectionManager (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mrController(rSlideSorter.GetController()),
+ mnInsertionPosition(-1),
+ mpSelectionObserver(std::make_shared<SelectionObserver>(rSlideSorter))
+{
+}
+
+SelectionManager::~SelectionManager()
+{
+}
+
+void SelectionManager::DeleteSelectedPages (const bool bSelectFollowingPage)
+{
+ // Create some locks to prevent updates of the model, view, selection
+ // state while modifying any of them.
+ SlideSorterController::ModelChangeLock aLock (mrController);
+ SlideSorterView::DrawLock aDrawLock (mrSlideSorter);
+ PageSelector::UpdateLock aSelectionLock (mrSlideSorter);
+
+ // Hide focus.
+ bool bIsFocusShowing = mrController.GetFocusManager().IsFocusShowing();
+ if (bIsFocusShowing)
+ mrController.GetFocusManager().ToggleFocus();
+
+ // Store pointers to all selected page descriptors. This is necessary
+ // because the pages get deselected when the first one is deleted.
+ model::PageEnumeration aPageEnumeration (
+ PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel()));
+ ::std::vector<SdPage*> aSelectedPages;
+ sal_Int32 nNewCurrentSlide (-1);
+ while (aPageEnumeration.HasMoreElements())
+ {
+ SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement());
+ aSelectedPages.push_back(pDescriptor->GetPage());
+ if (bSelectFollowingPage || nNewCurrentSlide<0)
+ nNewCurrentSlide = pDescriptor->GetPageIndex();
+ }
+ if (aSelectedPages.empty())
+ return;
+
+ // Determine the slide to select (and thereby make the current slide)
+ // after the deletion.
+ if (bSelectFollowingPage)
+ nNewCurrentSlide -= aSelectedPages.size() - 1;
+ else
+ --nNewCurrentSlide;
+
+ const auto pViewShell = mrSlideSorter.GetViewShell();
+ const auto pDrawViewShell = pViewShell ? std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell->GetViewShellBase().GetMainViewShell()) : nullptr;
+ const auto pDrawView = pDrawViewShell ? pDrawViewShell->GetDrawView() : nullptr;
+
+ if (pDrawView)
+ pDrawView->BlockPageOrderChangedHint(true);
+
+ // Proper naming for the undo action
+ OUString sUndoComment(SdResId(STR_UNDO_DELETEPAGES));
+ if (mrSlideSorter.GetView().GetDoc().GetDocumentType() == DocumentType::Draw)
+ sUndoComment = SdResId(STR_UNDO_DELETEPAGES_DRAW);
+
+ // The actual deletion of the selected pages is done in one of two
+ // helper functions. They are specialized for normal respectively for
+ // master pages.
+ mrSlideSorter.GetView().BegUndo (sUndoComment);
+ if (mrSlideSorter.GetModel().GetEditMode() == EditMode::Page)
+ DeleteSelectedNormalPages(aSelectedPages);
+ else
+ DeleteSelectedMasterPages(aSelectedPages);
+ mrSlideSorter.GetView().EndUndo ();
+
+ mrController.HandleModelChange();
+ aLock.Release();
+ if (pDrawView)
+ {
+ assert(pDrawViewShell);
+ pDrawView->BlockPageOrderChangedHint(false);
+ pDrawViewShell->ResetActualPage();
+ }
+
+ // Show focus and move it to next valid location.
+ if (bIsFocusShowing)
+ mrController.GetFocusManager().ToggleFocus();
+
+ // Set the new current slide.
+ if (nNewCurrentSlide < 0)
+ nNewCurrentSlide = 0;
+ else if (nNewCurrentSlide >= mrSlideSorter.GetModel().GetPageCount())
+ nNewCurrentSlide = mrSlideSorter.GetModel().GetPageCount()-1;
+ mrController.GetPageSelector().CountSelectedPages();
+ mrController.GetPageSelector().SelectPage(nNewCurrentSlide);
+ mrController.GetFocusManager().SetFocusedPage(nNewCurrentSlide);
+}
+
+void SelectionManager::DeleteSelectedNormalPages (const ::std::vector<SdPage*>& rSelectedPages)
+{
+ // Prepare the deletion via the UNO API.
+ OSL_ASSERT(mrSlideSorter.GetModel().GetEditMode() == EditMode::Page);
+
+ try
+ {
+ Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier( mrSlideSorter.GetModel().GetDocument()->getUnoModel(), UNO_QUERY_THROW );
+ Reference<drawing::XDrawPages> xPages( xDrawPagesSupplier->getDrawPages(), UNO_SET_THROW );
+
+ // Iterate over all pages that were selected when this method was called
+ // and delete the draw page the notes page. The iteration is done in
+ // reverse order so that when one slide is not deleted (to avoid an
+ // empty document) the remaining slide is the first one.
+ ::std::vector<SdPage*>::const_reverse_iterator aI;
+ for (aI=rSelectedPages.rbegin(); aI!=rSelectedPages.rend(); ++aI)
+ {
+ // Do not delete the last slide in the document.
+ if (xPages->getCount() <= 1)
+ break;
+
+ const sal_uInt16 nPage (model::FromCoreIndex((*aI)->GetPageNum()));
+
+ Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW );
+ xPages->remove(xPage);
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "SelectionManager::DeleteSelectedNormalPages()");
+ }
+}
+
+void SelectionManager::DeleteSelectedMasterPages (const ::std::vector<SdPage*>& rSelectedPages)
+{
+ // Prepare the deletion via the UNO API.
+ OSL_ASSERT(mrSlideSorter.GetModel().GetEditMode() == EditMode::MasterPage);
+
+ try
+ {
+ Reference<drawing::XMasterPagesSupplier> xDrawPagesSupplier( mrSlideSorter.GetModel().GetDocument()->getUnoModel(), UNO_QUERY_THROW );
+ Reference<drawing::XDrawPages> xPages( xDrawPagesSupplier->getMasterPages(), UNO_SET_THROW );
+
+ // Iterate over all pages that were selected when this method was called
+ // and delete the draw page the notes page. The iteration is done in
+ // reverse order so that when one slide is not deleted (to avoid an
+ // empty document) the remaining slide is the first one.
+ ::std::vector<SdPage*>::const_reverse_iterator aI;
+ for (aI=rSelectedPages.rbegin(); aI!=rSelectedPages.rend(); ++aI)
+ {
+ // Do not delete the last slide in the document.
+ if (xPages->getCount() <= 1)
+ break;
+
+ const sal_uInt16 nPage (model::FromCoreIndex((*aI)->GetPageNum()));
+
+ Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW );
+ xPages->remove(xPage);
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "SelectionManager::DeleteSelectedMasterPages()");
+ }
+}
+
+void SelectionManager::SelectionHasChanged ()
+{
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (pViewShell == nullptr)
+ return;
+
+ pViewShell->Invalidate (SID_EXPAND_PAGE);
+ pViewShell->Invalidate (SID_SUMMARY_PAGE);
+ pViewShell->Invalidate(SID_SHOW_SLIDE);
+ pViewShell->Invalidate(SID_HIDE_SLIDE);
+ pViewShell->Invalidate(SID_DELETE_PAGE);
+ pViewShell->Invalidate(SID_DELETE_MASTER_PAGE);
+ pViewShell->Invalidate(SID_ASSIGN_LAYOUT);
+
+ // StatusBar
+ pViewShell->Invalidate (SID_STATUS_PAGE);
+ pViewShell->Invalidate (SID_STATUS_LAYOUT);
+ pViewShell->Invalidate (SID_SCALE);
+
+ OSL_ASSERT(mrController.GetCurrentSlideManager());
+ SharedPageDescriptor pDescriptor(mrController.GetCurrentSlideManager()->GetCurrentSlide());
+ if (pDescriptor)
+ pViewShell->UpdatePreview(pDescriptor->GetPage());
+
+ // Tell the selection change listeners that the selection has changed.
+ for (const auto& rLink : maSelectionChangeListeners)
+ {
+ rLink.Call(nullptr);
+ }
+
+ // Reset the insertion position: until set again it is calculated from
+ // the current selection.
+ mnInsertionPosition = -1;
+}
+
+void SelectionManager::AddSelectionChangeListener (const Link<LinkParamNone*,void>& rListener)
+{
+ if (::std::find (
+ maSelectionChangeListeners.begin(),
+ maSelectionChangeListeners.end(),
+ rListener) == maSelectionChangeListeners.end())
+ {
+ maSelectionChangeListeners.push_back (rListener);
+ }
+}
+
+void SelectionManager::RemoveSelectionChangeListener(const Link<LinkParamNone*,void>& rListener)
+{
+ maSelectionChangeListeners.erase (
+ ::std::find (
+ maSelectionChangeListeners.begin(),
+ maSelectionChangeListeners.end(),
+ rListener));
+}
+
+sal_Int32 SelectionManager::GetInsertionPosition() const
+{
+ sal_Int32 nInsertionPosition (mnInsertionPosition);
+ if (nInsertionPosition < 0)
+ {
+ model::PageEnumeration aSelectedPages
+ (model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ // Initialize (for the case of an empty selection) with the position
+ // at the end of the document.
+ nInsertionPosition = mrSlideSorter.GetModel().GetPageCount();
+ while (aSelectedPages.HasMoreElements())
+ {
+ const sal_Int32 nPosition (aSelectedPages.GetNextElement()->GetPage()->GetPageNum());
+ // Convert *2+1 index to straight index (n-1)/2 after the page
+ // (+1).
+ nInsertionPosition = model::FromCoreIndex(nPosition) + 1;
+ }
+
+ }
+ return nInsertionPosition;
+}
+
+void SelectionManager::SetInsertionPosition (const sal_Int32 nInsertionPosition)
+{
+ if (nInsertionPosition < 0)
+ mnInsertionPosition = -1;
+ else if (nInsertionPosition > mrSlideSorter.GetModel().GetPageCount())
+ {
+ // Assert but then ignore invalid values.
+ OSL_ASSERT(nInsertionPosition<=mrSlideSorter.GetModel().GetPageCount());
+ return;
+ }
+ else
+ mnInsertionPosition = nInsertionPosition;
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx
new file mode 100644
index 000000000..8fb0493a0
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <SlideSorter.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsSelectionManager.hxx>
+#include <controller/SlsSelectionObserver.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsFocusManager.hxx>
+#include <sdpage.hxx>
+#include <osl/diagnose.h>
+
+namespace sd::slidesorter::controller
+{
+SelectionObserver::Context::Context(SlideSorter const& rSlideSorter)
+ : mpSelectionObserver(
+ rSlideSorter.GetController().GetSelectionManager()->GetSelectionObserver())
+{
+ if (mpSelectionObserver)
+ mpSelectionObserver->StartObservation();
+}
+
+SelectionObserver::Context::~Context() COVERITY_NOEXCEPT_FALSE
+{
+ if (mpSelectionObserver)
+ mpSelectionObserver->EndObservation();
+}
+
+void SelectionObserver::Context::Abort()
+{
+ if (mpSelectionObserver)
+ {
+ mpSelectionObserver->AbortObservation();
+ mpSelectionObserver.reset();
+ }
+}
+
+//===== SelectionObserver =====================================================
+
+SelectionObserver::SelectionObserver(SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter)
+ , mbIsObservationActive(false)
+ , mbPageEventOccurred(false)
+{
+}
+
+SelectionObserver::~SelectionObserver() {}
+
+void SelectionObserver::NotifyPageEvent(const SdrPage* pSdrPage)
+{
+ if (!mbIsObservationActive)
+ return;
+
+ mbPageEventOccurred = true;
+
+ const SdPage* pPage = dynamic_cast<const SdPage*>(pSdrPage);
+ if (pPage == nullptr)
+ return;
+
+ //NotifyPageEvent is called for add, remove, *and* change position so for
+ //the change position case we must ensure we don't end up with the slide
+ //duplicated in our list
+ std::vector<const SdPage*>::iterator iPage(
+ std::find(maInsertedPages.begin(), maInsertedPages.end(), pPage));
+ if (iPage != maInsertedPages.end())
+ maInsertedPages.erase(iPage);
+
+ if (pPage->IsInserted())
+ maInsertedPages.push_back(pPage);
+}
+
+void SelectionObserver::StartObservation()
+{
+ OSL_ASSERT(!mbIsObservationActive);
+ maInsertedPages.clear();
+ mbIsObservationActive = true;
+}
+
+void SelectionObserver::AbortObservation()
+{
+ OSL_ASSERT(mbIsObservationActive);
+ mbIsObservationActive = false;
+ maInsertedPages.clear();
+}
+
+void SelectionObserver::EndObservation()
+{
+ OSL_ASSERT(mbIsObservationActive);
+ mbIsObservationActive = false;
+
+ if (!mbPageEventOccurred)
+ return;
+
+ PageSelector& rSelector(mrSlideSorter.GetController().GetPageSelector());
+ PageSelector::UpdateLock aUpdateLock(mrSlideSorter);
+ rSelector.DeselectAllPages();
+ if (!maInsertedPages.empty())
+ {
+ // Select the inserted pages.
+ for (const auto& rpPage : maInsertedPages)
+ {
+ rSelector.SelectPage(rpPage);
+ }
+ maInsertedPages.clear();
+ }
+
+ aUpdateLock.Release();
+ FocusManager& rFocusManager = mrSlideSorter.GetController().GetFocusManager();
+ bool bSuccess = rFocusManager.SetFocusedPageToCurrentPage();
+ // tdf#129346 nothing currently selected, select something, if possible
+ // but (tdf#129346) only if setting focus to current page failed
+ if (rSelector.GetPageCount() && rSelector.GetSelectedPageCount() == 0)
+ {
+ if (bSuccess)
+ rSelector.SelectPage(rFocusManager.GetFocusedPageDescriptor());
+ else
+ rSelector.SelectPage(0);
+ }
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx
new file mode 100644
index 000000000..52e05557e
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx
@@ -0,0 +1,1284 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <controller/SlsSlotManager.hxx>
+#include <SlideSorter.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsClipboard.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <controller/SlsInsertionIndicatorHandler.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsSelectionFunction.hxx>
+#include <controller/SlsSelectionManager.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <Window.hxx>
+#include <fupoor.hxx>
+#include <fucushow.hxx>
+#include <fusldlg.hxx>
+#include <fuexpand.hxx>
+#include <fusumry.hxx>
+#include <slideshow.hxx>
+#include <app.hrc>
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <unokywds.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellImplementation.hxx>
+#include <sdpage.hxx>
+#include <sdxfer.hxx>
+#include <helpids.h>
+#include <unmodpg.hxx>
+#include <DrawViewShell.hxx>
+#include <sdabstdlg.hxx>
+#include <sdmod.hxx>
+
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svxdlg.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/whiter.hxx>
+#include <svl/itempool.hxx>
+#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPages.hpp>
+#include <osl/diagnose.h>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+
+namespace sd::slidesorter::controller {
+
+namespace {
+
+/** The state of a set of slides with respect to being excluded from the
+ slide show.
+*/
+enum SlideExclusionState {UNDEFINED, EXCLUDED, INCLUDED, MIXED};
+
+/** Return for the given set of slides whether they included are
+ excluded from the slide show.
+*/
+SlideExclusionState GetSlideExclusionState (model::PageEnumeration& rPageSet);
+
+} // end of anonymous namespace
+
+
+namespace {
+
+void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& rAction)
+{
+ EventDescription aDescription;
+ aDescription.aID = "impress_win_or_draw_win";
+ aDescription.aParameters = std::move(aParameters);
+ aDescription.aAction = rAction;
+ aDescription.aKeyWord = "ImpressWindowUIObject";
+ aDescription.aParent = "MainWindow";
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+SlotManager::SlotManager (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter)
+{
+}
+
+void SlotManager::FuTemporary (SfxRequest& rRequest)
+{
+ SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
+
+ SlideSorterViewShell* pShell
+ = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
+ if (pShell == nullptr)
+ return;
+
+ switch (rRequest.GetSlot())
+ {
+ case SID_PRESENTATION:
+ case SID_PRESENTATION_CURRENT_SLIDE:
+ case SID_REHEARSE_TIMINGS:
+ slideshowhelp::ShowSlideShow(rRequest, *mrSlideSorter.GetModel().GetDocument());
+ pShell->Cancel();
+ rRequest.Done();
+ break;
+
+ case SID_HIDE_SLIDE:
+ ChangeSlideExclusionState(model::SharedPageDescriptor(), true);
+ break;
+
+ case SID_SHOW_SLIDE:
+ ChangeSlideExclusionState(model::SharedPageDescriptor(), false);
+ break;
+
+ case SID_PAGES_PER_ROW:
+ if (rRequest.GetArgs() != nullptr)
+ {
+ const SfxUInt16Item* pPagesPerRow = rRequest.GetArg<SfxUInt16Item>(SID_PAGES_PER_ROW);
+ if (pPagesPerRow != nullptr)
+ {
+ sal_Int32 nColumnCount = pPagesPerRow->GetValue();
+ // Force the given number of columns by setting
+ // the minimal and maximal number of columns to
+ // the same value.
+ mrSlideSorter.GetView().GetLayouter().SetColumnCount (
+ nColumnCount, nColumnCount);
+ // Force a repaint and re-layout.
+ pShell->ArrangeGUIElements ();
+ // Rearrange the UI-elements controlled by the
+ // controller and force a rearrangement of the
+ // view.
+ mrSlideSorter.GetController().Rearrange(true);
+ }
+ }
+ rRequest.Done();
+ break;
+
+ case SID_SELECTALL:
+ mrSlideSorter.GetController().GetPageSelector().SelectAllPages();
+ rRequest.Done();
+ break;
+
+ case SID_SLIDE_TRANSITIONS_PANEL:
+ {
+ // First make sure that the sidebar is visible
+ pShell->GetViewFrame()->ShowChildWindow(SID_SIDEBAR);
+ ::sfx2::sidebar::Sidebar::ShowPanel(
+ u"SdSlideTransitionPanel",
+ pShell->GetViewFrame()->GetFrame().GetFrameInterface());
+ rRequest.Ignore ();
+ break;
+ }
+
+ case SID_MASTER_SLIDES_PANEL:
+ {
+ // First make sure that the sidebar is visible
+ pShell->GetViewFrame()->ShowChildWindow(SID_SIDEBAR);
+ ::sfx2::sidebar::Sidebar::ShowPanel(
+ u"SdAllMasterPagesPanel",
+ pShell->GetViewFrame()->GetFrame().GetFrameInterface());
+ rRequest.Ignore ();
+ break;
+ }
+
+ case SID_PRESENTATION_DLG:
+ FuSlideShowDlg::Create (
+ pShell,
+ mrSlideSorter.GetContentWindow(),
+ &mrSlideSorter.GetView(),
+ pDocument,
+ rRequest);
+ break;
+
+ case SID_CUSTOMSHOW_DLG:
+ FuCustomShowDlg::Create (
+ pShell,
+ mrSlideSorter.GetContentWindow(),
+ &mrSlideSorter.GetView(),
+ pDocument,
+ rRequest);
+ break;
+
+ case SID_EXPAND_PAGE:
+ FuExpandPage::Create (
+ pShell,
+ mrSlideSorter.GetContentWindow(),
+ &mrSlideSorter.GetView(),
+ pDocument,
+ rRequest);
+ break;
+
+ case SID_SUMMARY_PAGE:
+ FuSummaryPage::Create (
+ pShell,
+ mrSlideSorter.GetContentWindow(),
+ &mrSlideSorter.GetView(),
+ pDocument,
+ rRequest);
+ break;
+
+ case SID_INSERTPAGE:
+ case SID_INSERT_MASTER_PAGE:
+ InsertSlide(rRequest);
+ rRequest.Done();
+ break;
+
+ case SID_DUPLICATE_PAGE:
+ DuplicateSelectedSlides(rRequest);
+ rRequest.Done();
+ break;
+
+ case SID_DELETE_PAGE:
+ case SID_DELETE_MASTER_PAGE:
+ case SID_DELETE: // we need SID_CUT to handle the delete key
+ // (DEL -> accelerator -> SID_CUT).
+ if (mrSlideSorter.GetModel().GetPageCount() > 1)
+ {
+ mrSlideSorter.GetView().EndTextEditAllViews();
+ mrSlideSorter.GetController().GetSelectionManager()->DeleteSelectedPages();
+ }
+
+ rRequest.Done();
+ break;
+
+ case SID_RENAMEPAGE:
+ case SID_RENAME_MASTER_PAGE:
+ RenameSlide (rRequest);
+ rRequest.Done ();
+ break;
+
+ case SID_ASSIGN_LAYOUT:
+ {
+ pShell->mpImpl->AssignLayout( rRequest, PageKind::Standard );
+ rRequest.Done ();
+ }
+ break;
+
+ case SID_PHOTOALBUM:
+ {
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = mrSlideSorter.GetContentWindow();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateSdPhotoAlbumDialog(
+ pWin ? pWin->GetFrameWeld() : nullptr,
+ pDocument));
+ pDlg->Execute();
+ rRequest.Done ();
+ }
+ break;
+
+ case SID_REMOTE_DLG:
+ {
+#ifdef ENABLE_SDREMOTE
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = mrSlideSorter.GetContentWindow();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateRemoteDialog(pWin ? pWin->GetFrameWeld() : nullptr));
+ pDlg->Execute();
+#endif
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void SlotManager::FuPermanent (SfxRequest& rRequest)
+{
+ ViewShell* pShell = mrSlideSorter.GetViewShell();
+ if (pShell == nullptr)
+ return;
+
+ if(pShell->GetCurrentFunction().is())
+ {
+ rtl::Reference<FuPoor> xEmpty;
+ if (pShell->GetOldFunction() == pShell->GetCurrentFunction())
+ pShell->SetOldFunction(xEmpty);
+
+ pShell->GetCurrentFunction()->Deactivate();
+ pShell->SetCurrentFunction(xEmpty);
+ }
+
+ switch(rRequest.GetSlot())
+ {
+ case SID_OBJECT_SELECT:
+ pShell->SetCurrentFunction( SelectionFunction::Create(mrSlideSorter, rRequest) );
+ rRequest.Done();
+ break;
+
+ default:
+ break;
+ }
+
+ if(pShell->GetOldFunction().is())
+ {
+ pShell->GetOldFunction()->Deactivate();
+ rtl::Reference<FuPoor> xEmpty;
+ pShell->SetOldFunction(xEmpty);
+ }
+
+ if(pShell->GetCurrentFunction().is())
+ {
+ pShell->GetCurrentFunction()->Activate();
+ pShell->SetOldFunction(pShell->GetCurrentFunction());
+ }
+
+ //! that's only until ENUM-Slots ?are
+ // Invalidate( SID_OBJECT_SELECT );
+}
+
+void SlotManager::FuSupport (SfxRequest& rRequest)
+{
+ switch (rRequest.GetSlot())
+ {
+ case SID_STYLE_FAMILY:
+ if (rRequest.GetArgs() != nullptr)
+ {
+ SdDrawDocument* pDocument
+ = mrSlideSorter.GetModel().GetDocument();
+ if (pDocument != nullptr)
+ {
+ const SfxPoolItem& rItem (
+ rRequest.GetArgs()->Get(SID_STYLE_FAMILY));
+ pDocument->GetDocSh()->SetStyleFamily(
+ static_cast<SfxStyleFamily>(static_cast<const SfxUInt16Item&>(rItem).GetValue()));
+ }
+ }
+ break;
+
+ case SID_PASTE:
+ {
+ SdTransferable* pTransferClip = SD_MOD()->pTransferClip;
+ if( pTransferClip )
+ {
+ SfxObjectShell* pTransferDocShell = pTransferClip->GetDocShell().get();
+
+ DrawDocShell* pDocShell = dynamic_cast<DrawDocShell*>(pTransferDocShell);
+ if (pDocShell && pDocShell->GetDoc()->GetPageCount() > 1)
+ {
+ mrSlideSorter.GetController().GetClipboard().HandleSlotCall(rRequest);
+ break;
+ }
+ }
+ ViewShellBase* pBase = mrSlideSorter.GetViewShellBase();
+ if (pBase != nullptr)
+ {
+ std::shared_ptr<DrawViewShell> pDrawViewShell (
+ std::dynamic_pointer_cast<DrawViewShell>(pBase->GetMainViewShell()));
+ if (pDrawViewShell != nullptr)
+ pDrawViewShell->FuSupport(rRequest);
+ }
+ }
+ break;
+
+ case SID_CUT:
+ case SID_COPY:
+ case SID_DELETE:
+ mrSlideSorter.GetView().EndTextEditAllViews();
+ mrSlideSorter.GetController().GetClipboard().HandleSlotCall(rRequest);
+ break;
+
+ case SID_DRAWINGMODE:
+ case SID_NOTES_MODE:
+ case SID_HANDOUT_MASTER_MODE:
+ case SID_SLIDE_SORTER_MODE:
+ case SID_OUTLINE_MODE:
+ {
+ ViewShellBase* pBase = mrSlideSorter.GetViewShellBase();
+ if (pBase != nullptr)
+ {
+ framework::FrameworkHelper::Instance(*pBase)->HandleModeChangeSlot(
+ rRequest.GetSlot(), rRequest);
+ rRequest.Done();
+ }
+ break;
+ }
+
+ case SID_UNDO:
+ {
+ SlideSorterViewShell* pViewShell
+ = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
+ if (pViewShell != nullptr)
+ {
+ pViewShell->ImpSidUndo (rRequest);
+ }
+ break;
+ }
+
+ case SID_REDO:
+ {
+ SlideSorterViewShell* pViewShell
+ = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
+ if (pViewShell != nullptr)
+ {
+ pViewShell->ImpSidRedo (rRequest);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void SlotManager::ExecCtrl (SfxRequest& rRequest)
+{
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ sal_uInt16 nSlot = rRequest.GetSlot();
+ switch (nSlot)
+ {
+ case SID_RELOAD:
+ {
+ // empty Undo-Manager
+ mrSlideSorter.GetModel().GetDocument()->GetDocSh()->ClearUndoBuffer();
+
+ // normal forwarding to ViewFrame for execution
+ if (pViewShell != nullptr)
+ pViewShell->GetViewFrame()->ExecuteSlot(rRequest);
+
+ // has to be finished right away
+ return;
+ }
+
+ case SID_OUTPUT_QUALITY_COLOR:
+ case SID_OUTPUT_QUALITY_GRAYSCALE:
+ case SID_OUTPUT_QUALITY_BLACKWHITE:
+ case SID_OUTPUT_QUALITY_CONTRAST:
+ {
+ // flush page cache
+ if (pViewShell != nullptr)
+ pViewShell->ExecReq (rRequest);
+ break;
+ }
+
+ case SID_MAIL_SCROLLBODY_PAGEDOWN:
+ {
+ if (pViewShell != nullptr)
+ pViewShell->ExecReq (rRequest);
+ break;
+ }
+
+ case SID_OPT_LOCALE_CHANGED:
+ {
+ mrSlideSorter.GetController().UpdateAllPages();
+ if (pViewShell != nullptr)
+ pViewShell->UpdatePreview (pViewShell->GetActualPage());
+ rRequest.Done();
+ break;
+ }
+
+ case SID_SEARCH_DLG:
+ // We have to handle the SID_SEARCH_DLG slot explicitly because
+ // in some cases (when the slide sorter is displayed in the
+ // center pane) we want to disable the search dialog. Therefore
+ // we have to handle the execution of that slot as well.
+ // We try to do that by forwarding the request to the view frame
+ // of the view shell.
+ if (pViewShell != nullptr)
+ pViewShell->GetViewFrame()->ExecuteSlot(rRequest);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void SlotManager::GetAttrState (SfxItemSet& rSet)
+{
+ // Iterate over all items.
+ SfxWhichIter aIter (rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ sal_uInt16 nSlotId (nWhich);
+ if (SfxItemPool::IsWhich(nWhich) && mrSlideSorter.GetViewShell()!=nullptr)
+ nSlotId = mrSlideSorter.GetViewShell()->GetPool().GetSlotId(nWhich);
+ switch (nSlotId)
+ {
+ case SID_PAGES_PER_ROW:
+ rSet.Put (
+ SfxUInt16Item (
+ nSlotId,
+ static_cast<sal_uInt16>(mrSlideSorter.GetView().GetLayouter().GetColumnCount())
+ )
+ );
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void SlotManager::GetMenuState (SfxItemSet& rSet)
+{
+ EditMode eEditMode = mrSlideSorter.GetModel().GetEditMode();
+ ViewShell* pShell = mrSlideSorter.GetViewShell();
+ DrawDocShell* pDocShell = mrSlideSorter.GetModel().GetDocument()->GetDocSh();
+
+ if (pShell!=nullptr && pShell->GetCurrentFunction().is())
+ {
+ sal_uInt16 nSId = pShell->GetCurrentFunction()->GetSlotID();
+
+ rSet.Put( SfxBoolItem( nSId, true ) );
+ }
+ rSet.Put( SfxBoolItem( SID_DRAWINGMODE, false ) );
+ rSet.Put( SfxBoolItem( SID_SLIDE_SORTER_MODE, true ) );
+ rSet.Put( SfxBoolItem( SID_OUTLINE_MODE, false ) );
+ rSet.Put( SfxBoolItem( SID_NOTES_MODE, false ) );
+ rSet.Put( SfxBoolItem( SID_HANDOUT_MASTER_MODE, false ) );
+
+ if (pShell!=nullptr && pShell->IsMainViewShell())
+ {
+ rSet.DisableItem(SID_SPELL_DIALOG);
+ rSet.DisableItem(SID_SEARCH_DLG);
+ }
+
+ if (SfxItemState::DEFAULT == rSet.GetItemState(SID_EXPAND_PAGE))
+ {
+ bool bDisable = true;
+ if (eEditMode == EditMode::Page)
+ {
+ // At least one of the selected pages has to contain an outline
+ // presentation objects in order to enable the expand page menu
+ // entry.
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ while (aSelectedPages.HasMoreElements())
+ {
+ SdPage* pPage = aSelectedPages.GetNextElement()->GetPage();
+ SdrObject* pObj = pPage->GetPresObj(PresObjKind::Outline);
+ if (pObj!=nullptr )
+ {
+ if( !pObj->IsEmptyPresObj() )
+ {
+ bDisable = false;
+ }
+ else
+ {
+ // check if the object is in edit, then if it's temporarily not empty
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObj );
+ if( pTextObj )
+ {
+ if( pTextObj->CanCreateEditOutlinerParaObject() )
+ {
+ bDisable = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (bDisable)
+ rSet.DisableItem (SID_EXPAND_PAGE);
+ }
+
+ if (SfxItemState::DEFAULT == rSet.GetItemState(SID_SUMMARY_PAGE))
+ {
+ bool bDisable = true;
+ if (eEditMode == EditMode::Page)
+ {
+ // At least one of the selected pages has to contain a title
+ // presentation objects in order to enable the summary page menu
+ // entry.
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ while (aSelectedPages.HasMoreElements())
+ {
+ SdPage* pPage = aSelectedPages.GetNextElement()->GetPage();
+ SdrObject* pObj = pPage->GetPresObj(PresObjKind::Title);
+
+ if (pObj!=nullptr && !pObj->IsEmptyPresObj())
+ bDisable = false;
+ }
+ }
+ if (bDisable)
+ rSet.DisableItem (SID_SUMMARY_PAGE);
+ }
+
+ // starting of presentation possible?
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_PRESENTATION ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_REHEARSE_TIMINGS ) )
+ {
+ bool bDisable = true;
+ model::PageEnumeration aAllPages (
+ model::PageEnumerationProvider::CreateAllPagesEnumeration(mrSlideSorter.GetModel()));
+ while (aAllPages.HasMoreElements())
+ {
+ SdPage* pPage = aAllPages.GetNextElement()->GetPage();
+
+ if( !pPage->IsExcluded() )
+ bDisable = false;
+ }
+ if( bDisable || pDocShell->IsPreview())
+ {
+ rSet.DisableItem( SID_PRESENTATION );
+ rSet.DisableItem( SID_REHEARSE_TIMINGS );
+ }
+ }
+
+ // Disable the rename slots when there are no or more than one slides/master
+ // pages selected; disable the duplicate slot when there are no slides
+ // selected:
+ if (rSet.GetItemState(SID_RENAMEPAGE) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_RENAME_MASTER_PAGE) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_DUPLICATE_PAGE) == SfxItemState::DEFAULT)
+ {
+ int n = mrSlideSorter.GetController().GetPageSelector()
+ .GetSelectedPageCount();
+ if (n != 1)
+ {
+ rSet.DisableItem(SID_RENAMEPAGE);
+ rSet.DisableItem(SID_RENAME_MASTER_PAGE);
+ }
+ if (n == 0)
+ {
+ rSet.DisableItem(SID_DUPLICATE_PAGE);
+ }
+ }
+
+ if (rSet.GetItemState(SID_HIDE_SLIDE) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_SHOW_SLIDE) == SfxItemState::DEFAULT)
+ {
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ const SlideExclusionState eState (GetSlideExclusionState(aSelectedPages));
+ switch (eState)
+ {
+ case MIXED:
+ // Show both entries.
+ break;
+
+ case EXCLUDED:
+ rSet.DisableItem(SID_HIDE_SLIDE);
+ break;
+
+ case INCLUDED:
+ rSet.DisableItem(SID_SHOW_SLIDE);
+ break;
+
+ case UNDEFINED:
+ rSet.DisableItem(SID_HIDE_SLIDE);
+ rSet.DisableItem(SID_SHOW_SLIDE);
+ break;
+ }
+ }
+
+ if (eEditMode == EditMode::MasterPage)
+ {
+ // Disable some slots when in master page mode.
+ rSet.DisableItem(SID_ASSIGN_LAYOUT);
+ rSet.DisableItem(SID_INSERTPAGE);
+
+ if (rSet.GetItemState(SID_DUPLICATE_PAGE) == SfxItemState::DEFAULT)
+ rSet.DisableItem(SID_DUPLICATE_PAGE);
+ }
+}
+
+void SlotManager::GetClipboardState ( SfxItemSet& rSet)
+{
+ SdTransferable* pTransferClip = SD_MOD()->pTransferClip;
+
+ if (rSet.GetItemState(SID_PASTE) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_PASTE_SPECIAL) == SfxItemState::DEFAULT)
+ {
+ // no own clipboard data?
+ if ( !pTransferClip || !pTransferClip->GetDocShell().is() )
+ {
+ rSet.DisableItem(SID_PASTE);
+ rSet.DisableItem(SID_PASTE_SPECIAL);
+ }
+ else
+ {
+ SfxObjectShell* pTransferDocShell = pTransferClip->GetDocShell().get();
+
+ if( !pTransferDocShell || static_cast<DrawDocShell*>(pTransferDocShell)->GetDoc()->GetPageCount() <= 1 )
+ {
+ bool bIsPastingSupported (false);
+
+ // No or just one page. Check if there is anything that can be
+ // pasted via a DrawViewShell.
+ ViewShellBase* pBase = mrSlideSorter.GetViewShellBase();
+ if (pBase != nullptr)
+ {
+ std::shared_ptr<DrawViewShell> pDrawViewShell (
+ std::dynamic_pointer_cast<DrawViewShell>(pBase->GetMainViewShell()));
+ if (pDrawViewShell != nullptr)
+ {
+ TransferableDataHelper aDataHelper (
+ TransferableDataHelper::CreateFromSystemClipboard(
+ pDrawViewShell->GetActiveWindow()));
+ if (aDataHelper.GetFormatCount() > 0)
+ bIsPastingSupported = true;
+ }
+ }
+
+ if ( ! bIsPastingSupported)
+ {
+ rSet.DisableItem(SID_PASTE);
+ rSet.DisableItem(SID_PASTE_SPECIAL);
+ }
+ }
+ }
+ }
+
+ // Cut, copy and paste of master pages is not yet implemented properly
+ if (rSet.GetItemState(SID_COPY) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_PASTE) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_PASTE_SPECIAL) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_CUT) == SfxItemState::DEFAULT)
+ {
+ if (mrSlideSorter.GetModel().GetEditMode() == EditMode::MasterPage)
+ {
+ if (rSet.GetItemState(SID_CUT) == SfxItemState::DEFAULT)
+ rSet.DisableItem(SID_CUT);
+ if (rSet.GetItemState(SID_COPY) == SfxItemState::DEFAULT)
+ rSet.DisableItem(SID_COPY);
+ if (rSet.GetItemState(SID_PASTE) == SfxItemState::DEFAULT)
+ rSet.DisableItem(SID_PASTE);
+ if (rSet.GetItemState(SID_PASTE_SPECIAL) == SfxItemState::DEFAULT)
+ rSet.DisableItem(SID_PASTE_SPECIAL);
+ }
+ }
+
+ ViewShellBase* pBase = mrSlideSorter.GetViewShellBase();
+ if (pBase && pBase->GetObjectShell()->isContentExtractionLocked())
+ {
+ rSet.DisableItem(SID_COPY);
+ rSet.DisableItem(SID_CUT);
+ }
+
+ // Cut, copy, and delete page are disabled when there is no selection.
+ if (!(rSet.GetItemState(SID_CUT) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_COPY) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_DELETE) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_DELETE_PAGE) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_DELETE_MASTER_PAGE) == SfxItemState::DEFAULT))
+ return;
+
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+
+ // For copy to work we have to have at least one selected page.
+ if ( ! aSelectedPages.HasMoreElements())
+ rSet.DisableItem(SID_COPY);
+
+ bool bDisable = false;
+ // The operations that lead to the deletion of a page are valid if
+ // a) there is at least one selected page
+ // b) deleting the selected pages leaves at least one page in the
+ // document
+ // c) selected master pages must not be used by slides.
+
+ // Test a).
+ if ( ! aSelectedPages.HasMoreElements())
+ bDisable = true;
+ // Test b): Count the number of selected pages. It has to be less
+ // than the number of all pages.
+ else if (mrSlideSorter.GetController().GetPageSelector().GetSelectedPageCount()
+ >= mrSlideSorter.GetController().GetPageSelector().GetPageCount())
+ bDisable = true;
+ // Test c): Iterate over the selected pages and look for a master
+ // page that is used by at least one page.
+ else while (aSelectedPages.HasMoreElements())
+ {
+ SdPage* pPage = aSelectedPages.GetNextElement()->GetPage();
+ int nUseCount (mrSlideSorter.GetModel().GetDocument()
+ ->GetMasterPageUserCount(pPage));
+ if (nUseCount > 0)
+ {
+ bDisable = true;
+ break;
+ }
+ }
+
+ if (bDisable)
+ {
+ rSet.DisableItem(SID_CUT);
+ rSet.DisableItem(SID_DELETE_PAGE);
+ rSet.DisableItem(SID_DELETE_MASTER_PAGE);
+ }
+}
+
+void SlotManager::GetStatusBarState (SfxItemSet& rSet)
+{
+ // page view and layout
+ SdPage* pPage = nullptr;
+ sal_uInt16 nSelectedPages = mrSlideSorter.GetController().GetPageSelector().GetSelectedPageCount();
+
+ //Set number of slides
+ if (nSelectedPages > 0)
+ {
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ OUString aPageStr;
+ if (pDescriptor)
+ {
+ pPage = pDescriptor->GetPage();
+ sal_uInt16 nFirstPage = (pPage->GetPageNum()/2) + 1;
+ sal_Int32 nPageCount = mrSlideSorter.GetModel().GetPageCount();
+ sal_Int32 nActivePageCount = static_cast<sal_Int32>(mrSlideSorter.GetModel().GetDocument()->GetActiveSdPageCount());
+
+ aPageStr = (nPageCount == nActivePageCount) ? SdResId(STR_SD_PAGE_COUNT) : SdResId(STR_SD_PAGE_COUNT_CUSTOM);
+
+ aPageStr = aPageStr.replaceFirst("%1", OUString::number(nFirstPage));
+ aPageStr = aPageStr.replaceFirst("%2", OUString::number(nPageCount));
+ if(nPageCount != nActivePageCount)
+ aPageStr = aPageStr.replaceFirst("%3", OUString::number(nActivePageCount));
+ }
+ rSet.Put( SfxStringItem( SID_STATUS_PAGE, aPageStr ) );
+ }
+ //Set layout
+ if (nSelectedPages == 1 && pPage != nullptr)
+ {
+ SdPage* pFirstPage = pPage;
+ OUString aLayoutStr = pFirstPage->GetLayoutName();
+ sal_Int32 nIndex = aLayoutStr.indexOf( SD_LT_SEPARATOR );
+ if( nIndex != -1 )
+ aLayoutStr = aLayoutStr.copy(0, nIndex);
+ rSet.Put( SfxStringItem( SID_STATUS_LAYOUT, aLayoutStr ) );
+ }
+ //Scale value
+ const Fraction& aUIScale = mrSlideSorter.GetModel().GetDocument()->GetUIScale();
+ OUString aString = OUString::number(aUIScale.GetNumerator()) +
+ ":" + OUString::number(aUIScale.GetDenominator());
+ rSet.Put( SfxStringItem( SID_SCALE, aString ) );
+}
+
+void SlotManager::RenameSlide(const SfxRequest& rRequest)
+{
+ View* pDrView = &mrSlideSorter.GetView();
+
+ if ( pDrView->IsTextEdit() )
+ {
+ pDrView->SdrEndTextEdit();
+ }
+
+ SdPage* pSelectedPage = nullptr;
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ if (aSelectedPages.HasMoreElements())
+ pSelectedPage = aSelectedPages.GetNextElement()->GetPage();
+ if (pSelectedPage == nullptr)
+ return;
+
+ // tdf#107183 Set different dialog titles when renaming
+ // master slides or normal ones
+ OUString aTitle;
+ if( rRequest.GetSlot() == SID_RENAME_MASTER_PAGE )
+ aTitle = SdResId( STR_TITLE_RENAMEMASTER );
+ else if (pDrView->GetDoc().GetDocumentType() == DocumentType::Draw)
+ aTitle = SdResId( STR_TITLE_RENAMEPAGE );
+ else
+ aTitle = SdResId( STR_TITLE_RENAMESLIDE );
+
+ OUString aDescr( SdResId( STR_DESC_RENAMESLIDE ) );
+ OUString aPageName = pSelectedPage->GetName();
+
+ if(rRequest.GetArgs())
+ {
+ OUString aName = rRequest.GetArgs()->GetItem<const SfxStringItem>(SID_RENAMEPAGE)->GetValue();
+
+ bool bResult = RenameSlideFromDrawViewShell(pSelectedPage->GetPageNum()/2, aName );
+ DBG_ASSERT( bResult, "Couldn't rename slide or page" );
+ }
+ else
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ vcl::Window* pWin = mrSlideSorter.GetContentWindow();
+ ScopedVclPtr<AbstractSvxNameDialog> aNameDlg(pFact->CreateSvxNameDialog(
+ pWin ? pWin->GetFrameWeld() : nullptr,
+ aPageName, aDescr));
+ OUString aOldName;
+ aNameDlg->GetName( aOldName );
+ aNameDlg->SetText( aTitle );
+ aNameDlg->SetCheckNameHdl( LINK( this, SlotManager, RenameSlideHdl ), true );
+ aNameDlg->SetCheckNameTooltipHdl( LINK( this, SlotManager, RenameSlideTooltipHdl ) );
+ aNameDlg->SetEditHelpId( HID_SD_NAMEDIALOG_PAGE );
+
+ if( aNameDlg->Execute() == RET_OK )
+ {
+ OUString aNewName;
+ aNameDlg->GetName( aNewName );
+ if (aNewName != aPageName)
+ {
+ bool bResult =
+ RenameSlideFromDrawViewShell(
+ pSelectedPage->GetPageNum()/2, aNewName );
+ DBG_ASSERT( bResult, "Couldn't rename slide or page" );
+ }
+ }
+ OUString aNewName;
+ aNameDlg->GetName( aNewName );
+ collectUIInformation({{"OldName", aOldName}, {"NewName", aNewName}}, "RENAME");
+ aNameDlg.disposeAndClear();
+ }
+ // Tell the slide sorter about the name change (necessary for
+ // accessibility.)
+ mrSlideSorter.GetController().PageNameHasChanged(
+ (pSelectedPage->GetPageNum()-1)/2, aPageName);
+}
+
+IMPL_LINK(SlotManager, RenameSlideHdl, AbstractSvxNameDialog&, rDialog, bool)
+{
+ OUString aNewName;
+ rDialog.GetName( aNewName );
+
+ model::SharedPageDescriptor pDescriptor (
+ mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide());
+ SdPage* pCurrentPage = nullptr;
+ if (pDescriptor)
+ pCurrentPage = pDescriptor->GetPage();
+
+ return (pCurrentPage!=nullptr && aNewName == pCurrentPage->GetName())
+ || (mrSlideSorter.GetViewShell()
+ && mrSlideSorter.GetViewShell()->GetDocSh()->IsNewPageNameValid( aNewName ) );
+}
+
+IMPL_STATIC_LINK_NOARG(SlotManager, RenameSlideTooltipHdl, AbstractSvxNameDialog&, OUString)
+{
+ return SdResId(STR_TOOLTIP_RENAME);
+}
+
+bool SlotManager::RenameSlideFromDrawViewShell( sal_uInt16 nPageId, const OUString & rName )
+{
+ bool bOutDummy;
+ SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
+ if( pDocument->GetPageByName( rName, bOutDummy ) != SDRPAGE_NOTFOUND )
+ return false;
+
+ SdPage* pPageToRename = nullptr;
+
+ SfxUndoManager* pManager = pDocument->GetDocSh()->GetUndoManager();
+
+ if( mrSlideSorter.GetModel().GetEditMode() == EditMode::Page )
+ {
+ model::SharedPageDescriptor pDescriptor (
+ mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide());
+ if (pDescriptor)
+ pPageToRename = pDescriptor->GetPage();
+
+ if (pPageToRename != nullptr)
+ {
+ // Undo
+ SdPage* pUndoPage = pPageToRename;
+ SdrLayerAdmin & rLayerAdmin = pDocument->GetLayerAdmin();
+ SdrLayerID nBackground = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID nBgObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ SdrLayerIDSet aVisibleLayers = pPageToRename->TRG_GetMasterPageVisibleLayers();
+
+ // (#67720#)
+ pManager->AddUndoAction(
+ std::make_unique<ModifyPageUndoAction>(
+ pDocument, pUndoPage, rName, pUndoPage->GetAutoLayout(),
+ aVisibleLayers.IsSet( nBackground ),
+ aVisibleLayers.IsSet( nBgObj )));
+
+ // rename
+ pPageToRename->SetName( rName );
+
+ // also rename notes-page
+ SdPage* pNotesPage = pDocument->GetSdPage( nPageId, PageKind::Notes );
+ if (pNotesPage != nullptr)
+ pNotesPage->SetName (rName);
+ }
+ }
+ else
+ {
+ // rename MasterPage -> rename LayoutTemplate
+ pPageToRename = pDocument->GetMasterSdPage( nPageId, PageKind::Standard );
+ if (pPageToRename != nullptr)
+ {
+ const OUString aOldLayoutName( pPageToRename->GetLayoutName() );
+ pManager->AddUndoAction( std::make_unique<RenameLayoutTemplateUndoAction>( pDocument, aOldLayoutName, rName ) );
+ pDocument->RenameLayoutTemplate( aOldLayoutName, rName );
+ }
+ }
+
+ bool bSuccess = pPageToRename!=nullptr && ( rName == pPageToRename->GetName() );
+
+ if( bSuccess )
+ {
+ // user edited page names may be changed by the page so update control
+ // aTabControl.SetPageText( nPageId, rName );
+
+ // set document to modified state
+ pDocument->SetChanged();
+
+ // inform navigator about change
+ if (mrSlideSorter.GetViewShell() && mrSlideSorter.GetViewShell()->GetViewFrame())
+ mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings().Invalidate(
+ SID_NAVIGATOR_STATE, true);
+ }
+
+ return bSuccess;
+}
+
+/** Insert a slide. The insertion position depends on a) the selection and
+ b) the mouse position when there is no selection.
+
+ When there is a selection then insertion takes place after the last
+ slide of the selection. For this to work all but the last selected
+ slide are deselected first.
+
+ Otherwise, when there is no selection but the insertion marker is visible
+ the slide is inserted at that position. The slide before that marker is
+ selected first.
+
+ When both the selection and the insertion marker are not visible--can
+ that happen?--the new slide is inserted after the last slide.
+*/
+void SlotManager::InsertSlide (SfxRequest& rRequest)
+{
+ const sal_Int32 nInsertionIndex (GetInsertionPosition());
+
+ PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter);
+
+ SdPage* pNewPage = nullptr;
+ if (mrSlideSorter.GetModel().GetEditMode() == EditMode::Page)
+ {
+ SlideSorterViewShell* pShell = dynamic_cast<SlideSorterViewShell*>(
+ mrSlideSorter.GetViewShell());
+ if (pShell != nullptr)
+ {
+ pNewPage = pShell->CreateOrDuplicatePage (
+ rRequest,
+ PageKind::Standard,
+ nInsertionIndex>=0
+ ? mrSlideSorter.GetModel().GetPageDescriptor(nInsertionIndex)->GetPage()
+ : nullptr);
+ }
+ }
+ else
+ {
+ // Use the API to create a new page.
+ SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
+ Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier (
+ pDocument->getUnoModel(), UNO_QUERY);
+ if (xMasterPagesSupplier.is())
+ {
+ Reference<drawing::XDrawPages> xMasterPages (
+ xMasterPagesSupplier->getMasterPages());
+ if (xMasterPages.is())
+ {
+ xMasterPages->insertNewByIndex (nInsertionIndex+1);
+
+ // Create shapes for the default layout.
+ pNewPage = pDocument->GetMasterSdPage(
+ static_cast<sal_uInt16>(nInsertionIndex+1), PageKind::Standard);
+ pNewPage->CreateTitleAndLayout (true,true);
+ }
+ }
+ }
+ if (pNewPage == nullptr)
+ return;
+
+ // When a new page has been inserted then select it, make it the
+ // current page, and focus it.
+ view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter);
+ PageSelector::UpdateLock aUpdateLock (mrSlideSorter);
+ mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
+ mrSlideSorter.GetController().GetPageSelector().SelectPage(pNewPage);
+ collectUIInformation({{"POS", OUString::number(nInsertionIndex + 2)}}, "Insert_New_Page_or_Slide");
+}
+
+void SlotManager::DuplicateSelectedSlides (SfxRequest& rRequest)
+{
+ // Create a list of the pages that are to be duplicated. The process of
+ // duplication alters the selection.
+ sal_Int32 nInsertPosition (0);
+ ::std::vector<SdPage*> aPagesToDuplicate;
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel()));
+ while (aSelectedPages.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ if (pDescriptor && pDescriptor->GetPage())
+ {
+ aPagesToDuplicate.push_back(pDescriptor->GetPage());
+ nInsertPosition = pDescriptor->GetPage()->GetPageNum()+2;
+ }
+ }
+
+ // Duplicate the pages in aPagesToDuplicate and collect the newly
+ // created pages in aPagesToSelect.
+ const bool bUndo (aPagesToDuplicate.size()>1 && mrSlideSorter.GetView().IsUndoEnabled());
+ if (bUndo)
+ mrSlideSorter.GetView().BegUndo(SdResId(STR_INSERTPAGE));
+
+ ::std::vector<SdPage*> aPagesToSelect;
+ for(const auto& rpPage : aPagesToDuplicate)
+ {
+ aPagesToSelect.push_back(
+ mrSlideSorter.GetViewShell()->CreateOrDuplicatePage(
+ rRequest, PageKind::Standard, rpPage, nInsertPosition));
+ nInsertPosition += 2;
+ }
+ aPagesToDuplicate.clear();
+
+ if (bUndo)
+ mrSlideSorter.GetView().EndUndo();
+
+ // Set the selection to the pages in aPagesToSelect.
+ PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector());
+ rSelector.DeselectAllPages();
+ for (auto const& it: aPagesToSelect)
+ {
+ rSelector.SelectPage(it);
+ }
+
+ collectUIInformation({{"POS", OUString::number(nInsertPosition + 2)}}, "Duplicate");
+}
+
+void SlotManager::ChangeSlideExclusionState (
+ const model::SharedPageDescriptor& rpDescriptor,
+ const bool bExcludeSlide)
+{
+ if (rpDescriptor)
+ {
+ mrSlideSorter.GetView().SetState(
+ rpDescriptor,
+ model::PageDescriptor::ST_Excluded,
+ bExcludeSlide);
+ }
+ else
+ {
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ while (aSelectedPages.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ mrSlideSorter.GetView().SetState(
+ pDescriptor,
+ model::PageDescriptor::ST_Excluded,
+ bExcludeSlide);
+ }
+ }
+
+ SfxBindings& rBindings (mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings());
+ rBindings.Invalidate(SID_PRESENTATION);
+ rBindings.Invalidate(SID_REHEARSE_TIMINGS);
+ rBindings.Invalidate(SID_HIDE_SLIDE);
+ rBindings.Invalidate(SID_SHOW_SLIDE);
+ mrSlideSorter.GetModel().GetDocument()->SetChanged();
+}
+
+sal_Int32 SlotManager::GetInsertionPosition() const
+{
+ PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector());
+
+ // The insertion indicator is preferred. After all the user explicitly
+ // used it to define the insertion position.
+ if (mrSlideSorter.GetController().GetInsertionIndicatorHandler()->IsActive())
+ {
+ // Select the page before the insertion indicator.
+ return mrSlideSorter.GetController().GetInsertionIndicatorHandler()->GetInsertionPageIndex()
+ - 1;
+ }
+
+ // Is there a stored insertion position?
+ else if (mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() >= 0)
+ {
+ return mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() - 1;
+ }
+
+ // Use the index of the last selected slide.
+ else if (rSelector.GetSelectedPageCount() > 0)
+ {
+ for (int nIndex=rSelector.GetPageCount()-1; nIndex>=0; --nIndex)
+ if (rSelector.IsPageSelected(nIndex))
+ return nIndex;
+
+ // We should never get here.
+ OSL_ASSERT(false);
+ return rSelector.GetPageCount() - 1;
+ }
+
+ // Select the last page when there is at least one page.
+ else if (rSelector.GetPageCount() > 0)
+ {
+ return rSelector.GetPageCount() - 1;
+ }
+
+ // Hope for the best that CreateOrDuplicatePage() can cope with an empty
+ // selection.
+ else
+ {
+ // We should never get here because there has to be at least one page.
+ OSL_ASSERT(false);
+ return -1;
+ }
+}
+
+void SlotManager::NotifyEditModeChange()
+{
+ SfxBindings& rBindings (mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings());
+ rBindings.Invalidate(SID_PRESENTATION);
+ rBindings.Invalidate(SID_INSERTPAGE);
+ rBindings.Invalidate(SID_DUPLICATE_PAGE);
+}
+
+namespace {
+
+SlideExclusionState GetSlideExclusionState (model::PageEnumeration& rPageSet)
+{
+ SlideExclusionState eState (UNDEFINED);
+
+ // Get toggle state of the selected pages.
+ while (rPageSet.HasMoreElements() && eState!=MIXED)
+ {
+ const bool bState = rPageSet.GetNextElement()->GetPage()->IsExcluded();
+ switch (eState)
+ {
+ case UNDEFINED:
+ // Use the first selected page to set the initial value.
+ eState = bState ? EXCLUDED : INCLUDED;
+ break;
+
+ case EXCLUDED:
+ // The pages before where all not part of the show,
+ // this one is.
+ if ( ! bState)
+ eState = MIXED;
+ break;
+
+ case INCLUDED:
+ // The pages before where all part of the show,
+ // this one is not.
+ if (bState)
+ eState = MIXED;
+ break;
+
+ default:
+ // No need to change anything.
+ break;
+ }
+ }
+
+ return eState;
+}
+
+} // end of anonymous namespace
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsTransferableData.cxx b/sd/source/ui/slidesorter/controller/SlsTransferableData.cxx
new file mode 100644
index 000000000..f4b89a5ab
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsTransferableData.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <controller/SlsTransferableData.hxx>
+
+#include <SlideSorterViewShell.hxx>
+
+namespace sd::slidesorter::controller {
+
+rtl::Reference<SdTransferable> TransferableData::CreateTransferable (
+ SdDrawDocument* pSrcDoc,
+ SlideSorterViewShell* pViewShell,
+ ::std::vector<Representative>&& rRepresentatives)
+{
+ rtl::Reference<SdTransferable> pTransferable = new SdTransferable (pSrcDoc, nullptr, false/*bInitOnGetData*/);
+ auto pData = std::make_shared<TransferableData>(pViewShell, std::move(rRepresentatives));
+ pTransferable->AddUserData(pData);
+ return pTransferable;
+}
+
+std::shared_ptr<TransferableData> TransferableData::GetFromTransferable (const SdTransferable* pTransferable)
+{
+ if (pTransferable)
+ {
+ for (sal_Int32 nIndex=0,nCount=pTransferable->GetUserDataCount(); nIndex<nCount; ++nIndex)
+ {
+ std::shared_ptr<TransferableData> xData =
+ std::dynamic_pointer_cast<TransferableData>(pTransferable->GetUserData(nIndex));
+ if (xData)
+ return xData;
+ }
+ }
+ return std::shared_ptr<TransferableData>();
+}
+
+TransferableData::TransferableData (
+ SlideSorterViewShell* pViewShell,
+ ::std::vector<Representative>&& rRepresentatives)
+ : mpViewShell(pViewShell),
+ maRepresentatives(std::move(rRepresentatives))
+{
+ if (mpViewShell != nullptr)
+ StartListening(*mpViewShell);
+}
+
+TransferableData::~TransferableData()
+{
+ if (mpViewShell != nullptr)
+ EndListening(*mpViewShell);
+}
+
+void TransferableData::Notify (SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (mpViewShell)
+ {
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ // This hint may come either from the ViewShell or from the
+ // document (registered by SdTransferable). We do not know
+ // which but both are sufficient to disconnect from the
+ // ViewShell.
+ EndListening(*mpViewShell);
+ mpViewShell = nullptr;
+ }
+ }
+}
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx b/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx
new file mode 100644
index 000000000..6f85f362d
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx
@@ -0,0 +1,234 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <controller/SlsVisibleAreaManager.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsAnimationFunction.hxx>
+#include <controller/SlsScrollBarManager.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <Window.hxx>
+#include <SlideSorter.hxx>
+#include <view/SlideSorterView.hxx>
+
+namespace sd::slidesorter::controller {
+
+namespace {
+ class VisibleAreaScroller
+ {
+ public:
+ VisibleAreaScroller (
+ SlideSorter& rSlideSorter,
+ const Point& rStart,
+ const Point& rEnd);
+ void operator() (const double nValue);
+ private:
+ SlideSorter& mrSlideSorter;
+ Point maStart;
+ const Point maEnd;
+ const ::std::function<double (double)> maAccelerationFunction;
+ };
+
+} // end of anonymous namespace
+
+VisibleAreaManager::VisibleAreaManager (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mbIsCurrentSlideTrackingActive(true),
+ mnDisableCount(0)
+{
+}
+
+VisibleAreaManager::~VisibleAreaManager()
+{
+}
+
+void VisibleAreaManager::ActivateCurrentSlideTracking()
+{
+ mbIsCurrentSlideTrackingActive = true;
+}
+
+void VisibleAreaManager::DeactivateCurrentSlideTracking()
+{
+ mbIsCurrentSlideTrackingActive = false;
+}
+
+void VisibleAreaManager::RequestVisible (
+ const model::SharedPageDescriptor& rpDescriptor,
+ const bool bForce)
+{
+ if (!rpDescriptor)
+ return;
+
+ if (mnDisableCount == 0)
+ {
+ maVisibleRequests.push_back(
+ mrSlideSorter.GetView().GetLayouter().GetPageObjectBox(
+ rpDescriptor->GetPageIndex(),
+ true));
+ }
+ if (bForce && ! mbIsCurrentSlideTrackingActive)
+ ActivateCurrentSlideTracking();
+ MakeVisible();
+}
+
+void VisibleAreaManager::RequestCurrentSlideVisible()
+{
+ if (mbIsCurrentSlideTrackingActive && mnDisableCount==0)
+ RequestVisible(
+ mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide());
+}
+
+void VisibleAreaManager::MakeVisible()
+{
+ if (maVisibleRequests.empty())
+ return;
+
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if ( ! pWindow)
+ return;
+ const Point aCurrentTopLeft (pWindow->PixelToLogic(Point(0,0)));
+
+ const ::std::optional<Point> aNewVisibleTopLeft (GetRequestedTopLeft());
+ maVisibleRequests.clear();
+ if ( ! aNewVisibleTopLeft)
+ return;
+
+ maRequestedVisibleTopLeft = *aNewVisibleTopLeft;
+ VisibleAreaScroller aAnimation(
+ mrSlideSorter,
+ aCurrentTopLeft,
+ maRequestedVisibleTopLeft);
+ // Execute the animation at its final value.
+ aAnimation(1.0);
+}
+
+::std::optional<Point> VisibleAreaManager::GetRequestedTopLeft() const
+{
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if ( ! pWindow)
+ return ::std::optional<Point>();
+
+ // Get the currently visible area and the model area.
+ const ::tools::Rectangle aVisibleArea (pWindow->PixelToLogic(
+ ::tools::Rectangle(
+ Point(0,0),
+ pWindow->GetOutputSizePixel())));
+ const ::tools::Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea());
+
+ sal_Int32 nVisibleTop (aVisibleArea.Top());
+ const sal_Int32 nVisibleWidth (aVisibleArea.GetWidth());
+ sal_Int32 nVisibleLeft (aVisibleArea.Left());
+ const sal_Int32 nVisibleHeight (aVisibleArea.GetHeight());
+
+ // Find the longest run of boxes whose union fits into the visible area.
+ for (const auto& rBox : maVisibleRequests)
+ {
+ if (nVisibleTop+nVisibleHeight <= rBox.Bottom())
+ nVisibleTop = rBox.Bottom()-nVisibleHeight;
+ if (nVisibleTop > rBox.Top())
+ nVisibleTop = rBox.Top();
+
+ if (nVisibleLeft+nVisibleWidth <= rBox.Right())
+ nVisibleLeft = rBox.Right()-nVisibleWidth;
+ if (nVisibleLeft > rBox.Left())
+ nVisibleLeft = rBox.Left();
+
+ // Make sure the visible area does not move outside the model area.
+ if (nVisibleTop + nVisibleHeight > aModelArea.Bottom())
+ nVisibleTop = aModelArea.Bottom() - nVisibleHeight;
+ if (nVisibleTop < aModelArea.Top())
+ nVisibleTop = aModelArea.Top();
+
+ if (nVisibleLeft + nVisibleWidth > aModelArea.Right())
+ nVisibleLeft = aModelArea.Right() - nVisibleWidth;
+ if (nVisibleLeft < aModelArea.Left())
+ nVisibleLeft = aModelArea.Left();
+ }
+
+ const Point aRequestedTopLeft (nVisibleLeft, nVisibleTop);
+ if (aRequestedTopLeft == aVisibleArea.TopLeft())
+ return ::std::optional<Point>();
+ else
+ return ::std::optional<Point>(aRequestedTopLeft);
+}
+
+//===== VisibleAreaManager::TemporaryDisabler =================================
+
+VisibleAreaManager::TemporaryDisabler::TemporaryDisabler (SlideSorter const & rSlideSorter)
+ : mrVisibleAreaManager(rSlideSorter.GetController().GetVisibleAreaManager())
+{
+ ++mrVisibleAreaManager.mnDisableCount;
+}
+
+VisibleAreaManager::TemporaryDisabler::~TemporaryDisabler()
+{
+ --mrVisibleAreaManager.mnDisableCount;
+}
+
+//===== VerticalVisibleAreaScroller ===========================================
+
+namespace {
+
+const sal_Int32 gnMaxScrollDistance = 300;
+
+VisibleAreaScroller::VisibleAreaScroller (
+ SlideSorter& rSlideSorter,
+ const Point& rStart,
+ const Point& rEnd)
+ : mrSlideSorter(rSlideSorter),
+ maStart(rStart),
+ maEnd(rEnd),
+ maAccelerationFunction(
+ controller::AnimationParametricFunction(
+ controller::AnimationBezierFunction (0.1,0.6)))
+{
+ // When the distance to scroll is larger than a threshold then first
+ // jump to within this distance of the final value and start the
+ // animation from there.
+ if (std::abs(rStart.X()-rEnd.X()) > gnMaxScrollDistance)
+ {
+ if (rStart.X() < rEnd.X())
+ maStart.setX( rEnd.X()-gnMaxScrollDistance );
+ else
+ maStart.setX( rEnd.X()+gnMaxScrollDistance );
+ }
+ if (std::abs(rStart.Y()-rEnd.Y()) > gnMaxScrollDistance)
+ {
+ if (rStart.Y() < rEnd.Y())
+ maStart.setY( rEnd.Y()-gnMaxScrollDistance );
+ else
+ maStart.setY( rEnd.Y()+gnMaxScrollDistance );
+ }
+}
+
+void VisibleAreaScroller::operator() (const double nTime)
+{
+ const double nLocalTime (maAccelerationFunction(nTime));
+ mrSlideSorter.GetController().GetScrollBarManager().SetTopLeft(
+ Point(
+ sal_Int32(0.5 + maStart.X() * (1.0 - nLocalTime) + maEnd.X() * nLocalTime),
+ sal_Int32 (0.5 + maStart.Y() * (1.0 - nLocalTime) + maEnd.Y() * nLocalTime)));
+}
+
+} // end of anonymous namespace
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx b/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx
new file mode 100644
index 000000000..12993fdbb
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <com/sun/star/uno/Reference.hxx>
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::uno
+{
+class XInterface;
+}
+
+class SdrPage;
+
+namespace sd::slidesorter::cache
+{
+typedef const SdrPage* CacheKey;
+
+/** This interface allows the individualisation of different instances of
+ the PreviewCache.
+*/
+class CacheContext
+{
+public:
+ virtual ~CacheContext() {}
+
+ /** This method is called when the asynchronous creation of a preview
+ has been finished.
+ @param aKey
+ The key of the page for which the preview has been created.
+ */
+ virtual void NotifyPreviewCreation(CacheKey aKey) = 0;
+
+ /** Called to determine whether the system is idle and a preview can be
+ created without annoying the user.
+ */
+ virtual bool IsIdle() = 0;
+
+ /** This method is used to determine whether a page is currently visible
+ or not. It is called when the cache becomes too large and some
+ previews have to be released or scaled down.
+ */
+ virtual bool IsVisible(CacheKey aKey) = 0;
+
+ /** Return the page associated with the given key. Note that different
+ keys may map to a single page (this may be the case with custom
+ slide shows.)
+ */
+ virtual const SdrPage* GetPage(CacheKey aKey) = 0;
+
+ /** This method is used when the request queue is filled. It asks for
+ the list of visible entries and maybe for the list of not visible
+ entries and creates preview creation requests for them.
+ @param bVisible
+ When this is <FALSE/> then the implementation can decide whether
+ to allow rendering of previews that are not visible (ahead of
+ time). When not then return an empty pointer or an empty vector.
+ */
+ virtual std::shared_ptr<std::vector<CacheKey>> GetEntryList(bool bVisible) = 0;
+
+ /** Return the priority that defines the order in which previews are
+ created for different keys/pages. Typically the visible pages come
+ first, then top-down, left-to-right.
+ */
+ virtual sal_Int32 GetPriority(CacheKey aKey) = 0;
+
+ /** Return the model to which the pages belong for which the called
+ cache manages the previews. Different caches that belong to the
+ same model but have different preview sizes may access previews of
+ each other in order to create fast previews of the previews.
+ */
+ virtual css::uno::Reference<css::uno::XInterface> GetModel() = 0;
+};
+
+typedef std::shared_ptr<CacheContext> SharedCacheContext;
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx b/sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx
new file mode 100644
index 000000000..4fb596195
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/cache/SlsPageCache.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 .
+ */
+
+#pragma once
+
+#include <cache/SlsCacheContext.hxx>
+#include <vcl/bitmapex.hxx>
+#include <memory>
+
+class Size;
+
+namespace sd::slidesorter::cache
+{
+class GenericPageCache;
+
+/** The page cache is responsible for the creation and storage of preview
+ bitmaps of pages that are shown by the slide sorter.
+
+ <p>Bitmaps for previews and a cache are used to speed up the display
+ (painting) of the slide sorter. But, of course, we have to limit this
+ time-space-tradeoff by limiting the amount of space that can be use to
+ store bitmaps.</p>
+
+ <p>There are several strategies employed by this class to shorten the
+ perceived time that is used to paint the slide sorter:
+ <ul>
+ <li>Rendering pages ahead of time. Additionally to rendering the
+ visible slides we try to render part or all of the slides that are not
+ (yet) visible. This, of course, makes sense only when the computer is
+ otherwise idle while doing that.</li>
+ <li>When the size of the slides on the screen changes we mark the
+ bitmaps as needing an update but use them while the new bitmap in the
+ correct size is not available.</li>
+ <li>Give the UI the chance to handle user events between the rendering
+ of differe slides.</li>
+ <li>Limit the amount of space that may be used for storing preview
+ bitmaps and throw.</li>
+ </p>
+
+ <p>There is another somewhat similar methods for requesting new previews:
+ GetPreviewBitmap() schedules a re-rendering (when necessary) and
+ returns the preview what is currently available, either as a preview of
+ the preview or, when nothing has changed since the last call, as the
+ final thing.
+ </p>
+*/
+class PageCache
+{
+public:
+ /** The page cache is created with a reference to the slide sorter so
+ that it has access to both the view and the model and so can fill
+ itself with requests for all or just the visible pages.
+
+ It is the task of the PageCacheManager to create new objects of this
+ class.
+ */
+ PageCache(const Size& rPreviewSize, const bool bDoSuperSampling,
+ const SharedCacheContext& rpCacheContext);
+
+ ~PageCache();
+
+ void ChangeSize(const Size& rPreviewSize, const bool bDoSuperSampling);
+
+ /** Request a preview bitmap for the specified page object in the
+ specified size. The returned bitmap may be a preview of the
+ preview, i.e. either a scaled (up or down) version of a previous
+ preview (of the wrong size) or an empty bitmap. In this case a
+ request for the generation of a new preview is created and inserted
+ into the request queue. When the preview is available in the right
+ size the page shape will be told to paint itself again. When it
+ then calls this method again if receives the correctly sized preview
+ bitmap.
+ @param rRequestData
+ This data is used to determine the preview.
+ @param bResize
+ When <TRUE/> then when the available bitmap has not the
+ requested size, it is scaled before it is returned. When
+ <FALSE/> then the bitmap is returned in the wrong size and it is
+ the task of the caller to scale it.
+ @return
+ Returns a bitmap that is either empty, contains a scaled (up or
+ down) version or is the requested bitmap.
+ */
+ BitmapEx GetPreviewBitmap(const CacheKey aKey, const bool bResize);
+
+ BitmapEx GetMarkedPreviewBitmap(const CacheKey aKey);
+ void SetMarkedPreviewBitmap(const CacheKey aKey, const BitmapEx& rBitmap);
+
+ /** When the requested preview bitmap does not yet exist or is not
+ up-to-date then the rendering of one is scheduled. Otherwise this
+ method does nothing.
+ */
+ void RequestPreviewBitmap(const CacheKey aKey);
+
+ /** Tell the cache that the bitmap associated with the given request
+ data is not up-to-date anymore. This will invalidate all previews
+ in other caches that represent the same page as well.
+ A new preview is requested and will lead
+ eventually to a repaint of the associated page object.
+ */
+ void InvalidatePreviewBitmap(const CacheKey aKey);
+
+ /** Call this method when all preview bitmaps have to be generated anew.
+ This is the case when the size of the page objects on the screen has
+ changed or when the model has changed.
+ */
+ void InvalidateCache();
+
+ /** With the precious flag you can control whether a bitmap can be
+ removed or reduced in size to make room for other bitmaps or is so
+ precious that it will not touched. A typical use is to set the
+ precious flag for exactly the visible pages.
+ */
+ void SetPreciousFlag(const CacheKey aKey, const bool bIsPrecious);
+
+ void Pause();
+ void Resume();
+
+private:
+ std::unique_ptr<GenericPageCache> mpImplementation;
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx b/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx
new file mode 100644
index 000000000..eaddea5b2
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <memory>
+#include <vector>
+
+class Size;
+class SdrPage;
+
+namespace sd::slidesorter::cache {
+
+class BitmapCache;
+
+/** Provide and manage the preview bitmap caches for all slide sorter
+ instances. There is one cache per active slide sorter plus a small
+ number of caches that are no longer in use. The later are kept to speed
+ up the switching between views.
+*/
+class PageCacheManager
+{
+public:
+ typedef std::vector< std::pair<Size, std::shared_ptr<BitmapCache> > > BestFittingPageCaches;
+ typedef css::uno::Reference<css::uno::XInterface> DocumentKey;
+
+ /** Return the one instance of the PageCacheManager class.
+ */
+ static std::shared_ptr<PageCacheManager> Instance();
+
+ /** Look up the cache for the given model in which the previews have the
+ specified size. If no such cache exists, then one is created. When
+ a new BitmapCache is created its Recycle() method is called with a
+ sorted list of existing caches from which the new one initialize its
+ previews.
+ @return
+ The returned cache lives as long as somebody keeps a shared
+ pointer and the ReleaseCache() method has not been called.
+ */
+ std::shared_ptr<BitmapCache> GetCache (
+ const DocumentKey& pDocument,
+ const Size& rPreviewSize);
+
+ /** Tell the cache manager to release its own reference to the specified
+ cache. After that the cache will live as long as the caller (and
+ maybe others) holds its reference.
+ */
+ void ReleaseCache (const std::shared_ptr<BitmapCache>& rpCache);
+
+ /** This is an information to the cache manager that the size of preview
+ bitmaps in the specified cache has changed.
+
+ */
+ std::shared_ptr<BitmapCache> ChangeSize (
+ const std::shared_ptr<BitmapCache>& rpCache,
+ const Size& rOldPreviewSize,
+ const Size& rNewPreviewSize);
+
+ /** Invalidate the preview bitmap for one slide that belongs to the
+ specified document. The bitmaps for this slide in all caches are
+ marked as out-of-date and will be re-created when they are requested
+ the next time.
+ */
+ bool InvalidatePreviewBitmap (
+ const DocumentKey& pDocument,
+ const SdrPage* pPage);
+
+ /** Invalidate the preview bitmaps for all slides that belong to the
+ specified document. This is necessary after model changes that
+ affect e.g. page number fields.
+ */
+ void InvalidateAllPreviewBitmaps (const DocumentKey& pDocument);
+
+ /** Invalidate all the caches that are currently in use and destroy
+ those that are not. This is used for example when the high contrast
+ mode is turned on or off.
+ */
+ void InvalidateAllCaches();
+
+ /** Call this method when a page has been deleted and its preview
+ is not needed anymore.
+ */
+ void ReleasePreviewBitmap (const SdrPage* pPage);
+
+private:
+ /** Singleton instance of the cache manager. Note that this is a weak
+ pointer. The (implementation class of) ViewShellBase holds a
+ shared_ptr so that the cache manager has the same life time as the
+ ViewShellBase.
+ */
+ static std::weak_ptr<PageCacheManager> mpInstance;
+
+ /// List of active caches.
+ class PageCacheContainer;
+ std::unique_ptr<PageCacheContainer> mpPageCaches;
+
+ /// List of inactive, recently used caches.
+ class RecentlyUsedPageCaches;
+ std::unique_ptr<RecentlyUsedPageCaches> mpRecentlyUsedPageCaches;
+
+ /** The maximal number of recently used caches that are kept alive after
+ they have become inactive, i.e. after they are not used anymore by a
+ slide sorter.
+ */
+ static const sal_uInt32 mnMaximalRecentlyCacheCount = 2;
+
+ PageCacheManager();
+ ~PageCacheManager();
+
+ class Deleter;
+ friend class Deleter;
+
+ std::shared_ptr<BitmapCache> GetRecentlyUsedCache(
+ const DocumentKey& pDocument,
+ const Size& rSize);
+
+ /** Add the given cache to the list of recently used caches for the
+ document. There is one such list per document. Each least has at
+ most mnMaximalRecentlyCacheCount members.
+ */
+ void PutRecentlyUsedCache(
+ DocumentKey const & pDocument,
+ const Size& rPreviewSize,
+ const std::shared_ptr<BitmapCache>& rpCache);
+
+ /** This method is used internally to initialize a newly created
+ BitmapCache with already existing previews.
+ */
+ void Recycle (
+ const std::shared_ptr<BitmapCache>& rpCache,
+ const DocumentKey& pDocument,
+ const Size& rPreviewSize);
+};
+
+} // end of namespace ::sd::slidesorter::cache
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx b/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx
new file mode 100644
index 000000000..10c2aa13e
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx
@@ -0,0 +1,327 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsSharedPageDescriptor.hxx>
+#include <pres.hxx>
+
+#include <tools/link.hxx>
+#include <tools/gen.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+
+#include <sddllapi.h>
+
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::container
+{
+class XIndexAccess;
+}
+namespace com::sun::star::uno
+{
+template <typename> class Reference;
+}
+namespace sd
+{
+class FuPoor;
+}
+namespace sd
+{
+class Window;
+}
+namespace vcl
+{
+class Window;
+}
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+namespace sd::slidesorter::view
+{
+class SlideSorterView;
+}
+namespace sd::slidesorter::model
+{
+class SlideSorterModel;
+}
+
+class CommandEvent;
+class SdPage;
+class SfxItemSet;
+class SfxRequest;
+class VclSimpleEvent;
+class VclWindowEvent;
+
+namespace sd::slidesorter::controller
+{
+class Animator;
+class Clipboard;
+class CurrentSlideManager;
+class FocusManager;
+class InsertionIndicatorHandler;
+class Listener;
+class PageSelector;
+class ScrollBarManager;
+class SelectionFunction;
+class SelectionManager;
+class SlotManager;
+class VisibleAreaManager;
+
+class SlideSorterController final
+{
+public:
+ /** Create a new controller for the slide sorter.
+ @param pParentWindow
+ The window that contains the controls of the new
+ controller.
+ */
+ SlideSorterController(SlideSorter& rSlideSorter);
+
+ /** Late initialization. Call this method once a new object has been
+ created.
+ */
+ void Init();
+
+ ~SlideSorterController();
+
+ void Dispose();
+
+ /** Place and size the scroll bars and the browser window so that the
+ given rectangle is filled.
+ */
+ void Resize(const ::tools::Rectangle& rAvailableSpace);
+
+ /** Determine which of the UI elements--the scroll bars, the scroll bar
+ filler, the actual slide sorter view--are visible and place them in
+ the area last passed to Resize().
+ @param bForce
+ When <TRUE/> is given (<FALSE/> is the default) then the content
+ window and with it the SlideSorterView is resized event when its
+ size does not change (the size does change when the visibility
+ of scroll bars changes.)
+ */
+ void Rearrange(bool bForce);
+
+ /** Return the descriptor of the page that is rendered under the
+ given position. This takes the IsOnlyPreviewTriggersMouseOver
+ property into account.
+ @return
+ Returns a pointer to a page descriptor instead of a
+ reference because when no page is found at the position
+ then NULL is returned to indicate this.
+ */
+ model::SharedPageDescriptor GetPageAt(const Point& rPixelPosition);
+
+ // Exported for unit test
+ SD_DLLPUBLIC PageSelector& GetPageSelector();
+ FocusManager& GetFocusManager();
+ // Exported for unit test
+ SD_DLLPUBLIC controller::Clipboard& GetClipboard();
+
+ /** Return the object that manages the scroll bars.
+ */
+ ScrollBarManager& GetScrollBarManager();
+
+ std::shared_ptr<CurrentSlideManager> const& GetCurrentSlideManager() const;
+ std::shared_ptr<SlotManager> const& GetSlotManager() const;
+ std::shared_ptr<SelectionManager> const& GetSelectionManager() const;
+ std::shared_ptr<InsertionIndicatorHandler> const& GetInsertionIndicatorHandler() const;
+
+ /** This method forwards the call to the SlideSorterView and executes
+ pending operations like moving selected pages into the visible area.
+ */
+ void Paint(const ::tools::Rectangle& rRect, vcl::Window* pWin);
+
+ void FuTemporary(SfxRequest& rRequest);
+ void FuPermanent(SfxRequest& rRequest);
+ void FuSupport(SfxRequest& rRequest);
+ bool Command(const CommandEvent& rEvent, ::sd::Window* pWindow);
+
+ void GetCtrlState(SfxItemSet& rSet);
+ void GetStatusBarState(SfxItemSet& rSet);
+
+ void ExecCtrl(SfxRequest& rRequest);
+ void GetAttrState(SfxItemSet& rSet);
+
+ /** Create an object of this inner class to prevent updates due to model
+ changes.
+ */
+ class ModelChangeLock
+ {
+ public:
+ ModelChangeLock(SlideSorterController& rController);
+ ~ModelChangeLock() COVERITY_NOEXCEPT_FALSE;
+ void Release();
+
+ private:
+ SlideSorterController* mpController;
+ };
+ friend class ModelChangeLock;
+
+ /** Handle a change of the model, that is, handle the removal and
+ insertion of whole pages or a change of the edit mode.
+
+ This method is a convenience function that simply calls
+ PreModelChange() and then PostModelChange().
+ */
+ void HandleModelChange();
+
+ DECL_LINK(WindowEventHandler, VclWindowEvent&, void);
+ DECL_LINK(ApplicationEventHandler, VclSimpleEvent&, void);
+
+ /** Update the display of all pages. This involves a redraw and
+ releasing previews and caches.
+ */
+ void UpdateAllPages();
+
+ /** This factory method creates a selection function.
+ */
+ rtl::Reference<FuPoor> CreateSelectionFunction(SfxRequest& rRequest);
+
+ /** When the current function of the view shell is the slide sorter
+ selection function then return a reference to it. Otherwise return
+ an empty reference.
+ */
+ ::rtl::Reference<SelectionFunction> GetCurrentSelectionFunction() const;
+
+ /** Prepare for a change of the edit mode. Depending on the current
+ edit mode we may save the selection so that it can be restored when
+ later changing back to the current edit mode.
+ */
+ void PrepareEditModeChange();
+
+ /** Set a new edit mode and return whether the edit mode really
+ has been changed. For proper saving and restoring of the selection
+ this method should be called between calls to
+ PrepareEditModeChange() and FinishEditModeChange().
+ */
+ void ChangeEditMode(EditMode eEditMode);
+
+ /** Finish the change of the edit mode. Here we may select a page or
+ restore a previously saved selection.
+ */
+ void FinishEditModeChange();
+
+ /** Call this method when the name of one of the pages has changed.
+ This is then notified to the accessibility object, when that exists.
+ @param nPageIndex
+ The index of the page whose name has been changed.
+ @param rsOldName
+ The old name of the page. The new name can be taken from the
+ page object.
+ */
+ void PageNameHasChanged(int nPageIndex, const OUString& rsOldName);
+
+ /** Provide the set of pages to be displayed in the slide sorter. The
+ GetDocumentSlides() method can be found only in the SlideSorterModel.
+ */
+ void SetDocumentSlides(const css::uno::Reference<css::container::XIndexAccess>& rxSlides);
+
+ /** Return an Animator object.
+ */
+ const std::shared_ptr<Animator>& GetAnimator() const { return mpAnimator; }
+
+ VisibleAreaManager& GetVisibleAreaManager() const;
+
+ void CheckForMasterPageAssignment();
+ void CheckForSlideTransitionAssignment();
+
+private:
+ SlideSorter& mrSlideSorter;
+ model::SlideSorterModel& mrModel;
+ view::SlideSorterView& mrView;
+ std::unique_ptr<PageSelector> mpPageSelector;
+ std::unique_ptr<FocusManager> mpFocusManager;
+ std::shared_ptr<SlotManager> mpSlotManager;
+ std::unique_ptr<ScrollBarManager> mpScrollBarManager;
+ mutable std::shared_ptr<CurrentSlideManager> mpCurrentSlideManager;
+ std::shared_ptr<SelectionManager> mpSelectionManager;
+ std::unique_ptr<controller::Clipboard> mpClipboard;
+ std::shared_ptr<InsertionIndicatorHandler> mpInsertionIndicatorHandler;
+ std::shared_ptr<Animator> mpAnimator;
+ std::unique_ptr<VisibleAreaManager> mpVisibleAreaManager;
+
+ // The listener listens to UNO events and thus is a UNO object.
+ ::rtl::Reference<controller::Listener> mpListener;
+
+ int mnModelChangeLockCount;
+ bool mbIsForcedRearrangePending;
+ bool mbContextMenuOpen;
+
+ bool mbPostModelChangePending;
+
+ /** This array stores the indices of the selected page descriptors at
+ the time when the edit mode is switched to EditMode::MasterPage. With this
+ we can restore the selection when switching back to EditMode::Page mode.
+ */
+ ::std::vector<SdPage*> maSelectionBeforeSwitch;
+ /// The current page before the edit mode is switched to EditMode::MasterPage.
+ int mnCurrentPageBeforeSwitch;
+
+ /** The master page to select after the edit mode is changed. This
+ member is used to pass the pointer from PrepareEditModeChange() to
+ FinishEditModeChange().
+ */
+ SdPage* mpEditModeChangeMasterPage;
+
+ /** This rectangle in the parent window encloses scroll bars and slide
+ sorter window. It is set when Resize() is called.
+ */
+ ::tools::Rectangle maTotalWindowArea;
+
+ /** This counter is used to avoid processing of reentrant calls to
+ Paint().
+ */
+ sal_Int32 mnPaintEntranceCount;
+
+ /** Prepare for several model changes, i.e. prevent time-consuming and
+ non-critical operations like repaints until UnlockModelChange() is
+ called. Critical operations like releasing references to pages that
+ do not exist anymore are executed.
+ */
+ void LockModelChange();
+
+ /** Further calls to HandleModelChange() will result in a full featured
+ update of model, view, and controller. When HandleModelChange() has
+ been called since the last LockModelChange() then this is done right
+ away to bring the view up-to-date.
+ */
+ void UnlockModelChange();
+
+ /** Prepare for a model change. This method does all the things that
+ need to be done _before_ the model changes, e.g. because they need
+ access to the model data before the change.
+ */
+ void PreModelChange();
+
+ /** Complete a model change. This includes the recreation of data
+ structures that depend on the model and the request for a repaint to
+ show the changes.
+ */
+ void PostModelChange();
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsAnimationFunction.hxx b/sd/source/ui/slidesorter/inc/controller/SlsAnimationFunction.hxx
new file mode 100644
index 000000000..b4847de1a
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsAnimationFunction.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <basegfx/point/b2dpoint.hxx>
+
+#include <functional>
+#include <vector>
+
+
+namespace sd::slidesorter::controller {
+
+class AnimationBezierFunction
+{
+public:
+ /** Create a cubic bezier curve whose start and end points are given
+ implicitly as P0=(0,0) and P3=(1,1). The second control point is
+ implicitly given as P2=(1-nY1,1-nX1).
+ */
+ AnimationBezierFunction (
+ const double nX1,
+ const double nY1);
+
+ ::basegfx::B2DPoint operator() (const double nT);
+
+private:
+ const double mnX1;
+ const double mnY1;
+ const double mnX2;
+ const double mnY2;
+
+ static double EvaluateComponent (
+ const double nT,
+ const double nV1,
+ const double nV2);
+};
+
+/** Turn a parametric function into one whose y-Values depend on its
+ x-Values. Note a lot of interpolation takes place. The resulting
+ accuracy should be good enough for the purpose of acceleration
+ function for animations.
+*/
+class AnimationParametricFunction
+{
+public:
+ typedef ::std::function<basegfx::B2DPoint (double)> ParametricFunction;
+ AnimationParametricFunction (const ParametricFunction& rFunction);
+
+ double operator() (const double nX);
+
+private:
+ /** y-Values of the parametric function given to the constructor
+ evaluated (and interpolated) for evenly spaced x-Values.
+ */
+ ::std::vector<double> maY;
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx b/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx
new file mode 100644
index 000000000..8c9ec9e81
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <view/SlideSorterView.hxx>
+#include <canvas/elapsedtime.hxx>
+#include <vcl/idle.hxx>
+#include <sal/types.h>
+#include <o3tl/deleter.hxx>
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace sd::slidesorter { class SlideSorter; }
+
+namespace sd::slidesorter::controller {
+
+/** Experimental class for simple eye candy animations.
+*/
+class Animator
+{
+public:
+ /** In some circumstances we have to avoid animation and jump to the
+ final animation state immediately. Use this enum instead of a bool
+ to be more expressive.
+ */
+ enum AnimationMode { AM_Animated, AM_Immediate };
+
+ explicit Animator (SlideSorter& rSlideSorter);
+ ~Animator();
+ Animator(const Animator&) = delete;
+ Animator& operator=(const Animator&) = delete;
+
+ /** When disposed the animator will stop its work immediately and not
+ process any timer events anymore.
+ */
+ void Dispose();
+
+ /** An animation object is called with values between 0 and 1 as single
+ argument to its operator() method.
+ */
+ typedef ::std::function<void (double)> AnimationFunctor;
+ typedef ::std::function<void ()> FinishFunctor;
+
+ typedef sal_Int32 AnimationId;
+ static const AnimationId NotAnAnimationId = -1;
+
+ /** Schedule a new animation for execution. The () operator of that
+ animation will be called with increasing values between 0 and 1 for
+ the specified duration.
+ @param rAnimation
+ The animation operation.
+ */
+ AnimationId AddAnimation (
+ const AnimationFunctor& rAnimation,
+ const FinishFunctor& rFinishFunctor);
+
+ /** Abort and remove an animation. In order to reduce the bookkeeping
+ on the caller side, it is OK to call this method with an animation
+ function that is not currently being animated. Such a call is
+ silently ignored.
+ */
+ void RemoveAnimation (const AnimationId nAnimationId);
+
+ /** A typical use case for this method is the temporary shutdown of the
+ slidesorter when the slide sorter bar is put into a cache due to a
+ change of the edit mode.
+ */
+ void RemoveAllAnimations();
+
+private:
+ SlideSorter& mrSlideSorter;
+ Idle maIdle;
+ bool mbIsDisposed;
+ class Animation;
+ typedef ::std::vector<std::shared_ptr<Animation> > AnimationList;
+ AnimationList maAnimations;
+ ::canvas::tools::ElapsedTime maElapsedTime;
+
+ std::unique_ptr<view::SlideSorterView::DrawLock, o3tl::default_delete<view::SlideSorterView::DrawLock>> mpDrawLock;
+
+ AnimationId mnNextAnimationId;
+
+ DECL_LINK(TimeoutHandler, Timer *, void);
+
+ /** Execute one step of every active animation.
+ @param nTime
+ Time measured in milliseconds with some arbitrary reference point.
+ @return
+ When one or more animation has finished then <TRUE/> is
+ returned. Call CleanUpAnimationList() in this case.
+ */
+ bool ProcessAnimations (const double nTime);
+
+ /** Remove animations that have expired.
+ */
+ void CleanUpAnimationList();
+
+ void RequestNextFrame();
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx b/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx
new file mode 100644
index 000000000..6ced17486
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <ViewClipboard.hxx>
+#include <controller/SlsSelectionObserver.hxx>
+#include <sdxfer.hxx>
+
+#include <sal/types.h>
+#include <o3tl/deleter.hxx>
+#include <svx/svdtypes.hxx>
+
+#include <sddllapi.h>
+
+class SfxRequest;
+struct AcceptDropEvent;
+class DropTargetHelper;
+struct ExecuteDropEvent;
+struct ImplSVEvent;
+class Point;
+class SdPage;
+namespace vcl { class Window; }
+
+namespace sd {
+class Window;
+}
+
+namespace sd::slidesorter { class SlideSorter; }
+
+namespace sd::slidesorter::controller {
+
+class SlideSorterController;
+
+class SAL_DLLPUBLIC_RTTI Clipboard final
+ : public ViewClipboard
+{
+public:
+ Clipboard (SlideSorter& rSlideSorter);
+ virtual ~Clipboard() override;
+
+ /** Create a slide sorter transferable from the given sd
+ transferable. The returned transferable is set up with all
+ information necessary so that it can be dropped on a slide sorter.
+ */
+ static std::shared_ptr<SdTransferable::UserData> CreateTransferableUserData (SdTransferable* pTransferable);
+
+ void HandleSlotCall (SfxRequest& rRequest);
+
+ void DoCut ();
+ // Exported for unit test
+ SD_DLLPUBLIC void DoCopy();
+ // Exported for unit test
+ SD_DLLPUBLIC void DoPaste();
+ void DoDelete ();
+
+ void StartDrag (
+ const Point& rDragPt,
+ vcl::Window* pWindow );
+
+ void DragFinished (
+ sal_Int8 nDropAction);
+
+ sal_Int8 AcceptDrop (
+ const AcceptDropEvent& rEvt,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer );
+
+ sal_Int8 ExecuteDrop (
+ const ExecuteDropEvent& rEvt,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer );
+
+ void Abort();
+
+private:
+ virtual sal_uInt16 DetermineInsertPosition () override;
+
+ SlideSorter& mrSlideSorter;
+ SlideSorterController& mrController;
+
+ typedef ::std::vector<SdPage*> PageList;
+ /** Remember the pages that are dragged to another document or to
+ another place in the same document so that they can be removed after
+ a move operation.
+ */
+ PageList maPagesToRemove;
+
+ /** Used when a drop is executed to combine all undo actions into one.
+ Typically created in ExecuteDrop() and released in DragFinish().
+ */
+ class UndoContext;
+ std::unique_ptr<UndoContext> mxUndoContext;
+
+ std::unique_ptr<SelectionObserver::Context, o3tl::default_delete<SelectionObserver::Context>> mxSelectionObserverContext;
+ ImplSVEvent * mnDragFinishedUserEventId;
+
+ void CreateSlideTransferable (
+ vcl::Window* pWindow,
+ bool bDrag);
+
+ /** Determine the position of where to insert the pages in the current
+ transferable of the sd module.
+ @return
+ The index in the range [0,n] (both inclusive) with n the number
+ of pages is returned.
+ */
+ sal_Int32 GetInsertionPosition ();
+
+ /** Paste the pages of the transferable of the sd module at the given
+ position.
+ @param nInsertPosition
+ The position at which to insert the pages. The valid range is
+ [0,n] (both inclusive) with n the number of pages in the
+ document.
+ @return
+ The number of inserted pages is returned.
+ */
+ sal_Int32 PasteTransferable (sal_Int32 nInsertPosition);
+
+ /** Select a range of pages of the model. Typically usage is the
+ selection of newly inserted pages.
+ @param nFirstIndex
+ The index of the first page to select.
+ @param nPageCount
+ The number of pages to select.
+ */
+ void SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount);
+
+ /** Return <TRUE/> when the current transferable in the current state of
+ the slidesorter is acceptable to be pasted. For this the
+ transferable has to
+ a) exist,
+ b) contain one or more regular draw pages, no master pages.
+ When master pages are involved, either in the transferable or in the
+ slide sorter (by it displaying master pages) the drop of the
+ transferable is not accepted. The reason is the missing
+ implementation of proper handling master pages copy-and-paste.
+ */
+ enum DropType { DT_PAGE, DT_PAGE_FROM_NAVIGATOR, DT_SHAPE, DT_NONE };
+ DropType IsDropAccepted() const;
+
+ /** This method contains the code for AcceptDrop() and ExecuteDrop() shapes.
+ There are only minor differences for the two cases at this level.
+ @param eCommand
+ This parameter specifies whether to do an AcceptDrop() or
+ ExecuteDrop().
+ @param rPosition
+ Since the event is given as void pointer we can not take the
+ mouse position from it. The caller has to supply it in this
+ parameter.
+ @param pDropEvent
+ Event though the AcceptDropEvent and ExecuteDropEvent are very
+ similar they do not have a common base class. Because of that
+ we have to use a void* to pass these structs.
+ @param nPage
+ When the page number is given as 0xffff then it is replaced by
+ the number of the page at the mouse position. If the mouse is
+ not over a page then neither AcceptDrop() nor ExecuteDrop() are
+ executed.
+ */
+ enum DropCommand { DC_ACCEPT, DC_EXECUTE };
+ sal_Int8 ExecuteOrAcceptShapeDrop (
+ DropCommand eCommand,
+ const Point& rPosition,
+ const void* pDropEvent ,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer);
+
+ /** Return whether the insertion defined by the transferable is
+ trivial, ie would not change either source nor target document.
+ */
+ bool IsInsertionTrivial (
+ SdTransferable const * pTransferable,
+ const sal_Int8 nDndAction) const;
+
+ /** Asynchronous part of DragFinished. The argument is the sal_Int8
+ nDropAction, disguised as void*.
+ */
+ DECL_DLLPRIVATE_LINK(ProcessDragFinished, void*, void);
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx
new file mode 100644
index 000000000..0c5b3b243
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsSharedPageDescriptor.hxx>
+#include <vcl/timer.hxx>
+#include <tools/link.hxx>
+
+class SdPage;
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+
+namespace sd::slidesorter::controller
+{
+/** Manage the current slide. This includes setting the according flags at
+ the PageDescriptor objects and setting the current slide at the main
+ view shell.
+
+ Switching pages is triggered only after a little delay. This allows
+ fast travelling through a larger set of slides without having to wait
+ for the edit view to update its content after every slide change.
+*/
+class CurrentSlideManager
+{
+public:
+ /** Create a new CurrentSlideManager object that manages the current
+ slide for the given SlideSorter.
+ */
+ CurrentSlideManager(SlideSorter& rSlideSorter);
+
+ ~CurrentSlideManager();
+
+ /** Call this when the current page of the main view shell has been
+ switched. Use SwitchCurrentSlide() to initiate such a switch.
+ */
+ void NotifyCurrentSlideChange(const sal_Int32 nSlideIndex);
+ void NotifyCurrentSlideChange(const SdPage* pPage);
+
+ /** Call this method to switch the current page of the main view shell
+ to the given slide. Use CurrentSlideHasChanged() when the current
+ slide change has been initiated by someone else.
+ @param nSlideIndex
+ Zero based index in the range [0,number-of-slides).
+ The page selection is cleared and only the new
+ current slide is selected.
+ */
+ void SwitchCurrentSlide(const sal_Int32 nSlideIndex);
+ void SwitchCurrentSlide(const model::SharedPageDescriptor& rpSlide,
+ const bool bUpdateSelection = false);
+
+ /** Return the page descriptor for the current slide. Note, that when
+ there is no current slide then the returned pointer is empty.
+ */
+ const model::SharedPageDescriptor& GetCurrentSlide() const { return mpCurrentSlide; }
+
+ /** Release all references to model data.
+ */
+ void PrepareModelChange();
+
+ /** Modify inner state in reaction to a change of the SlideSorterModel.
+ */
+ void HandleModelChange();
+
+private:
+ SlideSorter& mrSlideSorter;
+ sal_Int32 mnCurrentSlideIndex;
+ model::SharedPageDescriptor mpCurrentSlide;
+ /** Timer to control the delay after which to ask
+ XController/ViewShellBase to switch to another slide.
+ */
+ Timer maSwitchPageDelayTimer;
+
+ void SetCurrentSlideAtViewShellBase(const model::SharedPageDescriptor& rpSlide);
+ void SetCurrentSlideAtTabControl(const model::SharedPageDescriptor& rpSlide);
+ void SetCurrentSlideAtXController(const model::SharedPageDescriptor& rpSlide);
+
+ /** When switching from one slide to a new current slide then this
+ method releases all ties to the old slide.
+ */
+ void ReleaseCurrentSlide();
+
+ /** When switching from one slide to a new current slide then this
+ method connects to the new current slide.
+ */
+ void AcquireCurrentSlide(const sal_Int32 nSlideIndex);
+
+ DECL_LINK(SwitchPageCallback, Timer*, void);
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx
new file mode 100644
index 000000000..180b7143f
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsSharedPageDescriptor.hxx>
+
+#include <sal/types.h>
+#include <tools/link.hxx>
+#include <vector>
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+
+namespace sd::slidesorter::controller
+{
+/** This class manages the focus of the slide sorter. There is the focus
+ page which is or is not focused. Initialized to point to the first page
+ it can be set to other pages by using the MoveFocus() method. The
+ focused state of the focus page can be toggled with the ToggleFocus()
+ method.
+*/
+class FocusManager
+{
+public:
+ /** Create a new focus manager that operates on the pages of the model
+ associated with the given controller. The focus page is set to the
+ first page. Focused state is off.
+ */
+ FocusManager(SlideSorter& rSlideSorter);
+
+ ~FocusManager();
+
+ enum class FocusMoveDirection
+ {
+ Left,
+ Right,
+ Up,
+ Down
+ };
+
+ /** Move the focus from the currently focused page to one that is
+ displayed adjacent to it, either vertically or horizontally.
+ @param eDirection
+ Direction in which to move the focus. Wrap around is done
+ differently when moving vertically or horizontally. Vertical
+ wrap around takes place in the same column, i.e. when you are
+ in the top row and move up you come out in the bottom row in the
+ same column. Horizontal wrap around moves to the next
+ (FocusMoveDirection::Right) or previous (FocusMoveDirection::Left) page. Moving to the right
+ from the last page goes to the first page and vice versa.
+ The current page index is set to the nearest valid
+ page index.
+ */
+ void MoveFocus(FocusMoveDirection eDirection);
+
+ /** Show the focus indicator of the current slide.
+ @param bScrollToFocus
+ When <TRUE/> (the default) then the view is scrolled so that the
+ focus rectangle lies inside its visible area.
+ */
+ void ShowFocus(const bool bScrollToFocus = true);
+
+ /** Hide the focus indicator.
+ */
+ void HideFocus();
+
+ /** Toggle the focused state of the current slide.
+ @return
+ Returns the focused state of the focus page after the call.
+ */
+ bool ToggleFocus();
+
+ /** Return whether the window managed by the called focus manager has
+ the input focus of the application.
+ */
+ bool HasFocus() const;
+
+ /** Return the descriptor of the page that currently has the focus.
+ @return
+ When there is no page that currently has the focus then NULL is
+ returned.
+ */
+ model::SharedPageDescriptor GetFocusedPageDescriptor() const;
+
+ /** Return the index of the page that currently has the focus as it is
+ accepted by the slide sorter model.
+ @return
+ When there is no page that currently has the focus then -1 is
+ returned.
+ */
+ sal_Int32 GetFocusedPageIndex() const { return mnPageIndex; }
+
+ /** Set the focused page to the one described by the given page
+ descriptor. The visibility of the focus indicator is not modified.
+ @param rDescriptor
+ One of the page descriptors that are currently managed by the
+ SlideSorterModel.
+ */
+ bool SetFocusedPage(const model::SharedPageDescriptor& rDescriptor);
+
+ /** Set the focused page to the one described by the given page
+ index. The visibility of the focus indicator is not modified.
+ @param nPageIndex
+ A valid page index that is understood by the SlideSorterModel.
+ */
+ void SetFocusedPage(sal_Int32 nPageIndex);
+
+ bool SetFocusedPageToCurrentPage();
+
+ /** Return <TRUE/> when the focus indicator is currently shown. A
+ prerequisite is that the window managed by this focus manager has
+ the input focus as indicated by a <TRUE/> return value of
+ HasFocus(). It is not necessary that the focus indicator is
+ visible. It may have been scrolled outside the visible area.
+ */
+ bool IsFocusShowing() const;
+
+ /** Add a listener that is called when the focus is shown or hidden or
+ set to another page object.
+ @param rListener
+ When this method is called multiple times for the same listener
+ the second and all following calls are ignored. Each listener
+ is added only once.
+ */
+ void AddFocusChangeListener(const Link<LinkParamNone*, void>& rListener);
+
+ /** Remove a focus change listener.
+ @param rListener
+ It is safe to pass a listener that was not added are has been
+ removed previously. Such calls are ignored.
+ */
+ void RemoveFocusChangeListener(const Link<LinkParamNone*, void>& rListener);
+
+ /** Create an instance of this class to temporarily hide the focus
+ indicator. It is restored to its former visibility state when the
+ FocusHider is destroyed.
+ */
+ class FocusHider
+ {
+ public:
+ FocusHider(FocusManager&);
+ ~FocusHider() COVERITY_NOEXCEPT_FALSE;
+
+ private:
+ bool mbFocusVisible;
+ FocusManager& mrManager;
+ };
+
+private:
+ SlideSorter& mrSlideSorter;
+
+ /** Index of the page that may be focused. It is -1 when the model
+ contains no page.
+ */
+ sal_Int32 mnPageIndex;
+
+ /** This flag indicates whether the page pointed to by mpFocusDescriptor
+ has the focus.
+ */
+ bool mbPageIsFocused;
+
+ ::std::vector<Link<LinkParamNone*, void>> maFocusChangeListeners;
+
+ /** Reset the focus state of the given descriptor and request a repaint
+ so that the focus indicator is hidden.
+ @param pDescriptor
+ When NULL is given then the call is ignored.
+ */
+ void HideFocusIndicator(const model::SharedPageDescriptor& rpDescriptor);
+
+ /** Set the focus state of the given descriptor, scroll it into the
+ visible area and request a repaint so that the focus indicator is
+ made visible.
+ @param pDescriptor
+ When NULL is given then the call is ignored.
+ @param bScrollToFocus
+ When <TRUE/> (the default) then the view is scrolled so that the
+ focus rectangle lies inside its visible area.
+ */
+ void ShowFocusIndicator(const model::SharedPageDescriptor& rpDescriptor,
+ const bool bScrollToFocus);
+
+ /** Call all currently registered listeners that a focus change has
+ happened. The focus may be hidden or shown or moved from one page
+ object to another.
+ */
+ void NotifyFocusChangeListeners() const;
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsInsertionIndicatorHandler.hxx b/sd/source/ui/slidesorter/inc/controller/SlsInsertionIndicatorHandler.hxx
new file mode 100644
index 000000000..43f2d2f6a
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsInsertionIndicatorHandler.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <controller/SlsAnimator.hxx>
+
+#include <view/SlsLayouter.hxx>
+
+namespace sd::slidesorter { class SlideSorter; }
+namespace sd::slidesorter::view {
+class InsertAnimator;
+class InsertionIndicatorOverlay;
+}
+
+class SdTransferable;
+
+namespace sd::slidesorter::controller {
+
+/** Manage the visibility and location of the insertion indicator. Its
+ actual display is controlled by the InsertionIndicatorOverlay.
+*/
+class InsertionIndicatorHandler
+{
+public:
+ InsertionIndicatorHandler (SlideSorter& rSlideSorter);
+ ~InsertionIndicatorHandler() COVERITY_NOEXCEPT_FALSE;
+
+ enum Mode { CopyMode, MoveMode, UnknownMode };
+ static Mode GetModeFromDndAction (const sal_Int8 nDndAction);
+
+ /** Activate the insertion marker at the given coordinates.
+ */
+ void Start (const bool bIsOverSourceView);
+
+ /** Deactivate the insertion marker.
+ */
+ void End (const controller::Animator::AnimationMode eMode);
+
+ /** This context make sure that the insertion indicator is shown
+ (provided that the clipboard is not empty) while the context is
+ alive. Typically used while a context menu is displayed.
+ */
+ class ForceShowContext
+ {
+ public:
+ ForceShowContext (const std::shared_ptr<InsertionIndicatorHandler>& rpHandler);
+ ~ForceShowContext() COVERITY_NOEXCEPT_FALSE;
+ private:
+ const std::shared_ptr<InsertionIndicatorHandler> mpHandler;
+ };
+
+ /** Update the indicator icon from the current transferable (from the
+ clipboard or an active drag and drop operation.)
+ */
+ void UpdateIndicatorIcon (const SdTransferable* pTransferable);
+
+ /** Set the position of the insertion marker to the given coordinates.
+ */
+ void UpdatePosition (
+ const Point& rMouseModelPosition,
+ const Mode eMode);
+ void UpdatePosition (
+ const Point& rMouseModelPosition,
+ const sal_Int8 nDndAction);
+
+ /** Return whether the insertion marker is active.
+ */
+ bool IsActive() const { return mbIsActive;}
+
+ /** Return the insertion index that corresponds with the current
+ graphical location of the insertion indicator.
+ */
+ sal_Int32 GetInsertionPageIndex() const;
+
+ /** Determine whether moving the current selection to the current
+ position of the insertion marker would alter the document. This
+ would be the case when the selection is not consecutive or would be
+ moved to a position outside and not adjacent to the selection.
+ */
+ bool IsInsertionTrivial (
+ const sal_Int32 nInsertionIndex,
+ const Mode eMode) const;
+ /** This method is like the other variant. It operates implicitly
+ on the current insertion index as would be returned by
+ GetInsertionPageIndex().
+ */
+ bool IsInsertionTrivial (const sal_Int8 nDndAction);
+
+private:
+ SlideSorter& mrSlideSorter;
+ std::shared_ptr<view::InsertAnimator> mpInsertAnimator;
+ std::shared_ptr<view::InsertionIndicatorOverlay> mpInsertionIndicatorOverlay;
+ view::InsertPosition maInsertPosition;
+ Mode meMode;
+ bool mbIsInsertionTrivial;
+ bool mbIsActive;
+ bool mbIsReadOnly;
+ bool mbIsOverSourceView;
+ Size maIconSize;
+ bool mbIsForcedShow;
+
+ void SetPosition (
+ const Point& rPoint,
+ const Mode eMode);
+ std::shared_ptr<view::InsertAnimator> const & GetInsertAnimator();
+
+ /** Make the insertion indicator visible (that is the show part) and
+ keep it visible, even when the mouse leaves the window (that is the
+ force part). We need this when a context menu is displayed (mouse
+ over the popup menu triggers a mouse leave event) while the
+ insertion indicator remains visible in the background.
+
+ In effect all calls to End() are ignored until ForceEnd() is called.
+ */
+ void ForceShow();
+ void ForceEnd();
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx b/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx
new file mode 100644
index 000000000..6a4b75004
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx
@@ -0,0 +1,219 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsSharedPageDescriptor.hxx>
+
+#include <vector>
+#include <memory>
+
+#include <sddllapi.h>
+
+class SdPage;
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+namespace sd::slidesorter::model
+{
+class SlideSorterModel;
+}
+
+namespace sd::slidesorter::controller
+{
+class SlideSorterController;
+
+/** A sub-controller that handles page selection of the slide browser.
+ Selecting a page does not make it the current page (of the main view)
+ automatically as this would not be desired in a multi selection. This
+ has to be done explicitly by calling the
+ CurrentSlideManager::SetCurrentSlide() method.
+
+ Indices of pages relate always to the number of all pages in the model
+ (as returned by GetPageCount()) not just the selected pages.
+*/
+class PageSelector
+{
+public:
+ explicit PageSelector(SlideSorter& rSlideSorter);
+ PageSelector(const PageSelector&) = delete;
+ PageSelector& operator=(const PageSelector&) = delete;
+
+ // Exported for unit test
+ SD_DLLPUBLIC void SelectAllPages();
+ SD_DLLPUBLIC void DeselectAllPages();
+
+ /** Update the selection state of all page descriptors to be the same as
+ that of the corresponding pages of the SdPage objects and issue
+ redraw requests where necessary.
+ */
+ void GetCoreSelection();
+
+ /** Update the selection state of the SdPage objects to be the same as
+ that of the corresponding page descriptors.
+ */
+ void SetCoreSelection();
+
+ /** Select the specified descriptor. The selection state of the other
+ descriptors is not affected.
+ */
+ void SelectPage(int nPageIndex);
+ /** Select the descriptor that is associated with the given page. The
+ selection state of the other descriptors is not affected.
+ */
+ void SelectPage(const SdPage* pPage);
+ /** Select the specified descriptor. The selection state of the other
+ descriptors is not affected.
+ */
+ void SelectPage(const model::SharedPageDescriptor& rpDescriptor);
+
+ /** Return whether the specified page is selected. This convenience
+ method is a substitute for
+ SlideSorterModel::GetPageDescriptor(i)->HasState(ST_Selected) is
+ included here to make this class more self contained.
+ */
+ SD_DLLPUBLIC bool IsPageSelected(int nPageIndex);
+
+ /** Return whether the specified page is visible. This convenience
+ method is a substitute for
+ SlideSorterModel::GetPageDescriptor(i)->HasState(ST_Visible) is
+ included here to make this class more self contained.
+ */
+ bool IsPageVisible(int nPageIndex);
+
+ /** Deselect the descriptor that is associated with the given page.
+ The current page is updated to the first slide
+ of the remaining selection.
+ */
+ void DeselectPage(int nPageIndex);
+ void DeselectPage(const model::SharedPageDescriptor& rpDescriptor,
+ const bool bUpdateCurrentPage = true);
+
+ /** This convenience method returns the same number of pages that
+ SlideSorterModel.GetPageCount() returns. It is included here so
+ that it is self contained for iterating over all pages to select or
+ deselect them.
+ */
+ int GetPageCount() const;
+ int GetSelectedPageCount() const { return mnSelectedPageCount; }
+
+ /** Return the anchor for a range selection. This usually is the first
+ selected page after all pages have been deselected.
+ @return
+ The returned anchor may be NULL.
+ */
+ const model::SharedPageDescriptor& GetSelectionAnchor() const { return mpSelectionAnchor; }
+
+ typedef ::std::vector<SdPage*> PageSelection;
+
+ /** Return an object that describes the current selection. The caller
+ can use that object to later restore the selection.
+ @return
+ The object returned describes the selection via indices. So
+ even if pages are exchanged a later call to SetPageSelection()
+ is valid.
+ */
+ std::shared_ptr<PageSelection> GetPageSelection() const;
+
+ /** Restore a page selection according to the given selection object.
+ @param rSelection
+ Typically obtained by calling GetPageSelection() this object
+ is used to restore the selection. If pages were exchanged since
+ the last call to GetPageSelection() it is still valid to call
+ this method with the selection. When pages have been inserted
+ or removed the result may be unexpected.
+ @param bUpdateCurrentPage
+ When <TRUE/> (the default value) then after setting the
+ selection update the current page to the first page of the
+ selection.
+ When called from within UpdateCurrentPage() then this flag is
+ used to prevent a recursion loop.
+ */
+ void SetPageSelection(const std::shared_ptr<PageSelection>& rSelection,
+ const bool bUpdateCurrentPage);
+
+ /** Call this method after the model has changed to set the number
+ of selected pages.
+ */
+ void CountSelectedPages();
+
+ /** Use the UpdateLock whenever you do a complex selection, i.e. call
+ more than one method in a row. An active lock prevents intermediate
+ changes of the current slide.
+ */
+ class UpdateLock
+ {
+ public:
+ UpdateLock(SlideSorter const& rSlideSorter);
+ UpdateLock(PageSelector& rPageSelector);
+ ~UpdateLock();
+ void Release();
+
+ private:
+ PageSelector* mpSelector;
+ };
+
+ class BroadcastLock
+ {
+ public:
+ BroadcastLock(SlideSorter const& rSlideSorter);
+ BroadcastLock(PageSelector& rPageSelector);
+ ~BroadcastLock();
+
+ private:
+ PageSelector& mrSelector;
+ };
+
+private:
+ model::SlideSorterModel& mrModel;
+ SlideSorter& mrSlideSorter;
+ SlideSorterController& mrController;
+ int mnSelectedPageCount;
+ int mnBroadcastDisableLevel;
+ bool mbSelectionChangeBroadcastPending;
+ model::SharedPageDescriptor mpMostRecentlySelectedPage;
+ /// Anchor for a range selection.
+ model::SharedPageDescriptor mpSelectionAnchor;
+ sal_Int32 mnUpdateLockCount;
+ bool mbIsUpdateCurrentPagePending;
+
+ /** Enable the broadcasting of selection change events. This calls the
+ SlideSorterController::SelectionHasChanged() method to do the actual
+ work. When EnableBroadcasting has been called as many times as
+ DisableBroadcasting() was called before and the selection has been
+ changed in the meantime, this change will be broadcasted.
+ */
+ void EnableBroadcasting();
+
+ /** Disable the broadcasting of selection change events. Subsequent
+ changes of the selection will set a flag that triggers the sending
+ of events when EnableBroadcasting() is called.
+ */
+ void DisableBroadcasting();
+
+ void UpdateCurrentPage(const bool bUpdateOnlyWhenPending = false);
+
+ void CheckConsistency() const;
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx b/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx
new file mode 100644
index 000000000..344ac67f3
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/color.hxx>
+
+namespace sd::slidesorter::controller
+{
+/** An extensible set of properties used throughout the slide sorter.
+*/
+class Properties
+{
+public:
+ Properties();
+
+ /** Call this method after receiving a VclEventId::ApplicationDataChanged
+ event.
+ */
+ void HandleDataChangeEvent();
+
+ /** When this method returns <TRUE/> then the current slide is
+ highlighted in the view. The default value is <FALSE/>.
+ */
+ bool IsHighlightCurrentSlide() const { return mbIsHighlightCurrentSlide; }
+ void SetHighlightCurrentSlide(const bool bIsHighlightCurrentSlide);
+
+ /** When this method returns <TRUE/> then the selection is indicated in
+ the view (typically by drawing rectangles around the selected
+ slides.) The default value is <TRUE/>.
+ */
+ bool IsShowSelection() const { return mbIsShowSelection; }
+ void SetShowSelection(const bool bIsShowSelection);
+
+ /** When this method returns <TRUE/> then the focusdselection is indicated in
+ the view (typically by drawing dotted rectangles around the selected
+ slides.) The default value is <TRUE/>.
+ */
+ bool IsShowFocus() const { return mbIsShowFocus; }
+ void SetShowFocus(const bool bIsShowFocus);
+
+ /** When this method returns <TRUE/> then on a selection change the
+ visible area is adapted so that the selected slides are shown
+ centered in the view. This can be used to center the current slide
+ by selecting only the current slide. The default value is <FALSE/>.
+ */
+ bool IsCenterSelection() const { return mbIsCenterSelection; }
+ void SetCenterSelection(const bool bIsCenterSelection);
+
+ /** When this method returns <TRUE/> then the view may try to change the
+ visible area by scrolling it smoothly on the screen. Experimental.
+ Default value is <FALSE/>.
+ */
+ bool IsSmoothSelectionScrolling() const { return mbIsSmoothSelectionScrolling; }
+ void SetSmoothSelectionScrolling(const bool bIsSmoothSelectionScrolling);
+
+ /** When this method returns <TRUE/> then during a full screen
+ presentation the previews in a slide sorter are not updated.
+ Default value is <TRUE/>.
+ */
+ bool IsSuspendPreviewUpdatesDuringFullScreenPresentation() const
+ {
+ return mbIsSuspendPreviewUpdatesDuringFullScreenPresentation;
+ }
+ void SetSuspendPreviewUpdatesDuringFullScreenPresentation(const bool bFlag);
+
+ /** Return the background color.
+ */
+ const Color& GetBackgroundColor() const { return maBackgroundColor; }
+ void SetBackgroundColor(const Color& rColor);
+
+ /** Return the text color.
+ */
+ const Color& GetTextColor() const { return maTextColor; }
+ void SetTextColor(const Color& rColor);
+
+ /** Return the color in which selections are to be painted.
+ */
+ const Color& GetSelectionColor() const { return maSelectionColor; }
+ void SetSelectionColor(const Color& rColor);
+
+ /** Return the color used for highlighting e.g. the current slide.
+ */
+ const Color& GetHighlightColor() const { return maHighlightColor; }
+ void SetHighlightColor(const Color& rColor);
+
+ /** The UI can be set to be read only independently from the model status.
+ Used for instance in the presenter view.
+ */
+ bool IsUIReadOnly() const { return mbIsUIReadOnly; }
+ void SetUIReadOnly(const bool bIsUIReadOnly);
+
+private:
+ bool mbIsHighlightCurrentSlide;
+ bool mbIsShowSelection;
+ bool mbIsShowFocus;
+ bool mbIsCenterSelection;
+ bool mbIsSmoothSelectionScrolling;
+ bool mbIsSuspendPreviewUpdatesDuringFullScreenPresentation;
+ Color maBackgroundColor;
+ Color maTextColor;
+ Color maSelectionColor;
+ Color maHighlightColor;
+ bool mbIsUIReadOnly;
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx
new file mode 100644
index 000000000..853d98f4a
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <tools/link.hxx>
+#include <tools/gen.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/scrbar.hxx>
+#include <vcl/vclptr.hxx>
+
+#include <functional>
+
+namespace sd { class Window; }
+
+namespace sd::slidesorter { class SlideSorter; }
+
+namespace sd::slidesorter::controller {
+
+/** Manage the horizontal and vertical scroll bars. Listen for events, set
+ their sizes, place them in the window, determine their visibilities.
+
+ <p>Handle auto scrolling, i.e. the scrolling of the window when the
+ mouse comes near the window border while dragging a selection.</p>
+
+ <p>In order to make the slide sorter be used in the task pane with its
+ own vertical scrollbars the vertical scrollbar of the use of the slide
+ sorter is optional. When using it the available area in a window is
+ used and the vertical scrollbar is displayed when that area is not large
+ enough. When the vertical scrollbar is not used then the available area
+ is assumed to be modifiable. In that case the PlaceScrollBars() method
+ may return an area larger than the one given.<p>
+*/
+class ScrollBarManager
+{
+public:
+ /** Create a new scroll bar manager that manages three controls: the
+ horizontal scroll bar, the vertical scroll bar, and the little
+ window that fills the gap at the bottom right corner that is left
+ between the two scroll bars. Call LateInitialization() after
+ constructing a new object.
+ */
+ ScrollBarManager (SlideSorter& rSlideSorter);
+
+ ~ScrollBarManager();
+
+ /** Register listeners at the scroll bars. This method is called after
+ startup of a new slide sorter object or after a reactivation of a
+ slide sorter that for example is taken from a cache.
+ */
+ void Connect();
+
+ /** Remove listeners from the scroll bars. This method is called when
+ the slide sorter is destroyed or when it is suspended, e.g. put
+ into a cache for later reuse.
+ */
+ void Disconnect();
+
+ /** Set up the scroll bar, i.e. thumb size and position. Call this
+ method when the content of the browser window changed, i.e. pages
+ were inserted or deleted, the layout or the zoom factor has
+ changed.
+ @param bScrollToCurrentPosition
+ When <TRUE/> then scroll the window to the new offset that is
+ defined by the scroll bars. Otherwise the new offset is simply
+ set and the whole window is repainted.
+ */
+ void UpdateScrollBars (
+ bool bScrollToCurrentPosition);
+
+ /** Place the scroll bars inside the given area. When the available
+ area is not large enough for the content to display the horizontal
+ and/or vertical scroll bar is enabled.
+ @param rAvailableArea
+ The scroll bars will be placed inside this rectangle. It is
+ expected to be given in pixel relative to its parent.
+ @param bIsHorizontalScrollBarAllowed
+ Only when this flag is <TRUE/> the horizontal scroll may be
+ displayed.
+ @param bIsVerticalScrollBarAllowed
+ Only when this flag is <TRUE/> the horizontal scroll may be
+ displayed.
+ @return
+ Returns the space that remains after the scroll bars are
+ placed.
+ */
+ ::tools::Rectangle PlaceScrollBars (
+ const ::tools::Rectangle& rAvailableArea,
+ const bool bIsHorizontalScrollBarAllowed,
+ const bool bIsVerticalScrollBarAllowed);
+
+ /** Update the vertical and horizontal scroll bars so that the visible
+ area has the given top and left values.
+ */
+ void SetTopLeft (const Point& rNewTopLeft);
+
+ /** Return the width of the vertical scroll bar, which--when
+ shown--should be fixed in contrast to its height.
+ @return
+ Returns 0 when the vertical scroll bar is not shown or does not
+ exist, otherwise its width in pixel is returned.
+ */
+ int GetVerticalScrollBarWidth() const;
+
+ /** Return the height of the horizontal scroll bar, which--when
+ shown--should be fixed in contrast to its width.
+ @return
+ Returns 0 when the vertical scroll bar is not shown or does not
+ exist, otherwise its height in pixel is returned.
+ */
+ int GetHorizontalScrollBarHeight() const;
+
+ /** Call this method to scroll a window while the mouse is in dragging a
+ selection. If the mouse is near the window border or is outside the
+ window then scroll the window accordingly.
+ @param rMouseWindowPosition
+ The mouse position for which the scroll amount is calculated.
+ @param rAutoScrollFunctor
+ Every time when the window is scrolled then this functor is executed.
+ @return
+ When the window is scrolled then this method returns <TRUE/>.
+ When the window is not changed then <FALSE/> is returned.
+ */
+ bool AutoScroll (
+ const Point& rMouseWindowPosition,
+ const ::std::function<void ()>& rAutoScrollFunctor);
+
+ void StopAutoScroll();
+
+ void clearAutoScrollFunctor();
+
+ enum Orientation { Orientation_Horizontal, Orientation_Vertical };
+ /** Scroll the slide sorter by setting the thumbs of the scroll bars and
+ by moving the content of the content window.
+ @param eOrientation
+ Defines whether to scroll horizontally or vertically.
+ @param nDistance
+ distance in slides.
+ */
+ void Scroll(
+ const Orientation eOrientation,
+ const sal_Int32 nDistance);
+
+private:
+ SlideSorter& mrSlideSorter;
+
+ /** The horizontal scroll bar. Note that is used but not owned by
+ objects of this class. It is given to the constructor.
+ */
+ VclPtr<ScrollBar> mpHorizontalScrollBar;
+
+ /** The vertical scroll bar. Note that is used but not owned by
+ objects of this class. It is given to the constructor.
+ */
+ VclPtr<ScrollBar> mpVerticalScrollBar;
+
+ /// Relative horizontal position of the visible area in the view.
+ double mnHorizontalPosition;
+ /// Relative vertical position of the visible area in the view.
+ double mnVerticalPosition;
+ /** The width and height of the border at the inside of the window which
+ when entered while in drag mode leads to a scrolling of the window.
+ */
+ Size maScrollBorder;
+ /** The only task of this little window is to paint the little square at
+ the bottom right corner left by the two scroll bars (when both are
+ visible).
+ */
+ VclPtr<ScrollBarBox> mpScrollBarFiller;
+
+ /** The auto scroll timer is used for keep scrolling the window when the
+ mouse reaches its border while dragging a selection. When the mouse
+ is not moved the timer issues events to keep scrolling.
+ */
+ Timer maAutoScrollTimer;
+ Size maAutoScrollOffset;
+ bool mbIsAutoScrollActive;
+
+ /** The content window is the one whose view port is controlled by the
+ scroll bars.
+ */
+ VclPtr<sd::Window> mpContentWindow;
+
+ ::std::function<void ()> maAutoScrollFunctor;
+
+ void SetWindowOrigin (
+ double nHorizontalPosition,
+ double nVerticalPosition);
+
+ /** Determine the visibility of the scroll bars so that the window
+ content is not clipped in any dimension without showing a scroll
+ bar.
+ @param rAvailableArea
+ The area in which the scroll bars, the scroll bar filler, and
+ the SlideSorterView will be placed.
+ @return
+ The area that is enclosed by the scroll bars is returned. It
+ will be filled with the SlideSorterView.
+ */
+ ::tools::Rectangle DetermineScrollBarVisibilities(
+ const ::tools::Rectangle& rAvailableArea,
+ const bool bIsHorizontalScrollBarAllowed,
+ const bool bIsVerticalScrollBarAllowed);
+
+ /** Typically called by DetermineScrollBarVisibilities() this method
+ tests a specific configuration of the two scroll bars being visible
+ or hidden.
+ @return
+ When the window content can be shown with only being clipped in
+ an orientation where the scroll bar would be shown then <TRUE/>
+ is returned.
+ */
+ bool TestScrollBarVisibilities (
+ bool bHorizontalScrollBarVisible,
+ bool bVerticalScrollBarVisible,
+ const ::tools::Rectangle& rAvailableArea);
+
+ void CalcAutoScrollOffset (const Point& rMouseWindowPosition);
+ bool RepeatAutoScroll();
+
+ DECL_LINK(HorizontalScrollBarHandler, ScrollBar*, void);
+ DECL_LINK(VerticalScrollBarHandler, ScrollBar*, void);
+ DECL_LINK(AutoScrollTimeoutHandler, Timer *, void);
+
+ void PlaceHorizontalScrollBar (const ::tools::Rectangle& aArea);
+ void PlaceVerticalScrollBar (const ::tools::Rectangle& aArea);
+ void PlaceFiller (const ::tools::Rectangle& aArea);
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx
new file mode 100644
index 000000000..7d80fbd26
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <controller/SlsFocusManager.hxx>
+#include <fupoor.hxx>
+#include <memory>
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+
+struct AcceptDropEvent;
+
+namespace sd::slidesorter::controller
+{
+class SlideSorterController;
+
+class SelectionFunction final : public FuPoor
+{
+public:
+ SelectionFunction(const SelectionFunction&) = delete;
+ SelectionFunction& operator=(const SelectionFunction&) = delete;
+
+ static rtl::Reference<FuPoor> Create(SlideSorter& rSlideSorter, SfxRequest& rRequest);
+
+ // Mouse- & Key-Events
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ /// Forward to the clipboard manager.
+ virtual void DoCut() override;
+
+ /// Forward to the clipboard manager.
+ virtual void DoCopy() override;
+
+ /// Forward to the clipboard manager.
+ virtual void DoPaste() override;
+
+ /** is called when the current function should be aborted. <p>
+ This is used when a function gets a KEY_ESCAPE but can also
+ be called directly.
+
+ @returns
+ true if an active function was aborted
+ */
+ virtual bool cancel() override;
+
+ void MouseDragged(const AcceptDropEvent& rEvent, const sal_Int8 nDragAction);
+
+ /** Turn of substitution display and insertion indicator.
+ */
+ void NotifyDragFinished();
+
+ class EventDescriptor;
+ class ModeHandler;
+ friend class ModeHandler;
+ enum Mode
+ {
+ NormalMode,
+ MultiSelectionMode,
+ DragAndDropMode
+ };
+ void SwitchToNormalMode();
+ void SwitchToDragAndDropMode(const Point& rMousePosition);
+ void SwitchToMultiSelectionMode(const Point& rMousePosition, const sal_uInt32 nEventCode);
+
+ void ResetShiftKeySelectionAnchor();
+ /** Special case handling for when the context menu is hidden. This
+ method will reinitialize the current mouse position to prevent the
+ mouse motion during the time the context menu is displayed from
+ being interpreted as drag-and-drop start.
+ */
+ void ResetMouseAnchor();
+
+private:
+ SlideSorter& mrSlideSorter;
+ SlideSorterController& mrController;
+
+ SelectionFunction(SlideSorter& rSlideSorter, SfxRequest& rRequest);
+
+ virtual ~SelectionFunction() override;
+
+ /** Remember the slide where the shift key was pressed and started a
+ multiselection via keyboard.
+ */
+ sal_Int32 mnShiftKeySelectionAnchor;
+
+ /** The selection function can be in one of several mutually
+ exclusive modes.
+ */
+ std::shared_ptr<ModeHandler> mpModeHandler;
+
+ /** Make the slide nOffset slides away of the current one the new
+ current slide. When the new index is outside the range of valid
+ page numbers it is clipped to that range.
+ @param nOffset
+ When nOffset is negative then go back. When nOffset if positive go
+ forward. When it is zero then ignore the call.
+ */
+ void GotoNextPage(int nOffset);
+
+ /** Make the slide with the given index the new current slide.
+ @param nIndex
+ Index of the new current slide. When the new index is outside
+ the range of valid page numbers it is clipped to that range.
+ */
+ void GotoPage(int nIndex);
+
+ void ProcessMouseEvent(sal_uInt32 nEventType, const MouseEvent& rEvent);
+
+ // What follows are a couple of helper methods that are used by
+ // ProcessMouseEvent().
+
+ void ProcessEvent(EventDescriptor& rEvent);
+
+ void MoveFocus(const FocusManager::FocusMoveDirection eDirection, const bool bIsShiftDown,
+ const bool bIsControlDown);
+
+ void SwitchMode(const std::shared_ptr<ModeHandler>& rpHandler);
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx
new file mode 100644
index 000000000..4f52d49e6
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <tools/link.hxx>
+#include <vector>
+#include <memory>
+
+class SdPage;
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+
+namespace sd::slidesorter::controller
+{
+class SlideSorterController;
+class SelectionObserver;
+
+/** This class is a part of the controller and handles the selection of
+ slides.
+ <p>It has methods to modify the selected slides (delete them or
+ move them to other places in the document), change the visible area so
+ to make the selected slides visible, tell listeners when the selection
+ changes.</p>
+*/
+class SelectionManager
+{
+public:
+ /** Create a new SelectionManager for the given slide sorter.
+ */
+ SelectionManager(SlideSorter& rSlideSorter);
+
+ ~SelectionManager();
+
+ /** Delete the currently selected slides. When this method returns the
+ selection is empty.
+ @param bSelectFollowingPage
+ When <TRUE/> then after deleting the selected pages make the
+ slide after the last selected page the new current page.
+ When <FALSE/> then make the first slide before the selected
+ pages the new current slide.
+ */
+ void DeleteSelectedPages(const bool bSelectFollowingPage = true);
+
+ /** Call this method after the selection has changed (possible several
+ calls to the PageSelector) to invalidate the relevant slots and send
+ appropriate events.
+ */
+ void SelectionHasChanged();
+
+ /** Add a listener that is called when the selection of the slide sorter
+ changes.
+ @param rListener
+ When this method is called multiple times for the same listener
+ the second and all following calls are ignored. Each listener
+ is added only once.
+ */
+ void AddSelectionChangeListener(const Link<LinkParamNone*, void>& rListener);
+
+ /** Remove a listener that was called when the selection of the slide
+ sorter changes.
+ @param rListener
+ It is safe to pass a listener that was not added are has been
+ removed previously. Such calls are ignored.
+ */
+ void RemoveSelectionChangeListener(const Link<LinkParamNone*, void>& rListener);
+
+ /** Return the position where to insert pasted slides based on the
+ current selection. When there is a selection then the insert
+ position is behind the last slide. When the selection is empty then
+ most of the time the insert position is at the end of the document.
+ There is an exception right after the display of a popup-menu. The
+ position of the associated insertion marker is stored here and reset
+ the next time the selection changes.
+ */
+ sal_Int32 GetInsertionPosition() const;
+
+ /** Store an insertion position temporarily. It is reset when the
+ selection changes the next time.
+ */
+ void SetInsertionPosition(const sal_Int32 nInsertionPosition);
+
+ const std::shared_ptr<SelectionObserver>& GetSelectionObserver() const
+ {
+ return mpSelectionObserver;
+ }
+
+private:
+ SlideSorter& mrSlideSorter;
+ SlideSorterController& mrController;
+
+ ::std::vector<Link<LinkParamNone*, void>> maSelectionChangeListeners;
+
+ /** The insertion position is only temporarily valid. Negative values
+ indicate that the explicit insertion position is not valid. In this
+ case GetInsertionPosition() calculates it from the current selection.
+ */
+ sal_Int32 mnInsertionPosition;
+
+ std::shared_ptr<SelectionObserver> mpSelectionObserver;
+
+ /** Delete the given list of normal pages. This method is a helper
+ function for DeleteSelectedPages().
+ @param rSelectedNormalPages
+ A list of normal pages. Supplying master pages is an error.
+ */
+ void DeleteSelectedNormalPages(const ::std::vector<SdPage*>& rSelectedNormalPages);
+
+ /** Delete the given list of master pages. This method is a helper
+ function for DeleteSelectedPages().
+ @param rSelectedMasterPages
+ A list of master pages. Supplying normal pages is an error.
+ */
+ void DeleteSelectedMasterPages(const ::std::vector<SdPage*>& rSelectedMasterPages);
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSelectionObserver.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSelectionObserver.hxx
new file mode 100644
index 000000000..11742b890
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionObserver.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <memory>
+#include <vector>
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+
+class SdrPage;
+class SdPage;
+
+namespace sd::slidesorter::controller
+{
+/** Observe insertions and deletions of pages between calls to
+ StartObservation() and EndObservation(). When the later is called
+ the selection is set to just the newly inserted pages.
+*/
+class SelectionObserver final
+{
+public:
+ SelectionObserver(SlideSorter& rSlideSorter);
+ ~SelectionObserver();
+
+ void NotifyPageEvent(const SdrPage* pPage);
+ void StartObservation();
+ void AbortObservation();
+ void EndObservation();
+
+ /** Use this little class instead of calling StartObservation and
+ EndObservation directly so that EndObservation is not forgotten or
+ omitted due to an exception or some break or return in the middle of
+ code.
+ */
+ class Context
+ {
+ public:
+ Context(SlideSorter const& rSlideSorter);
+ ~Context() COVERITY_NOEXCEPT_FALSE;
+ void Abort();
+
+ private:
+ std::shared_ptr<SelectionObserver> mpSelectionObserver;
+ };
+
+private:
+ SlideSorter& mrSlideSorter;
+ bool mbIsObservationActive;
+ bool mbPageEventOccurred;
+
+ ::std::vector<const SdPage*> maInsertedPages;
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx
new file mode 100644
index 000000000..57de8422a
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx
@@ -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 .
+ */
+#pragma once
+
+#include <model/SlsSharedPageDescriptor.hxx>
+#include <tools/link.hxx>
+#include <rtl/ustring.hxx>
+
+class AbstractSvxNameDialog;
+class SfxItemSet;
+class SfxRequest;
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+
+namespace sd::slidesorter::controller
+{
+/** This manager takes over the work of handling slot calls from the
+ controller of the slide sorter.
+*/
+class SlotManager
+{
+public:
+ /** Create a new slot manager that handles slot calls for the controller
+ of a slide sorter.
+ @param rController
+ The controller for which to handle the slot calls.
+ */
+ SlotManager(SlideSorter& rSlideSorter);
+
+ void FuTemporary(SfxRequest& rRequest);
+ void FuPermanent(SfxRequest& rRequest);
+ void FuSupport(SfxRequest& rRequest);
+ void GetMenuState(SfxItemSet& rSet);
+ void GetClipboardState(SfxItemSet& rSet);
+ void GetStatusBarState(SfxItemSet& rSet);
+ void ExecCtrl(SfxRequest& rRequest);
+ void GetAttrState(SfxItemSet& rSet);
+
+ /** Exclude or include one slide or all selected slides.
+ @param rpDescriptor
+ When the pointer is empty then apply the new state to all
+ selected pages. Otherwise apply the new state to just the
+ specified state.
+ */
+ void ChangeSlideExclusionState(const model::SharedPageDescriptor& rpDescriptor,
+ const bool bExcludeSlide);
+
+ /** Call this after a change from normal mode to master mode or back.
+ The affected slots are invalidated.
+ */
+ void NotifyEditModeChange();
+
+private:
+ /// The controller for which we manage the slot calls.
+ SlideSorter& mrSlideSorter;
+
+ /** The implementation is a copy of the code for SID_RENAMEPAGE in
+ drviews2.cxx.
+ */
+ void RenameSlide(const SfxRequest& rRequest);
+ DECL_LINK(RenameSlideHdl, AbstractSvxNameDialog&, bool);
+ DECL_STATIC_LINK(SlotManager, RenameSlideTooltipHdl, AbstractSvxNameDialog&, OUString);
+ bool RenameSlideFromDrawViewShell(sal_uInt16 nPageId, const OUString& rName);
+
+ /** Handle SID_INSERTPAGE slot calls.
+ */
+ void InsertSlide(SfxRequest& rRequest);
+
+ void DuplicateSelectedSlides(SfxRequest& rRequest);
+
+ /** Use one of several ways to determine where to insert a new page.
+ This can be the current selection or the insertion indicator.
+ */
+ sal_Int32 GetInsertionPosition() const;
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsTransferableData.hxx b/sd/source/ui/slidesorter/inc/controller/SlsTransferableData.hxx
new file mode 100644
index 000000000..863c2fe73
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsTransferableData.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdxfer.hxx>
+
+#include <vcl/bitmapex.hxx>
+
+#include <vector>
+
+class SdDrawDocument;
+namespace sd::slidesorter { class SlideSorterViewShell; }
+
+namespace sd::slidesorter::controller {
+
+/** Represent previews and other information so that they can be
+ attached to an existing transferable.
+*/
+class TransferableData final
+ : public SdTransferable::UserData,
+ public SfxListener
+{
+public:
+ class Representative
+ {
+ public:
+ Representative (const BitmapEx& rBitmap, const bool bIsExcluded)
+ : maBitmap(rBitmap), mbIsExcluded(bIsExcluded) {}
+
+ BitmapEx maBitmap;
+ bool mbIsExcluded;
+ };
+
+ static rtl::Reference<SdTransferable> CreateTransferable (
+ SdDrawDocument* pSrcDoc,
+ SlideSorterViewShell* pViewShell,
+ ::std::vector<TransferableData::Representative>&& rRepresentatives);
+
+ static std::shared_ptr<TransferableData> GetFromTransferable (const SdTransferable* pTransferable);
+
+ TransferableData (
+ SlideSorterViewShell* pViewShell,
+ ::std::vector<TransferableData::Representative>&& rRepresentatives);
+ virtual ~TransferableData() override;
+
+ const ::std::vector<Representative>& GetRepresentatives() const { return maRepresentatives;}
+
+ /** Return the view shell for which the transferable was created.
+ */
+ SlideSorterViewShell* GetSourceViewShell() const { return mpViewShell;}
+
+private:
+ SlideSorterViewShell* mpViewShell;
+ const ::std::vector<Representative> maRepresentatives;
+
+ virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override;
+};
+
+} // end of namespace ::sd::slidesorter::controller
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/controller/SlsVisibleAreaManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsVisibleAreaManager.hxx
new file mode 100644
index 000000000..d9f5845af
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/controller/SlsVisibleAreaManager.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 .
+ */
+
+#pragma once
+
+#include <model/SlsSharedPageDescriptor.hxx>
+#include <optional>
+#include <tools/gen.hxx>
+#include <vector>
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+
+namespace sd::slidesorter::controller
+{
+/** Manage requests for scrolling page objects into view.
+*/
+class VisibleAreaManager
+{
+public:
+ explicit VisibleAreaManager(SlideSorter& rSlideSorter);
+ ~VisibleAreaManager();
+ VisibleAreaManager(const VisibleAreaManager&) = delete;
+ VisibleAreaManager& operator=(const VisibleAreaManager&) = delete;
+
+ void ActivateCurrentSlideTracking();
+ void DeactivateCurrentSlideTracking();
+ bool IsCurrentSlideTrackingActive() const { return mbIsCurrentSlideTrackingActive; }
+
+ /** Request the current slide to be moved into the visible area.
+ This request is only obeyed when the current slide tracking is
+ active.
+ @see ActivateCurrentSlideTracking() and DeactivateCurrentSlideTracking()
+ */
+ void RequestCurrentSlideVisible();
+
+ /** Request to make the specified page object visible.
+ */
+ void RequestVisible(const model::SharedPageDescriptor& rpDescriptor, const bool bForce = false);
+
+ /** Temporarily disable the update of the visible area.
+ */
+ class TemporaryDisabler
+ {
+ public:
+ explicit TemporaryDisabler(SlideSorter const& rSlideSorter);
+ ~TemporaryDisabler();
+
+ private:
+ VisibleAreaManager& mrVisibleAreaManager;
+ };
+
+private:
+ SlideSorter& mrSlideSorter;
+
+ /** List of rectangle that someone wants to be moved into the visible
+ area.
+ Cleared on every call to ForgetVisibleRequests() and MakeVisible().
+ */
+ ::std::vector<::tools::Rectangle> maVisibleRequests;
+
+ Point maRequestedVisibleTopLeft;
+ bool mbIsCurrentSlideTrackingActive;
+ int mnDisableCount;
+
+ void MakeVisible();
+ ::std::optional<Point> GetRequestedTopLeft() const;
+};
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx b/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx
new file mode 100644
index 000000000..90223a1bc
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsSharedPageDescriptor.hxx>
+#include <pres.hxx>
+#include <osl/mutex.hxx>
+#include <vcl/region.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <vector>
+
+class SdDrawDocument;
+class SdrPage;
+class SdPage;
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+namespace com::sun::star::container
+{
+class XIndexAccess;
+}
+namespace com::sun::star::drawing
+{
+class XDrawPage;
+}
+
+namespace sd::slidesorter::model
+{
+inline sal_Int32 FromCoreIndex(const sal_uInt16 nCoreIndex) { return (nCoreIndex - 1) / 2; }
+
+/** The model of the slide sorter gives access to the slides that are to be
+ displayed in the slide sorter view. Via the SetDocumentSlides() method
+ this set of slides can be modified (but do not call it directly, use
+ SlideSorterController::SetDocumentSlides() instead.)
+*/
+class SlideSorterModel final
+{
+public:
+ SlideSorterModel(SlideSorter& rSlideSorter);
+
+ ~SlideSorterModel();
+ void Dispose();
+
+ /** This method is present to let the view create a ShowView for
+ displaying slides.
+ */
+ SdDrawDocument* GetDocument();
+
+ /** Set a new edit mode and return whether the edit mode really
+ has been changed. When the edit mode is changed then the
+ previous page descriptor list is replaced by a new one which
+ has to be repainted.
+ @return
+ A return value of <TRUE/> indicates that the edit mode has
+ changed and thus the page descriptor list has been set up
+ to reflect that change. A repaint is necessary.
+ */
+ bool SetEditMode(EditMode eEditMode);
+
+ EditMode GetEditMode() const { return meEditMode; }
+
+ /** Return the number of slides in the document regardless of whether
+ they are visible or not or whether they are hidden or not.
+ The number of slides depends on the set of slides available through
+ the XIndexAccess given to SetDocumentSlides().
+ */
+ sal_Int32 GetPageCount() const;
+
+ /** Return a page descriptor for the page with the specified index.
+ Page descriptors are created on demand. The page descriptor is
+ found (or not found) in constant time.
+ @param nPageIndex
+ The index of the requested slide. The valid values
+ are 0 to GetPageCount()-1.
+ @param bCreate
+ When <TRUE/> and the requested page descriptor is missing then
+ it is created. When <FALSE/> then an empty reference is
+ returned for missing descriptors.
+ @return
+ When the given index is not valid, i.e. lower than zero or
+ larger than or equal to the number of pages then an empty
+ reference is returned. Note that the page count may change
+ between calls to GetPageCount() and GetPageDescriptor().
+ */
+ SharedPageDescriptor GetPageDescriptor(const sal_Int32 nPageIndex,
+ const bool bCreate = true) const;
+
+ /** Return a page descriptor for the given XDrawPage. Page descriptors
+ are created on demand. The page descriptor is found (or not found)
+ in (at most) linear time. Note that all page descriptors in front of
+ the one associated with the given XDrawPage are created when not yet
+ present. When the XDrawPage is not found then all descriptors are
+ created.
+ @return
+ Returns the index to the requested page descriptor or -1 when
+ there is no such page descriptor.
+ */
+ sal_Int32 GetIndex(const css::uno::Reference<css::drawing::XDrawPage>& rxSlide) const;
+
+ /** Return a page descriptor for the given SdrPage. Page descriptors
+ are created on demand. The page descriptor is found (or not found)
+ in (at most) linear time. Note that all page descriptors in front of
+ the one associated with the given XDrawPage are created when not yet
+ present. When the SdrPage is not found then all descriptors are
+ created.
+ @return
+ Returns the index to the requested page descriptor or -1 when
+ there is no such page descriptor.
+ */
+ sal_Int32 GetIndex(const SdrPage* pPage) const;
+
+ /** Return an index for accessing an SdrModel that corresponds to the
+ given SlideSorterModel index. In many cases we just have to apply
+ the n*2+1 magic. Only when a special model is set, like a custom
+ slide show, then the returned value is different.
+ */
+ sal_uInt16 GetCoreIndex(const sal_Int32 nIndex) const;
+
+ /** Call this method after the document has changed its structure. This
+ will get the model in sync with the SdDrawDocument. This method
+ tries not to throw away too much information already gathered. This
+ is especially important for previews of complex pages that take some
+ time to create.
+ */
+ void Resync();
+
+ /** Delete all descriptors that currently are in the container. The size
+ of the container, however, is not altered. Use the AdaptSize
+ method for that.
+ */
+ void ClearDescriptorList();
+
+ /** Set the selection of the document to exactly that of the called model.
+ */
+ void SynchronizeDocumentSelection();
+
+ /** Set the selection of the called model to exactly that of the document.
+ */
+ void SynchronizeModelSelection();
+
+ /** Return the mutex so that the caller can lock it and then safely
+ access the model.
+ */
+ ::osl::Mutex& GetMutex() { return maMutex; }
+
+ /** Set the XIndexAccess from which the called SlideSorterModel takes
+ its pages.
+ @param rxSlides
+ The set of slides accessible through this XIndexAccess are not
+ necessarily the same as the ones of the XModel of the
+ XController (although it typically is a subset).
+ */
+ void SetDocumentSlides(const css::uno::Reference<css::container::XIndexAccess>& rxSlides);
+
+ /** Return the set of pages that is currently displayed by the slide sorter.
+ */
+ css::uno::Reference<css::container::XIndexAccess> GetDocumentSlides() const;
+
+ /** This method is called when the edit mode has changed. It calls
+ SetDocumentSlides() with the set of slides or master pages obtained
+ from the model of the XController.
+ */
+ void UpdatePageList();
+
+ bool IsReadOnly() const;
+
+ /** The current selection is saved by copying the ST_Selected state into
+ ST_WasSelected for slides.
+ */
+ void SaveCurrentSelection();
+
+ /** The current selection is restored from the ST_WasSelected state from
+ the slides.
+ @returns
+ The returned region has to be repainted to reflect the updated
+ selection states.
+ */
+ vcl::Region RestoreSelection();
+
+ /** Typically called from controller::Listener this method handles the
+ insertion and deletion of single pages.
+ @return
+ Returns <TRUE/> when the given page is relevant for the current
+ page kind and edit mode.
+ */
+ bool NotifyPageEvent(const SdrPage* pPage);
+
+private:
+ mutable ::osl::Mutex maMutex;
+ SlideSorter& mrSlideSorter;
+ css::uno::Reference<css::container::XIndexAccess> mxSlides;
+ EditMode meEditMode;
+ mutable ::std::vector<SharedPageDescriptor> maPageDescriptors;
+
+ /** Resize the descriptor container according to current values of
+ page kind and edit mode.
+ */
+ void AdaptSize();
+
+ SdPage* GetPage(const sal_Int32 nCoreIndex) const;
+ void InsertSlide(SdPage* pPage, bool bMarkSelected);
+ // return if this page was marked as selected before being removed
+ bool DeleteSlide(const SdPage* pPage);
+ void UpdateIndices(const sal_Int32 nFirstIndex);
+};
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/model/SlsEnumeration.hxx b/sd/source/ui/slidesorter/inc/model/SlsEnumeration.hxx
new file mode 100644
index 000000000..289f85911
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/model/SlsEnumeration.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+namespace sd::slidesorter::model
+{
+/** Interface to generic enumerations. Designed to operate on shared
+ pointers. Therefore GetNextElement() returns T and not T&.
+*/
+template <class T> class Enumeration
+{
+public:
+ virtual ~Enumeration() {}
+
+ virtual bool HasMoreElements() const = 0;
+ /** Returns T instead of T& so that it can handle shared pointers.
+ */
+ virtual T GetNextElement() = 0;
+ virtual void Rewind() = 0;
+ virtual ::std::unique_ptr<Enumeration<T>> Clone() = 0;
+};
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx b/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx
new file mode 100644
index 000000000..4f3be3b42
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsVisualState.hxx>
+#include <tools/gen.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <memory>
+
+namespace com::sun::star::drawing { class XDrawPage; }
+
+class SdPage;
+class SdrPage;
+
+namespace sd::slidesorter::model {
+
+/** Each PageDescriptor object represents the preview of one draw page,
+ slide, or master page of a Draw or Impress document as they are displayed
+ in the slide sorter. This class gives access to some associated
+ information like prerendered preview or position on the screen.
+
+ <p>Bounding boxes of page objects come in four varieties:
+ Model and screen/pixel coordinates and the bounding boxes of the actual
+ page objects and the larger bounding boxes that include page names and
+ fade symbol.</p>
+*/
+class PageDescriptor
+ : public ::std::enable_shared_from_this<PageDescriptor>
+{
+public:
+ /** Create a PageDescriptor for the given SdPage object.
+ @param rxPage
+ The page that is represented by the new PageDescriptor object.
+ @param pPage
+ The page pointer can in some situations not be detected from
+ rxPage, e.g. after undo of page deletion. Therefore supply it
+ separately.
+ @param nIndex
+ This index is displayed in the view as page number. It is not
+ necessarily the page index (not even when you add or subtract 1
+ or use (x-1)/2 magic).
+ */
+ PageDescriptor (
+ const css::uno::Reference<css::drawing::XDrawPage>& rxPage,
+ SdPage* pPage,
+ const sal_Int32 nIndex);
+
+ ~PageDescriptor();
+
+ /** Return the page that is represented by the descriptor as SdPage pointer .
+ */
+ SdPage* GetPage() const { return mpPage;}
+
+ /** Return the page that is represented by the descriptor as XDrawPage reference.
+ */
+ const css::uno::Reference<css::drawing::XDrawPage>& GetXDrawPage() const { return mxPage;}
+
+ /** Returns the index of the page as it is displayed in the view as page
+ number. The value may differ from the index returned by the
+ XDrawPage when there are hidden slides and the XIndexAccess used to
+ access the model filters them out.
+ */
+ sal_Int32 GetPageIndex() const { return mnIndex;}
+ void SetPageIndex (const sal_Int32 nIndex);
+
+ bool UpdateMasterPage();
+ bool UpdateTransitionFlag();
+
+ enum State { ST_Visible, ST_Selected, ST_WasSelected,
+ ST_Focused, ST_MouseOver, ST_Current, ST_Excluded };
+
+ bool HasState (const State eState) const;
+
+ bool SetState (const State eState, const bool bStateValue);
+
+ /** Set the internal mbIsSelected flag to the selection state of the
+ page. Use this method to synchronize a page descriptor with the
+ page it describes and determine whether a redraw to update the
+ selection indicator is necessary.
+ @return
+ When the two selection states were different <TRUE/> is
+ returned. When they were the same this method returns
+ <FALSE/>.
+ */
+ bool GetCoreSelection();
+
+ /** Set the selection flags of the SdPage objects to the corresponding
+ selection states of the page descriptors.
+ */
+ void SetCoreSelection();
+
+ VisualState& GetVisualState() { return maVisualState;}
+
+ ::tools::Rectangle GetBoundingBox() const;
+ Point GetLocation (const bool bIgnoreLocation) const;
+ void SetBoundingBox (const ::tools::Rectangle& rBoundingBox);
+
+private:
+ SdPage* mpPage;
+ css::uno::Reference<css::drawing::XDrawPage> mxPage;
+ SdrPage const* mpMasterPage;
+
+ /** This index is displayed as page number in the view. It may or may
+ not be the actual page index.
+ */
+ sal_Int32 mnIndex;
+
+ ::tools::Rectangle maBoundingBox;
+ VisualState maVisualState;
+
+ bool mbIsSelected : 1;
+ bool mbWasSelected : 1;
+ bool mbIsVisible : 1;
+ bool mbIsFocused : 1;
+ bool mbIsCurrent : 1;
+ bool mbIsMouseOver : 1;
+ bool mbHasTransition : 1;
+
+ PageDescriptor (const PageDescriptor& rDescriptor) = delete;
+
+ PageDescriptor& operator= (const PageDescriptor& rDescriptor) = delete;
+};
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/model/SlsPageEnumeration.hxx b/sd/source/ui/slidesorter/inc/model/SlsPageEnumeration.hxx
new file mode 100644
index 000000000..6901a9ff1
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/model/SlsPageEnumeration.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsEnumeration.hxx>
+#include <model/SlsSharedPageDescriptor.hxx>
+
+#include <functional>
+#include <memory>
+
+namespace sd::slidesorter::model
+{
+class SlideSorterModel;
+
+/** Public class of page enumerations that delegates its calls to an
+ implementation object that can filter pages by using a given predicate.
+
+ @see PageEnumerationProvider
+ The PageEnumerationProvider has methods for creating different types
+ of page enumerations.
+*/
+class PageEnumeration final : public Enumeration<SharedPageDescriptor>
+{
+public:
+ /** Create a new page enumeration that enumerates a subset of the pages
+ of the given model.
+ @param rModel
+ The new page enumeration enumerates the pages of this model.
+ @param rPredicate
+ This predicate determines which pages to include in the
+ enumeration. Pages for which rPredicate returns <FALSE/> are
+ exclude.
+ */
+ typedef ::std::function<bool(const SharedPageDescriptor&)> PagePredicate;
+ static PageEnumeration Create(const SlideSorterModel& rModel, const PagePredicate& rPredicate);
+
+ /** This copy constructor creates a copy of the given enumeration.
+ */
+ PageEnumeration(const PageEnumeration& rEnumeration);
+
+ virtual ~PageEnumeration() override;
+
+ /** Create and return an exact copy of the called object.
+ */
+ virtual ::std::unique_ptr<Enumeration<SharedPageDescriptor>> Clone() override;
+
+ PageEnumeration& operator=(const PageEnumeration& rEnumeration);
+
+ /** Return <TRUE/> when the enumeration has more elements, i.e. it is
+ save to call GetNextElement() at least one more time.
+ */
+ virtual bool HasMoreElements() const override;
+
+ /** Return the next element of the enumeration. Call the
+ HasMoreElements() before to make sure that there exists at least one
+ more element. Calling this method with HasMoreElements() returning
+ <FALSE/> is an error.
+ */
+ virtual SharedPageDescriptor GetNextElement() override;
+
+ /** Rewind the enumeration so that the next call to GetNextElement()
+ will return its first element.
+ */
+ virtual void Rewind() override;
+
+private:
+ /// Implementation object.
+ ::std::unique_ptr<Enumeration<SharedPageDescriptor>> mpImpl;
+
+ /** This constructor expects an implementation object that holds
+ the predicate that filters the pages.
+ */
+ PageEnumeration(::std::unique_ptr<Enumeration<SharedPageDescriptor>>&& pImpl);
+};
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/model/SlsPageEnumerationProvider.hxx b/sd/source/ui/slidesorter/inc/model/SlsPageEnumerationProvider.hxx
new file mode 100644
index 000000000..b6de98d13
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/model/SlsPageEnumerationProvider.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsPageEnumeration.hxx>
+
+namespace sd::slidesorter::model
+{
+class SlideSorterModel;
+
+/** Collection of methods that create enumeration of slides.
+*/
+class PageEnumerationProvider
+{
+public:
+ /** The returned enumeration of slides iterates over all slides of the
+ given model.
+ */
+ static PageEnumeration CreateAllPagesEnumeration(const SlideSorterModel& rModel);
+
+ /** The returned enumeration of slides iterates over the currently
+ selected slides of the given model.
+ */
+ static PageEnumeration CreateSelectedPagesEnumeration(const SlideSorterModel& rModel);
+
+ /** The returned enumeration of slides iterates over the slides
+ (partially) inside the visible area.
+ */
+ static PageEnumeration CreateVisiblePagesEnumeration(const SlideSorterModel& rModel);
+};
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/model/SlsSharedPageDescriptor.hxx b/sd/source/ui/slidesorter/inc/model/SlsSharedPageDescriptor.hxx
new file mode 100644
index 000000000..6ee1e2b22
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/model/SlsSharedPageDescriptor.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+namespace sd::slidesorter::model
+{
+class PageDescriptor;
+
+typedef std::shared_ptr<PageDescriptor> SharedPageDescriptor;
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/model/SlsVisualState.hxx b/sd/source/ui/slidesorter/inc/model/SlsVisualState.hxx
new file mode 100644
index 000000000..89eae16ca
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/model/SlsVisualState.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <tools/gen.hxx>
+
+namespace sd::slidesorter::model
+{
+/** This class gives access to values related to the visualization of page
+ objects. This includes animation state when blending from one state to
+ another.
+*/
+class VisualState
+{
+public:
+ VisualState(const sal_Int32 nPageId);
+
+ const Point& GetLocationOffset() const { return maLocationOffset; }
+ void SetLocationOffset(const Point& rPoint);
+
+ sal_Int32 mnPageId; // For debugging
+
+private:
+ Point maLocationOffset;
+};
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx b/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx
new file mode 100644
index 000000000..0f3493ab3
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsPageDescriptor.hxx>
+#include <model/SlsSharedPageDescriptor.hxx>
+#include <view/SlsLayouter.hxx>
+#include <view/SlsILayerPainter.hxx>
+#include <o3tl/deleter.hxx>
+
+#include <View.hxx>
+#include <tools/gen.hxx>
+#include <vcl/region.hxx>
+#include <memory>
+
+namespace sd::slidesorter::cache { class PageCache; }
+namespace sd::slidesorter::model { class SlideSorterModel; }
+namespace sd { class Window; }
+namespace sd::slidesorter { class SlideSorter; }
+namespace sd::slidesorter::view {
+
+class LayeredDevice;
+class PageObjectPainter;
+class ToolTip;
+
+class SlideSorterView final
+ : public sd::View
+{
+public:
+
+ /** Create a new view for the slide sorter.
+ @param rViewShell
+ This reference is simply passed to the base class and not used
+ by this class.
+
+ */
+ explicit SlideSorterView (SlideSorter& rSlideSorter);
+ void Init();
+
+ virtual ~SlideSorterView() override;
+ void Dispose();
+
+ SlideSorterView(const SlideSorterView&) = delete;
+ SlideSorterView& operator=(const SlideSorterView&) = delete;
+
+ /** Set the general way of layouting the page objects. Note that this
+ method does not trigger any repaints or layouts.
+ */
+ bool SetOrientation (const Layouter::Orientation eOrientation);
+ Layouter::Orientation GetOrientation() const { return meOrientation;}
+
+ void RequestRepaint();
+ void RequestRepaint (const model::SharedPageDescriptor& rDescriptor);
+ void RequestRepaint (const ::tools::Rectangle& rRepaintBox);
+ void RequestRepaint (const vcl::Region& rRepaintRegion);
+
+ ::tools::Rectangle GetModelArea() const;
+
+ /** Return the index of the page that is rendered at the given position.
+ @param rPosition
+ The position is expected to be in pixel coordinates.
+ @return
+ The returned index is -1 when there is no page object at the
+ given position.
+ */
+ sal_Int32 GetPageIndexAtPoint (const Point& rPosition) const;
+
+ view::Layouter& GetLayouter();
+
+ virtual void ModelHasChanged() override;
+
+ /** This method is typically called before a model change takes place.
+ All references to model data are released. PostModelChange() has to
+ be called to complete the handling of the model change. When the
+ calls to Pre- and PostModelChange() are very close to each other you
+ may call HandleModelChange() instead.
+ */
+ void PreModelChange();
+
+ /** This method is typically called after a model change took place.
+ References to model data are re-allocated. Call this method only
+ after PreModelChange() has been called.
+ */
+ void PostModelChange();
+
+ /** This method is a convenience function that simply calls
+ PreModelChange() and then PostModelChange().
+ */
+ void HandleModelChange();
+
+ void HandleDrawModeChange();
+
+ void Resize();
+ virtual void CompleteRedraw (
+ OutputDevice* pDevice,
+ const vcl::Region& rPaintArea,
+ sdr::contact::ViewObjectContactRedirector* pRedirector = nullptr) override;
+ void Paint (OutputDevice& rDevice, const ::tools::Rectangle& rRepaintArea);
+
+ virtual void ConfigurationChanged (
+ utl::ConfigurationBroadcaster* pBroadcaster,
+ ConfigurationHints nHint) override;
+
+ void HandleDataChangeEvent();
+
+ void Layout();
+ /** This tells the view that it has to re-determine the visibility of
+ the page objects before painting them the next time.
+ */
+ void InvalidatePageObjectVisibilities();
+
+ std::shared_ptr<cache::PageCache> const & GetPreviewCache();
+
+ /** Return the range of currently visible page objects including the
+ first and last one in that range.
+ @return
+ The returned pair of page object indices is empty when the
+ second index is lower than the first.
+ */
+ Range const & GetVisiblePageRange();
+
+ /** Add a shape to the page. Typically used from inside
+ PostModelChange().
+ */
+ // void AddSdrObject (SdrObject& rObject);
+
+ /** Add a listener that is called when the set of visible slides.
+ @param rListener
+ When this method is called multiple times for the same listener
+ the second and all following calls are ignored. Each listener
+ is added only once.
+ */
+ void AddVisibilityChangeListener (const Link<LinkParamNone*,void>& rListener);
+
+ /** Remove a listener that is called when the set of visible slides changes.
+ @param rListener
+ It is safe to pass a listener that was not added or has been
+ removed previously. Such calls are ignored.
+ */
+ void RemoveVisibilityChangeListener (const Link<LinkParamNone*,void>& rListener);
+
+ /** The page under the mouse is not highlighted in some contexts. Call
+ this method on context changes.
+ */
+ void UpdatePageUnderMouse ();
+ void UpdatePageUnderMouse (const Point& rMousePosition);
+ void SetPageUnderMouse (const model::SharedPageDescriptor& rpDescriptor);
+
+ bool SetState (
+ const model::SharedPageDescriptor& rpDescriptor,
+ const model::PageDescriptor::State eState,
+ const bool bStateValue);
+
+ void UpdateOrientation();
+
+ std::shared_ptr<PageObjectPainter> const & GetPageObjectPainter();
+ const std::shared_ptr<LayeredDevice>& GetLayeredDevice() const { return mpLayeredDevice;}
+
+ class DrawLock
+ {
+ public:
+ DrawLock (SlideSorter const & rSlideSorter);
+ ~DrawLock();
+ /** When the DrawLock is disposed then it will not request a repaint
+ on destruction.
+ */
+ void Dispose();
+ private:
+ view::SlideSorterView& mrView;
+ VclPtr<sd::Window> mpWindow;
+ };
+
+ ToolTip& GetToolTip() const;
+
+ virtual void DragFinished (sal_Int8 nDropAction) override;
+
+private:
+ SlideSorter& mrSlideSorter;
+ model::SlideSorterModel& mrModel;
+ bool mbIsDisposed;
+ ::std::unique_ptr<Layouter> mpLayouter;
+ bool mbPageObjectVisibilitiesValid;
+ std::shared_ptr<cache::PageCache> mpPreviewCache;
+ std::shared_ptr<LayeredDevice> mpLayeredDevice;
+ Range maVisiblePageRange;
+ Size maPreviewSize;
+ bool mbPreciousFlagUpdatePending;
+ Layouter::Orientation meOrientation;
+ model::SharedPageDescriptor mpPageUnderMouse;
+ std::shared_ptr<PageObjectPainter> mpPageObjectPainter;
+ vcl::Region maRedrawRegion;
+ SharedILayerPainter mpBackgroundPainter;
+ std::unique_ptr<ToolTip, o3tl::default_delete<ToolTip>> mpToolTip;
+ bool mbIsRearrangePending;
+ ::std::vector<Link<LinkParamNone*,void>> maVisibilityChangeListeners;
+
+ /** Determine the visibility of all page objects.
+ */
+ void DeterminePageObjectVisibilities();
+
+ void UpdatePreciousFlags();
+ void RequestRearrange();
+ void Rearrange();
+};
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/view/SlsILayerPainter.hxx b/sd/source/ui/slidesorter/inc/view/SlsILayerPainter.hxx
new file mode 100644
index 000000000..57b90af0a
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/view/SlsILayerPainter.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+class OutputDevice;
+namespace tools { class Rectangle; }
+
+namespace sd::slidesorter::view {
+
+class ILayerInvalidator
+{
+public:
+ virtual ~ILayerInvalidator() {}
+
+ virtual void Invalidate (const ::tools::Rectangle& rInvalidationBox) = 0;
+};
+typedef std::shared_ptr<ILayerInvalidator> SharedILayerInvalidator;
+
+class ILayerPainter
+{
+public:
+ virtual ~ILayerPainter() {}
+
+ virtual void SetLayerInvalidator (
+ const SharedILayerInvalidator& rpInvalidator) = 0;
+ virtual void Paint (
+ OutputDevice& rDevice,
+ const ::tools::Rectangle& rRepaintArea) = 0;
+};
+typedef std::shared_ptr<ILayerPainter> SharedILayerPainter;
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/view/SlsInsertAnimator.hxx b/sd/source/ui/slidesorter/inc/view/SlsInsertAnimator.hxx
new file mode 100644
index 000000000..c74d06cb9
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/view/SlsInsertAnimator.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <controller/SlsAnimator.hxx>
+#include <memory>
+
+namespace sd::slidesorter::view
+{
+class InsertPosition;
+
+/** Animate the positions of page objects to make room at the insert
+ position while a move or copy operation takes place.
+*/
+class InsertAnimator
+{
+public:
+ explicit InsertAnimator(SlideSorter& rSlideSorter);
+ InsertAnimator(const InsertAnimator&) = delete;
+ InsertAnimator& operator=(const InsertAnimator&) = delete;
+
+ /** Set the position at which we have to make room for the display of an
+ icon.
+ */
+ void SetInsertPosition(const InsertPosition& rInsertPosition);
+
+ /** Restore the normal position of all page objects.
+ @param eMode
+ This flag controls whether to start an animation that ends in the
+ normal positions of all slides (AM_Animated) or to restore the
+ normal positions immediately (AM_Immediate).
+ */
+ void Reset(const controller::Animator::AnimationMode eMode);
+
+private:
+ class Implementation;
+ std::shared_ptr<Implementation> mpImplementation;
+};
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/view/SlsInsertionIndicatorOverlay.hxx b/sd/source/ui/slidesorter/inc/view/SlsInsertionIndicatorOverlay.hxx
new file mode 100644
index 000000000..3f4cc2218
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/view/SlsInsertionIndicatorOverlay.hxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <view/SlsILayerPainter.hxx>
+#include <controller/SlsTransferableData.hxx>
+
+#include <tools/gen.hxx>
+#include <vcl/bitmapex.hxx>
+#include <memory>
+#include <vector>
+
+class OutputDevice;
+class SdTransferable;
+
+namespace sd::slidesorter { class SlideSorter; }
+
+namespace sd::slidesorter::view {
+
+class FramePainter;
+
+/** The insertion indicator is painted as a vertical or horizontal bar
+ in the space between slides.
+*/
+class InsertionIndicatorOverlay final
+ : public ILayerPainter,
+ public std::enable_shared_from_this<InsertionIndicatorOverlay>
+{
+public:
+ InsertionIndicatorOverlay (SlideSorter& rSlideSorter);
+ virtual ~InsertionIndicatorOverlay() override;
+
+ virtual void SetLayerInvalidator (const SharedILayerInvalidator& rpInvalidator) override;
+
+ void Create (const SdTransferable* pTransferable);
+
+ /** Given a position in model coordinates this method calculates the
+ insertion marker both as an index in the document and as a location
+ used for drawing the insertion indicator.
+ */
+ void SetLocation (const Point& rPosition);
+
+ Size GetSize() const;
+
+ virtual void Paint (
+ OutputDevice& rDevice,
+ const ::tools::Rectangle& rRepaintArea) override;
+
+ bool IsVisible() const { return mbIsVisible;}
+ void Hide();
+ void Show();
+
+ ::tools::Rectangle GetBoundingBox() const;
+
+private:
+ SlideSorter& mrSlideSorter;
+ bool mbIsVisible;
+ SharedILayerInvalidator mpLayerInvalidator;
+ // Center of the insertion indicator.
+ Point maLocation;
+ BitmapEx maIcon;
+ std::unique_ptr<FramePainter> mpShadowPainter;
+
+ Point PaintRepresentatives (
+ OutputDevice& rContent,
+ const Size& rPreviewSize,
+ const sal_Int32 nOffset,
+ const ::std::vector<controller::TransferableData::Representative>& rPages) const;
+ void PaintPageCount (
+ OutputDevice& rDevice,
+ const sal_Int32 nSelectionCount,
+ const Size& rPreviewSize,
+ const Point& rFirstPageOffset) const;
+ /** Setup the insertion indicator by creating the icon. It consists of
+ scaled down previews of some of the selected pages.
+ */
+ void Create (
+ const ::std::vector<controller::TransferableData::Representative>& rPages,
+ const sal_Int32 nSelectionCount);
+};
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx b/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx
new file mode 100644
index 000000000..b91ae83c5
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx
@@ -0,0 +1,237 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/vclptr.hxx>
+#include <tools/gen.hxx>
+#include <sal/types.h>
+#include <memory>
+
+namespace sd { class Window; }
+namespace sd::slidesorter::model { class SlideSorterModel; }
+namespace sd::slidesorter::view { class PageObjectLayouter; }
+namespace sd::slidesorter::view { class Theme; }
+
+namespace sd::slidesorter::view {
+
+class InsertPosition;
+
+/** Calculate the size and position of page objects displayed by a slide
+ sorter. The layouter takes into account various input values:
+ 1.) Size of the window in which the slide sorter is displayed.
+ 2.) Desired and minimal and maximal widths of page objects.
+ 3.) Minimal and maximal number of columns.
+ 4.) Vertical and horizontal gaps between objects in adjacent columns.
+ 5.) Borders around every page object.
+ 6.) Vertical and horizontal borders between enclosing page and outer
+ page objects.
+ From these, it calculates various output values:
+ 1.) The width of page objects.
+ 2.) The number of columns.
+ 3.) The size of the enclosing page.
+
+ <p>Sizes and lengths are all in pixel except where explicitly stated
+ otherwise.</p>
+
+ <p>The GetIndex... methods may return indices that are larger than or
+ equal to (zero based) the number of pages. This is so because the
+ number of pages is not known to the class instances. Indices are
+ calculated with reference to the general grid layout of page
+ objects.</p>
+*/
+class Layouter
+{
+public:
+ enum Orientation { HORIZONTAL, VERTICAL, GRID };
+
+ Layouter (
+ sd::Window *rpWindow,
+ const std::shared_ptr<Theme>& rpTheme);
+ ~Layouter();
+
+ std::shared_ptr<PageObjectLayouter> const & GetPageObjectLayouter() const;
+ /** Set the interval of valid column counts. When nMinimalColumnCount
+ <= nMaximalColumnCount is not fulfilled then the call is ignored.
+ @param nMinimalColumnCount
+ The default value is 1. The question whether higher values make
+ any sense is left to the caller.
+ @param nMaximalColumnCount
+ The default value is 5.
+ */
+ void SetColumnCount (sal_Int32 nMinimalColumnCount,
+ sal_Int32 nMaximalColumnCount);
+
+ /** Central method of this class. It takes the input values and
+ calculates the output values. Both given sizes must not be 0 in any
+ dimension or the call is ignored.
+ @param eOrientation
+ This defines the generally layout and specifies whether there may
+ be more than one row or more than one column.
+ @param rWindowSize
+ The size of the window in pixels that the slide sorter is
+ displayed in. This can differ from the size of mpWindow during
+ detection of whether or not the scroll bars should be visible.
+ @param rPreviewModelSize
+ Size of each page in model coordinates.
+ @param rpWindow
+ The map mode of this window is adapted to the new layout of the
+ page objects.
+ @return
+ The return value indicates whether the Get... methods can be
+ used to obtain valid values (<TRUE/>).
+ */
+ bool Rearrange (
+ const Orientation eOrientation,
+ const Size& rWindowSize,
+ const Size& rPreviewModelSize,
+ const sal_uInt32 nPageCount);
+
+ /** Return the number of columns.
+ */
+ sal_Int32 GetColumnCount() const;
+
+ sal_Int32 GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const;
+
+ Size const & GetPageObjectSize() const;
+
+ /** Return the bounding box in window coordinates of the nIndex-th page
+ object.
+ */
+ ::tools::Rectangle GetPageObjectBox (
+ const sal_Int32 nIndex,
+ const bool bIncludeBorderAndGap) const;
+
+ /** Return the bounding box in model coordinates of the page that
+ contains the given amount of page objects.
+ */
+ ::tools::Rectangle GetTotalBoundingBox() const;
+
+ /** Return the index of the first fully or partially visible page
+ object. This takes into account only the vertical dimension.
+ @return
+ The second index may be larger than the number of existing
+ page objects.
+ */
+ Range GetRangeOfVisiblePageObjects (const ::tools::Rectangle& rVisibleArea) const;
+
+ /** Return the index of the page object that is rendered at the given
+ point.
+ @param rPosition
+ The position is expected to be in model coordinates relative to
+ the page origin.
+ @param bIncludePageBorders
+ When <TRUE/> then include the page borders into the calculation,
+ i.e. when a point lies in the border of a page object but not on
+ the actual page area the index of that page is returned;
+ otherwise -1 would be returned to indicate that no page object
+ has been hit.
+ @param bClampToValidRange
+ When <TRUE/> then values outside the valid range [0,mnPageCount)
+ are mapped to 0 (when smaller than 0) or mnPageCount-1 when
+ equal to or larger than mnPageCount.
+ When <FALSE/> then -1 is returned for values outside the valid range.
+ @return
+ The returned index may be larger than the number of existing
+ page objects.
+ */
+ sal_Int32 GetIndexAtPoint (
+ const Point& rModelPosition,
+ const bool bIncludePageBorders,
+ const bool bClampToValidRange = true) const;
+
+ /** Return an object that describes the logical and visual properties of
+ where to do an insert operation when the user would release the
+ mouse button at the given position after a drag operation and of
+ where and how to display an insertion indicator.
+ @param rModelPosition
+ The position in the model coordinate system for which to
+ determine the insertion page index. The position does not have
+ to be over a page object to return a valid value.
+ @param rIndicatorSize
+ The size of the insertion indicator. This size is used to adapt
+ the location when at the left or right of a row or at the top or
+ bottom of a column.
+ @param rModel
+ The model is used to get access to the selection states of the
+ pages. This in turn is used to determine the visual bounding
+ boxes.
+ */
+ InsertPosition GetInsertPosition (
+ const Point& rModelPosition,
+ const Size& rIndicatorSize,
+ model::SlideSorterModel const & rModel) const;
+
+ Range GetValidHorizontalSizeRange() const;
+ Range GetValidVerticalSizeRange() const;
+
+ class Implementation;
+
+private:
+ std::unique_ptr<Implementation> mpImplementation;
+ VclPtr<sd::Window> mpWindow;
+};
+
+/** Collect all values concerning the logical and visual properties of the
+ insertion position that is used for drag-and-drop and copy-and-paste.
+*/
+class InsertPosition
+{
+public:
+ InsertPosition();
+ bool operator== (const InsertPosition& rInsertPosition) const;
+ bool operator!= (const InsertPosition& rInsertPosition) const;
+
+ void SetLogicalPosition (
+ const sal_Int32 nRow,
+ const sal_Int32 nColumn,
+ const sal_Int32 nIndex,
+ const bool bIsAtRunStart,
+ const bool bIsAtRunEnd,
+ const bool bIsExtraSpaceNeeded);
+ void SetGeometricalPosition(
+ const Point& rLocation,
+ const Point& rLeadingOffset,
+ const Point& rTrailingOffset);
+
+ sal_Int32 GetRow() const { return mnRow; }
+ sal_Int32 GetColumn() const { return mnColumn; }
+ sal_Int32 GetIndex() const { return mnIndex; }
+ const Point& GetLocation() const { return maLocation; }
+ const Point& GetLeadingOffset() const { return maLeadingOffset; }
+ const Point& GetTrailingOffset() const { return maTrailingOffset; }
+ bool IsAtRunStart() const { return mbIsAtRunStart; }
+ bool IsAtRunEnd() const { return mbIsAtRunEnd; }
+ bool IsExtraSpaceNeeded() const { return mbIsExtraSpaceNeeded; }
+
+private:
+ sal_Int32 mnRow;
+ sal_Int32 mnColumn;
+ sal_Int32 mnIndex;
+ bool mbIsAtRunStart : 1;
+ bool mbIsAtRunEnd : 1;
+ bool mbIsExtraSpaceNeeded : 1;
+ Point maLocation;
+ Point maLeadingOffset;
+ Point maTrailingOffset;
+};
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/view/SlsPageObjectLayouter.hxx b/sd/source/ui/slidesorter/inc/view/SlsPageObjectLayouter.hxx
new file mode 100644
index 000000000..8bb77a988
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/view/SlsPageObjectLayouter.hxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsSharedPageDescriptor.hxx>
+#include <tools/gen.hxx>
+#include <vcl/image.hxx>
+
+namespace vcl { class Font; }
+namespace sd { class Window; }
+
+namespace sd::slidesorter::view {
+
+/** In contrast to the Layouter that places page objects in the view, the
+ PageObjectLayouter places the parts of individual page objects like page
+ number area, borders, preview.
+*/
+class PageObjectLayouter
+{
+public:
+ /** Create a new PageObjectLayouter object.
+ @param rPageObjectSize
+ In general either the width or the height will be 0 in order to
+ signal that this size component has to be calculated from the other.
+ This calculation will make the preview as large as possible.
+ @param nPageCount
+ The page count is used to determine how wide the page number
+ area has to be, how many digits to except for the largest page number.
+ */
+ PageObjectLayouter(
+ const Size& rPageObjectWindowSize,
+ const Size& rPreviewModelSize,
+ sd::Window *pWindow,
+ const sal_Int32 nPageCount);
+ ~PageObjectLayouter();
+
+ enum class Part {
+ // The focus indicator is painted outside the actual page object.
+ FocusIndicator,
+ // This is the outer bounding box that includes the preview, page
+ // number, title.
+ PageObject,
+ // Bounding box of the actual preview.
+ Preview,
+ // Bounding box of the page number.
+ PageNumber,
+ // Indicator whether or not there is a slide transition associated
+ // with this slide.
+ TransitionEffectIndicator,
+ // Indicator whether or not there is a custom animation associated
+ // with this slide.
+ CustomAnimationEffectIndicator
+ };
+ /** Two coordinate systems are supported. They differ only in
+ translation not in scale. Both relate to pixel values in the window.
+ A position in the model coordinate system does not change when the window content is
+ scrolled up or down. In the window coordinate system (relative
+ to the top left point of the window)scrolling leads to different values.
+ */
+ enum CoordinateSystem {
+ WindowCoordinateSystem,
+ ModelCoordinateSystem
+ };
+
+ /** Return the bounding box of the page object or one of its graphical
+ parts.
+ @param rWindow
+ This device is used to translate between model and window
+ coordinates.
+ @param rpPageDescriptor
+ The page for which to calculate the bounding box. This may be
+ NULL. When it is NULL then a generic bounding box is calculated
+ for the location (0,0).
+ @param ePart
+ The part of the page object for which to return the bounding
+ box.
+ @param eCoordinateSystem
+ The bounding box can be returned in model and in pixel
+ (window) coordinates.
+ @param bIgnoreLocation
+ Return a position ignoring the slides' location, ie. as if
+ we were the first slide.
+ */
+ ::tools::Rectangle GetBoundingBox (
+ const model::SharedPageDescriptor& rpPageDescriptor,
+ const Part ePart,
+ const CoordinateSystem eCoordinateSystem,
+ bool bIgnoreLocation = false);
+
+ /// the size of the embedded preview: position independent, in window coordinate system
+ Size GetPreviewSize();
+
+ /// the maximum size of each tile, also position independent, in window coordinate system
+ Size GetGridMaxSize();
+
+ const Image& GetTransitionEffectIcon() const { return maTransitionEffectIcon;}
+ const Image& GetCustomAnimationEffectIcon() const { return maCustomAnimationEffectIcon;}
+
+private:
+ ::tools::Rectangle GetBoundingBox (
+ const Point& rPageObjectLocation,
+ const Part ePart,
+ const CoordinateSystem eCoordinateSystem);
+
+private:
+ VclPtr<sd::Window> mpWindow;
+ ::tools::Rectangle maFocusIndicatorBoundingBox;
+ ::tools::Rectangle maPageObjectBoundingBox;
+ ::tools::Rectangle maPageNumberAreaBoundingBox;
+ ::tools::Rectangle maPreviewBoundingBox;
+ ::tools::Rectangle maTransitionEffectBoundingBox;
+ ::tools::Rectangle maCustomAnimationEffectBoundingBox;
+ const Image maTransitionEffectIcon;
+ const Image maCustomAnimationEffectIcon;
+ const std::shared_ptr<vcl::Font> mpPageNumberFont;
+
+ Size GetPageNumberAreaSize (const int nPageCount);
+ ::tools::Rectangle CalculatePreviewBoundingBox (
+ Size& rPageObjectSize,
+ const Size& rPreviewModelSize,
+ const sal_Int32 nPageNumberAreaWidth,
+ const sal_Int32 nFocusIndicatorWidth);
+};
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/view/SlsPageObjectPainter.hxx b/sd/source/ui/slidesorter/inc/view/SlsPageObjectPainter.hxx
new file mode 100644
index 000000000..747c09500
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/view/SlsPageObjectPainter.hxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsSharedPageDescriptor.hxx>
+#include <view/SlsTheme.hxx>
+#include <memory>
+
+namespace sd::slidesorter::cache { class PageCache; }
+namespace sd::slidesorter { class SlideSorter; }
+
+namespace sd::slidesorter::view {
+
+class Layouter;
+class PageObjectLayouter;
+class FramePainter;
+
+class PageObjectPainter
+{
+public:
+ PageObjectPainter (const SlideSorter& rSlideSorter);
+ ~PageObjectPainter();
+
+ void PaintPageObject (
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor);
+
+ /** Called when the theme changes, either because it is replaced with
+ another or because the system colors have changed. So, even when
+ the given theme is the same object as the one already in use by this
+ painter everything that depends on the theme is updated.
+ */
+ void SetTheme (const std::shared_ptr<view::Theme>& rpTheme);
+
+ /** Return a preview bitmap for the given page descriptor. When the
+ page is excluded from the show then the preview is marked
+ accordingly.
+ @rpDescriptor
+ Defines the page for which to return the preview.
+ @pReferenceDevice
+ When not <NULL/> then this reference device is used to created a
+ compatible bitmap.
+ @return
+ The returned bitmap may have a different size then the preview area.
+ */
+ BitmapEx GetPreviewBitmap (
+ const model::SharedPageDescriptor& rpDescriptor,
+ const OutputDevice* pReferenceDevice) const;
+
+private:
+ const Layouter& mrLayouter;
+ std::shared_ptr<cache::PageCache> mpCache;
+ std::shared_ptr<view::Theme> mpTheme;
+ std::shared_ptr<vcl::Font> mpPageNumberFont;
+ std::unique_ptr<FramePainter> mpShadowPainter;
+ std::unique_ptr<FramePainter> mpFocusBorderPainter;
+
+ void PaintBackground (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor) const;
+ void PaintPreview (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor) const;
+ void PaintPageNumber (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor) const;
+ static void PaintTransitionEffect (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor);
+ static void PaintCustomAnimationEffect (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor);
+ void PaintBorder (
+ OutputDevice& rDevice,
+ const Theme::GradientColorType eColorType,
+ const ::tools::Rectangle& rBox) const;
+ void PaintBackgroundDetail(
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor) const;
+
+ static BitmapEx CreateMarkedPreview(
+ const Size& rSize,
+ const BitmapEx& rPreview,
+ const BitmapEx& rOverlay,
+ const OutputDevice* pReferenceDevice);
+
+ /** Update the local pointer to the page object layouter to the
+ one owned by the general layouter.
+ Return <TRUE/> when after the call we have a valid page object layouter.
+ */
+ bool UpdatePageObjectLayouter();
+};
+
+} // end of namespace sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/view/SlsTheme.hxx b/sd/source/ui/slidesorter/inc/view/SlsTheme.hxx
new file mode 100644
index 000000000..efb7b2a3e
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/view/SlsTheme.hxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/bitmapex.hxx>
+#include <tools/color.hxx>
+
+#include <memory>
+
+namespace vcl { class Font; }
+
+namespace sd::slidesorter::controller { class Properties; }
+
+namespace sd::slidesorter::view {
+
+const int Theme_FocusIndicatorWidth = 3;
+
+/** Collection of colors and styles that are used to paint the slide sorter
+ view.
+*/
+class Theme
+{
+public:
+ Theme (const std::shared_ptr<controller::Properties>& rpProperties);
+
+ /** Call this method to update some colors as response to a change of
+ a system color change.
+ */
+ void Update (
+ const std::shared_ptr<controller::Properties>& rpProperties);
+
+ // BitmapEx GetInsertIndicatorIcon() const;
+
+ enum FontType {
+ Font_PageNumber,
+ Font_PageCount
+ };
+ static std::shared_ptr<vcl::Font> GetFont (
+ const FontType eType,
+ const OutputDevice& rDevice);
+
+ enum ColorType {
+ Color_Background,
+ Color_PageNumberDefault,
+ Color_PageNumberHover,
+ Color_PageNumberHighContrast,
+ Color_PageNumberBrightBackground,
+ Color_PageNumberDarkBackground,
+ Color_Selection,
+ Color_PreviewBorder,
+ Color_PageCountFontColor,
+ ColorType_Size_
+ };
+ Color GetColor (const ColorType eType);
+
+ enum GradientColorType {
+ Gradient_NormalPage,
+ Gradient_SelectedPage,
+ Gradient_SelectedAndFocusedPage,
+ Gradient_MouseOverPage,
+ Gradient_MouseOverSelected,
+ Gradient_MouseOverSelectedAndFocusedPage,
+ Gradient_FocusedPage,
+ GradientColorType_Size_
+ };
+ enum class GradientColorClass {
+ Border1,
+ Border2,
+ Fill1,
+ Fill2
+ };
+ Color GetGradientColor (
+ const GradientColorType eType,
+ const GradientColorClass eClass);
+ void SetGradient (
+ const GradientColorType eType,
+ const Color aBaseColor,
+ const sal_Int32 nSaturationOverride,
+ const sal_Int32 nBrightnessOverride,
+ const sal_Int32 nFillStartOffset,
+ const sal_Int32 nFillEndOffset,
+ const sal_Int32 nBorderStartOffset,
+ const sal_Int32 nBorderEndOffset);
+
+ enum IconType
+ {
+ Icon_RawShadow,
+ Icon_RawInsertShadow,
+ Icon_HideSlideOverlay,
+ Icon_FocusBorder,
+ IconType_Size_
+ };
+ const BitmapEx& GetIcon (const IconType eType);
+
+private:
+ class GradientDescriptor
+ {
+ public:
+ Color maFillColor1;
+ Color maFillColor2;
+ Color maBorderColor1;
+ Color maBorderColor2;
+ };
+ Color maBackgroundColor;
+ ::std::vector<GradientDescriptor> maGradients;
+ ::std::vector<BitmapEx> maIcons;
+ ::std::vector<Color> maColor;
+
+ GradientDescriptor& GetGradient (const GradientColorType eType);
+ /** Guarded initialization of the specified icon in the maIcons
+ container.
+ */
+ void InitializeIcon(const IconType eType, const OUString& rResourceId);
+};
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/inc/view/SlsToolTip.hxx b/sd/source/ui/slidesorter/inc/view/SlsToolTip.hxx
new file mode 100644
index 000000000..6c3557e64
--- /dev/null
+++ b/sd/source/ui/slidesorter/inc/view/SlsToolTip.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <model/SlsSharedPageDescriptor.hxx>
+#include <rtl/ustring.hxx>
+#include <vcl/timer.hxx>
+
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+
+namespace sd::slidesorter::view
+{
+/** Manage the display of tool tips. The tool tip text changes when the
+ mouse is moved from slide to slide or from button to button.
+ After the mouse enters a slide the first display of the tool tip is
+ delayed for a short time in order to not draw attention from the slide
+ or its button bar.
+*/
+class ToolTip
+{
+public:
+ ToolTip(SlideSorter& rSlideSorter);
+ ~ToolTip();
+
+ /** Set a new page. This modifies the default help text. After a page
+ change a timer is started to delay the display of the tool tip for
+ the new page.
+ @param rpPage
+ When this is empty then the tool tip is hidden.
+ */
+ void SetPage(const model::SharedPageDescriptor& rpPage);
+
+ /** Hide the tool tip.
+ @return
+ Returns whether the tool tip was visible at the time this method
+ was called.
+ */
+ bool Hide();
+
+private:
+ SlideSorter& mrSlideSorter;
+ model::SharedPageDescriptor mpDescriptor;
+ OUString msCurrentHelpText;
+ void* mnHelpWindowHandle;
+ Timer maShowTimer;
+ Timer maHiddenTimer;
+
+ void DoShow();
+
+ DECL_LINK(DelayTrigger, Timer*, void);
+};
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/model/SlideSorterModel.cxx b/sd/source/ui/slidesorter/model/SlideSorterModel.cxx
new file mode 100644
index 000000000..4d3e79656
--- /dev/null
+++ b/sd/source/ui/slidesorter/model/SlideSorterModel.cxx
@@ -0,0 +1,676 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <model/SlideSorterModel.hxx>
+
+#include <SlideSorter.hxx>
+#include <sal/log.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <controller/SlsSlotManager.hxx>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XController.hpp>
+
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+
+#include <ViewShellBase.hxx>
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <FrameView.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::slidesorter::model {
+
+namespace {
+ bool PrintModel (const SlideSorterModel& rModel)
+ {
+ for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex)
+ {
+ SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
+ if (pDescriptor)
+ {
+ SAL_INFO(
+ "sd.sls",
+ nIndex << " " << pDescriptor->GetPageIndex() << " "
+ << pDescriptor->GetVisualState().mnPageId << " "
+ << FromCoreIndex(pDescriptor->GetPage()->GetPageNum())
+ << " " << pDescriptor->GetPage());
+ }
+ else
+ {
+ SAL_INFO("sd.sls", nIndex);
+ }
+ }
+
+ return true;
+ }
+ bool CheckModel (const SlideSorterModel& rModel)
+ {
+ for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex)
+ {
+ SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
+ if ( ! pDescriptor)
+ {
+ PrintModel(rModel);
+ assert(pDescriptor);
+ return false;
+ }
+ if (nIndex != pDescriptor->GetPageIndex())
+ {
+ PrintModel(rModel);
+ assert(nIndex == pDescriptor->GetPageIndex());
+ return false;
+ }
+ if (nIndex != pDescriptor->GetVisualState().mnPageId)
+ {
+ PrintModel(rModel);
+ assert(nIndex == pDescriptor->GetVisualState().mnPageId);
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
+namespace {
+
+void collectUIInformation(const OUString& num, const OUString& rAction)
+{
+ EventDescription aDescription;
+ aDescription.aID = "impress_win_or_draw_win";
+ aDescription.aParameters = {{"POS", num}};
+ aDescription.aAction = rAction;
+ aDescription.aKeyWord = "ImpressWindowUIObject";
+ aDescription.aParent = "MainWindow";
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+SlideSorterModel::SlideSorterModel (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ meEditMode(EditMode::Page),
+ maPageDescriptors(0)
+{
+}
+
+SlideSorterModel::~SlideSorterModel()
+{
+ ClearDescriptorList ();
+}
+
+void SlideSorterModel::Dispose()
+{
+ ClearDescriptorList ();
+}
+
+SdDrawDocument* SlideSorterModel::GetDocument()
+{
+ if (mrSlideSorter.GetViewShellBase() != nullptr)
+ return mrSlideSorter.GetViewShellBase()->GetDocument();
+ else
+ return nullptr;
+}
+
+bool SlideSorterModel::SetEditMode (EditMode eEditMode)
+{
+ bool bEditModeChanged = false;
+ if (meEditMode != eEditMode)
+ {
+ meEditMode = eEditMode;
+ UpdatePageList();
+ bEditModeChanged = true;
+ }
+ return bEditModeChanged;
+}
+
+sal_Int32 SlideSorterModel::GetPageCount() const
+{
+ return maPageDescriptors.size();
+}
+
+SharedPageDescriptor SlideSorterModel::GetPageDescriptor (
+ const sal_Int32 nPageIndex,
+ const bool bCreate) const
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ SharedPageDescriptor pDescriptor;
+
+ if (nPageIndex>=0 && nPageIndex<GetPageCount())
+ {
+ pDescriptor = maPageDescriptors[nPageIndex];
+ if (pDescriptor == nullptr && bCreate && mxSlides.is())
+ {
+ SdPage* pPage = GetPage(nPageIndex);
+ pDescriptor = std::make_shared<PageDescriptor>(
+ Reference<drawing::XDrawPage>(mxSlides->getByIndex(nPageIndex),UNO_QUERY),
+ pPage,
+ nPageIndex);
+ maPageDescriptors[nPageIndex] = pDescriptor;
+ }
+ }
+
+ return pDescriptor;
+}
+
+sal_Int32 SlideSorterModel::GetIndex (const Reference<drawing::XDrawPage>& rxSlide) const
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // First try to guess the right index.
+ Reference<beans::XPropertySet> xSet (rxSlide, UNO_QUERY);
+ if (xSet.is())
+ {
+ try
+ {
+ const Any aNumber (xSet->getPropertyValue("Number"));
+ sal_Int16 nNumber (-1);
+ aNumber >>= nNumber;
+ nNumber -= 1;
+ SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false));
+ if (pDescriptor
+ && pDescriptor->GetXDrawPage() == rxSlide)
+ {
+ return nNumber;
+ }
+ }
+ catch (uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ }
+
+ // Guess was wrong, iterate over all slides and search for the right
+ // one.
+ const sal_Int32 nCount (maPageDescriptors.size());
+ for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
+ {
+ SharedPageDescriptor pDescriptor (maPageDescriptors[nIndex]);
+
+ // Make sure that the descriptor exists. Without it the given slide
+ // can not be found.
+ if (!pDescriptor)
+ {
+ // Call GetPageDescriptor() to create the missing descriptor.
+ pDescriptor = GetPageDescriptor(nIndex);
+ }
+
+ if (pDescriptor->GetXDrawPage() == rxSlide)
+ return nIndex;
+ }
+
+ return -1;
+}
+
+sal_Int32 SlideSorterModel::GetIndex (const SdrPage* pPage) const
+{
+ if (pPage == nullptr)
+ return -1;
+
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // First try to guess the right index.
+ sal_Int16 nNumber ((pPage->GetPageNum()-1)/2);
+ SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false));
+ if (pDescriptor
+ && pDescriptor->GetPage() == pPage)
+ {
+ return nNumber;
+ }
+
+ // Guess was wrong, iterate over all slides and search for the right
+ // one.
+ const sal_Int32 nCount (maPageDescriptors.size());
+ for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
+ {
+ pDescriptor = maPageDescriptors[nIndex];
+
+ // Make sure that the descriptor exists. Without it the given slide
+ // can not be found.
+ if (!pDescriptor)
+ {
+ // Call GetPageDescriptor() to create the missing descriptor.
+ pDescriptor = GetPageDescriptor(nIndex);
+ }
+
+ if (pDescriptor->GetPage() == pPage)
+ return nIndex;
+ }
+
+ return -1;
+}
+
+sal_uInt16 SlideSorterModel::GetCoreIndex (const sal_Int32 nIndex) const
+{
+ SharedPageDescriptor pDescriptor (GetPageDescriptor(nIndex));
+ if (pDescriptor)
+ return pDescriptor->GetPage()->GetPageNum();
+ else
+ return mxSlides->getCount()*2+1;
+}
+
+/** For now this method uses a trivial algorithm: throw away all descriptors
+ and create them anew (on demand). The main problem that we are facing
+ when designing a better algorithm is that we can not compare pointers to
+ pages stored in the PageDescriptor objects and those obtained from the
+ document: pages may have been deleted and others may have been created
+ at the exact same memory locations.
+*/
+void SlideSorterModel::Resync()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Check if document and this model really differ.
+ bool bIsUpToDate (true);
+ SdDrawDocument* pDocument = GetDocument();
+ if (pDocument!=nullptr && maPageDescriptors.size()==pDocument->GetSdPageCount(PageKind::Standard))
+ {
+ for (sal_Int32 nIndex=0,nCount=maPageDescriptors.size(); nIndex<nCount; ++nIndex)
+ {
+ if (maPageDescriptors[nIndex]
+ && maPageDescriptors[nIndex]->GetPage()
+ != GetPage(nIndex))
+ {
+ SAL_INFO("sd.sls", "page " << nIndex << " differs");
+ bIsUpToDate = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ bIsUpToDate = false;
+ }
+
+ if ( ! bIsUpToDate)
+ {
+ SynchronizeDocumentSelection(); // Try to make the current selection persistent.
+ ClearDescriptorList ();
+ AdaptSize();
+ SynchronizeModelSelection();
+ mrSlideSorter.GetController().GetPageSelector().CountSelectedPages();
+ }
+ CheckModel(*this);
+}
+
+void SlideSorterModel::ClearDescriptorList()
+{
+ ::std::vector<SharedPageDescriptor> aDescriptors;
+
+ {
+ ::osl::MutexGuard aGuard (maMutex);
+ aDescriptors.swap(maPageDescriptors);
+ }
+
+ for (auto& rxDescriptor : aDescriptors)
+ {
+ if (rxDescriptor != nullptr)
+ {
+ if (rxDescriptor.use_count() > 1)
+ {
+ SAL_INFO(
+ "sd.sls",
+ "trying to delete page descriptor that is still used with"
+ " count " << rxDescriptor.use_count());
+ // No assertion here because that can hang the office when
+ // opening a dialog from here.
+ }
+ rxDescriptor.reset();
+ }
+ }
+}
+
+void SlideSorterModel::SynchronizeDocumentSelection()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
+ while (aAllPages.HasMoreElements())
+ {
+ SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
+ const bool bIsSelected (pDescriptor->HasState(PageDescriptor::ST_Selected));
+ pDescriptor->GetPage()->SetSelected(bIsSelected);
+ }
+}
+
+void SlideSorterModel::SynchronizeModelSelection()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
+ while (aAllPages.HasMoreElements())
+ {
+ SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
+ const bool bIsSelected (pDescriptor->GetPage()->IsSelected());
+ pDescriptor->SetState(PageDescriptor::ST_Selected, bIsSelected);
+ }
+}
+
+void SlideSorterModel::SetDocumentSlides (
+ const Reference<container::XIndexAccess>& rxSlides)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Make the current selection persistent and then release the
+ // current set of pages.
+ SynchronizeDocumentSelection();
+ mxSlides = nullptr;
+ ClearDescriptorList ();
+
+ // Reset the current page to cause everybody to release references to it.
+ mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(-1);
+
+ // Set the new set of pages.
+ mxSlides = rxSlides;
+ AdaptSize();
+ SynchronizeModelSelection();
+ mrSlideSorter.GetController().GetPageSelector().CountSelectedPages();
+
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(*this));
+ if (aSelectedPages.HasMoreElements())
+ {
+ SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
+ pDescriptor->GetPage());
+ }
+
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (pViewShell != nullptr)
+ {
+ SdPage* pPage = pViewShell->getCurrentPage();
+ if (pPage != nullptr)
+ mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
+ pPage);
+ else
+ {
+ // No current page. This can only be when the slide sorter is
+ // the main view shell. Get current slide form frame view.
+ const FrameView* pFrameView = pViewShell->GetFrameView();
+ if (pFrameView != nullptr)
+ mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
+ pFrameView->GetSelectedPage());
+ else
+ {
+ // No frame view. As a last resort use the first slide as
+ // current slide.
+ mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
+ sal_Int32(0));
+ }
+ }
+ }
+
+ mrSlideSorter.GetController().GetSlotManager()->NotifyEditModeChange();
+}
+
+Reference<container::XIndexAccess> SlideSorterModel::GetDocumentSlides() const
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ return mxSlides;
+}
+
+void SlideSorterModel::UpdatePageList()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ Reference<container::XIndexAccess> xPages;
+
+ // Get the list of pages according to the edit mode.
+ Reference<frame::XController> xController (mrSlideSorter.GetXController());
+ if (xController.is())
+ {
+ switch (meEditMode)
+ {
+ case EditMode::MasterPage:
+ {
+ Reference<drawing::XMasterPagesSupplier> xSupplier (
+ xController->getModel(), UNO_QUERY);
+ if (xSupplier.is())
+ {
+ xPages = xSupplier->getMasterPages();
+ }
+ }
+ break;
+
+ case EditMode::Page:
+ {
+ Reference<drawing::XDrawPagesSupplier> xSupplier (
+ xController->getModel(), UNO_QUERY);
+ if (xSupplier.is())
+ {
+ xPages = xSupplier->getDrawPages();
+ }
+ }
+ break;
+
+ default:
+ // We should never get here.
+ assert(false);
+ break;
+ }
+ }
+
+ mrSlideSorter.GetController().SetDocumentSlides(xPages);
+}
+
+void SlideSorterModel::AdaptSize()
+{
+ if (mxSlides.is())
+ maPageDescriptors.resize(mxSlides->getCount());
+ else
+ maPageDescriptors.resize(0);
+}
+
+bool SlideSorterModel::IsReadOnly() const
+{
+ if (mrSlideSorter.GetViewShellBase() != nullptr
+ && mrSlideSorter.GetViewShellBase()->GetDocShell())
+ return mrSlideSorter.GetViewShellBase()->GetDocShell()->IsReadOnly();
+ else
+ return true;
+}
+
+void SlideSorterModel::SaveCurrentSelection()
+{
+ PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
+ while (aPages.HasMoreElements())
+ {
+ SharedPageDescriptor pDescriptor (aPages.GetNextElement());
+ pDescriptor->SetState(
+ PageDescriptor::ST_WasSelected,
+ pDescriptor->HasState(PageDescriptor::ST_Selected));
+ }
+}
+
+vcl::Region SlideSorterModel::RestoreSelection()
+{
+ vcl::Region aRepaintRegion;
+ PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
+ while (aPages.HasMoreElements())
+ {
+ SharedPageDescriptor pDescriptor (aPages.GetNextElement());
+ if (pDescriptor->SetState(
+ PageDescriptor::ST_Selected,
+ pDescriptor->HasState(PageDescriptor::ST_WasSelected)))
+ {
+ aRepaintRegion.Union(pDescriptor->GetBoundingBox());
+ }
+ }
+ return aRepaintRegion;
+}
+
+bool SlideSorterModel::NotifyPageEvent (const SdrPage* pSdrPage)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ SdPage* pPage = const_cast<SdPage*>(dynamic_cast<const SdPage*>(pSdrPage));
+ if (pPage == nullptr)
+ return false;
+
+ // We are only interested in pages that are currently served by this
+ // model.
+ if (pPage->GetPageKind() != PageKind::Standard)
+ return false;
+ if (pPage->IsMasterPage() != (meEditMode==EditMode::MasterPage))
+ return false;
+
+ //NotifyPageEvent is called for add, remove, *and* change position so for
+ //the change position case we must ensure we don't end up with the slide
+ //duplicated in our list
+ bool bSelected = DeleteSlide(pPage);
+ if (pPage->IsInserted())
+ {
+ InsertSlide(pPage, bSelected);
+ }
+ CheckModel(*this);
+
+ return true;
+}
+
+void SlideSorterModel::InsertSlide(SdPage* pPage, bool bMarkSelected)
+{
+ // Find the index at which to insert the given page.
+ sal_uInt16 nCoreIndex (pPage->GetPageNum());
+ sal_Int32 nIndex (FromCoreIndex(nCoreIndex));
+ if (pPage != GetPage(nIndex))
+ return;
+
+ // Check that the pages in the document before and after the given page
+ // are present in this model.
+ if (nIndex>0)
+ if (GetPage(nIndex-1) != GetPageDescriptor(nIndex-1)->GetPage())
+ return;
+ if (nIndex < static_cast<sal_Int32>(maPageDescriptors.size()) -1)
+ if (GetPage(nIndex+1) != GetPageDescriptor(nIndex)->GetPage())
+ return;
+
+ auto iter = maPageDescriptors.begin() + nIndex;
+
+ // Insert the given page at index nIndex
+ iter = maPageDescriptors.insert(
+ iter,
+ std::make_shared<PageDescriptor>(
+ Reference<drawing::XDrawPage>(mxSlides->getByIndex(nIndex),UNO_QUERY),
+ pPage,
+ nIndex));
+
+ if (bMarkSelected)
+ (*iter)->SetState(PageDescriptor::ST_Selected, true);
+
+ // Update page indices.
+ UpdateIndices(nIndex+1);
+}
+
+bool SlideSorterModel::DeleteSlide (const SdPage* pPage)
+{
+ sal_Int32 nIndex(0);
+
+ // Caution, GetIndex() may be negative since it uses GetPageNumber()-1
+ // for calculation, so do this only when page is inserted, else the
+ // GetPageNumber() will be zero and thus GetIndex() == -1
+ if(pPage->IsInserted())
+ {
+ nIndex = GetIndex(pPage);
+ }
+ else
+ {
+ // if not inserted, search for page
+ for(; nIndex < static_cast<sal_Int32>(maPageDescriptors.size()); nIndex++)
+ {
+ if(maPageDescriptors[nIndex]->GetPage() == pPage)
+ {
+ break;
+ }
+ }
+ }
+
+ bool bMarkedSelected(false);
+
+ if(nIndex >= 0 && o3tl::make_unsigned(nIndex) < maPageDescriptors.size())
+ {
+ if (maPageDescriptors[nIndex])
+ if (maPageDescriptors[nIndex]->GetPage() != pPage)
+ return false;
+
+ auto iter = maPageDescriptors.begin() + nIndex;
+ bMarkedSelected = (*iter)->HasState(PageDescriptor::ST_Selected);
+ maPageDescriptors.erase(iter);
+ UpdateIndices(nIndex);
+
+ collectUIInformation(OUString::number(nIndex + 1), "Delete_Slide_or_Page");
+ }
+ return bMarkedSelected;
+}
+
+void SlideSorterModel::UpdateIndices (const sal_Int32 nFirstIndex)
+{
+ for (sal_Int32 nDescriptorIndex=0,nCount=maPageDescriptors.size();
+ nDescriptorIndex<nCount;
+ ++nDescriptorIndex)
+ {
+ SharedPageDescriptor& rpDescriptor (maPageDescriptors[nDescriptorIndex]);
+ if (rpDescriptor)
+ {
+ if (nDescriptorIndex < nFirstIndex)
+ {
+ if (rpDescriptor->GetPageIndex()!=nDescriptorIndex)
+ {
+ assert(rpDescriptor->GetPageIndex()==nDescriptorIndex);
+ }
+ }
+ else
+ {
+ rpDescriptor->SetPageIndex(nDescriptorIndex);
+ }
+ }
+ }
+}
+
+SdPage* SlideSorterModel::GetPage (const sal_Int32 nSdIndex) const
+{
+ SdDrawDocument* pModel = const_cast<SlideSorterModel*>(this)->GetDocument();
+ if (pModel != nullptr)
+ {
+ if (meEditMode == EditMode::Page)
+ return pModel->GetSdPage (static_cast<sal_uInt16>(nSdIndex), PageKind::Standard);
+ else
+ return pModel->GetMasterSdPage (static_cast<sal_uInt16>(nSdIndex), PageKind::Standard);
+ }
+ else
+ return nullptr;
+}
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx b/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx
new file mode 100644
index 000000000..5118cf58e
--- /dev/null
+++ b/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <model/SlsPageDescriptor.hxx>
+
+#include <sdpage.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+namespace sd::slidesorter::model {
+
+PageDescriptor::PageDescriptor (
+ const Reference<drawing::XDrawPage>& rxPage,
+ SdPage* pPage,
+ const sal_Int32 nIndex)
+ : mpPage(pPage),
+ mxPage(rxPage),
+ mpMasterPage(nullptr),
+ mnIndex(nIndex),
+ maVisualState(nIndex),
+ mbIsSelected(false),
+ mbWasSelected(false),
+ mbIsVisible(false),
+ mbIsFocused(false),
+ mbIsCurrent(false),
+ mbIsMouseOver(false),
+ mbHasTransition(false)
+{
+ assert(mpPage);
+ assert(mpPage == SdPage::getImplementation(rxPage));
+ if (mpPage != nullptr)
+ {
+ if (mpPage->TRG_HasMasterPage())
+ mpMasterPage = &mpPage->TRG_GetMasterPage();
+ if (mpPage->getTransitionType() > 0)
+ mbHasTransition = true;
+ }
+}
+
+PageDescriptor::~PageDescriptor()
+{
+}
+
+void PageDescriptor::SetPageIndex (const sal_Int32 nNewIndex)
+{
+ mnIndex = nNewIndex;
+ maVisualState.mnPageId = nNewIndex;
+}
+
+bool PageDescriptor::UpdateMasterPage()
+{
+ const SdrPage* pMaster = nullptr;
+ if (mpPage!=nullptr && mpPage->TRG_HasMasterPage())
+ pMaster = &mpPage->TRG_GetMasterPage();
+ if (mpMasterPage != pMaster)
+ {
+ mpMasterPage = pMaster;
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PageDescriptor::UpdateTransitionFlag()
+{
+ bool bHasSlideTransition (false);
+ if (mpPage != nullptr)
+ bHasSlideTransition = mpPage->getTransitionType() > 0;
+ if (bHasSlideTransition != mbHasTransition)
+ {
+ mbHasTransition = bHasSlideTransition;
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PageDescriptor::HasState (const State eState) const
+{
+ switch (eState)
+ {
+ case ST_Visible:
+ return mbIsVisible;
+
+ case ST_Selected:
+ return mbIsSelected;
+
+ case ST_WasSelected:
+ return mbWasSelected;
+
+ case ST_Focused:
+ return mbIsFocused;
+
+ case ST_MouseOver:
+ return mbIsMouseOver;
+
+ case ST_Current:
+ return mbIsCurrent;
+
+ case ST_Excluded:
+ return mpPage!=nullptr && mpPage->IsExcluded();
+
+ default:
+ assert(false);
+ return false;
+ }
+}
+
+bool PageDescriptor::SetState (const State eState, const bool bNewStateValue)
+{
+ bool bModified (false);
+ switch (eState)
+ {
+ case ST_Visible:
+ bModified = (bNewStateValue!=mbIsVisible);
+ if (bModified)
+ mbIsVisible = bNewStateValue;
+ break;
+
+ case ST_Selected:
+ bModified = (bNewStateValue!=mbIsSelected);
+ if (bModified)
+ mbIsSelected = bNewStateValue;
+ break;
+
+ case ST_WasSelected:
+ bModified = (bNewStateValue!=mbWasSelected);
+ if (bModified)
+ mbWasSelected = bNewStateValue;
+ break;
+
+ case ST_Focused:
+ bModified = (bNewStateValue!=mbIsFocused);
+ if (bModified)
+ mbIsFocused = bNewStateValue;
+ break;
+
+ case ST_MouseOver:
+ bModified = (bNewStateValue!=mbIsMouseOver);
+ if (bModified)
+ mbIsMouseOver = bNewStateValue;
+ break;
+
+ case ST_Current:
+ bModified = (bNewStateValue!=mbIsCurrent);
+ if (bModified)
+ mbIsCurrent = bNewStateValue;
+ break;
+
+ case ST_Excluded:
+ // This is a state of the page and has to be handled differently
+ // from the view-only states.
+ if (mpPage != nullptr)
+ if (bNewStateValue != mpPage->IsExcluded())
+ {
+ mpPage->SetExcluded(bNewStateValue);
+ bModified = true;
+ }
+ break;
+ }
+
+ return bModified;
+}
+
+bool PageDescriptor::GetCoreSelection()
+{
+ if (mpPage!=nullptr && mpPage->IsSelected() != mbIsSelected)
+ return SetState(ST_Selected, !mbIsSelected);
+ else
+ return false;
+}
+
+void PageDescriptor::SetCoreSelection()
+{
+ if (mpPage != nullptr)
+ if (HasState(ST_Selected))
+ mpPage->SetSelected(true);
+ else
+ mpPage->SetSelected(false);
+ else
+ {
+ assert(mpPage!=nullptr);
+ }
+}
+
+::tools::Rectangle PageDescriptor::GetBoundingBox() const
+{
+ ::tools::Rectangle aBox (maBoundingBox);
+ const Point aOffset (maVisualState.GetLocationOffset());
+ aBox.Move(aOffset.X(), aOffset.Y());
+ return aBox;
+}
+
+Point PageDescriptor::GetLocation (const bool bIgnoreOffset) const
+{
+ if (bIgnoreOffset)
+ return maBoundingBox.TopLeft();
+ else
+ return maBoundingBox.TopLeft() + maVisualState.GetLocationOffset();
+}
+
+void PageDescriptor::SetBoundingBox (const ::tools::Rectangle& rBoundingBox)
+{
+ maBoundingBox = rBoundingBox;
+}
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/model/SlsPageEnumeration.cxx b/sd/source/ui/slidesorter/model/SlsPageEnumeration.cxx
new file mode 100644
index 000000000..a67f057e7
--- /dev/null
+++ b/sd/source/ui/slidesorter/model/SlsPageEnumeration.cxx
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+
+#include <utility>
+
+#include <model/SlsPageEnumeration.hxx>
+#include <model/SlideSorterModel.hxx>
+
+using namespace ::sd::slidesorter;
+using namespace ::sd::slidesorter::model;
+
+namespace {
+
+class PageEnumerationImpl
+ : public Enumeration<SharedPageDescriptor>
+{
+public:
+ PageEnumerationImpl (
+ const SlideSorterModel& rModel,
+ const PageEnumeration::PagePredicate& rPredicate);
+ PageEnumerationImpl(const PageEnumerationImpl&) = delete;
+ PageEnumerationImpl& operator=(const PageEnumerationImpl&) = delete;
+ /** Create a copy of the called enumeration object.
+ */
+ virtual ::std::unique_ptr<Enumeration<SharedPageDescriptor> > Clone() override;
+
+ virtual bool HasMoreElements() const override;
+ virtual SharedPageDescriptor GetNextElement() override;
+ virtual void Rewind() override;
+
+private:
+ const SlideSorterModel& mrModel;
+ const PageEnumeration::PagePredicate maPredicate;
+ int mnIndex;
+
+ /** This constructor sets the internal page index to the given value.
+ It does not call AdvanceToNextValidElement() to skip elements that
+ do not fulfill Predicate.
+ */
+ PageEnumerationImpl (
+ const SlideSorterModel& rModel,
+ const PageEnumeration::PagePredicate& rPredicate,
+ int nIndex);
+
+ /** Skip all elements that do not fulfill Predicate starting with the
+ one pointed to by mnIndex.
+ */
+ void AdvanceToNextValidElement();
+};
+
+} // end of anonymous namespace
+
+namespace sd::slidesorter::model {
+
+PageEnumeration PageEnumeration::Create (
+ const SlideSorterModel& rModel,
+ const PagePredicate& rPredicate)
+{
+ return PageEnumeration(::std::unique_ptr<Enumeration<SharedPageDescriptor> >(
+ new PageEnumerationImpl(rModel, rPredicate)));
+}
+
+PageEnumeration::PageEnumeration (
+ ::std::unique_ptr<Enumeration<SharedPageDescriptor> > && pImpl)
+ : mpImpl(std::move(pImpl))
+{
+}
+
+PageEnumeration::PageEnumeration (const PageEnumeration& rEnumeration )
+: sd::slidesorter::model::Enumeration<sd::slidesorter::model::SharedPageDescriptor>()
+{
+ mpImpl = rEnumeration.mpImpl->Clone();
+}
+
+PageEnumeration::~PageEnumeration()
+{
+}
+
+PageEnumeration& PageEnumeration::operator= (
+ const PageEnumeration& rEnumeration)
+{
+ mpImpl = rEnumeration.mpImpl->Clone();
+ return *this;
+}
+
+::std::unique_ptr<Enumeration<SharedPageDescriptor> > PageEnumeration::Clone()
+{
+ return ::std::unique_ptr<Enumeration<SharedPageDescriptor> >(
+ new PageEnumeration (*this));
+}
+
+bool PageEnumeration::HasMoreElements() const
+{
+ return mpImpl->HasMoreElements();
+}
+
+SharedPageDescriptor PageEnumeration::GetNextElement()
+{
+ return mpImpl->GetNextElement();
+}
+
+void PageEnumeration::Rewind()
+{
+ return mpImpl->Rewind();
+}
+
+} // end of namespace ::sd::slidesorter::model
+
+namespace {
+
+PageEnumerationImpl::PageEnumerationImpl (
+ const SlideSorterModel& rModel,
+ const PageEnumeration::PagePredicate& rPredicate)
+ : mrModel(rModel),
+ maPredicate(rPredicate),
+ mnIndex(0)
+{
+ Rewind();
+}
+
+PageEnumerationImpl::PageEnumerationImpl (
+ const SlideSorterModel& rModel,
+ const PageEnumeration::PagePredicate& rPredicate,
+ int nIndex)
+ : mrModel(rModel),
+ maPredicate(rPredicate),
+ mnIndex(nIndex)
+{
+}
+
+::std::unique_ptr<Enumeration<SharedPageDescriptor> >
+ PageEnumerationImpl::Clone()
+{
+ return ::std::unique_ptr<Enumeration<SharedPageDescriptor> >(
+ new PageEnumerationImpl(mrModel,maPredicate,mnIndex));
+}
+
+bool PageEnumerationImpl::HasMoreElements() const
+{
+ return (mnIndex < mrModel.GetPageCount());
+}
+
+SharedPageDescriptor PageEnumerationImpl::GetNextElement()
+{
+ SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(mnIndex));
+
+ // Go to the following valid element.
+ mnIndex += 1;
+ AdvanceToNextValidElement();
+
+ return pDescriptor;
+}
+
+void PageEnumerationImpl::Rewind()
+{
+ // Go to first valid element.
+ mnIndex = 0;
+ AdvanceToNextValidElement();
+}
+
+void PageEnumerationImpl::AdvanceToNextValidElement()
+{
+ while (mnIndex < mrModel.GetPageCount())
+ {
+ SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(mnIndex));
+
+ // Test for the predicate being fulfilled.
+ if (pDescriptor && maPredicate(pDescriptor))
+ {
+ // This predicate is valid.
+ break;
+ }
+ else
+ {
+ // Advance to next predicate.
+ mnIndex += 1;
+ }
+ }
+}
+
+} // end of anonymous namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx b/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx
new file mode 100644
index 000000000..800fa12db
--- /dev/null
+++ b/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.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 <model/SlsPageEnumerationProvider.hxx>
+#include <model/SlsPageEnumeration.hxx>
+#include <model/SlsPageDescriptor.hxx>
+
+namespace sd::slidesorter::model {
+
+namespace {
+
+class AllPagesPredicate
+{
+public:
+ bool operator() (const SharedPageDescriptor&) const
+ {
+ return true;
+ }
+};
+
+class SelectedPagesPredicate
+{
+public:
+ bool operator() (const SharedPageDescriptor& rpDescriptor)
+ {
+ return rpDescriptor->HasState(PageDescriptor::ST_Selected);
+ }
+};
+
+class VisiblePagesPredicate
+{
+public:
+ bool operator() (const SharedPageDescriptor& rpDescriptor)
+ {
+ return rpDescriptor->HasState(PageDescriptor::ST_Visible);
+ }
+};
+
+}
+
+PageEnumeration PageEnumerationProvider::CreateAllPagesEnumeration (
+ const SlideSorterModel& rModel)
+{
+ return PageEnumeration::Create(rModel, AllPagesPredicate());
+}
+
+PageEnumeration PageEnumerationProvider::CreateSelectedPagesEnumeration (
+ const SlideSorterModel& rModel)
+{
+ return PageEnumeration::Create(
+ rModel,
+ SelectedPagesPredicate());
+}
+
+PageEnumeration PageEnumerationProvider::CreateVisiblePagesEnumeration (
+ const SlideSorterModel& rModel)
+{
+ return PageEnumeration::Create(
+ rModel,
+ VisiblePagesPredicate());
+}
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/model/SlsVisualState.cxx b/sd/source/ui/slidesorter/model/SlsVisualState.cxx
new file mode 100644
index 000000000..3e16823ff
--- /dev/null
+++ b/sd/source/ui/slidesorter/model/SlsVisualState.cxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <model/SlsVisualState.hxx>
+
+namespace sd::slidesorter::model
+{
+VisualState::VisualState(const sal_Int32 nPageId)
+ : mnPageId(nPageId)
+ , maLocationOffset(0, 0)
+{
+}
+
+void VisualState::SetLocationOffset(const Point& rOffset)
+{
+ if (maLocationOffset != rOffset)
+ {
+ maLocationOffset = rOffset;
+ }
+}
+
+} // end of namespace ::sd::slidesorter::model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/shell/SlideSorter.cxx b/sd/source/ui/slidesorter/shell/SlideSorter.cxx
new file mode 100644
index 000000000..550a40469
--- /dev/null
+++ b/sd/source/ui/slidesorter/shell/SlideSorter.cxx
@@ -0,0 +1,456 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <SlideSorter.hxx>
+
+#include <com/sun/star/frame/XController.hpp>
+
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsScrollBarManager.hxx>
+#include <controller/SlsProperties.hxx>
+#include <controller/SlsAnimator.hxx>
+#include <o3tl/deleter.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsTheme.hxx>
+#include <model/SlideSorterModel.hxx>
+
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <Window.hxx>
+
+#include <tools/debug.hxx>
+#include <vcl/scrbar.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+namespace sd::slidesorter {
+
+namespace {
+class ContentWindow : public ::sd::Window
+{
+public:
+ ContentWindow(vcl::Window& rParent, SlideSorter& rSlideSorter);
+
+ void SetCurrentFunction (const rtl::Reference<FuPoor>& rpFunction);
+ virtual void Paint(vcl::RenderContext& /*rRenderContext*/, const ::tools::Rectangle& rRect) override;
+ virtual void KeyInput (const KeyEvent& rEvent) override;
+ virtual void MouseMove (const MouseEvent& rEvent) override;
+ virtual void MouseButtonUp (const MouseEvent& rEvent) override;
+ virtual void MouseButtonDown (const MouseEvent& rEvent) override;
+ virtual void Command (const CommandEvent& rEvent) override;
+ virtual bool EventNotify (NotifyEvent& rEvent) override;
+
+private:
+ SlideSorter& mrSlideSorter;
+ rtl::Reference<FuPoor> mpCurrentFunction;
+};
+}
+
+//===== SlideSorter ===========================================================
+
+std::shared_ptr<SlideSorter> SlideSorter::CreateSlideSorter(
+ ViewShell& rViewShell,
+ sd::Window* pContentWindow,
+ ScrollBar* pHorizontalScrollBar,
+ ScrollBar* pVerticalScrollBar,
+ ScrollBarBox* pScrollBarBox)
+{
+ std::shared_ptr<SlideSorter> pSlideSorter(
+ new SlideSorter(
+ rViewShell,
+ pContentWindow,
+ pHorizontalScrollBar,
+ pVerticalScrollBar,
+ pScrollBarBox),
+ o3tl::default_delete<SlideSorter>());
+ pSlideSorter->Init();
+ return pSlideSorter;
+}
+
+std::shared_ptr<SlideSorter> SlideSorter::CreateSlideSorter (
+ ViewShellBase& rBase,
+ vcl::Window& rParentWindow)
+{
+ std::shared_ptr<SlideSorter> pSlideSorter(
+ new SlideSorter(
+ rBase,
+ rParentWindow),
+ o3tl::default_delete<SlideSorter>());
+ pSlideSorter->Init();
+ return pSlideSorter;
+}
+
+SlideSorter::SlideSorter (
+ ViewShell& rViewShell,
+ sd::Window* pContentWindow,
+ ScrollBar* pHorizontalScrollBar,
+ ScrollBar* pVerticalScrollBar,
+ ScrollBarBox* pScrollBarBox)
+ : mbIsValid(false),
+ mpViewShell(&rViewShell),
+ mpViewShellBase(&rViewShell.GetViewShellBase()),
+ mpContentWindow(pContentWindow),
+ mpHorizontalScrollBar(pHorizontalScrollBar),
+ mpVerticalScrollBar(pVerticalScrollBar),
+ mpScrollBarBox(pScrollBarBox),
+ mpProperties(std::make_shared<controller::Properties>()),
+ mpTheme(std::make_shared<view::Theme>(mpProperties))
+{
+}
+
+SlideSorter::SlideSorter (
+ ViewShellBase& rBase,
+ vcl::Window& rParentWindow)
+ : mbIsValid(false),
+ mpViewShell(nullptr),
+ mpViewShellBase(&rBase),
+ mpContentWindow(VclPtr<ContentWindow>::Create(rParentWindow,*this )),
+ mpHorizontalScrollBar(VclPtr<ScrollBar>::Create(&rParentWindow,WinBits(WB_HSCROLL | WB_DRAG))),
+ mpVerticalScrollBar(VclPtr<ScrollBar>::Create(&rParentWindow,WinBits(WB_VSCROLL | WB_DRAG))),
+ mpScrollBarBox(VclPtr<ScrollBarBox>::Create(&rParentWindow)),
+ mpProperties(std::make_shared<controller::Properties>()),
+ mpTheme(std::make_shared<view::Theme>(mpProperties))
+{
+}
+
+void SlideSorter::Init()
+{
+ if (mpViewShellBase != nullptr)
+ mxControllerWeak = mpViewShellBase->GetController();
+
+ // Reinitialize colors in Properties with window specific values.
+ if (mpContentWindow)
+ {
+ mpProperties->SetBackgroundColor(
+ mpContentWindow->GetSettings().GetStyleSettings().GetWindowColor());
+ mpProperties->SetTextColor(
+ mpContentWindow->GetSettings().GetStyleSettings().GetWindowTextColor());
+ mpProperties->SetSelectionColor(
+ mpContentWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor());
+ mpProperties->SetHighlightColor(
+ mpContentWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor());
+ }
+
+ CreateModelViewController ();
+
+ SetupListeners ();
+
+ // Initialize the window.
+ sd::Window *pContentWindow = GetContentWindow().get();
+ if (!pContentWindow)
+ return;
+
+ vcl::Window* pParentWindow = pContentWindow->GetParent();
+ if (pParentWindow != nullptr)
+ pParentWindow->SetBackground(Wallpaper());
+ pContentWindow->SetBackground(Wallpaper());
+ pContentWindow->SetViewOrigin (Point(0,0));
+ // We do our own scrolling while dragging a page selection.
+ pContentWindow->SetUseDropScroll (false);
+ // Change the winbits so that the active window accepts the focus.
+ pContentWindow->SetStyle ((pContentWindow->GetStyle() & ~WB_DIALOGCONTROL) | WB_TABSTOP);
+ pContentWindow->Hide();
+
+ // Set view pointer of base class.
+ SetupControls();
+
+ mbIsValid = true;
+}
+
+SlideSorter::~SlideSorter()
+{
+ mbIsValid = false;
+
+ ReleaseListeners();
+
+ // Dispose model, view and controller to avoid calls between them when
+ // they are being destructed and one or two of them are already gone.
+ mpSlideSorterController->Dispose();
+ mpSlideSorterView->Dispose();
+ mpSlideSorterModel->Dispose();
+
+ // Reset the auto pointers explicitly to control the order of destruction.
+ mpSlideSorterController.reset();
+ mpSlideSorterView.reset();
+ mpSlideSorterModel.reset();
+
+ mpHorizontalScrollBar.reset();
+ mpVerticalScrollBar.reset();
+ mpScrollBarBox.reset();
+}
+
+model::SlideSorterModel& SlideSorter::GetModel() const
+{
+ assert(mpSlideSorterModel);
+ return *mpSlideSorterModel;
+}
+
+view::SlideSorterView& SlideSorter::GetView() const
+{
+ assert(mpSlideSorterView);
+ return *mpSlideSorterView;
+}
+
+controller::SlideSorterController& SlideSorter::GetController() const
+{
+ assert(mpSlideSorterController);
+ return *mpSlideSorterController;
+}
+
+Reference<frame::XController> SlideSorter::GetXController() const
+{
+ Reference<frame::XController> xController(mxControllerWeak);
+ return xController;
+}
+
+void SlideSorter::Paint (const ::tools::Rectangle& rRepaintArea)
+{
+ GetController().Paint(
+ rRepaintArea,
+ GetContentWindow());
+}
+
+void SlideSorter::SetupControls()
+{
+ GetVerticalScrollBar()->Show();
+}
+
+void SlideSorter::SetupListeners()
+{
+ sd::Window *pWindow = GetContentWindow().get();
+ if (pWindow)
+ {
+ vcl::Window* pParentWindow = pWindow->GetParent();
+ if (pParentWindow != nullptr)
+ pParentWindow->AddEventListener(
+ LINK(
+ mpSlideSorterController.get(),
+ controller::SlideSorterController,
+ WindowEventHandler));
+ pWindow->AddEventListener(
+ LINK(
+ mpSlideSorterController.get(),
+ controller::SlideSorterController,
+ WindowEventHandler));
+ }
+ Application::AddEventListener(
+ LINK(
+ mpSlideSorterController.get(),
+ controller::SlideSorterController,
+ ApplicationEventHandler));
+
+ mpSlideSorterController->GetScrollBarManager().Connect();
+}
+
+void SlideSorter::ReleaseListeners()
+{
+ mpSlideSorterController->GetScrollBarManager().Disconnect();
+
+ sd::Window *pWindow (GetContentWindow().get());
+ if (pWindow)
+ {
+ pWindow->RemoveEventListener(
+ LINK(mpSlideSorterController.get(),
+ controller::SlideSorterController,
+ WindowEventHandler));
+
+ vcl::Window* pParentWindow = pWindow->GetParent();
+ if (pParentWindow != nullptr)
+ pParentWindow->RemoveEventListener(
+ LINK(mpSlideSorterController.get(),
+ controller::SlideSorterController,
+ WindowEventHandler));
+ }
+ Application::RemoveEventListener(
+ LINK(mpSlideSorterController.get(),
+ controller::SlideSorterController,
+ ApplicationEventHandler));
+}
+
+void SlideSorter::CreateModelViewController()
+{
+ mpSlideSorterModel.reset(CreateModel());
+ DBG_ASSERT(mpSlideSorterModel != nullptr, "Can not create model for slide browser");
+
+ mpSlideSorterView.reset(new view::SlideSorterView (*this));
+ mpSlideSorterController.reset(new controller::SlideSorterController(*this));
+
+ // Now that model, view, and controller are constructed, do the
+ // initialization that relies on all three being in place.
+ mpSlideSorterController->Init();
+ mpSlideSorterView->Init();
+}
+
+model::SlideSorterModel* SlideSorter::CreateModel()
+{
+ // Get pointers to the document.
+ ViewShellBase* pViewShellBase = GetViewShellBase();
+ if (pViewShellBase != nullptr)
+ {
+ assert (pViewShellBase->GetDocument() != nullptr);
+
+ return new model::SlideSorterModel(*this);
+ }
+ else
+ return nullptr;
+}
+
+void SlideSorter::ArrangeGUIElements (
+ const Point& rOffset,
+ const Size& rSize)
+{
+ Point aOrigin (rOffset);
+
+ if (rSize.Width()>0
+ && rSize.Height()>0
+ && GetContentWindow()
+ && GetContentWindow()->IsVisible())
+ {
+ // Prevent untimely redraws while the view is not yet correctly
+ // resized.
+ view::SlideSorterView::DrawLock aLock (*this);
+ GetContentWindow()->EnablePaint (false);
+
+ mpSlideSorterController->Resize (::tools::Rectangle(aOrigin, rSize));
+
+ GetContentWindow()->EnablePaint (true);
+ }
+}
+
+void SlideSorter::RelocateToWindow (vcl::Window* pParentWindow)
+{
+ // Stop all animations for they have been started for the old window.
+ mpSlideSorterController->GetAnimator()->RemoveAllAnimations();
+
+ ReleaseListeners();
+
+ if (mpViewShell)
+ {
+ mpViewShell->ViewShell::RelocateToParentWindow(pParentWindow);
+ }
+
+ SetupControls();
+ SetupListeners();
+
+ // For accessibility we have to shortly hide the content window. This
+ // triggers the construction of a new accessibility object for the new
+ // view shell. (One is created earlier while the constructor of the base
+ // class is executed. But because at that time the correct
+ // accessibility object can not be constructed we do that now.)
+ if (mpContentWindow)
+ {
+ mpContentWindow->Hide();
+ mpContentWindow->Show();
+ }
+}
+
+void SlideSorter::SetCurrentFunction (const rtl::Reference<FuPoor>& rpFunction)
+{
+ if (GetViewShell() != nullptr)
+ {
+ GetViewShell()->SetCurrentFunction(rpFunction);
+ GetViewShell()->SetOldFunction(rpFunction);
+ }
+ else
+ {
+ ContentWindow* pWindow = dynamic_cast<ContentWindow*>(GetContentWindow().get());
+ if (pWindow != nullptr)
+ pWindow->SetCurrentFunction(rpFunction);
+ }
+}
+
+std::shared_ptr<controller::Properties> const & SlideSorter::GetProperties() const
+{
+ assert(mpProperties);
+ return mpProperties;
+}
+
+std::shared_ptr<view::Theme> const & SlideSorter::GetTheme() const
+{
+ assert(mpTheme);
+ return mpTheme;
+}
+
+//===== ContentWindow =========================================================
+
+namespace {
+
+ContentWindow::ContentWindow(
+ vcl::Window& rParent,
+ SlideSorter& rSlideSorter)
+ : ::sd::Window(&rParent),
+ mrSlideSorter(rSlideSorter)
+{
+ SetDialogControlFlags(GetDialogControlFlags() & ~DialogControlFlags::WantFocus);
+ SetStyle(GetStyle() | WB_NOPOINTERFOCUS);
+}
+
+void ContentWindow::SetCurrentFunction (const rtl::Reference<FuPoor>& rpFunction)
+{
+ mpCurrentFunction = rpFunction;
+}
+
+void ContentWindow::Paint (vcl::RenderContext& /*rRenderContext*/, const ::tools::Rectangle& rRect)
+{
+ mrSlideSorter.Paint(rRect);
+}
+
+void ContentWindow::KeyInput (const KeyEvent& rEvent)
+{
+ if (mpCurrentFunction.is())
+ mpCurrentFunction->KeyInput(rEvent);
+}
+
+void ContentWindow::MouseMove (const MouseEvent& rEvent)
+{
+ if (mpCurrentFunction.is())
+ mpCurrentFunction->MouseMove(rEvent);
+}
+
+void ContentWindow::MouseButtonUp(const MouseEvent& rEvent)
+{
+ if (mpCurrentFunction.is())
+ mpCurrentFunction->MouseButtonUp(rEvent);
+}
+
+void ContentWindow::MouseButtonDown(const MouseEvent& rEvent)
+{
+ if (mpCurrentFunction.is())
+ mpCurrentFunction->MouseButtonDown(rEvent);
+}
+
+void ContentWindow::Command(const CommandEvent& rEvent)
+{
+ if (mpCurrentFunction.is())
+ mpCurrentFunction->Command(rEvent);
+}
+
+bool ContentWindow::EventNotify(NotifyEvent&)
+{
+ return false;
+}
+
+} // end of anonymous namespace
+
+} // end of namespace ::sd::slidesorter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/shell/SlideSorterService.cxx b/sd/source/ui/slidesorter/shell/SlideSorterService.cxx
new file mode 100644
index 000000000..a086f3b9e
--- /dev/null
+++ b/sd/source/ui/slidesorter/shell/SlideSorterService.cxx
@@ -0,0 +1,412 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlideSorterService.hxx"
+#include <SlideSorter.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsProperties.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <DrawController.hxx>
+
+#include <comphelper/servicehelper.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::slidesorter::view::Layouter;
+
+namespace sd::slidesorter {
+
+//===== SlideSorterService ==========================================================
+
+SlideSorterService::SlideSorterService()
+{
+}
+
+SlideSorterService::~SlideSorterService()
+{
+}
+
+void SlideSorterService::disposing(std::unique_lock<std::mutex>&)
+{
+ mpSlideSorter.reset();
+
+ if (mxParentWindow.is())
+ {
+ mxParentWindow->removeWindowListener(this);
+ }
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL SlideSorterService::initialize (const Sequence<Any>& rArguments)
+{
+ ThrowIfDisposed();
+
+ if (rArguments.getLength() != 3)
+ {
+ throw RuntimeException("SlideSorterService: invalid number of arguments",
+ static_cast<drawing::XDrawView*>(this));
+ }
+
+ mxViewId.set(rArguments[0], UNO_QUERY_THROW);
+
+ // Get the XController.
+ Reference<frame::XController> xController (rArguments[1], UNO_QUERY_THROW);
+
+ // Tunnel through the controller to obtain a ViewShellBase.
+ ViewShellBase* pBase = nullptr;
+ Reference<lang::XUnoTunnel> xTunnel (xController, UNO_QUERY_THROW);
+ ::sd::DrawController* pController = comphelper::getFromUnoTunnel<sd::DrawController>(xTunnel);
+ if (pController != nullptr)
+ pBase = pController->GetViewShellBase();
+
+ // Get the parent window.
+ mxParentWindow.set(rArguments[2], UNO_QUERY_THROW);
+ VclPtr<vcl::Window> pParentWindow = VCLUnoHelper::GetWindow(mxParentWindow);
+
+ mxParentWindow->addWindowListener(this);
+
+ if (pBase != nullptr && pParentWindow)
+ mpSlideSorter = SlideSorter::CreateSlideSorter(
+ *pBase,
+ *pParentWindow);
+
+ Resize();
+}
+
+//----- XView -----------------------------------------------------------------
+
+Reference<XResourceId> SAL_CALL SlideSorterService::getResourceId()
+{
+ return mxViewId;
+}
+
+sal_Bool SAL_CALL SlideSorterService::isAnchorOnly()
+{
+ return false;
+}
+
+//----- XWindowListener -------------------------------------------------------
+
+void SAL_CALL SlideSorterService::windowResized (const awt::WindowEvent&)
+{
+ ThrowIfDisposed();
+
+ Resize();
+}
+
+void SAL_CALL SlideSorterService::windowMoved (const awt::WindowEvent&) {}
+
+void SAL_CALL SlideSorterService::windowShown (const lang::EventObject&)
+{
+ ThrowIfDisposed();
+ Resize();
+}
+
+void SAL_CALL SlideSorterService::windowHidden (const lang::EventObject&)
+{
+ ThrowIfDisposed();
+}
+
+//----- lang::XEventListener --------------------------------------------------
+
+void SAL_CALL SlideSorterService::disposing (const lang::EventObject& rEvent)
+{
+ if (rEvent.Source == mxParentWindow)
+ mxParentWindow = nullptr;
+}
+
+//----- XDrawView -------------------------------------------------------------
+
+void SAL_CALL SlideSorterService::setCurrentPage(const Reference<drawing::XDrawPage>& rxSlide)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr)
+ mpSlideSorter->GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
+ mpSlideSorter->GetModel().GetIndex(rxSlide));
+}
+
+Reference<drawing::XDrawPage> SAL_CALL SlideSorterService::getCurrentPage()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr)
+ return mpSlideSorter->GetController().GetCurrentSlideManager()->GetCurrentSlide()->GetXDrawPage();
+ else
+ return nullptr;
+}
+
+//----- attributes ------------------------------------------------------------
+
+Reference<container::XIndexAccess> SAL_CALL SlideSorterService::getDocumentSlides()
+{
+ return mpSlideSorter->GetModel().GetDocumentSlides();
+}
+
+void SAL_CALL SlideSorterService::setDocumentSlides (
+ const Reference<container::XIndexAccess >& rxSlides)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetController().SetDocumentSlides(rxSlides);
+}
+
+sal_Bool SAL_CALL SlideSorterService::getIsHighlightCurrentSlide()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return false;
+ else
+ return mpSlideSorter->GetProperties()->IsHighlightCurrentSlide();
+}
+
+void SAL_CALL SlideSorterService::setIsHighlightCurrentSlide (sal_Bool bValue)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ {
+ mpSlideSorter->GetProperties()->SetHighlightCurrentSlide(bValue);
+ controller::SlideSorterController::ModelChangeLock aLock (mpSlideSorter->GetController());
+ mpSlideSorter->GetController().HandleModelChange();
+ }
+}
+
+sal_Bool SAL_CALL SlideSorterService::getIsShowSelection()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return false;
+ else
+ return mpSlideSorter->GetProperties()->IsShowSelection();
+}
+
+void SAL_CALL SlideSorterService::setIsShowSelection (sal_Bool bValue)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetProperties()->SetShowSelection(bValue);
+}
+
+sal_Bool SAL_CALL SlideSorterService::getIsShowFocus()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return false;
+ else
+ return mpSlideSorter->GetProperties()->IsShowFocus();
+}
+
+void SAL_CALL SlideSorterService::setIsShowFocus (sal_Bool bValue)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetProperties()->SetShowFocus(bValue);
+}
+
+sal_Bool SAL_CALL SlideSorterService::getIsCenterSelection()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return false;
+ else
+ return mpSlideSorter->GetProperties()->IsCenterSelection();
+}
+
+void SAL_CALL SlideSorterService::setIsCenterSelection (sal_Bool bValue)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetProperties()->SetCenterSelection(bValue);
+}
+
+sal_Bool SAL_CALL SlideSorterService::getIsSuspendPreviewUpdatesDuringFullScreenPresentation()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return true;
+ else
+ return mpSlideSorter->GetProperties()
+ ->IsSuspendPreviewUpdatesDuringFullScreenPresentation();
+}
+
+void SAL_CALL SlideSorterService::setIsSuspendPreviewUpdatesDuringFullScreenPresentation (
+ sal_Bool bValue)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetProperties()
+ ->SetSuspendPreviewUpdatesDuringFullScreenPresentation(bValue);
+}
+
+sal_Bool SAL_CALL SlideSorterService::getIsOrientationVertical()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return true;
+ else
+ return mpSlideSorter->GetView().GetOrientation() != Layouter::HORIZONTAL;
+}
+
+void SAL_CALL SlideSorterService::setIsOrientationVertical (sal_Bool bValue)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetView().SetOrientation(bValue
+ ? Layouter::GRID
+ : Layouter::HORIZONTAL);
+}
+
+sal_Bool SAL_CALL SlideSorterService::getIsSmoothScrolling()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return false;
+ else
+ return mpSlideSorter->GetProperties()->IsSmoothSelectionScrolling();
+}
+
+void SAL_CALL SlideSorterService::setIsSmoothScrolling (sal_Bool bValue)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetProperties()->SetSmoothSelectionScrolling(bValue);
+}
+
+sal_Int32 SAL_CALL SlideSorterService::getBackgroundColor()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return util::Color();
+ else
+ return util::Color(
+ mpSlideSorter->GetProperties()->GetBackgroundColor());
+}
+
+void SAL_CALL SlideSorterService::setBackgroundColor (sal_Int32 aBackgroundColor)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetProperties()->SetBackgroundColor(Color(ColorTransparency, aBackgroundColor));
+}
+
+sal_Int32 SAL_CALL SlideSorterService::getTextColor()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return util::Color();
+ else
+ return util::Color(
+ mpSlideSorter->GetProperties()->GetTextColor());
+}
+
+void SAL_CALL SlideSorterService::setTextColor (sal_Int32 aTextColor)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetProperties()->SetTextColor(Color(ColorTransparency, aTextColor));
+}
+
+sal_Int32 SAL_CALL SlideSorterService::getSelectionColor()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return util::Color();
+ else
+ return util::Color(
+ mpSlideSorter->GetProperties()->GetSelectionColor());
+}
+
+void SAL_CALL SlideSorterService::setSelectionColor (sal_Int32 aSelectionColor)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetProperties()->SetSelectionColor(Color(ColorTransparency, aSelectionColor));
+}
+
+sal_Int32 SAL_CALL SlideSorterService::getHighlightColor()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return util::Color();
+ else
+ return util::Color(
+ mpSlideSorter->GetProperties()->GetHighlightColor());
+}
+
+void SAL_CALL SlideSorterService::setHighlightColor (sal_Int32 aHighlightColor)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetProperties()->SetHighlightColor(Color(ColorTransparency, aHighlightColor));
+}
+
+sal_Bool SAL_CALL SlideSorterService::getIsUIReadOnly()
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter == nullptr || !mpSlideSorter->IsValid())
+ return true;
+ else
+ return mpSlideSorter->GetProperties()->IsUIReadOnly();
+}
+
+void SAL_CALL SlideSorterService::setIsUIReadOnly (sal_Bool bIsUIReadOnly)
+{
+ ThrowIfDisposed();
+ if (mpSlideSorter != nullptr && mpSlideSorter->IsValid())
+ mpSlideSorter->GetProperties()->SetUIReadOnly(bIsUIReadOnly);
+}
+
+void SlideSorterService::Resize()
+{
+ if (mxParentWindow.is())
+ {
+ awt::Rectangle aWindowBox = mxParentWindow->getPosSize();
+ mpSlideSorter->ArrangeGUIElements(
+ Point(0,0),
+ Size(aWindowBox.Width, aWindowBox.Height));
+ }
+}
+
+void SlideSorterService::ThrowIfDisposed()
+{
+ if (SlideSorterServiceInterfaceBase::m_bDisposed)
+ {
+ throw lang::DisposedException ("SlideSorterService object has already been disposed",
+ static_cast<drawing::XDrawView*>(this));
+ }
+}
+
+} // end of namespace ::sd::slidesorter
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_SlideSorter_get_implementation(css::uno::XComponentContext* /*context*/,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::slidesorter::SlideSorterService);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/shell/SlideSorterService.hxx b/sd/source/ui/slidesorter/shell/SlideSorterService.hxx
new file mode 100644
index 000000000..579a5bae5
--- /dev/null
+++ b/sd/source/ui/slidesorter/shell/SlideSorterService.hxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/drawing/XSlideSorterBase.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/compbase.hxx>
+#include <memory>
+
+namespace com::sun::star::awt { class XWindow; }
+
+namespace sd::slidesorter {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::XSlideSorterBase,
+ css::lang::XInitialization,
+ css::awt::XWindowListener
+> SlideSorterServiceInterfaceBase;
+
+class SlideSorter;
+
+/** Implementation of the com.sun.star.drawing.SlideSorter service.
+*/
+class SlideSorterService
+ : public SlideSorterServiceInterfaceBase
+{
+public:
+ explicit SlideSorterService();
+ virtual ~SlideSorterService() override;
+ SlideSorterService(const SlideSorterService&) = delete;
+ SlideSorterService& operator=(const SlideSorterService&) = delete;
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize (const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ // XResourceId
+
+ css::uno::Reference<css::drawing::framework::XResourceId> SAL_CALL getResourceId() override;
+
+ sal_Bool SAL_CALL isAnchorOnly() override;
+
+ // XWindowListener
+
+ virtual void SAL_CALL windowResized (const css::awt::WindowEvent& rEvent) override;
+
+ virtual void SAL_CALL windowMoved (const css::awt::WindowEvent& rEvent) override;
+
+ virtual void SAL_CALL windowShown (const css::lang::EventObject& rEvent) override;
+
+ virtual void SAL_CALL windowHidden (const css::lang::EventObject& rEvent) override;
+
+ // lang::XEventListener
+ virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
+
+ // XDrawView
+
+ virtual void SAL_CALL setCurrentPage(
+ const css::uno::Reference<css::drawing::XDrawPage>& rxSlide) override;
+
+ virtual css::uno::Reference<css::drawing::XDrawPage> SAL_CALL getCurrentPage() override;
+
+ // Attributes
+
+ virtual css::uno::Reference<css::container::XIndexAccess> SAL_CALL getDocumentSlides() override;
+
+ virtual void SAL_CALL setDocumentSlides (
+ const css::uno::Reference<css::container::XIndexAccess >& rxSlides) override;
+
+ virtual sal_Bool SAL_CALL getIsHighlightCurrentSlide() override;
+
+ virtual void SAL_CALL setIsHighlightCurrentSlide (sal_Bool bIsHighlightCurrentSlide) override;
+
+ virtual sal_Bool SAL_CALL getIsShowSelection() override;
+
+ virtual void SAL_CALL setIsShowSelection (sal_Bool bIsShowSelection) override;
+
+ virtual sal_Bool SAL_CALL getIsCenterSelection() override;
+
+ virtual void SAL_CALL setIsCenterSelection (sal_Bool bIsCenterSelection) override;
+
+ virtual sal_Bool SAL_CALL getIsSuspendPreviewUpdatesDuringFullScreenPresentation() override;
+
+ virtual void SAL_CALL setIsSuspendPreviewUpdatesDuringFullScreenPresentation (
+ sal_Bool bIsSuspendPreviewUpdatesDuringFullScreenPresentation) override;
+
+ virtual sal_Bool SAL_CALL getIsOrientationVertical() override;
+
+ virtual void SAL_CALL setIsOrientationVertical (sal_Bool bIsOrientationVertical) override;
+
+ virtual sal_Bool SAL_CALL getIsSmoothScrolling() override;
+
+ virtual void SAL_CALL setIsSmoothScrolling (sal_Bool bIsOrientationVertical) override;
+
+ virtual sal_Int32 SAL_CALL getBackgroundColor() override;
+
+ virtual void SAL_CALL setBackgroundColor (sal_Int32 aBackgroundColor) override;
+
+ virtual sal_Int32 SAL_CALL getTextColor() override;
+
+ virtual void SAL_CALL setTextColor (sal_Int32 aTextColor) override;
+
+ virtual sal_Int32 SAL_CALL getSelectionColor() override;
+
+ virtual void SAL_CALL setSelectionColor (sal_Int32 aSelectionColor) override;
+
+ virtual sal_Int32 SAL_CALL getHighlightColor() override;
+
+ virtual void SAL_CALL setHighlightColor (sal_Int32 aHighlightColor) override;
+
+ virtual sal_Bool SAL_CALL getIsUIReadOnly() override;
+
+ virtual void SAL_CALL setIsUIReadOnly (sal_Bool bIsUIReadOnly) override;
+
+ virtual sal_Bool SAL_CALL getIsShowFocus() override;
+
+ virtual void SAL_CALL setIsShowFocus (sal_Bool bIsShowFocus) override;
+
+private:
+ std::shared_ptr<SlideSorter> mpSlideSorter;
+ css::uno::Reference<css::drawing::framework::XResourceId> mxViewId;
+ css::uno::Reference<css::awt::XWindow> mxParentWindow;
+
+ void Resize();
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::sd::slidesorter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx b/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx
new file mode 100644
index 000000000..af5bd5791
--- /dev/null
+++ b/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx
@@ -0,0 +1,924 @@
+#/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <SlideSorterViewShell.hxx>
+#include <ViewShellImplementation.hxx>
+
+#include <SlideSorter.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsClipboard.hxx>
+#include <controller/SlsScrollBarManager.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsSlotManager.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <controller/SlsSelectionManager.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <ViewShellBase.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <app.hrc>
+#include <AccessibleSlideSorterView.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <FrameView.hxx>
+#include <SdUnoSlideView.hxx>
+#include <ViewShellManager.hxx>
+#include <Window.hxx>
+#include <drawview.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sidebar/SidebarChildWindow.hxx>
+#include <sfx2/devtools/DevelopmentToolChildWindow.hxx>
+#include <svx/svxids.hrc>
+#include <vcl/EnumContext.hxx>
+#include <svx/sidebar/ContextChangeEventMultiplexer.hxx>
+#include <tools/diagnose_ex.h>
+#include <sfx2/sidebar/SidebarController.hxx>
+
+using namespace ::sd::slidesorter;
+#define ShellClass_SlideSorterViewShell
+#include <sdslots.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+using ::vcl::EnumContext;
+using namespace sfx2::sidebar;
+
+namespace sd::slidesorter {
+
+namespace {
+
+bool inChartContext(const sd::View* pView)
+{
+ if (!pView)
+ return false;
+
+ SfxViewShell* pViewShell = pView->GetSfxViewShell();
+ SidebarController* pSidebar = SidebarController::GetSidebarControllerForView(pViewShell);
+ if (pSidebar)
+ return pSidebar->hasChartContextCurrently();
+
+ return false;
+}
+
+} // anonymous namespace
+
+
+SFX_IMPL_INTERFACE(SlideSorterViewShell, SfxShell)
+
+void SlideSorterViewShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterChildWindow(::sfx2::sidebar::SidebarChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(DevelopmentToolChildWindow::GetChildWindowId());
+}
+
+
+std::shared_ptr<SlideSorterViewShell> SlideSorterViewShell::Create (
+ SfxViewFrame* pFrame,
+ ViewShellBase& rViewShellBase,
+ vcl::Window* pParentWindow,
+ FrameView* pFrameViewArgument)
+{
+ std::shared_ptr<SlideSorterViewShell> pViewShell;
+ try
+ {
+ pViewShell.reset(
+ new SlideSorterViewShell(pFrame,rViewShellBase,pParentWindow,pFrameViewArgument));
+ pViewShell->Initialize();
+ if (pViewShell->mpSlideSorter == nullptr)
+ pViewShell.reset();
+ }
+ catch(Exception&)
+ {
+ pViewShell.reset();
+ }
+ return pViewShell;
+}
+
+SlideSorterViewShell::SlideSorterViewShell (
+ SfxViewFrame* /*pFrame*/,
+ ViewShellBase& rViewShellBase,
+ vcl::Window* pParentWindow,
+ FrameView* pFrameViewArgument)
+ : ViewShell (pParentWindow, rViewShellBase),
+ mbIsArrangeGUIElementsPending(true)
+{
+ GetContentWindow()->set_id("slidesorter");
+ meShellType = ST_SLIDE_SORTER;
+
+ if (pFrameViewArgument != nullptr)
+ mpFrameView = pFrameViewArgument;
+ else
+ mpFrameView = new FrameView(GetDoc());
+ GetFrameView()->Connect();
+
+ SetName ("SlideSorterViewShell");
+
+ pParentWindow->SetStyle(pParentWindow->GetStyle() | WB_DIALOGCONTROL);
+}
+
+SlideSorterViewShell::~SlideSorterViewShell()
+{
+ DisposeFunctions();
+
+ try
+ {
+ ::sd::Window* pWindow = GetActiveWindow();
+ if (pWindow!=nullptr)
+ {
+ css::uno::Reference<css::lang::XComponent> xComponent (
+ pWindow->GetAccessible(false),
+ css::uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+ }
+ }
+ catch( css::uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SlideSorterViewShell::~SlideSorterViewShell()" );
+ }
+ GetFrameView()->Disconnect();
+}
+
+void SlideSorterViewShell::Initialize()
+{
+ mpSlideSorter = SlideSorter::CreateSlideSorter(
+ *this,
+ mpContentWindow,
+ mpHorizontalScrollBar,
+ mpVerticalScrollBar,
+ mpScrollBarBox);
+ mpView = &mpSlideSorter->GetView();
+
+ doShow();
+
+ SetPool( &GetDoc()->GetPool() );
+ SetUndoManager( GetDoc()->GetDocSh()->GetUndoManager() );
+
+ // For accessibility we have to shortly hide the content window.
+ // This triggers the construction of a new accessibility object for
+ // the new view shell. (One is created earlier while the constructor
+ // of the base class is executed. At that time the correct
+ // accessibility object can not be constructed.)
+ sd::Window *pWindow (mpSlideSorter->GetContentWindow().get());
+ if (pWindow)
+ {
+ pWindow->Hide();
+ pWindow->Show();
+ }
+}
+
+void SlideSorterViewShell::Init (bool bIsMainViewShell)
+{
+ ViewShell::Init(bIsMainViewShell);
+
+ // since the updatePageList will show focus, the window.show() must be called ahead. This show is deferred from Init()
+ ::sd::Window* pActiveWindow = GetActiveWindow();
+ if (pActiveWindow)
+ pActiveWindow->Show();
+ mpSlideSorter->GetModel().UpdatePageList();
+
+ if (mpContentWindow)
+ mpContentWindow->SetViewShell(this);
+}
+
+SlideSorterViewShell* SlideSorterViewShell::GetSlideSorter (ViewShellBase& rBase)
+{
+ SlideSorterViewShell* pViewShell = nullptr;
+
+ // Test the center and left pane for showing a slide sorter.
+ OUString aPaneURLs[] = {
+ FrameworkHelper::msCenterPaneURL,
+ FrameworkHelper::msFullScreenPaneURL,
+ FrameworkHelper::msLeftImpressPaneURL,
+ FrameworkHelper::msLeftDrawPaneURL,
+ OUString()};
+
+ try
+ {
+ std::shared_ptr<FrameworkHelper> pFrameworkHelper (FrameworkHelper::Instance(rBase));
+ if (pFrameworkHelper->IsValid())
+ for (int i=0; pViewShell==nullptr && !aPaneURLs[i].isEmpty(); ++i)
+ {
+ pViewShell = dynamic_cast<SlideSorterViewShell*>(
+ pFrameworkHelper->GetViewShell(aPaneURLs[i]).get());
+ }
+ }
+ catch (RuntimeException&)
+ {}
+
+ return pViewShell;
+}
+
+Reference<drawing::XDrawSubController> SlideSorterViewShell::CreateSubController()
+{
+ Reference<drawing::XDrawSubController> xSubController;
+
+ if (IsMainViewShell())
+ {
+ // Create uno controller for the main view shell.
+ xSubController.set( new SdUnoSlideView( *mpSlideSorter));
+ }
+
+ return xSubController;
+}
+
+/** If there is a valid controller then create a new instance of
+ <type>AccessibleSlideSorterView</type>. Otherwise delegate this call
+ to the base class to return a default object (probably an empty
+ reference).
+*/
+css::uno::Reference<css::accessibility::XAccessible>
+ SlideSorterViewShell::CreateAccessibleDocumentView (::sd::Window* pWindow)
+{
+ // When the view is not set then the initialization is not yet complete
+ // and we can not yet provide an accessibility object.
+ if (mpView == nullptr || mpSlideSorter == nullptr)
+ return nullptr;
+
+ assert(mpSlideSorter);
+
+ rtl::Reference<::accessibility::AccessibleSlideSorterView> pAccessibleView =
+ new ::accessibility::AccessibleSlideSorterView(
+ *mpSlideSorter,
+ pWindow);
+
+ pAccessibleView->Init();
+
+ return pAccessibleView;
+}
+
+void SlideSorterViewShell::SwitchViewFireFocus(const css::uno::Reference< css::accessibility::XAccessible >& xAcc )
+{
+ if (xAcc)
+ {
+ ::accessibility::AccessibleSlideSorterView* pBase = static_cast< ::accessibility::AccessibleSlideSorterView* >(xAcc.get());
+ if (pBase)
+ {
+ pBase->SwitchViewActivated();
+ }
+ }
+}
+
+SlideSorter& SlideSorterViewShell::GetSlideSorter() const
+{
+ assert(mpSlideSorter);
+ return *mpSlideSorter;
+}
+
+bool SlideSorterViewShell::RelocateToParentWindow (vcl::Window* pParentWindow)
+{
+ assert(mpSlideSorter);
+ if ( ! mpSlideSorter)
+ return false;
+
+ mpSlideSorter->RelocateToWindow(pParentWindow);
+ ReadFrameViewData(mpFrameView);
+
+ return true;
+}
+
+SfxUndoManager* SlideSorterViewShell::ImpGetUndoManager() const
+{
+ SfxShell* pObjectBar = GetViewShellBase().GetViewShellManager()->GetTopShell();
+ if (pObjectBar != nullptr)
+ {
+ // When it exists then return the undo manager of the currently
+ // active object bar. The object bar is missing when the
+ // SlideSorterViewShell is not the main view shell.
+ return pObjectBar->GetUndoManager();
+ }
+ else
+ {
+ // Return the undo manager of this shell when there is no object or
+ // tool bar.
+ return const_cast<SlideSorterViewShell*>(this)->GetUndoManager();
+ }
+}
+
+SdPage* SlideSorterViewShell::getCurrentPage() const
+{
+ // since SlideSorterViewShell::GetActualPage() currently also
+ // returns master pages, which is a wrong behaviour for GetActualPage(),
+ // we can just use that for now
+ return const_cast<SlideSorterViewShell*>(this)->GetActualPage();
+}
+
+SdPage* SlideSorterViewShell::GetActualPage()
+{
+ SdPage* pCurrentPage = nullptr;
+
+ // 1. Try to get the current page from the view shell in the center pane
+ // (if we are that not ourself).
+ if ( ! IsMainViewShell())
+ {
+ std::shared_ptr<ViewShell> pMainViewShell = GetViewShellBase().GetMainViewShell();
+ if (pMainViewShell != nullptr)
+ pCurrentPage = pMainViewShell->GetActualPage();
+ }
+
+ if (pCurrentPage == nullptr)
+ {
+ model::SharedPageDescriptor pDescriptor (
+ mpSlideSorter->GetController().GetCurrentSlideManager()->GetCurrentSlide());
+ if (pDescriptor)
+ pCurrentPage = pDescriptor->GetPage();
+ }
+
+ return pCurrentPage;
+}
+
+void SlideSorterViewShell::GetMenuState ( SfxItemSet& rSet)
+{
+ ViewShell::GetMenuState(rSet);
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().GetSlotManager()->GetMenuState(rSet);
+}
+
+void SlideSorterViewShell::GetClipboardState ( SfxItemSet& rSet)
+{
+ ViewShell::GetMenuState(rSet);
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().GetSlotManager()->GetClipboardState(rSet);
+}
+
+void SlideSorterViewShell::ExecCtrl (SfxRequest& rRequest)
+{
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().ExecCtrl(rRequest);
+}
+
+void SlideSorterViewShell::GetCtrlState (SfxItemSet& rSet)
+{
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().GetCtrlState(rSet);
+}
+
+void SlideSorterViewShell::FuSupport (SfxRequest& rRequest)
+{
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().FuSupport(rRequest);
+}
+
+/** We have to handle those slot calls here that need to have access to
+ private or protected members and methods of this class.
+*/
+void SlideSorterViewShell::FuTemporary (SfxRequest& rRequest)
+{
+ assert(mpSlideSorter);
+ switch (rRequest.GetSlot())
+ {
+ case SID_MODIFYPAGE:
+ {
+ SdPage* pCurrentPage = GetActualPage();
+ if (pCurrentPage != nullptr)
+ mpImpl->ProcessModifyPageSlot (
+ rRequest,
+ pCurrentPage,
+ PageKind::Standard);
+ Cancel();
+ rRequest.Done ();
+ }
+ break;
+
+ default:
+ mpSlideSorter->GetController().FuTemporary(rRequest);
+ break;
+ }
+}
+
+void SlideSorterViewShell::GetStatusBarState (SfxItemSet& rSet)
+{
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().GetStatusBarState(rSet);
+}
+
+void SlideSorterViewShell::FuPermanent (SfxRequest& rRequest)
+{
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().FuPermanent(rRequest);
+}
+
+void SlideSorterViewShell::GetAttrState (SfxItemSet& rSet)
+{
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().GetAttrState(rSet);
+}
+
+void SlideSorterViewShell::ExecStatusBar (SfxRequest& )
+{
+}
+
+void SlideSorterViewShell::Paint (
+ const ::tools::Rectangle& rBBox,
+ ::sd::Window* pWindow)
+{
+ SetActiveWindow (pWindow);
+ assert(mpSlideSorter);
+ if (mpSlideSorter)
+ mpSlideSorter->GetController().Paint(rBBox,pWindow);
+}
+
+void SlideSorterViewShell::ArrangeGUIElements()
+{
+ if (IsActive())
+ {
+ assert(mpSlideSorter);
+ mpSlideSorter->ArrangeGUIElements(maViewPos, maViewSize);
+ mbIsArrangeGUIElementsPending = false;
+ }
+ else
+ mbIsArrangeGUIElementsPending = true;
+}
+
+void SlideSorterViewShell::Activate (bool bIsMDIActivate)
+{
+ if(inChartContext(GetView()))
+ {
+ // Avoid context changes for chart during activation / deactivation.
+ const bool bIsContextBroadcasterEnabled (SfxShell::SetContextBroadcasterEnabled(false));
+
+ ViewShell::Activate(bIsMDIActivate);
+
+ SfxShell::SetContextBroadcasterEnabled(bIsContextBroadcasterEnabled);
+ return;
+ }
+
+ ViewShell::Activate(bIsMDIActivate);
+ if (mbIsArrangeGUIElementsPending)
+ ArrangeGUIElements();
+
+ // Determine and broadcast the context that belongs to the main view shell.
+ EnumContext::Context eContext = EnumContext::Context::Unknown;
+ std::shared_ptr<ViewShell> pMainViewShell (GetViewShellBase().GetMainViewShell());
+ ViewShell::ShellType eMainViewShellType (
+ pMainViewShell
+ ? pMainViewShell->GetShellType()
+ : ViewShell::ST_NONE);
+ switch (eMainViewShellType)
+ {
+ case ViewShell::ST_IMPRESS:
+ case ViewShell::ST_SLIDE_SORTER:
+ case ViewShell::ST_NOTES:
+ case ViewShell::ST_DRAW:
+ eContext = EnumContext::Context::DrawPage;
+ if( nullptr != dynamic_cast< const DrawViewShell *>( pMainViewShell.get() ))
+ {
+ DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pMainViewShell.get());
+ if (pDrawViewShell != nullptr)
+ eContext = EnumContext::GetContextEnum(pDrawViewShell->GetSidebarContextName());
+ }
+ break;
+
+ default:
+ break;
+ }
+ ContextChangeEventMultiplexer::NotifyContextChange(
+ &GetViewShellBase(),
+ eContext);
+}
+
+void SlideSorterViewShell::Deactivate (bool /*bIsMDIActivate*/)
+{
+ // Save Settings - Specifically SlidesPerRow to retrieve it later
+ WriteFrameViewData();
+}
+
+void SlideSorterViewShell::Command (
+ const CommandEvent& rEvent,
+ ::sd::Window* pWindow)
+{
+ assert(mpSlideSorter);
+ if ( ! mpSlideSorter->GetController().Command (rEvent, pWindow))
+ ViewShell::Command (rEvent, pWindow);
+}
+
+void SlideSorterViewShell::ReadFrameViewData (FrameView* pFrameView)
+{
+ assert(mpSlideSorter);
+ if (pFrameView != nullptr)
+ {
+ view::SlideSorterView& rView (mpSlideSorter->GetView());
+
+ sal_uInt16 nSlidesPerRow (pFrameView->GetSlidesPerRow());
+ if (nSlidesPerRow > 0
+ && rView.GetOrientation() == view::Layouter::GRID
+ && IsMainViewShell())
+ {
+ rView.GetLayouter().SetColumnCount(nSlidesPerRow,nSlidesPerRow);
+ }
+ if (IsMainViewShell())
+ mpSlideSorter->GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
+ mpFrameView->GetSelectedPage());
+ mpSlideSorter->GetController().Rearrange(true);
+
+ // DrawMode for 'main' window
+ if (GetActiveWindow()->GetOutDev()->GetDrawMode() != pFrameView->GetDrawMode() )
+ GetActiveWindow()->GetOutDev()->SetDrawMode( pFrameView->GetDrawMode() );
+ }
+
+ // When this slide sorter is not displayed in the main window then we do
+ // not share the same frame view and have to find other ways to acquire
+ // certain values.
+ if ( ! IsMainViewShell())
+ {
+ std::shared_ptr<ViewShell> pMainViewShell = GetViewShellBase().GetMainViewShell();
+ if (pMainViewShell != nullptr)
+ mpSlideSorter->GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
+ pMainViewShell->getCurrentPage());
+ }
+}
+
+void SlideSorterViewShell::WriteFrameViewData()
+{
+ assert(mpSlideSorter);
+ if (mpFrameView == nullptr)
+ return;
+
+ view::SlideSorterView& rView (mpSlideSorter->GetView());
+ mpFrameView->SetSlidesPerRow(static_cast<sal_uInt16>(rView.GetLayouter().GetColumnCount()));
+
+ // DrawMode for 'main' window
+ if( mpFrameView->GetDrawMode() != GetActiveWindow()->GetOutDev()->GetDrawMode() )
+ mpFrameView->SetDrawMode( GetActiveWindow()->GetOutDev()->GetDrawMode() );
+
+ SdPage* pActualPage = GetActualPage();
+ if (pActualPage != nullptr)
+ {
+ if (IsMainViewShell())
+ mpFrameView->SetSelectedPage((pActualPage->GetPageNum()- 1) / 2);
+ // else
+ // The slide sorter is not expected to switch the current page
+ // other than by double clicks. That is handled separately.
+ }
+ else
+ {
+ // We have no current page to set but at least we can make sure
+ // that the index of the frame view has a legal value.
+ if (mpFrameView->GetSelectedPage() >= mpSlideSorter->GetModel().GetPageCount())
+ mpFrameView->SetSelectedPage(static_cast<sal_uInt16>(mpSlideSorter->GetModel().GetPageCount())-1);
+ }
+}
+
+void SlideSorterViewShell::SetZoom (::tools::Long )
+{
+ // Ignored.
+ // The zoom scale is adapted internally to fit a number of columns in
+ // the window.
+}
+
+void SlideSorterViewShell::SetZoomRect (const ::tools::Rectangle& rZoomRect)
+{
+ assert(mpSlideSorter);
+ Size aPageSize (mpSlideSorter->GetView().GetLayouter().GetPageObjectSize());
+
+ ::tools::Rectangle aRect(rZoomRect);
+
+ if (aRect.GetWidth() < aPageSize.Width())
+ {
+ ::tools::Long nWidthDiff = (aPageSize.Width() - aRect.GetWidth()) / 2;
+
+ aRect.AdjustLeft( -nWidthDiff );
+ aRect.AdjustRight(nWidthDiff );
+
+ if (aRect.Left() < 0)
+ {
+ aRect.SetPos(Point(0, aRect.Top()));
+ }
+ }
+
+ if (aRect.GetHeight() < aPageSize.Height())
+ {
+ ::tools::Long nHeightDiff = (aPageSize.Height() - aRect.GetHeight()) / 2;
+
+ aRect.AdjustTop( -nHeightDiff );
+ aRect.AdjustBottom(nHeightDiff );
+
+ if (aRect.Top() < 0)
+ {
+ aRect.SetPos(Point(aRect.Left(), 0));
+ }
+ }
+
+ ViewShell::SetZoomRect(aRect);
+
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM );
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
+}
+
+void SlideSorterViewShell::UpdateScrollBars()
+{
+ // Do not call the overwritten method of the base class: We do all the
+ // scroll bar setup by ourselves.
+ mpSlideSorter->GetController().GetScrollBarManager().UpdateScrollBars(true);
+}
+
+void SlideSorterViewShell::StartDrag (
+ const Point& rDragPt,
+ vcl::Window* pWindow )
+{
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().GetClipboard().StartDrag (
+ rDragPt,
+ pWindow);
+}
+
+sal_Int8 SlideSorterViewShell::AcceptDrop (
+ const AcceptDropEvent& rEvt,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer)
+{
+ assert(mpSlideSorter);
+ return mpSlideSorter->GetController().GetClipboard().AcceptDrop (
+ rEvt,
+ rTargetHelper,
+ pTargetWindow,
+ nPage,
+ nLayer);
+}
+
+sal_Int8 SlideSorterViewShell::ExecuteDrop (
+ const ExecuteDropEvent& rEvt,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer)
+{
+ assert(mpSlideSorter);
+ return mpSlideSorter->GetController().GetClipboard().ExecuteDrop (
+ rEvt,
+ rTargetHelper,
+ pTargetWindow,
+ nPage,
+ nLayer);
+}
+
+std::shared_ptr<SlideSorterViewShell::PageSelection>
+ SlideSorterViewShell::GetPageSelection() const
+{
+ assert(mpSlideSorter);
+ return mpSlideSorter->GetController().GetPageSelector().GetPageSelection();
+}
+
+void SlideSorterViewShell::SetPageSelection (
+ const std::shared_ptr<PageSelection>& rSelection)
+{
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().GetPageSelector().SetPageSelection(rSelection, true);
+}
+
+void SlideSorterViewShell::AddSelectionChangeListener (
+ const Link<LinkParamNone*,void>& rCallback)
+{
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().GetSelectionManager()->AddSelectionChangeListener(rCallback);
+}
+
+void SlideSorterViewShell::RemoveSelectionChangeListener (
+ const Link<LinkParamNone*,void>& rCallback)
+{
+ assert(mpSlideSorter);
+ mpSlideSorter->GetController().GetSelectionManager()->RemoveSelectionChangeListener(rCallback);
+}
+
+void SlideSorterViewShell::MainViewEndEditAndUnmarkAll()
+{
+ std::shared_ptr<ViewShell> pMainViewShell = GetViewShellBase().GetMainViewShell();
+ DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pMainViewShell.get());
+ SdrView* pView = pDrawViewShell ? pDrawViewShell->GetDrawView() : nullptr;
+ if (pView)
+ {
+ pView->SdrEndTextEdit();
+ pView->UnmarkAll();
+ }
+}
+
+std::pair<sal_uInt16, sal_uInt16> SlideSorterViewShell::SyncPageSelectionToDocument(const std::shared_ptr<SlideSorterViewShell::PageSelection> &rpSelection)
+{
+ sal_uInt16 firstSelectedPageNo = SAL_MAX_UINT16;
+ sal_uInt16 lastSelectedPageNo = 0;
+
+ GetDoc()->UnselectAllPages();
+ for (auto& rpPage : *rpSelection)
+ {
+ // Check page number
+ sal_uInt16 pageNo = rpPage->GetPageNum();
+ if (pageNo > lastSelectedPageNo)
+ lastSelectedPageNo = pageNo;
+ if (pageNo < firstSelectedPageNo)
+ firstSelectedPageNo = pageNo;
+ GetDoc()->SetSelected(rpPage, true);
+ }
+
+ return std::make_pair(firstSelectedPageNo, lastSelectedPageNo);
+}
+
+void SlideSorterViewShell::ExecMovePageFirst (SfxRequest& /*rReq*/)
+{
+ MainViewEndEditAndUnmarkAll();
+
+ std::shared_ptr<SlideSorterViewShell::PageSelection> xSelection(GetPageSelection());
+
+ // SdDrawDocument MovePages is based on SdPage IsSelected, so
+ // transfer the SlideSorter selection to SdPages
+ SyncPageSelectionToDocument(xSelection);
+
+ // Moves selected pages after page -1
+ GetDoc()->MovePages( sal_uInt16(-1) );
+
+ PostMoveSlidesActions(xSelection);
+}
+
+void SlideSorterViewShell::GetStateMovePageFirst (SfxItemSet& rSet)
+{
+ if ( ! IsMainViewShell())
+ {
+ std::shared_ptr<ViewShell> pMainViewShell = GetViewShellBase().GetMainViewShell();
+ DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pMainViewShell.get());
+ if (pDrawViewShell != nullptr && pDrawViewShell->GetPageKind() == PageKind::Handout)
+ {
+ rSet.DisableItem( SID_MOVE_PAGE_FIRST );
+ rSet.DisableItem( SID_MOVE_PAGE_UP );
+ return;
+ }
+ }
+
+ std::shared_ptr<SlideSorterViewShell::PageSelection> xSelection(GetPageSelection());
+
+ // SdDrawDocument MovePages is based on SdPage IsSelected, so
+ // transfer the SlideSorter selection to SdPages
+ sal_uInt16 firstSelectedPageNo = SyncPageSelectionToDocument(xSelection).first;
+ // Now compute human page number from internal page number
+ firstSelectedPageNo = (firstSelectedPageNo - 1) / 2;
+
+ if (firstSelectedPageNo == 0)
+ {
+ rSet.DisableItem( SID_MOVE_PAGE_FIRST );
+ rSet.DisableItem( SID_MOVE_PAGE_UP );
+ }
+}
+
+void SlideSorterViewShell::ExecMovePageUp (SfxRequest& /*rReq*/)
+{
+ MainViewEndEditAndUnmarkAll();
+
+ std::shared_ptr<SlideSorterViewShell::PageSelection> xSelection(GetPageSelection());
+
+ // SdDrawDocument MovePages is based on SdPage IsSelected, so
+ // transfer the SlideSorter selection to SdPages
+ sal_uInt16 firstSelectedPageNo = SyncPageSelectionToDocument(xSelection).first;
+
+ // In case no slide is selected
+ if (firstSelectedPageNo == SAL_MAX_UINT16)
+ return;
+
+ // Now compute human page number from internal page number
+ firstSelectedPageNo = (firstSelectedPageNo - 1) / 2;
+
+ if (firstSelectedPageNo == 0)
+ return;
+
+ // Move pages before firstSelectedPageNo - 1 (so after firstSelectedPageNo - 2),
+ // remembering that -1 means at first, which is good.
+ GetDoc()->MovePages( firstSelectedPageNo - 2 );
+
+ PostMoveSlidesActions(xSelection);
+}
+
+void SlideSorterViewShell::GetStateMovePageUp (SfxItemSet& rSet)
+{
+ GetStateMovePageFirst(rSet);
+}
+
+void SlideSorterViewShell::ExecMovePageDown (SfxRequest& /*rReq*/)
+{
+ MainViewEndEditAndUnmarkAll();
+
+ std::shared_ptr<SlideSorterViewShell::PageSelection> xSelection(GetPageSelection());
+
+ // SdDrawDocument MovePages is based on SdPage IsSelected, so
+ // transfer the SlideSorter selection to SdPages
+ sal_uInt16 lastSelectedPageNo = SyncPageSelectionToDocument(xSelection).second;
+
+ // Get page number of the last page
+ sal_uInt16 nNoOfPages = GetDoc()->GetSdPageCount(PageKind::Standard);
+
+ // Now compute human page number from internal page number
+ lastSelectedPageNo = (lastSelectedPageNo - 1) / 2;
+ if (lastSelectedPageNo == nNoOfPages - 1)
+ return;
+
+ // Move to position after lastSelectedPageNo
+ GetDoc()->MovePages( lastSelectedPageNo + 1 );
+
+ PostMoveSlidesActions(xSelection);
+}
+
+void SlideSorterViewShell::GetStateMovePageDown (SfxItemSet& rSet)
+{
+ GetStateMovePageLast( rSet );
+}
+
+void SlideSorterViewShell::ExecMovePageLast (SfxRequest& /*rReq*/)
+{
+ MainViewEndEditAndUnmarkAll();
+
+ std::shared_ptr<SlideSorterViewShell::PageSelection> xSelection(GetPageSelection());
+
+ // SdDrawDocument MovePages is based on SdPage IsSelected, so
+ // transfer the SlideSorter selection to SdPages
+ SyncPageSelectionToDocument(xSelection);
+
+ // Get page number of the last page
+ sal_uInt16 nNoOfPages = GetDoc()->GetSdPageCount(PageKind::Standard);
+
+ // Move to position after last page No (=Number of pages - 1)
+ GetDoc()->MovePages( nNoOfPages - 1 );
+
+ PostMoveSlidesActions(xSelection);
+}
+
+void SlideSorterViewShell::GetStateMovePageLast (SfxItemSet& rSet)
+{
+ std::shared_ptr<ViewShell> pMainViewShell = GetViewShellBase().GetMainViewShell();
+ DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pMainViewShell.get());
+ if (pDrawViewShell != nullptr && pDrawViewShell->GetPageKind() == PageKind::Handout)
+ {
+ rSet.DisableItem( SID_MOVE_PAGE_LAST );
+ rSet.DisableItem( SID_MOVE_PAGE_DOWN );
+ return;
+ }
+
+ std::shared_ptr<SlideSorterViewShell::PageSelection> xSelection(GetPageSelection());
+
+ // SdDrawDocument MovePages is based on SdPage IsSelected, so
+ // transfer the SlideSorter selection to SdPages
+ sal_uInt16 lastSelectedPageNo = SyncPageSelectionToDocument(xSelection).second;
+
+ // Get page number of the last page
+ sal_uInt16 nNoOfPages = GetDoc()->GetSdPageCount(PageKind::Standard);
+
+ // Now compute human page number from internal page number
+ lastSelectedPageNo = (lastSelectedPageNo - 1) / 2;
+ if (lastSelectedPageNo == nNoOfPages - 1)
+ {
+ rSet.DisableItem( SID_MOVE_PAGE_LAST );
+ rSet.DisableItem( SID_MOVE_PAGE_DOWN );
+ }
+}
+
+void SlideSorterViewShell::PostMoveSlidesActions(const std::shared_ptr<SlideSorterViewShell::PageSelection> &rpSelection)
+{
+ sal_uInt16 nNoOfPages = GetDoc()->GetSdPageCount(PageKind::Standard);
+ for (sal_uInt16 nPage = 0; nPage < nNoOfPages; nPage++)
+ {
+ SdPage* pPage = GetDoc()->GetSdPage(nPage, PageKind::Standard);
+ GetDoc()->SetSelected(pPage, false);
+ }
+
+ mpSlideSorter->GetController().GetPageSelector().DeselectAllPages();
+ for (const auto& rpPage : *rpSelection)
+ {
+ mpSlideSorter->GetController().GetPageSelector().SelectPage(rpPage);
+ }
+
+ // Refresh toolbar icons
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_MOVE_PAGE_FIRST);
+ rBindings.Invalidate(SID_MOVE_PAGE_UP);
+ rBindings.Invalidate(SID_MOVE_PAGE_DOWN);
+ rBindings.Invalidate(SID_MOVE_PAGE_LAST);
+
+}
+
+} // end of namespace ::sd::slidesorter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlideSorterView.cxx b/sd/source/ui/slidesorter/view/SlideSorterView.cxx
new file mode 100644
index 000000000..390541e37
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlideSorterView.cxx
@@ -0,0 +1,856 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <view/SlideSorterView.hxx>
+
+#include <SlideSorter.hxx>
+#include <ViewShell.hxx>
+#include "SlsViewCacheContext.hxx"
+#include "SlsLayeredDevice.hxx"
+#include <view/SlsLayouter.hxx>
+#include <view/SlsPageObjectLayouter.hxx>
+#include <view/SlsPageObjectPainter.hxx>
+#include <view/SlsILayerPainter.hxx>
+#include <view/SlsToolTip.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsClipboard.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <cache/SlsPageCache.hxx>
+#include <cache/SlsPageCacheManager.hxx>
+#include <PaneDockingWindow.hxx>
+
+#include <sdpage.hxx>
+#include <Window.hxx>
+
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+#include <vcl/scrbar.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/graphicfilter.hxx>
+
+#include <algorithm>
+
+//#define DEBUG_TIMING
+#ifdef DEBUG_TIMING
+#include <memory>
+#include <vector>
+#endif
+
+using namespace ::sd::slidesorter::model;
+using namespace ::drawinglayer::primitive2d;
+
+namespace sd::slidesorter::view {
+
+namespace {
+ /** Wrapper around the SlideSorterView that supports the IPainter
+ interface and that allows the LayeredDevice to hold the
+ SlideSorterView (held as unique_ptr by the SlideSorter) as
+ shared_ptr.
+ */
+ class Painter : public ILayerPainter
+ {
+ public:
+ explicit Painter (SlideSorterView& rView) : mrView(rView) {}
+
+ virtual void Paint (OutputDevice& rDevice, const ::tools::Rectangle& rRepaintArea) override
+ {
+ mrView.Paint(rDevice,rRepaintArea);
+ }
+
+ virtual void SetLayerInvalidator (const SharedILayerInvalidator&) override {}
+
+ private:
+ SlideSorterView& mrView;
+ };
+}
+
+namespace {
+
+class BackgroundPainter
+ : public ILayerPainter
+{
+public:
+ explicit BackgroundPainter (const Color& rBackgroundColor) : maBackgroundColor(rBackgroundColor) {}
+ BackgroundPainter(const BackgroundPainter&) = delete;
+ BackgroundPainter& operator=(const BackgroundPainter&) = delete;
+
+ virtual void Paint (OutputDevice& rDevice, const ::tools::Rectangle& rRepaintArea) override
+ {
+ rDevice.SetFillColor(maBackgroundColor);
+ rDevice.SetLineColor();
+ rDevice.DrawRect(rRepaintArea);
+ }
+
+ virtual void SetLayerInvalidator (const SharedILayerInvalidator&) override {}
+
+ void SetColor (const Color& rColor) { maBackgroundColor = rColor; }
+
+private:
+ Color maBackgroundColor;
+};
+
+}
+
+SlideSorterView::SlideSorterView (SlideSorter& rSlideSorter)
+ : ::sd::View (
+ *rSlideSorter.GetModel().GetDocument(),
+ rSlideSorter.GetContentWindow()->GetOutDev(),
+ rSlideSorter.GetViewShell()),
+ mrSlideSorter(rSlideSorter),
+ mrModel(rSlideSorter.GetModel()),
+ mbIsDisposed(false),
+ mpLayouter (new Layouter(rSlideSorter.GetContentWindow(), rSlideSorter.GetTheme())),
+ mbPageObjectVisibilitiesValid (false),
+ mpLayeredDevice(std::make_shared<LayeredDevice>(rSlideSorter.GetContentWindow())),
+ maVisiblePageRange(-1,-1),
+ maPreviewSize(0,0),
+ mbPreciousFlagUpdatePending(true),
+ meOrientation(Layouter::GRID),
+ mpBackgroundPainter(
+ std::make_shared<BackgroundPainter>(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background))),
+ mpToolTip(new ToolTip(mrSlideSorter)),
+ mbIsRearrangePending(true)
+{
+ // Hide the page that contains the page objects.
+ SetPageVisible (false);
+
+ // Register the background painter on level 1 to avoid the creation of a
+ // background buffer.
+ mpLayeredDevice->RegisterPainter(mpBackgroundPainter, 1);
+
+ // Wrap a shared_ptr-held-wrapper around this view and register it as
+ // painter at the layered device. There is no explicit destruction: in
+ // the SlideSorterView destructor the layered device is destroyed and
+ // with it the only reference to the wrapper which therefore is also
+ // destroyed.
+ SharedILayerPainter pPainter = std::make_shared<Painter>(*this);
+
+ // The painter is placed on level 1 to avoid buffering. This should be
+ // a little faster during animations because the previews are painted
+ // directly into the window, not via the buffer.
+ mpLayeredDevice->RegisterPainter(pPainter, 1);
+}
+
+SlideSorterView::~SlideSorterView()
+{
+ if ( ! mbIsDisposed)
+ {
+ OSL_ASSERT(mbIsDisposed);
+ Dispose();
+ }
+}
+
+void SlideSorterView::Init()
+{
+ HandleModelChange();
+}
+
+void SlideSorterView::Dispose()
+{
+ mpLayeredDevice->Dispose();
+ mpPreviewCache.reset();
+
+ SetPageUnderMouse(SharedPageDescriptor());
+
+ // Hide the page to avoid problems in the view when deleting
+ // visualized objects
+ HideSdrPage();
+
+ // Deletion of the objects and the page will be done in SdrModel
+ // destructor (as long as objects and pages are added)
+
+ OSL_ASSERT(mpLayeredDevice.use_count() == 1);
+ mpLayeredDevice.reset();
+
+ mbIsDisposed = true;
+}
+
+sal_Int32 SlideSorterView::GetPageIndexAtPoint (const Point& rWindowPosition) const
+{
+ sal_Int32 nIndex (-1);
+
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (pWindow)
+ {
+ nIndex = mpLayouter->GetIndexAtPoint(pWindow->PixelToLogic(rWindowPosition), false, false);
+
+ // Clip the page index against the page count.
+ if (nIndex >= mrModel.GetPageCount())
+ nIndex = -1;
+ }
+
+ return nIndex;
+}
+
+Layouter& SlideSorterView::GetLayouter() { return *mpLayouter; }
+
+void SlideSorterView::ModelHasChanged()
+{
+ // Ignore this call. Rely on hints sent by the model to get informed of
+ // model changes.
+}
+
+void SlideSorterView::PreModelChange()
+{
+ // Reset the slide under the mouse. It will be re-set in PostModelChange().
+ SetPageUnderMouse(SharedPageDescriptor());
+}
+
+void SlideSorterView::PostModelChange()
+{
+ // In PreModelChange() the page objects have been released. Here we
+ // create new ones.
+ ::osl::MutexGuard aGuard (mrModel.GetMutex());
+
+ model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel);
+
+ // The new page objects have to be scaled and positioned.
+ RequestRearrange();
+ RequestRepaint();
+}
+
+/** At the moment for every model change all page objects are destroyed and
+ re-created again. This can be optimized by accepting hints that
+ describe the type of change so that existing page objects can be
+ reused.
+*/
+void SlideSorterView::HandleModelChange()
+{
+ PreModelChange ();
+ PostModelChange();
+}
+
+void SlideSorterView::HandleDrawModeChange()
+{
+ // Replace the preview cache with a new and empty one. The
+ // PreviewRenderer that is used by the cache is replaced by this as
+ // well.
+ mpPreviewCache.reset();
+ GetPreviewCache()->InvalidateCache();
+
+ RequestRepaint();
+}
+
+void SlideSorterView::HandleDataChangeEvent()
+{
+ GetPageObjectPainter()->SetTheme(mrSlideSorter.GetTheme());
+
+ // Update the color used by the background painter.
+ std::shared_ptr<BackgroundPainter> pPainter (
+ std::dynamic_pointer_cast<BackgroundPainter>(mpBackgroundPainter));
+ if (pPainter)
+ pPainter->SetColor(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background));
+
+ RequestRepaint();
+}
+
+void SlideSorterView::Resize()
+{
+ UpdateOrientation();
+
+ mpLayeredDevice->Resize();
+ RequestRearrange();
+}
+
+void SlideSorterView::RequestRearrange()
+{
+ mbIsRearrangePending = true;
+ Rearrange();
+}
+
+void SlideSorterView::Rearrange()
+{
+ if ( ! mbIsRearrangePending)
+ return;
+ if (mrModel.GetPageCount() <= 0)
+ return;
+
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if ( ! pWindow)
+ return;
+ const Size aWindowSize (pWindow->GetSizePixel());
+ if (aWindowSize.IsEmpty())
+ return;
+
+ const bool bRearrangeSuccess (
+ mpLayouter->Rearrange (
+ meOrientation,
+ aWindowSize,
+ mrModel.GetPageDescriptor(0)->GetPage()->GetSize(),
+ mrModel.GetPageCount()));
+ if (bRearrangeSuccess)
+ {
+ mbIsRearrangePending = false;
+ Layout();
+ UpdatePageUnderMouse();
+ // RequestRepaint();
+ }
+}
+
+void SlideSorterView::UpdateOrientation()
+{
+ // The layout of slides depends on whether the slide sorter is
+ // displayed in the center or the side pane.
+ if (mrSlideSorter.GetViewShell()->IsMainViewShell())
+ SetOrientation(Layouter::GRID);
+ else
+ {
+ // Get access to the docking window.
+ vcl::Window* pWindow = mrSlideSorter.GetContentWindow();
+ PaneDockingWindow* pDockingWindow = nullptr;
+ while (pWindow!=nullptr && pDockingWindow==nullptr)
+ {
+ pDockingWindow = dynamic_cast<PaneDockingWindow*>(pWindow);
+ pWindow = pWindow->GetParent();
+ }
+
+ if (pDockingWindow != nullptr)
+ {
+ const ::tools::Long nScrollBarSize (
+ Application::GetSettings().GetStyleSettings().GetScrollBarSize());
+ switch (pDockingWindow->GetOrientation())
+ {
+ case PaneDockingWindow::HorizontalOrientation:
+ if (SetOrientation(Layouter::HORIZONTAL))
+ {
+ const Range aRange (mpLayouter->GetValidVerticalSizeRange());
+ pDockingWindow->SetValidSizeRange(Range(
+ aRange.Min() + nScrollBarSize,
+ aRange.Max() + nScrollBarSize));
+ }
+ break;
+
+ case PaneDockingWindow::VerticalOrientation:
+ if (SetOrientation(Layouter::VERTICAL))
+ {
+ const Range aRange (mpLayouter->GetValidHorizontalSizeRange());
+ pDockingWindow->SetValidSizeRange(Range(
+ aRange.Min() + nScrollBarSize,
+ aRange.Max() + nScrollBarSize));
+ }
+ break;
+
+ case PaneDockingWindow::UnknownOrientation:
+ if (SetOrientation(Layouter::GRID))
+ {
+ const sal_Int32 nAdditionalSize (10);
+ pDockingWindow->SetMinOutputSizePixel(Size(
+ mpLayouter->GetValidHorizontalSizeRange().Min()
+ + nScrollBarSize
+ + nAdditionalSize,
+ mpLayouter->GetValidVerticalSizeRange().Min()
+ + nScrollBarSize
+ + nAdditionalSize));
+ }
+ return;
+ }
+ }
+ else
+ {
+ // We are not placed in a docking window. One possible reason
+ // is that the slide sorter is temporarily into a cache and was
+ // reparented to a non-docking window.
+ SetOrientation(Layouter::GRID);
+ }
+ }
+}
+
+void SlideSorterView::Layout ()
+{
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (pWindow)
+ {
+ // Set the model area, i.e. the smallest rectangle that includes all
+ // page objects.
+ const ::tools::Rectangle aViewBox (mpLayouter->GetTotalBoundingBox());
+ pWindow->SetViewOrigin (aViewBox.TopLeft());
+ pWindow->SetViewSize (aViewBox.GetSize());
+
+ std::shared_ptr<PageObjectLayouter> pPageObjectLayouter(
+ mpLayouter->GetPageObjectLayouter());
+ if (pPageObjectLayouter)
+ {
+ const Size aNewPreviewSize (mpLayouter->GetPageObjectLayouter()->GetPreviewSize());
+ if (maPreviewSize != aNewPreviewSize && GetPreviewCache())
+ {
+ mpPreviewCache->ChangeSize(aNewPreviewSize, Bitmap::HasFastScale());
+ maPreviewSize = aNewPreviewSize;
+ }
+ }
+
+ // Iterate over all page objects and place them relative to the
+ // containing page.
+ model::PageEnumeration aPageEnumeration (
+ model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
+ while (aPageEnumeration.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement());
+ pDescriptor->SetBoundingBox(mpLayouter->GetPageObjectBox(pDescriptor->GetPageIndex(), false));
+ }
+ }
+
+ InvalidatePageObjectVisibilities ();
+}
+
+void SlideSorterView::InvalidatePageObjectVisibilities()
+{
+ mbPageObjectVisibilitiesValid = false;
+}
+
+void SlideSorterView::DeterminePageObjectVisibilities()
+{
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (!pWindow)
+ return;
+
+ // Set this flag to true here so that an invalidate during the
+ // visibility calculation can correctly invalidate it again.
+ mbPageObjectVisibilitiesValid = true;
+
+ ::tools::Rectangle aViewArea (pWindow->PixelToLogic(::tools::Rectangle(Point(0,0),pWindow->GetSizePixel())));
+ const Range aRange (mpLayouter->GetRangeOfVisiblePageObjects(aViewArea));
+ const Range aUnion(
+ ::std::min(maVisiblePageRange.Min(), aRange.Min()),
+ ::std::max(maVisiblePageRange.Max(), aRange.Max()));
+
+ // For page objects that just dropped off the visible area we
+ // decrease the priority of pending requests for preview bitmaps.
+ if (maVisiblePageRange != aRange)
+ mbPreciousFlagUpdatePending |= true;
+
+ model::SharedPageDescriptor pDescriptor;
+ for (::tools::Long nIndex=aUnion.Min(); nIndex<=aUnion.Max(); nIndex++)
+ {
+ pDescriptor = mrModel.GetPageDescriptor(nIndex);
+ if (pDescriptor)
+ SetState(
+ pDescriptor,
+ PageDescriptor::ST_Visible,
+ aRange.Contains(nIndex));
+ }
+
+ // Broadcast a change of the set of visible page objects.
+ if (maVisiblePageRange != aRange)
+ {
+ maVisiblePageRange = aRange;
+
+ // Tell the listeners that the visibility of some objects has
+ // changed.
+ ::std::vector<Link<LinkParamNone*,void>>& aChangeListeners (maVisibilityChangeListeners);
+ for (const auto& rLink : aChangeListeners)
+ {
+ rLink.Call(nullptr);
+ }
+ }
+
+ // Restore the mouse over state.
+ UpdatePageUnderMouse();
+}
+
+void SlideSorterView::UpdatePreciousFlags()
+{
+ if (!mbPreciousFlagUpdatePending)
+ return;
+
+ mbPreciousFlagUpdatePending = false;
+
+ model::SharedPageDescriptor pDescriptor;
+ std::shared_ptr<cache::PageCache> pCache = GetPreviewCache();
+ sal_Int32 nPageCount (mrModel.GetPageCount());
+
+ for (int nIndex=0; nIndex<=nPageCount; ++nIndex)
+ {
+ pDescriptor = mrModel.GetPageDescriptor(nIndex);
+ if (pDescriptor)
+ {
+ pCache->SetPreciousFlag(
+ pDescriptor->GetPage(),
+ maVisiblePageRange.Contains(nIndex));
+ }
+ else
+ {
+ // At least one cache entry can not be updated. Remember to
+ // repeat the whole updating later and leave the loop now.
+ mbPreciousFlagUpdatePending = true;
+ break;
+ }
+ }
+}
+
+bool SlideSorterView::SetOrientation (const Layouter::Orientation eOrientation)
+{
+ if (meOrientation != eOrientation)
+ {
+ meOrientation = eOrientation;
+ return true;
+ }
+ else
+ return false;
+}
+
+void SlideSorterView::RequestRepaint()
+{
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (pWindow)
+ {
+ mpLayeredDevice->InvalidateAllLayers(
+ ::tools::Rectangle(
+ pWindow->PixelToLogic(Point(0,0)),
+ pWindow->PixelToLogic(pWindow->GetSizePixel())));
+ pWindow->Invalidate();
+ }
+}
+
+void SlideSorterView::RequestRepaint (const model::SharedPageDescriptor& rpDescriptor)
+{
+ if (rpDescriptor)
+ RequestRepaint(rpDescriptor->GetBoundingBox());
+}
+
+void SlideSorterView::RequestRepaint (const ::tools::Rectangle& rRepaintBox)
+{
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (pWindow)
+ {
+ mpLayeredDevice->InvalidateAllLayers(rRepaintBox);
+ pWindow->Invalidate(rRepaintBox);
+ }
+}
+
+void SlideSorterView::RequestRepaint (const vcl::Region& rRepaintRegion)
+{
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (pWindow)
+ {
+ mpLayeredDevice->InvalidateAllLayers(rRepaintRegion);
+ pWindow->Invalidate(rRepaintRegion);
+ }
+}
+
+::tools::Rectangle SlideSorterView::GetModelArea() const
+{
+ return mpLayouter->GetTotalBoundingBox();
+}
+
+#ifdef DEBUG_TIMING
+static ::canvas::tools::ElapsedTime gaTimer;
+static const size_t gFrameTimeCount (10);
+static size_t gFrameTimeIndex (0);
+static ::std::vector<double> gFrameTimes (gFrameTimeCount, 0);
+static double gFrameTimeSum (0);
+static const ::tools::Rectangle gFrameTimeBox (10,10,150,20);
+static double gnLastFrameStart = 0;
+#endif
+
+void SlideSorterView::CompleteRedraw (
+ OutputDevice* pDevice,
+ const vcl::Region& rPaintArea,
+ sdr::contact::ViewObjectContactRedirector* pRedirector)
+{
+ (void)pRedirector;
+
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+
+ if (pDevice == nullptr || pDevice!=mrSlideSorter.GetContentWindow()->GetOutDev())
+ return;
+
+#ifdef DEBUG_TIMING
+ const double nStartTime (gaTimer.getElapsedTime());
+ SAL_INFO("sd.timing", "SlideSorterView::CompleteRedraw start" << (mnLockRedrawSmph ? " locked" : ""));
+#endif
+
+ // The parent implementation of CompleteRedraw is called only when
+ // painting is locked. We do all the painting ourself. When painting
+ // is locked the parent implementation keeps track of the repaint
+ // requests and later, when painting is unlocked, calls CompleteRedraw
+ // for all missed repaints.
+
+ if (mnLockRedrawSmph == 0)
+ {
+ if (mpLayeredDevice->HandleMapModeChange())
+ DeterminePageObjectVisibilities();
+ mpLayeredDevice->Repaint(rPaintArea);
+ }
+ else
+ {
+ maRedrawRegion.Union(rPaintArea);
+ }
+
+#ifdef DEBUG_TIMING
+ const double nEndTime (gaTimer.getElapsedTime());
+ SAL_INFO("sd.timing", "SlideSorterView::CompleteRedraw end after " << (nEndTime-nStartTime)*1000 << " ms");
+ gFrameTimeSum -= gFrameTimes[gFrameTimeIndex];
+ gFrameTimes[gFrameTimeIndex] = nStartTime - gnLastFrameStart;
+ gnLastFrameStart = nStartTime;
+ gFrameTimeSum += gFrameTimes[gFrameTimeIndex];
+ gFrameTimeIndex = (gFrameTimeIndex+1) % gFrameTimeCount;
+
+ mrSlideSorter.GetContentWindow()->SetFillColor(COL_BLUE);
+ mrSlideSorter.GetContentWindow()->DrawRect(gFrameTimeBox);
+ mrSlideSorter.GetContentWindow()->SetTextColor(COL_WHITE);
+ mrSlideSorter.GetContentWindow()->DrawText(
+ gFrameTimeBox,
+ OUString::number(1 / (gFrameTimeSum / gFrameTimeCount)),
+ DrawTextFlags::Right | DrawTextFlags::VCenter);
+ // mrSlideSorter.GetContentWindow()->Invalidate(gFrameTimeBox);
+#endif
+}
+
+void SlideSorterView::Paint (
+ OutputDevice& rDevice,
+ const ::tools::Rectangle& rRepaintArea)
+{
+ if (rRepaintArea.IsEmpty())
+ return;
+
+ if ( ! mpPageObjectPainter)
+ if ( ! GetPageObjectPainter())
+ return;
+
+ // Update the page visibilities when they have been invalidated.
+ if ( ! mbPageObjectVisibilitiesValid)
+ DeterminePageObjectVisibilities();
+
+ if (mbPreciousFlagUpdatePending)
+ UpdatePreciousFlags();
+
+ if (mbIsRearrangePending)
+ Rearrange();
+
+ // Paint all page objects that are fully or partially inside the
+ // repaint region.
+ const Range aRange (mpLayouter->GetRangeOfVisiblePageObjects(rRepaintArea));
+ // Try to prefetch all graphics from the pages to paint. This will be done
+ // in threads to be more efficient than loading them on-demand one by one.
+ std::vector<Graphic*> graphics;
+ for (::tools::Long nIndex=aRange.Min(); nIndex<=aRange.Max(); ++nIndex)
+ {
+ model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex));
+ if (!pDescriptor || ! pDescriptor->HasState(PageDescriptor::ST_Visible))
+ continue;
+ pDescriptor->GetPage()->getGraphicsForPrefetch(graphics);
+ }
+ // Handle also one page before and after to have those in advance on scrolling.
+ for (::tools::Long nIndex : { aRange.Min() - 1, aRange.Max() + 1 })
+ {
+ model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex));
+ if (!pDescriptor)
+ continue;
+ pDescriptor->GetPage()->getGraphicsForPrefetch(graphics);
+ }
+ if(graphics.size() > 1) // threading does not help with loading just one
+ GraphicFilter::GetGraphicFilter().MakeGraphicsAvailableThreaded(graphics);
+
+ for (::tools::Long nIndex=aRange.Min(); nIndex<=aRange.Max(); ++nIndex)
+ {
+ model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex));
+ if (!pDescriptor || ! pDescriptor->HasState(PageDescriptor::ST_Visible))
+ continue;
+
+ mpPageObjectPainter->PaintPageObject(rDevice, pDescriptor);
+ }
+}
+
+void SlideSorterView::ConfigurationChanged (
+ utl::ConfigurationBroadcaster* pBroadcaster,
+ ConfigurationHints nHint)
+{
+ // Some changes of the configuration (some of the colors for example)
+ // may affect the previews. Throw away the old ones and create new ones.
+ cache::PageCacheManager::Instance()->InvalidateAllCaches();
+
+ ::sd::View::ConfigurationChanged(pBroadcaster, nHint);
+ RequestRepaint();
+
+}
+
+std::shared_ptr<cache::PageCache> const & SlideSorterView::GetPreviewCache()
+{
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (pWindow && mpPreviewCache == nullptr)
+ {
+ mpPreviewCache =
+ std::make_shared<cache::PageCache>(
+ mpLayouter->GetPageObjectSize(),
+ Bitmap::HasFastScale(),
+ std::make_shared<ViewCacheContext>(mrSlideSorter));
+ }
+
+ return mpPreviewCache;
+}
+
+Range const & SlideSorterView::GetVisiblePageRange()
+{
+ if ( ! mbPageObjectVisibilitiesValid)
+ DeterminePageObjectVisibilities();
+ return maVisiblePageRange;
+}
+
+void SlideSorterView::AddVisibilityChangeListener (const Link<LinkParamNone*,void>& rListener)
+{
+ if (::std::find (
+ maVisibilityChangeListeners.begin(),
+ maVisibilityChangeListeners.end(),
+ rListener) == maVisibilityChangeListeners.end())
+ {
+ maVisibilityChangeListeners.push_back(rListener);
+ }
+}
+
+void SlideSorterView::RemoveVisibilityChangeListener(const Link<LinkParamNone*,void>&rListener)
+{
+ maVisibilityChangeListeners.erase (
+ ::std::find (
+ maVisibilityChangeListeners.begin(),
+ maVisibilityChangeListeners.end(),
+ rListener));
+}
+
+ToolTip& SlideSorterView::GetToolTip() const
+{
+ OSL_ASSERT(mpToolTip);
+ return *mpToolTip;
+}
+
+void SlideSorterView::DragFinished (sal_Int8 nDropAction)
+{
+ mrSlideSorter.GetController().GetClipboard().DragFinished(nDropAction);
+
+ View::DragFinished(nDropAction);
+}
+
+void SlideSorterView::UpdatePageUnderMouse ()
+{
+ VclPtr<ScrollBar> pVScrollBar (mrSlideSorter.GetVerticalScrollBar());
+ VclPtr<ScrollBar> pHScrollBar (mrSlideSorter.GetHorizontalScrollBar());
+ if ((pVScrollBar && pVScrollBar->IsVisible() && pVScrollBar->IsTracking())
+ || (pHScrollBar && pHScrollBar->IsVisible() && pHScrollBar->IsTracking()))
+ {
+ // One of the scroll bars is tracking mouse movement. Do not
+ // highlight the slide under the mouse in this case.
+ SetPageUnderMouse(SharedPageDescriptor());
+ return;
+ }
+
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (pWindow && pWindow->IsVisible() && ! pWindow->IsMouseCaptured())
+ {
+ const Window::PointerState aPointerState (pWindow->GetPointerState());
+ const ::tools::Rectangle aWindowBox (pWindow->GetPosPixel(), pWindow->GetSizePixel());
+ if (aWindowBox.Contains(aPointerState.maPos))
+ {
+ UpdatePageUnderMouse(aPointerState.maPos);
+ return;
+ }
+ }
+
+ SetPageUnderMouse(SharedPageDescriptor());
+}
+
+void SlideSorterView::UpdatePageUnderMouse (
+ const Point& rMousePosition)
+{
+ SetPageUnderMouse(mrSlideSorter.GetController().GetPageAt(rMousePosition));
+}
+
+void SlideSorterView::SetPageUnderMouse (
+ const model::SharedPageDescriptor& rpDescriptor)
+{
+ if (mpPageUnderMouse == rpDescriptor)
+ return;
+
+ if (mpPageUnderMouse)
+ SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, false);
+
+ mpPageUnderMouse = rpDescriptor;
+
+ if (mpPageUnderMouse)
+ SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, true);
+
+ // Change the quick help text to display the name of the page under
+ // the mouse.
+ mpToolTip->SetPage(rpDescriptor);
+}
+
+bool SlideSorterView::SetState (
+ const model::SharedPageDescriptor& rpDescriptor,
+ const PageDescriptor::State eState,
+ const bool bStateValue)
+{
+ if ( ! rpDescriptor)
+ return false;
+
+ const bool bModified (rpDescriptor->SetState(eState, bStateValue));
+ if ( ! bModified)
+ return false;
+
+ // When the page object is not visible (i.e. not on the screen then
+ // nothing has to be painted.
+ if (rpDescriptor->HasState(PageDescriptor::ST_Visible))
+ {
+ // For most states a change of that state leads to visible
+ // difference and we have to request a repaint.
+ if (eState != PageDescriptor::ST_WasSelected)
+ RequestRepaint(rpDescriptor);
+ }
+
+ return bModified;
+}
+
+std::shared_ptr<PageObjectPainter> const & SlideSorterView::GetPageObjectPainter()
+{
+ if ( ! mpPageObjectPainter)
+ mpPageObjectPainter = std::make_shared<PageObjectPainter>(mrSlideSorter);
+ return mpPageObjectPainter;
+}
+
+//===== SlideSorterView::DrawLock =============================================
+
+SlideSorterView::DrawLock::DrawLock (SlideSorter const & rSlideSorter)
+ : mrView(rSlideSorter.GetView()),
+ mpWindow(rSlideSorter.GetContentWindow())
+{
+ if (mrView.mnLockRedrawSmph == 0)
+ mrView.maRedrawRegion.SetEmpty();
+ ++mrView.mnLockRedrawSmph;
+}
+
+SlideSorterView::DrawLock::~DrawLock()
+{
+ OSL_ASSERT(mrView.mnLockRedrawSmph>0);
+ --mrView.mnLockRedrawSmph;
+ if (mrView.mnLockRedrawSmph == 0)
+ if (mpWindow)
+ {
+ mpWindow->Invalidate(mrView.maRedrawRegion);
+ }
+}
+
+void SlideSorterView::DrawLock::Dispose()
+{
+ mpWindow.reset();
+}
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsFramePainter.cxx b/sd/source/ui/slidesorter/view/SlsFramePainter.cxx
new file mode 100644
index 000000000..31c301868
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsFramePainter.cxx
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlsFramePainter.hxx"
+#include <vcl/outdev.hxx>
+#include <osl/diagnose.h>
+
+namespace sd::slidesorter::view {
+
+FramePainter::FramePainter (const BitmapEx& rShadowBitmap)
+ : maTopLeft(rShadowBitmap,-1,-1),
+ maTop(rShadowBitmap,0,-1),
+ maTopRight(rShadowBitmap,+1,-1),
+ maLeft(rShadowBitmap,-1,0),
+ maRight(rShadowBitmap,+1,0),
+ maBottomLeft(rShadowBitmap,-1,+1),
+ maBottom(rShadowBitmap,0,+1),
+ maBottomRight(rShadowBitmap,+1,+1),
+ maCenter(rShadowBitmap,0,0),
+ mbIsValid(false)
+{
+ if (rShadowBitmap.GetSizePixel().Width() == rShadowBitmap.GetSizePixel().Height()
+ && (rShadowBitmap.GetSizePixel().Width()-1)%2 == 0
+ && ((rShadowBitmap.GetSizePixel().Width()-1)/2)%2 == 1)
+ {
+ mbIsValid = true;
+ }
+ else
+ {
+ OSL_ASSERT(rShadowBitmap.GetSizePixel().Width() == rShadowBitmap.GetSizePixel().Height());
+ OSL_ASSERT((rShadowBitmap.GetSizePixel().Width()-1)%2 == 0);
+ OSL_ASSERT(((rShadowBitmap.GetSizePixel().Width()-1)/2)%2 == 1);
+ }
+}
+
+FramePainter::~FramePainter()
+{
+}
+
+void FramePainter::PaintFrame (
+ OutputDevice& rDevice,
+ const ::tools::Rectangle& rBox) const
+{
+ if ( ! mbIsValid)
+ return;
+
+ // Paint the shadow.
+ maTopLeft.PaintCorner(rDevice, rBox.TopLeft());
+ maTopRight.PaintCorner(rDevice, rBox.TopRight());
+ maBottomLeft.PaintCorner(rDevice, rBox.BottomLeft());
+ maBottomRight.PaintCorner(rDevice, rBox.BottomRight());
+ maLeft.PaintSide(rDevice, rBox.TopLeft(), rBox.BottomLeft(), maTopLeft, maBottomLeft);
+ maRight.PaintSide(rDevice, rBox.TopRight(), rBox.BottomRight(), maTopRight, maBottomRight);
+ maTop.PaintSide(rDevice, rBox.TopLeft(), rBox.TopRight(), maTopLeft, maTopRight);
+ maBottom.PaintSide(rDevice, rBox.BottomLeft(), rBox.BottomRight(), maBottomLeft, maBottomRight);
+ maCenter.PaintCenter(rDevice,rBox);
+}
+
+void FramePainter::AdaptColor (
+ const Color aNewColor)
+{
+ // Get the source color.
+ if (maCenter.maBitmap.IsEmpty())
+ return;
+ const Color aSourceColor = maCenter.maBitmap.GetPixelColor(0,0);
+
+ // Erase the center bitmap.
+ maCenter.maBitmap.SetEmpty();
+
+ // Replace the color in all bitmaps.
+ maTopLeft.maBitmap.Replace(aSourceColor, aNewColor);
+ maTop.maBitmap.Replace(aSourceColor, aNewColor);
+ maTopRight.maBitmap.Replace(aSourceColor, aNewColor);
+ maLeft.maBitmap.Replace(aSourceColor, aNewColor);
+ maCenter.maBitmap.Replace(aSourceColor, aNewColor);
+ maRight.maBitmap.Replace(aSourceColor, aNewColor);
+ maBottomLeft.maBitmap.Replace(aSourceColor, aNewColor);
+ maBottom.maBitmap.Replace(aSourceColor, aNewColor);
+ maBottomRight.maBitmap.Replace(aSourceColor, aNewColor);
+}
+
+//===== FramePainter::OffsetBitmap ============================================
+
+FramePainter::OffsetBitmap::OffsetBitmap (
+ const BitmapEx& rBitmap,
+ const sal_Int32 nHorizontalPosition,
+ const sal_Int32 nVerticalPosition)
+{
+ OSL_ASSERT(nHorizontalPosition>=-1 && nHorizontalPosition<=+1);
+ OSL_ASSERT(nVerticalPosition>=-1 && nVerticalPosition<=+1);
+
+ const sal_Int32 nS (1);
+ const sal_Int32 nC (::std::max<sal_Int32>(0,(rBitmap.GetSizePixel().Width()-nS)/2));
+ const sal_Int32 nO (nC/2);
+
+ const Point aOrigin(
+ nHorizontalPosition<0 ? 0 : (nHorizontalPosition == 0 ? nC : nC+nS),
+ nVerticalPosition<0 ? 0 : (nVerticalPosition == 0 ? nC : nC+nS));
+ const Size aSize(
+ nHorizontalPosition==0 ? nS : nC,
+ nVerticalPosition==0 ? nS : nC);
+ maBitmap = BitmapEx(rBitmap, aOrigin, aSize);
+ if (maBitmap.IsEmpty())
+ return;
+ maOffset = Point(
+ nHorizontalPosition<0 ? -nO : nHorizontalPosition>0 ? -nO : 0,
+ nVerticalPosition<0 ? -nO : nVerticalPosition>0 ? -nO : 0);
+
+ // Enlarge the side bitmaps so that painting the frame requires less
+ // paint calls.
+ const sal_Int32 nSideBitmapSize (64);
+ if (nHorizontalPosition == 0 && nVerticalPosition == 0)
+ {
+ maBitmap.Scale(Size(nSideBitmapSize,nSideBitmapSize));
+ }
+ else if (nHorizontalPosition == 0)
+ {
+ maBitmap.Scale(Size(nSideBitmapSize,aSize.Height()));
+ }
+ else if (nVerticalPosition == 0)
+ {
+ maBitmap.Scale(Size(maBitmap.GetSizePixel().Width(), nSideBitmapSize));
+ }
+}
+
+void FramePainter::OffsetBitmap::PaintCorner (
+ OutputDevice& rDevice,
+ const Point& rAnchor) const
+{
+ if ( ! maBitmap.IsEmpty())
+ rDevice.DrawBitmapEx(rAnchor+maOffset, maBitmap);
+}
+
+void FramePainter::OffsetBitmap::PaintSide (
+ OutputDevice& rDevice,
+ const Point& rAnchor1,
+ const Point& rAnchor2,
+ const OffsetBitmap& rCornerBitmap1,
+ const OffsetBitmap& rCornerBitmap2) const
+{
+ if (maBitmap.IsEmpty())
+ return;
+
+ const Size aBitmapSize (maBitmap.GetSizePixel());
+ if (rAnchor1.Y() == rAnchor2.Y())
+ {
+ // Side is horizontal.
+ const sal_Int32 nY (rAnchor1.Y() + maOffset.Y());
+ const sal_Int32 nLeft (
+ rAnchor1.X()
+ + rCornerBitmap1.maBitmap.GetSizePixel().Width()
+ + rCornerBitmap1.maOffset.X());
+ const sal_Int32 nRight (
+ rAnchor2.X()
+ + rCornerBitmap2.maOffset.X()
+ - 1);
+ for (sal_Int32 nX=nLeft; nX<=nRight; nX+=aBitmapSize.Width())
+ {
+ rDevice.DrawBitmapEx(
+ Point(nX,nY),
+ Size(std::min(aBitmapSize.Width(),static_cast<::tools::Long>(nRight-nX+1)),aBitmapSize.Height()),
+ maBitmap);
+ }
+ }
+ else if (rAnchor1.X() == rAnchor2.X())
+ {
+ // Side is vertical.
+ const sal_Int32 nX (rAnchor1.X() + maOffset.X());
+ const sal_Int32 nTop (
+ rAnchor1.Y()
+ + rCornerBitmap1.maBitmap.GetSizePixel().Height()
+ + rCornerBitmap1.maOffset.Y());
+ const sal_Int32 nBottom (
+ rAnchor2.Y()
+ + rCornerBitmap2.maOffset.Y()
+ - 1);
+ for (sal_Int32 nY=nTop; nY<=nBottom; nY+=aBitmapSize.Height())
+ {
+ rDevice.DrawBitmapEx(
+ Point(nX,nY),
+ Size(aBitmapSize.Width(), std::min(aBitmapSize.Height(), static_cast<::tools::Long>(nBottom-nY+1))),
+ maBitmap);
+ }
+ }
+ else
+ {
+ // Diagonal sides indicates an error.
+ OSL_ASSERT(false);
+ }
+}
+
+void FramePainter::OffsetBitmap::PaintCenter (
+ OutputDevice& rDevice,
+ const ::tools::Rectangle& rBox) const
+{
+ const Size aBitmapSize (maBitmap.GetSizePixel());
+ for (::tools::Long nY=rBox.Top(); nY<=rBox.Bottom(); nY+=aBitmapSize.Height())
+ for (::tools::Long nX=rBox.Left(); nX<=rBox.Right(); nX+=aBitmapSize.Width())
+ rDevice.DrawBitmapEx(
+ Point(nX,nY),
+ Size(
+ ::std::min(aBitmapSize.Width(), rBox.Right()-nX+1),
+ std::min(aBitmapSize.Height(), rBox.Bottom()-nY+1)),
+ maBitmap);
+}
+
+} // end of namespace sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsFramePainter.hxx b/sd/source/ui/slidesorter/view/SlsFramePainter.hxx
new file mode 100644
index 000000000..9398cb94e
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsFramePainter.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/bitmapex.hxx>
+
+namespace sd::slidesorter::view {
+
+class FramePainter
+{
+public:
+ explicit FramePainter (const BitmapEx& rBitmap);
+ ~FramePainter();
+
+ /** Paint a border around the given box by using a set of bitmaps for
+ the corners and sides.
+ */
+ void PaintFrame (OutputDevice&rDevice, const ::tools::Rectangle& rBox) const;
+
+ /** Special functionality that takes the color from the center
+ bitmap and replaces that color in all bitmaps by the given new
+ color. Alpha values are not modified.
+ The center bitmap is erased.
+ */
+ void AdaptColor (const Color aNewColor);
+
+private:
+ /** Bitmap with offset that is used when the bitmap is painted. The bitmap
+ */
+ class OffsetBitmap {
+ public:
+ BitmapEx maBitmap;
+ Point maOffset;
+
+ /** Create one of the eight shadow bitmaps from one that combines
+ them all. This larger bitmap is expected to have dimension NxN
+ with N=1+2*M. Of this larger bitmap there are created four
+ corner bitmaps of size 2*M x 2*M and four side bitmaps of sizes
+ 1xM (top and bottom) and Mx1 (left and right). The corner
+ bitmaps have each one quadrant of size MxM that is painted under
+ the interior of the frame.
+ @param rBitmap
+ The larger bitmap of which the eight shadow bitmaps are cut
+ out from.
+ @param nHorizontalPosition
+ Valid values are -1 (left), 0 (center), and +1 (right).
+ @param nVerticalPosition
+ Valid values are -1 (top), 0 (center), and +1 (bottom).
+ */
+ OffsetBitmap (
+ const BitmapEx& rBitmap,
+ const sal_Int32 nHorizontalPosition,
+ const sal_Int32 nVerticalPosition);
+
+ /** Use the given device to paint the bitmap at the location that is
+ the sum of the given anchor and the internal offset.
+ */
+ void PaintCorner (OutputDevice& rDevice, const Point& rAnchor) const;
+
+ /** Use the given device to paint the bitmap stretched between the
+ two given locations. Offsets of the adjacent corner bitmaps and
+ the offset of the side bitmap are used to determine the area
+ that is to be filled with the side bitmap.
+ */
+ void PaintSide (
+ OutputDevice& rDevice,
+ const Point& rAnchor1,
+ const Point& rAnchor2,
+ const OffsetBitmap& rCornerBitmap1,
+ const OffsetBitmap& rCornerBitmap2) const;
+
+ /** Fill the given rectangle with the bitmap.
+ */
+ void PaintCenter (
+ OutputDevice& rDevice,
+ const ::tools::Rectangle& rBox) const;
+ };
+ OffsetBitmap maTopLeft;
+ OffsetBitmap maTop;
+ OffsetBitmap maTopRight;
+ OffsetBitmap maLeft;
+ OffsetBitmap maRight;
+ OffsetBitmap maBottomLeft;
+ OffsetBitmap maBottom;
+ OffsetBitmap maBottomRight;
+ OffsetBitmap maCenter;
+ bool mbIsValid;
+};
+
+} // end of namespace sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsInsertAnimator.cxx b/sd/source/ui/slidesorter/view/SlsInsertAnimator.cxx
new file mode 100644
index 000000000..361c55f05
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsInsertAnimator.cxx
@@ -0,0 +1,428 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <view/SlsInsertAnimator.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsAnimationFunction.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <SlideSorter.hxx>
+#include <Window.hxx>
+#include <osl/diagnose.h>
+
+#include <memory>
+#include <set>
+
+namespace sd::slidesorter::view {
+
+namespace {
+
+class PageObjectRun;
+
+class AnimatorAccess
+{
+public:
+ virtual void AddRun (const std::shared_ptr<PageObjectRun>& rRun) = 0;
+ virtual void RemoveRun (const std::shared_ptr<PageObjectRun>& rRun) = 0;
+ virtual model::SlideSorterModel& GetModel () const = 0;
+ virtual view::SlideSorterView& GetView () const = 0;
+ virtual std::shared_ptr<controller::Animator> GetAnimator () = 0;
+ virtual VclPtr<sd::Window> GetContentWindow () = 0;
+
+protected:
+ ~AnimatorAccess() COVERITY_NOEXCEPT_FALSE {}
+};
+
+/** Controller of the position offsets of all page objects in one row or one
+ column.
+*/
+class PageObjectRun : public std::enable_shared_from_this<PageObjectRun>
+{
+public:
+ PageObjectRun (
+ AnimatorAccess& rAnimatorAccess,
+ const sal_Int32 nRunIndex,
+ const sal_Int32 nStartIndex,
+ const sal_Int32 nEndIndex);
+
+ void operator () (const double nTime);
+
+ void UpdateOffsets(
+ const InsertPosition& rInsertPosition,
+ const view::Layouter& GetLayouter);
+ void ResetOffsets (const controller::Animator::AnimationMode eMode);
+
+ /// Index of the row or column that this run represents.
+ sal_Int32 mnRunIndex;
+ /// The index at which to make place for the insertion indicator (-1 for
+ /// no indicator).
+ sal_Int32 mnLocalInsertIndex;
+ /// Index of the first page in the run.
+ sal_Int32 mnStartIndex;
+ /// Index of the last page in the run.
+ sal_Int32 mnEndIndex;
+ /// Offset of each item in the run at the start of the current animation.
+ ::std::vector<Point> maStartOffset;
+ /// Target offset of each item in the run at the end of the current animation.
+ ::std::vector<Point> maEndOffset;
+ /// Time at which the current animation started.
+ double mnStartTime;
+
+ class Comparator
+ {
+ public: bool operator() (
+ const std::shared_ptr<PageObjectRun>& rpRunA,
+ const std::shared_ptr<PageObjectRun>& rpRunB) const
+ {
+ return rpRunA->mnRunIndex < rpRunB->mnRunIndex;
+ }
+ };
+private:
+ controller::Animator::AnimationId mnAnimationId;
+ AnimatorAccess& mrAnimatorAccess;
+ ::std::function<double (double)> maAccelerationFunction;
+
+ void RestartAnimation();
+};
+typedef std::shared_ptr<PageObjectRun> SharedPageObjectRun;
+
+Point Blend (const Point& rPointA, const Point& rPointB, const double nT)
+{
+ return Point(
+ sal_Int32(rPointA.X() * (1-nT) + rPointB.X() * nT),
+ sal_Int32(rPointA.Y() * (1-nT) + rPointB.Y() * nT));
+}
+
+} // end of anonymous namespace
+
+class InsertAnimator::Implementation : public AnimatorAccess
+{
+public:
+ explicit Implementation (SlideSorter& rSlideSorter);
+ virtual ~Implementation();
+
+ void SetInsertPosition (
+ const InsertPosition& rInsertPosition,
+ const controller::Animator::AnimationMode eAnimationMode);
+
+ virtual void AddRun (const std::shared_ptr<PageObjectRun>& rRun) override;
+ virtual void RemoveRun (const std::shared_ptr<PageObjectRun>& rRun) override;
+
+ virtual model::SlideSorterModel& GetModel() const override { return mrModel; }
+ virtual view::SlideSorterView& GetView() const override { return mrView; }
+ virtual std::shared_ptr<controller::Animator> GetAnimator() override { return mpAnimator; }
+ virtual VclPtr<sd::Window> GetContentWindow() override { return mrSlideSorter.GetContentWindow(); }
+
+private:
+ model::SlideSorterModel& mrModel;
+ view::SlideSorterView& mrView;
+ SlideSorter& mrSlideSorter;
+ std::shared_ptr<controller::Animator> mpAnimator;
+ typedef ::std::set<SharedPageObjectRun, PageObjectRun::Comparator> RunContainer;
+ RunContainer maRuns;
+ InsertPosition maInsertPosition;
+
+ SharedPageObjectRun GetRun (
+ view::Layouter const & rLayouter,
+ const InsertPosition& rInsertPosition);
+ RunContainer::const_iterator FindRun (const sal_Int32 nRunIndex) const;
+};
+
+//===== InsertAnimator ========================================================
+
+InsertAnimator::InsertAnimator (SlideSorter& rSlideSorter)
+ : mpImplementation(std::make_shared<Implementation>(rSlideSorter))
+{
+}
+
+void InsertAnimator::SetInsertPosition (const InsertPosition& rInsertPosition)
+{
+ mpImplementation->SetInsertPosition(rInsertPosition, controller::Animator::AM_Animated);
+}
+
+void InsertAnimator::Reset (const controller::Animator::AnimationMode eMode)
+{
+ mpImplementation->SetInsertPosition(InsertPosition(), eMode);
+}
+
+//===== InsertAnimator::Implementation ========================================
+
+InsertAnimator::Implementation::Implementation (SlideSorter& rSlideSorter)
+ : mrModel(rSlideSorter.GetModel()),
+ mrView(rSlideSorter.GetView()),
+ mrSlideSorter(rSlideSorter),
+ mpAnimator(rSlideSorter.GetController().GetAnimator())
+{
+}
+
+InsertAnimator::Implementation::~Implementation()
+{
+ SetInsertPosition(InsertPosition(), controller::Animator::AM_Immediate);
+}
+
+void InsertAnimator::Implementation::SetInsertPosition (
+ const InsertPosition& rInsertPosition,
+ const controller::Animator::AnimationMode eMode)
+{
+ if (maInsertPosition == rInsertPosition)
+ return;
+
+ SharedPageObjectRun pOldRun (GetRun(mrView.GetLayouter(), maInsertPosition));
+ SharedPageObjectRun pCurrentRun (GetRun(mrView.GetLayouter(), rInsertPosition));
+ maInsertPosition = rInsertPosition;
+
+ // When the new insert position is in a different run then move the page
+ // objects in the old run to their default positions.
+ if (pOldRun != pCurrentRun && pOldRun)
+ pOldRun->ResetOffsets(eMode);
+
+ if (pCurrentRun)
+ {
+ pCurrentRun->UpdateOffsets(rInsertPosition, mrView.GetLayouter());
+ }
+}
+
+SharedPageObjectRun InsertAnimator::Implementation::GetRun (
+ view::Layouter const & rLayouter,
+ const InsertPosition& rInsertPosition)
+{
+ const sal_Int32 nRow (rInsertPosition.GetRow());
+ if (nRow < 0)
+ return SharedPageObjectRun();
+
+ RunContainer::const_iterator iRun (maRuns.end());
+ if (rLayouter.GetColumnCount() == 1)
+ {
+ // There is only one run that contains all slides.
+ if (maRuns.empty())
+ maRuns.insert(std::make_shared<PageObjectRun>(
+ *this,
+ 0,
+ 0,
+ mrModel.GetPageCount()-1));
+ iRun = maRuns.begin();
+ }
+ else
+ {
+ iRun = FindRun(nRow);
+ if (iRun == maRuns.end())
+ {
+ // Create a new run.
+ const sal_Int32 nStartIndex (rLayouter.GetIndex(nRow, 0));
+ const sal_Int32 nEndIndex (rLayouter.GetIndex(nRow, rLayouter.GetColumnCount()-1));
+ if (nStartIndex <= nEndIndex)
+ {
+ iRun = maRuns.insert(std::make_shared<PageObjectRun>(
+ *this,
+ nRow,
+ nStartIndex,
+ nEndIndex)).first;
+ OSL_ASSERT(iRun != maRuns.end());
+ }
+ }
+ }
+
+ if (iRun != maRuns.end())
+ return *iRun;
+ else
+ return SharedPageObjectRun();
+}
+
+InsertAnimator::Implementation::RunContainer::const_iterator
+ InsertAnimator::Implementation::FindRun (const sal_Int32 nRunIndex) const
+{
+ return std::find_if(
+ maRuns.begin(),
+ maRuns.end(),
+ [nRunIndex] (std::shared_ptr<PageObjectRun> const& rRun)
+ { return rRun->mnRunIndex == nRunIndex; });
+}
+
+void InsertAnimator::Implementation::AddRun (const std::shared_ptr<PageObjectRun>& rRun)
+{
+ if (rRun)
+ {
+ maRuns.insert(rRun);
+ }
+ else
+ {
+ OSL_ASSERT(rRun);
+ }
+}
+
+void InsertAnimator::Implementation::RemoveRun (const std::shared_ptr<PageObjectRun>& rRun)
+{
+ if (rRun)
+ {
+ // Do not remove runs that show the space for the insertion indicator.
+ if (rRun->mnLocalInsertIndex == -1)
+ {
+ InsertAnimator::Implementation::RunContainer::const_iterator iRun (FindRun(rRun->mnRunIndex));
+ if (iRun != maRuns.end())
+ {
+ OSL_ASSERT(*iRun == rRun);
+ maRuns.erase(iRun);
+ }
+ }
+ }
+ else
+ {
+ OSL_ASSERT(rRun);
+ }
+}
+
+//===== PageObjectRun =========================================================
+
+PageObjectRun::PageObjectRun (
+ AnimatorAccess& rAnimatorAccess,
+ const sal_Int32 nRunIndex,
+ const sal_Int32 nStartIndex,
+ const sal_Int32 nEndIndex)
+ : mnRunIndex(nRunIndex),
+ mnLocalInsertIndex(-1),
+ mnStartIndex(nStartIndex),
+ mnEndIndex(nEndIndex),
+ mnStartTime(-1),
+ mnAnimationId(controller::Animator::NotAnAnimationId),
+ mrAnimatorAccess(rAnimatorAccess),
+ maAccelerationFunction(
+ controller::AnimationParametricFunction(
+ controller::AnimationBezierFunction (0.1,0.7)))
+{
+ maStartOffset.resize(nEndIndex - nStartIndex + 1);
+ maEndOffset.resize(nEndIndex - nStartIndex + 1);
+}
+
+void PageObjectRun::UpdateOffsets(
+ const InsertPosition& rInsertPosition,
+ const view::Layouter& rLayouter)
+{
+ const bool bIsVertical (rLayouter.GetColumnCount()==1);
+ const sal_Int32 nLocalInsertIndex(bIsVertical
+ ? rInsertPosition.GetRow()
+ : rInsertPosition.GetColumn());
+ if (nLocalInsertIndex == mnLocalInsertIndex)
+ return;
+
+ mnLocalInsertIndex = nLocalInsertIndex;
+
+ model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
+ const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1);
+ for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex)
+ {
+ model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex));
+ if (pDescriptor)
+ maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset();
+ maEndOffset[nIndex] = nIndex < mnLocalInsertIndex
+ ? rInsertPosition.GetLeadingOffset()
+ : rInsertPosition.GetTrailingOffset();
+ if (bIsVertical)
+ maEndOffset[nIndex].setX( 0 );
+ else
+ maEndOffset[nIndex].setY( 0 );
+ }
+ RestartAnimation();
+}
+
+void PageObjectRun::ResetOffsets (const controller::Animator::AnimationMode eMode)
+{
+ mnLocalInsertIndex = -1;
+ const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1);
+ model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
+ view::SlideSorterView& rView (mrAnimatorAccess.GetView());
+ for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex)
+ {
+ model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex));
+ if (pDescriptor)
+ {
+ if (eMode == controller::Animator::AM_Animated)
+ maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset();
+ else
+ {
+ const ::tools::Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox());
+ pDescriptor->GetVisualState().SetLocationOffset(Point(0,0));
+ rView.RequestRepaint(aOldBoundingBox);
+ rView.RequestRepaint(pDescriptor);
+ }
+ }
+ maEndOffset[nIndex] = Point(0,0);
+ }
+ if (eMode == controller::Animator::AM_Animated)
+ RestartAnimation();
+ else
+ mrAnimatorAccess.RemoveRun(shared_from_this());
+}
+
+void PageObjectRun::RestartAnimation()
+{
+ // Stop the current animation.
+ if (mnAnimationId != controller::Animator::NotAnAnimationId)
+ {
+ mrAnimatorAccess.GetAnimator()->RemoveAnimation(mnAnimationId);
+ }
+
+ // Restart the animation.
+ mrAnimatorAccess.AddRun(shared_from_this());
+ auto sharedThis(shared_from_this());
+ mnAnimationId = mrAnimatorAccess.GetAnimator()->AddAnimation(
+ [this] (double const val) { (*this)(val); },
+ [sharedThis] () { sharedThis->mrAnimatorAccess.RemoveRun(sharedThis); }
+ );
+}
+
+void PageObjectRun::operator () (const double nGlobalTime)
+{
+ if (mnStartTime < 0)
+ mnStartTime = nGlobalTime;
+
+ double nLocalTime (nGlobalTime - mnStartTime);
+ if (nLocalTime > 1.0)
+ nLocalTime = 1.0;
+ nLocalTime = maAccelerationFunction(nLocalTime);
+
+ model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel());
+ view::SlideSorterView& rView (mrAnimatorAccess.GetView());
+ for (sal_Int32 nIndex=mnStartIndex; nIndex<=mnEndIndex; ++nIndex)
+ {
+ model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
+ if ( ! pDescriptor)
+ continue;
+ const ::tools::Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox());
+ pDescriptor->GetVisualState().SetLocationOffset(
+ Blend(
+ maStartOffset[nIndex-mnStartIndex],
+ maEndOffset[nIndex-mnStartIndex],
+ nLocalTime));
+
+ // Request a repaint of the old and new bounding box (which largely overlap.)
+ rView.RequestRepaint(aOldBoundingBox);
+ rView.RequestRepaint(pDescriptor);
+ }
+
+ // Call Flush to make
+ // a) animations a bit more smooth and
+ // b) on Mac without the Flush a Reset of the page locations is not properly
+ // visualized when the mouse leaves the window during drag-and-drop.
+ mrAnimatorAccess.GetContentWindow()->GetOutDev()->Flush();
+}
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx
new file mode 100644
index 000000000..c1eb0ea90
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx
@@ -0,0 +1,360 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <view/SlsInsertionIndicatorOverlay.hxx>
+
+#include <SlideSorter.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <view/SlsPageObjectLayouter.hxx>
+#include <view/SlsTheme.hxx>
+#include "SlsFramePainter.hxx"
+#include "SlsLayeredDevice.hxx"
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <Window.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <rtl/math.hxx>
+#include <vcl/virdev.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+namespace {
+
+const double gnPreviewOffsetScale = 1.0 / 8.0;
+
+::tools::Rectangle GrowRectangle (const ::tools::Rectangle& rBox, const sal_Int32 nOffset)
+{
+ return ::tools::Rectangle (
+ rBox.Left() - nOffset,
+ rBox.Top() - nOffset,
+ rBox.Right() + nOffset,
+ rBox.Bottom() + nOffset);
+}
+
+sal_Int32 RoundToInt (const double nValue) { return sal_Int32(::rtl::math::round(nValue)); }
+
+} // end of anonymous namespace
+
+namespace sd::slidesorter::view {
+
+//===== InsertionIndicatorOverlay ===========================================
+
+const sal_Int32 gnShadowBorder = 3;
+const sal_Int32 gnLayerIndex = 2;
+
+InsertionIndicatorOverlay::InsertionIndicatorOverlay (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mbIsVisible(false),
+ mpShadowPainter(
+ new FramePainter(mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_RawInsertShadow)))
+{
+}
+
+InsertionIndicatorOverlay::~InsertionIndicatorOverlay()
+{
+ // cid#1491947 silence Uncaught exception
+ suppress_fun_call_w_exception(Hide());
+}
+
+void InsertionIndicatorOverlay::Create (const SdTransferable* pTransferable)
+{
+ if (pTransferable == nullptr)
+ return;
+
+ std::shared_ptr<controller::TransferableData> pData (
+ controller::TransferableData::GetFromTransferable(pTransferable));
+ if ( ! pData)
+ return;
+ sal_Int32 nSelectionCount (0);
+ if (pTransferable->HasPageBookmarks())
+ nSelectionCount = pTransferable->GetPageBookmarks().size();
+ else
+ {
+ DrawDocShell* pDataDocShell = dynamic_cast<DrawDocShell*>(pTransferable->GetDocShell().get());
+ if (pDataDocShell != nullptr)
+ {
+ SdDrawDocument* pDataDocument = pDataDocShell->GetDoc();
+ if (pDataDocument != nullptr)
+ nSelectionCount = pDataDocument->GetSdPageCount(PageKind::Standard);
+ }
+ }
+ Create(pData->GetRepresentatives(), nSelectionCount);
+}
+
+void InsertionIndicatorOverlay::Create (
+ const ::std::vector<controller::TransferableData::Representative>& rRepresentatives,
+ const sal_Int32 nSelectionCount)
+{
+ view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter());
+ const std::shared_ptr<view::PageObjectLayouter>& pPageObjectLayouter (
+ rLayouter.GetPageObjectLayouter());
+ std::shared_ptr<view::Theme> pTheme (mrSlideSorter.GetTheme());
+ const Size aOriginalPreviewSize (pPageObjectLayouter->GetPreviewSize());
+
+ const double nPreviewScale (0.5);
+ const Size aPreviewSize (
+ RoundToInt(aOriginalPreviewSize.Width()*nPreviewScale),
+ RoundToInt(aOriginalPreviewSize.Height()*nPreviewScale));
+ const sal_Int32 nOffset (
+ RoundToInt(std::min(aPreviewSize.Width(),aPreviewSize.Height()) * gnPreviewOffsetScale));
+
+ // Determine size and offset depending on the number of previews.
+ sal_Int32 nCount (rRepresentatives.size());
+ if (nCount > 0)
+ --nCount;
+ Size aIconSize(
+ aPreviewSize.Width() + 2 * gnShadowBorder + nCount*nOffset,
+ aPreviewSize.Height() + 2 * gnShadowBorder + nCount*nOffset);
+
+ // Create virtual devices for bitmap and mask whose bitmaps later be
+ // combined to form the BitmapEx of the icon.
+ ScopedVclPtrInstance<VirtualDevice> pContent(
+ *mrSlideSorter.GetContentWindow()->GetOutDev(), DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
+ pContent->SetOutputSizePixel(aIconSize);
+
+ pContent->SetFillColor();
+ pContent->SetLineColor(pTheme->GetColor(Theme::Color_PreviewBorder));
+ const Point aOffset = PaintRepresentatives(*pContent, aPreviewSize, nOffset, rRepresentatives);
+
+ PaintPageCount(*pContent, nSelectionCount, aPreviewSize, aOffset);
+
+ maIcon = pContent->GetBitmapEx(Point(0,0), aIconSize);
+ maIcon.Scale(aIconSize);
+}
+
+Point InsertionIndicatorOverlay::PaintRepresentatives (
+ OutputDevice& rContent,
+ const Size& rPreviewSize,
+ const sal_Int32 nOffset,
+ const ::std::vector<controller::TransferableData::Representative>& rRepresentatives) const
+{
+ const Point aOffset (0,rRepresentatives.size()==1 ? -nOffset : 0);
+
+ // Paint the pages.
+ Point aPageOffset (0,0);
+ double nTransparency (0);
+ const BitmapEx aExclusionOverlay (mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_HideSlideOverlay));
+ for (sal_Int32 nIndex=2; nIndex>=0; --nIndex)
+ {
+ if (rRepresentatives.size() <= o3tl::make_unsigned(nIndex))
+ continue;
+ switch(nIndex)
+ {
+ case 0 :
+ aPageOffset = Point(0, nOffset);
+ nTransparency = 0.85;
+ break;
+ case 1:
+ aPageOffset = Point(nOffset, 0);
+ nTransparency = 0.75;
+ break;
+ case 2:
+ aPageOffset = Point(2*nOffset, 2*nOffset);
+ nTransparency = 0.65;
+ break;
+ }
+ aPageOffset += aOffset;
+ aPageOffset.AdjustX(gnShadowBorder );
+ aPageOffset.AdjustY(gnShadowBorder );
+
+ // Paint the preview.
+ BitmapEx aPreview (rRepresentatives[nIndex].maBitmap);
+ aPreview.Scale(rPreviewSize, BmpScaleFlag::BestQuality);
+ rContent.DrawBitmapEx(aPageOffset, aPreview);
+
+ // When the page is marked as excluded from the slide show then
+ // paint an overlay that visualizes this.
+ if (rRepresentatives[nIndex].mbIsExcluded)
+ {
+ const vcl::Region aSavedClipRegion (rContent.GetClipRegion());
+ rContent.IntersectClipRegion(::tools::Rectangle(aPageOffset, rPreviewSize));
+ // Paint bitmap tiled over the preview to mark it as excluded.
+ const sal_Int32 nIconWidth (aExclusionOverlay.GetSizePixel().Width());
+ const sal_Int32 nIconHeight (aExclusionOverlay.GetSizePixel().Height());
+ if (nIconWidth>0 && nIconHeight>0)
+ {
+ for (::tools::Long nX=0; nX<rPreviewSize.Width(); nX+=nIconWidth)
+ for (::tools::Long nY=0; nY<rPreviewSize.Height(); nY+=nIconHeight)
+ rContent.DrawBitmapEx(Point(nX,nY)+aPageOffset, aExclusionOverlay);
+ }
+ rContent.SetClipRegion(aSavedClipRegion);
+ }
+
+ // Tone down the bitmap. The further back the darker it becomes.
+ ::tools::Rectangle aBox (
+ aPageOffset.X(),
+ aPageOffset.Y(),
+ aPageOffset.X()+rPreviewSize.Width()-1,
+ aPageOffset.Y()+rPreviewSize.Height()-1);
+ rContent.SetFillColor(COL_BLACK);
+ rContent.SetLineColor();
+ rContent.DrawTransparent(
+ basegfx::B2DHomMatrix(),
+ ::basegfx::B2DPolyPolygon(::basegfx::utils::createPolygonFromRect(
+ ::basegfx::B2DRectangle(aBox.Left(), aBox.Top(), aBox.Right()+1, aBox.Bottom()+1),
+ 0,
+ 0)),
+ nTransparency);
+
+ // Draw border around preview.
+ ::tools::Rectangle aBorderBox (GrowRectangle(aBox, 1));
+ rContent.SetLineColor(COL_GRAY);
+ rContent.SetFillColor();
+ rContent.DrawRect(aBorderBox);
+
+ // Draw shadow around preview.
+ mpShadowPainter->PaintFrame(rContent, aBorderBox);
+ }
+
+ return aPageOffset;
+}
+
+void InsertionIndicatorOverlay::PaintPageCount (
+ OutputDevice& rDevice,
+ const sal_Int32 nSelectionCount,
+ const Size& rPreviewSize,
+ const Point& rFirstPageOffset) const
+{
+ // Paint the number of slides.
+ std::shared_ptr<view::Theme> pTheme (mrSlideSorter.GetTheme());
+ std::shared_ptr<vcl::Font> pFont(Theme::GetFont(Theme::Font_PageCount, rDevice));
+ if (!pFont)
+ return;
+
+ OUString sNumber (OUString::number(nSelectionCount));
+
+ // Determine the size of the (painted) text and create a bounding
+ // box that centers the text on the first preview.
+ rDevice.SetFont(*pFont);
+ ::tools::Rectangle aTextBox;
+ rDevice.GetTextBoundRect(aTextBox, sNumber);
+ Point aTextOffset (aTextBox.TopLeft());
+ Size aTextSize (aTextBox.GetSize());
+ // Place text inside the first page preview.
+ Point aTextLocation(rFirstPageOffset);
+ // Center the text.
+ aTextLocation += Point(
+ (rPreviewSize.Width()-aTextBox.GetWidth())/2,
+ (rPreviewSize.Height()-aTextBox.GetHeight())/2);
+ aTextBox = ::tools::Rectangle(aTextLocation, aTextSize);
+
+ // Paint background, border and text.
+ static const sal_Int32 nBorder = 5;
+ rDevice.SetFillColor(pTheme->GetColor(Theme::Color_Selection));
+ rDevice.SetLineColor(pTheme->GetColor(Theme::Color_Selection));
+ rDevice.DrawRect(GrowRectangle(aTextBox, nBorder));
+
+ rDevice.SetFillColor();
+ rDevice.SetLineColor(pTheme->GetColor(Theme::Color_PageCountFontColor));
+ rDevice.DrawRect(GrowRectangle(aTextBox, nBorder-1));
+
+ rDevice.SetTextColor(pTheme->GetColor(Theme::Color_PageCountFontColor));
+ rDevice.DrawText(aTextBox.TopLeft()-aTextOffset, sNumber);
+}
+
+void InsertionIndicatorOverlay::SetLocation (const Point& rLocation)
+{
+ const Point aTopLeft (
+ rLocation - Point(
+ maIcon.GetSizePixel().Width()/2,
+ maIcon.GetSizePixel().Height()/2));
+ if (maLocation != aTopLeft)
+ {
+ const ::tools::Rectangle aOldBoundingBox (GetBoundingBox());
+
+ maLocation = aTopLeft;
+
+ if (mpLayerInvalidator && IsVisible())
+ {
+ mpLayerInvalidator->Invalidate(aOldBoundingBox);
+ mpLayerInvalidator->Invalidate(GetBoundingBox());
+ }
+ }
+}
+
+void InsertionIndicatorOverlay::Paint (
+ OutputDevice& rDevice,
+ const ::tools::Rectangle&)
+{
+ if ( ! IsVisible())
+ return;
+
+ rDevice.DrawImage(maLocation, Image(maIcon));
+}
+
+void InsertionIndicatorOverlay::SetLayerInvalidator (const SharedILayerInvalidator& rpInvalidator)
+{
+ mpLayerInvalidator = rpInvalidator;
+
+ if (mbIsVisible && mpLayerInvalidator)
+ mpLayerInvalidator->Invalidate(GetBoundingBox());
+}
+
+void InsertionIndicatorOverlay::Show()
+{
+ if ( mbIsVisible)
+ return;
+
+ mbIsVisible = true;
+
+ std::shared_ptr<LayeredDevice> pLayeredDevice (
+ mrSlideSorter.GetView().GetLayeredDevice());
+ if (pLayeredDevice)
+ {
+ pLayeredDevice->RegisterPainter(shared_from_this(), gnLayerIndex);
+ if (mpLayerInvalidator)
+ mpLayerInvalidator->Invalidate(GetBoundingBox());
+ }
+}
+
+void InsertionIndicatorOverlay::Hide()
+{
+ if (!mbIsVisible)
+ return;
+
+ mbIsVisible = false;
+
+ std::shared_ptr<LayeredDevice> pLayeredDevice (
+ mrSlideSorter.GetView().GetLayeredDevice());
+ if (pLayeredDevice)
+ {
+ if (mpLayerInvalidator)
+ mpLayerInvalidator->Invalidate(GetBoundingBox());
+ pLayeredDevice->RemovePainter(shared_from_this(), gnLayerIndex);
+ }
+}
+
+::tools::Rectangle InsertionIndicatorOverlay::GetBoundingBox() const
+{
+ return ::tools::Rectangle(maLocation, maIcon.GetSizePixel());
+}
+
+Size InsertionIndicatorOverlay::GetSize() const
+{
+ return Size(
+ maIcon.GetSizePixel().Width() + 10,
+ maIcon.GetSizePixel().Height() + 10);
+}
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx b/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx
new file mode 100644
index 000000000..b41bbe307
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx
@@ -0,0 +1,491 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlsLayeredDevice.hxx"
+#include <Window.hxx>
+
+#include <vcl/virdev.hxx>
+#include <sal/log.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+
+#include <tools/gen.hxx>
+#include <tools/fract.hxx>
+
+#include <functional>
+
+namespace sd::slidesorter::view {
+
+namespace {
+const sal_Int32 gnMaximumLayerCount = 8;
+
+class LayerInvalidator : public ILayerInvalidator
+{
+public:
+ LayerInvalidator (
+ const std::shared_ptr<LayeredDevice>& rpLayeredDevice,
+ sd::Window *pTargetWindow,
+ const int nLayer)
+ : mpLayeredDevice(rpLayeredDevice),
+ mpTargetWindow(pTargetWindow),
+ mnLayer(nLayer)
+ {
+ }
+
+ virtual void Invalidate (const ::tools::Rectangle& rInvalidationBox) override
+ {
+ mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer);
+ mpTargetWindow->Invalidate(rInvalidationBox);
+ }
+
+private:
+ const std::shared_ptr<LayeredDevice> mpLayeredDevice;
+ VclPtr<sd::Window> mpTargetWindow;
+ const int mnLayer;
+};
+
+void DeviceCopy (
+ vcl::RenderContext& rTargetDevice,
+ vcl::RenderContext const & rSourceDevice,
+ const ::tools::Rectangle& rBox)
+{
+ rTargetDevice.DrawOutDev(
+ rBox.TopLeft(),
+ rBox.GetSize(),
+ rBox.TopLeft(),
+ rBox.GetSize(),
+ rSourceDevice);
+}
+
+void ForAllRectangles (const vcl::Region& rRegion, const std::function<void (const ::tools::Rectangle&)>& aFunction)
+{
+ OSL_ASSERT(aFunction);
+ RectangleVector aRectangles;
+ rRegion.GetRegionRectangles(aRectangles);
+
+ if(aRectangles.empty())
+ {
+ aFunction(::tools::Rectangle());
+ }
+ else
+ {
+ for(const auto& rRect : aRectangles)
+ {
+ aFunction(rRect);
+ }
+
+ //Region aMutableRegionCopy (rRegion);
+ //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects());
+ //Rectangle aBox;
+ //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox))
+ // aFunction(aBox);
+ //aMutableRegionCopy.EndEnumRects(aHandle);
+ }
+}
+
+class Layer
+{
+public:
+ Layer();
+ Layer(const Layer&) = delete;
+ Layer& operator=(const Layer&) = delete;
+
+ void Initialize (sd::Window *pTargetWindow);
+ void InvalidateRectangle (const ::tools::Rectangle& rInvalidationBox);
+ void InvalidateRegion (const vcl::Region& rInvalidationRegion);
+ void Validate (const MapMode& rMapMode);
+ void Repaint (
+ OutputDevice& rTargetDevice,
+ const ::tools::Rectangle& rRepaintRectangle);
+ void Resize (const Size& rSize);
+ void AddPainter (const SharedILayerPainter& rpPainter);
+ void RemovePainter (const SharedILayerPainter& rpPainter);
+ bool HasPainter() const;
+ void Dispose();
+
+private:
+ ScopedVclPtr<VirtualDevice> mpLayerDevice;
+ ::std::vector<SharedILayerPainter> maPainters;
+ vcl::Region maInvalidationRegion;
+
+ void ValidateRectangle (const ::tools::Rectangle& rBox);
+};
+typedef std::shared_ptr<Layer> SharedLayer;
+
+} // end of anonymous namespace
+
+class LayeredDevice::LayerContainer
+{
+public:
+ LayerContainer() {}
+
+ bool empty() const { return mvLayers.empty(); }
+
+ size_t size() const { return mvLayers.size(); }
+
+ const SharedLayer& back() const { return mvLayers.back(); }
+
+ ::std::vector<SharedLayer>::const_iterator begin() const { return mvLayers.begin(); }
+ ::std::vector<SharedLayer>::const_iterator end() const { return mvLayers.end(); }
+
+ void clear() { mvLayers.clear(); }
+
+ void pop_back() { mvLayers.pop_back(); }
+
+ void resize(size_t n) { mvLayers.resize(n); }
+
+ SharedLayer& operator[](size_t i) { return mvLayers[i]; }
+
+private:
+ ::std::vector<SharedLayer> mvLayers;
+};
+
+//===== LayeredDevice =========================================================
+
+LayeredDevice::LayeredDevice (const VclPtr<sd::Window>& pTargetWindow)
+ : mpTargetWindow(pTargetWindow),
+ mpLayers(new LayerContainer()),
+ mpBackBuffer(VclPtr<VirtualDevice>::Create(*mpTargetWindow->GetOutDev())),
+ maSavedMapMode(pTargetWindow->GetMapMode())
+{
+ mpBackBuffer->SetOutputSizePixel(mpTargetWindow->GetSizePixel());
+}
+
+LayeredDevice::~LayeredDevice()
+{
+}
+
+void LayeredDevice::Invalidate (
+ const ::tools::Rectangle& rInvalidationArea,
+ const sal_Int32 nLayer)
+{
+ if (nLayer<0 || o3tl::make_unsigned(nLayer)>=mpLayers->size())
+ {
+ OSL_ASSERT(nLayer>=0 && o3tl::make_unsigned(nLayer)<mpLayers->size());
+ return;
+ }
+
+ (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea);
+}
+
+void LayeredDevice::InvalidateAllLayers (const ::tools::Rectangle& rInvalidationArea)
+{
+ for (size_t nLayer=0; nLayer<mpLayers->size(); ++nLayer)
+ (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea);
+}
+
+void LayeredDevice::InvalidateAllLayers (const vcl::Region& rInvalidationRegion)
+{
+ for (size_t nLayer=0; nLayer<mpLayers->size(); ++nLayer)
+ (*mpLayers)[nLayer]->InvalidateRegion(rInvalidationRegion);
+}
+
+void LayeredDevice::RegisterPainter (
+ const SharedILayerPainter& rpPainter,
+ const sal_Int32 nLayer)
+{
+ OSL_ASSERT(mpLayers);
+ if ( ! rpPainter)
+ {
+ OSL_ASSERT(rpPainter);
+ return;
+ }
+ if (nLayer<0 || nLayer>=gnMaximumLayerCount)
+ {
+ OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount);
+ return;
+ }
+
+ // Provide the layers.
+ if (o3tl::make_unsigned(nLayer) >= mpLayers->size())
+ {
+ const sal_Int32 nOldLayerCount (mpLayers->size());
+ mpLayers->resize(nLayer+1);
+
+ for (size_t nIndex=nOldLayerCount; nIndex<mpLayers->size(); ++nIndex)
+ (*mpLayers)[nIndex] = std::make_shared<Layer>();
+ }
+
+ (*mpLayers)[nLayer]->AddPainter(rpPainter);
+ if (nLayer == 0)
+ (*mpLayers)[nLayer]->Initialize(mpTargetWindow);
+
+ rpPainter->SetLayerInvalidator(
+ std::make_shared<LayerInvalidator>(shared_from_this(),mpTargetWindow,nLayer));
+}
+
+void LayeredDevice::RemovePainter (
+ const SharedILayerPainter& rpPainter,
+ const sal_Int32 nLayer)
+{
+ if ( ! rpPainter)
+ {
+ OSL_ASSERT(rpPainter);
+ return;
+ }
+ if (nLayer<0 || o3tl::make_unsigned(nLayer)>=mpLayers->size())
+ {
+ OSL_ASSERT(nLayer>=0 && o3tl::make_unsigned(nLayer)<mpLayers->size());
+ return;
+ }
+
+ rpPainter->SetLayerInvalidator(SharedILayerInvalidator());
+
+ (*mpLayers)[nLayer]->RemovePainter(rpPainter);
+
+ // Remove top most layers that do not contain any painters.
+ while ( ! mpLayers->empty() && ! mpLayers->back()->HasPainter())
+ mpLayers->pop_back();
+}
+
+void LayeredDevice::Repaint (const vcl::Region& rRepaintRegion)
+{
+ // Validate the contents of all layers (that have their own devices.)
+ for (auto const& it : *mpLayers)
+ {
+ it->Validate(mpTargetWindow->GetMapMode());
+ }
+
+ ForAllRectangles(rRepaintRegion,
+ [this] (::tools::Rectangle const& r) { this->RepaintRectangle(r); });
+}
+
+void LayeredDevice::RepaintRectangle (const ::tools::Rectangle& rRepaintRectangle)
+{
+ if (mpLayers->empty())
+ return;
+ else if (mpLayers->size() == 1)
+ {
+ // Just copy the main layer into the target device.
+ (*mpLayers)[0]->Repaint(*mpTargetWindow->GetOutDev(), rRepaintRectangle);
+ }
+ else
+ {
+ // Paint all layers first into the back buffer (to avoid flickering
+ // due to synchronous paints) and then copy that into the target
+ // device.
+ mpBackBuffer->SetMapMode(mpTargetWindow->GetMapMode());
+ for (auto const& it : *mpLayers)
+ {
+ it->Repaint(*mpBackBuffer, rRepaintRectangle);
+ }
+ DeviceCopy(*mpTargetWindow->GetOutDev(), *mpBackBuffer, rRepaintRectangle);
+ }
+}
+
+void LayeredDevice::Resize()
+{
+ const Size aSize (mpTargetWindow->GetSizePixel());
+ mpBackBuffer->SetOutputSizePixel(aSize);
+ for (auto const& it : *mpLayers)
+ {
+ it->Resize(aSize);
+ }
+}
+
+void LayeredDevice::Dispose()
+{
+ for (auto const& it : *mpLayers)
+ {
+ it->Dispose();
+ }
+ mpLayers->clear();
+}
+
+bool LayeredDevice::HandleMapModeChange()
+{
+ const MapMode& rMapMode (mpTargetWindow->GetMapMode());
+ if (maSavedMapMode == rMapMode)
+ return false;
+
+ const ::tools::Rectangle aLogicWindowBox (
+ mpTargetWindow->PixelToLogic(::tools::Rectangle(Point(0,0), mpTargetWindow->GetSizePixel())));
+ if (maSavedMapMode.GetScaleX() != rMapMode.GetScaleX()
+ || maSavedMapMode.GetScaleY() != rMapMode.GetScaleY()
+ || maSavedMapMode.GetMapUnit() != rMapMode.GetMapUnit())
+ {
+ // When the scale has changed then we have to paint everything.
+ InvalidateAllLayers(aLogicWindowBox);
+ }
+ else if (maSavedMapMode.GetOrigin() != rMapMode.GetOrigin())
+ {
+ // Window has been scrolled. Adapt contents of backbuffers and
+ // layer devices.
+ const Point aDelta (rMapMode.GetOrigin() - maSavedMapMode.GetOrigin());
+ mpBackBuffer->CopyArea(
+ aLogicWindowBox.TopLeft(),
+ mpTargetWindow->PixelToLogic(Point(0,0), maSavedMapMode),
+ aLogicWindowBox.GetSize());
+
+ // Invalidate the area(s) that have been exposed.
+ const ::tools::Rectangle aWindowBox (Point(0,0), mpTargetWindow->GetSizePixel());
+ if (aDelta.Y() < 0)
+ InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
+ aWindowBox.Left(),
+ aWindowBox.Bottom()+aDelta.Y(),
+ aWindowBox.Right(),
+ aWindowBox.Bottom())));
+ else if (aDelta.Y() > 0)
+ InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
+ aWindowBox.Left(),
+ aWindowBox.Top(),
+ aWindowBox.Right(),
+ aWindowBox.Top()+aDelta.Y())));
+ if (aDelta.X() < 0)
+ InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
+ aWindowBox.Right()+aDelta.X(),
+ aWindowBox.Top(),
+ aWindowBox.Right(),
+ aWindowBox.Bottom())));
+ else if (aDelta.X() > 0)
+ InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
+ aWindowBox.Left(),
+ aWindowBox.Top(),
+ aWindowBox.Left()+aDelta.X(),
+ aWindowBox.Bottom())));
+ }
+ else
+ {
+ // Can this happen? Lets trigger a warning when it does.
+ OSL_ASSERT(false);
+ }
+
+ maSavedMapMode = rMapMode;
+
+ return true;
+}
+
+//===== Layer =================================================================
+
+Layer::Layer()
+{
+}
+
+void Layer::Initialize (sd::Window *pTargetWindow)
+{
+#if 0
+ (void)pTargetWindow;
+#else
+ if ( ! mpLayerDevice)
+ {
+ mpLayerDevice.disposeAndReset(VclPtr<VirtualDevice>::Create(*pTargetWindow->GetOutDev()));
+ mpLayerDevice->SetOutputSizePixel(pTargetWindow->GetSizePixel());
+ }
+#endif
+}
+
+void Layer::InvalidateRectangle (const ::tools::Rectangle& rInvalidationBox)
+{
+ maInvalidationRegion.Union(rInvalidationBox);
+}
+
+void Layer::InvalidateRegion (const vcl::Region& rInvalidationRegion)
+{
+ maInvalidationRegion.Union(rInvalidationRegion);
+}
+
+void Layer::Validate (const MapMode& rMapMode)
+{
+ if (mpLayerDevice && ! maInvalidationRegion.IsEmpty())
+ {
+ vcl::Region aRegion (maInvalidationRegion);
+ maInvalidationRegion.SetEmpty();
+
+ mpLayerDevice->SetMapMode(rMapMode);
+ ForAllRectangles(
+ aRegion,
+ [this] (::tools::Rectangle const& r) { return this->ValidateRectangle(r); });
+ }
+}
+
+void Layer::ValidateRectangle (const ::tools::Rectangle& rBox)
+{
+ if ( ! mpLayerDevice)
+ return;
+ const vcl::Region aSavedClipRegion (mpLayerDevice->GetClipRegion());
+ mpLayerDevice->IntersectClipRegion(rBox);
+
+ for (const auto& rxPainter : maPainters)
+ {
+ rxPainter->Paint(*mpLayerDevice, rBox);
+ }
+
+ mpLayerDevice->SetClipRegion(aSavedClipRegion);
+}
+
+void Layer::Repaint (
+ OutputDevice& rTargetDevice,
+ const ::tools::Rectangle& rRepaintRectangle)
+{
+ if (mpLayerDevice)
+ {
+ DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle);
+ }
+ else
+ {
+ for (auto const& it : maPainters)
+ {
+ it->Paint(rTargetDevice, rRepaintRectangle);
+ }
+ }
+}
+
+void Layer::Resize (const Size& rSize)
+{
+ if (mpLayerDevice)
+ {
+ mpLayerDevice->SetOutputSizePixel(rSize);
+ maInvalidationRegion = ::tools::Rectangle(Point(0,0), rSize);
+ }
+}
+
+void Layer::AddPainter (const SharedILayerPainter& rpPainter)
+{
+ OSL_ASSERT(::std::find(maPainters.begin(), maPainters.end(), rpPainter) == maPainters.end());
+
+ maPainters.push_back(rpPainter);
+}
+
+void Layer::RemovePainter (const SharedILayerPainter& rpPainter)
+{
+ const ::std::vector<SharedILayerPainter>::iterator iPainter (
+ ::std::find(maPainters.begin(), maPainters.end(), rpPainter));
+ if (iPainter != maPainters.end())
+ {
+ maPainters.erase(iPainter);
+ }
+ else
+ {
+ SAL_WARN("sd", "LayeredDevice::RemovePainter called for painter that is not registered");
+ }
+}
+
+bool Layer::HasPainter() const
+{
+ return !maPainters.empty();
+}
+
+void Layer::Dispose()
+{
+ maPainters.clear();
+}
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsLayeredDevice.hxx b/sd/source/ui/slidesorter/view/SlsLayeredDevice.hxx
new file mode 100644
index 000000000..5ec0d0e9f
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsLayeredDevice.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <view/SlsILayerPainter.hxx>
+
+#include <vcl/vclptr.hxx>
+#include <vcl/mapmod.hxx>
+
+#include <memory>
+
+namespace sd { class Window; }
+namespace tools { class Rectangle; }
+namespace vcl { class Region; }
+
+class VirtualDevice;
+
+namespace sd::slidesorter::view {
+
+/** A simple wrapper around an OutputDevice that provides support for
+ independent layers and buffering.
+ Each layer may contain any number of painters.
+*/
+class LayeredDevice
+ : public std::enable_shared_from_this<LayeredDevice>
+
+{
+public:
+ explicit LayeredDevice (const VclPtr<sd::Window>& pTargetWindow);
+ ~LayeredDevice ();
+
+ void Invalidate (
+ const ::tools::Rectangle& rInvalidationBox,
+ const sal_Int32 nLayer);
+ void InvalidateAllLayers (
+ const ::tools::Rectangle& rInvalidationBox);
+ void InvalidateAllLayers (
+ const vcl::Region& rInvalidationRegion);
+
+ void RegisterPainter (
+ const SharedILayerPainter& rPainter,
+ const sal_Int32 nLayer);
+
+ void RemovePainter (
+ const SharedILayerPainter& rPainter,
+ const sal_Int32 nLayer);
+
+ bool HandleMapModeChange();
+ void Repaint (const vcl::Region& rRepaintRegion);
+
+ void Resize();
+
+ void Dispose();
+
+private:
+ VclPtr<sd::Window> mpTargetWindow;
+ class LayerContainer;
+ std::unique_ptr<LayerContainer> mpLayers;
+ ScopedVclPtr<VirtualDevice> mpBackBuffer;
+ MapMode maSavedMapMode;
+
+ void RepaintRectangle (const ::tools::Rectangle& rRepaintRectangle);
+};
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsLayouter.cxx b/sd/source/ui/slidesorter/view/SlsLayouter.cxx
new file mode 100644
index 000000000..21f0be13c
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsLayouter.cxx
@@ -0,0 +1,1225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <view/SlsPageObjectLayouter.hxx>
+#include <view/SlsTheme.hxx>
+#include <view/SlsLayouter.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <Window.hxx>
+#include <osl/diagnose.h>
+
+namespace sd::slidesorter::view {
+
+class Layouter::Implementation
+{
+public:
+ VclPtr<sd::Window> mpWindow;
+ static const sal_Int32 mnRequestedLeftBorder = 5;
+ static const sal_Int32 mnRequestedRightBorder = 5;
+ static const sal_Int32 mnRequestedTopBorder = 5;
+ static const sal_Int32 mnRequestedBottomBorder = 5;
+ sal_Int32 mnLeftBorder;
+ sal_Int32 mnRightBorder;
+ sal_Int32 mnTopBorder;
+ sal_Int32 mnBottomBorder;
+ static const sal_Int32 gnVerticalGap = 10 - 2*Theme_FocusIndicatorWidth;
+ static const sal_Int32 gnHorizontalGap = 10 - 2*Theme_FocusIndicatorWidth;
+ Size maMinimalSize;
+ Size maPreferredSize;
+ Size maMaximalSize;
+ sal_Int32 mnMinimalColumnCount;
+ sal_Int32 mnMaximalColumnCount;
+ sal_Int32 mnPageCount;
+ sal_Int32 mnColumnCount;
+ sal_Int32 mnRowCount;
+ /// The maximum number of columns. Can only be larger than the current
+ /// number of columns when there are not enough pages to fill all
+ /// available columns.
+ sal_Int32 mnMaxColumnCount;
+ /// The maximum number of rows. Can only be larger than the current
+ /// number of rows when there are not enough pages to fill all available
+ /// rows.
+ sal_Int32 mnMaxRowCount;
+ Size maPageObjectSize;
+ std::shared_ptr<PageObjectLayouter> mpPageObjectLayouter;
+ std::shared_ptr<view::Theme> mpTheme;
+
+ /** Specify how the gap between two page objects is associated with the
+ page objects.
+ */
+ enum GapMembership {
+ GM_NONE, // Gap is not associated with any page object.
+ GM_PREVIOUS, // The whole gap is associated with the previous page
+ // object (left or above the gap.)
+ GM_BOTH, // Half of the gap is associated with previous, half
+ // with the next page object.
+ GM_NEXT, // The whole gap is associated with the next page
+ // object (right or below the gap.)
+ GM_PAGE_BORDER
+ };
+
+ static Implementation* Create (
+ const Implementation& rImplementation,
+ const Layouter::Orientation eOrientation);
+
+ virtual Layouter::Orientation GetOrientation() const = 0;
+
+ bool Rearrange (
+ const Size& rWindowSize,
+ const Size& rPreviewModelSize,
+ const sal_uInt32 nPageCount);
+
+ /** Calculate the row that the point with the given vertical coordinate
+ is over. The horizontal component is ignored.
+ @param nYPosition
+ Vertical position in model coordinates.
+ @param bIncludeBordersAndGaps
+ When this flag is <TRUE/> then the area of borders and gaps are
+ interpreted as belonging to one of the rows.
+ @param eGapMembership
+ Specifies to what row the gap areas belong. Here GM_NONE
+ corresponds to bIncludeBordersAndGaps being <FALSE/>. When
+ GM_BOTH is given then the upper half is associated to the row
+ above and the lower half to the row below. Values of
+ GM_PREVIOUS and GM_NEXT associate the whole gap area with the
+ row above or below respectively.
+ */
+ sal_Int32 GetRowAtPosition (
+ sal_Int32 nYPosition,
+ bool bIncludeBordersAndGaps,
+ GapMembership eGapMembership) const;
+
+ /** Calculate the column that the point with the given horizontal
+ coordinate is over. The vertical component is ignored.
+ @param nXPosition
+ Horizontal position in model coordinates.
+ @param bIncludeBordersAndGaps
+ When this flag is <TRUE/> then the area of borders and gaps are
+ interpreted as belonging to one of the columns.
+ @param eGapMembership
+ Specifies to what column the gap areas belong.
+ */
+ sal_Int32 GetColumnAtPosition (
+ sal_Int32 nXPosition,
+ bool bIncludeBordersAndGaps,
+ GapMembership eGapMembership) const;
+
+ /** This method is typically called from GetRowAtPosition() and
+ GetColumnAtPosition() to handle a position that lies inside the gap
+ between two adjacent rows or columns.
+ @param nDistanceIntoGap
+ Vertical distance from the bottom of the upper row down into the
+ gap or horizontal distance from the right edge right into the
+ gap.
+ @param eGapMemberhship
+ This value decides what areas in the gap belong to which (or no)
+ row or column.
+ @param nIndex
+ The row index of the upper row or the column index of the left
+ column.
+ @param nGap
+ Width or height of the gap in model coordinates between the
+ page borders.
+ @return
+ Returns either the index of the upper row (as given as nRow), the
+ index of the lower row (nRow+1) or -1 to indicate that the
+ position belongs to no row.
+ */
+ static sal_Int32 ResolvePositionInGap (
+ sal_Int32 nDistanceIntoGap,
+ GapMembership eGapMembership,
+ sal_Int32 nIndex,
+ sal_Int32 nGap);
+
+ /** Calculate the logical part of the insert position, i.e. the page
+ after which to insert.
+ */
+ virtual void CalculateLogicalInsertPosition (
+ const Point& rModelPosition,
+ InsertPosition& rPosition) const = 0;
+
+ /** Calculate the geometrical part of the insert position, i.e. the
+ location of where to display the insertion indicator and the
+ distances about which the leading and trailing pages have to be
+ moved to make room for the indicator.
+ */
+ void CalculateGeometricPosition (
+ InsertPosition& rPosition,
+ const Size& rIndicatorSize,
+ const bool bIsVertical,
+ model::SlideSorterModel const & rModel) const;
+
+ /** Return the bounding box of the preview or, when selected, of the page
+ object. Thus, it returns something like a visual bounding box.
+ */
+ ::tools::Rectangle GetInnerBoundingBox (
+ model::SlideSorterModel const & rModel,
+ const sal_Int32 nIndex) const;
+
+ Range GetValidHorizontalSizeRange() const;
+ Range GetValidVerticalSizeRange() const;
+
+ Range GetRangeOfVisiblePageObjects (const ::tools::Rectangle& aVisibleArea) const;
+ sal_Int32 GetIndex (
+ const sal_Int32 nRow,
+ const sal_Int32 nColumn,
+ const bool bClampToValidRange) const;
+
+ ::tools::Rectangle GetPageObjectBox (
+ const sal_Int32 nIndex,
+ const bool bIncludeBorderAndGap = false) const;
+
+ ::tools::Rectangle GetPageObjectBox (
+ const sal_Int32 nRow,
+ const sal_Int32 nColumn) const;
+
+ ::tools::Rectangle AddBorderAndGap (
+ const ::tools::Rectangle& rBoundingBox,
+ const sal_Int32 nRow,
+ const sal_Int32 nColumn) const;
+
+ ::tools::Rectangle GetTotalBoundingBox() const;
+
+ virtual ~Implementation();
+
+protected:
+ Implementation (
+ sd::Window *pWindow,
+ const std::shared_ptr<view::Theme>& rpTheme);
+ explicit Implementation (const Implementation& rImplementation);
+
+ virtual void CalculateRowAndColumnCount (const Size& rWindowSize) = 0;
+ virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) = 0;
+ virtual Size CalculateTargetSize (
+ const Size& rWindowSize) const = 0;
+ Size GetTargetSize (
+ const Size& rWindowSize,
+ const bool bCalculateWidth,
+ const bool bCalculateHeight) const;
+ void CalculateVerticalLogicalInsertPosition (
+ const Point& rModelPosition,
+ InsertPosition& rPosition) const;
+};
+
+namespace {
+
+/** The vertical layouter has one column and as many rows as there are
+ pages.
+*/
+class VerticalImplementation : public Layouter::Implementation
+{
+public:
+ explicit VerticalImplementation (const Implementation& rImplementation);
+
+ virtual Layouter::Orientation GetOrientation() const override;
+
+ void CalculateLogicalInsertPosition (
+ const Point& rModelPosition,
+ InsertPosition& rPosition) const override;
+
+protected:
+ virtual void CalculateRowAndColumnCount (const Size& rWindowSize) override;
+ virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) override;
+ virtual Size CalculateTargetSize (
+ const Size& rWindowSize) const override;
+};
+
+/** The horizontal layouter has one row and as many columns as there are
+ pages.
+*/
+class HorizontalImplementation : public Layouter::Implementation
+{
+public:
+ explicit HorizontalImplementation(const Implementation& rImplementation);
+
+ virtual Layouter::Orientation GetOrientation() const override;
+
+ void CalculateLogicalInsertPosition (
+ const Point& rModelPosition,
+ InsertPosition& rPosition) const override;
+
+protected:
+ virtual void CalculateRowAndColumnCount (const Size& rWindowSize) override;
+ virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) override;
+ virtual Size CalculateTargetSize (
+ const Size& rWindowSize) const override;
+};
+
+/** The number of columns of the grid layouter is defined via a control in
+ the slide sorter tool bar. The number of rows is calculated from the
+ number of columns and the number of pages.
+*/
+class GridImplementation : public Layouter::Implementation
+{
+public:
+ GridImplementation (
+ sd::Window *pWindow,
+ const std::shared_ptr<view::Theme>& rpTheme);
+ explicit GridImplementation(const Implementation& rImplementation);
+
+ virtual Layouter::Orientation GetOrientation() const override;
+
+ void CalculateLogicalInsertPosition (
+ const Point& rModelPosition,
+ InsertPosition& rPosition) const override;
+
+protected:
+ virtual void CalculateRowAndColumnCount (const Size& rWindowSize) override;
+ virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) override;
+ virtual Size CalculateTargetSize (
+ const Size& rWindowSize) const override;
+};
+
+}
+
+//===== Layouter ==============================================================
+
+Layouter::Layouter (
+ sd::Window *pWindow,
+ const std::shared_ptr<Theme>& rpTheme)
+ : mpImplementation(new GridImplementation(pWindow, rpTheme)),
+ mpWindow(pWindow)
+{
+}
+
+Layouter::~Layouter()
+{
+}
+
+std::shared_ptr<PageObjectLayouter> const & Layouter::GetPageObjectLayouter() const
+{
+ return mpImplementation->mpPageObjectLayouter;
+}
+
+void Layouter::SetColumnCount (
+ sal_Int32 nMinimalColumnCount,
+ sal_Int32 nMaximalColumnCount)
+{
+ if (nMinimalColumnCount <= nMaximalColumnCount)
+ {
+ mpImplementation->mnMinimalColumnCount = nMinimalColumnCount;
+ mpImplementation->mnMaximalColumnCount = nMaximalColumnCount;
+ }
+}
+
+bool Layouter::Rearrange (
+ const Orientation eOrientation,
+ const Size& rWindowSize,
+ const Size& rPageSize,
+ const sal_uInt32 nPageCount)
+{
+ OSL_ASSERT(mpWindow);
+
+ if (eOrientation != mpImplementation->GetOrientation())
+ mpImplementation.reset(Implementation::Create(*mpImplementation, eOrientation));
+
+ return mpImplementation->Rearrange(rWindowSize, rPageSize, nPageCount);
+}
+
+sal_Int32 Layouter::GetColumnCount() const
+{
+ return mpImplementation->mnColumnCount;
+}
+
+sal_Int32 Layouter::GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const
+{
+ return mpImplementation->GetIndex(nRow,nColumn,true);
+}
+
+Size const & Layouter::GetPageObjectSize() const
+{
+ return mpImplementation->maPageObjectSize;
+}
+
+::tools::Rectangle Layouter::GetPageObjectBox (
+ const sal_Int32 nIndex,
+ const bool bIncludeBorderAndGap) const
+{
+ return mpImplementation->GetPageObjectBox(nIndex, bIncludeBorderAndGap);
+}
+
+::tools::Rectangle Layouter::GetTotalBoundingBox() const
+{
+ return mpImplementation->GetTotalBoundingBox();
+}
+
+InsertPosition Layouter::GetInsertPosition (
+ const Point& rModelPosition,
+ const Size& rIndicatorSize,
+ model::SlideSorterModel const & rModel) const
+{
+ InsertPosition aPosition;
+ mpImplementation->CalculateLogicalInsertPosition(
+ rModelPosition,
+ aPosition);
+ mpImplementation->CalculateGeometricPosition(
+ aPosition,
+ rIndicatorSize,
+ GetColumnCount()==1,
+ rModel);
+ return aPosition;
+}
+
+Range Layouter::GetValidHorizontalSizeRange() const
+{
+ return mpImplementation->GetValidHorizontalSizeRange();
+}
+
+Range Layouter::GetValidVerticalSizeRange() const
+{
+ return mpImplementation->GetValidVerticalSizeRange();
+}
+
+Range Layouter::GetRangeOfVisiblePageObjects (const ::tools::Rectangle& aVisibleArea) const
+{
+ return mpImplementation->GetRangeOfVisiblePageObjects(aVisibleArea);
+}
+
+sal_Int32 Layouter::GetIndexAtPoint (
+ const Point& rPosition,
+ const bool bIncludePageBorders,
+ const bool bClampToValidRange) const
+{
+ const sal_Int32 nRow (
+ mpImplementation->GetRowAtPosition (
+ rPosition.Y(),
+ bIncludePageBorders,
+ bIncludePageBorders ? Implementation::GM_PAGE_BORDER : Implementation::GM_NONE));
+ const sal_Int32 nColumn (
+ mpImplementation->GetColumnAtPosition (
+ rPosition.X(),
+ bIncludePageBorders,
+ bIncludePageBorders ? Implementation::GM_PAGE_BORDER : Implementation::GM_NONE));
+
+ return mpImplementation->GetIndex(nRow,nColumn,bClampToValidRange);
+}
+
+//===== Layouter::Implementation ==============================================
+
+Layouter::Implementation* Layouter::Implementation::Create (
+ const Implementation& rImplementation,
+ const Layouter::Orientation eOrientation)
+{
+ switch (eOrientation)
+ {
+ case HORIZONTAL: return new HorizontalImplementation(rImplementation);
+ case VERTICAL: return new VerticalImplementation(rImplementation);
+ case GRID:
+ default: return new GridImplementation(rImplementation);
+ }
+}
+
+Layouter::Implementation::Implementation (
+ sd::Window *pWindow,
+ const std::shared_ptr<view::Theme>& rpTheme)
+ : mpWindow(pWindow),
+ mnLeftBorder(5),
+ mnRightBorder(5),
+ mnTopBorder(5),
+ mnBottomBorder(5),
+ maMinimalSize(132,98),
+ maPreferredSize(200,150),
+ maMaximalSize(600,400),
+ mnMinimalColumnCount(1),
+ mnMaximalColumnCount(15),
+ mnPageCount(0),
+ mnColumnCount(1),
+ mnRowCount(0),
+ mnMaxColumnCount(0),
+ mnMaxRowCount(0),
+ maPageObjectSize(1,1),
+ mpTheme(rpTheme)
+{
+}
+
+Layouter::Implementation::Implementation (const Implementation& rImplementation)
+ : mpWindow(rImplementation.mpWindow),
+ mnLeftBorder(rImplementation.mnLeftBorder),
+ mnRightBorder(rImplementation.mnRightBorder),
+ mnTopBorder(rImplementation.mnTopBorder),
+ mnBottomBorder(rImplementation.mnBottomBorder),
+ maMinimalSize(rImplementation.maMinimalSize),
+ maPreferredSize(rImplementation.maPreferredSize),
+ maMaximalSize(rImplementation.maMaximalSize),
+ mnMinimalColumnCount(rImplementation.mnMinimalColumnCount),
+ mnMaximalColumnCount(rImplementation.mnMaximalColumnCount),
+ mnPageCount(rImplementation.mnPageCount),
+ mnColumnCount(rImplementation.mnColumnCount),
+ mnRowCount(rImplementation.mnRowCount),
+ mnMaxColumnCount(rImplementation.mnMaxColumnCount),
+ mnMaxRowCount(rImplementation.mnMaxRowCount),
+ maPageObjectSize(rImplementation.maPageObjectSize),
+ mpTheme(rImplementation.mpTheme)
+{
+}
+
+Layouter::Implementation::~Implementation()
+{
+}
+
+bool Layouter::Implementation::Rearrange (
+ const Size& rWindowSize,
+ const Size& rPreviewModelSize,
+ const sal_uInt32 nPageCount)
+{
+ mnPageCount = nPageCount;
+
+ // Return early when the window or the model have not yet been initialized.
+ if (rWindowSize.IsEmpty())
+ return false;
+ if (rPreviewModelSize.IsEmpty())
+ return false;
+
+ CalculateRowAndColumnCount(rWindowSize);
+
+ // Update the border values.
+ mnLeftBorder = mnRequestedLeftBorder;
+ mnTopBorder = mnRequestedTopBorder;
+ mnRightBorder = mnRequestedRightBorder;
+ mnBottomBorder = mnRequestedBottomBorder;
+ if (mnColumnCount > 1)
+ {
+ int nMinimumBorderWidth = gnHorizontalGap/2;
+ if (mnLeftBorder < nMinimumBorderWidth)
+ mnLeftBorder = nMinimumBorderWidth;
+ if (mnRightBorder < nMinimumBorderWidth)
+ mnRightBorder = nMinimumBorderWidth;
+ }
+ else
+ {
+ int nMinimumBorderHeight = gnVerticalGap/2;
+ if (mnTopBorder < nMinimumBorderHeight)
+ mnTopBorder = nMinimumBorderHeight;
+ if (mnBottomBorder < nMinimumBorderHeight)
+ mnBottomBorder = nMinimumBorderHeight;
+ }
+
+ mpPageObjectLayouter =
+ std::make_shared<PageObjectLayouter>(
+ CalculateTargetSize(rWindowSize),
+ rPreviewModelSize,
+ mpWindow,
+ mnPageCount);
+
+ maPageObjectSize = mpPageObjectLayouter->GetGridMaxSize();
+
+ CalculateMaxRowAndColumnCount(rWindowSize);
+
+ return true;
+}
+
+sal_Int32 Layouter::Implementation::GetRowAtPosition (
+ sal_Int32 nYPosition,
+ bool bIncludeBordersAndGaps,
+ GapMembership eGapMembership) const
+{
+ sal_Int32 nRow = -1;
+
+ const sal_Int32 nY = nYPosition - mnTopBorder;
+ if (nY >= 0)
+ {
+ // Vertical distance from one row to the next.
+ const sal_Int32 nRowOffset (maPageObjectSize.Height() + gnVerticalGap);
+
+ // Calculate row consisting of page objects and gap below.
+ nRow = nY / nRowOffset;
+
+ const sal_Int32 nDistanceIntoGap ((nY - nRow*nRowOffset) - maPageObjectSize.Height());
+ // When inside the gap below then nYPosition is not over a page
+ // object.
+ if (nDistanceIntoGap > 0)
+ {
+ sal_Int32 nResolvedRow = ResolvePositionInGap(
+ nDistanceIntoGap,
+ eGapMembership,
+ nRow,
+ gnVerticalGap);
+ if (!bIncludeBordersAndGaps || nResolvedRow != -1)
+ nRow = nResolvedRow;
+ }
+ }
+ else if (bIncludeBordersAndGaps)
+ {
+ // We are in the top border area. Set nRow to the first row when
+ // the top border shall be considered to belong to the first row.
+ nRow = 0;
+ }
+
+ return nRow;
+}
+
+sal_Int32 Layouter::Implementation::GetColumnAtPosition (
+ sal_Int32 nXPosition,
+ bool bIncludeBordersAndGaps,
+ GapMembership eGapMembership) const
+{
+ sal_Int32 nColumn = -1;
+
+ sal_Int32 nX = nXPosition - mnLeftBorder;
+ if (nX >= 0)
+ {
+ // Horizontal distance from one column to the next.
+ const sal_Int32 nColumnOffset (maPageObjectSize.Width() + gnHorizontalGap);
+
+ // Calculate row consisting of page objects and gap below.
+ nColumn = nX / nColumnOffset;
+ if (nColumn < 0)
+ nColumn = 0;
+ else if (nColumn >= mnColumnCount)
+ nColumn = mnColumnCount-1;
+
+ const sal_Int32 nDistanceIntoGap ((nX - nColumn*nColumnOffset) - maPageObjectSize.Width());
+ // When inside the gap at the right then nXPosition is not over a
+ // page object.
+ if (nDistanceIntoGap > 0)
+ {
+ sal_Int32 nResolvedColumn = ResolvePositionInGap(
+ nDistanceIntoGap,
+ eGapMembership,
+ nColumn,
+ gnHorizontalGap);
+ if (!bIncludeBordersAndGaps || nResolvedColumn != -1)
+ nColumn = nResolvedColumn;
+ }
+ }
+ else if (bIncludeBordersAndGaps)
+ {
+ // We are in the left border area. Set nColumn to the first column
+ // when the left border shall be considered to belong to the first
+ // column.
+ nColumn = 0;
+ }
+ return nColumn;
+}
+
+sal_Int32 Layouter::Implementation::ResolvePositionInGap (
+ sal_Int32 nDistanceIntoGap,
+ GapMembership eGapMembership,
+ sal_Int32 nIndex,
+ sal_Int32 nGap)
+{
+ switch (eGapMembership)
+ {
+ case GM_NONE:
+ // The gap is no man's land.
+ nIndex = -1;
+ break;
+
+ case GM_BOTH:
+ {
+ // The lower half of the gap belongs to the next row or column.
+ sal_Int32 nFirstHalfGapWidth = nGap / 2;
+ if (nDistanceIntoGap > nFirstHalfGapWidth)
+ nIndex ++;
+ break;
+ }
+
+ case GM_PREVIOUS:
+ // Row or column already at correct value.
+ break;
+
+ case GM_NEXT:
+ // The complete gap belongs to the next row or column.
+ nIndex ++;
+ break;
+
+ case GM_PAGE_BORDER:
+ if (nDistanceIntoGap > 0)
+ {
+ if (nDistanceIntoGap > nGap)
+ {
+ // Inside the border of the next row or column.
+ nIndex ++;
+ }
+ else
+ {
+ // Inside the gap between the page borders.
+ nIndex = -1;
+ }
+ }
+ break;
+
+ default:
+ nIndex = -1;
+ }
+
+ return nIndex;
+}
+
+void Layouter::Implementation::CalculateGeometricPosition (
+ InsertPosition& rPosition,
+ const Size& rIndicatorSize,
+ const bool bIsVertical,
+ model::SlideSorterModel const & rModel) const
+{
+ // 1. Determine right/bottom of the leading page and the left/top of the
+ // trailing page object and how to distribute the missing space.
+ sal_Int32 nLeadingLocation (0);
+ sal_Int32 nTrailingLocation (0);
+ bool bIsLeadingFixed (false);
+ bool bIsTrailingFixed (false);
+ sal_Int32 nSecondaryLocation (0);
+ const sal_Int32 nIndex (rPosition.GetIndex());
+
+ if (rPosition.IsAtRunStart())
+ {
+ // Place indicator at the top of the column.
+ const ::tools::Rectangle aOuterBox (GetPageObjectBox(nIndex));
+ const ::tools::Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex));
+ if (bIsVertical)
+ {
+ nLeadingLocation = aOuterBox.Top();
+ nTrailingLocation = aInnerBox.Top();
+ nSecondaryLocation = aInnerBox.Center().X();
+ }
+ else
+ {
+ nLeadingLocation = aOuterBox.Left();
+ nTrailingLocation = aInnerBox.Left();
+ nSecondaryLocation = aInnerBox.Center().Y();
+ }
+ bIsLeadingFixed = true;
+ }
+ else if (rPosition.IsAtRunEnd())
+ {
+ // Place indicator at the bottom/right of the column/row.
+
+ const ::tools::Rectangle aOuterBox (GetPageObjectBox(nIndex-1));
+ const ::tools::Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex-1));
+ if (bIsVertical)
+ {
+ nLeadingLocation = aInnerBox.Bottom();
+ nTrailingLocation = aOuterBox.Bottom();
+ nSecondaryLocation = aInnerBox.Center().X();
+ }
+ else
+ {
+ nLeadingLocation = aInnerBox.Right();
+ nTrailingLocation = aOuterBox.Right();
+ nSecondaryLocation = aInnerBox.Center().Y();
+ }
+ bIsTrailingFixed = true;
+ if ( ! rPosition.IsExtraSpaceNeeded())
+ bIsLeadingFixed = true;
+ }
+ else
+ {
+ // Place indicator between two rows/columns.
+ const ::tools::Rectangle aBox1 (GetInnerBoundingBox(rModel, nIndex-1));
+ const ::tools::Rectangle aBox2 (GetInnerBoundingBox(rModel, nIndex));
+ if (bIsVertical)
+ {
+ nLeadingLocation = aBox1.Bottom();
+ nTrailingLocation = aBox2.Top();
+ nSecondaryLocation = (aBox1.Center().X() + aBox2.Center().X()) / 2;
+ }
+ else
+ {
+ nLeadingLocation = aBox1.Right();
+ nTrailingLocation = aBox2.Left();
+ nSecondaryLocation = (aBox1.Center().Y() + aBox2.Center().Y()) / 2;
+ }
+ }
+
+ // 2. Calculate the location of the insert indicator and the offsets of
+ // leading and trailing pages.
+ const sal_Int32 nAvailableSpace (nTrailingLocation - nLeadingLocation);
+ const sal_Int32 nRequiredSpace (bIsVertical ? rIndicatorSize.Height():rIndicatorSize.Width());
+ const sal_Int32 nMissingSpace (::std::max(sal_Int32(0), nRequiredSpace - nAvailableSpace));
+ sal_Int32 nPrimaryLocation (0);
+ sal_Int32 nLeadingOffset (0);
+ sal_Int32 nTrailingOffset (0);
+ if (bIsLeadingFixed)
+ {
+ nPrimaryLocation = nLeadingLocation + nRequiredSpace/2;
+ if ( ! bIsTrailingFixed)
+ nTrailingOffset = nMissingSpace;
+ }
+ else if (bIsTrailingFixed)
+ {
+ nPrimaryLocation = nTrailingLocation - nRequiredSpace/2;
+ nLeadingOffset = -nMissingSpace;
+ }
+ else
+ {
+ nPrimaryLocation = (nLeadingLocation + nTrailingLocation) /2;
+ nLeadingOffset = -nMissingSpace/2;
+ nTrailingOffset = nMissingSpace + nLeadingOffset;
+ }
+
+ if (bIsVertical)
+ {
+ rPosition.SetGeometricalPosition(
+ Point(nSecondaryLocation, nPrimaryLocation),
+ Point(0, nLeadingOffset),
+ Point(0, nTrailingOffset));
+ }
+ else
+ {
+ rPosition.SetGeometricalPosition(
+ Point(nPrimaryLocation, nSecondaryLocation),
+ Point(nLeadingOffset, 0),
+ Point(nTrailingOffset, 0));
+ }
+}
+
+::tools::Rectangle Layouter::Implementation::GetInnerBoundingBox (
+ model::SlideSorterModel const & rModel,
+ const sal_Int32 nIndex) const
+{
+ model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
+ if ( ! pDescriptor)
+ return ::tools::Rectangle();
+
+ PageObjectLayouter::Part ePart = PageObjectLayouter::Part::Preview;
+
+ if (pDescriptor->HasState(model::PageDescriptor::ST_Selected))
+ ePart = PageObjectLayouter::Part::PageObject;
+
+ return mpPageObjectLayouter->GetBoundingBox(
+ pDescriptor, ePart,
+ PageObjectLayouter::ModelCoordinateSystem, true);
+}
+
+Range Layouter::Implementation::GetValidHorizontalSizeRange() const
+{
+ return Range(
+ mnLeftBorder + maMinimalSize.Width() + mnRightBorder,
+ mnLeftBorder + maMaximalSize.Width() + mnRightBorder);
+}
+
+Range Layouter::Implementation::GetValidVerticalSizeRange() const
+{
+ return Range(
+ mnTopBorder + maMinimalSize.Height() + mnBottomBorder,
+ mnTopBorder + maMaximalSize.Height() + mnBottomBorder);
+}
+
+Range Layouter::Implementation::GetRangeOfVisiblePageObjects (const ::tools::Rectangle& aVisibleArea) const
+{
+ // technically that's not empty, but it's the default, so...
+ if (aVisibleArea.IsEmpty())
+ return Range(-1, -1);
+
+ const sal_Int32 nRow0 (GetRowAtPosition(aVisibleArea.Top(), true, GM_NEXT));
+ const sal_Int32 nCol0 (GetColumnAtPosition(aVisibleArea.Left(),true, GM_NEXT));
+ const sal_Int32 nRow1 (GetRowAtPosition(aVisibleArea.Bottom(), true, GM_PREVIOUS));
+ const sal_Int32 nCol1 (GetColumnAtPosition(aVisibleArea.Right(), true, GM_PREVIOUS));
+
+ // When start and end lie in different rows then the range may include
+ // slides outside (left or right of) the given area.
+ return Range(GetIndex(nRow0,nCol0,true), GetIndex(nRow1,nCol1,true));
+}
+
+Size Layouter::Implementation::GetTargetSize (
+ const Size& rWindowSize,
+ const bool bCalculateWidth,
+ const bool bCalculateHeight) const
+{
+ if (mnColumnCount<=0 || mnRowCount<=0)
+ return maPreferredSize;
+ if ( ! (bCalculateWidth || bCalculateHeight))
+ {
+ OSL_ASSERT(bCalculateWidth || bCalculateHeight);
+ return maPreferredSize;
+ }
+
+ // Calculate the width of each page object.
+ Size aTargetSize (0,0);
+ if (bCalculateWidth)
+ aTargetSize.setWidth(
+ (rWindowSize.Width() - mnLeftBorder - mnRightBorder
+ - (mnColumnCount-1) * gnHorizontalGap)
+ / mnColumnCount);
+ else if (bCalculateHeight)
+ aTargetSize.setHeight(
+ (rWindowSize.Height() - mnTopBorder - mnBottomBorder
+ - (mnRowCount-1) * gnVerticalGap)
+ / mnRowCount);
+
+ if (bCalculateWidth)
+ {
+ if (aTargetSize.Width() < maMinimalSize.Width())
+ aTargetSize.setWidth(maMinimalSize.Width());
+ else if (aTargetSize.Width() > maMaximalSize.Width())
+ aTargetSize.setWidth(maMaximalSize.Width());
+ }
+ else if (bCalculateHeight)
+ {
+ if (aTargetSize.Height() < maMinimalSize.Height())
+ aTargetSize.setHeight(maMinimalSize.Height());
+ else if (aTargetSize.Height() > maMaximalSize.Height())
+ aTargetSize.setHeight(maMaximalSize.Height());
+ }
+
+ return aTargetSize;
+}
+
+sal_Int32 Layouter::Implementation::GetIndex (
+ const sal_Int32 nRow,
+ const sal_Int32 nColumn,
+ const bool bClampToValidRange) const
+{
+ if (nRow >= 0 && nColumn >= 0)
+ {
+ const sal_Int32 nIndex (nRow * mnColumnCount + nColumn);
+ if (nIndex >= mnPageCount)
+ if (bClampToValidRange)
+ return mnPageCount-1;
+ else
+ return -1;
+ else
+ return nIndex;
+ }
+ else if (bClampToValidRange)
+ return 0;
+ else
+ return -1;
+}
+
+::tools::Rectangle Layouter::Implementation::GetPageObjectBox (
+ const sal_Int32 nIndex,
+ const bool bIncludeBorderAndGap) const
+{
+ const sal_Int32 nRow (nIndex / mnColumnCount);
+ const sal_Int32 nColumn (nIndex % mnColumnCount);
+
+ const ::tools::Rectangle aBoundingBox (GetPageObjectBox(nRow,nColumn));
+ if (bIncludeBorderAndGap)
+ return AddBorderAndGap(aBoundingBox, nRow, nColumn);
+ else
+ return aBoundingBox;
+}
+
+::tools::Rectangle Layouter::Implementation::GetPageObjectBox (
+ const sal_Int32 nRow,
+ const sal_Int32 nColumn) const
+{
+ return ::tools::Rectangle(
+ Point (mnLeftBorder
+ + nColumn * maPageObjectSize.Width()
+ + std::max<sal_Int32>(nColumn,0) * gnHorizontalGap,
+ mnTopBorder
+ + nRow * maPageObjectSize.Height()
+ + std::max<sal_Int32>(nRow,0) * gnVerticalGap),
+ maPageObjectSize);
+}
+
+::tools::Rectangle Layouter::Implementation::AddBorderAndGap (
+ const ::tools::Rectangle& rBoundingBox,
+ const sal_Int32 nRow,
+ const sal_Int32 nColumn) const
+{
+ ::tools::Rectangle aBoundingBox (rBoundingBox);
+
+ if (nColumn == 0)
+ aBoundingBox.SetLeft( 0 );
+ else
+ aBoundingBox.AdjustLeft( -(gnHorizontalGap/2) );
+ if (nColumn == mnColumnCount-1)
+ aBoundingBox.AdjustRight(mnRightBorder );
+ else
+ aBoundingBox.AdjustRight(gnHorizontalGap/2 );
+ if (nRow == 0)
+ aBoundingBox.SetTop( 0 );
+ else
+ aBoundingBox.AdjustTop( -(gnVerticalGap/2) );
+ if (nRow == mnRowCount-1)
+ aBoundingBox.AdjustBottom(mnBottomBorder );
+ else
+ aBoundingBox.AdjustBottom(gnVerticalGap/2 );
+ return aBoundingBox;
+}
+
+::tools::Rectangle Layouter::Implementation::GetTotalBoundingBox() const
+{
+ sal_Int32 nHorizontalSize = 0;
+ sal_Int32 nVerticalSize = 0;
+ if (mnColumnCount > 0)
+ {
+ sal_Int32 nRowCount = (mnPageCount+mnColumnCount-1) / mnColumnCount;
+ nHorizontalSize =
+ mnLeftBorder
+ + mnRightBorder
+ + mnColumnCount * maPageObjectSize.Width();
+ if (mnColumnCount > 1)
+ nHorizontalSize += (mnColumnCount-1) * gnHorizontalGap;
+ nVerticalSize =
+ mnTopBorder
+ + mnBottomBorder
+ + nRowCount * maPageObjectSize.Height();
+ if (nRowCount > 1)
+ nVerticalSize += (nRowCount-1) * gnVerticalGap;
+ }
+
+ return ::tools::Rectangle (
+ Point(0,0),
+ Size (nHorizontalSize, nVerticalSize)
+ );
+}
+
+void Layouter::Implementation::CalculateVerticalLogicalInsertPosition (
+ const Point& rModelPosition,
+ InsertPosition& rPosition) const
+{
+ const sal_Int32 nY = rModelPosition.Y() - mnTopBorder + maPageObjectSize.Height()/2;
+ const sal_Int32 nRowHeight (maPageObjectSize.Height() + gnVerticalGap);
+ const sal_Int32 nRow (::std::min(mnPageCount, nY / nRowHeight));
+ rPosition.SetLogicalPosition (
+ nRow,
+ 0,
+ nRow,
+ (nRow == 0),
+ (nRow == mnRowCount),
+ (nRow >= mnMaxRowCount));
+}
+
+//===== HorizontalImplementation ================================================
+
+HorizontalImplementation::HorizontalImplementation (const Implementation& rImplementation)
+ : Implementation(rImplementation)
+{
+}
+
+Layouter::Orientation HorizontalImplementation::GetOrientation() const
+{
+ return Layouter::HORIZONTAL;
+}
+
+void HorizontalImplementation::CalculateRowAndColumnCount (const Size&)
+{
+ // Row and column count are fixed (for a given page count.)
+ mnColumnCount = mnPageCount;
+ mnRowCount = 1;
+}
+
+void HorizontalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize)
+{
+ mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder)
+ / (maPageObjectSize.Width() + gnHorizontalGap);
+ mnMaxRowCount = 1;
+}
+
+Size HorizontalImplementation::CalculateTargetSize (
+ const Size& rWindowSize) const
+{
+ return Implementation::GetTargetSize(rWindowSize, false, true);
+}
+
+void HorizontalImplementation::CalculateLogicalInsertPosition (
+ const Point& rModelPosition,
+ InsertPosition& rPosition) const
+{
+ const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2;
+ const sal_Int32 nColumnWidth (maPageObjectSize.Width() + gnHorizontalGap);
+ const sal_Int32 nColumn (::std::min(mnPageCount, nX / nColumnWidth));
+ rPosition.SetLogicalPosition (
+ 0,
+ nColumn,
+ nColumn,
+ (nColumn == 0),
+ (nColumn == mnColumnCount),
+ (nColumn >= mnMaxColumnCount));
+}
+
+//===== VerticalImplementation ================================================
+
+VerticalImplementation::VerticalImplementation (const Implementation& rImplementation)
+ : Implementation(rImplementation)
+{
+}
+
+Layouter::Orientation VerticalImplementation::GetOrientation() const
+{
+ return Layouter::VERTICAL;
+}
+
+void VerticalImplementation::CalculateRowAndColumnCount (const Size&)
+{
+ // Row and column count are fixed (for a given page count.)
+ mnRowCount = mnPageCount;
+ mnColumnCount = 1;
+
+}
+
+void VerticalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize)
+{
+ mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder)
+ / (maPageObjectSize.Height() + gnVerticalGap);
+ mnMaxColumnCount = 1;
+}
+
+Size VerticalImplementation::CalculateTargetSize (
+ const Size& rWindowSize) const
+{
+ return Implementation::GetTargetSize(rWindowSize, true, false);
+}
+
+void VerticalImplementation::CalculateLogicalInsertPosition (
+ const Point& rModelPosition,
+ InsertPosition& rPosition) const
+{
+ return CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition);
+}
+
+//===== GridImplementation ================================================
+
+GridImplementation::GridImplementation (
+ sd::Window *pWindow,
+ const std::shared_ptr<view::Theme>& rpTheme)
+ : Implementation(pWindow, rpTheme)
+{
+}
+
+GridImplementation::GridImplementation (const Implementation& rImplementation)
+ : Implementation(rImplementation)
+{
+}
+
+Layouter::Orientation GridImplementation::GetOrientation() const
+{
+ return Layouter::GRID;
+}
+
+void GridImplementation::CalculateRowAndColumnCount (const Size& rWindowSize)
+{
+ // Calculate the column count.
+ mnColumnCount
+ = (rWindowSize.Width() - mnRequestedLeftBorder - mnRequestedRightBorder)
+ / (maPreferredSize.Width() + gnHorizontalGap);
+ if (mnColumnCount < mnMinimalColumnCount)
+ mnColumnCount = mnMinimalColumnCount;
+ if (mnColumnCount > mnMaximalColumnCount)
+ mnColumnCount = mnMaximalColumnCount;
+ mnRowCount = (mnPageCount + mnColumnCount-1)/mnColumnCount;
+}
+
+void GridImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize)
+{
+ mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder)
+ / (maPageObjectSize.Width() + gnHorizontalGap);
+ mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder)
+ / (maPageObjectSize.Height() + gnVerticalGap);
+}
+
+Size GridImplementation::CalculateTargetSize (
+ const Size& rWindowSize) const
+{
+ return Implementation::GetTargetSize(rWindowSize, true, true);
+}
+
+void GridImplementation::CalculateLogicalInsertPosition (
+ const Point& rModelPosition,
+ InsertPosition& rPosition) const
+{
+ if (mnColumnCount == 1)
+ {
+ CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition);
+ }
+ else
+ {
+ // Handle the general case of more than one column.
+ sal_Int32 nRow (::std::min(
+ mnRowCount-1,
+ GetRowAtPosition (rModelPosition.Y(), true, GM_BOTH)));
+ const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2;
+ const sal_Int32 nColumnWidth (maPageObjectSize.Width() + gnHorizontalGap);
+ sal_Int32 nColumn (::std::min(mnColumnCount, nX / nColumnWidth));
+ sal_Int32 nIndex (nRow * mnColumnCount + nColumn);
+ bool bIsAtRunEnd (nColumn == mnColumnCount);
+
+ if (nIndex >= mnPageCount)
+ {
+ nIndex = mnPageCount;
+ nRow = mnRowCount-1;
+ nColumn = ::std::min(::std::min(mnPageCount, mnColumnCount), nColumn);
+ bIsAtRunEnd = true;
+ }
+
+ rPosition.SetLogicalPosition (
+ nRow,
+ nColumn,
+ nIndex,
+ (nColumn == 0),
+ bIsAtRunEnd,
+ (nColumn >= mnMaxColumnCount));
+ }
+}
+
+//===== InsertPosition ========================================================
+
+InsertPosition::InsertPosition()
+ : mnRow(-1),
+ mnColumn(-1),
+ mnIndex(-1),
+ mbIsAtRunStart(false),
+ mbIsAtRunEnd(false),
+ mbIsExtraSpaceNeeded(false),
+ maLocation(0,0),
+ maLeadingOffset(0,0),
+ maTrailingOffset(0,0)
+{
+}
+
+bool InsertPosition::operator== (const InsertPosition& rInsertPosition) const
+{
+ // Do not compare the geometrical information (maLocation).
+ return mnRow==rInsertPosition.mnRow
+ && mnColumn==rInsertPosition.mnColumn
+ && mnIndex==rInsertPosition.mnIndex
+ && mbIsAtRunStart==rInsertPosition.mbIsAtRunStart
+ && mbIsAtRunEnd==rInsertPosition.mbIsAtRunEnd
+ && mbIsExtraSpaceNeeded==rInsertPosition.mbIsExtraSpaceNeeded;
+}
+
+bool InsertPosition::operator!= (const InsertPosition& rInsertPosition) const
+{
+ return !operator==(rInsertPosition);
+}
+
+void InsertPosition::SetLogicalPosition (
+ const sal_Int32 nRow,
+ const sal_Int32 nColumn,
+ const sal_Int32 nIndex,
+ const bool bIsAtRunStart,
+ const bool bIsAtRunEnd,
+ const bool bIsExtraSpaceNeeded)
+{
+ mnRow = nRow;
+ mnColumn = nColumn;
+ mnIndex = nIndex;
+ mbIsAtRunStart = bIsAtRunStart;
+ mbIsAtRunEnd = bIsAtRunEnd;
+ mbIsExtraSpaceNeeded = bIsExtraSpaceNeeded;
+}
+
+void InsertPosition::SetGeometricalPosition(
+ const Point& rLocation,
+ const Point& rLeadingOffset,
+ const Point& rTrailingOffset)
+{
+ maLocation = rLocation;
+ maLeadingOffset = rLeadingOffset;
+ maTrailingOffset = rTrailingOffset;
+}
+
+} // end of namespace ::sd::slidesorter::namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectLayouter.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectLayouter.cxx
new file mode 100644
index 000000000..b26eb0746
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsPageObjectLayouter.cxx
@@ -0,0 +1,259 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <view/SlsPageObjectLayouter.hxx>
+
+#include <model/SlsPageDescriptor.hxx>
+#include <view/SlsTheme.hxx>
+#include <tools/IconCache.hxx>
+#include <Window.hxx>
+
+#include <bitmaps.hlst>
+#include <osl/diagnose.h>
+
+namespace sd::slidesorter::view {
+
+namespace {
+const sal_Int32 gnLeftPageNumberOffset = 2;
+const sal_Int32 gnRightPageNumberOffset = 5;
+const sal_Int32 gnOuterBorderWidth = 5;
+const sal_Int32 gnInfoAreaMinWidth = 26;
+}
+
+PageObjectLayouter::PageObjectLayouter (
+ const Size& rPageObjectWindowSize,
+ const Size& rPageSize,
+ sd::Window *pWindow,
+ const sal_Int32 nPageCount)
+ : mpWindow(pWindow),
+ maTransitionEffectIcon(IconCache::Instance().GetIcon(BMP_FADE_EFFECT_INDICATOR)),
+ maCustomAnimationEffectIcon(IconCache::Instance().GetIcon(BMP_CUSTOM_ANIMATION_INDICATOR)),
+ mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *pWindow->GetOutDev()))
+{
+ const Size aPageNumberAreaSize (GetPageNumberAreaSize(nPageCount));
+
+ const int nMaximumBorderWidth (gnOuterBorderWidth);
+ const int nFocusIndicatorWidth (Theme_FocusIndicatorWidth);
+
+ Size aPageObjectSize(rPageObjectWindowSize.Width(), rPageObjectWindowSize.Height());
+ maPreviewBoundingBox = CalculatePreviewBoundingBox(
+ aPageObjectSize,
+ Size(rPageSize.Width(), rPageSize.Height()),
+ aPageNumberAreaSize.Width(),
+ nFocusIndicatorWidth);
+ maFocusIndicatorBoundingBox = ::tools::Rectangle(Point(0,0), aPageObjectSize);
+ maPageObjectBoundingBox = ::tools::Rectangle(
+ Point(
+ nFocusIndicatorWidth,
+ nFocusIndicatorWidth),
+ Size(
+ aPageObjectSize.Width()-2*nFocusIndicatorWidth,
+ aPageObjectSize.Height()-2*nFocusIndicatorWidth));
+
+ maPageNumberAreaBoundingBox = ::tools::Rectangle(
+ Point(
+ std::max(gnLeftPageNumberOffset,
+ sal_Int32(maPreviewBoundingBox.Left()
+ - gnRightPageNumberOffset
+ - aPageNumberAreaSize.Width())),
+ nMaximumBorderWidth),
+ aPageNumberAreaSize);
+
+ const Size aIconSize (maTransitionEffectIcon.GetSizePixel());
+ maTransitionEffectBoundingBox = ::tools::Rectangle(
+ Point(
+ (maPreviewBoundingBox.Left() - 2*aIconSize.Width()) / 2,
+ maPreviewBoundingBox.Bottom() - aIconSize.Height()),
+ aIconSize);
+ maCustomAnimationEffectBoundingBox = ::tools::Rectangle(
+ Point(
+ (maPreviewBoundingBox.Left() - 2*aIconSize.Width()) / 2,
+ maPreviewBoundingBox.Bottom() - 2*aIconSize.Height()),
+ aIconSize);
+}
+
+PageObjectLayouter::~PageObjectLayouter()
+{
+}
+
+::tools::Rectangle PageObjectLayouter::CalculatePreviewBoundingBox (
+ Size& rPageObjectSize,
+ const Size& rPageSize,
+ const sal_Int32 nPageNumberAreaWidth,
+ const sal_Int32 nFocusIndicatorWidth)
+{
+ const sal_Int32 nIconWidth (maTransitionEffectIcon.GetSizePixel().Width());
+ const sal_Int32 nLeftAreaWidth (
+ ::std::max(
+ gnInfoAreaMinWidth,
+ gnRightPageNumberOffset
+ + ::std::max(
+ nPageNumberAreaWidth,
+ nIconWidth)));
+ sal_Int32 nPreviewWidth;
+ sal_Int32 nPreviewHeight;
+ const double nPageAspectRatio (double(rPageSize.Width()) / double(rPageSize.Height()));
+ if (rPageObjectSize.Height() == 0)
+ {
+ // Calculate height so that the preview fills the available
+ // horizontal space completely while observing the aspect ratio of
+ // the preview.
+ nPreviewWidth = rPageObjectSize.Width()
+ - nLeftAreaWidth - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
+ nPreviewHeight = ::basegfx::fround(nPreviewWidth / nPageAspectRatio);
+ rPageObjectSize.setHeight(nPreviewHeight + 2*gnOuterBorderWidth + 2*nFocusIndicatorWidth + 1);
+ }
+ else if (rPageObjectSize.Width() == 0)
+ {
+ // Calculate the width of the page object so that the preview fills
+ // the available vertical space completely while observing the
+ // aspect ratio of the preview.
+ nPreviewHeight = rPageObjectSize.Height() - 2*gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
+ nPreviewWidth = ::basegfx::fround(nPreviewHeight * nPageAspectRatio);
+ rPageObjectSize.setWidth(nPreviewWidth
+ + nLeftAreaWidth + gnOuterBorderWidth + 2*nFocusIndicatorWidth + 1);
+
+ }
+ else
+ {
+ // The size of the page object is given. Calculate the size of the
+ // preview.
+ nPreviewWidth = rPageObjectSize.Width()
+ - nLeftAreaWidth - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
+ nPreviewHeight = rPageObjectSize.Height()
+ - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
+ if (double(nPreviewWidth)/double(nPreviewHeight) > nPageAspectRatio)
+ nPreviewWidth = ::basegfx::fround(nPreviewHeight * nPageAspectRatio);
+ else
+ nPreviewHeight = ::basegfx::fround(nPreviewWidth / nPageAspectRatio);
+ }
+ // When the preview does not fill the available space completely then
+ // place it flush right and vertically centered.
+ const int nLeft (rPageObjectSize.Width()
+ - gnOuterBorderWidth - nPreviewWidth - nFocusIndicatorWidth - 1);
+ const int nTop ((rPageObjectSize.Height() - nPreviewHeight)/2);
+ return ::tools::Rectangle(
+ nLeft,
+ nTop,
+ nLeft + nPreviewWidth,
+ nTop + nPreviewHeight);
+}
+
+::tools::Rectangle PageObjectLayouter::GetBoundingBox (
+ const model::SharedPageDescriptor& rpPageDescriptor,
+ const Part ePart,
+ const CoordinateSystem eCoordinateSystem,
+ bool bIgnoreLocation)
+{
+ OSL_ASSERT(rpPageDescriptor);
+ Point aLocation(0,0);
+ if (rpPageDescriptor)
+ aLocation = rpPageDescriptor->GetLocation( bIgnoreLocation );
+ return GetBoundingBox(aLocation, ePart, eCoordinateSystem);
+}
+
+::tools::Rectangle PageObjectLayouter::GetBoundingBox (
+ const Point& rPageObjectLocation,
+ const Part ePart,
+ const CoordinateSystem eCoordinateSystem)
+{
+ ::tools::Rectangle aBoundingBox;
+ switch (ePart)
+ {
+ case Part::FocusIndicator:
+ aBoundingBox = maFocusIndicatorBoundingBox;
+ break;
+
+ case Part::PageObject:
+ aBoundingBox = maPageObjectBoundingBox;
+ break;
+
+ case Part::Preview:
+ aBoundingBox = maPreviewBoundingBox;
+ break;
+
+ case Part::PageNumber:
+ aBoundingBox = maPageNumberAreaBoundingBox;
+ break;
+
+ case Part::TransitionEffectIndicator:
+ aBoundingBox = maTransitionEffectBoundingBox;
+ break;
+ case Part::CustomAnimationEffectIndicator:
+ aBoundingBox = maCustomAnimationEffectBoundingBox;
+ break;
+ }
+
+ // Adapt coordinates to the requested coordinate system.
+ Point aLocation (rPageObjectLocation);
+ if (eCoordinateSystem == WindowCoordinateSystem)
+ aLocation += mpWindow->GetMapMode().GetOrigin();
+
+ return ::tools::Rectangle(
+ aBoundingBox.TopLeft() + aLocation,
+ aBoundingBox.BottomRight() + aLocation);
+}
+
+Size PageObjectLayouter::GetPreviewSize ()
+{
+ return GetBoundingBox(Point(0,0), PageObjectLayouter::Part::Preview,
+ WindowCoordinateSystem).GetSize();
+}
+
+Size PageObjectLayouter::GetGridMaxSize()
+{
+ return GetBoundingBox(Point(0,0), PageObjectLayouter::Part::FocusIndicator,
+ WindowCoordinateSystem).GetSize();
+}
+
+Size PageObjectLayouter::GetPageNumberAreaSize (const int nPageCount)
+{
+ OSL_ASSERT(mpWindow);
+
+ // Set the correct font.
+ vcl::Font aOriginalFont (mpWindow->GetFont());
+ if (mpPageNumberFont)
+ mpWindow->SetFont(*mpPageNumberFont);
+
+ OUString sPageNumberTemplate;
+ if (nPageCount < 10)
+ sPageNumberTemplate = "9";
+ else if (nPageCount < 100)
+ sPageNumberTemplate = "99";
+ else if (nPageCount < 200)
+ // Just for the case that 1 is narrower than 9.
+ sPageNumberTemplate = "199";
+ else if (nPageCount < 1000)
+ sPageNumberTemplate = "999";
+ else
+ sPageNumberTemplate = "9999";
+ // More than 9999 pages are not handled.
+
+ const Size aSize (
+ mpWindow->GetTextWidth(sPageNumberTemplate),
+ mpWindow->GetTextHeight());
+
+ mpWindow->SetFont(aOriginalFont);
+
+ return aSize;
+}
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx
new file mode 100644
index 000000000..feaf5a5fa
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx
@@ -0,0 +1,442 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <view/SlsPageObjectPainter.hxx>
+
+#include <model/SlsPageDescriptor.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsPageObjectLayouter.hxx>
+#include <view/SlsLayouter.hxx>
+#include <view/SlsTheme.hxx>
+#include <SlideSorter.hxx>
+#include "SlsFramePainter.hxx"
+#include <cache/SlsPageCache.hxx>
+#include <Window.hxx>
+#include <sdpage.hxx>
+#include <vcl/virdev.hxx>
+#include <CustomAnimationEffect.hxx>
+#include <osl/diagnose.h>
+#include <memory>
+
+using namespace ::drawinglayer::primitive2d;
+
+namespace sd::slidesorter::view {
+
+//===== PageObjectPainter =====================================================
+
+PageObjectPainter::PageObjectPainter (
+ const SlideSorter& rSlideSorter)
+ : mrLayouter(rSlideSorter.GetView().GetLayouter()),
+ mpCache(rSlideSorter.GetView().GetPreviewCache()),
+ mpTheme(rSlideSorter.GetTheme()),
+ mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rSlideSorter.GetContentWindow()->GetOutDev())),
+ mpShadowPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_RawShadow))),
+ mpFocusBorderPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_FocusBorder)))
+{
+ // Replace the color (not the alpha values) in the focus border with a
+ // color derived from the current selection color.
+ Color aColor (mpTheme->GetColor(Theme::Color_Selection));
+ sal_uInt16 nHue, nSat, nBri;
+ aColor.RGBtoHSB(nHue, nSat, nBri);
+ aColor = Color::HSBtoRGB(nHue, 28, 65);
+ mpFocusBorderPainter->AdaptColor(aColor);
+}
+
+PageObjectPainter::~PageObjectPainter()
+{
+}
+
+void PageObjectPainter::PaintPageObject (
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor)
+{
+ if (!UpdatePageObjectLayouter())
+ return;
+
+ PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
+ // Turn off antialiasing to avoid the bitmaps from being
+ // shifted by fractions of a pixel and thus show blurry edges.
+ const AntialiasingFlags nSavedAntialiasingMode (rDevice.GetAntialiasing());
+ rDevice.SetAntialiasing(nSavedAntialiasingMode & ~AntialiasingFlags::Enable);
+
+ PaintBackground(pPageObjectLayouter, rDevice, rpDescriptor);
+ PaintPreview(pPageObjectLayouter, rDevice, rpDescriptor);
+ PaintPageNumber(pPageObjectLayouter, rDevice, rpDescriptor);
+ PaintTransitionEffect(pPageObjectLayouter, rDevice, rpDescriptor);
+ if (rpDescriptor->GetPage()->hasAnimationNode())
+ PaintCustomAnimationEffect(pPageObjectLayouter, rDevice, rpDescriptor);
+ rDevice.SetAntialiasing(nSavedAntialiasingMode);
+}
+
+bool PageObjectPainter::UpdatePageObjectLayouter()
+{
+ // The page object layouter is quite volatile. It may have been replaced
+ // since the last call. Update it now.
+ PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
+ if ( ! pPageObjectLayouter)
+ {
+ OSL_FAIL("no page object layouter");
+ return false;
+ }
+
+ return true;
+}
+
+void PageObjectPainter::SetTheme (const std::shared_ptr<view::Theme>& rpTheme)
+{
+ mpTheme = rpTheme;
+}
+
+void PageObjectPainter::PaintBackground (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor) const
+{
+ PaintBackgroundDetail(pPageObjectLayouter, rDevice, rpDescriptor);
+
+ // Fill the interior of the preview area with the default background
+ // color of the page.
+ SdPage* pPage = rpDescriptor->GetPage();
+ if (pPage != nullptr)
+ {
+ rDevice.SetFillColor(pPage->GetPageBackgroundColor(nullptr));
+ rDevice.SetLineColor(pPage->GetPageBackgroundColor(nullptr));
+ const ::tools::Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
+ rpDescriptor,
+ PageObjectLayouter::Part::Preview,
+ PageObjectLayouter::ModelCoordinateSystem));
+ rDevice.DrawRect(aPreviewBox);
+ }
+}
+
+void PageObjectPainter::PaintPreview (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor) const
+{
+ const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
+ rpDescriptor,
+ PageObjectLayouter::Part::Preview,
+ PageObjectLayouter::ModelCoordinateSystem));
+
+ if (mpCache == nullptr)
+ return;
+
+ const SdrPage* pPage = rpDescriptor->GetPage();
+ mpCache->SetPreciousFlag(pPage, true);
+
+ const BitmapEx aPreview (GetPreviewBitmap(rpDescriptor, &rDevice));
+ if ( ! aPreview.IsEmpty())
+ {
+ if (aPreview.GetSizePixel() != aBox.GetSize())
+ rDevice.DrawBitmapEx(aBox.TopLeft(), aBox.GetSize(), aPreview);
+ else
+ rDevice.DrawBitmapEx(aBox.TopLeft(), aPreview);
+ }
+}
+
+BitmapEx PageObjectPainter::CreateMarkedPreview (
+ const Size& rSize,
+ const BitmapEx& rPreview,
+ const BitmapEx& rOverlay,
+ const OutputDevice* pReferenceDevice)
+{
+ ScopedVclPtr<VirtualDevice> pDevice;
+ if (pReferenceDevice != nullptr)
+ pDevice.disposeAndReset(VclPtr<VirtualDevice>::Create(*pReferenceDevice));
+ else
+ pDevice.disposeAndReset(VclPtr<VirtualDevice>::Create());
+ pDevice->SetOutputSizePixel(rSize);
+
+ pDevice->DrawBitmapEx(Point(0,0), rSize, rPreview);
+
+ // Paint bitmap tiled over the preview to mark it as excluded.
+ const sal_Int32 nIconWidth (rOverlay.GetSizePixel().Width());
+ const sal_Int32 nIconHeight (rOverlay.GetSizePixel().Height());
+ if (nIconWidth>0 && nIconHeight>0)
+ {
+ for (::tools::Long nX=0; nX<rSize.Width(); nX+=nIconWidth)
+ for (::tools::Long nY=0; nY<rSize.Height(); nY+=nIconHeight)
+ pDevice->DrawBitmapEx(Point(nX,nY), rOverlay);
+ }
+ return pDevice->GetBitmapEx(Point(0,0), rSize);
+}
+
+BitmapEx PageObjectPainter::GetPreviewBitmap (
+ const model::SharedPageDescriptor& rpDescriptor,
+ const OutputDevice* pReferenceDevice) const
+{
+ const SdrPage* pPage = rpDescriptor->GetPage();
+ const bool bIsExcluded (rpDescriptor->HasState(model::PageDescriptor::ST_Excluded));
+
+ if (bIsExcluded)
+ {
+ PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
+
+ BitmapEx aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage));
+ const ::tools::Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
+ rpDescriptor,
+ PageObjectLayouter::Part::Preview,
+ PageObjectLayouter::ModelCoordinateSystem));
+ if (aMarkedPreview.IsEmpty() || aMarkedPreview.GetSizePixel()!=aPreviewBox.GetSize())
+ {
+ aMarkedPreview = CreateMarkedPreview(
+ aPreviewBox.GetSize(),
+ mpCache->GetPreviewBitmap(pPage,true),
+ mpTheme->GetIcon(Theme::Icon_HideSlideOverlay),
+ pReferenceDevice);
+ mpCache->SetMarkedPreviewBitmap(pPage, aMarkedPreview);
+ }
+ return aMarkedPreview;
+ }
+ else
+ {
+ return mpCache->GetPreviewBitmap(pPage,false);
+ }
+}
+
+void PageObjectPainter::PaintPageNumber (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor) const
+{
+ const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
+ rpDescriptor,
+ PageObjectLayouter::Part::PageNumber,
+ PageObjectLayouter::ModelCoordinateSystem));
+
+ // Determine the color of the page number.
+ Color aPageNumberColor (mpTheme->GetColor(Theme::Color_PageNumberDefault));
+ if (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ||
+ rpDescriptor->HasState(model::PageDescriptor::ST_Selected))
+ {
+ // Page number is painted on background for hover or selection or
+ // both. Each of these background colors has a predefined luminance
+ // which is compatible with the PageNumberHover color.
+ aPageNumberColor = mpTheme->GetColor(Theme::Color_PageNumberHover);
+ }
+ else
+ {
+ const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
+ const sal_Int32 nBackgroundLuminance (aBackgroundColor.GetLuminance());
+ // When the background color is black then this is interpreted as
+ // high contrast mode and the font color is set to white.
+ if (nBackgroundLuminance == 0)
+ aPageNumberColor = mpTheme->GetColor(Theme::Color_PageNumberHighContrast);
+ else
+ {
+ // Compare luminance of default page number color and background
+ // color. When the two are similar then use a darker
+ // (preferred) or brighter font color.
+ const sal_Int32 nFontLuminance (aPageNumberColor.GetLuminance());
+ if (abs(nBackgroundLuminance - nFontLuminance) < 60)
+ {
+ if (nBackgroundLuminance > nFontLuminance-30)
+ aPageNumberColor = mpTheme->GetColor(Theme::Color_PageNumberBrightBackground);
+ else
+ aPageNumberColor = mpTheme->GetColor(Theme::Color_PageNumberDarkBackground);
+ }
+ }
+ }
+
+ // Paint the page number.
+ OSL_ASSERT(rpDescriptor->GetPage()!=nullptr);
+ const sal_Int32 nPageNumber ((rpDescriptor->GetPage()->GetPageNum() - 1) / 2 + 1);
+ const OUString sPageNumber(OUString::number(nPageNumber));
+ rDevice.SetFont(*mpPageNumberFont);
+ rDevice.SetTextColor(aPageNumberColor);
+ rDevice.DrawText(aBox, sPageNumber, DrawTextFlags::Right | DrawTextFlags::VCenter);
+}
+
+void PageObjectPainter::PaintTransitionEffect (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor)
+{
+ const SdPage* pPage = rpDescriptor->GetPage();
+ if (pPage!=nullptr && pPage->getTransitionType() > 0)
+ {
+ const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
+ rpDescriptor,
+ PageObjectLayouter::Part::TransitionEffectIndicator,
+ PageObjectLayouter::ModelCoordinateSystem));
+
+ rDevice.DrawBitmapEx(
+ aBox.TopCenter(),
+ pPageObjectLayouter->GetTransitionEffectIcon().GetBitmapEx());
+ }
+}
+
+void PageObjectPainter::PaintCustomAnimationEffect (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor)
+{
+ SdPage* pPage = rpDescriptor->GetPage();
+ std::shared_ptr< MainSequence > aMainSequence = pPage->getMainSequence();
+ EffectSequence::iterator aIter = aMainSequence->getBegin();
+ EffectSequence::iterator aEnd = aMainSequence->getEnd();
+ if ( aIter != aEnd )
+ {
+ const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
+ rpDescriptor,
+ PageObjectLayouter::Part::CustomAnimationEffectIndicator,
+ PageObjectLayouter::ModelCoordinateSystem));
+ rDevice.DrawBitmapEx(
+ aBox.TopCenter(),
+ pPageObjectLayouter->GetCustomAnimationEffectIcon().GetBitmapEx());
+ }
+}
+
+void PageObjectPainter::PaintBackgroundDetail (
+ PageObjectLayouter *pPageObjectLayouter,
+ OutputDevice& rDevice,
+ const model::SharedPageDescriptor& rpDescriptor) const
+{
+ enum State { None = 0x00, Selected = 0x01, MouseOver = 0x02, Focused = 0x04 };
+ const int eState =
+ (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) ? Selected : None)
+ | (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ? MouseOver : None)
+ | (rpDescriptor->HasState(model::PageDescriptor::ST_Focused) ? Focused : None);
+
+ bool bHasFocusBorder;
+ Theme::GradientColorType eColorType;
+
+ switch (eState)
+ {
+ case MouseOver | Selected | Focused:
+ eColorType = Theme::Gradient_MouseOverSelectedAndFocusedPage;
+ bHasFocusBorder = true;
+ break;
+
+ case MouseOver | Selected:
+ eColorType = Theme::Gradient_MouseOverSelected;
+ bHasFocusBorder = false;
+ break;
+
+ case MouseOver:
+ eColorType = Theme::Gradient_MouseOverPage;
+ bHasFocusBorder = false;
+ break;
+
+ case MouseOver | Focused:
+ eColorType = Theme::Gradient_MouseOverPage;
+ bHasFocusBorder = true;
+ break;
+
+ case Selected | Focused:
+ eColorType = Theme::Gradient_SelectedAndFocusedPage;
+ bHasFocusBorder = true;
+ break;
+
+ case Selected:
+ eColorType = Theme::Gradient_SelectedPage;
+ bHasFocusBorder = false;
+ break;
+
+ case Focused:
+ eColorType = Theme::Gradient_FocusedPage;
+ bHasFocusBorder = true;
+ break;
+
+ case None:
+ default:
+ eColorType = Theme::Gradient_NormalPage;
+ bHasFocusBorder = false;
+ break;
+ }
+
+ const ::tools::Rectangle aFocusSize (pPageObjectLayouter->GetBoundingBox(
+ rpDescriptor,
+ PageObjectLayouter::Part::FocusIndicator,
+ PageObjectLayouter::ModelCoordinateSystem));
+
+ const ::tools::Rectangle aPageObjectBox (pPageObjectLayouter->GetBoundingBox(
+ rpDescriptor,
+ PageObjectLayouter::Part::PageObject,
+ PageObjectLayouter::ModelCoordinateSystem));
+
+ // Fill the background with the background color of the slide sorter.
+ const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
+ rDevice.SetFillColor(aBackgroundColor);
+ rDevice.SetLineColor(aBackgroundColor);
+ rDevice.DrawRect(aFocusSize);
+
+ // Paint the slide area with a linear gradient that starts some pixels
+ // below the top and ends some pixels above the bottom.
+ const Color aTopColor(mpTheme->GetGradientColor(eColorType, Theme::GradientColorClass::Fill1));
+ const Color aBottomColor(mpTheme->GetGradientColor(eColorType, Theme::GradientColorClass::Fill2));
+ if (aTopColor != aBottomColor)
+ {
+ Gradient gradient(GradientStyle::Linear, aTopColor, aBottomColor);
+ rDevice.DrawGradient(aPageObjectBox, gradient);
+ }
+ else
+ {
+ rDevice.SetFillColor(aTopColor);
+ rDevice.DrawRect(aPageObjectBox);
+ }
+
+ // Paint the simple border and, for some backgrounds, the focus border.
+ if (bHasFocusBorder)
+ mpFocusBorderPainter->PaintFrame(rDevice, aPageObjectBox);
+ else
+ PaintBorder(rDevice, eColorType, aPageObjectBox);
+
+ // Get bounding box of the preview around which a shadow is painted.
+ // Compensate for the border around the preview.
+ const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
+ rpDescriptor,
+ PageObjectLayouter::Part::Preview,
+ PageObjectLayouter::ModelCoordinateSystem));
+ ::tools::Rectangle aFrameBox (aBox.Left()-1,aBox.Top()-1,aBox.Right()+1,aBox.Bottom()+1);
+ mpShadowPainter->PaintFrame(rDevice, aFrameBox);
+}
+
+void PageObjectPainter::PaintBorder (
+ OutputDevice& rDevice,
+ const Theme::GradientColorType eColorType,
+ const ::tools::Rectangle& rBox) const
+{
+ rDevice.SetFillColor();
+ const sal_Int32 nBorderWidth (1);
+ for (int nIndex=0; nIndex<nBorderWidth; ++nIndex)
+ {
+ const int nDelta (nIndex);
+ rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::GradientColorClass::Border2));
+ rDevice.DrawLine(
+ Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
+ Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta));
+ rDevice.DrawLine(
+ Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta),
+ Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta));
+ rDevice.DrawLine(
+ Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta),
+ Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
+
+ rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::GradientColorClass::Border1));
+ rDevice.DrawLine(
+ Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
+ Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
+ }
+}
+
+} // end of namespace sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsTheme.cxx b/sd/source/ui/slidesorter/view/SlsTheme.cxx
new file mode 100644
index 000000000..5172e6241
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsTheme.cxx
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <bitmaps.hlst>
+#include <view/SlsTheme.hxx>
+#include <controller/SlsProperties.hxx>
+#include <tools/color.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <osl/diagnose.h>
+
+namespace sd::slidesorter::view {
+
+const Color Black(0x000000);
+const Color White(0xffffff);
+
+static Color ChangeLuminance (Color aColor, const int nValue)
+{
+ if (nValue > 0)
+ aColor.IncreaseLuminance(nValue);
+ else
+ aColor.DecreaseLuminance(-nValue);
+ return aColor;
+}
+
+static Color HGBAdapt (
+ const Color aColor,
+ const sal_Int32 nNewSaturation,
+ const sal_Int32 nNewBrightness)
+{
+ sal_uInt16 nHue (0);
+ sal_uInt16 nSaturation (0);
+ sal_uInt16 nBrightness (0);
+ aColor.RGBtoHSB(nHue, nSaturation, nBrightness);
+ return Color::HSBtoRGB(
+ nHue,
+ nNewSaturation>=0 ? nNewSaturation : nSaturation,
+ nNewBrightness>=0 ? nNewBrightness : nBrightness);
+}
+
+Theme::Theme (const std::shared_ptr<controller::Properties>& rpProperties)
+ : maBackgroundColor(rpProperties->GetBackgroundColor())
+{
+ maColor.resize(ColorType_Size_);
+ maColor[Color_Background] = maBackgroundColor;
+ maColor[Color_PageNumberDefault] = Color(0x0808080);
+ maColor[Color_PageNumberHover] = Color(0x4c4c4c);
+ maColor[Color_PageNumberHighContrast] = White;
+ maColor[Color_PageNumberBrightBackground] = Color(0x333333);
+ maColor[Color_PageNumberDarkBackground] = Color(0xcccccc);
+ maColor[Color_PreviewBorder] = Color(0x949599);
+
+ Update(rpProperties);
+}
+
+void Theme::Update (const std::shared_ptr<controller::Properties>& rpProperties)
+{
+ // Set up colors.
+ maBackgroundColor = rpProperties->GetBackgroundColor();
+
+ maColor[Color_Background] = maBackgroundColor;
+
+ maGradients.resize(GradientColorType_Size_);
+
+ maColor[Color_Background] = maBackgroundColor;
+ const Color aSelectionColor (rpProperties->GetSelectionColor());
+ maColor[Color_Selection] = aSelectionColor;
+ if (aSelectionColor.IsBright())
+ maColor[Color_PageCountFontColor] = Black;
+ else
+ maColor[Color_PageCountFontColor] = White;
+
+ // Set up gradients.
+ SetGradient(Gradient_MouseOverPage, aSelectionColor, 0, 60, +80,+100, +50,+25);
+ SetGradient(Gradient_SelectedPage, aSelectionColor, 50, 50, +80,+100, +50,+25);
+ SetGradient(Gradient_FocusedPage, aSelectionColor, -1,-1, 0,0, -50,-75);
+ SetGradient(Gradient_MouseOverSelected, aSelectionColor, 55, 60, +80,+100, +50,+25);
+ SetGradient(Gradient_SelectedAndFocusedPage, aSelectionColor, 50, 50, +80,+100, -50,-75);
+ SetGradient(Gradient_MouseOverSelectedAndFocusedPage, aSelectionColor, 55, 60, +80,+100, -50,-75);
+
+ SetGradient(Gradient_NormalPage, maBackgroundColor, -1,-1, 0,0, 0,0);
+
+ // The focused gradient needs special handling because its fill color is
+ // like that of the NormalPage gradient.
+ GetGradient(Gradient_FocusedPage).maFillColor1 = GetGradient(Gradient_NormalPage).maFillColor1;
+ GetGradient(Gradient_FocusedPage).maFillColor2 = GetGradient(Gradient_NormalPage).maFillColor2;
+
+ // Set up icons.
+ if (maIcons.empty())
+ {
+ maIcons.resize(IconType_Size_);
+
+ InitializeIcon(Icon_RawShadow, IMAGE_SHADOW);
+ InitializeIcon(Icon_RawInsertShadow, IMAGE_INSERT_SHADOW);
+ InitializeIcon(Icon_HideSlideOverlay, IMAGE_HIDE_SLIDE_OVERLAY);
+ InitializeIcon(Icon_FocusBorder, IMAGE_FOCUS_BORDER);
+ }
+}
+
+std::shared_ptr<vcl::Font> Theme::GetFont (
+ const FontType eType,
+ const OutputDevice& rDevice)
+{
+ std::shared_ptr<vcl::Font> pFont;
+
+ switch (eType)
+ {
+ case Font_PageNumber:
+ pFont = std::make_shared<vcl::Font>(Application::GetSettings().GetStyleSettings().GetAppFont());
+ pFont->SetTransparent(true);
+ pFont->SetWeight(WEIGHT_BOLD);
+ break;
+
+ case Font_PageCount:
+ pFont = std::make_shared<vcl::Font>(Application::GetSettings().GetStyleSettings().GetAppFont());
+ pFont->SetTransparent(true);
+ pFont->SetWeight(WEIGHT_NORMAL);
+ {
+ const Size aSize (pFont->GetFontSize());
+ pFont->SetFontSize(Size(aSize.Width()*5/3, aSize.Height()*5/3));
+ }
+ break;
+ }
+
+ if (pFont)
+ {
+ // Transform the point size to pixel size.
+ const MapMode aFontMapMode (MapUnit::MapPoint);
+ const Size aFontSize (rDevice.LogicToPixel(pFont->GetFontSize(), aFontMapMode));
+
+ // Transform the font size to the logical coordinates of the device.
+ pFont->SetFontSize(rDevice.PixelToLogic(aFontSize));
+ }
+
+ return pFont;
+}
+
+Color Theme::GetColor (const ColorType eType)
+{
+ if (sal_uInt32(eType)<maColor.size())
+ return maColor[eType];
+ else
+ return Color(0);
+}
+
+Color Theme::GetGradientColor (
+ const GradientColorType eType,
+ const GradientColorClass eClass)
+{
+ GradientDescriptor& rDescriptor (GetGradient(eType));
+
+ switch (eClass)
+ {
+ case GradientColorClass::Border1: return rDescriptor.maBorderColor1;
+ case GradientColorClass::Border2: return rDescriptor.maBorderColor2;
+ case GradientColorClass::Fill1: return rDescriptor.maFillColor1;
+ case GradientColorClass::Fill2: return rDescriptor.maFillColor2;
+ }
+ return Color(0);
+}
+
+void Theme::SetGradient (
+ const GradientColorType eType,
+ const Color aBaseColor,
+ const sal_Int32 nSaturationOverride,
+ const sal_Int32 nBrightnessOverride,
+ const sal_Int32 nFillStartOffset,
+ const sal_Int32 nFillEndOffset,
+ const sal_Int32 nBorderStartOffset,
+ const sal_Int32 nBorderEndOffset)
+{
+ GradientDescriptor& rGradient (GetGradient(eType));
+
+ const Color aColor (nSaturationOverride>=0 || nBrightnessOverride>=0
+ ? HGBAdapt(aBaseColor, nSaturationOverride, nBrightnessOverride)
+ : aBaseColor);
+
+ rGradient.maFillColor1 = ChangeLuminance(aColor, nFillStartOffset);
+ rGradient.maFillColor2 = ChangeLuminance(aColor, nFillEndOffset);
+ rGradient.maBorderColor1 = ChangeLuminance(aColor, nBorderStartOffset);
+ rGradient.maBorderColor2 = ChangeLuminance(aColor, nBorderEndOffset);
+}
+
+const BitmapEx& Theme::GetIcon (const IconType eType)
+{
+ if (size_t(eType)<maIcons.size())
+ return maIcons[eType];
+ else
+ {
+ OSL_ASSERT(eType>=0 && size_t(eType)<maIcons.size());
+ return maIcons[0];
+ }
+}
+
+Theme::GradientDescriptor& Theme::GetGradient (const GradientColorType eType)
+{
+ if (size_t(eType)<maGradients.size())
+ return maGradients[eType];
+ else
+ {
+ OSL_ASSERT(eType>=0 && size_t(eType)<maGradients.size());
+ return maGradients[0];
+ }
+}
+
+void Theme::InitializeIcon(const IconType eType, const OUString& rResourceId)
+{
+ if (size_t(eType)<maIcons.size())
+ {
+ const BitmapEx aIcon(rResourceId);
+ maIcons[eType] = aIcon;
+ }
+ else
+ {
+ OSL_ASSERT(eType>=0 && size_t(eType)<maIcons.size());
+ }
+}
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsToolTip.cxx b/sd/source/ui/slidesorter/view/SlsToolTip.cxx
new file mode 100644
index 000000000..c266bbe3d
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsToolTip.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <view/SlsPageObjectLayouter.hxx>
+#include <view/SlsToolTip.hxx>
+#include <view/SlideSorterView.hxx>
+#include <view/SlsLayouter.hxx>
+#include <SlideSorter.hxx>
+#include <Window.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+
+#include <osl/diagnose.h>
+#include <vcl/settings.hxx>
+#include <vcl/help.hxx>
+
+namespace sd::slidesorter::view {
+
+ToolTip::ToolTip (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mnHelpWindowHandle(nullptr),
+ maShowTimer("sd::slidesorter::view::ToolTip maShowTimer"),
+ maHiddenTimer("sd::slidesorter::view::ToolTip maHiddenTimer")
+{
+ maShowTimer.SetTimeout(HelpSettings::GetTipDelay());
+ maShowTimer.SetInvokeHandler(LINK(this, ToolTip, DelayTrigger));
+ maHiddenTimer.SetTimeout(HelpSettings::GetTipDelay());
+}
+
+ToolTip::~ToolTip()
+{
+ maShowTimer.Stop();
+ maHiddenTimer.Stop();
+ Hide();
+}
+
+void ToolTip::SetPage (const model::SharedPageDescriptor& rpDescriptor)
+{
+ if (mpDescriptor == rpDescriptor)
+ return;
+
+ maShowTimer.Stop();
+ bool bWasVisible = Hide();
+
+ if (bWasVisible)
+ {
+ maHiddenTimer.Start();
+ }
+
+ mpDescriptor = rpDescriptor;
+
+ if (mpDescriptor)
+ {
+ SdPage* pPage = mpDescriptor->GetPage();
+ OUString sHelpText;
+ if (pPage != nullptr)
+ sHelpText = pPage->GetName();
+ else
+ {
+ OSL_ASSERT(mpDescriptor->GetPage() != nullptr);
+ }
+ if (sHelpText.isEmpty())
+ {
+ sHelpText = SdResId(STR_PAGE) +
+ OUString::number(mpDescriptor->GetPageIndex()+1);
+ }
+
+ msCurrentHelpText = sHelpText;
+ // show new tooltip immediately, if last one was recently hidden
+ if(maHiddenTimer.IsActive())
+ DoShow();
+ else
+ maShowTimer.Start();
+ }
+ else
+ {
+ msCurrentHelpText.clear();
+ }
+}
+
+void ToolTip::DoShow()
+{
+ if (maShowTimer.IsActive())
+ {
+ // The delay timer is active. Wait for it to trigger the showing of
+ // the tool tip.
+ return;
+ }
+
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ if (msCurrentHelpText.isEmpty() || !pWindow)
+ return;
+
+ ::tools::Rectangle aBox (
+ mrSlideSorter.GetView().GetLayouter().GetPageObjectLayouter()->GetBoundingBox(
+ mpDescriptor,
+ PageObjectLayouter::Part::Preview,
+ PageObjectLayouter::WindowCoordinateSystem));
+
+ // Do not show the help text when the (lower edge of the ) preview
+ // is not visible. The tool tip itself may still be outside the
+ // window.
+ if (aBox.Bottom() >= pWindow->GetSizePixel().Height())
+ return;
+
+ vcl::Window* pParent (pWindow);
+ while (pParent!=nullptr && pParent->GetParent()!=nullptr)
+ pParent = pParent->GetParent();
+ const Point aOffset (pWindow->GetWindowExtentsRelative(pParent).TopLeft());
+
+ // We do not know how high the tool tip will be but want its top
+ // edge not its bottom to be at a specific position (a little below
+ // the preview). Therefore we use a little trick and place the tool
+ // tip at the top of a rectangle that is placed below the preview.
+ aBox.Move(aOffset.X(), aOffset.Y() + aBox.GetHeight() + 3);
+ mnHelpWindowHandle = Help::ShowPopover(
+ pWindow,
+ aBox,
+ msCurrentHelpText,
+ QuickHelpFlags::Center | QuickHelpFlags::Top);
+}
+
+bool ToolTip::Hide()
+{
+ if (mnHelpWindowHandle)
+ {
+ sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
+ Help::HidePopover(pWindow, mnHelpWindowHandle);
+ mnHelpWindowHandle = nullptr;
+ return true;
+ }
+ else
+ return false;
+}
+
+IMPL_LINK_NOARG(ToolTip, DelayTrigger, Timer *, void)
+{
+ DoShow();
+}
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx b/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx
new file mode 100644
index 000000000..ce27cec28
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsViewCacheContext.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 "SlsViewCacheContext.hxx"
+
+#include <SlideSorter.hxx>
+#include <model/SlideSorterModel.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <view/SlideSorterView.hxx>
+#include <sdpage.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <tools/IdleDetection.hxx>
+#include <svx/svdpage.hxx>
+
+namespace sd::slidesorter::view {
+
+ViewCacheContext::ViewCacheContext (SlideSorter& rSlideSorter)
+ : mrModel(rSlideSorter.GetModel()),
+ mrSlideSorter(rSlideSorter)
+{
+}
+
+ViewCacheContext::~ViewCacheContext()
+{
+}
+
+void ViewCacheContext::NotifyPreviewCreation(cache::CacheKey aKey)
+{
+ const model::SharedPageDescriptor pDescriptor (GetDescriptor(aKey));
+ if (pDescriptor)
+ {
+ // Force a repaint that will trigger their re-creation.
+ mrSlideSorter.GetView().RequestRepaint(pDescriptor);
+ }
+ else
+ {
+ // It is OK when a preview was created for a page that is not
+ // currently displayed because both normal and master pages are
+ // kept in the same cache.
+ }
+}
+
+bool ViewCacheContext::IsIdle()
+{
+ tools::IdleState nIdleState (tools::IdleDetection::GetIdleState(mrSlideSorter.GetContentWindow()));
+ return nIdleState == tools::IdleState::Idle;
+}
+
+bool ViewCacheContext::IsVisible (cache::CacheKey aKey)
+{
+ const model::SharedPageDescriptor pDescriptor (GetDescriptor(aKey));
+ return pDescriptor && pDescriptor->HasState(model::PageDescriptor::ST_Visible);
+}
+
+const SdrPage* ViewCacheContext::GetPage (cache::CacheKey aKey)
+{
+ return aKey;
+}
+
+std::shared_ptr<std::vector<cache::CacheKey> > ViewCacheContext::GetEntryList (bool bVisible)
+{
+ auto pKeys = std::make_shared<std::vector<cache::CacheKey>>();
+
+ model::PageEnumeration aPageEnumeration (
+ bVisible
+ ? model::PageEnumerationProvider::CreateVisiblePagesEnumeration(mrModel)
+ : model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
+
+ while (aPageEnumeration.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement());
+ pKeys->push_back(pDescriptor->GetPage());
+ }
+
+ return pKeys;
+}
+
+sal_Int32 ViewCacheContext::GetPriority (cache::CacheKey aKey)
+{
+ return - (aKey->GetPageNum()-1) / 2;
+}
+
+model::SharedPageDescriptor ViewCacheContext::GetDescriptor (cache::CacheKey aKey)
+{
+ sal_uInt16 nPageIndex ((aKey->GetPageNum() - 1) / 2);
+ return mrModel.GetPageDescriptor(nPageIndex);
+}
+
+css::uno::Reference<css::uno::XInterface> ViewCacheContext::GetModel()
+{
+ if (mrModel.GetDocument() == nullptr)
+ return nullptr;
+ else
+ return mrModel.GetDocument()->getUnoModel();
+}
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx b/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx
new file mode 100644
index 000000000..501517cb8
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cache/SlsCacheContext.hxx>
+#include <model/SlsSharedPageDescriptor.hxx>
+
+namespace sd::slidesorter::model
+{
+class SlideSorterModel;
+}
+namespace sd::slidesorter
+{
+class SlideSorter;
+}
+
+namespace sd::slidesorter::view
+{
+/** The cache context for the SlideSorter as used by Draw and Impress. See
+ the base class for documentation of the individual methods.
+*/
+class ViewCacheContext : public cache::CacheContext
+{
+public:
+ explicit ViewCacheContext(SlideSorter& rSlideSorter);
+ virtual ~ViewCacheContext() override;
+ virtual void NotifyPreviewCreation(cache::CacheKey aKey) override;
+ virtual bool IsIdle() override;
+ virtual bool IsVisible(cache::CacheKey aKey) override;
+ virtual const SdrPage* GetPage(cache::CacheKey aKey) override;
+ virtual std::shared_ptr<std::vector<cache::CacheKey>> GetEntryList(bool bVisible) override;
+ virtual sal_Int32 GetPriority(cache::CacheKey aKey) override;
+ virtual css::uno::Reference<css::uno::XInterface> GetModel() override;
+
+private:
+ model::SlideSorterModel& mrModel;
+ SlideSorter& mrSlideSorter;
+
+ model::SharedPageDescriptor GetDescriptor(cache::CacheKey aKey);
+};
+
+} // end of namespace ::sd::slidesorter::view
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/table/TableDesignPane.cxx b/sd/source/ui/table/TableDesignPane.cxx
new file mode 100644
index 000000000..82d4485fb
--- /dev/null
+++ b/sd/source/ui/table/TableDesignPane.cxx
@@ -0,0 +1,763 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawView.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/image.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <svl/style.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svdetc.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/sdr/table/tabledesign.hxx>
+#include <o3tl/enumrange.hxx>
+
+#include <TableDesignPane.hxx>
+
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <EventMultiplexer.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui;
+
+namespace sd {
+
+const sal_Int32 nPreviewColumns = 5;
+const sal_Int32 nPreviewRows = 5;
+const sal_Int32 nCellWidth = 12; // one pixel is shared with the next cell!
+const sal_Int32 nCellHeight = 7; // one pixel is shared with the next cell!
+const sal_Int32 nBitmapWidth = (nCellWidth * nPreviewColumns) - (nPreviewColumns - 1);
+const sal_Int32 nBitmapHeight = (nCellHeight * nPreviewRows) - (nPreviewRows - 1);
+
+const std::string_view gPropNames[CB_COUNT] =
+{
+ "UseFirstRowStyle",
+ "UseLastRowStyle",
+ "UseBandingRowStyle",
+ "UseFirstColumnStyle",
+ "UseLastColumnStyle",
+ "UseBandingColumnStyle"
+};
+
+TableDesignWidget::TableDesignWidget(weld::Builder& rBuilder, ViewShellBase& rBase)
+ : mrBase(rBase)
+ , m_xValueSet(new TableValueSet(rBuilder.weld_scrolled_window("previewswin", true)))
+ , m_xValueSetWin(new weld::CustomWeld(rBuilder, "previews", *m_xValueSet))
+{
+ m_xValueSet->SetStyle(m_xValueSet->GetStyle() | WB_NO_DIRECTSELECT | WB_FLATVALUESET | WB_ITEMBORDER);
+ m_xValueSet->SetExtraSpacing(8);
+ m_xValueSet->setModal(false);
+ m_xValueSet->SetColor();
+ m_xValueSet->SetSelectHdl(LINK(this, TableDesignWidget, implValueSetHdl));
+
+ for (sal_uInt16 i = CB_HEADER_ROW; i <= CB_BANDED_COLUMNS; ++i)
+ {
+ m_aCheckBoxes[i] = rBuilder.weld_check_button(OString(gPropNames[i].data(), gPropNames[i].size()));
+ m_aCheckBoxes[i]->connect_toggled(LINK(this, TableDesignWidget, implCheckBoxHdl));
+ }
+
+ // get current controller and initialize listeners
+ try
+ {
+ mxView.set(mrBase.GetController(), UNO_QUERY);
+ addListener();
+
+ Reference< XController > xController( mrBase.GetController(), UNO_SET_THROW );
+ Reference< XStyleFamiliesSupplier > xFamiliesSupp( xController->getModel(), UNO_QUERY_THROW );
+ Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() );
+ mxTableFamily.set( xFamilies->getByName( "table" ), UNO_QUERY_THROW );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::CustomAnimationPane()" );
+ }
+
+ onSelectionChanged();
+ updateControls();
+}
+
+TableDesignWidget::~TableDesignWidget()
+{
+ removeListener();
+}
+
+static SfxBindings* getBindings( ViewShellBase const & rBase )
+{
+ if( rBase.GetMainViewShell() && rBase.GetMainViewShell()->GetViewFrame() )
+ return &rBase.GetMainViewShell()->GetViewFrame()->GetBindings();
+ else
+ return nullptr;
+}
+
+static SfxDispatcher* getDispatcher( ViewShellBase const & rBase )
+{
+ if( rBase.GetMainViewShell() && rBase.GetMainViewShell()->GetViewFrame() )
+ return rBase.GetMainViewShell()->GetViewFrame()->GetDispatcher();
+ else
+ return nullptr;
+}
+
+IMPL_LINK_NOARG(TableDesignWidget, implValueSetHdl, ValueSet*, void)
+{
+ ApplyStyle();
+}
+
+void TableDesignWidget::ApplyStyle()
+{
+ try
+ {
+ OUString sStyleName;
+ sal_Int32 nIndex = static_cast< sal_Int32 >( m_xValueSet->GetSelectedItemId() ) - 1;
+
+ if( (nIndex >= 0) && (nIndex < mxTableFamily->getCount()) )
+ {
+ Reference< XNameAccess > xNames( mxTableFamily, UNO_QUERY_THROW );
+ sStyleName = xNames->getElementNames()[nIndex];
+ }
+
+ if( sStyleName.isEmpty() )
+ return;
+
+ SdrView* pView = mrBase.GetDrawView();
+ if( mxSelectedTable.is() )
+ {
+ if( pView )
+ {
+ SfxRequest aReq( SID_TABLE_STYLE, SfxCallMode::SYNCHRON, SfxGetpApp()->GetPool() );
+ aReq.AppendItem( SfxStringItem( SID_TABLE_STYLE, sStyleName ) );
+
+ const rtl::Reference< sdr::SelectionController >& xController( pView->getSelectionController() );
+ if( xController.is() )
+ xController->Execute( aReq );
+
+ SfxBindings* pBindings = getBindings( mrBase );
+ if( pBindings )
+ {
+ pBindings->Invalidate( SID_UNDO );
+ pBindings->Invalidate( SID_REDO );
+ }
+ }
+ }
+ else
+ {
+ SfxDispatcher* pDispatcher = getDispatcher( mrBase );
+ SfxStringItem aArg( SID_TABLE_STYLE, sStyleName );
+ pDispatcher->ExecuteList(SID_INSERT_TABLE, SfxCallMode::ASYNCHRON,
+ { &aArg });
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "TableDesignWidget::implValueSetHdl()");
+ }
+}
+
+IMPL_LINK_NOARG(TableDesignWidget, implCheckBoxHdl, weld::Toggleable&, void)
+{
+ ApplyOptions();
+ FillDesignPreviewControl();
+}
+
+void TableDesignWidget::ApplyOptions()
+{
+ static const sal_uInt16 gParamIds[CB_COUNT] =
+ {
+ ID_VAL_USEFIRSTROWSTYLE, ID_VAL_USELASTROWSTYLE, ID_VAL_USEBANDINGROWSTYLE,
+ ID_VAL_USEFIRSTCOLUMNSTYLE, ID_VAL_USELASTCOLUMNSTYLE, ID_VAL_USEBANDINGCOLUMNSTYLE
+ };
+
+ if( !mxSelectedTable.is() )
+ return;
+
+ SfxRequest aReq( SID_TABLE_STYLE_SETTINGS, SfxCallMode::SYNCHRON, SfxGetpApp()->GetPool() );
+
+ for( sal_uInt16 i = CB_HEADER_ROW; i <= CB_BANDED_COLUMNS; ++i )
+ {
+ aReq.AppendItem( SfxBoolItem( gParamIds[i], m_aCheckBoxes[i]->get_active() ) );
+ }
+
+ SdrView* pView = mrBase.GetDrawView();
+ if( !pView )
+ return;
+
+ const rtl::Reference< sdr::SelectionController >& xController( pView->getSelectionController() );
+ if( xController.is() )
+ {
+ xController->Execute( aReq );
+
+ SfxBindings* pBindings = getBindings( mrBase );
+ if( pBindings )
+ {
+ pBindings->Invalidate( SID_UNDO );
+ pBindings->Invalidate( SID_REDO );
+ }
+ }
+}
+
+void TableDesignWidget::onSelectionChanged()
+{
+ Reference< XPropertySet > xNewSelection;
+
+ if( mxView.is() ) try
+ {
+ Reference< XSelectionSupplier > xSel( mxView, UNO_QUERY_THROW );
+ Any aSel( xSel->getSelection() );
+ Sequence< XShape > xShapeSeq;
+ if( aSel >>= xShapeSeq )
+ {
+ if( xShapeSeq.getLength() == 1 )
+ aSel <<= xShapeSeq[0];
+ }
+ else
+ {
+ Reference< XShapes > xShapes( aSel, UNO_QUERY );
+ if( xShapes.is() && (xShapes->getCount() == 1) )
+ aSel = xShapes->getByIndex(0);
+ }
+
+ Reference< XShapeDescriptor > xDesc( aSel, UNO_QUERY );
+ if( xDesc.is() && ( xDesc->getShapeType() == "com.sun.star.drawing.TableShape" || xDesc->getShapeType() == "com.sun.star.presentation.TableShape" ) )
+ {
+ xNewSelection.set( xDesc, UNO_QUERY );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::TableDesignWidget::onSelectionChanged()" );
+ }
+
+ if( mxSelectedTable != xNewSelection )
+ {
+ mxSelectedTable = xNewSelection;
+ updateControls();
+ }
+}
+
+void TableValueSet::Resize()
+{
+ ValueSet::Resize();
+ // Calculate the number of rows and columns.
+ if( GetItemCount() <= 0 )
+ return;
+
+ Size aValueSetSize = GetOutputSizePixel();
+
+ Image aImage = GetItemImage(GetItemId(0));
+ Size aItemSize = aImage.GetSizePixel();
+
+ aItemSize.AdjustHeight(10 );
+ int nColumnCount = (aValueSetSize.Width() - GetScrollWidth()) / aItemSize.Width();
+ if (nColumnCount < 1)
+ nColumnCount = 1;
+
+ int nRowCount = (GetItemCount() + nColumnCount - 1) / nColumnCount;
+ if (nRowCount < 1)
+ nRowCount = 1;
+
+ int nVisibleRowCount = (aValueSetSize.Height()+2) / aItemSize.Height();
+
+ SetColCount (static_cast<sal_uInt16>(nColumnCount));
+ SetLineCount (static_cast<sal_uInt16>(nRowCount));
+
+ if( !m_bModal )
+ {
+ WinBits nStyle = GetStyle() & ~WB_VSCROLL;
+ if( nRowCount > nVisibleRowCount )
+ {
+ nStyle |= WB_VSCROLL;
+ }
+ SetStyle( nStyle );
+ }
+}
+
+TableValueSet::TableValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
+ : ValueSet(std::move(pScrolledWindow))
+ , m_bModal(false)
+{
+}
+
+void TableValueSet::StyleUpdated()
+{
+ updateSettings();
+}
+
+void TableValueSet::updateSettings()
+{
+ if( !m_bModal )
+ {
+ Color aColor = Application::GetSettings().GetStyleSettings().GetWindowColor();
+ SetColor(aColor);
+ SetExtraSpacing(8);
+ }
+}
+
+void TableDesignWidget::updateControls()
+{
+ static const bool gDefaults[CB_COUNT] = { true, false, true, false, false, false };
+
+ const bool bHasTable = mxSelectedTable.is();
+
+ for (sal_uInt16 i = CB_HEADER_ROW; i <= CB_BANDED_COLUMNS; ++i)
+ {
+ bool bUse = gDefaults[i];
+ if( bHasTable ) try
+ {
+ mxSelectedTable->getPropertyValue( OUString::createFromAscii(gPropNames[i]) ) >>= bUse;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::TableDesignWidget::updateControls()");
+ }
+ m_aCheckBoxes[i]->set_active(bUse);
+ m_aCheckBoxes[i]->set_sensitive(bHasTable);
+ }
+
+ FillDesignPreviewControl();
+ m_xValueSet->updateSettings();
+ m_xValueSet->Resize();
+
+ sal_uInt16 nSelection = 0;
+ if( mxSelectedTable.is() )
+ {
+ Reference< XNamed > xNamed( mxSelectedTable->getPropertyValue( "TableTemplate" ), UNO_QUERY );
+ if( xNamed.is() )
+ {
+ const OUString sStyleName( xNamed->getName() );
+
+ Reference< XNameAccess > xNames( mxTableFamily, UNO_QUERY );
+ if( xNames.is() )
+ {
+ Sequence< OUString > aNames( xNames->getElementNames() );
+ sal_Int32 nIndex = comphelper::findValue(aNames, sStyleName);
+ if (nIndex != -1)
+ nSelection = static_cast<sal_uInt16>(nIndex) + 1;
+ }
+ }
+ }
+ m_xValueSet->SelectItem( nSelection );
+}
+
+void TableDesignWidget::addListener()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,TableDesignWidget,EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->AddEventListener( aLink );
+}
+
+void TableDesignWidget::removeListener()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,TableDesignWidget,EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
+}
+
+IMPL_LINK(TableDesignWidget,EventMultiplexerListener,
+ tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ case EventMultiplexerEventId::CurrentPageChanged:
+ case EventMultiplexerEventId::EditViewSelection:
+ onSelectionChanged();
+ break;
+
+ case EventMultiplexerEventId::MainViewRemoved:
+ mxView.clear();
+ onSelectionChanged();
+ break;
+
+ case EventMultiplexerEventId::MainViewAdded:
+ mxView.set( mrBase.GetController(), UNO_QUERY );
+ onSelectionChanged();
+ break;
+
+ default: break;
+ }
+}
+
+namespace {
+
+struct CellInfo
+{
+ Color maCellColor;
+ Color maTextColor;
+ std::shared_ptr<SvxBoxItem> maBorder;
+
+ explicit CellInfo( const Reference< XStyle >& xStyle );
+};
+
+}
+
+CellInfo::CellInfo( const Reference< XStyle >& xStyle )
+: maBorder(std::make_shared<SvxBoxItem>(SDRATTR_TABLE_BORDER))
+{
+ SfxStyleSheet* pStyleSheet = SfxUnoStyleSheet::getUnoStyleSheet( xStyle );
+ if( !pStyleSheet )
+ return;
+
+ SfxItemSet& rSet = pStyleSheet->GetItemSet();
+
+ // get style fill color
+ if( !GetDraftFillColor(rSet, maCellColor) )
+ maCellColor = COL_TRANSPARENT;
+
+ // get style text color
+ const SvxColorItem* pTextColor = rSet.GetItem(EE_CHAR_COLOR);
+ if( pTextColor )
+ maTextColor = pTextColor->GetValue();
+ else
+ maTextColor = COL_TRANSPARENT;
+
+ // get border
+ const SvxBoxItem* pBoxItem = rSet.GetItem( SDRATTR_TABLE_BORDER );
+ if( pBoxItem )
+ maBorder.reset(pBoxItem->Clone());
+}
+
+typedef std::vector< std::shared_ptr< CellInfo > > CellInfoVector;
+typedef std::shared_ptr< CellInfo > CellInfoMatrix[nPreviewColumns * nPreviewRows];
+
+namespace {
+
+struct TableStyleSettings
+{
+ bool mbUseFirstRow;
+ bool mbUseLastRow;
+ bool mbUseFirstColumn;
+ bool mbUseLastColumn;
+ bool mbUseRowBanding;
+ bool mbUseColumnBanding;
+
+ TableStyleSettings()
+ : mbUseFirstRow(true)
+ , mbUseLastRow(false)
+ , mbUseFirstColumn(false)
+ , mbUseLastColumn(false)
+ , mbUseRowBanding(true)
+ , mbUseColumnBanding(false) {}
+};
+
+}
+
+static void FillCellInfoVector( const Reference< XIndexAccess >& xTableStyle, CellInfoVector& rVector )
+{
+ DBG_ASSERT( xTableStyle.is() && (xTableStyle->getCount() == sdr::table::style_count ), "sd::FillCellInfoVector(), invalid table style!" );
+ if( !xTableStyle.is() )
+ return;
+
+ try
+ {
+ rVector.resize( sdr::table::style_count );
+
+ for( sal_Int32 nStyle = 0; nStyle < sdr::table::style_count; ++nStyle )
+ {
+ Reference< XStyle > xStyle( xTableStyle->getByIndex( nStyle ), UNO_QUERY );
+ if( xStyle.is() )
+ rVector[nStyle] = std::make_shared<CellInfo>( xStyle );
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::FillCellInfoVector()");
+ }
+}
+
+static void FillCellInfoMatrix( const CellInfoVector& rStyle, const TableStyleSettings& rSettings, CellInfoMatrix& rMatrix )
+{
+ for( sal_Int32 nRow = 0; nRow < nPreviewColumns; ++nRow )
+ {
+ const bool bFirstRow = rSettings.mbUseFirstRow && (nRow == 0);
+ const bool bLastRow = rSettings.mbUseLastRow && (nRow == nPreviewColumns - 1);
+
+ for( sal_Int32 nCol = 0; nCol < nPreviewColumns; ++nCol )
+ {
+ std::shared_ptr< CellInfo > xCellInfo;
+
+ // first and last row win first, if used and available
+ if( bFirstRow )
+ {
+ xCellInfo = rStyle[sdr::table::first_row_style];
+ }
+ else if( bLastRow )
+ {
+ xCellInfo = rStyle[sdr::table::last_row_style];
+ }
+
+ if( !xCellInfo )
+ {
+ // next come first and last column, if used and available
+ if( rSettings.mbUseFirstColumn && (nCol == 0) )
+ {
+ xCellInfo = rStyle[sdr::table::first_column_style];
+ }
+ else if( rSettings.mbUseLastColumn && (nCol == nPreviewColumns-1) )
+ {
+ xCellInfo = rStyle[sdr::table::last_column_style];
+ }
+ }
+
+ if( !xCellInfo )
+ {
+ if( rSettings.mbUseRowBanding )
+ {
+ if( (nRow & 1) == 0 )
+ {
+ xCellInfo = rStyle[sdr::table::even_rows_style];
+ }
+ else
+ {
+ xCellInfo = rStyle[sdr::table::odd_rows_style];
+ }
+ }
+ }
+
+ if( !xCellInfo )
+ {
+ if( rSettings.mbUseColumnBanding )
+ {
+ if( (nCol & 1) == 0 )
+ {
+ xCellInfo = rStyle[sdr::table::even_columns_style];
+ }
+ else
+ {
+ xCellInfo = rStyle[sdr::table::odd_columns_style];
+ }
+ }
+ }
+
+ if( !xCellInfo )
+ {
+ // use default cell style if non found yet
+ xCellInfo = rStyle[sdr::table::body_style];
+ }
+
+ rMatrix[(nCol * nPreviewColumns) + nRow] = xCellInfo;
+ }
+ }
+}
+
+static BitmapEx CreateDesignPreview( const Reference< XIndexAccess >& xTableStyle, const TableStyleSettings& rSettings, bool bIsPageDark )
+{
+ CellInfoVector aCellInfoVector(sdr::table::style_count);
+ FillCellInfoVector( xTableStyle, aCellInfoVector );
+
+ CellInfoMatrix aMatrix;
+ FillCellInfoMatrix( aCellInfoVector, rSettings, aMatrix );
+
+ // bbbbbbbbbbbb w = 12 pixel
+ // bccccccccccb h = 7 pixel
+ // bccccccccccb b = border color
+ // bcttttttttcb c = cell color
+ // bccccccccccb t = text color
+ // bccccccccccb
+ // bbbbbbbbbbbb
+
+ ScopedVclPtr<VirtualDevice> pVirDev(VclPtr<VirtualDevice>::Create());
+ Size aBmpSize(nBitmapWidth, nBitmapHeight);
+ pVirDev->SetOutputSizePixel(aBmpSize);
+
+ pVirDev->SetBackground( bIsPageDark ? COL_BLACK : COL_WHITE );
+ pVirDev->Erase();
+
+ // first draw cell background and text line previews
+ sal_Int32 nY = 0;
+ sal_Int32 nRow;
+ for( nRow = 0; nRow < nPreviewRows; ++nRow, nY += nCellHeight-1 )
+ {
+ sal_Int32 nX = 0;
+ for( sal_Int32 nCol = 0; nCol < nPreviewColumns; ++nCol, nX += nCellWidth-1 )
+ {
+ std::shared_ptr< CellInfo > xCellInfo(aMatrix[(nCol * nPreviewColumns) + nRow]);
+
+ Color aTextColor( COL_AUTO );
+ if( xCellInfo )
+ {
+ // fill cell background
+ const ::tools::Rectangle aRect( nX, nY, nX + nCellWidth - 1, nY + nCellHeight - 1 );
+
+ if( xCellInfo->maCellColor != COL_TRANSPARENT )
+ {
+ pVirDev->SetFillColor( xCellInfo->maCellColor );
+ pVirDev->DrawRect( aRect );
+ }
+
+ aTextColor = xCellInfo->maTextColor;
+ }
+
+ // draw text preview line
+ if( aTextColor == COL_AUTO )
+ aTextColor = bIsPageDark ? COL_WHITE : COL_BLACK;
+ pVirDev->SetLineColor( aTextColor );
+ const Point aPnt1( nX + 2, nY + ((nCellHeight - 1 ) >> 1) );
+ const Point aPnt2( nX + nCellWidth - 3, aPnt1.Y() );
+ pVirDev->DrawLine( aPnt1, aPnt2 );
+ }
+ }
+
+ // second draw border lines
+ nY = 0;
+ for( nRow = 0; nRow < nPreviewRows; ++nRow, nY += nCellHeight-1 )
+ {
+ sal_Int32 nX = 0;
+ for( sal_Int32 nCol = 0; nCol < nPreviewColumns; ++nCol, nX += nCellWidth-1 )
+ {
+ std::shared_ptr< CellInfo > xCellInfo(aMatrix[(nCol * nPreviewColumns) + nRow]);
+
+ if( xCellInfo )
+ {
+ const Point aPntTL( nX, nY );
+ const Point aPntTR( nX + nCellWidth - 1, nY );
+ const Point aPntBL( nX, nY + nCellHeight - 1 );
+ const Point aPntBR( nX + nCellWidth - 1, nY + nCellHeight - 1 );
+
+ sal_Int32 border_diffs[8] = { 0,-1, 0,1, -1,0, 1,0 };
+ sal_Int32* pDiff = &border_diffs[0];
+
+ // draw top border
+ for( SvxBoxItemLine nLine : o3tl::enumrange<SvxBoxItemLine>() )
+ {
+ const ::editeng::SvxBorderLine* pBorderLine = xCellInfo->maBorder->GetLine(nLine);
+ if( !pBorderLine || ((pBorderLine->GetOutWidth() == 0) && (pBorderLine->GetInWidth()==0)) )
+ continue;
+
+ sal_Int32 nBorderCol = nCol + *pDiff++;
+ sal_Int32 nBorderRow = nRow + *pDiff++;
+ if( (nBorderCol >= 0) && (nBorderCol < nPreviewColumns) && (nBorderRow >= 0) && (nBorderRow < nPreviewRows) )
+ {
+ // check border
+ std::shared_ptr< CellInfo > xBorderInfo(aMatrix[(nBorderCol * nPreviewColumns) + nBorderRow]);
+ if( xBorderInfo )
+ {
+ const ::editeng::SvxBorderLine* pBorderLine2 = xBorderInfo->maBorder->GetLine(static_cast<SvxBoxItemLine>(static_cast<int>(nLine)^1));
+ if( pBorderLine2 && pBorderLine2->HasPriority(*pBorderLine) )
+ continue; // other border line wins
+ }
+ }
+
+ pVirDev->SetLineColor( pBorderLine->GetColor() );
+ switch( nLine )
+ {
+ case SvxBoxItemLine::TOP: pVirDev->DrawLine( aPntTL, aPntTR ); break;
+ case SvxBoxItemLine::BOTTOM: pVirDev->DrawLine( aPntBL, aPntBR ); break;
+ case SvxBoxItemLine::LEFT: pVirDev->DrawLine( aPntTL, aPntBL ); break;
+ case SvxBoxItemLine::RIGHT: pVirDev->DrawLine( aPntTR, aPntBR ); break;
+ }
+ }
+ }
+ }
+ }
+
+ return pVirDev->GetBitmapEx(Point(0,0), aBmpSize);
+}
+
+void TableDesignWidget::FillDesignPreviewControl()
+{
+ sal_uInt16 nSelectedItem = m_xValueSet->GetSelectedItemId();
+ m_xValueSet->Clear();
+ try
+ {
+ TableStyleSettings aSettings;
+ if( mxSelectedTable.is() )
+ {
+ aSettings.mbUseFirstRow = m_aCheckBoxes[CB_HEADER_ROW]->get_active();
+ aSettings.mbUseLastRow = m_aCheckBoxes[CB_TOTAL_ROW]->get_active();
+ aSettings.mbUseRowBanding = m_aCheckBoxes[CB_BANDED_ROWS]->get_active();
+ aSettings.mbUseFirstColumn = m_aCheckBoxes[CB_FIRST_COLUMN]->get_active();
+ aSettings.mbUseLastColumn = m_aCheckBoxes[CB_LAST_COLUMN]->get_active();
+ aSettings.mbUseColumnBanding = m_aCheckBoxes[CB_BANDED_COLUMNS]->get_active();
+ }
+
+ bool bIsPageDark = false;
+ if( mxView.is() )
+ {
+ Reference< XPropertySet > xPageSet( mxView->getCurrentPage(), UNO_QUERY );
+ if( xPageSet.is() )
+ {
+ xPageSet->getPropertyValue("IsBackgroundDark") >>= bIsPageDark;
+ }
+ }
+
+ sal_Int32 nCount = mxTableFamily->getCount();
+ for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) try
+ {
+ Reference< XIndexAccess > xTableStyle( mxTableFamily->getByIndex( nIndex ), UNO_QUERY );
+ if( xTableStyle.is() )
+ m_xValueSet->InsertItem( sal::static_int_cast<sal_uInt16>( nIndex + 1 ), Image( CreateDesignPreview( xTableStyle, aSettings, bIsPageDark ) ) );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::TableDesignWidget::FillDesignPreviewControl()");
+ }
+ sal_Int32 nCols = 3;
+ sal_Int32 nRows = (nCount+2)/3;
+ m_xValueSet->SetColCount(nCols);
+ m_xValueSet->SetLineCount(nRows);
+ WinBits nStyle = m_xValueSet->GetStyle() & ~WB_VSCROLL;
+ m_xValueSet->SetStyle(nStyle);
+
+ m_xValueSet->SetOptimalSize();
+ weld::DrawingArea* pDrawingArea = m_xValueSet->GetDrawingArea();
+ Size aSize = pDrawingArea->get_preferred_size();
+ aSize.AdjustWidth(10 * nCols);
+ aSize.AdjustHeight(10 * nRows);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+
+ m_xValueSet->Resize();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::TableDesignWidget::FillDesignPreviewControl()");
+ }
+ m_xValueSet->SelectItem(nSelectedItem);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/table/tablefunction.cxx b/sd/source/ui/table/tablefunction.cxx
new file mode 100644
index 000000000..c19445429
--- /dev/null
+++ b/sd/source/ui/table/tablefunction.cxx
@@ -0,0 +1,292 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/drawing/XSelectionFunction.hpp>
+
+#include <comphelper/lok.hxx>
+
+#include <svx/svdotable.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svdpagv.hxx>
+#include <svx/svxdlg.hxx>
+
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <svl/style.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <tablefunction.hxx>
+#include <DrawViewShell.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <Window.hxx>
+#include <drawview.hxx>
+#include <sdmod.hxx>
+
+#include <memory>
+
+using namespace ::sd;
+using namespace sdr::table;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::linguistic2;
+
+namespace sd
+{
+
+static void apply_table_style( SdrTableObj* pObj, SdrModel const * pModel, const OUString& sTableStyle )
+{
+ if( !(pModel && pObj) )
+ return;
+
+ Reference< XNameAccess > xPool( dynamic_cast< XNameAccess* >( pModel->GetStyleSheetPool() ) );
+ if( !xPool.is() )
+ return;
+
+ try
+ {
+ Reference< XNameContainer > xTableFamily( xPool->getByName( "table" ), UNO_QUERY_THROW );
+ OUString aStdName( "default" );
+ if( !sTableStyle.isEmpty() )
+ aStdName = sTableStyle;
+ Reference< XIndexAccess > xStyle( xTableFamily->getByName( aStdName ), UNO_QUERY_THROW );
+ pObj->setTableStyle( xStyle );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::apply_default_table_style()");
+ }
+}
+
+static void InsertTableImpl(const DrawViewShell* pShell,
+ ::sd::View* pView,
+ sal_Int32 nColumns,
+ sal_Int32 nRows,
+ const OUString& sTableStyle)
+{
+ ::tools::Rectangle aRect;
+
+ SdrObject* pPickObj = pView->GetEmptyPresentationObject( PresObjKind::Table );
+ if( pPickObj )
+ {
+ aRect = pPickObj->GetLogicRect();
+ aRect.setHeight( 200 );
+ }
+ else
+ {
+ Size aSize( 14100, 2000 );
+
+ Point aPos;
+ ::tools::Rectangle aWinRect(aPos, pShell->GetActiveWindow()->GetOutputSizePixel());
+ aWinRect = pShell->GetActiveWindow()->PixelToLogic(aWinRect);
+
+ // make sure that the default size of the table fits on the paper and is inside the viewing area.
+ // if zoomed in close, don't make the table bigger than the viewing window.
+ Size aMaxSize = pShell->getCurrentPage()->GetSize();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // aWinRect is nonsensical in the LOK case
+ aWinRect = ::tools::Rectangle(aPos, aMaxSize);
+ }
+ else
+ {
+ if( aMaxSize.Height() > aWinRect.getHeight() )
+ aMaxSize.setHeight( aWinRect.getHeight() );
+ if( aMaxSize.Width() > aWinRect.getWidth() )
+ aMaxSize.setWidth( aWinRect.getWidth() );
+ }
+
+ if( aSize.Width() > aMaxSize.getWidth() )
+ aSize.setWidth( aMaxSize.getWidth() );
+
+ // adjust height based on # of rows.
+ if( nRows > 0 )
+ {
+ aSize.setHeight( aSize.Height() * nRows );
+ if( aSize.Height() > aMaxSize.getHeight() )
+ aSize.setHeight( aMaxSize.getHeight() );
+ }
+
+ aPos = aWinRect.Center();
+ aPos.AdjustX( -(aSize.Width() / 2) );
+ aPos.AdjustY( -(aSize.Height() / 2) );
+ aRect = ::tools::Rectangle(aPos, aSize);
+ }
+
+ sdr::table::SdrTableObj* pObj = new sdr::table::SdrTableObj(
+ *pShell->GetDoc(), // TTTT should be reference
+ aRect,
+ nColumns,
+ nRows);
+ pObj->NbcSetStyleSheet( pShell->GetDoc()->GetDefaultStyleSheet(), true );
+ apply_table_style( pObj, pShell->GetDoc(), sTableStyle );
+ SdrPageView* pPV = pView->GetSdrPageView();
+
+ // #i123359# if an object is to be replaced/manipulated it may be that it is in text edit mode,
+ // so to be on the safe side call SdrEndTextEdit here
+ SdrTextObj* pCheckForTextEdit = dynamic_cast< SdrTextObj* >(pPickObj);
+
+ if(pCheckForTextEdit && pCheckForTextEdit->IsInEditMode())
+ {
+ pView->SdrEndTextEdit();
+ }
+
+ // if we have a pick obj we need to make this new ole a pres obj replacing the current pick obj
+ if( pPickObj )
+ {
+ SdPage* pPage = static_cast< SdPage* >(pPickObj->getSdrPageFromSdrObject());
+ if(pPage && pPage->IsPresObj(pPickObj))
+ {
+ pObj->SetUserCall( pPickObj->GetUserCall() );
+ pPage->InsertPresObj( pObj, PresObjKind::Table );
+ }
+ }
+
+ pShell->GetParentWindow()->GrabFocus();
+ if( pPickObj )
+ pView->ReplaceObjectAtView(pPickObj, *pPV, pObj );
+ else
+ pView->InsertObjectAtView(pObj, *pPV, SdrInsertFlags::SETDEFLAYER);
+}
+
+void DrawViewShell::FuTable(SfxRequest& rReq)
+{
+ switch( rReq.GetSlot() )
+ {
+ case SID_INSERT_TABLE:
+ {
+ sal_Int32 nColumns = 0;
+ sal_Int32 nRows = 0;
+ OUString sTableStyle;
+ DrawViewShell* pShell = this;
+ ::sd::View* pView = mpView;
+
+ const SfxUInt16Item* pCols = rReq.GetArg<SfxUInt16Item>(SID_ATTR_TABLE_COLUMN);
+ const SfxUInt16Item* pRows = rReq.GetArg<SfxUInt16Item>(SID_ATTR_TABLE_ROW);
+ const SfxStringItem* pStyle = rReq.GetArg<SfxStringItem>(SID_TABLE_STYLE);
+
+ if( pCols )
+ nColumns = pCols->GetValue();
+
+ if( pRows )
+ nRows = pRows->GetValue();
+
+ if( pStyle )
+ sTableStyle = pStyle->GetValue();
+
+ if( (nColumns == 0) || (nRows == 0) )
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ std::shared_ptr<SvxAbstractNewTableDialog> pDlg( pFact->CreateSvxNewTableDialog(rReq.GetFrameWeld()) );
+
+ weld::DialogController::runAsync(pDlg->getDialogController(),
+ [pDlg, pShell, pView, sTableStyle] (sal_Int32 nResult) {
+ if (nResult == RET_OK)
+ {
+ sal_Int32 nColumnsIn = pDlg->getColumns();
+ sal_Int32 nRowsIn = pDlg->getRows();
+
+ InsertTableImpl(pShell, pView, nColumnsIn, nRowsIn, sTableStyle);
+ }
+ });
+ }
+ else
+ {
+ InsertTableImpl(pShell, pView, nColumns, nRows, sTableStyle);
+ }
+
+ rReq.Ignore();
+ SfxViewShell* pViewShell = GetViewShell();
+ OSL_ASSERT (pViewShell!=nullptr);
+ SfxBindings& rBindings = pViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_INSERT_TABLE, true );
+ break;
+ }
+ case SID_TABLEDESIGN:
+ {
+ // First make sure that the sidebar is visible
+ GetViewFrame()->ShowChildWindow(SID_SIDEBAR);
+ ::sfx2::sidebar::Sidebar::ShowPanel(
+ u"SdTableDesignPanel",
+ GetViewFrame()->GetFrame().GetFrameInterface());
+
+ Cancel();
+ rReq.Done ();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void DrawViewShell::GetTableMenuState( SfxItemSet &rSet )
+{
+ OUString aActiveLayer = mpDrawView->GetActiveLayer();
+ SdrPageView* pPV = mpDrawView->GetSdrPageView();
+
+ if(
+ ( !aActiveLayer.isEmpty() && pPV && ( pPV->IsLayerLocked(aActiveLayer) ||
+ !pPV->IsLayerVisible(aActiveLayer) ) ) ||
+ SD_MOD()->GetWaterCan() )
+ {
+ rSet.DisableItem( SID_INSERT_TABLE );
+ }
+}
+
+void CreateTableFromRTF( SvStream& rStream, SdDrawDocument* pModel )
+{
+ rStream.Seek( 0 );
+
+ if( !pModel )
+ return;
+
+ SdrPage* pPage = pModel->GetPage(0);
+ if( !pPage )
+ return;
+
+ Size aSize( 200, 200 );
+ ::tools::Rectangle aRect (Point(), aSize);
+ sdr::table::SdrTableObj* pObj = new sdr::table::SdrTableObj(
+ *pModel,
+ aRect,
+ 1,
+ 1);
+ pObj->NbcSetStyleSheet( pModel->GetDefaultStyleSheet(), true );
+ apply_table_style( pObj, pModel, OUString() );
+
+ pPage->NbcInsertObject( pObj );
+
+ sdr::table::ImportAsRTF( rStream, *pObj );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/table/tableobjectbar.cxx b/sd/source/ui/table/tableobjectbar.cxx
new file mode 100644
index 000000000..62d81d980
--- /dev/null
+++ b/sd/source/ui/table/tableobjectbar.cxx
@@ -0,0 +1,224 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/msgpool.hxx>
+#include <vcl/EnumContext.hxx>
+#include <svl/intitem.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/svxids.hrc>
+
+#include <createtableobjectbar.hxx>
+#include <registerinterfaces.hxx>
+
+#include <strings.hrc>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <sdmod.hxx>
+#include <sdresid.hxx>
+#include <DrawViewShell.hxx>
+
+#include "tableobjectbar.hxx"
+
+using namespace sd;
+using namespace sd::ui::table;
+
+#define ShellClass_TableObjectBar
+#include <sdslots.hxx>
+
+namespace sd::ui::table {
+
+/** creates a table object bar for the given ViewShell */
+SfxShell* CreateTableObjectBar( ViewShell& rShell, ::sd::View* pView )
+{
+ return new TableObjectBar( &rShell, pView );
+}
+
+/** registers the interfaces from the table ui */
+void RegisterInterfaces(const SfxModule* pMod)
+{
+ TableObjectBar::RegisterInterface(pMod);
+}
+
+
+SFX_IMPL_INTERFACE(TableObjectBar, SfxShell)
+
+void TableObjectBar::InitInterface_Impl()
+{
+}
+
+TableObjectBar::TableObjectBar( ViewShell* pSdViewShell, ::sd::View* pSdView )
+: SfxShell( pSdViewShell->GetViewShell() )
+, mpView( pSdView )
+, mpViewSh( pSdViewShell )
+{
+ DrawDocShell* pDocShell = mpViewSh->GetDocSh();
+ if( pDocShell )
+ {
+ SetPool( &pDocShell->GetPool() );
+ SetUndoManager( pDocShell->GetUndoManager() );
+ }
+ SetRepeatTarget( mpView );
+ SetName( SdResId( RID_DRAW_TABLE_TOOLBOX ) );
+ SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Table));
+}
+
+TableObjectBar::~TableObjectBar()
+{
+ SetRepeatTarget( nullptr );
+}
+
+void TableObjectBar::GetState( SfxItemSet& rSet )
+{
+ if( mpView )
+ {
+ rtl::Reference< sdr::SelectionController > xController( mpView->getSelectionController() );
+ if( xController.is() )
+ {
+ xController->GetState( rSet );
+ }
+ }
+}
+
+void TableObjectBar::GetAttrState( SfxItemSet& rSet )
+{
+ DrawViewShell* pDrawViewShell = dynamic_cast< DrawViewShell* >( mpViewSh );
+ if( pDrawViewShell )
+ pDrawViewShell->GetAttrState( rSet );
+}
+
+void TableObjectBar::Execute( SfxRequest& rReq )
+{
+ if( !mpView )
+ return;
+
+ SdrView* pView = mpView;
+ SfxBindings* pBindings = &mpViewSh->GetViewFrame()->GetBindings();
+
+ rtl::Reference< sdr::SelectionController > xController( mpView->getSelectionController() );
+ sal_uLong nSlotId = rReq.GetSlot();
+ if( xController.is() )
+ {
+ switch( nSlotId )
+ {
+ case SID_TABLE_INSERT_ROW_DLG:
+ case SID_TABLE_INSERT_ROW_BEFORE:
+ case SID_TABLE_INSERT_ROW_AFTER:
+ case SID_TABLE_INSERT_COL_DLG:
+ case SID_TABLE_INSERT_COL_BEFORE:
+ case SID_TABLE_INSERT_COL_AFTER:
+ {
+ ScopedVclPtr<SvxAbstractInsRowColDlg> pDlg;
+ if (nSlotId == SID_TABLE_INSERT_ROW_DLG || nSlotId == SID_TABLE_INSERT_COL_DLG)
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ vcl::Window* pWin = mpView->GetViewShell()->GetParentWindow();
+ pDlg.disposeAndReset( pFact->CreateSvxInsRowColDlg(pWin ? pWin->GetFrameWeld() : nullptr,
+ nSlotId == SID_TABLE_INSERT_COL_DLG,
+ SD_MOD()->GetSlotPool()->GetSlot(nSlotId)->GetCommand()) );
+
+ if (pDlg->Execute() != 1)
+ break;
+ }
+
+ sal_uInt16 nCount = 1;
+ bool bInsertAfter = (nSlotId == SID_TABLE_INSERT_ROW_AFTER) || (nSlotId == SID_TABLE_INSERT_COL_AFTER);
+
+ if (nSlotId == SID_TABLE_INSERT_ROW_DLG)
+ {
+ nCount = pDlg->getInsertCount();
+ bInsertAfter = !pDlg->isInsertBefore();
+ }
+ else if (nSlotId == SID_TABLE_INSERT_COL_DLG)
+ {
+ nCount = pDlg->getInsertCount();
+ bInsertAfter = !pDlg->isInsertBefore();
+ }
+
+ if (nSlotId == SID_TABLE_INSERT_ROW_DLG || nSlotId == SID_TABLE_INSERT_ROW_BEFORE || nSlotId == SID_TABLE_INSERT_ROW_AFTER)
+ nSlotId = SID_TABLE_INSERT_ROW;
+ else
+ nSlotId = SID_TABLE_INSERT_COL;
+
+ rReq.AppendItem(SfxInt16Item(static_cast<sal_uInt16>(nSlotId), nCount));
+ rReq.AppendItem(SfxBoolItem(SID_TABLE_PARAM_INSERT_AFTER, bInsertAfter));
+
+ rReq.SetSlot( static_cast<sal_uInt16>(nSlotId) );
+ }
+ }
+
+ xController->Execute( rReq );
+ }
+
+ // note: we may be deleted at this point, no more member access possible
+
+ switch( rReq.GetSlot() )
+ {
+ case SID_ATTR_BORDER:
+ case SID_TABLE_MERGE_CELLS:
+ case SID_TABLE_SPLIT_CELLS:
+ case SID_OPTIMIZE_TABLE:
+ case SID_TABLE_DELETE_ROW:
+ case SID_TABLE_DELETE_COL:
+ case SID_TABLE_DELETE_TABLE:
+ case SID_FORMAT_TABLE_DLG:
+ case SID_TABLE_INSERT_ROW:
+ case SID_TABLE_INSERT_COL:
+ {
+ pView->AdjustMarkHdl();
+ pBindings->Invalidate( SID_TABLE_DELETE_ROW );
+ pBindings->Invalidate( SID_TABLE_DELETE_COL );
+ pBindings->Invalidate( SID_TABLE_DELETE_TABLE );
+ pBindings->Invalidate( SID_FRAME_LINESTYLE );
+ pBindings->Invalidate( SID_FRAME_LINECOLOR );
+ pBindings->Invalidate( SID_ATTR_BORDER );
+ pBindings->Invalidate( SID_ATTR_FILL_STYLE );
+ pBindings->Invalidate( SID_ATTR_FILL_USE_SLIDE_BACKGROUND );
+ pBindings->Invalidate( SID_ATTR_FILL_TRANSPARENCE );
+ pBindings->Invalidate( SID_ATTR_FILL_FLOATTRANSPARENCE );
+ pBindings->Invalidate( SID_TABLE_MERGE_CELLS );
+ pBindings->Invalidate( SID_TABLE_SPLIT_CELLS );
+ pBindings->Invalidate( SID_OPTIMIZE_TABLE );
+ pBindings->Invalidate( SID_TABLE_VERT_BOTTOM );
+ pBindings->Invalidate( SID_TABLE_VERT_CENTER );
+ pBindings->Invalidate( SID_TABLE_VERT_NONE );
+ break;
+ }
+ case SID_TABLE_VERT_BOTTOM:
+ case SID_TABLE_VERT_CENTER:
+ case SID_TABLE_VERT_NONE:
+ {
+ pBindings->Invalidate( SID_TABLE_VERT_BOTTOM );
+ pBindings->Invalidate( SID_TABLE_VERT_CENTER );
+ pBindings->Invalidate( SID_TABLE_VERT_NONE );
+ break;
+ }
+ }
+
+ pBindings->Invalidate( SID_UNDO );
+ pBindings->Invalidate( SID_REDO );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/table/tableobjectbar.hxx b/sd/source/ui/table/tableobjectbar.hxx
new file mode 100644
index 000000000..c5d513bff
--- /dev/null
+++ b/sd/source/ui/table/tableobjectbar.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/shell.hxx>
+#include <glob.hxx>
+
+namespace sd {
+
+class View;
+class ViewShell;
+
+}
+
+namespace sd::ui::table {
+
+class TableObjectBar final : public SfxShell
+{
+public:
+ SFX_DECL_INTERFACE( SD_IF_SDDRAWTABLEOBJECTBAR )
+
+ TableObjectBar( ::sd::ViewShell* pSdViewShell, ::sd::View* pSdView);
+ virtual ~TableObjectBar() override;
+
+ void GetState( SfxItemSet& rSet );
+ void GetAttrState( SfxItemSet& rSet );
+ void Execute( SfxRequest& rReq );
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+ ::sd::View* mpView;
+ ::sd::ViewShell* mpViewSh;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/AsynchronousCall.cxx b/sd/source/ui/tools/AsynchronousCall.cxx
new file mode 100644
index 000000000..b7b70f63a
--- /dev/null
+++ b/sd/source/ui/tools/AsynchronousCall.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 <memory>
+#include <tools/AsynchronousCall.hxx>
+
+namespace sd::tools
+{
+AsynchronousCall::AsynchronousCall()
+ : maTimer("sd AsynchronousCall")
+{
+ maTimer.SetInvokeHandler(LINK(this, AsynchronousCall, TimerCallback));
+}
+
+AsynchronousCall::~AsynchronousCall()
+{
+ mpFunction.reset();
+ maTimer.Stop();
+}
+
+void AsynchronousCall::Post(const AsynchronousFunction& rFunction)
+{
+ mpFunction.reset(new AsynchronousFunction(rFunction));
+ maTimer.SetTimeout(10);
+ maTimer.Start();
+}
+
+IMPL_LINK(AsynchronousCall, TimerCallback, Timer*, pTimer, void)
+{
+ if (pTimer == &maTimer)
+ {
+ ::std::unique_ptr<AsynchronousFunction> pFunction;
+ pFunction.swap(mpFunction);
+ (*pFunction)();
+ }
+}
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/ConfigurationAccess.cxx b/sd/source/ui/tools/ConfigurationAccess.cxx
new file mode 100644
index 000000000..d359aeb18
--- /dev/null
+++ b/sd/source/ui/tools/ConfigurationAccess.cxx
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/ConfigurationAccess.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/util/XChangesBatch.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::tools {
+
+ConfigurationAccess::ConfigurationAccess (
+ const Reference<XComponentContext>& rxContext,
+ const OUString& rsRootName,
+ const WriteMode eMode)
+{
+ Reference<lang::XMultiServiceFactory> xProvider =
+ configuration::theDefaultProvider::get( rxContext );
+ Initialize(xProvider, rsRootName, eMode);
+}
+
+ConfigurationAccess::ConfigurationAccess (
+ const OUString& rsRootName,
+ const WriteMode eMode)
+{
+ Reference<lang::XMultiServiceFactory> xProvider =
+ configuration::theDefaultProvider::get( ::comphelper::getProcessComponentContext() );
+ Initialize(xProvider, rsRootName, eMode);
+}
+
+void ConfigurationAccess::Initialize (
+ const Reference<lang::XMultiServiceFactory>& rxProvider,
+ const OUString& rsRootName,
+ const WriteMode eMode)
+{
+ try
+ {
+ Sequence<Any> aCreationArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", Any(rsRootName)},
+ {"depth", Any(sal_Int32(-1))}
+ }));
+
+ OUString sAccessService;
+ if (eMode == READ_ONLY)
+ sAccessService = "com.sun.star.configuration.ConfigurationAccess";
+ else
+ sAccessService = "com.sun.star.configuration.ConfigurationUpdateAccess";
+
+ mxRoot = rxProvider->createInstanceWithArguments(
+ sAccessService,
+ aCreationArguments);
+ }
+ catch (Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd.tools");
+ }
+}
+
+Any ConfigurationAccess::GetConfigurationNode (
+ const OUString& sPathToNode)
+{
+ return GetConfigurationNode(
+ Reference<container::XHierarchicalNameAccess>(mxRoot, UNO_QUERY),
+ sPathToNode);
+}
+
+Any ConfigurationAccess::GetConfigurationNode (
+ const css::uno::Reference<css::container::XHierarchicalNameAccess>& rxNode,
+ const OUString& sPathToNode)
+{
+ if (sPathToNode.isEmpty())
+ return Any(rxNode);
+
+ try
+ {
+ if (rxNode.is())
+ {
+ return rxNode->getByHierarchicalName(sPathToNode);
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sd", "caught exception while getting configuration node" << sPathToNode);
+ }
+
+ return Any();
+}
+
+void ConfigurationAccess::CommitChanges()
+{
+ Reference<util::XChangesBatch> xConfiguration (mxRoot, UNO_QUERY);
+ if (xConfiguration.is())
+ xConfiguration->commitChanges();
+}
+
+void ConfigurationAccess::ForAll (
+ const Reference<container::XNameAccess>& rxContainer,
+ const ::std::vector<OUString>& rArguments,
+ const Functor& rFunctor)
+{
+ if (!rxContainer.is())
+ return;
+
+ ::std::vector<Any> aValues(rArguments.size());
+ const Sequence<OUString> aKeys (rxContainer->getElementNames());
+ for (const OUString& rsKey : aKeys)
+ {
+ Reference<container::XNameAccess> xSetItem (rxContainer->getByName(rsKey), UNO_QUERY);
+ if (xSetItem.is())
+ {
+ // Get from the current item of the container the children
+ // that match the names in the rArguments list.
+ for (size_t nValueIndex=0; nValueIndex<aValues.size(); ++nValueIndex)
+ aValues[nValueIndex] = xSetItem->getByName(rArguments[nValueIndex]);
+ }
+ rFunctor(rsKey, aValues);
+ }
+}
+
+void ConfigurationAccess::FillList(
+ const Reference<container::XNameAccess>& rxContainer,
+ const OUString& rsArgument,
+ ::std::vector<OUString>& rList)
+{
+ try
+ {
+ if (rxContainer.is())
+ {
+ Sequence<OUString> aKeys (rxContainer->getElementNames());
+ rList.resize(aKeys.getLength());
+ for (sal_Int32 nItemIndex=0; nItemIndex<aKeys.getLength(); ++nItemIndex)
+ {
+ Reference<container::XNameAccess> xSetItem (
+ rxContainer->getByName(aKeys[nItemIndex]), UNO_QUERY);
+ if (xSetItem.is())
+ {
+ xSetItem->getByName(rsArgument) >>= rList[nItemIndex];
+ }
+ }
+ }
+ }
+ catch (RuntimeException&)
+ {}
+}
+
+} // end of namespace sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/EventMultiplexer.cxx b/sd/source/ui/tools/EventMultiplexer.cxx
new file mode 100644
index 000000000..a61413ac6
--- /dev/null
+++ b/sd/source/ui/tools/EventMultiplexer.cxx
@@ -0,0 +1,661 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <EventMultiplexer.hxx>
+
+#include <ViewShellBase.hxx>
+#include <drawdoc.hxx>
+#include <DrawController.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <com/sun/star/drawing/framework/XView.hpp>
+#include <comphelper/compbase.hxx>
+#include <sfx2/viewfrm.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+class SdDrawDocument;
+
+namespace {
+const sal_Int32 ResourceActivationEvent = 0;
+const sal_Int32 ResourceDeactivationEvent = 1;
+const sal_Int32 ConfigurationUpdateEvent = 2;
+}
+
+namespace sd::tools {
+
+typedef comphelper::WeakComponentImplHelper<
+ css::beans::XPropertyChangeListener,
+ css::frame::XFrameActionListener,
+ css::view::XSelectionChangeListener,
+ css::drawing::framework::XConfigurationChangeListener
+ > EventMultiplexerImplementationInterfaceBase;
+
+class EventMultiplexer::Implementation
+ : public EventMultiplexerImplementationInterfaceBase,
+ public SfxListener
+{
+public:
+ explicit Implementation (ViewShellBase& rBase);
+ virtual ~Implementation() override;
+
+ void AddEventListener (
+ const Link<EventMultiplexerEvent&,void>& rCallback);
+
+ void RemoveEventListener (
+ const Link<EventMultiplexerEvent&,void>& rCallback);
+
+ void CallListeners (EventMultiplexerEvent& rEvent);
+
+ //===== lang::XEventListener ==============================================
+ virtual void SAL_CALL
+ disposing (const css::lang::EventObject& rEventObject) override;
+
+ //===== beans::XPropertySetListener =======================================
+ virtual void SAL_CALL
+ propertyChange (
+ const css::beans::PropertyChangeEvent& rEvent) override;
+
+ //===== view::XSelectionChangeListener ====================================
+ virtual void SAL_CALL
+ selectionChanged (
+ const css::lang::EventObject& rEvent) override;
+
+ //===== frame::XFrameActionListener ======================================
+ /** For certain actions the listener connects to a new controller of the
+ frame it is listening to. This usually happens when the view shell
+ in the center pane is replaced by another view shell.
+ */
+ virtual void SAL_CALL
+ frameAction (const css::frame::FrameActionEvent& rEvent) override;
+
+ //===== drawing::framework::XConfigurationChangeListener ==================
+ virtual void SAL_CALL
+ notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+protected:
+ virtual void Notify (
+ SfxBroadcaster& rBroadcaster,
+ const SfxHint& rHint) override;
+
+private:
+ ViewShellBase& mrBase;
+ typedef ::std::vector<Link<EventMultiplexerEvent&,void>> ListenerList;
+ ListenerList maListeners;
+
+ /// Remember whether we are listening to the UNO controller.
+ bool mbListeningToController;
+ /// Remember whether we are listening to the frame.
+ bool mbListeningToFrame;
+
+ css::uno::WeakReference<css::frame::XController> mxControllerWeak;
+ css::uno::WeakReference<css::frame::XFrame> mxFrameWeak;
+ SdDrawDocument* mpDocument;
+ css::uno::WeakReference<css::drawing::framework::XConfigurationController>
+ mxConfigurationControllerWeak;
+
+ void ReleaseListeners();
+
+ void ConnectToController();
+ void DisconnectFromController();
+
+ void CallListeners (
+ EventMultiplexerEventId eId,
+ void const * pUserData = nullptr);
+
+ DECL_LINK(SlideSorterSelectionChangeListener, LinkParamNone*, void);
+};
+
+constexpr OUStringLiteral aCurrentPagePropertyName = u"CurrentPage";
+constexpr OUStringLiteral aEditModePropertyName = u"IsMasterPageMode";
+
+//===== EventMultiplexer ======================================================
+
+EventMultiplexer::EventMultiplexer (ViewShellBase& rBase)
+ : mpImpl (new EventMultiplexer::Implementation(rBase))
+{
+}
+
+EventMultiplexer::~EventMultiplexer()
+{
+ try
+ {
+ mpImpl->dispose();
+ }
+ catch (const RuntimeException&)
+ {
+ }
+ catch (const Exception&)
+ {
+ }
+}
+
+void EventMultiplexer::AddEventListener (
+ const Link<EventMultiplexerEvent&,void>& rCallback)
+{
+ mpImpl->AddEventListener(rCallback);
+}
+
+void EventMultiplexer::RemoveEventListener (
+ const Link<EventMultiplexerEvent&,void>& rCallback)
+{
+ mpImpl->RemoveEventListener(rCallback);
+}
+
+void EventMultiplexer::MultiplexEvent(
+ EventMultiplexerEventId eEventId,
+ void const * pUserData )
+{
+ EventMultiplexerEvent aEvent(eEventId, pUserData);
+ mpImpl->CallListeners(aEvent);
+}
+
+//===== EventMultiplexer::Implementation ======================================
+
+EventMultiplexer::Implementation::Implementation (ViewShellBase& rBase)
+ : mrBase (rBase),
+ mbListeningToController (false),
+ mbListeningToFrame (false),
+ mxControllerWeak(nullptr),
+ mxFrameWeak(nullptr),
+ mpDocument(nullptr)
+{
+ // Connect to the frame to listen for controllers being exchanged.
+ // Listen to changes of certain properties.
+ Reference<frame::XFrame> xFrame =
+ mrBase.GetFrame()->GetFrame().GetFrameInterface();
+ mxFrameWeak = xFrame;
+ if (xFrame.is())
+ {
+ xFrame->addFrameActionListener ( Reference<frame::XFrameActionListener>(this) );
+ mbListeningToFrame = true;
+ }
+
+ // Connect to the current controller.
+ ConnectToController ();
+
+ // Listen for document changes.
+ mpDocument = mrBase.GetDocument();
+ if (mpDocument != nullptr)
+ StartListening (*mpDocument);
+
+ // Listen for configuration changes.
+ Reference<XControllerManager> xControllerManager (
+ Reference<XWeak>(&mrBase.GetDrawController()), UNO_QUERY);
+ if (!xControllerManager.is())
+ return;
+
+ Reference<XConfigurationController> xConfigurationController (
+ xControllerManager->getConfigurationController());
+ mxConfigurationControllerWeak = xConfigurationController;
+ if (!xConfigurationController.is())
+ return;
+
+ Reference<XComponent> xComponent (xConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(static_cast<beans::XPropertyChangeListener*>(this));
+
+ xConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationEvent,
+ Any(ResourceActivationEvent));
+ xConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceDeactivationEvent,
+ Any(ResourceDeactivationEvent));
+ xConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ Any(ConfigurationUpdateEvent));
+}
+
+EventMultiplexer::Implementation::~Implementation()
+{
+ DBG_ASSERT( !mbListeningToFrame,
+ "sd::EventMultiplexer::Implementation::~Implementation(), disposing was not called!" );
+}
+
+void EventMultiplexer::Implementation::ReleaseListeners()
+{
+ if (mbListeningToFrame)
+ {
+ mbListeningToFrame = false;
+
+ // Stop listening for changes of certain properties.
+ Reference<frame::XFrame> xFrame (mxFrameWeak);
+ if (xFrame.is())
+ {
+ xFrame->removeFrameActionListener (
+ Reference<frame::XFrameActionListener>(this) );
+ }
+ }
+
+ DisconnectFromController ();
+
+ if (mpDocument != nullptr)
+ {
+ EndListening (*mpDocument);
+ mpDocument = nullptr;
+ }
+
+ // Stop listening for configuration changes.
+ Reference<XConfigurationController> xConfigurationController (mxConfigurationControllerWeak);
+ if (xConfigurationController.is())
+ {
+ Reference<XComponent> xComponent (xConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(static_cast<beans::XPropertyChangeListener*>(this));
+
+ xConfigurationController->removeConfigurationChangeListener(this);
+ }
+}
+
+void EventMultiplexer::Implementation::AddEventListener (
+ const Link<EventMultiplexerEvent&,void>& rCallback)
+{
+ for (auto const & i : maListeners)
+ if (i == rCallback)
+ return;
+ maListeners.push_back(rCallback);
+}
+
+void EventMultiplexer::Implementation::RemoveEventListener (
+ const Link<EventMultiplexerEvent&,void>& rCallback)
+{
+ auto iListener = std::find(maListeners.begin(), maListeners.end(), rCallback);
+ if (iListener != maListeners.end())
+ maListeners.erase(iListener);
+}
+
+void EventMultiplexer::Implementation::ConnectToController()
+{
+ // Just in case that we missed some event we now disconnect from the old
+ // controller.
+ DisconnectFromController ();
+
+ // Register at the controller of the main view shell.
+
+ // We have to store a (weak) reference to the controller so that we can
+ // unregister without having to ask the mrBase member (which at that
+ // time may be destroyed.)
+ Reference<frame::XController> xController = mrBase.GetController();
+ mxControllerWeak = mrBase.GetController();
+
+ try
+ {
+ // Listen for disposing events.
+ if (xController.is())
+ {
+ xController->addEventListener (
+ Reference<lang::XEventListener>(
+ static_cast<XWeak*>(this), UNO_QUERY));
+ mbListeningToController = true;
+ }
+
+ // Listen to changes of certain properties.
+ Reference<beans::XPropertySet> xSet (xController, UNO_QUERY);
+ if (xSet.is())
+ {
+ try
+ {
+ xSet->addPropertyChangeListener(aCurrentPagePropertyName, this);
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ SAL_WARN("sd", "EventMultiplexer::ConnectToController: CurrentPage unknown");
+ }
+
+ try
+ {
+ xSet->addPropertyChangeListener(aEditModePropertyName, this);
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ SAL_WARN("sd", "EventMultiplexer::ConnectToController: IsMasterPageMode unknown");
+ }
+ }
+
+ // Listen for selection change events.
+ Reference<view::XSelectionSupplier> xSelection (xController, UNO_QUERY);
+ if (xSelection.is())
+ {
+ xSelection->addSelectionChangeListener(this);
+ }
+ }
+ catch (const lang::DisposedException&)
+ {
+ mbListeningToController = false;
+ }
+}
+
+void EventMultiplexer::Implementation::DisconnectFromController()
+{
+ if (!mbListeningToController)
+ return;
+
+ mbListeningToController = false;
+
+ Reference<frame::XController> xController = mxControllerWeak;
+
+ Reference<beans::XPropertySet> xSet (xController, UNO_QUERY);
+ // Remove the property listener.
+ if (xSet.is())
+ {
+ try
+ {
+ xSet->removePropertyChangeListener(aCurrentPagePropertyName, this);
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ SAL_WARN("sd", "DisconnectFromController: CurrentPage unknown");
+ }
+
+ try
+ {
+ xSet->removePropertyChangeListener(aEditModePropertyName, this);
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ SAL_WARN("sd", "DisconnectFromController: IsMasterPageMode unknown");
+ }
+ }
+
+ // Remove selection change listener.
+ Reference<view::XSelectionSupplier> xSelection (xController, UNO_QUERY);
+ if (xSelection.is())
+ {
+ xSelection->removeSelectionChangeListener(this);
+ }
+
+ // Remove listener for disposing events.
+ if (xController.is())
+ {
+ xController->removeEventListener (
+ Reference<lang::XEventListener>(static_cast<XWeak*>(this), UNO_QUERY));
+ }
+}
+
+//===== lang::XEventListener ================================================
+
+void SAL_CALL EventMultiplexer::Implementation::disposing (
+ const lang::EventObject& rEventObject)
+{
+ if (mbListeningToController)
+ {
+ Reference<frame::XController> xController (mxControllerWeak);
+ if (rEventObject.Source == xController)
+ {
+ mbListeningToController = false;
+ }
+ }
+
+ Reference<XConfigurationController> xConfigurationController (
+ mxConfigurationControllerWeak);
+ if (xConfigurationController.is()
+ && rEventObject.Source == xConfigurationController)
+ {
+ mxConfigurationControllerWeak.clear();
+ }
+}
+
+//===== beans::XPropertySetListener =========================================
+
+void SAL_CALL EventMultiplexer::Implementation::propertyChange (
+ const beans::PropertyChangeEvent& rEvent)
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException (
+ "SlideSorterController object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+
+ if ( rEvent.PropertyName == aCurrentPagePropertyName )
+ {
+ CallListeners(EventMultiplexerEventId::CurrentPageChanged);
+ }
+ else if ( rEvent.PropertyName == aEditModePropertyName )
+ {
+ bool bIsMasterPageMode (false);
+ rEvent.NewValue >>= bIsMasterPageMode;
+ if (bIsMasterPageMode)
+ CallListeners(EventMultiplexerEventId::EditModeMaster);
+ else
+ CallListeners(EventMultiplexerEventId::EditModeNormal);
+ }
+}
+
+//===== frame::XFrameActionListener ==========================================
+
+void SAL_CALL EventMultiplexer::Implementation::frameAction (
+ const frame::FrameActionEvent& rEvent)
+{
+ Reference<frame::XFrame> xFrame (mxFrameWeak);
+ if (rEvent.Frame != xFrame)
+ return;
+
+ switch (rEvent.Action)
+ {
+ case frame::FrameAction_COMPONENT_DETACHING:
+ DisconnectFromController();
+ CallListeners (EventMultiplexerEventId::ControllerDetached);
+ break;
+
+ case frame::FrameAction_COMPONENT_REATTACHED:
+ CallListeners (EventMultiplexerEventId::ControllerDetached);
+ DisconnectFromController();
+ ConnectToController();
+ CallListeners (EventMultiplexerEventId::ControllerAttached);
+ break;
+
+ case frame::FrameAction_COMPONENT_ATTACHED:
+ ConnectToController();
+ CallListeners (EventMultiplexerEventId::ControllerAttached);
+ break;
+
+ default:
+ break;
+ }
+}
+
+//===== view::XSelectionChangeListener ========================================
+
+void SAL_CALL EventMultiplexer::Implementation::selectionChanged (
+ const lang::EventObject& )
+{
+ CallListeners (EventMultiplexerEventId::EditViewSelection);
+}
+
+//===== drawing::framework::XConfigurationChangeListener ==================
+
+void SAL_CALL EventMultiplexer::Implementation::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ sal_Int32 nEventType = 0;
+ rEvent.UserData >>= nEventType;
+ switch (nEventType)
+ {
+ case ResourceActivationEvent:
+ if (rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix))
+ {
+ CallListeners (EventMultiplexerEventId::ViewAdded);
+
+ if (rEvent.ResourceId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
+ {
+ CallListeners (EventMultiplexerEventId::MainViewAdded);
+ }
+
+ // Add selection change listener at slide sorter.
+ if (rEvent.ResourceId->getResourceURL() == FrameworkHelper::msSlideSorterURL)
+ {
+ slidesorter::SlideSorterViewShell* pViewShell
+ = dynamic_cast<slidesorter::SlideSorterViewShell*>(
+ FrameworkHelper::GetViewShell(
+ Reference<XView>(rEvent.ResourceObject,UNO_QUERY)).get());
+ if (pViewShell != nullptr)
+ pViewShell->AddSelectionChangeListener (
+ LINK(this,
+ EventMultiplexer::Implementation,
+ SlideSorterSelectionChangeListener));
+ }
+ }
+ break;
+
+ case ResourceDeactivationEvent:
+ if (rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix))
+ {
+ if (rEvent.ResourceId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
+ {
+ CallListeners (EventMultiplexerEventId::MainViewRemoved);
+ }
+
+ // Remove selection change listener from slide sorter. Add
+ // selection change listener at slide sorter.
+ if (rEvent.ResourceId->getResourceURL() == FrameworkHelper::msSlideSorterURL)
+ {
+ slidesorter::SlideSorterViewShell* pViewShell
+ = dynamic_cast<slidesorter::SlideSorterViewShell*>(
+ FrameworkHelper::GetViewShell(
+ Reference<XView>(rEvent.ResourceObject, UNO_QUERY)).get());
+ if (pViewShell != nullptr)
+ pViewShell->RemoveSelectionChangeListener (
+ LINK(this,
+ EventMultiplexer::Implementation,
+ SlideSorterSelectionChangeListener));
+ }
+ }
+ break;
+
+ case ConfigurationUpdateEvent:
+ CallListeners (EventMultiplexerEventId::ConfigurationUpdated);
+ break;
+ }
+
+}
+
+void EventMultiplexer::Implementation::disposing(std::unique_lock<std::mutex>& rGuard)
+{
+ ListenerList aCopyListeners( maListeners );
+
+ rGuard.unlock();
+
+ EventMultiplexerEvent rEvent(EventMultiplexerEventId::Disposing, nullptr);
+ for (const auto& rListener : aCopyListeners)
+ rListener.Call(rEvent);
+
+ rGuard.lock();
+
+ ReleaseListeners();
+}
+
+void EventMultiplexer::Implementation::Notify (
+ SfxBroadcaster&,
+ const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ switch (pSdrHint->GetKind())
+ {
+ case SdrHintKind::ModelCleared:
+ case SdrHintKind::PageOrderChange:
+ CallListeners (EventMultiplexerEventId::PageOrder);
+ break;
+
+ case SdrHintKind::SwitchToPage:
+ CallListeners (EventMultiplexerEventId::CurrentPageChanged);
+ break;
+
+ case SdrHintKind::ObjectChange:
+ CallListeners(EventMultiplexerEventId::ShapeChanged,
+ static_cast<const void*>(pSdrHint->GetPage()));
+ break;
+
+ case SdrHintKind::ObjectInserted:
+ CallListeners(EventMultiplexerEventId::ShapeInserted,
+ static_cast<const void*>(pSdrHint->GetPage()));
+ break;
+
+ case SdrHintKind::ObjectRemoved:
+ CallListeners(EventMultiplexerEventId::ShapeRemoved,
+ static_cast<const void*>(pSdrHint->GetPage()));
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ if (rHint.GetId() == SfxHintId::Dying)
+ mpDocument = nullptr;
+ }
+}
+
+void EventMultiplexer::Implementation::CallListeners (
+ EventMultiplexerEventId eId,
+ void const * pUserData)
+{
+ EventMultiplexerEvent aEvent(eId, pUserData);
+ CallListeners(aEvent);
+}
+
+void EventMultiplexer::Implementation::CallListeners (EventMultiplexerEvent& rEvent)
+{
+ ListenerList aCopyListeners( maListeners );
+ for (const auto& rListener : aCopyListeners)
+ {
+ rListener.Call(rEvent);
+ }
+}
+
+IMPL_LINK_NOARG(EventMultiplexer::Implementation, SlideSorterSelectionChangeListener, LinkParamNone*, void)
+{
+ CallListeners(EventMultiplexerEventId::SlideSortedSelection);
+}
+
+//===== EventMultiplexerEvent =================================================
+
+EventMultiplexerEvent::EventMultiplexerEvent (
+ EventMultiplexerEventId eEventId,
+ const void* pUserData)
+ : meEventId(eEventId),
+ mpUserData(pUserData)
+{
+}
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/GraphicSizeCheck.cxx b/sd/source/ui/tools/GraphicSizeCheck.cxx
new file mode 100644
index 000000000..492a2d70b
--- /dev/null
+++ b/sd/source/ui/tools/GraphicSizeCheck.cxx
@@ -0,0 +1,221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <memory>
+#include <tools/GraphicSizeCheck.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdobj.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/dispatch.hxx>
+
+#include <sdresid.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+
+namespace sd
+{
+namespace
+{
+/**
+ * Interface for the visitor class, which handles each visited SdrObject
+ * in the DOM.
+ */
+class ModelTraverseHandler
+{
+public:
+ virtual ~ModelTraverseHandler() {}
+
+ virtual void handleSdrObject(SdrObject* pObject) = 0;
+};
+
+/**
+ * Traverses the DOM and calls a handler for each object (SdrObject) it
+ * encounters.
+ */
+class ModelTraverser
+{
+private:
+ std::vector<std::shared_ptr<ModelTraverseHandler>> m_pNodeHandler;
+ SdDrawDocument* m_pDocument;
+
+public:
+ ModelTraverser(SdDrawDocument* pDocument)
+ : m_pDocument(pDocument)
+ {
+ }
+
+ void traverse()
+ {
+ if (!m_pDocument)
+ return;
+
+ for (sal_uInt16 nPage = 0; nPage < m_pDocument->GetPageCount(); ++nPage)
+ {
+ SdrPage* pPage = m_pDocument->GetPage(nPage);
+ if (pPage)
+ {
+ for (size_t nObject = 0; nObject < pPage->GetObjCount(); ++nObject)
+ {
+ SdrObject* pObject = pPage->GetObj(nObject);
+ if (pObject)
+ {
+ for (auto& pNodeHandler : m_pNodeHandler)
+ {
+ pNodeHandler->handleSdrObject(pObject);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void addNodeHandler(std::shared_ptr<ModelTraverseHandler> pHandler)
+ {
+ m_pNodeHandler.push_back(pHandler);
+ }
+};
+}
+
+GraphicSizeViolation::GraphicSizeViolation(sal_Int32 nDPI, SdrGrafObj* pGraphicObject)
+ : m_pGraphicObject(pGraphicObject)
+{
+ constexpr double fLowPercentage = 110;
+ constexpr double fHighPercentage = 50;
+
+ m_nLowDPILimit = sal_Int32(100.0 / fLowPercentage * nDPI);
+ m_nHighDPILimit = sal_Int32(100.0 / fHighPercentage * nDPI);
+}
+
+bool GraphicSizeViolation::check()
+{
+ Graphic aGraphic = m_pGraphicObject->GetGraphic();
+ Size aSizePixel = aGraphic.GetSizePixel();
+ Size aGraphicSize = m_pGraphicObject->GetLogicRect().GetSize();
+
+ double nSizeXInch
+ = o3tl::convert(double(aGraphicSize.Width()), o3tl::Length::mm100, o3tl::Length::in);
+ double nSizeYInch
+ = o3tl::convert(double(aGraphicSize.Height()), o3tl::Length::mm100, o3tl::Length::in);
+
+ m_nDPIX = sal_Int32(aSizePixel.Width() / nSizeXInch);
+ m_nDPIY = sal_Int32(aSizePixel.Height() / nSizeYInch);
+
+ return isDPITooLow() || isDPITooHigh();
+}
+
+const OUString& GraphicSizeViolation::getGraphicName() { return m_pGraphicObject->GetName(); }
+
+namespace
+{
+class GraphicSizeCheckHandler : public ModelTraverseHandler
+{
+ sal_Int32 m_nDPI;
+ std::vector<std::unique_ptr<GraphicSizeViolation>>& m_rGraphicSizeViolationList;
+
+public:
+ GraphicSizeCheckHandler(
+ sal_Int32 nDPI,
+ std::vector<std::unique_ptr<GraphicSizeViolation>>& rGraphicSizeViolationList)
+ : m_nDPI(nDPI)
+ , m_rGraphicSizeViolationList(rGraphicSizeViolationList)
+ {
+ }
+
+ void handleSdrObject(SdrObject* pObject) override
+ {
+ auto* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject);
+ if (!pGraphicObject)
+ return;
+
+ auto pEntry = std::make_unique<GraphicSizeViolation>(m_nDPI, pGraphicObject);
+ if (pEntry->check())
+ {
+ m_rGraphicSizeViolationList.push_back(std::move(pEntry));
+ }
+ }
+};
+
+} // end anonymous namespace
+
+void GraphicSizeCheck::check()
+{
+ if (!m_pDocument)
+ return;
+
+ sal_Int32 nDPI = m_pDocument->getImagePreferredDPI();
+ if (nDPI == 0)
+ return;
+
+ auto pHandler = std::make_shared<GraphicSizeCheckHandler>(nDPI, m_aGraphicSizeViolationList);
+
+ ModelTraverser aModelTraverser(m_pDocument);
+ aModelTraverser.addNodeHandler(pHandler);
+ aModelTraverser.traverse();
+}
+
+OUString GraphicSizeCheckGUIEntry::getText()
+{
+ OUString sText;
+
+ if (m_pViolation->isDPITooLow())
+ {
+ sText = SdResId(STR_WARNING_GRAPHIC_PIXEL_COUNT_LOW);
+ }
+ else if (m_pViolation->isDPITooHigh())
+ {
+ sText = SdResId(STR_WARNING_GRAPHIC_PIXEL_COUNT_HIGH);
+ }
+
+ sText = sText.replaceAll("%NAME%", m_pViolation->getGraphicName());
+ sText = sText.replaceAll("%DPIX%", OUString::number(m_pViolation->getDPIX()));
+ sText = sText.replaceAll("%DPIY%", OUString::number(m_pViolation->getDPIY()));
+
+ return sText;
+}
+
+void GraphicSizeCheckGUIEntry::markObject()
+{
+ sd::ViewShell* pViewShell = m_pDocument->GetDocSh()->GetViewShell();
+ SdrView* pView = pViewShell->GetView();
+ pView->ShowSdrPage(m_pViolation->getObject()->getSdrPageFromSdrObject());
+ pView->UnmarkAll();
+ pView->MarkObj(m_pViolation->getObject(), pView->GetSdrPageView());
+}
+
+void GraphicSizeCheckGUIEntry::runProperties()
+{
+ markObject();
+ sd::ViewShell* pViewShell = m_pDocument->GetDocSh()->GetViewShell();
+ pViewShell->GetDispatcher()->Execute(SID_ATTR_GRAF_CROP, SfxCallMode::SYNCHRON);
+}
+
+GraphicSizeCheckGUIResult::GraphicSizeCheckGUIResult(SdDrawDocument* pDocument)
+{
+ GraphicSizeCheck aCheck(pDocument);
+ aCheck.check();
+
+ auto& rCollection = getCollection();
+ for (auto& rpViolation : aCheck.getViolationList())
+ {
+ auto rGUIEntry
+ = std::make_unique<GraphicSizeCheckGUIEntry>(pDocument, std::move(rpViolation));
+ rCollection.push_back(std::move(rGUIEntry));
+ }
+}
+
+OUString GraphicSizeCheckGUIResult::getTitle()
+{
+ return SdResId(STR_GRAPHIC_SIZE_CHECK_DIALOG_TITLE);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/IconCache.cxx b/sd/source/ui/tools/IconCache.cxx
new file mode 100644
index 000000000..0ce80922b
--- /dev/null
+++ b/sd/source/ui/tools/IconCache.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <tools/IconCache.hxx>
+
+#include <tools/debug.hxx>
+#include <osl/doublecheckedlocking.h>
+#include <osl/getglobalmutex.hxx>
+#include <unordered_map>
+
+namespace sd
+{
+//===== IconCache::Implementation =============================================
+
+class IconCache::Implementation
+{
+private:
+ friend class IconCache;
+
+ /** This pointer holds a valid reference from first time that
+ IconCache::Instance() is called to the end of the sd module when the
+ cache is destroyed from SdGlobalResourceContainer.
+ */
+ static IconCache* s_pIconCache;
+
+ typedef std::unordered_map<OUString, Image> ImageContainer;
+ ImageContainer maContainer;
+
+ Image GetIcon(const OUString& rResourceId);
+};
+
+IconCache* IconCache::Implementation::s_pIconCache = nullptr;
+
+Image IconCache::Implementation::GetIcon(const OUString& rResourceId)
+{
+ Image aResult;
+ ImageContainer::iterator iImage = maContainer.find(rResourceId);
+ if (iImage == maContainer.end())
+ {
+ aResult = Image(StockImage::Yes, rResourceId);
+ maContainer[rResourceId] = aResult;
+ }
+ else
+ aResult = iImage->second;
+ return aResult;
+}
+
+//===== IconCache =============================================================
+
+//static
+IconCache& IconCache::Instance()
+{
+ if (Implementation::s_pIconCache == nullptr)
+ {
+ ::osl::GetGlobalMutex aMutexFunctor;
+ ::osl::MutexGuard aGuard(aMutexFunctor());
+ if (Implementation::s_pIconCache == nullptr)
+ {
+ IconCache* pCache = new IconCache();
+ SdGlobalResourceContainer::Instance().AddResource(
+ ::std::unique_ptr<SdGlobalResource>(pCache));
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ Implementation::s_pIconCache = pCache;
+ }
+ }
+ else
+ {
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ }
+
+ DBG_ASSERT(Implementation::s_pIconCache != nullptr, "IconCache::Instance(): instance is NULL");
+ return *Implementation::s_pIconCache;
+}
+
+Image IconCache::GetIcon(const OUString& rResourceId) { return mpImpl->GetIcon(rResourceId); }
+
+IconCache::IconCache()
+ : mpImpl(new Implementation)
+{
+}
+
+IconCache::~IconCache()
+{
+ // empty
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/IdleDetection.cxx b/sd/source/ui/tools/IdleDetection.cxx
new file mode 100644
index 000000000..988bd849b
--- /dev/null
+++ b/sd/source/ui/tools/IdleDetection.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 <tools/IdleDetection.hxx>
+
+#include <slideshow.hxx>
+#include <ViewShellBase.hxx>
+
+#include <vcl/window.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd::tools {
+
+IdleState IdleDetection::GetIdleState (const vcl::Window* pWindow)
+{
+ IdleState nResult (CheckInputPending() | CheckSlideShowRunning());
+ if (pWindow != nullptr)
+ nResult |= CheckWindowPainting(*pWindow);
+ return nResult;
+}
+
+IdleState IdleDetection::CheckInputPending()
+{
+ if (Application::AnyInput(VclInputFlags::MOUSE | VclInputFlags::KEYBOARD | VclInputFlags::PAINT))
+ return IdleState::SystemEventPending;
+ else
+ return IdleState::Idle;
+}
+
+IdleState IdleDetection::CheckSlideShowRunning()
+{
+ IdleState eResult (IdleState::Idle);
+
+ // Iterate over all view frames.
+ for (SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst();
+ pViewFrame!=nullptr;
+ pViewFrame = SfxViewFrame::GetNext(*pViewFrame))
+ {
+ // Ignore the current frame when it does not exist, is not valid, or
+ // is not active.
+ bool bIgnoreFrame (true);
+ uno::Reference<frame::XFrame> xFrame (pViewFrame->GetFrame().GetFrameInterface());
+ try
+ {
+ if (xFrame.is() && xFrame->isActive())
+ bIgnoreFrame = false;
+ }
+ catch (const uno::RuntimeException&)
+ {
+ }
+ if (bIgnoreFrame)
+ continue;
+
+ // Get sd::ViewShell from active frame.
+ ViewShellBase* pBase = ViewShellBase::GetViewShellBase(pViewFrame);
+ if (pBase != nullptr)
+ {
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( *pBase ) );
+ if( xSlideShow.is() && xSlideShow->isRunning() )
+ {
+ if (xSlideShow->isFullScreen())
+ eResult |= IdleState::FullScreenShowActive;
+ else
+ eResult |= IdleState::WindowShowActive;
+ }
+ }
+ }
+
+ return eResult;
+}
+
+IdleState IdleDetection::CheckWindowPainting (const vcl::Window& rWindow)
+{
+ if (rWindow.IsInPaint())
+ return IdleState::WindowPainting;
+ else
+ return IdleState::Idle;
+}
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/PreviewRenderer.cxx b/sd/source/ui/tools/PreviewRenderer.cxx
new file mode 100644
index 000000000..be8d8ca20
--- /dev/null
+++ b/sd/source/ui/tools/PreviewRenderer.cxx
@@ -0,0 +1,532 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <PreviewRenderer.hxx>
+
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <drawview.hxx>
+#include <sdpage.hxx>
+#include <ViewShell.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/settings.hxx>
+
+#include <svx/svdpagv.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editstat.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/diagnose_ex.h>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+const int PreviewRenderer::snSubstitutionTextSize = 11;
+const int PreviewRenderer::snFrameWidth = 1;
+
+namespace {
+ /** This incarnation of the ViewObjectContactRedirector filters away all
+ PageObj objects, unconditionally.
+ */
+ class ViewRedirector : public sdr::contact::ViewObjectContactRedirector
+ {
+ public:
+ ViewRedirector();
+
+ virtual void createRedirectedPrimitive2DSequence(
+ const sdr::contact::ViewObjectContact& rOriginal,
+ const sdr::contact::DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) override;
+ };
+}
+
+//===== PreviewRenderer =======================================================
+
+PreviewRenderer::PreviewRenderer (
+ const bool bHasFrame)
+ : mpPreviewDevice (VclPtr<VirtualDevice>::Create()),
+ mpDocShellOfView(nullptr),
+ maFrameColor (svtools::ColorConfig().GetColorValue(svtools::DOCBOUNDARIES).nColor),
+ mbHasFrame(bHasFrame)
+{
+ mpPreviewDevice->SetBackground(Wallpaper(
+ Application::GetSettings().GetStyleSettings().GetWindowColor()));
+}
+
+PreviewRenderer::~PreviewRenderer()
+{
+ if (mpDocShellOfView != nullptr)
+ EndListening (*mpDocShellOfView);
+}
+
+Image PreviewRenderer::RenderPage (
+ const SdPage* pPage,
+ const sal_Int32 nWidth)
+{
+ if (pPage != nullptr)
+ {
+ const Size aPageModelSize (pPage->GetSize());
+ const double nAspectRatio (
+ double(aPageModelSize.Width()) / double(aPageModelSize.Height()));
+ const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0);
+ const sal_Int32 nHeight (sal::static_int_cast<sal_Int32>(
+ (nWidth - 2*nFrameWidth) / nAspectRatio + 2*nFrameWidth + 0.5));
+ return RenderPage (
+ pPage,
+ Size(nWidth,nHeight),
+ false/*bObeyHighContrastMode*/);
+ }
+ else
+ return Image();
+}
+
+Image PreviewRenderer::RenderPage (
+ const SdPage* pPage,
+ Size aPixelSize,
+ const bool bObeyHighContrastMode,
+ const bool bDisplayPresentationObjects)
+{
+ Image aPreview;
+
+ if (pPage != nullptr)
+ {
+ try
+ {
+ if (Initialize(pPage, aPixelSize, bObeyHighContrastMode))
+ {
+ PaintPage(pPage, bDisplayPresentationObjects);
+ PaintSubstitutionText("");
+ PaintFrame();
+
+ Size aSize (mpPreviewDevice->GetOutputSizePixel());
+ aPreview = Image(mpPreviewDevice->GetBitmapEx(
+ mpPreviewDevice->PixelToLogic(Point(0,0)),
+ mpPreviewDevice->PixelToLogic(aSize)));
+
+ mpView->HideSdrPage();
+ }
+ }
+ catch (const css::uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd.tools");
+ }
+ }
+
+ return aPreview;
+}
+
+Image PreviewRenderer::RenderSubstitution (
+ const Size& rPreviewPixelSize,
+ const OUString& rSubstitutionText)
+{
+ Image aPreview;
+
+ try
+ {
+ // Set size.
+ mpPreviewDevice->SetOutputSizePixel(rPreviewPixelSize);
+
+ // Adjust contrast mode.
+ const bool bUseContrast (
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode());
+ mpPreviewDevice->SetDrawMode (bUseContrast
+ ? sd::OUTPUT_DRAWMODE_CONTRAST
+ : sd::OUTPUT_DRAWMODE_COLOR);
+
+ // Set a map mode that makes a typical substitution text completely
+ // visible.
+ MapMode aMapMode (mpPreviewDevice->GetMapMode());
+ aMapMode.SetMapUnit(MapUnit::Map100thMM);
+ Fraction aFinalScale(25 * rPreviewPixelSize.Width(), 28000);
+ aMapMode.SetScaleX(aFinalScale);
+ aMapMode.SetScaleY(aFinalScale);
+ const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0);
+ aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(
+ Point(nFrameWidth,nFrameWidth),aMapMode));
+ mpPreviewDevice->SetMapMode (aMapMode);
+
+ // Clear the background.
+ const ::tools::Rectangle aPaintRectangle (
+ Point(0,0),
+ mpPreviewDevice->GetOutputSizePixel());
+ mpPreviewDevice->EnableMapMode(false);
+ mpPreviewDevice->SetLineColor();
+ svtools::ColorConfig aColorConfig;
+ mpPreviewDevice->SetFillColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
+ mpPreviewDevice->DrawRect (aPaintRectangle);
+ mpPreviewDevice->EnableMapMode();
+
+ // Paint substitution text and a frame around it.
+ PaintSubstitutionText (rSubstitutionText);
+ PaintFrame();
+
+ const Size aSize (mpPreviewDevice->GetOutputSizePixel());
+ aPreview = Image(mpPreviewDevice->GetBitmapEx(
+ mpPreviewDevice->PixelToLogic(Point(0,0)),
+ mpPreviewDevice->PixelToLogic(aSize)));
+ }
+ catch (const css::uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd.tools");
+ }
+
+ return aPreview;
+}
+
+bool PreviewRenderer::Initialize (
+ const SdPage* pPage,
+ const Size& rPixelSize,
+ const bool bObeyHighContrastMode)
+{
+ if (!pPage)
+ return false;
+
+ SetupOutputSize(*pPage, rPixelSize);
+ SdDrawDocument& rDocument(static_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
+ DrawDocShell* pDocShell = rDocument.GetDocSh();
+
+ if (!pDocShell)
+ return false;
+
+ // Create view
+ ProvideView (pDocShell);
+ if (mpView == nullptr)
+ return false;
+
+ // Adjust contrast mode.
+ bool bUseContrast (bObeyHighContrastMode
+ && Application::GetSettings().GetStyleSettings().GetHighContrastMode());
+ mpPreviewDevice->SetDrawMode (bUseContrast
+ ? sd::OUTPUT_DRAWMODE_CONTRAST
+ : sd::OUTPUT_DRAWMODE_COLOR);
+ mpPreviewDevice->SetSettings(Application::GetSettings());
+
+ // Tell the view to show the given page.
+ SdPage* pNonConstPage = const_cast<SdPage*>(pPage);
+ if (pPage->IsMasterPage())
+ {
+ mpView->ShowSdrPage(mpView->GetModel()->GetMasterPage(pPage->GetPageNum()));
+ }
+ else
+ {
+ mpView->ShowSdrPage(pNonConstPage);
+ }
+
+ // Make sure that a page view exists.
+ SdrPageView* pPageView = mpView->GetSdrPageView();
+
+ if (pPageView == nullptr)
+ return false;
+
+ // #i121224# No need to set SetApplicationBackgroundColor (which is the color
+ // of the area 'behind' the page (formerly called 'Wiese') since the page previews
+ // produced exactly cover the page's area, so it would never be visible. What
+ // needs to be set is the ApplicationDocumentColor which is derived from
+ // svtools::DOCCOLOR normally
+ Color aApplicationDocumentColor;
+
+ if (pPageView->GetApplicationDocumentColor() == COL_AUTO)
+ {
+ svtools::ColorConfig aColorConfig;
+ aApplicationDocumentColor = aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor;
+ }
+ else
+ {
+ aApplicationDocumentColor = pPageView->GetApplicationDocumentColor();
+ }
+
+ pPageView->SetApplicationDocumentColor(aApplicationDocumentColor);
+ SdrOutliner& rOutliner(rDocument.GetDrawOutliner());
+ rOutliner.SetBackgroundColor(aApplicationDocumentColor);
+ rOutliner.SetDefaultLanguage(rDocument.GetLanguage(EE_CHAR_LANGUAGE));
+ mpPreviewDevice->SetBackground(Wallpaper(aApplicationDocumentColor));
+ mpPreviewDevice->Erase();
+
+ return true;
+}
+
+void PreviewRenderer::PaintPage (
+ const SdPage* pPage,
+ const bool bDisplayPresentationObjects)
+{
+ // Paint the page.
+ ::tools::Rectangle aPaintRectangle (Point(0,0), pPage->GetSize());
+ vcl::Region aRegion (aPaintRectangle);
+
+ // Turn off online spelling and redlining.
+ SdrOutliner* pOutliner = nullptr;
+ EEControlBits nSavedControlWord = EEControlBits::NONE;
+ if (mpDocShellOfView!=nullptr && mpDocShellOfView->GetDoc()!=nullptr)
+ {
+ pOutliner = &mpDocShellOfView->GetDoc()->GetDrawOutliner();
+ nSavedControlWord = pOutliner->GetControlWord();
+ pOutliner->SetControlWord(nSavedControlWord & ~EEControlBits::ONLINESPELLING);
+ }
+
+ // Use a special redirector to prevent PresObj shapes from being painted.
+ std::unique_ptr<ViewRedirector> pRedirector;
+ if ( ! bDisplayPresentationObjects)
+ pRedirector.reset(new ViewRedirector());
+
+ try
+ {
+ mpView->CompleteRedraw(mpPreviewDevice.get(), aRegion, pRedirector.get());
+ }
+ catch (const css::uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd.tools");
+ }
+
+ // Restore the previous online spelling and redlining states.
+ if (pOutliner != nullptr)
+ pOutliner->SetControlWord(nSavedControlWord);
+}
+
+void PreviewRenderer::PaintSubstitutionText (const OUString& rSubstitutionText)
+{
+ if (rSubstitutionText.isEmpty())
+ return;
+
+ // Set the font size.
+ const vcl::Font& rOriginalFont (mpPreviewDevice->GetFont());
+ vcl::Font aFont (mpPreviewDevice->GetSettings().GetStyleSettings().GetAppFont());
+ sal_Int32 nHeight (mpPreviewDevice->PixelToLogic(Size(0,snSubstitutionTextSize)).Height());
+ aFont.SetFontHeight(nHeight);
+ mpPreviewDevice->SetFont (aFont);
+
+ // Paint the substitution text.
+ ::tools::Rectangle aTextBox (
+ Point(0,0),
+ mpPreviewDevice->PixelToLogic(
+ mpPreviewDevice->GetOutputSizePixel()));
+ DrawTextFlags const nTextStyle =
+ DrawTextFlags::Center
+ | DrawTextFlags::VCenter
+ | DrawTextFlags::MultiLine
+ | DrawTextFlags::WordBreak;
+ mpPreviewDevice->DrawText (aTextBox, rSubstitutionText, nTextStyle);
+
+ // Restore the font.
+ mpPreviewDevice->SetFont (rOriginalFont);
+}
+
+void PreviewRenderer::PaintFrame()
+{
+ if (mbHasFrame)
+ {
+ // Paint a frame around the preview.
+ ::tools::Rectangle aPaintRectangle (
+ Point(0,0),
+ mpPreviewDevice->GetOutputSizePixel());
+ mpPreviewDevice->EnableMapMode(false);
+ mpPreviewDevice->SetLineColor(maFrameColor);
+ mpPreviewDevice->SetFillColor();
+ mpPreviewDevice->DrawRect(aPaintRectangle);
+ mpPreviewDevice->EnableMapMode();
+ }
+}
+
+void PreviewRenderer::SetupOutputSize (
+ const SdPage& rPage,
+ const Size& rFramePixelSize)
+{
+ // First set the map mode to some arbitrary scale that is numerically
+ // stable.
+ MapMode aMapMode (mpPreviewDevice->GetMapMode());
+ aMapMode.SetMapUnit(MapUnit::MapPixel);
+
+ // Adapt it to the desired width.
+ const Size aPageModelSize (rPage.GetSize());
+ if (!aPageModelSize.IsEmpty())
+ {
+ const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0);
+ aMapMode.SetScaleX(
+ Fraction(rFramePixelSize.Width()-2*nFrameWidth-1, aPageModelSize.Width()));
+ aMapMode.SetScaleY(
+ Fraction(rFramePixelSize.Height()-2*nFrameWidth-1, aPageModelSize.Height()));
+ aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(Point(nFrameWidth,nFrameWidth),aMapMode));
+ }
+ else
+ {
+ // We should never get here.
+ OSL_ASSERT(false);
+ aMapMode.SetScaleX(Fraction(1.0));
+ aMapMode.SetScaleY(Fraction(1.0));
+ }
+ mpPreviewDevice->SetMapMode (aMapMode);
+ mpPreviewDevice->SetOutputSizePixel(rFramePixelSize);
+}
+
+void PreviewRenderer::ProvideView (DrawDocShell* pDocShell)
+{
+ if (pDocShell != mpDocShellOfView)
+ {
+ // Destroy the view that is connected to the current doc shell.
+ mpView.reset();
+
+ // Switch our attention, i.e. listening for DYING events, to
+ // the new doc shell.
+ if (mpDocShellOfView != nullptr)
+ EndListening (*mpDocShellOfView);
+ mpDocShellOfView = pDocShell;
+ if (mpDocShellOfView != nullptr)
+ StartListening (*mpDocShellOfView);
+ }
+ if (mpView == nullptr)
+ {
+ mpView.reset (new DrawView (pDocShell, mpPreviewDevice.get(), nullptr));
+ }
+ mpView->SetPreviewRenderer(true);
+#if 1
+ mpView->SetPageVisible(false);
+ mpView->SetPageBorderVisible();
+ mpView->SetBordVisible(false);
+ mpView->SetGridVisible(false);
+ mpView->SetHlplVisible(false);
+ mpView->SetGlueVisible(false);
+
+#else
+ // This works in the slide sorter but prevents the master page
+ // background being painted in the list of current master pages in the
+ // task manager.
+ mpView->SetPagePaintingAllowed(false);
+#endif
+}
+
+Image PreviewRenderer::ScaleBitmap (
+ const BitmapEx& rBitmapEx,
+ int nWidth)
+{
+ Image aPreview;
+
+ do
+ {
+ // Adjust contrast mode.
+ bool bUseContrast = Application::GetSettings().GetStyleSettings().
+ GetHighContrastMode();
+ mpPreviewDevice->SetDrawMode (bUseContrast
+ ? sd::OUTPUT_DRAWMODE_CONTRAST
+ : sd::OUTPUT_DRAWMODE_COLOR);
+
+ // Set output size.
+ Size aSize (rBitmapEx.GetSizePixel());
+ if (aSize.Width() <= 0)
+ break;
+ Size aFrameSize (
+ nWidth,
+ static_cast<::tools::Long>((nWidth*1.0 * aSize.Height()) / aSize.Width() + 0.5));
+ Size aPreviewSize (aFrameSize.Width()-2,aFrameSize.Height()-2);
+ MapMode aMapMode (mpPreviewDevice->GetMapMode());
+ aMapMode.SetMapUnit(MapUnit::MapPixel);
+ aMapMode.SetOrigin (Point());
+ aMapMode.SetScaleX (Fraction(1.0));
+ aMapMode.SetScaleY (Fraction(1.0));
+ mpPreviewDevice->SetMapMode (aMapMode);
+ mpPreviewDevice->SetOutputSize (aFrameSize);
+
+ // Paint a frame around the preview.
+ mpPreviewDevice->SetLineColor (maFrameColor);
+ mpPreviewDevice->SetFillColor ();
+ mpPreviewDevice->DrawRect (::tools::Rectangle(Point(0,0), aFrameSize));
+
+ // Paint the bitmap scaled to the desired width.
+ BitmapEx aScaledBitmap(rBitmapEx);
+ aScaledBitmap.Scale (aPreviewSize, BmpScaleFlag::BestQuality);
+ mpPreviewDevice->DrawBitmapEx (
+ Point(1,1),
+ aPreviewSize,
+ aScaledBitmap);
+
+ // Get the resulting bitmap.
+ aPreview = Image(mpPreviewDevice->GetBitmapEx(Point(0,0), aFrameSize));
+ }
+ while (false);
+
+ return aPreview;
+}
+
+void PreviewRenderer::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (!mpDocShellOfView)
+ return;
+
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ // The doc shell is dying. Our view uses its item pool and
+ // has to be destroyed as well. The next call to
+ // ProvideView will create a new one (for another
+ // doc shell, of course.)
+ mpView.reset();
+ mpDocShellOfView = nullptr;
+ }
+}
+
+//===== ViewRedirector ========================================================
+
+namespace {
+
+ViewRedirector::ViewRedirector()
+{
+}
+
+void ViewRedirector::createRedirectedPrimitive2DSequence(
+ const sdr::contact::ViewObjectContact& rOriginal,
+ const sdr::contact::DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+{
+ SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
+
+ if (pObject==nullptr || pObject->getSdrPageFromSdrObject() == nullptr)
+ {
+ // not a SdrObject visualisation (maybe e.g. page) or no page
+ sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
+ rOriginal,
+ rDisplayInfo,
+ rVisitor);
+ return;
+ }
+
+ const bool bDoCreateGeometry (pObject->getSdrPageFromSdrObject()->checkVisibility( rOriginal, rDisplayInfo, true));
+
+ if ( ! bDoCreateGeometry
+ && (pObject->GetObjInventor() != SdrInventor::Default || pObject->GetObjIdentifier() != SdrObjKind::Page))
+ {
+ return;
+ }
+
+ if (pObject->IsEmptyPresObj())
+ return;
+
+ sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
+ rOriginal,
+ rDisplayInfo,
+ rVisitor);
+}
+
+} // end of anonymous namespace
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/PropertySet.cxx b/sd/source/ui/tools/PropertySet.cxx
new file mode 100644
index 000000000..057b7dd96
--- /dev/null
+++ b/sd/source/ui/tools/PropertySet.cxx
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/PropertySet.hxx>
+#include <algorithm>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::tools {
+
+PropertySet::PropertySet()
+ : PropertySetInterfaceBase(m_aMutex),
+ mpChangeListeners(new ChangeListenerContainer)
+{
+}
+
+PropertySet::~PropertySet()
+{
+}
+
+void SAL_CALL PropertySet::disposing()
+{
+}
+
+//----- XPropertySet ----------------------------------------------------------
+
+Reference<beans::XPropertySetInfo> SAL_CALL PropertySet::getPropertySetInfo()
+{
+ return nullptr;
+}
+
+void SAL_CALL PropertySet::setPropertyValue (
+ const OUString& rsPropertyName,
+ const css::uno::Any& rsPropertyValue)
+{
+ ThrowIfDisposed();
+
+ Any aOldValue (SetPropertyValue(rsPropertyName,rsPropertyValue));
+ if (aOldValue == rsPropertyValue)
+ return;
+
+ // Inform listeners that are registered specifically for the
+ // property and those registered for any property.
+ beans::PropertyChangeEvent aEvent(
+ static_cast<XWeak*>(this),
+ rsPropertyName,
+ false,
+ -1,
+ aOldValue,
+ rsPropertyValue);
+ CallListeners(rsPropertyName, aEvent);
+ CallListeners(OUString(), aEvent);
+}
+
+Any SAL_CALL PropertySet::getPropertyValue (const OUString& rsPropertyName)
+{
+ ThrowIfDisposed();
+
+ return GetPropertyValue(rsPropertyName);
+}
+
+void SAL_CALL PropertySet::addPropertyChangeListener (
+ const OUString& rsPropertyName,
+ const css::uno::Reference<css::beans::XPropertyChangeListener>& rxListener)
+{
+ if ( ! rxListener.is())
+ throw lang::IllegalArgumentException();
+
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ return;
+
+ mpChangeListeners->emplace(rsPropertyName, rxListener);
+}
+
+void SAL_CALL PropertySet::removePropertyChangeListener (
+ const OUString& rsPropertyName,
+ const css::uno::Reference<css::beans::XPropertyChangeListener>& rxListener)
+{
+ ::std::pair<ChangeListenerContainer::iterator,ChangeListenerContainer::iterator>
+ aRange (mpChangeListeners->equal_range(rsPropertyName));
+
+ ChangeListenerContainer::iterator iListener (
+ ::std::find_if(
+ aRange.first,
+ aRange.second,
+ [&rxListener] (const ChangeListenerContainer::value_type& listener) {
+ return listener.second == rxListener;
+ }));
+
+ if (iListener == mpChangeListeners->end())
+ {
+ throw lang::IllegalArgumentException();
+ }
+
+ mpChangeListeners->erase(iListener);
+
+}
+
+void SAL_CALL PropertySet::addVetoableChangeListener (
+ const OUString&,
+ const css::uno::Reference<css::beans::XVetoableChangeListener>&)
+{
+ // Constraint properties are not supported and thus no vetoable
+ // listeners.
+}
+
+void SAL_CALL PropertySet::removeVetoableChangeListener (
+ const OUString&,
+ const css::uno::Reference<css::beans::XVetoableChangeListener>&)
+{
+ // Constraint properties are not supported and thus no vetoable
+ // listeners.
+}
+
+void PropertySet::CallListeners (
+ const OUString& rsPropertyName,
+ const beans::PropertyChangeEvent& rEvent)
+{
+ ::std::pair<ChangeListenerContainer::iterator,ChangeListenerContainer::iterator>
+ aRange (mpChangeListeners->equal_range(rsPropertyName));
+ ChangeListenerContainer::const_iterator iListener;
+ for (iListener=aRange.first; iListener!=aRange.second; ++iListener)
+ {
+ if (iListener->second.is())
+ iListener->second->propertyChange(rEvent);
+ }
+}
+
+void PropertySet::ThrowIfDisposed()
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ {
+ throw lang::DisposedException (
+ "PropertySet object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/SdGlobalResourceContainer.cxx b/sd/source/ui/tools/SdGlobalResourceContainer.cxx
new file mode 100644
index 000000000..a7dbc5f25
--- /dev/null
+++ b/sd/source/ui/tools/SdGlobalResourceContainer.cxx
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/SdGlobalResourceContainer.hxx>
+
+#include <../cache/SlsCacheConfiguration.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/unique_disposing_ptr.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+class SdGlobalResourceContainerInstance
+ : public comphelper::unique_disposing_solar_mutex_reset_ptr<SdGlobalResourceContainer>
+{
+public:
+ SdGlobalResourceContainerInstance()
+ : comphelper::unique_disposing_solar_mutex_reset_ptr<SdGlobalResourceContainer>(
+ uno::Reference<lang::XComponent>(frame::Desktop::create(comphelper::getProcessComponentContext()), uno::UNO_QUERY_THROW),
+ new SdGlobalResourceContainer, true)
+ {
+ }
+};
+
+namespace {
+
+SdGlobalResourceContainerInstance& theSdGlobalResourceContainerInstance()
+{
+ static SdGlobalResourceContainerInstance SINGLETON;
+ return SINGLETON;
+}
+
+} // namespace
+
+//===== SdGlobalResourceContainer::Implementation =============================
+
+class SdGlobalResourceContainer::Implementation
+{
+private:
+ friend class SdGlobalResourceContainer;
+
+ ::osl::Mutex maMutex;
+
+ /** All instances of SdGlobalResource in this vector are owned by the
+ container and will be destroyed when the container is destroyed.
+ */
+ std::vector<std::unique_ptr<SdGlobalResource>> maResources;
+
+ typedef ::std::vector<std::shared_ptr<SdGlobalResource> > SharedResourceList;
+ SharedResourceList maSharedResources;
+
+ typedef ::std::vector<Reference<XInterface> > XInterfaceResourceList;
+ XInterfaceResourceList maXInterfaceResources;
+};
+
+// static
+SdGlobalResourceContainer& SdGlobalResourceContainer::Instance()
+{
+ SdGlobalResourceContainer *const pRet(theSdGlobalResourceContainerInstance().get());
+ assert(pRet); // error if it has been deleted and is null
+ return *pRet;
+}
+
+//===== SdGlobalResourceContainer =============================================
+
+void SdGlobalResourceContainer::AddResource (
+ ::std::unique_ptr<SdGlobalResource> pResource)
+{
+ ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ assert( std::none_of(
+ mpImpl->maResources.begin(),
+ mpImpl->maResources.end(),
+ [&](const std::unique_ptr<SdGlobalResource>& p) { return p == pResource; })
+ && "duplicate resource?");
+
+ mpImpl->maResources.push_back(std::move(pResource));
+}
+
+void SdGlobalResourceContainer::AddResource (
+ const std::shared_ptr<SdGlobalResource>& pResource)
+{
+ ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ Implementation::SharedResourceList::iterator iResource = ::std::find (
+ mpImpl->maSharedResources.begin(),
+ mpImpl->maSharedResources.end(),
+ pResource);
+ if (iResource == mpImpl->maSharedResources.end())
+ mpImpl->maSharedResources.push_back(pResource);
+ else
+ {
+ SAL_WARN ("sd.tools",
+ "SdGlobalResourceContainer:AddResource(): Resource added twice.");
+ }
+}
+
+void SdGlobalResourceContainer::AddResource (const Reference<XInterface>& rxResource)
+{
+ ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ Implementation::XInterfaceResourceList::iterator iResource = ::std::find (
+ mpImpl->maXInterfaceResources.begin(),
+ mpImpl->maXInterfaceResources.end(),
+ rxResource);
+ if (iResource == mpImpl->maXInterfaceResources.end())
+ mpImpl->maXInterfaceResources.push_back(rxResource);
+ else
+ {
+ SAL_WARN ("sd.tools",
+ "SdGlobalResourceContainer:AddResource(): Resource added twice.");
+ }
+}
+
+SdGlobalResourceContainer::SdGlobalResourceContainer()
+ : mpImpl (new SdGlobalResourceContainer::Implementation)
+{
+}
+
+SdGlobalResourceContainer::~SdGlobalResourceContainer()
+{
+ ::osl::MutexGuard aGuard (mpImpl->maMutex);
+
+ // Release the resources in reversed order of their addition to the
+ // container. This is because a resource A added before resource B
+ // may have been created due to a request of B. Thus B depends on A and
+ // should be destroyed first.
+ for (auto iResource = mpImpl->maResources.rbegin();
+ iResource != mpImpl->maResources.rend();
+ ++iResource)
+ {
+ iResource->reset();
+ }
+
+
+ // The SharedResourceList has not to be released manually. We just
+ // assert resources that are still held by someone other than us.
+ Implementation::SharedResourceList::reverse_iterator iSharedResource;
+ for (iSharedResource = mpImpl->maSharedResources.rbegin();
+ iSharedResource != mpImpl->maSharedResources.rend();
+ ++iSharedResource)
+ {
+ if (iSharedResource->use_count() > 1)
+ {
+ SdGlobalResource* pResource = iSharedResource->get();
+ SAL_INFO(
+ "sd.tools", pResource << " " << iSharedResource->use_count());
+ DBG_ASSERT(iSharedResource->use_count() == 1,
+ "SdGlobalResource still held in ~SdGlobalResourceContainer");
+ }
+ }
+
+ Implementation::XInterfaceResourceList::reverse_iterator iXInterfaceResource;
+ for (iXInterfaceResource = mpImpl->maXInterfaceResources.rbegin();
+ iXInterfaceResource != mpImpl->maXInterfaceResources.rend();
+ ++iXInterfaceResource)
+ {
+ Reference<lang::XComponent> xComponent (*iXInterfaceResource, UNO_QUERY);
+ *iXInterfaceResource = nullptr;
+ if (xComponent.is())
+ xComponent->dispose();
+ }
+
+ sd::slidesorter::cache::CacheConfiguration::Shutdown();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/SlotStateListener.cxx b/sd/source/ui/tools/SlotStateListener.cxx
new file mode 100644
index 000000000..9b75b322e
--- /dev/null
+++ b/sd/source/ui/tools/SlotStateListener.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 <tools/SlotStateListener.hxx>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+
+#include <comphelper/processfactory.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd::tools {
+
+SlotStateListener::SlotStateListener (
+ Link<const OUString&,void> const & rCallback,
+ const uno::Reference<frame::XDispatchProvider>& rxDispatchProvider,
+ const OUString& rSlotName)
+ : mxDispatchProviderWeak(nullptr)
+{
+ SetCallback(rCallback);
+ ConnectToDispatchProvider(rxDispatchProvider);
+ ObserveSlot(rSlotName);
+}
+
+SlotStateListener::~SlotStateListener()
+{
+ ReleaseListeners();
+}
+
+void SlotStateListener::SetCallback (const Link<const OUString&,void>& rCallback)
+{
+ ThrowIfDisposed();
+
+ maCallback = rCallback;
+}
+
+void SlotStateListener::ConnectToDispatchProvider (
+ const uno::Reference<frame::XDispatchProvider>& rxDispatchProvider)
+{
+ ThrowIfDisposed();
+
+ // When we are listening to state changes of slots of another frame then
+ // release these listeners first.
+ if ( ! maRegisteredURLList.empty())
+ ReleaseListeners();
+
+ mxDispatchProviderWeak = rxDispatchProvider;
+}
+
+void SlotStateListener::ObserveSlot (const OUString& rSlotName)
+{
+ ThrowIfDisposed();
+
+ if (maCallback.IsSet())
+ {
+ // Connect the state change listener.
+ util::URL aURL (MakeURL(rSlotName));
+ uno::Reference<frame::XDispatch> xDispatch (GetDispatch(aURL));
+ if (xDispatch.is())
+ {
+ maRegisteredURLList.push_back(aURL);
+ xDispatch->addStatusListener(this,aURL);
+ }
+ }
+}
+
+void SlotStateListener::disposing(std::unique_lock<std::mutex>&)
+{
+ ReleaseListeners();
+ mxDispatchProviderWeak.clear();
+ maCallback = Link<const OUString&,void>();
+}
+
+util::URL SlotStateListener::MakeURL (const OUString& rSlotName)
+{
+ util::URL aURL;
+ aURL.Complete = rSlotName;
+
+ uno::Reference<util::XURLTransformer> xTransformer(util::URLTransformer::create(::comphelper::getProcessComponentContext()));
+ xTransformer->parseStrict(aURL);
+
+ return aURL;
+}
+
+uno::Reference<frame::XDispatch>
+ SlotStateListener::GetDispatch (const util::URL& rURL) const
+{
+ uno::Reference<frame::XDispatch> xDispatch;
+
+ uno::Reference<frame::XDispatchProvider> xDispatchProvider (mxDispatchProviderWeak);
+ if (xDispatchProvider.is())
+ xDispatch = xDispatchProvider->queryDispatch(rURL, OUString(), 0);
+
+ return xDispatch;
+}
+
+void SlotStateListener::statusChanged (
+ const frame::FeatureStateEvent& rState)
+{
+ ThrowIfDisposed();
+ OUString sSlotName (rState.FeatureURL.Complete);
+ maCallback.Call(sSlotName);
+}
+
+void SlotStateListener::ReleaseListeners()
+{
+ for (const auto& rURL : maRegisteredURLList)
+ {
+ uno::Reference<frame::XDispatch> xDispatch (GetDispatch(rURL));
+ if (xDispatch.is())
+ {
+ xDispatch->removeStatusListener(this,rURL);
+ }
+ }
+}
+
+//===== lang::XEventListener ================================================
+
+void SAL_CALL SlotStateListener::disposing (
+ const lang::EventObject& )
+{
+}
+
+void SlotStateListener::ThrowIfDisposed()
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("SlideSorterController object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/TimerBasedTaskExecution.cxx b/sd/source/ui/tools/TimerBasedTaskExecution.cxx
new file mode 100644
index 000000000..ae1f2233f
--- /dev/null
+++ b/sd/source/ui/tools/TimerBasedTaskExecution.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/TimerBasedTaskExecution.hxx>
+#include <tools/AsynchronousTask.hxx>
+#include <tools/time.hxx>
+#include <sal/log.hxx>
+#include <memory>
+
+namespace sd::tools {
+
+/** Used by the shared_ptr instead of the private destructor.
+*/
+class TimerBasedTaskExecution::Deleter
+{
+public:
+ void operator() (TimerBasedTaskExecution* pObject)
+ {
+ delete pObject;
+ }
+};
+
+std::shared_ptr<TimerBasedTaskExecution> TimerBasedTaskExecution::Create (
+ const std::shared_ptr<AsynchronousTask>& rpTask,
+ sal_uInt32 nMillisecondsBetweenSteps,
+ sal_uInt32 nMaxTimePerStep)
+{
+ std::shared_ptr<TimerBasedTaskExecution> pExecution(
+ new TimerBasedTaskExecution(rpTask,nMillisecondsBetweenSteps,nMaxTimePerStep),
+ Deleter());
+ // Let the new object have a shared_ptr to itself, so that it can
+ // release itself when the AsynchronousTask has been executed
+ // completely.
+ if (pExecution->mpTask != nullptr)
+ pExecution->mpSelf = pExecution;
+ return pExecution;
+}
+
+void TimerBasedTaskExecution::Release()
+{
+ maTimer.Stop();
+ mpSelf.reset();
+}
+
+//static
+void TimerBasedTaskExecution::ReleaseTask (
+ const std::weak_ptr<TimerBasedTaskExecution>& rpExecution)
+{
+ if ( rpExecution.expired())
+ return;
+
+ try
+ {
+ std::shared_ptr<tools::TimerBasedTaskExecution> pExecution (rpExecution);
+ pExecution->Release();
+ }
+ catch (const std::bad_weak_ptr&)
+ {
+ // When a bad_weak_ptr has been thrown then the object pointed
+ // to by rpTask has been released right after we checked that it
+ // still existed. Too bad, but that means, that we have nothing
+ // more do.
+ }
+}
+
+TimerBasedTaskExecution::TimerBasedTaskExecution (
+ const std::shared_ptr<AsynchronousTask>& rpTask,
+ sal_uInt32 nMillisecondsBetweenSteps,
+ sal_uInt32 nMaxTimePerStep)
+ : mpTask(rpTask),
+ maTimer("sd TimerBasedTaskExecution maTimer"),
+ mnMaxTimePerStep(nMaxTimePerStep)
+{
+ maTimer.SetInvokeHandler( LINK(this,TimerBasedTaskExecution,TimerCallback) );
+ maTimer.SetTimeout(nMillisecondsBetweenSteps);
+ maTimer.Start();
+}
+
+TimerBasedTaskExecution::~TimerBasedTaskExecution()
+{
+ maTimer.Stop();
+}
+
+IMPL_LINK_NOARG(TimerBasedTaskExecution, TimerCallback, Timer *, void)
+{
+ if (mpTask == nullptr)
+ return;
+
+ if (mpTask->HasNextStep())
+ {
+ // Execute as many steps as fit into the time span of length
+ // mnMaxTimePerStep. Note that the last step may take longer
+ // than allowed.
+ sal_uInt32 nStartTime (::tools::Time( ::tools::Time::SYSTEM ).GetMSFromTime());
+ SAL_INFO("sd.tools", __func__ << ": starting TimerBasedTaskExecution at " << nStartTime);
+ do
+ {
+ mpTask->RunNextStep();
+ sal_uInt32 nDuration (::tools::Time( ::tools::Time::SYSTEM ).GetMSFromTime()-nStartTime);
+ SAL_INFO("sd.tools", __func__ << ": executed step in " << nDuration);
+ if (nDuration > mnMaxTimePerStep)
+ break;
+ }
+ while (mpTask->HasNextStep());
+ SAL_INFO("sd.tools", __func__ << ": TimerBasedTaskExecution sleeping");
+ maTimer.Start();
+ }
+ else
+ mpSelf.reset();
+}
+
+} // end of namespace ::sd::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/uitest/uiobject.cxx b/sd/source/ui/uitest/uiobject.cxx
new file mode 100644
index 000000000..afd130ee2
--- /dev/null
+++ b/sd/source/ui/uitest/uiobject.cxx
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <memory>
+#include <uiobject.hxx>
+
+#include <Window.hxx>
+#include <DrawViewShell.hxx>
+#include <sdpage.hxx>
+
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svx/uiobject.hxx>
+#include <tools/debug.hxx>
+
+namespace
+{
+class ImpressSdrObject : public SdrUIObject
+{
+public:
+ ImpressSdrObject(const VclPtr<sd::Window>& xImpressWin, const OUString& rName);
+
+ SdrObject* get_object() override;
+
+private:
+ VclPtr<sd::Window> mxWindow;
+
+ OUString maName;
+};
+
+sd::DrawViewShell* getViewShell(const VclPtr<sd::Window>& xWindow)
+{
+ sd::DrawViewShell* pViewShell = dynamic_cast<sd::DrawViewShell*>(xWindow->GetViewShell());
+ assert(pViewShell);
+
+ return pViewShell;
+}
+
+OUString getObjectName(SdrObject const* pObject)
+{
+ if (pObject->GetName().isEmpty())
+ return "Unnamed Drawinglayer object " + OUString::number(pObject->GetOrdNum());
+ else
+ return pObject->GetName();
+}
+
+SdrObject* getObject(const VclPtr<sd::Window>& xWindow, std::u16string_view rName)
+{
+ SdrPage* pPage = getViewShell(xWindow)->getCurrentPage();
+
+ if (!pPage)
+ return nullptr;
+
+ size_t nObjs = pPage->GetObjCount();
+ for (size_t i = 0; i < nObjs; ++i)
+ {
+ SdrObject* pObj = pPage->GetObj(i);
+ if (rName == getObjectName(pObj))
+ return pObj;
+ }
+
+ return nullptr;
+}
+}
+
+ImpressSdrObject::ImpressSdrObject(const VclPtr<sd::Window>& xImpressWin, const OUString& rName)
+ : mxWindow(xImpressWin)
+ , maName(rName)
+{
+}
+
+SdrObject* ImpressSdrObject::get_object() { return getObject(mxWindow, maName); }
+
+ImpressWindowUIObject::ImpressWindowUIObject(const VclPtr<sd::Window>& xWindow)
+ : WindowUIObject(xWindow)
+ , mxWindow(xWindow)
+{
+}
+
+StringMap ImpressWindowUIObject::get_state()
+{
+ StringMap aMap = WindowUIObject::get_state();
+
+ aMap["SelectedText"] = getViewShell(mxWindow)->GetSelectionText(false);
+ aMap["CurrentSlide"] = OUString::number(getViewShell(mxWindow)->GetCurPagePos() + 1);
+ aMap["Zoom"] = OUString::number(getViewShell(mxWindow)->GetZoom());
+
+ return aMap;
+}
+
+void ImpressWindowUIObject::execute(const OUString& rAction, const StringMap& rParameters)
+{
+ if (rAction == "SET")
+ {
+ if (rParameters.find("ZOOM") != rParameters.end())
+ {
+ auto itr = rParameters.find("ZOOM");
+ OUString aVal = itr->second;
+ sal_Int32 nVal = aVal.toInt32();
+ getViewShell(mxWindow)->SetZoom(nVal);
+ }
+ }
+ else if (rAction == "GOTO")
+ {
+ if (rParameters.find("PAGE") != rParameters.end())
+ {
+ auto itr = rParameters.find("PAGE");
+ OUString aVal = itr->second;
+ sal_Int32 nVal = aVal.toInt32();
+ getViewShell(mxWindow)->SwitchPage(nVal - 1);
+ }
+ }
+ else if (rAction == "SELECT")
+ {
+ if (rParameters.find("OBJECT") != rParameters.end())
+ {
+ auto itr = rParameters.find("OBJECT");
+ OUString aName = itr->second;
+ SdrObject* pObj = getObject(mxWindow, aName);
+ SdrPageView* pPageView = getViewShell(mxWindow)->GetView()->GetSdrPageView();
+ getViewShell(mxWindow)->GetView()->MarkObj(pObj, pPageView);
+ }
+ }
+ else if (rAction == "SIDEBAR")
+ {
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ DBG_ASSERT(pViewFrm, "ImpressWindowUIObject::execute: no viewframe");
+ pViewFrm->ShowChildWindow(SID_SIDEBAR);
+
+ auto itr = rParameters.find("PANEL");
+ if (itr != rParameters.end())
+ {
+ OUString aVal = itr->second;
+ ::sfx2::sidebar::Sidebar::ShowPanel(aVal, pViewFrm->GetFrame().GetFrameInterface());
+ }
+ }
+ else if (rAction == "DESELECT")
+ {
+ getViewShell(mxWindow)->GetView()->UnMarkAll();
+ }
+ else
+ WindowUIObject::execute(rAction, rParameters);
+}
+
+std::unique_ptr<UIObject> ImpressWindowUIObject::get_child(const OUString& rID)
+{
+ return std::unique_ptr<UIObject>(new ImpressSdrObject(mxWindow, rID));
+}
+
+std::set<OUString> ImpressWindowUIObject::get_children() const
+{
+ SdrPage* pPage = getViewShell(mxWindow)->getCurrentPage();
+
+ std::set<OUString> aRet;
+ if (!pPage)
+ return aRet;
+
+ size_t nObjs = pPage->GetObjCount();
+ for (size_t i = 0; i < nObjs; ++i)
+ {
+ SdrObject* pObject = pPage->GetObj(i);
+ aRet.insert(getObjectName(pObject));
+ }
+
+ return aRet;
+}
+
+OUString ImpressWindowUIObject::get_name() const { return "ImpressWindowUIObject"; }
+
+std::unique_ptr<UIObject> ImpressWindowUIObject::create(vcl::Window* pWindow)
+{
+ sd::Window* pWin = dynamic_cast<sd::Window*>(pWindow);
+ assert(pWin);
+ return std::unique_ptr<UIObject>(new ImpressWindowUIObject(pWin));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/DrawController.cxx b/sd/source/ui/unoidl/DrawController.cxx
new file mode 100644
index 000000000..e4afc842a
--- /dev/null
+++ b/sd/source/ui/unoidl/DrawController.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 <DrawController.hxx>
+
+#include <sdpage.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <FormShellManager.hxx>
+#include <Window.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/drawing/framework/ConfigurationController.hpp>
+#include <com/sun/star/drawing/framework/ModuleController.hpp>
+#include <com/sun/star/drawing/XDrawSubController.hpp>
+#include <com/sun/star/drawing/XLayer.hpp>
+
+#include <slideshow.hxx>
+
+#include <sal/log.hxx>
+#include <svx/fmshell.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/EnumContext.hxx>
+#include <svx/sidebar/ContextChangeEventMultiplexer.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <memory>
+
+using namespace ::std;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using vcl::EnumContext;
+
+namespace sd {
+
+DrawController::DrawController (ViewShellBase& rBase) noexcept
+ : DrawControllerInterfaceBase(&rBase),
+ BroadcastHelperOwner(SfxBaseController::m_aMutex),
+ OPropertySetHelper(BroadcastHelperOwner::maBroadcastHelper),
+ mpCurrentLayer(nullptr),
+ m_aSelectionTypeIdentifier(
+ cppu::UnoType<view::XSelectionChangeListener>::get()),
+ mpBase(&rBase),
+ mpCurrentPage(nullptr),
+ mbMasterPageMode(false),
+ mbLayerMode(false),
+ mbDisposing(false)
+{
+ ProvideFrameworkControllers();
+}
+
+DrawController::~DrawController() noexcept
+{
+}
+
+void DrawController::SetSubController (
+ const Reference<drawing::XDrawSubController>& rxSubController)
+{
+ // Update the internal state.
+ mxSubController = rxSubController;
+ mpPropertyArrayHelper.reset();
+ maLastVisArea = ::tools::Rectangle();
+
+ // Inform listeners about the changed state.
+ FireSelectionChangeListener();
+}
+
+// XInterface
+
+IMPLEMENT_FORWARD_XINTERFACE2(
+ DrawController,
+ DrawControllerInterfaceBase,
+ OPropertySetHelper);
+
+// XTypeProvider
+
+Sequence<Type> SAL_CALL DrawController::getTypes()
+{
+ ThrowIfDisposed();
+ // OPropertySetHelper does not provide getTypes, so we have to
+ // implement this method manually and list its three interfaces.
+ OTypeCollection aTypeCollection (
+ cppu::UnoType<beans::XMultiPropertySet>::get(),
+ cppu::UnoType<beans::XFastPropertySet>::get(),
+ cppu::UnoType<beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(
+ SfxBaseController::getTypes(),
+ aTypeCollection.getTypes(),
+ DrawControllerInterfaceBase::getTypes());
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID(DrawController);
+
+// XComponent
+
+void SAL_CALL DrawController::dispose()
+{
+ if( mbDisposing )
+ return;
+
+ SolarMutexGuard aGuard;
+
+ if( mbDisposing )
+ return;
+
+ mbDisposing = true;
+
+ std::shared_ptr<ViewShell> pViewShell;
+ if (mpBase)
+ pViewShell = mpBase->GetMainViewShell();
+ if ( pViewShell )
+ {
+ pViewShell->DeactivateCurrentFunction();
+ auto* pView = pViewShell->GetView();
+ if (pView)
+ pView->getSearchContext().resetSearchFunction();
+ }
+ pViewShell.reset();
+
+ // When the controller has not been detached from its view
+ // shell, i.e. mpViewShell is not NULL, then tell PaneManager
+ // and ViewShellManager to clear the shell stack.
+ if (mxSubController.is() && mpBase!=nullptr)
+ {
+ mpBase->DisconnectAllClients();
+ mpBase->GetViewShellManager()->Shutdown();
+ }
+
+ OPropertySetHelper::disposing();
+
+ DisposeFrameworkControllers();
+
+ SfxBaseController::dispose();
+}
+
+void SAL_CALL DrawController::addEventListener(
+ const Reference<lang::XEventListener >& xListener)
+{
+ ThrowIfDisposed();
+ SfxBaseController::addEventListener( xListener );
+}
+
+void SAL_CALL DrawController::removeEventListener (
+ const Reference<lang::XEventListener >& aListener)
+{
+ if(!rBHelper.bDisposed && !rBHelper.bInDispose && !mbDisposing)
+ SfxBaseController::removeEventListener( aListener );
+}
+
+// XController
+sal_Bool SAL_CALL DrawController::suspend( sal_Bool Suspend )
+{
+ if( Suspend )
+ {
+ ViewShellBase* pViewShellBase = GetViewShellBase();
+ if( pViewShellBase )
+ {
+ // do not allow suspend if a slideshow needs this controller!
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( *pViewShellBase ) );
+ if( xSlideShow.is() && xSlideShow->dependsOn(pViewShellBase) )
+ return false;
+ }
+ }
+
+ return SfxBaseController::suspend( Suspend );
+}
+
+// XServiceInfo
+OUString SAL_CALL DrawController::getImplementationName( )
+{
+ // Do not throw an exception at the moment. This leads to a crash
+ // under Solaris on reload. See issue i70929 for details.
+ // ThrowIfDisposed();
+ return "DrawController" ;
+}
+
+constexpr OUStringLiteral ssServiceName = u"com.sun.star.drawing.DrawingDocumentDrawView";
+
+sal_Bool SAL_CALL DrawController::supportsService (const OUString& rsServiceName)
+{
+ return cppu::supportsService(this, rsServiceName);
+}
+
+Sequence<OUString> SAL_CALL DrawController::getSupportedServiceNames()
+{
+ ThrowIfDisposed();
+ Sequence<OUString> aSupportedServices { ssServiceName };
+ return aSupportedServices;
+}
+
+//------ XSelectionSupplier --------------------------------------------
+sal_Bool SAL_CALL DrawController::select (const Any& aSelection)
+{
+ ThrowIfDisposed();
+ SolarMutexGuard aGuard;
+
+ if (mxSubController.is())
+ return mxSubController->select(aSelection);
+ else
+ return false;
+}
+
+Any SAL_CALL DrawController::getSelection()
+{
+ ThrowIfDisposed();
+ SolarMutexGuard aGuard;
+
+ if (mxSubController.is())
+ return mxSubController->getSelection();
+ else
+ return Any();
+}
+
+void SAL_CALL DrawController::addSelectionChangeListener(
+ const Reference< view::XSelectionChangeListener >& xListener)
+{
+ if( mbDisposing )
+ throw lang::DisposedException();
+
+ BroadcastHelperOwner::maBroadcastHelper.addListener (m_aSelectionTypeIdentifier, xListener);
+}
+
+void SAL_CALL DrawController::removeSelectionChangeListener(
+ const Reference< view::XSelectionChangeListener >& xListener )
+{
+ if (rBHelper.bDisposed)
+ throw lang::DisposedException();
+
+ BroadcastHelperOwner::maBroadcastHelper.removeListener (m_aSelectionTypeIdentifier, xListener);
+}
+
+//===== lang::XEventListener ================================================
+
+void SAL_CALL
+ DrawController::disposing (const lang::EventObject& )
+{
+}
+
+//===== view::XSelectionChangeListener ======================================
+
+void SAL_CALL
+ DrawController::selectionChanged (const lang::EventObject& rEvent)
+{
+ ThrowIfDisposed();
+ // Have to forward the event to our selection change listeners.
+ OInterfaceContainerHelper* pListeners = BroadcastHelperOwner::maBroadcastHelper.getContainer(
+ cppu::UnoType<view::XSelectionChangeListener>::get());
+ if (!pListeners)
+ return;
+
+ // Re-send the event to all of our listeners.
+ OInterfaceIteratorHelper aIterator (*pListeners);
+ while (aIterator.hasMoreElements())
+ {
+ try
+ {
+ view::XSelectionChangeListener* pListener =
+ static_cast<view::XSelectionChangeListener*>(
+ aIterator.next());
+ if (pListener != nullptr)
+ pListener->selectionChanged (rEvent);
+ }
+ catch (const RuntimeException&)
+ {
+ }
+ }
+}
+
+// XDrawView
+
+void SAL_CALL DrawController::setCurrentPage( const Reference< drawing::XDrawPage >& xPage )
+{
+ ThrowIfDisposed();
+ SolarMutexGuard aGuard;
+
+ if (mxSubController.is())
+ mxSubController->setCurrentPage(xPage);
+}
+
+Reference< drawing::XDrawPage > SAL_CALL DrawController::getCurrentPage()
+{
+ ThrowIfDisposed();
+ SolarMutexGuard aGuard;
+ Reference<drawing::XDrawPage> xPage;
+
+ // Get current page from sub controller.
+ if (mxSubController.is())
+ xPage = mxSubController->getCurrentPage();
+
+ // When there is not yet a sub controller (during initialization) then fall back
+ // to the current page in mpCurrentPage.
+ if ( ! xPage.is() )
+ if (rtl::Reference<SdPage> pPage = mpCurrentPage.get())
+ xPage.set(pPage->getUnoPage(), UNO_QUERY);
+
+ return xPage;
+}
+
+void DrawController::FireVisAreaChanged (const ::tools::Rectangle& rVisArea) noexcept
+{
+ if( maLastVisArea == rVisArea )
+ return;
+
+ Any aNewValue;
+ aNewValue <<= awt::Rectangle(
+ rVisArea.Left(),
+ rVisArea.Top(),
+ rVisArea.GetWidth(),
+ rVisArea.GetHeight() );
+
+ Any aOldValue;
+ aOldValue <<= awt::Rectangle(
+ maLastVisArea.Left(),
+ maLastVisArea.Top(),
+ maLastVisArea.GetWidth(),
+ maLastVisArea.GetHeight() );
+
+ FirePropertyChange (PROPERTY_WORKAREA, aNewValue, aOldValue);
+
+ maLastVisArea = rVisArea;
+}
+
+void DrawController::FireSelectionChangeListener() noexcept
+{
+ OInterfaceContainerHelper * pLC = BroadcastHelperOwner::maBroadcastHelper.getContainer(
+ m_aSelectionTypeIdentifier);
+ if( !pLC )
+ return;
+
+ Reference< XInterface > xSource( static_cast<XWeak*>(this) );
+ const lang::EventObject aEvent( xSource );
+
+ // iterate over all listeners and send events
+ OInterfaceIteratorHelper aIt( *pLC);
+ while( aIt.hasMoreElements() )
+ {
+ try
+ {
+ view::XSelectionChangeListener * pL =
+ static_cast<view::XSelectionChangeListener*>(aIt.next());
+ if (pL != nullptr)
+ pL->selectionChanged( aEvent );
+ }
+ catch (const RuntimeException&)
+ {
+ }
+ }
+}
+
+void DrawController::FireChangeEditMode (bool bMasterPageMode) noexcept
+{
+ if (bMasterPageMode != mbMasterPageMode )
+ {
+ FirePropertyChange(
+ PROPERTY_MASTERPAGEMODE,
+ Any(bMasterPageMode),
+ Any(mbMasterPageMode));
+
+ mbMasterPageMode = bMasterPageMode;
+ }
+}
+
+void DrawController::FireChangeLayerMode (bool bLayerMode) noexcept
+{
+ if (bLayerMode != mbLayerMode)
+ {
+ FirePropertyChange(
+ PROPERTY_LAYERMODE,
+ Any(bLayerMode),
+ Any(mbLayerMode));
+
+ mbLayerMode = bLayerMode;
+ }
+}
+
+void DrawController::FireSwitchCurrentPage (SdPage* pNewCurrentPage) noexcept
+{
+ rtl::Reference<SdrPage> pCurrentPage = mpCurrentPage.get();
+ if (pNewCurrentPage == pCurrentPage.get())
+ return;
+
+ try
+ {
+ Any aNewValue (
+ Any(Reference<drawing::XDrawPage>(pNewCurrentPage->getUnoPage(), UNO_QUERY)));
+
+ Any aOldValue;
+ if (pCurrentPage != nullptr)
+ {
+ Reference<drawing::XDrawPage> xOldPage (pCurrentPage->getUnoPage(), UNO_QUERY);
+ aOldValue <<= xOldPage;
+ }
+
+ FirePropertyChange(PROPERTY_CURRENTPAGE, aNewValue, aOldValue);
+
+ mpCurrentPage = pNewCurrentPage;
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sd", "sd::SdUnoDrawView::FireSwitchCurrentPage()");
+ }
+}
+
+void DrawController::NotifyAccUpdate()
+{
+ sal_Int32 nHandle = PROPERTY_UPDATEACC;
+ Any aNewValue, aOldValue;
+ fire (&nHandle, &aNewValue, &aOldValue, 1, false);
+}
+
+void DrawController::fireChangeLayer( css::uno::Reference< css::drawing::XLayer>* pCurrentLayer ) noexcept
+{
+ if( pCurrentLayer != mpCurrentLayer )
+ {
+ sal_Int32 nHandle = PROPERTY_ACTIVE_LAYER;
+
+ Any aNewValue ( *pCurrentLayer);
+
+ Any aOldValue ;
+
+ fire (&nHandle, &aNewValue, &aOldValue, 1, false);
+
+ mpCurrentLayer = pCurrentLayer;
+ }
+}
+
+// This method is only called in slide show and outline view
+//void DrawController::fireSwitchCurrentPage(String pageName ) throw()
+void DrawController::fireSwitchCurrentPage(sal_Int32 pageIndex ) noexcept
+{
+ Any aNewValue;
+ Any aOldValue;
+ //OUString aPageName( pageName );
+ //aNewValue <<= aPageName ;
+ aNewValue <<= pageIndex;
+
+ // Use new property to handle page change event
+ sal_Int32 nHandles = PROPERTY_PAGE_CHANGE;
+ fire( &nHandles, &aNewValue, &aOldValue, 1, false );
+}
+
+void DrawController::FirePropertyChange (
+ sal_Int32 nHandle,
+ const Any& rNewValue,
+ const Any& rOldValue)
+{
+ try
+ {
+ fire (&nHandle, &rNewValue, &rOldValue, 1, false);
+ }
+ catch (const RuntimeException&)
+ {
+ // Ignore this exception. Exceptions should be handled in the
+ // fire() function so that all listeners are called. This is
+ // not the case at the moment, so we simply ignore the
+ // exception.
+ }
+
+}
+
+void DrawController::BroadcastContextChange() const
+{
+ std::shared_ptr<ViewShell> pViewShell (mpBase->GetMainViewShell());
+ if ( ! pViewShell)
+ return;
+
+ EnumContext::Context eContext (EnumContext::Context::Unknown);
+ switch (pViewShell->GetShellType())
+ {
+ case ViewShell::ST_IMPRESS:
+ case ViewShell::ST_DRAW:
+ if (mbMasterPageMode)
+ eContext = EnumContext::Context::MasterPage;
+ else
+ eContext = EnumContext::Context::DrawPage;
+ break;
+
+ case ViewShell::ST_NOTES:
+ eContext = EnumContext::Context::NotesPage;
+ break;
+
+ case ViewShell::ST_HANDOUT:
+ eContext = EnumContext::Context::HandoutPage;
+ break;
+
+ case ViewShell::ST_OUTLINE:
+ eContext = EnumContext::Context::OutlineText;
+ break;
+
+ case ViewShell::ST_SLIDE_SORTER:
+ eContext = EnumContext::Context::SlidesorterPage;
+ break;
+
+ case ViewShell::ST_PRESENTATION:
+ case ViewShell::ST_NONE:
+ default:
+ eContext = EnumContext::Context::Empty;
+ break;
+ }
+
+ ContextChangeEventMultiplexer::NotifyContextChange(mpBase, eContext);
+}
+
+void DrawController::ReleaseViewShellBase()
+{
+ DisposeFrameworkControllers();
+ mpBase = nullptr;
+}
+
+//===== XControllerManager ==============================================================
+
+Reference<XConfigurationController> SAL_CALL
+ DrawController::getConfigurationController()
+{
+ ThrowIfDisposed();
+
+ return mxConfigurationController;
+}
+
+Reference<XModuleController> SAL_CALL
+ DrawController::getModuleController()
+{
+ ThrowIfDisposed();
+
+ return mxModuleController;
+}
+
+//===== XUnoTunnel ============================================================
+
+const Sequence<sal_Int8>& DrawController::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theDrawControllerUnoTunnelId;
+ return theDrawControllerUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL DrawController::getSomething (const Sequence<sal_Int8>& rId)
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+//===== Properties ============================================================
+
+void DrawController::FillPropertyTable (
+ ::std::vector<beans::Property>& rProperties)
+{
+ rProperties.emplace_back("VisibleArea",
+ PROPERTY_WORKAREA,
+ ::cppu::UnoType< css::awt::Rectangle>::get(),
+ beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY);
+ rProperties.emplace_back(
+ "SubController",
+ PROPERTY_SUB_CONTROLLER,
+ cppu::UnoType<drawing::XDrawSubController>::get(),
+ beans::PropertyAttribute::BOUND);
+ rProperties.emplace_back(
+ "CurrentPage",
+ PROPERTY_CURRENTPAGE,
+ cppu::UnoType<drawing::XDrawPage>::get(),
+ beans::PropertyAttribute::BOUND );
+ rProperties.emplace_back("IsLayerMode",
+ PROPERTY_LAYERMODE,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::BOUND );
+ rProperties.emplace_back("IsMasterPageMode",
+ PROPERTY_MASTERPAGEMODE,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::BOUND );
+ rProperties.emplace_back("ActiveLayer",
+ PROPERTY_ACTIVE_LAYER,
+ cppu::UnoType<drawing::XLayer>::get(),
+ beans::PropertyAttribute::BOUND );
+ rProperties.emplace_back("ZoomValue",
+ PROPERTY_ZOOMVALUE,
+ ::cppu::UnoType<sal_Int16>::get(),
+ beans::PropertyAttribute::BOUND );
+ rProperties.emplace_back("ZoomType",
+ PROPERTY_ZOOMTYPE,
+ ::cppu::UnoType<sal_Int16>::get(),
+ beans::PropertyAttribute::BOUND );
+ rProperties.emplace_back("ViewOffset",
+ PROPERTY_VIEWOFFSET,
+ ::cppu::UnoType< css::awt::Point>::get(),
+ beans::PropertyAttribute::BOUND );
+ rProperties.emplace_back("DrawViewMode",
+ PROPERTY_DRAWVIEWMODE,
+ ::cppu::UnoType< css::awt::Point>::get(),
+ beans::PropertyAttribute::BOUND|beans::PropertyAttribute::READONLY|beans::PropertyAttribute::MAYBEVOID );
+ // add new property to update current page's acc information
+ rProperties.emplace_back( "UpdateAcc",
+ PROPERTY_UPDATEACC,
+ ::cppu::UnoType<sal_Int16>::get(),
+ beans::PropertyAttribute::BOUND );
+ rProperties.emplace_back( "PageChange",
+ PROPERTY_PAGE_CHANGE,
+ ::cppu::UnoType<sal_Int16>::get(),
+ beans::PropertyAttribute::BOUND );
+}
+
+IPropertyArrayHelper & DrawController::getInfoHelper()
+{
+ SolarMutexGuard aGuard;
+
+ if (mpPropertyArrayHelper == nullptr)
+ {
+ ::std::vector<beans::Property> aProperties;
+ FillPropertyTable(aProperties);
+ mpPropertyArrayHelper.reset(new OPropertyArrayHelper(comphelper::containerToSequence(aProperties), false));
+ }
+
+ return *mpPropertyArrayHelper;
+}
+
+Reference < beans::XPropertySetInfo > DrawController::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+
+ static Reference < beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+uno::Reference< form::runtime::XFormController > SAL_CALL DrawController::getFormController( const uno::Reference< form::XForm >& Form )
+{
+ SolarMutexGuard aGuard;
+
+ FmFormShell* pFormShell = mpBase->GetFormShellManager()->GetFormShell();
+ SdrView* pSdrView = mpBase->GetDrawView();
+ std::shared_ptr<ViewShell> pViewShell = mpBase->GetMainViewShell();
+ ::sd::Window* pWindow = pViewShell ? pViewShell->GetActiveWindow() : nullptr;
+
+ uno::Reference< form::runtime::XFormController > xController;
+ if ( pFormShell && pSdrView && pWindow )
+ xController = FmFormShell::GetFormController( Form, *pSdrView, *pWindow->GetOutDev() );
+ return xController;
+}
+
+sal_Bool SAL_CALL DrawController::isFormDesignMode( )
+{
+ SolarMutexGuard aGuard;
+
+ bool bIsDesignMode = true;
+
+ FmFormShell* pFormShell = mpBase->GetFormShellManager()->GetFormShell();
+ if ( pFormShell )
+ bIsDesignMode = pFormShell->IsDesignMode();
+
+ return bIsDesignMode;
+}
+
+void SAL_CALL DrawController::setFormDesignMode( sal_Bool DesignMode )
+{
+ SolarMutexGuard aGuard;
+
+ FmFormShell* pFormShell = mpBase->GetFormShellManager()->GetFormShell();
+ if ( pFormShell )
+ pFormShell->SetDesignMode( DesignMode );
+}
+
+uno::Reference< awt::XControl > SAL_CALL DrawController::getControl( const uno::Reference< awt::XControlModel >& xModel )
+{
+ SolarMutexGuard aGuard;
+
+ FmFormShell* pFormShell = mpBase->GetFormShellManager()->GetFormShell();
+ SdrView* pSdrView = mpBase->GetDrawView();
+ std::shared_ptr<ViewShell> pViewShell = mpBase->GetMainViewShell();
+ ::sd::Window* pWindow = pViewShell ? pViewShell->GetActiveWindow() : nullptr;
+
+ uno::Reference< awt::XControl > xControl;
+ if ( pFormShell && pSdrView && pWindow )
+ pFormShell->GetFormControl( xModel, *pSdrView, *pWindow->GetOutDev(), xControl );
+ return xControl;
+}
+
+sal_Bool DrawController::convertFastPropertyValue (
+ Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue)
+{
+ bool bResult = false;
+
+ if (nHandle == PROPERTY_SUB_CONTROLLER)
+ {
+ rOldValue <<= mxSubController;
+ rConvertedValue <<= Reference<drawing::XDrawSubController>(rValue, UNO_QUERY);
+ bResult = (rOldValue != rConvertedValue);
+ }
+ else if (mxSubController.is())
+ {
+ rConvertedValue = rValue;
+ try
+ {
+ rOldValue = mxSubController->getFastPropertyValue(nHandle);
+ bResult = (rOldValue != rConvertedValue);
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ // The property is unknown and thus an illegal argument to this method.
+ throw css::lang::IllegalArgumentException();
+ }
+ }
+
+ return bResult;
+}
+
+void DrawController::setFastPropertyValue_NoBroadcast (
+ sal_Int32 nHandle,
+ const Any& rValue)
+{
+ SolarMutexGuard aGuard;
+ if (nHandle == PROPERTY_SUB_CONTROLLER)
+ SetSubController(Reference<drawing::XDrawSubController>(rValue, UNO_QUERY));
+ else if (mxSubController.is())
+ mxSubController->setFastPropertyValue(nHandle, rValue);
+}
+
+void DrawController::getFastPropertyValue (
+ Any & rRet,
+ sal_Int32 nHandle ) const
+{
+ SolarMutexGuard aGuard;
+
+ switch( nHandle )
+ {
+ case PROPERTY_WORKAREA:
+ rRet <<= awt::Rectangle(
+ maLastVisArea.Left(),
+ maLastVisArea.Top(),
+ maLastVisArea.GetWidth(),
+ maLastVisArea.GetHeight());
+ break;
+
+ case PROPERTY_SUB_CONTROLLER:
+ rRet <<= mxSubController;
+ break;
+
+ default:
+ if (mxSubController.is())
+ rRet = mxSubController->getFastPropertyValue(nHandle);
+ break;
+ }
+}
+
+void DrawController::ProvideFrameworkControllers()
+{
+ SolarMutexGuard aGuard;
+ try
+ {
+ Reference<XController> xController (this);
+ const Reference<XComponentContext> xContext (
+ ::comphelper::getProcessComponentContext() );
+ mxConfigurationController = ConfigurationController::create(
+ xContext,
+ xController);
+ mxModuleController = ModuleController::create(
+ xContext,
+ xController);
+ }
+ catch (const RuntimeException&)
+ {
+ mxConfigurationController = nullptr;
+ mxModuleController = nullptr;
+ }
+}
+
+void DrawController::DisposeFrameworkControllers()
+{
+ Reference<XComponent> xComponent (mxModuleController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+
+ xComponent.set(mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+}
+
+void DrawController::ThrowIfDisposed() const
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose || mbDisposing)
+ {
+ SAL_WARN("sd", "Calling disposed DrawController object. Throwing exception:");
+ throw lang::DisposedException (
+ "DrawController object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/SdUnoDrawView.cxx b/sd/source/ui/unoidl/SdUnoDrawView.cxx
new file mode 100644
index 000000000..379a2956f
--- /dev/null
+++ b/sd/source/ui/unoidl/SdUnoDrawView.cxx
@@ -0,0 +1,548 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <SdUnoDrawView.hxx>
+
+#include <DrawController.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <drawdoc.hxx>
+#include "unolayer.hxx"
+#include <unomodel.hxx>
+#include <Window.hxx>
+#include <pres.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/unopage.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <com/sun/star/drawing/DrawViewMode.hpp>
+#include <com/sun/star/drawing/ShapeCollection.hpp>
+#include <com/sun/star/drawing/XLayerManager.hpp>
+#include <com/sun/star/view/DocumentZoomType.hpp>
+
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+
+namespace sd {
+
+SdUnoDrawView::SdUnoDrawView(
+ DrawViewShell& rViewShell,
+ View& rView) noexcept
+ : DrawSubControllerInterfaceBase(m_aMutex),
+ mrDrawViewShell(rViewShell),
+ mrView(rView)
+{
+}
+
+SdUnoDrawView::~SdUnoDrawView() noexcept
+{
+}
+
+bool SdUnoDrawView::getMasterPageMode() const noexcept
+{
+ return (mrDrawViewShell.GetEditMode() == EditMode::MasterPage);
+}
+
+void SdUnoDrawView::setMasterPageMode (bool bMasterPageMode) noexcept
+{
+ if ((mrDrawViewShell.GetEditMode() == EditMode::MasterPage) != bMasterPageMode)
+ {
+ mrDrawViewShell.ChangeEditMode (
+ bMasterPageMode ? EditMode::MasterPage : EditMode::Page,
+ mrDrawViewShell.IsLayerModeActive());
+ }
+}
+
+bool SdUnoDrawView::getLayerMode() const noexcept
+{
+ return mrDrawViewShell.IsLayerModeActive();
+}
+
+void SdUnoDrawView::setLayerMode (bool bLayerMode) noexcept
+{
+ if (mrDrawViewShell.IsLayerModeActive() != bLayerMode)
+ {
+ mrDrawViewShell.ChangeEditMode (
+ mrDrawViewShell.GetEditMode(),
+ bLayerMode);
+ }
+}
+
+Reference<drawing::XLayer> SdUnoDrawView::getActiveLayer() const
+{
+ Reference<drawing::XLayer> xCurrentLayer;
+
+ do
+ {
+ // Retrieve the layer manager from the model.
+ SdXImpressDocument* pModel = GetModel();
+ if (pModel == nullptr)
+ break;
+
+ SdDrawDocument* pSdModel = pModel->GetDoc();
+ if (pSdModel == nullptr)
+ break;
+
+ // From the model get the current SdrLayer object via the layer admin.
+ SdrLayerAdmin& rLayerAdmin = pSdModel->GetLayerAdmin ();
+ SdrLayer* pLayer = rLayerAdmin.GetLayer (mrView.GetActiveLayer());
+ if (pLayer == nullptr)
+ break;
+
+ // Get the corresponding XLayer object from the implementation
+ // object of the layer manager.
+ Reference<drawing::XLayerManager> xManager (pModel->getLayerManager(), uno::UNO_QUERY);
+ SdLayerManager* pManager = comphelper::getFromUnoTunnel<SdLayerManager> (xManager);
+ if (pManager != nullptr)
+ xCurrentLayer = pManager->GetLayer (pLayer);
+ }
+ while (false);
+
+ return xCurrentLayer;
+}
+
+void SdUnoDrawView::setActiveLayer (const Reference<drawing::XLayer>& rxLayer)
+{
+ // Get the SdrLayer object corresponding to the given reference.
+ if ( ! rxLayer.is())
+ return;
+
+ SdLayer* pLayer = comphelper::getFromUnoTunnel<SdLayer> (rxLayer);
+ if (pLayer == nullptr)
+ return;
+
+ SdrLayer* pSdrLayer = pLayer->GetSdrLayer();
+ if (pSdrLayer == nullptr)
+ return;
+
+ // Set the new active layer and make the change visible.
+ mrView.SetActiveLayer (pSdrLayer->GetName());
+ mrDrawViewShell.ResetActualLayer ();
+}
+
+// XSelectionSupplier
+
+sal_Bool SAL_CALL SdUnoDrawView::select( const Any& aSelection )
+{
+ bool bOk = true;
+
+ ::std::vector<SdrObject*> aObjects;
+
+ SdrPage* pSdrPage = nullptr;
+
+ Reference< drawing::XShape > xShape;
+ aSelection >>= xShape;
+
+ if(xShape.is())
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape( xShape );
+ if( pObj )
+ {
+ pSdrPage = pObj->getSdrPageFromSdrObject();
+ aObjects.push_back( pObj );
+ }
+ else
+ {
+ bOk = false;
+ }
+ }
+ else
+ {
+ Reference< drawing::XShapes > xShapes;
+ aSelection >>= xShapes;
+ if( xShapes.is() )
+ {
+ const sal_uInt32 nCount = xShapes->getCount();
+ for( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ xShapes->getByIndex(i) >>= xShape;
+ if( xShape.is() )
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
+ if( !pObj )
+ {
+ bOk = false;
+ break;
+ }
+
+ if( pSdrPage == nullptr )
+ {
+ pSdrPage = pObj->getSdrPageFromSdrObject();
+ }
+ else if( pSdrPage != pObj->getSdrPageFromSdrObject() )
+ {
+ bOk = false;
+ break;
+ }
+
+ aObjects.push_back( pObj );
+ }
+ }
+ }
+ }
+
+ if( bOk )
+ {
+ if( pSdrPage )
+ {
+ setMasterPageMode( pSdrPage->IsMasterPage() );
+ mrDrawViewShell.SwitchPage( (pSdrPage->GetPageNum() - 1) >> 1 );
+ mrDrawViewShell.WriteFrameViewData();
+ }
+
+ SdrPageView *pPV = mrView.GetSdrPageView();
+
+ if(pPV)
+ {
+ // first deselect all
+ mrView.UnmarkAllObj( pPV );
+
+ for( SdrObject* pObj : aObjects )
+ {
+ mrView.MarkObj( pObj, pPV );
+ }
+ }
+ else
+ {
+ bOk = false;
+ }
+ }
+
+ return bOk;
+}
+
+Any SAL_CALL SdUnoDrawView::getSelection()
+{
+ Any aAny;
+
+ if( mrView.IsTextEdit() )
+ mrView.getTextSelection( aAny );
+
+ if( !aAny.hasValue() )
+ {
+ const SdrMarkList& rMarkList = mrView.GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+ if( nCount )
+ {
+ Reference< drawing::XShapes > xShapes = drawing::ShapeCollection::create(
+ comphelper::getProcessComponentContext());
+ for( size_t nNum = 0; nNum < nCount; ++nNum)
+ {
+ SdrMark *pMark = rMarkList.GetMark(nNum);
+ if(pMark==nullptr)
+ continue;
+
+ SdrObject *pObj = pMark->GetMarkedSdrObj();
+ if(pObj==nullptr || pObj->getSdrPageFromSdrObject() == nullptr)
+ continue;
+
+ Reference< drawing::XDrawPage > xPage( pObj->getSdrPageFromSdrObject()->getUnoPage(), UNO_QUERY);
+
+ if(!xPage.is())
+ continue;
+
+ SvxDrawPage* pDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
+
+ if(pDrawPage==nullptr)
+ continue;
+
+ Reference< drawing::XShape > xShape( pObj->getUnoShape(), UNO_QUERY );
+
+ if(xShape.is())
+ xShapes->add(xShape);
+ }
+ aAny <<= xShapes;
+ }
+ }
+
+ return aAny;
+}
+
+void SAL_CALL SdUnoDrawView::addSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>&)
+{}
+
+void SAL_CALL SdUnoDrawView::removeSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>&)
+{}
+
+void SdUnoDrawView::setFastPropertyValue (
+ sal_Int32 nHandle,
+ const Any& rValue)
+{
+ switch( nHandle )
+ {
+ case DrawController::PROPERTY_CURRENTPAGE:
+ {
+ Reference< drawing::XDrawPage > xPage;
+ rValue >>= xPage;
+ setCurrentPage( xPage );
+ }
+ break;
+
+ case DrawController::PROPERTY_MASTERPAGEMODE:
+ {
+ bool bValue = false;
+ rValue >>= bValue;
+ setMasterPageMode( bValue );
+ }
+ break;
+
+ case DrawController::PROPERTY_LAYERMODE:
+ {
+ bool bValue = false;
+ rValue >>= bValue;
+ setLayerMode( bValue );
+ }
+ break;
+ case DrawController::PROPERTY_ACTIVE_LAYER:
+ {
+ Reference<drawing::XLayer> xLayer;
+ rValue >>= xLayer;
+ setActiveLayer (xLayer);
+ }
+ break;
+ case DrawController::PROPERTY_ZOOMVALUE:
+ {
+ sal_Int16 nZoom = 0;
+ rValue >>= nZoom;
+ SetZoom( nZoom );
+ }
+ break;
+ case DrawController::PROPERTY_ZOOMTYPE:
+ {
+ sal_Int16 nType = 0;
+ rValue >>= nType;
+ SetZoomType( nType );
+ }
+ break;
+ case DrawController::PROPERTY_VIEWOFFSET:
+ {
+ awt::Point aOffset;
+ rValue >>= aOffset;
+ SetViewOffset( aOffset );
+ }
+ break;
+ default:
+ throw beans::UnknownPropertyException( OUString::number(nHandle), static_cast<cppu::OWeakObject*>(this));
+ }
+}
+
+Any SAL_CALL SdUnoDrawView::getFastPropertyValue (
+ sal_Int32 nHandle)
+{
+ Any aValue;
+ switch( nHandle )
+ {
+ case DrawController::PROPERTY_CURRENTPAGE:
+ aValue <<= getCurrentPage();
+ break;
+
+ case DrawController::PROPERTY_MASTERPAGEMODE:
+ aValue <<= getMasterPageMode();
+ break;
+
+ case DrawController::PROPERTY_LAYERMODE:
+ aValue <<= getLayerMode();
+ break;
+
+ case DrawController::PROPERTY_ACTIVE_LAYER:
+ aValue <<= getActiveLayer();
+ break;
+
+ case DrawController::PROPERTY_ZOOMVALUE:
+ aValue <<= GetZoom();
+ break;
+ case DrawController::PROPERTY_ZOOMTYPE:
+ aValue <<= sal_Int16(css::view::DocumentZoomType::BY_VALUE);
+ break;
+ case DrawController::PROPERTY_VIEWOFFSET:
+ aValue <<= GetViewOffset();
+ break;
+
+ case DrawController::PROPERTY_DRAWVIEWMODE:
+ aValue = getDrawViewMode();
+ break;
+
+ default:
+ throw beans::UnknownPropertyException( OUString::number(nHandle), static_cast<cppu::OWeakObject*>(this));
+ }
+
+ return aValue;
+}
+
+// XDrawView
+
+void SAL_CALL SdUnoDrawView::setCurrentPage (
+ const Reference< drawing::XDrawPage >& xPage )
+{
+ SvxDrawPage* pDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
+ SdrPage *pSdrPage = pDrawPage ? pDrawPage->GetSdrPage() : nullptr;
+
+ if(pSdrPage)
+ {
+ // End editing of text. Otherwise the edited text object would
+ // still be visible on the new page.
+ mrDrawViewShell.GetView()->SdrEndTextEdit();
+
+ setMasterPageMode( pSdrPage->IsMasterPage() );
+ mrDrawViewShell.SwitchPage( (pSdrPage->GetPageNum() - 1) >> 1 );
+ mrDrawViewShell.WriteFrameViewData();
+ }
+}
+
+Reference< drawing::XDrawPage > SAL_CALL SdUnoDrawView::getCurrentPage()
+{
+ Reference< drawing::XDrawPage > xPage;
+
+ SdrPageView *pPV = mrView.GetSdrPageView();
+ SdrPage* pPage = pPV ? pPV->GetPage() : nullptr;
+
+ if(pPage)
+ xPage.set( pPage->getUnoPage(), UNO_QUERY );
+
+ return xPage;
+}
+
+sal_Int16 SdUnoDrawView::GetZoom() const
+{
+ if (mrDrawViewShell.GetActiveWindow() )
+ {
+ return static_cast<sal_Int16>(mrDrawViewShell.GetActiveWindow()->GetZoom());
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void SdUnoDrawView::SetZoom( sal_Int16 nZoom )
+{
+ SvxZoomItem aZoomItem( SvxZoomType::PERCENT, nZoom );
+
+ SfxViewFrame* pViewFrame = mrDrawViewShell.GetViewFrame();
+ if( pViewFrame )
+ {
+ SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher();
+ if( pDispatcher )
+ {
+ pDispatcher->ExecuteList(SID_ATTR_ZOOM, SfxCallMode::SYNCHRON,
+ { &aZoomItem });
+ }
+ }
+}
+
+void SdUnoDrawView::SetViewOffset(const awt::Point& rWinPos )
+{
+ Point aWinPos( rWinPos.X, rWinPos.Y );
+ aWinPos += mrDrawViewShell.GetViewOrigin();
+ mrDrawViewShell.SetWinViewPos( aWinPos );
+}
+
+awt::Point SdUnoDrawView::GetViewOffset() const
+{
+ Point aRet = mrDrawViewShell.GetWinViewPos();
+ aRet -= mrDrawViewShell.GetViewOrigin();
+
+ return awt::Point( aRet.X(), aRet.Y() );
+}
+
+void SdUnoDrawView::SetZoomType ( sal_Int16 nType )
+{
+ SfxViewFrame* pViewFrame = mrDrawViewShell.GetViewFrame();
+ if( !pViewFrame )
+ return;
+
+ SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher();
+ if( !pDispatcher )
+ return;
+
+ SvxZoomType eZoomType;
+ switch( nType )
+ {
+ case css::view::DocumentZoomType::OPTIMAL:
+ eZoomType = SvxZoomType::OPTIMAL;
+ break;
+
+ case css::view::DocumentZoomType::PAGE_WIDTH:
+ case css::view::DocumentZoomType::PAGE_WIDTH_EXACT:
+ eZoomType = SvxZoomType::PAGEWIDTH;
+ break;
+
+ case css::view::DocumentZoomType::ENTIRE_PAGE:
+ eZoomType = SvxZoomType::WHOLEPAGE;
+ break;
+
+ default:
+ return;
+ }
+ SvxZoomItem aZoomItem( eZoomType );
+ pDispatcher->ExecuteList(SID_ATTR_ZOOM, SfxCallMode::SYNCHRON,
+ { &aZoomItem });
+}
+
+SdXImpressDocument* SdUnoDrawView::GetModel() const noexcept
+{
+ if (mrView.GetDocSh()!=nullptr)
+ {
+ Reference<frame::XModel> xModel (mrView.GetDocSh()->GetModel());
+ return comphelper::getFromUnoTunnel<SdXImpressDocument>(xModel);
+ }
+ else
+ return nullptr;
+}
+
+Any SdUnoDrawView::getDrawViewMode() const
+{
+ Any aRet;
+ switch( mrDrawViewShell.GetPageKind() )
+ {
+ case PageKind::Notes: aRet <<= DrawViewMode_NOTES; break;
+ case PageKind::Handout: aRet <<= DrawViewMode_HANDOUT; break;
+ case PageKind::Standard: aRet <<= DrawViewMode_DRAW; break;
+ }
+ return aRet;
+}
+
+// XServiceInfo
+OUString SAL_CALL SdUnoDrawView::getImplementationName( )
+{
+ return "com.sun.star.comp.sd.SdUnoDrawView" ;
+}
+
+sal_Bool SAL_CALL SdUnoDrawView::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+Sequence< OUString > SAL_CALL SdUnoDrawView::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.DrawingDocumentDrawView" };
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/SdUnoOutlineView.cxx b/sd/source/ui/unoidl/SdUnoOutlineView.cxx
new file mode 100644
index 000000000..6b98f2140
--- /dev/null
+++ b/sd/source/ui/unoidl/SdUnoOutlineView.cxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <SdUnoOutlineView.hxx>
+
+#include <DrawController.hxx>
+#include <OutlineViewShell.hxx>
+#include <sdpage.hxx>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <svx/unopage.hxx>
+
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+SdUnoOutlineView::SdUnoOutlineView(
+ OutlineViewShell& rViewShell) noexcept
+ : DrawSubControllerInterfaceBase(m_aMutex),
+ mrOutlineViewShell(rViewShell)
+{
+}
+
+SdUnoOutlineView::~SdUnoOutlineView() noexcept
+{
+}
+
+void SAL_CALL SdUnoOutlineView::disposing()
+{
+}
+
+//----- XSelectionSupplier ----------------------------------------------------
+
+sal_Bool SAL_CALL SdUnoOutlineView::select( const Any& )
+{
+ // todo: add selections for text ranges
+ return false;
+}
+
+Any SAL_CALL SdUnoOutlineView::getSelection()
+{
+ Any aAny;
+ return aAny;
+}
+
+void SAL_CALL SdUnoOutlineView::addSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>&)
+{}
+
+void SAL_CALL SdUnoOutlineView::removeSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>&)
+{}
+
+//----- XDrawView -------------------------------------------------------------
+void SAL_CALL SdUnoOutlineView::setCurrentPage (
+ const Reference< drawing::XDrawPage >& xPage)
+{
+ SvxDrawPage* pDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
+ SdrPage *pSdrPage = pDrawPage ? pDrawPage->GetSdrPage() : nullptr;
+ SdPage *pSdPage = dynamic_cast<SdPage*>(pSdrPage);
+
+ if (pSdPage != nullptr)
+ mrOutlineViewShell.SetCurrentPage(pSdPage);
+}
+
+Reference< drawing::XDrawPage > SAL_CALL SdUnoOutlineView::getCurrentPage()
+{
+ Reference<drawing::XDrawPage> xPage;
+
+ SdPage* pPage = mrOutlineViewShell.getCurrentPage();
+ if (pPage != nullptr)
+ xPage.set(pPage->getUnoPage(), UNO_QUERY);
+
+ return xPage;
+}
+
+void SdUnoOutlineView::setFastPropertyValue (
+ sal_Int32 nHandle,
+ const Any& rValue)
+{
+ switch( nHandle )
+ {
+ case DrawController::PROPERTY_CURRENTPAGE:
+ {
+ Reference< drawing::XDrawPage > xPage;
+ rValue >>= xPage;
+ setCurrentPage( xPage );
+ }
+ break;
+
+ default:
+ throw beans::UnknownPropertyException( OUString::number(nHandle), static_cast<cppu::OWeakObject*>(this));
+ }
+}
+
+Any SAL_CALL SdUnoOutlineView::getFastPropertyValue (
+ sal_Int32 nHandle)
+{
+ Any aValue;
+
+ switch( nHandle )
+ {
+ case DrawController::PROPERTY_CURRENTPAGE:
+ {
+ SdPage* pPage = mrOutlineViewShell.GetActualPage();
+ if (pPage != nullptr)
+ aValue <<= pPage->getUnoPage();
+ }
+ break;
+ case DrawController::PROPERTY_VIEWOFFSET:
+ break;
+
+ default:
+ throw beans::UnknownPropertyException( OUString::number(nHandle), static_cast<cppu::OWeakObject*>(this));
+ }
+
+ return aValue;
+}
+
+// XServiceInfo
+OUString SAL_CALL SdUnoOutlineView::getImplementationName( )
+{
+ return "com.sun.star.comp.sd.SdUnoOutlineView";
+}
+
+sal_Bool SAL_CALL SdUnoOutlineView::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+Sequence< OUString > SAL_CALL SdUnoOutlineView::getSupportedServiceNames( )
+{
+ return { "com.sun.star.presentation.OutlineView" };
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/SdUnoSlideView.cxx b/sd/source/ui/unoidl/SdUnoSlideView.cxx
new file mode 100644
index 000000000..c30962ed7
--- /dev/null
+++ b/sd/source/ui/unoidl/SdUnoSlideView.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cppuhelper/supportsservice.hxx>
+
+#include <DrawController.hxx>
+#include <SdUnoSlideView.hxx>
+
+#include <SlideSorter.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsCurrentSlideManager.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <sdpage.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+SdUnoSlideView::SdUnoSlideView (
+ slidesorter::SlideSorter& rSlideSorter) noexcept
+ : DrawSubControllerInterfaceBase(m_aMutex),
+ mrSlideSorter(rSlideSorter)
+{
+}
+
+SdUnoSlideView::~SdUnoSlideView() noexcept
+{
+}
+
+//----- XSelectionSupplier ----------------------------------------------------
+
+sal_Bool SAL_CALL SdUnoSlideView::select (const Any& aSelection)
+{
+ slidesorter::controller::SlideSorterController& rSlideSorterController
+ = mrSlideSorter.GetController();
+ slidesorter::controller::PageSelector& rSelector (rSlideSorterController.GetPageSelector());
+ rSelector.DeselectAllPages();
+ Sequence<Reference<drawing::XDrawPage> > xPages;
+ aSelection >>= xPages;
+ for (const auto& rPage : std::as_const(xPages))
+ {
+ Reference<beans::XPropertySet> xSet (rPage, UNO_QUERY);
+ if (xSet.is())
+ {
+ try
+ {
+ Any aNumber = xSet->getPropertyValue("Number");
+ sal_Int32 nPageNumber = 0;
+ aNumber >>= nPageNumber;
+ nPageNumber -=1; // Transform 1-based page numbers to 0-based ones.
+ rSelector.SelectPage(nPageNumber);
+ }
+ catch (const RuntimeException&)
+ {
+ }
+ }
+ }
+
+ return true;
+}
+
+Any SAL_CALL SdUnoSlideView::getSelection()
+{
+ Any aResult;
+
+ slidesorter::model::PageEnumeration aSelectedPages (
+ slidesorter::model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ int nSelectedPageCount (
+ mrSlideSorter.GetController().GetPageSelector().GetSelectedPageCount());
+
+ Sequence<Reference<XInterface> > aPages(nSelectedPageCount);
+ auto aPagesRange = asNonConstRange(aPages);
+ int nIndex = 0;
+ while (aSelectedPages.HasMoreElements() && nIndex<nSelectedPageCount)
+ {
+ slidesorter::model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ aPagesRange[nIndex++] = pDescriptor->GetPage()->getUnoPage();
+ }
+ aResult <<= aPages;
+
+ return aResult;
+}
+
+void SAL_CALL SdUnoSlideView::addSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>&)
+{}
+
+void SAL_CALL SdUnoSlideView::removeSelectionChangeListener (
+ const css::uno::Reference<css::view::XSelectionChangeListener>&)
+{}
+
+//----- XDrawView -------------------------------------------------------------
+
+void SAL_CALL SdUnoSlideView::setCurrentPage (
+ const css::uno::Reference<css::drawing::XDrawPage>& rxDrawPage)
+{
+ Reference<beans::XPropertySet> xProperties (rxDrawPage, UNO_QUERY);
+ if (xProperties.is())
+ {
+ sal_uInt16 nPageNumber(0);
+ if (xProperties->getPropertyValue("Number") >>= nPageNumber)
+ {
+ mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(
+ nPageNumber-1);
+ }
+ }
+}
+
+css::uno::Reference<css::drawing::XDrawPage > SAL_CALL
+ SdUnoSlideView::getCurrentPage()
+{
+ return mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()->GetXDrawPage();
+}
+
+//----- XFastPropertySet ------------------------------------------------------
+
+void SdUnoSlideView::setFastPropertyValue (
+ sal_Int32 nHandle,
+ const Any&)
+{
+ throw beans::UnknownPropertyException( OUString::number(nHandle), static_cast<cppu::OWeakObject*>(this));
+}
+
+Any SAL_CALL SdUnoSlideView::getFastPropertyValue (
+ sal_Int32 nHandle)
+{
+ if( nHandle != DrawController::PROPERTY_VIEWOFFSET )
+ throw beans::UnknownPropertyException( OUString::number(nHandle), static_cast<cppu::OWeakObject*>(this));
+
+ return Any();
+}
+
+// XServiceInfo
+OUString SAL_CALL SdUnoSlideView::getImplementationName( )
+{
+ return "com.sun.star.comp.sd.SdUnoSlideView";
+}
+
+sal_Bool SAL_CALL SdUnoSlideView::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+Sequence< OUString > SAL_CALL SdUnoSlideView::getSupportedServiceNames( )
+{
+ return { "com.sun.star.presentation.SlidesView" };
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/UnoDocumentSettings.cxx b/sd/source/ui/unoidl/UnoDocumentSettings.cxx
new file mode 100644
index 000000000..331f90b53
--- /dev/null
+++ b/sd/source/ui/unoidl/UnoDocumentSettings.cxx
@@ -0,0 +1,1431 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+#include <utility>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/i18n/XForbiddenCharacters.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/propertysethelper.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <o3tl/string_view.hxx>
+#include <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <svx/xtable.hxx>
+#include <vcl/svapp.hxx>
+
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include "UnoDocumentSettings.hxx"
+#include <unomodel.hxx>
+
+#include <optsitem.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sdattr.hrc>
+#include <sdmod.hxx>
+#include <Outliner.hxx>
+#include <xmloff/settingsstore.hxx>
+#include <editeng/editstat.hxx>
+#include <svx/unoapi.hxx>
+
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::i18n;
+
+namespace sd
+{
+ namespace {
+
+ class DocumentSettings : public WeakImplHelper< XPropertySet, XMultiPropertySet, XServiceInfo >,
+ public comphelper::PropertySetHelper,
+ public DocumentSettingsSerializer
+ {
+ public:
+ explicit DocumentSettings( SdXImpressDocument* pModel );
+
+ // XInterface
+ virtual Any SAL_CALL queryInterface( const Type& aType ) override;
+ virtual void SAL_CALL acquire( ) noexcept override;
+ virtual void SAL_CALL release( ) noexcept override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // XMultiPropertySet
+ virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override;
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override;
+ virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // DocumentSettingsSerializer cf. xmloff
+ virtual uno::Sequence<beans::PropertyValue>
+ filterStreamsFromStorage(OUString const & referer,
+ const uno::Reference< embed::XStorage > &xStorage,
+ const uno::Sequence<beans::PropertyValue>& aConfigProps ) override;
+ virtual uno::Sequence<beans::PropertyValue>
+ filterStreamsToStorage(const uno::Reference< embed::XStorage > &xStorage,
+ const uno::Sequence<beans::PropertyValue>& aConfigProps ) override;
+
+ protected:
+ virtual void _setPropertyValues( const comphelper::PropertyMapEntry** ppEntries, const css::uno::Any* pValues ) override;
+ virtual void _getPropertyValues( const comphelper::PropertyMapEntry** ppEntries, css::uno::Any* pValue ) override;
+
+ private:
+ bool LoadList( XPropertyListType t, const OUString &rPath,
+ const OUString &rReferer,
+ const uno::Reference< embed::XStorage > &xStorage );
+ void AssignURL( XPropertyListType t, const Any* pValue, bool *pOk, bool *pChanged );
+ void ExtractURL( XPropertyListType t, Any* pValue );
+ rtl::Reference<SdXImpressDocument> mxModel;
+ };
+
+ }
+
+ Reference< XInterface > DocumentSettings_createInstance( SdXImpressDocument* pModel )
+ noexcept
+ {
+ DBG_ASSERT( pModel, "I need a model for the DocumentSettings!" );
+ return static_cast<XWeak*>(new DocumentSettings( pModel ));
+ }
+
+namespace {
+
+enum SdDocumentSettingsPropertyHandles
+{
+ HANDLE_PRINTDRAWING, HANDLE_PRINTNOTES, HANDLE_PRINTHANDOUT, HANDLE_PRINTOUTLINE, HANDLE_MEASUREUNIT, HANDLE_SCALE_NUM,
+ HANDLE_SCALE_DOM, HANDLE_TABSTOP, HANDLE_PRINTPAGENAME, HANDLE_PRINTDATE, HANDLE_PRINTTIME,
+ HANDLE_PRINTHIDDENPAGES, HANDLE_PRINTFITPAGE, HANDLE_PRINTTILEPAGE, HANDLE_PRINTBOOKLET, HANDLE_PRINTBOOKLETFRONT,
+ HANDLE_PRINTBOOKLETBACK, HANDLE_PRINTQUALITY, HANDLE_COLORTABLEURL, HANDLE_DASHTABLEURL, HANDLE_LINEENDTABLEURL, HANDLE_HATCHTABLEURL,
+ HANDLE_GRADIENTTABLEURL, HANDLE_BITMAPTABLEURL, HANDLE_FORBIDDENCHARS, HANDLE_APPLYUSERDATA, HANDLE_SAVETHUMBNAIL, HANDLE_PAGENUMFMT,
+ HANDLE_PRINTERNAME, HANDLE_PRINTERJOB, HANDLE_PRINTERPAPERSIZE, HANDLE_PARAGRAPHSUMMATION, HANDLE_CHARCOMPRESS, HANDLE_ASIANPUNCT,
+ HANDLE_UPDATEFROMTEMPLATE, HANDLE_PRINTER_INDEPENDENT_LAYOUT
+ // #i33095#
+ ,HANDLE_LOAD_READONLY, HANDLE_MODIFY_PASSWD, HANDLE_SAVE_VERSION
+ ,HANDLE_SLIDESPERHANDOUT, HANDLE_HANDOUTHORIZONTAL,
+ HANDLE_EMBED_FONTS, HANDLE_EMBED_USED_FONTS,
+ HANDLE_EMBED_LATIN_SCRIPT_FONTS, HANDLE_EMBED_ASIAN_SCRIPT_FONTS, HANDLE_EMBED_COMPLEX_SCRIPT_FONTS,
+ HANDLE_IMAGE_PREFERRED_DPI
+};
+
+}
+
+#define MID_PRINTER 1
+
+ static rtl::Reference<PropertySetInfo> createSettingsInfoImpl( bool bIsDraw )
+ {
+ static PropertyMapEntry const aImpressSettingsInfoMap[] =
+ {
+ { OUString("IsPrintDrawing"), HANDLE_PRINTDRAWING, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintNotes"), HANDLE_PRINTNOTES, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintHandout"), HANDLE_PRINTHANDOUT, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintOutline"), HANDLE_PRINTOUTLINE, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("SlidesPerHandout"), HANDLE_SLIDESPERHANDOUT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_PRINTER },
+ { OUString("HandoutsHorizontal"), HANDLE_HANDOUTHORIZONTAL, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ };
+
+ static PropertyMapEntry const aDrawSettingsInfoMap[] =
+ {
+ { OUString("MeasureUnit"), HANDLE_MEASUREUNIT, ::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { OUString("ScaleNumerator"), HANDLE_SCALE_NUM, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { OUString("ScaleDenominator"), HANDLE_SCALE_DOM, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ };
+
+ static PropertyMapEntry const aCommonSettingsInfoMap[] =
+ {
+ { OUString("DefaultTabStop"), HANDLE_TABSTOP, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { OUString("PrinterName"), HANDLE_PRINTERNAME, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("PrinterSetup"), HANDLE_PRINTERJOB, cppu::UnoType<uno::Sequence < sal_Int8 >>::get(), 0, MID_PRINTER },
+ { OUString("PrinterPaperFromSetup"), HANDLE_PRINTERPAPERSIZE, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+
+ { OUString("IsPrintPageName"), HANDLE_PRINTPAGENAME, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintDate"), HANDLE_PRINTDATE, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintTime"), HANDLE_PRINTTIME, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintHiddenPages"), HANDLE_PRINTHIDDENPAGES, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintFitPage"), HANDLE_PRINTFITPAGE, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintTilePage"), HANDLE_PRINTTILEPAGE, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintBooklet"), HANDLE_PRINTBOOKLET, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintBookletFront"), HANDLE_PRINTBOOKLETFRONT, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("IsPrintBookletBack"), HANDLE_PRINTBOOKLETBACK, cppu::UnoType<bool>::get(), 0, MID_PRINTER },
+ { OUString("PrintQuality"), HANDLE_PRINTQUALITY, ::cppu::UnoType<sal_Int32>::get(), 0, MID_PRINTER },
+ { OUString("ColorTableURL"), HANDLE_COLORTABLEURL, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("DashTableURL"), HANDLE_DASHTABLEURL, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("LineEndTableURL"), HANDLE_LINEENDTABLEURL, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("HatchTableURL"), HANDLE_HATCHTABLEURL, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("GradientTableURL"), HANDLE_GRADIENTTABLEURL, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { OUString("BitmapTableURL"), HANDLE_BITMAPTABLEURL, ::cppu::UnoType<OUString>::get(), 0, 0 },
+
+ { OUString("ForbiddenCharacters"), HANDLE_FORBIDDENCHARS, cppu::UnoType<XForbiddenCharacters>::get(), 0, 0 },
+ { OUString("ApplyUserData"), HANDLE_APPLYUSERDATA, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("SaveThumbnail"), HANDLE_SAVETHUMBNAIL, cppu::UnoType<bool>::get(), 0, 0 },
+
+ { OUString("PageNumberFormat"), HANDLE_PAGENUMFMT, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { OUString("ParagraphSummation"), HANDLE_PARAGRAPHSUMMATION, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("CharacterCompressionType"),HANDLE_CHARCOMPRESS, ::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { OUString("IsKernAsianPunctuation"),HANDLE_ASIANPUNCT, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("UpdateFromTemplate"), HANDLE_UPDATEFROMTEMPLATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("PrinterIndependentLayout"),HANDLE_PRINTER_INDEPENDENT_LAYOUT,::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ // --> #i33095#
+ { OUString("LoadReadonly"), HANDLE_LOAD_READONLY, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("ModifyPasswordInfo"), HANDLE_MODIFY_PASSWD, cppu::UnoType<uno::Sequence < beans::PropertyValue >>::get(), 0, 0 },
+ { OUString("SaveVersionOnClose"), HANDLE_SAVE_VERSION, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("EmbedFonts"), HANDLE_EMBED_FONTS, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("EmbedOnlyUsedFonts"), HANDLE_EMBED_USED_FONTS, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("EmbedLatinScriptFonts"), HANDLE_EMBED_LATIN_SCRIPT_FONTS, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("EmbedAsianScriptFonts"), HANDLE_EMBED_ASIAN_SCRIPT_FONTS, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("EmbedComplexScriptFonts"), HANDLE_EMBED_COMPLEX_SCRIPT_FONTS, cppu::UnoType<bool>::get(), 0, 0 },
+ { OUString("ImagePreferredDPI"), HANDLE_IMAGE_PREFERRED_DPI, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ };
+
+ rtl::Reference<PropertySetInfo> xInfo = new PropertySetInfo( aCommonSettingsInfoMap );
+ if (bIsDraw)
+ xInfo->add( aDrawSettingsInfoMap );
+ else
+ xInfo->add( aImpressSettingsInfoMap );
+
+ return xInfo;
+ }
+}
+
+using namespace ::sd;
+
+DocumentSettings::DocumentSettings( SdXImpressDocument* pModel )
+: PropertySetHelper( createSettingsInfoImpl( !pModel->IsImpressDocument() ) ),
+ mxModel( pModel )
+{
+}
+
+bool DocumentSettings::LoadList( XPropertyListType t, const OUString &rInPath,
+ const OUString &rReferer,
+ const uno::Reference< embed::XStorage > &xStorage )
+{
+ SdDrawDocument* pDoc = mxModel->GetDoc();
+
+ sal_Int32 nSlash = rInPath.lastIndexOf('/');
+ OUString aPath, aName;
+ if (nSlash < 0)
+ aName = rInPath;
+ else {
+ aName = rInPath.copy( nSlash + 1 );
+ aPath = rInPath.copy( 0, nSlash );
+ }
+
+ XPropertyListRef pList = XPropertyList::CreatePropertyList(
+ t, aPath, rReferer );
+ pList->SetName( aName );
+
+ if( pList->LoadFrom( xStorage, rInPath, rReferer ) )
+ {
+ pDoc->SetPropertyList( pList );
+ return true;
+ }
+
+ return false;
+}
+
+void DocumentSettings::AssignURL( XPropertyListType t, const Any* pValue,
+ bool *pOk, bool *pChanged )
+{
+ OUString aURL;
+ if( !( *pValue >>= aURL ) )
+ return;
+
+ if( LoadList( t, aURL, ""/*TODO?*/, uno::Reference< embed::XStorage >() ) )
+ *pOk = *pChanged = true;
+}
+
+struct {
+ const char *pName;
+ XPropertyListType t;
+} const aURLPropertyNames[] = {
+ { "ColorTableURL", XPropertyListType::Color },
+ { "DashTableURL", XPropertyListType::Dash },
+ { "LineEndTableURL", XPropertyListType::LineEnd },
+ { "HatchTableURL", XPropertyListType::Hatch },
+ { "GradientTableURL", XPropertyListType::Gradient },
+ { "BitmapTableURL", XPropertyListType::Bitmap }
+};
+
+static XPropertyListType getTypeOfName( std::u16string_view aName )
+{
+ for(const auto & rURLPropertyName : aURLPropertyNames) {
+ if( o3tl::equalsAscii( aName, rURLPropertyName.pName ) )
+ return rURLPropertyName.t;
+ }
+ return XPropertyListType::Unknown;
+}
+
+static OUString getNameOfType( XPropertyListType t )
+{
+ for(const auto & rURLPropertyName : aURLPropertyNames) {
+ if( t == rURLPropertyName.t )
+ return OUString( rURLPropertyName.pName,
+ strlen( rURLPropertyName.pName ) - 3,
+ RTL_TEXTENCODING_ASCII_US );
+ }
+ return OUString();
+}
+
+uno::Sequence<beans::PropertyValue>
+ DocumentSettings::filterStreamsFromStorage(
+ OUString const & referer,
+ const uno::Reference< embed::XStorage > &xStorage,
+ const uno::Sequence<beans::PropertyValue>& aConfigProps )
+{
+ uno::Sequence<beans::PropertyValue> aRet( aConfigProps.getLength() );
+ auto aRetRange = asNonConstRange(aRet);
+ int nRet = 0;
+ for( const auto& rConfigProp : aConfigProps )
+ {
+ XPropertyListType t = getTypeOfName( rConfigProp.Name );
+ if (t == XPropertyListType::Unknown)
+ aRetRange[nRet++] = rConfigProp;
+ else
+ {
+ OUString aURL;
+ rConfigProp.Value >>= aURL;
+ LoadList( t, aURL, referer, xStorage );
+ }
+ }
+ aRet.realloc( nRet );
+ return aRet;
+}
+
+uno::Sequence<beans::PropertyValue>
+ DocumentSettings::filterStreamsToStorage(
+ const uno::Reference< embed::XStorage > &xStorage,
+ const uno::Sequence<beans::PropertyValue>& aConfigProps )
+{
+ uno::Sequence<beans::PropertyValue> aRet( aConfigProps.getLength() );
+
+ bool bHasEmbed = false;
+ SdDrawDocument* pDoc = mxModel->GetDoc();
+ for( size_t i = 0; i < SAL_N_ELEMENTS( aURLPropertyNames ); i++ )
+ {
+ const XPropertyListRef& pList = pDoc->GetPropertyList( static_cast<XPropertyListType>(i) );
+ bHasEmbed = pList.is() && pList->IsEmbedInDocument();
+ if( bHasEmbed )
+ break;
+ }
+ if( !bHasEmbed )
+ return aConfigProps;
+
+ try {
+ // create Settings/ sub storage.
+ uno::Reference< embed::XStorage > xSubStorage = xStorage->openStorageElement( "Settings" ,
+ embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
+ if( !xSubStorage.is() )
+ return aRet;
+
+ auto aRetRange = asNonConstRange(aRet);
+ // now populate it
+ for( sal_Int32 i = 0; i < aConfigProps.getLength(); i++ )
+ {
+ XPropertyListType t = getTypeOfName( aConfigProps[i].Name );
+ aRetRange[i] = aConfigProps[i];
+ if (t != XPropertyListType::Unknown) {
+ const XPropertyListRef& pList = pDoc->GetPropertyList( t );
+ if( !pList.is() || !pList->IsEmbedInDocument() )
+ continue; // no change ...
+ else
+ {
+ // Such specific path construction is grim.
+
+ OUString aName( getNameOfType( t ) );
+ OUString aResult;
+ if( pList->SaveTo( xSubStorage, aName, &aResult ) )
+ {
+ OUString aRealPath = "Settings/" + aResult;
+ aRetRange[i].Value <<= aRealPath;
+ }
+ }
+ }
+ }
+
+ // surprisingly difficult to make it really exist
+ uno::Reference< embed::XTransactedObject > xTrans( xSubStorage, UNO_QUERY );
+ if( xTrans.is() )
+ xTrans->commit();
+ if( xSubStorage.is() )
+ xSubStorage->dispose();
+ } catch (const uno::Exception &) {
+// fprintf (stderr, "saving etc. exception '%s'\n",
+// OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
+ }
+
+ return aRet;
+}
+
+// Most of the code reading/writing UNO document settings is the same in
+// sd, sc and sw and it is mostly copy-pasted back and forth.
+// TODO: Move _setPropertyValues and _getPropertyValues to some shared
+// place, at least for the settings that are common to sd, sc and sw
+void
+DocumentSettings::_setPropertyValues(const PropertyMapEntry** ppEntries,
+ const Any* pValues)
+{
+ ::SolarMutexGuard aGuard;
+
+ SdDrawDocument* pDoc = mxModel->GetDoc();
+ ::sd::DrawDocShell* pDocSh = mxModel->GetDocShell();
+ if( nullptr == pDoc || nullptr == pDocSh )
+ {
+ throw RuntimeException("Document or Shell missing",
+ static_cast<OWeakObject *>(this));
+ }
+
+ bool bValue = false;
+ bool bOk, bChanged = false, bOptionsChanged = false;
+
+ SdOptionsPrintItem aOptionsPrintItem;
+
+ VclPtr<SfxPrinter> pPrinter = pDocSh->GetPrinter( false );
+ if( pPrinter )
+ {
+ SdOptionsPrintItem const * pPrinterOptions = pPrinter->GetOptions().GetItemIfSet( ATTR_OPTIONS_PRINT, false );
+ if(pPrinterOptions)
+ aOptionsPrintItem.GetOptionsPrint() = pPrinterOptions->GetOptionsPrint();
+ }
+ else
+ {
+ aOptionsPrintItem.SetOptions( SD_MOD()->GetSdOptions(pDoc->GetDocumentType()) );
+ }
+ SdOptionsPrint& aPrintOpts = aOptionsPrintItem.GetOptionsPrint();
+
+ for( ; *ppEntries; ppEntries++, pValues++ )
+ {
+ bOk = false;
+
+ switch( (*ppEntries)->mnHandle )
+ {
+ case HANDLE_COLORTABLEURL:
+ AssignURL( XPropertyListType::Color, pValues, &bOk, &bChanged );
+ break;
+
+ case HANDLE_DASHTABLEURL:
+ AssignURL( XPropertyListType::Dash, pValues, &bOk, &bChanged );
+ break;
+
+ case HANDLE_LINEENDTABLEURL:
+ AssignURL( XPropertyListType::LineEnd, pValues, &bOk, &bChanged );
+ break;
+
+ case HANDLE_HATCHTABLEURL:
+ AssignURL( XPropertyListType::Hatch, pValues, &bOk, &bChanged );
+ break;
+
+ case HANDLE_GRADIENTTABLEURL:
+ AssignURL( XPropertyListType::Gradient, pValues, &bOk, &bChanged );
+ break;
+
+ case HANDLE_BITMAPTABLEURL:
+ AssignURL( XPropertyListType::Bitmap, pValues, &bOk, &bChanged );
+ break;
+
+ case HANDLE_FORBIDDENCHARS:
+ bOk = true;
+ break;
+
+ case HANDLE_APPLYUSERDATA:
+ {
+ bool bApplyUserData = false;
+ if( *pValues >>= bApplyUserData )
+ {
+ bChanged = ( bApplyUserData != pDocSh->IsUseUserData() );
+ pDocSh->SetUseUserData( bApplyUserData );
+ bOk = true;
+ }
+ }
+ break;
+ case HANDLE_SAVETHUMBNAIL:
+ {
+ bool bSaveThumbnail = false;
+ if (*pValues >>= bSaveThumbnail)
+ {
+ bChanged = (bSaveThumbnail != pDocSh->IsUseThumbnailSave());
+ pDocSh->SetUseThumbnailSave(bSaveThumbnail);
+ bOk = true;
+ }
+ }
+ break;
+
+ case HANDLE_PRINTDRAWING:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsDraw() != bValue )
+ {
+ aPrintOpts.SetDraw( bValue );
+ bOptionsChanged = true;
+ }
+
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTNOTES:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsNotes() != bValue )
+ {
+ aPrintOpts.SetNotes( bValue );
+ bOptionsChanged = true;
+ }
+
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTHANDOUT:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsHandout() != bValue)
+ {
+ aPrintOpts.SetHandout( bValue );
+ bOptionsChanged = true;
+ }
+
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTOUTLINE:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsOutline() != bValue)
+ {
+ aPrintOpts.SetOutline( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+ case HANDLE_SLIDESPERHANDOUT:
+ {
+ sal_Int16 nValue = 0;
+ if( (*pValues >>= nValue) && (nValue >= 1) && (nValue <= 9) )
+ {
+ if( static_cast<sal_Int16>( aPrintOpts.GetHandoutPages() ) != nValue )
+ {
+ aPrintOpts.SetHandoutPages( static_cast< sal_uInt16 >( nValue ) );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ }
+ break;
+ case HANDLE_HANDOUTHORIZONTAL:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsHandoutHorizontal() != bValue )
+ {
+ aPrintOpts.SetHandoutHorizontal( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+
+ case HANDLE_PRINTPAGENAME:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsPagename() != bValue)
+ {
+ aPrintOpts.SetPagename( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTDATE:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsDate() != bValue)
+ {
+ aPrintOpts.SetDate( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTTIME:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsDate() != bValue)
+ {
+ aPrintOpts.SetTime( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTHIDDENPAGES:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsHiddenPages() != bValue)
+ {
+ aPrintOpts.SetHiddenPages( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTFITPAGE:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsPagesize() != bValue)
+ {
+ aPrintOpts.SetPagesize( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTTILEPAGE:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsPagetile() != bValue)
+ {
+ aPrintOpts.SetPagetile( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTBOOKLET:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsBooklet() != bValue)
+ {
+ aPrintOpts.SetBooklet( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTBOOKLETFRONT:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsFrontPage() != bValue)
+ {
+ aPrintOpts.SetFrontPage( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTBOOKLETBACK:
+ if( *pValues >>= bValue )
+ {
+ if( aPrintOpts.IsBackPage() != bValue)
+ {
+ aPrintOpts.SetBackPage( bValue );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ break;
+ case HANDLE_PRINTQUALITY:
+ {
+ sal_Int32 nValue = 0;
+ if( *pValues >>= nValue )
+ {
+ if( aPrintOpts.GetOutputQuality() != nValue)
+ {
+ aPrintOpts.SetOutputQuality( static_cast<sal_uInt16>(nValue) );
+ bOptionsChanged = true;
+ }
+ bOk = true;
+ }
+ }
+ break;
+ case HANDLE_MEASUREUNIT:
+ {
+ sal_Int16 nValue = 0;
+ if( *pValues >>= nValue )
+ {
+ FieldUnit nFieldUnit;
+ if( SvxMeasureUnitToFieldUnit( nValue, nFieldUnit ) )
+ {
+ pDoc->SetUIUnit( nFieldUnit );
+ bOk = true;
+ }
+ }
+ }
+ break;
+ case HANDLE_SCALE_NUM:
+ {
+ sal_Int32 nValue = 0;
+ if( *pValues >>= nValue )
+ {
+ Fraction aFract( nValue, pDoc->GetUIScale().GetDenominator() );
+ pDoc->SetUIScale( aFract );
+ bOk = true;
+ bChanged = true;
+ }
+ }
+ break;
+ case HANDLE_SCALE_DOM:
+ {
+ sal_Int32 nValue = 0;
+ if( *pValues >>= nValue )
+ {
+ auto nNumerator = pDoc->GetUIScale().GetNumerator();
+ assert(nNumerator != 0);
+ Fraction aFract(nNumerator, nValue);
+ pDoc->SetUIScale( aFract );
+ bOk = true;
+ bChanged = true;
+ }
+ }
+ break;
+
+ case HANDLE_TABSTOP:
+ {
+ sal_Int32 nValue = 0;
+ if( (*pValues >>= nValue) && (nValue >= 0) )
+ {
+ pDoc->SetDefaultTabulator(static_cast<sal_uInt16>(nValue));
+ bOk = true;
+ bChanged = true;
+ }
+ }
+ break;
+ case HANDLE_PAGENUMFMT:
+ {
+ sal_Int32 nValue = 0;
+ if( (*pValues >>= nValue ) && (nValue >= css::style::NumberingType::CHARS_UPPER_LETTER ) && (nValue <= css::style::NumberingType::PAGE_DESCRIPTOR) )
+ {
+ pDoc->SetPageNumType(static_cast<SvxNumType>(nValue));
+ bOk = true;
+ bChanged = true;
+ }
+ }
+ break;
+ case HANDLE_PRINTERNAME:
+ {
+ OUString aPrinterName;
+ if( *pValues >>= aPrinterName )
+ {
+ bOk = true;
+ if( !aPrinterName.isEmpty() && pDocSh->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
+ {
+ SfxPrinter *pTempPrinter = pDocSh->GetPrinter( true );
+ if (pTempPrinter)
+ {
+ VclPtr<SfxPrinter> pNewPrinter = VclPtr<SfxPrinter>::Create( pTempPrinter->GetOptions().Clone(), aPrinterName );
+ pDocSh->SetPrinter( pNewPrinter );
+ }
+ }
+ }
+ }
+ break;
+ case HANDLE_PRINTERJOB:
+ {
+ Sequence < sal_Int8 > aSequence;
+ if ( *pValues >>= aSequence )
+ {
+ bOk = true;
+ sal_uInt32 nSize = aSequence.getLength();
+ if( nSize )
+ {
+ SvMemoryStream aStream (aSequence.getArray(), nSize, StreamMode::READ );
+ aStream.Seek ( STREAM_SEEK_TO_BEGIN );
+ std::unique_ptr<SfxItemSet> pItemSet;
+
+ bool bPreferPrinterPapersize = false;
+ if( pPrinter )
+ {
+ pItemSet = pPrinter->GetOptions().Clone();
+ bPreferPrinterPapersize = pPrinter->GetPrinterSettingsPreferred();
+ }
+ else
+ {
+ pItemSet = std::make_unique<SfxItemSetFixed
+ <SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
+ SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC,
+ ATTR_OPTIONS_PRINT, ATTR_OPTIONS_PRINT>>(pDoc->GetPool());
+ }
+
+ pPrinter = SfxPrinter::Create ( aStream, std::move(pItemSet) );
+ pPrinter->SetPrinterSettingsPreferred( bPreferPrinterPapersize );
+
+ MapMode aMM (pPrinter->GetMapMode());
+ aMM.SetMapUnit(MapUnit::Map100thMM);
+ pPrinter->SetMapMode(aMM);
+
+ pDocSh->SetPrinter( pPrinter );
+
+ pPrinter = nullptr;
+ }
+ }
+ }
+ break;
+
+ case HANDLE_PRINTERPAPERSIZE:
+ {
+ bool bPreferPrinterPapersize;
+ if( *pValues >>= bPreferPrinterPapersize )
+ {
+ bOk = true;
+ if( pDocSh->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
+ {
+ SfxPrinter *pTempPrinter = pDocSh->GetPrinter( true );
+ if (pTempPrinter)
+ pTempPrinter->SetPrinterSettingsPreferred( bPreferPrinterPapersize );
+ }
+ }
+ }
+ break;
+
+ case HANDLE_PARAGRAPHSUMMATION :
+ {
+ bool bIsSummationOfParagraphs = false;
+ if ( *pValues >>= bIsSummationOfParagraphs )
+ {
+ bOk = true;
+ bChanged = true;
+ if ( pDoc->GetDocumentType() == DocumentType::Impress )
+ {
+ EEControlBits nSum = bIsSummationOfParagraphs ? EEControlBits::ULSPACESUMMATION : EEControlBits::NONE;
+ EEControlBits nCntrl;
+
+ pDoc->SetSummationOfParagraphs( bIsSummationOfParagraphs );
+ SdDrawDocument* pDocument = pDocSh->GetDoc();
+ SdrOutliner& rOutl = pDocument->GetDrawOutliner();
+ nCntrl = rOutl.GetControlWord() &~ EEControlBits::ULSPACESUMMATION;
+ rOutl.SetControlWord( nCntrl | nSum );
+ SdOutliner* pOutl = pDocument->GetOutliner( false );
+ if( pOutl )
+ {
+ nCntrl = pOutl->GetControlWord() &~ EEControlBits::ULSPACESUMMATION;
+ pOutl->SetControlWord( nCntrl | nSum );
+ }
+ pOutl = pDocument->GetInternalOutliner( false );
+ if( pOutl )
+ {
+ nCntrl = pOutl->GetControlWord() &~ EEControlBits::ULSPACESUMMATION;
+ pOutl->SetControlWord( nCntrl | nSum );
+ }
+ }
+ }
+ }
+ break;
+
+ case HANDLE_CHARCOMPRESS:
+ {
+ sal_Int16 nCharCompressType = 0;
+ if( *pValues >>= nCharCompressType )
+ {
+ bOk = true;
+
+ pDoc->SetCharCompressType( static_cast<CharCompressType>(nCharCompressType) );
+ SdDrawDocument* pDocument = pDocSh->GetDoc();
+ SdrOutliner& rOutl = pDocument->GetDrawOutliner();
+ rOutl.SetAsianCompressionMode( static_cast<CharCompressType>(nCharCompressType) );
+ SdOutliner* pOutl = pDocument->GetOutliner( false );
+ if( pOutl )
+ {
+ pOutl->SetAsianCompressionMode( static_cast<CharCompressType>(nCharCompressType) );
+ }
+ pOutl = pDocument->GetInternalOutliner( false );
+ if( pOutl )
+ {
+ pOutl->SetAsianCompressionMode( static_cast<CharCompressType>(nCharCompressType) );
+ }
+ }
+ break;
+
+ }
+ case HANDLE_ASIANPUNCT:
+ {
+ bool bAsianPunct = false;
+ if( *pValues >>= bAsianPunct )
+ {
+ bOk = true;
+
+ pDoc->SetKernAsianPunctuation( bAsianPunct );
+ SdDrawDocument* pDocument = pDocSh->GetDoc();
+ SdrOutliner& rOutl = pDocument->GetDrawOutliner();
+ rOutl.SetKernAsianPunctuation( bAsianPunct );
+ SdOutliner* pOutl = pDocument->GetOutliner( false );
+ if( pOutl )
+ {
+ pOutl->SetKernAsianPunctuation( bAsianPunct );
+ }
+ pOutl = pDocument->GetInternalOutliner( false );
+ if( pOutl )
+ {
+ pOutl->SetKernAsianPunctuation( bAsianPunct );
+ }
+ }
+ break;
+
+ }
+ case HANDLE_UPDATEFROMTEMPLATE:
+ {
+ bool value = false;
+ if( *pValues >>= value )
+ {
+ bChanged = ( value != pDocSh->IsQueryLoadTemplate() );
+ pDocSh->SetQueryLoadTemplate( value );
+ bOk = true;
+ }
+ }
+ break;
+
+ case HANDLE_PRINTER_INDEPENDENT_LAYOUT:
+ {
+ // Just propagate the new printer independent layout mode to
+ // the document and determine it really differs from the old
+ // one.
+ sal_Int16 nOldValue =
+ static_cast<sal_Int16>(pDoc->GetPrinterIndependentLayout ());
+ sal_Int16 nValue = 0;
+ if (*pValues >>= nValue)
+ {
+ pDoc->SetPrinterIndependentLayout (nValue);
+ bChanged = (nValue != nOldValue);
+ bOk = true;
+ }
+ }
+ break;
+
+ // --> #i33095#
+ case HANDLE_LOAD_READONLY:
+ {
+ bool bNewValue = false;
+ if ( *pValues >>= bNewValue )
+ {
+ bChanged = ( pDocSh->IsLoadReadonly() != bNewValue );
+ pDocSh->SetLoadReadonly( bNewValue );
+ bOk = true;
+ }
+ }
+ break;
+
+ case HANDLE_MODIFY_PASSWD:
+ {
+ uno::Sequence< beans::PropertyValue > aInfo;
+ if ( !( *pValues >>= aInfo ) )
+ throw lang::IllegalArgumentException(
+ "Value of type Sequence<PropertyValue> expected!",
+ uno::Reference< uno::XInterface >(),
+ 2 );
+
+ if ( !pDocSh->SetModifyPasswordInfo( aInfo ) )
+ throw beans::PropertyVetoException(
+ "The hash is not allowed to be changed now!" );
+
+ bOk = true
+;
+
+ }
+ break;
+
+ case HANDLE_SAVE_VERSION:
+ {
+ bool bNewValue = false;
+ if ( *pValues >>= bNewValue )
+ {
+ bChanged = ( pDocSh->IsSaveVersionOnClose() != bNewValue );
+ pDocSh->SetSaveVersionOnClose( bNewValue );
+ bOk = true;
+ }
+ }
+ break;
+
+ case HANDLE_EMBED_FONTS:
+ {
+ if (pValues->has<bool>())
+ {
+ bool bNewValue = pValues->get<bool>();
+ bChanged = (pDoc->IsEmbedFonts() != bNewValue);
+ pDoc->SetEmbedFonts(bNewValue);
+ bOk = true;
+ }
+ }
+ break;
+
+ case HANDLE_EMBED_USED_FONTS:
+ {
+ if (pValues->has<bool>())
+ {
+ bool bNewValue = pValues->get<bool>();
+ bChanged = (pDoc->IsEmbedUsedFontsOnly() != bNewValue);
+ pDoc->SetEmbedUsedFontsOnly(bNewValue);
+ bOk = true;
+ }
+ }
+ break;
+
+ case HANDLE_EMBED_LATIN_SCRIPT_FONTS:
+ {
+ if (pValues->has<bool>())
+ {
+ bool bNewValue = pValues->get<bool>();
+ bChanged = (pDoc->IsEmbedFontScriptLatin() != bNewValue);
+ pDoc->SetEmbedFontScriptLatin(bNewValue);
+ bOk = true;
+ }
+ }
+ break;
+
+ case HANDLE_EMBED_ASIAN_SCRIPT_FONTS:
+ {
+ if (pValues->has<bool>())
+ {
+ bool bNewValue = pValues->get<bool>();
+ bChanged = (pDoc->IsEmbedFontScriptAsian() != bNewValue);
+ pDoc->SetEmbedFontScriptAsian(bNewValue);
+ bOk = true;
+ }
+ }
+ break;
+
+ case HANDLE_EMBED_COMPLEX_SCRIPT_FONTS:
+ {
+ if (pValues->has<bool>())
+ {
+ bool bNewValue = pValues->get<bool>();
+ bChanged = (pDoc->IsEmbedFontScriptComplex() != bNewValue);
+ pDoc->SetEmbedFontScriptComplex(bNewValue);
+ bOk = true;
+ }
+ }
+ break;
+
+ case HANDLE_IMAGE_PREFERRED_DPI:
+ {
+ if (pValues->has<sal_Int32>())
+ {
+ auto nNewValue = pValues->get<sal_Int32>();
+ bChanged = (pDoc->getImagePreferredDPI() != nNewValue);
+ pDoc->setImagePreferredDPI(nNewValue);
+ bOk = true;
+ }
+ }
+ break;
+
+ default:
+ throw UnknownPropertyException( OUString::number((*ppEntries)->mnHandle), static_cast<cppu::OWeakObject*>(this));
+ }
+
+ if( !bOk )
+ throw IllegalArgumentException();
+ }
+
+ if( bOptionsChanged )
+ {
+ if( !pPrinter )
+ pPrinter = pDocSh->GetPrinter( true );
+ SfxItemSet aNewOptions( pPrinter->GetOptions() );
+ aNewOptions.Put( aOptionsPrintItem );
+ pPrinter->SetOptions( aNewOptions );
+ }
+
+ if( bChanged || bOptionsChanged )
+ mxModel->SetModified();
+}
+
+void DocumentSettings::ExtractURL( XPropertyListType t, Any* pValue )
+{
+ XPropertyListRef pList = mxModel->GetDoc()->GetPropertyList( t );
+ if( !pList.is() )
+ return;
+
+ INetURLObject aPathURL( pList->GetPath() );
+ aPathURL.insertName( pList->GetName() );
+ aPathURL.setExtension( pList->GetDefaultExt() );
+ OUString aPath( aPathURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ *pValue <<= aPath;
+}
+
+void
+DocumentSettings::_getPropertyValues(
+ const PropertyMapEntry** ppEntries, Any* pValue)
+{
+ ::SolarMutexGuard aGuard;
+
+ SdDrawDocument* pDoc = mxModel->GetDoc();
+ ::sd::DrawDocShell* pDocSh = mxModel->GetDocShell();
+ if( nullptr == pDoc || nullptr == pDocSh )
+ {
+ throw RuntimeException("Document or Shell missing",
+ static_cast<OWeakObject *>(this));
+ }
+
+ SdOptionsPrintItem aOptionsPrintItem;
+
+ SfxPrinter* pPrinter = pDocSh->GetPrinter( false );
+ if( pPrinter )
+ {
+ SdOptionsPrintItem const * pPrinterOptions = pPrinter->GetOptions().GetItemIfSet( ATTR_OPTIONS_PRINT, false );
+ if (pPrinterOptions)
+ aOptionsPrintItem.GetOptionsPrint() = pPrinterOptions->GetOptionsPrint();
+ }
+ else
+ {
+ aOptionsPrintItem.SetOptions( SD_MOD()->GetSdOptions(pDoc->GetDocumentType()) );
+ }
+ SdOptionsPrint& aPrintOpts = aOptionsPrintItem.GetOptionsPrint();
+
+ for( ; *ppEntries; ppEntries++, pValue++ )
+ {
+ switch( (*ppEntries)->mnHandle )
+ {
+ case HANDLE_COLORTABLEURL:
+ ExtractURL( XPropertyListType::Color, pValue );
+ break;
+ case HANDLE_DASHTABLEURL:
+ ExtractURL( XPropertyListType::Dash, pValue );
+ break;
+ case HANDLE_LINEENDTABLEURL:
+ ExtractURL( XPropertyListType::LineEnd, pValue );
+ break;
+ case HANDLE_HATCHTABLEURL:
+ ExtractURL( XPropertyListType::Hatch, pValue );
+ break;
+ case HANDLE_GRADIENTTABLEURL:
+ ExtractURL( XPropertyListType::Gradient, pValue );
+ break;
+ case HANDLE_BITMAPTABLEURL:
+ ExtractURL( XPropertyListType::Bitmap, pValue );
+ break;
+ case HANDLE_FORBIDDENCHARS:
+ *pValue <<= mxModel->getForbiddenCharsTable();
+ break;
+ case HANDLE_APPLYUSERDATA:
+ *pValue <<= pDocSh->IsUseUserData();
+ break;
+ case HANDLE_SAVETHUMBNAIL:
+ *pValue <<= pDocSh->IsUseThumbnailSave();
+ break;
+ case HANDLE_PRINTDRAWING:
+ *pValue <<= aPrintOpts.IsDraw();
+ break;
+ case HANDLE_PRINTNOTES:
+ *pValue <<= aPrintOpts.IsNotes();
+ break;
+ case HANDLE_PRINTHANDOUT:
+ *pValue <<= aPrintOpts.IsHandout();
+ break;
+ case HANDLE_PRINTOUTLINE:
+ *pValue <<= aPrintOpts.IsOutline();
+ break;
+ case HANDLE_SLIDESPERHANDOUT:
+ *pValue <<= static_cast<sal_Int16>(aPrintOpts.GetHandoutPages());
+ break;
+ case HANDLE_HANDOUTHORIZONTAL:
+ *pValue <<= aPrintOpts.IsHandoutHorizontal();
+ break;
+ case HANDLE_PRINTPAGENAME:
+ *pValue <<= aPrintOpts.IsPagename();
+ break;
+ case HANDLE_PRINTDATE:
+ *pValue <<= aPrintOpts.IsDate();
+ break;
+ case HANDLE_PRINTTIME:
+ *pValue <<= aPrintOpts.IsTime();
+ break;
+ case HANDLE_PRINTHIDDENPAGES:
+ *pValue <<= aPrintOpts.IsHiddenPages();
+ break;
+ case HANDLE_PRINTFITPAGE:
+ *pValue <<= aPrintOpts.IsPagesize();
+ break;
+ case HANDLE_PRINTTILEPAGE:
+ *pValue <<= aPrintOpts.IsPagetile();
+ break;
+ case HANDLE_PRINTBOOKLET:
+ *pValue <<= aPrintOpts.IsBooklet();
+ break;
+ case HANDLE_PRINTBOOKLETFRONT:
+ *pValue <<= aPrintOpts.IsFrontPage();
+ break;
+ case HANDLE_PRINTBOOKLETBACK:
+ *pValue <<= aPrintOpts.IsBackPage();
+ break;
+ case HANDLE_PRINTQUALITY:
+ *pValue <<= static_cast<sal_Int32>(aPrintOpts.GetOutputQuality());
+ break;
+ case HANDLE_MEASUREUNIT:
+ {
+ short nMeasure;
+ SvxFieldUnitToMeasureUnit( pDoc->GetUIUnit(), nMeasure );
+ *pValue <<= static_cast<sal_Int16>(nMeasure);
+ }
+ break;
+ case HANDLE_SCALE_NUM:
+ *pValue <<= pDoc->GetUIScale().GetNumerator();
+ break;
+ case HANDLE_SCALE_DOM:
+ *pValue <<= pDoc->GetUIScale().GetDenominator();
+ break;
+ case HANDLE_TABSTOP:
+ *pValue <<= static_cast<sal_Int32>(pDoc->GetDefaultTabulator());
+ break;
+ case HANDLE_PAGENUMFMT:
+ *pValue <<= static_cast<sal_Int32>(pDoc->GetPageNumType());
+ break;
+ case HANDLE_PRINTERNAME:
+ {
+ SfxPrinter *pTempPrinter = pDocSh->GetPrinter( false );
+ *pValue <<= pTempPrinter ? pTempPrinter->GetName() : OUString();
+ }
+ break;
+ case HANDLE_PRINTERJOB:
+ {
+ SfxPrinter *pTempPrinter = pDocSh->GetPrinter( false );
+ if (pTempPrinter)
+ {
+ SvMemoryStream aStream;
+ pTempPrinter->Store( aStream );
+ *pValue <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aStream.GetData() ),
+ aStream.TellEnd() );
+ }
+ else
+ {
+ Sequence < sal_Int8 > aSequence;
+ *pValue <<= aSequence;
+ }
+ }
+ break;
+
+ case HANDLE_PRINTERPAPERSIZE:
+ {
+ SfxPrinter *pTempPrinter = pDocSh->GetPrinter( false );
+ *pValue <<= pTempPrinter && pTempPrinter->GetPrinterSettingsPreferred();
+ }
+ break;
+
+ case HANDLE_PARAGRAPHSUMMATION :
+ {
+ bool bIsSummationOfParagraphs = pDoc->IsSummationOfParagraphs();
+ *pValue <<= bIsSummationOfParagraphs;
+ }
+ break;
+
+ case HANDLE_CHARCOMPRESS:
+ {
+ *pValue <<= static_cast<sal_Int16>(pDoc->GetCharCompressType());
+ break;
+ }
+
+ case HANDLE_ASIANPUNCT:
+ {
+ *pValue <<= pDoc->IsKernAsianPunctuation();
+ break;
+ }
+
+ case HANDLE_UPDATEFROMTEMPLATE:
+ {
+ *pValue <<= pDocSh->IsQueryLoadTemplate();
+ }
+ break;
+
+ case HANDLE_PRINTER_INDEPENDENT_LAYOUT:
+ {
+ sal_Int16 nPrinterIndependentLayout =
+ static_cast<sal_Int16>(pDoc->GetPrinterIndependentLayout());
+ *pValue <<= nPrinterIndependentLayout;
+ }
+ break;
+
+ // --> #i33095#
+ case HANDLE_LOAD_READONLY:
+ {
+ *pValue <<= pDocSh->IsLoadReadonly();
+ }
+ break;
+
+ case HANDLE_MODIFY_PASSWD:
+ {
+ *pValue <<= pDocSh->GetModifyPasswordInfo();
+ }
+ break;
+
+ case HANDLE_SAVE_VERSION:
+ {
+ *pValue <<= pDocSh->IsSaveVersionOnClose();
+ }
+ break;
+
+ case HANDLE_EMBED_FONTS:
+ {
+ *pValue <<= pDoc->IsEmbedFonts();
+ }
+ break;
+
+ case HANDLE_EMBED_USED_FONTS:
+ {
+ *pValue <<= pDoc->IsEmbedUsedFontsOnly();
+ }
+ break;
+
+ case HANDLE_EMBED_LATIN_SCRIPT_FONTS:
+ {
+ *pValue <<= pDoc->IsEmbedFontScriptLatin();
+ }
+ break;
+
+ case HANDLE_EMBED_ASIAN_SCRIPT_FONTS:
+ {
+ *pValue <<= pDoc->IsEmbedFontScriptAsian();
+ }
+ break;
+
+ case HANDLE_EMBED_COMPLEX_SCRIPT_FONTS:
+ {
+ *pValue <<= pDoc->IsEmbedFontScriptComplex();
+ }
+ break;
+
+ case HANDLE_IMAGE_PREFERRED_DPI:
+ {
+ *pValue <<= pDoc->getImagePreferredDPI();
+ }
+ break;
+
+ default:
+ throw UnknownPropertyException( OUString::number((*ppEntries)->mnHandle), static_cast<cppu::OWeakObject*>(this));
+ }
+ }
+}
+
+// XInterface
+Any SAL_CALL DocumentSettings::queryInterface( const Type& aType )
+{
+ return WeakImplHelper< XPropertySet, XMultiPropertySet, XServiceInfo >::queryInterface( aType );
+}
+
+void SAL_CALL DocumentSettings::acquire( ) noexcept
+{
+ WeakImplHelper< XPropertySet, XMultiPropertySet, XServiceInfo >::acquire();
+}
+
+void SAL_CALL DocumentSettings::release( ) noexcept
+{
+ WeakImplHelper< XPropertySet, XMultiPropertySet, XServiceInfo >::release();
+}
+
+// XPropertySet
+Reference< XPropertySetInfo > SAL_CALL DocumentSettings::getPropertySetInfo( )
+{
+ return PropertySetHelper::getPropertySetInfo();
+}
+
+void SAL_CALL DocumentSettings::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ PropertySetHelper::setPropertyValue( aPropertyName, aValue );
+}
+
+Any SAL_CALL DocumentSettings::getPropertyValue( const OUString& PropertyName )
+{
+ return PropertySetHelper::getPropertyValue( PropertyName );
+}
+
+void SAL_CALL DocumentSettings::addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener )
+{
+ PropertySetHelper::addPropertyChangeListener( aPropertyName, xListener );
+}
+
+void SAL_CALL DocumentSettings::removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener )
+{
+ PropertySetHelper::removePropertyChangeListener( aPropertyName, aListener );
+}
+
+void SAL_CALL DocumentSettings::addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener )
+{
+ PropertySetHelper::addVetoableChangeListener( PropertyName, aListener );
+}
+
+void SAL_CALL DocumentSettings::removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener )
+{
+ PropertySetHelper::removeVetoableChangeListener( PropertyName, aListener );
+}
+
+// XMultiPropertySet
+void SAL_CALL DocumentSettings::setPropertyValues( const Sequence< OUString >& aPropertyNames, const Sequence< Any >& aValues )
+{
+ PropertySetHelper::setPropertyValues( aPropertyNames, aValues );
+}
+
+Sequence< Any > SAL_CALL DocumentSettings::getPropertyValues( const Sequence< OUString >& aPropertyNames )
+{
+ return PropertySetHelper::getPropertyValues( aPropertyNames );
+}
+
+void SAL_CALL DocumentSettings::addPropertiesChangeListener( const Sequence< OUString >& aPropertyNames, const Reference< XPropertiesChangeListener >& xListener )
+{
+ PropertySetHelper::addPropertiesChangeListener( aPropertyNames, xListener );
+}
+
+void SAL_CALL DocumentSettings::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& xListener )
+{
+ PropertySetHelper::removePropertiesChangeListener( xListener );
+}
+
+void SAL_CALL DocumentSettings::firePropertiesChangeEvent( const Sequence< OUString >& aPropertyNames, const Reference< XPropertiesChangeListener >& xListener )
+{
+ PropertySetHelper::firePropertiesChangeEvent( aPropertyNames, xListener );
+}
+
+// XServiceInfo
+OUString SAL_CALL DocumentSettings::getImplementationName( )
+{
+ return "com.sun.star.comp.Draw.DocumentSettings";
+}
+
+sal_Bool SAL_CALL DocumentSettings::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL DocumentSettings::getSupportedServiceNames( )
+{
+ return { "com.sun.star.document.Settings" ,
+ mxModel->IsImpressDocument()?OUString("com.sun.star.presentation.DocumentSettings"):OUString("com.sun.star.drawing.DocumentSettings") };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/UnoDocumentSettings.hxx b/sd/source/ui/unoidl/UnoDocumentSettings.hxx
new file mode 100644
index 000000000..bba3c66b1
--- /dev/null
+++ b/sd/source/ui/unoidl/UnoDocumentSettings.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace com::sun::star::uno
+{
+class XInterface;
+}
+
+class SdXImpressDocument;
+
+namespace sd
+{
+css::uno::Reference<css::uno::XInterface>
+DocumentSettings_createInstance(SdXImpressDocument* pDoc) noexcept;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/randomnode.cxx b/sd/source/ui/unoidl/randomnode.cxx
new file mode 100644
index 000000000..a87ae1783
--- /dev/null
+++ b/sd/source/ui/unoidl/randomnode.cxx
@@ -0,0 +1,573 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/animations/XTimeContainer.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/XAnimate.hpp>
+#include <com/sun/star/animations/AnimationRestart.hpp>
+#include <com/sun/star/animations/ParallelTimeContainer.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <comphelper/processfactory.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <osl/mutex.hxx>
+#include <CustomAnimationPreset.hxx>
+#include <randomnode.hxx>
+
+using ::osl::Mutex;
+using ::osl::Guard;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::uno::WeakReference;
+using ::com::sun::star::beans::NamedValue;
+using ::com::sun::star::lang::IllegalArgumentException;
+using ::com::sun::star::container::XEnumeration;
+using ::com::sun::star::container::XEnumerationAccess;
+using ::com::sun::star::util::XCloneable;
+using ::com::sun::star::lang::XServiceInfo;
+using ::com::sun::star::lang::XInitialization;
+using ::com::sun::star::uno::Type;
+using ::com::sun::star::uno::XWeak;
+using ::com::sun::star::presentation::ParagraphTarget;
+using ::com::sun::star::drawing::XShape;
+
+using namespace ::com::sun::star::animations;
+
+namespace sd
+{
+
+typedef ::cppu::WeakImplHelper< XTimeContainer, XEnumerationAccess, XCloneable, XServiceInfo, XInitialization > RandomAnimationNodeBase;
+
+namespace {
+
+class RandomAnimationNode : public RandomAnimationNodeBase
+{
+public:
+ RandomAnimationNode( const RandomAnimationNode& rNode );
+ explicit RandomAnimationNode( sal_Int16 nPresetClass );
+ RandomAnimationNode();
+
+ void init( sal_Int16 nPresetClass );
+
+ // XInitialization
+ void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ // XChild
+ Reference< XInterface > SAL_CALL getParent( ) override;
+ void SAL_CALL setParent( const Reference< XInterface >& Parent ) override;
+
+ // XCloneable
+ virtual Reference< XCloneable > SAL_CALL createClone() override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+
+ // XAnimationNode
+ ::sal_Int16 SAL_CALL getType() override;
+ Any SAL_CALL getBegin() override;
+ void SAL_CALL setBegin( const Any& _begin ) override;
+ Any SAL_CALL getDuration() override;
+ void SAL_CALL setDuration( const Any& _duration ) override;
+ Any SAL_CALL getEnd() override;
+ void SAL_CALL setEnd( const Any& _end ) override;
+ Any SAL_CALL getEndSync() override;
+ void SAL_CALL setEndSync( const Any& _endsync ) override;
+ Any SAL_CALL getRepeatCount() override;
+ void SAL_CALL setRepeatCount( const Any& _repeatcount ) override;
+ Any SAL_CALL getRepeatDuration() override;
+ void SAL_CALL setRepeatDuration( const Any& _repeatduration ) override;
+ ::sal_Int16 SAL_CALL getFill() override;
+ void SAL_CALL setFill( ::sal_Int16 _fill ) override;
+ ::sal_Int16 SAL_CALL getFillDefault() override;
+ void SAL_CALL setFillDefault( ::sal_Int16 _filldefault ) override;
+ ::sal_Int16 SAL_CALL getRestart() override;
+ void SAL_CALL setRestart( ::sal_Int16 _restart ) override;
+ ::sal_Int16 SAL_CALL getRestartDefault() override;
+ void SAL_CALL setRestartDefault( ::sal_Int16 _restartdefault ) override;
+ double SAL_CALL getAcceleration() override;
+ void SAL_CALL setAcceleration( double _acceleration ) override;
+ double SAL_CALL getDecelerate() override;
+ void SAL_CALL setDecelerate( double _decelerate ) override;
+ sal_Bool SAL_CALL getAutoReverse() override;
+ void SAL_CALL setAutoReverse( sal_Bool _autoreverse ) override;
+ Sequence< NamedValue > SAL_CALL getUserData() override;
+ void SAL_CALL setUserData( const Sequence< NamedValue >& _userdata ) override;
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XEnumerationAccess
+ virtual Reference< XEnumeration > SAL_CALL createEnumeration() override;
+
+ // XTimeContainer
+ Reference< XAnimationNode > SAL_CALL insertBefore( const Reference< XAnimationNode >& newChild, const Reference< XAnimationNode >& refChild ) override;
+ Reference< XAnimationNode > SAL_CALL insertAfter( const Reference< XAnimationNode >& newChild, const Reference< XAnimationNode >& refChild ) override;
+ Reference< XAnimationNode > SAL_CALL replaceChild( const Reference< XAnimationNode >& newChild, const Reference< XAnimationNode >& oldChild ) override;
+ Reference< XAnimationNode > SAL_CALL removeChild( const Reference< XAnimationNode >& oldChild ) override;
+ Reference< XAnimationNode > SAL_CALL appendChild( const Reference< XAnimationNode >& newChild ) override;
+
+private:
+ // our first, last and only protection from multi-threads!
+ Mutex maMutex;
+
+ sal_Int16 mnPresetClass;
+ WeakReference<XInterface> mxParent;
+
+ Any maBegin, maDuration, maEnd, maEndSync, maRepeatCount, maRepeatDuration, maTarget;
+ sal_Int16 mnFill, mnFillDefault, mnRestart, mnRestartDefault;
+ double mfAcceleration, mfDecelerate;
+ bool mbAutoReverse;
+ Sequence< NamedValue > maUserData;
+
+ Reference< XAnimate > mxFirstNode;
+};
+
+}
+
+Reference< XInterface > RandomAnimationNode_createInstance( sal_Int16 nPresetClass )
+{
+ Reference< XInterface > xInt( static_cast<XWeak*>( new RandomAnimationNode( nPresetClass ) ) );
+ return xInt;
+}
+
+RandomAnimationNode::RandomAnimationNode( const RandomAnimationNode& rNode )
+: RandomAnimationNodeBase(rNode),
+ mnPresetClass( rNode.mnPresetClass ),
+ maBegin( rNode.maBegin ),
+ maDuration( rNode.maDuration ),
+ maEnd( rNode.maEnd ),
+ maEndSync( rNode.maEndSync ),
+ maRepeatCount( rNode.maRepeatCount ),
+ maRepeatDuration( rNode.maRepeatDuration ),
+ maTarget( rNode.maTarget ),
+ mnFill( rNode.mnFill ),
+ mnFillDefault( rNode.mnFillDefault ),
+ mnRestart( rNode.mnRestart ),
+ mnRestartDefault( rNode.mnRestartDefault ),
+ mfAcceleration( rNode.mfAcceleration ),
+ mfDecelerate( rNode.mfDecelerate ),
+ mbAutoReverse( rNode.mbAutoReverse ),
+ maUserData( rNode.maUserData )
+{
+}
+
+RandomAnimationNode::RandomAnimationNode( sal_Int16 nPresetClass )
+{
+ init( nPresetClass );
+}
+
+RandomAnimationNode::RandomAnimationNode()
+{
+ init( 1 );
+}
+
+void RandomAnimationNode::init( sal_Int16 nPresetClass )
+{
+ mnPresetClass = nPresetClass;
+ mnFill = AnimationFill::DEFAULT;
+ mnFillDefault = AnimationFill::INHERIT;
+ mnRestart = AnimationRestart::DEFAULT;
+ mnRestartDefault = AnimationRestart::INHERIT;
+ mfAcceleration = 0.0;
+ mfDecelerate = 0.0;
+ mbAutoReverse = false;
+}
+
+// XInitialization
+void SAL_CALL RandomAnimationNode::initialize( const Sequence< Any >& aArguments )
+{
+ if( aArguments.getLength() != 1 )
+ throw IllegalArgumentException();
+
+ if( aArguments[0].getValueType() == ::cppu::UnoType<sal_Int16>::get() )
+ {
+ aArguments[0] >>= mnPresetClass;
+ }
+ else if( aArguments[0].getValueType() != ::cppu::UnoType<ParagraphTarget>::get() )
+ {
+ Reference< XShape > xShape;
+ aArguments[0] >>= xShape;
+ if( !xShape.is() )
+ throw IllegalArgumentException();
+ }
+ maTarget = aArguments[0];
+}
+
+// XAnimationNode
+sal_Int16 SAL_CALL RandomAnimationNode::getType()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return css::animations::AnimationNodeType::PAR;
+}
+
+// XAnimationNode
+Any SAL_CALL RandomAnimationNode::getBegin()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return maBegin;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setBegin( const Any& _begin )
+{
+ Guard< Mutex > aGuard( maMutex );
+ maBegin = _begin;
+}
+
+// XAnimationNode
+Any SAL_CALL RandomAnimationNode::getDuration()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return maDuration;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setDuration( const Any& _duration )
+{
+ Guard< Mutex > aGuard( maMutex );
+ maDuration = _duration;
+}
+
+// XAnimationNode
+Any SAL_CALL RandomAnimationNode::getEnd()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return maEnd;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setEnd( const Any& _end )
+{
+ Guard< Mutex > aGuard( maMutex );
+ maEnd = _end;
+}
+
+// XAnimationNode
+Any SAL_CALL RandomAnimationNode::getEndSync()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return maEndSync;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setEndSync( const Any& _endsync )
+{
+ Guard< Mutex > aGuard( maMutex );
+ maEndSync = _endsync;
+}
+
+// XAnimationNode
+Any SAL_CALL RandomAnimationNode::getRepeatCount()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return maRepeatCount;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setRepeatCount( const Any& _repeatcount )
+{
+ Guard< Mutex > aGuard( maMutex );
+ maRepeatCount = _repeatcount;
+}
+
+// XAnimationNode
+Any SAL_CALL RandomAnimationNode::getRepeatDuration()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return maRepeatDuration;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setRepeatDuration( const Any& _repeatduration )
+{
+ Guard< Mutex > aGuard( maMutex );
+ maRepeatDuration = _repeatduration;
+}
+
+// XAnimationNode
+sal_Int16 SAL_CALL RandomAnimationNode::getFill()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return mnFill;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setFill( sal_Int16 _fill )
+{
+ Guard< Mutex > aGuard( maMutex );
+ mnFill = _fill;
+}
+
+// XAnimationNode
+sal_Int16 SAL_CALL RandomAnimationNode::getFillDefault()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return mnFillDefault;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setFillDefault( sal_Int16 _filldefault )
+{
+ Guard< Mutex > aGuard( maMutex );
+ mnFillDefault = _filldefault;
+}
+
+// XAnimationNode
+sal_Int16 SAL_CALL RandomAnimationNode::getRestart()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return mnRestart;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setRestart( sal_Int16 _restart )
+{
+ Guard< Mutex > aGuard( maMutex );
+ mnRestart = _restart;
+}
+
+// XAnimationNode
+sal_Int16 SAL_CALL RandomAnimationNode::getRestartDefault()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return mnRestartDefault;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setRestartDefault( sal_Int16 _restartdefault )
+{
+ Guard< Mutex > aGuard( maMutex );
+ mnRestartDefault = _restartdefault;
+}
+
+// XAnimationNode
+double SAL_CALL RandomAnimationNode::getAcceleration()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return mfAcceleration;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setAcceleration( double _acceleration )
+{
+ Guard< Mutex > aGuard( maMutex );
+ mfAcceleration = _acceleration;
+}
+
+// XAnimationNode
+double SAL_CALL RandomAnimationNode::getDecelerate()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return mfDecelerate;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setDecelerate( double _decelerate )
+{
+ Guard< Mutex > aGuard( maMutex );
+ mfDecelerate = _decelerate;
+}
+
+// XAnimationNode
+sal_Bool SAL_CALL RandomAnimationNode::getAutoReverse()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return mbAutoReverse;
+}
+
+// XAnimationNode
+void SAL_CALL RandomAnimationNode::setAutoReverse( sal_Bool _autoreverse )
+{
+ Guard< Mutex > aGuard( maMutex );
+ mbAutoReverse = _autoreverse;
+}
+
+Sequence< NamedValue > SAL_CALL RandomAnimationNode::getUserData()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return maUserData;
+}
+
+void SAL_CALL RandomAnimationNode::setUserData( const Sequence< NamedValue >& _userdata )
+{
+ Guard< Mutex > aGuard( maMutex );
+ maUserData = _userdata;
+}
+
+// XChild
+Reference< XInterface > SAL_CALL RandomAnimationNode::getParent()
+{
+ Guard< Mutex > aGuard( maMutex );
+ return mxParent.get();
+}
+
+// XChild
+void SAL_CALL RandomAnimationNode::setParent( const Reference< XInterface >& Parent )
+{
+ Guard< Mutex > aGuard( maMutex );
+ mxParent = Parent;
+}
+
+// XCloneable
+Reference< XCloneable > SAL_CALL RandomAnimationNode::createClone()
+{
+ Reference< XCloneable > xNewNode( new RandomAnimationNode( *this ) );
+ return xNewNode;
+}
+
+// XElementAccess
+Type SAL_CALL RandomAnimationNode::getElementType()
+{
+ return cppu::UnoType<XAnimationNode>::get();
+}
+
+// XElementAccess
+sal_Bool SAL_CALL RandomAnimationNode::hasElements()
+{
+ return true;
+}
+
+// XEnumerationAccess
+Reference< XEnumeration > SAL_CALL RandomAnimationNode::createEnumeration()
+{
+ Guard< Mutex > aGuard( maMutex );
+
+ if( !maTarget.hasValue() && mxFirstNode.is() )
+ {
+ Any aTarget( mxFirstNode->getTarget() );
+ if( aTarget.hasValue() )
+ {
+ maTarget = aTarget;
+ mxFirstNode.clear();
+ }
+ }
+
+ Reference< XEnumeration > xEnum;
+
+ Reference< XEnumerationAccess > aEnumAccess( CustomAnimationPresets::getCustomAnimationPresets().getRandomPreset( mnPresetClass ), UNO_QUERY );
+
+ if( aEnumAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = aEnumAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
+ if( xAnimate.is() )
+ xAnimate->setTarget( maTarget );
+ }
+ }
+ xEnum = aEnumAccess->createEnumeration();
+ }
+ else
+ {
+ // no presets? give empty node!
+ Reference< XParallelTimeContainer > xTimeContainer = ParallelTimeContainer::create( comphelper::getProcessComponentContext() );
+ xEnum = xTimeContainer->createEnumeration();
+ }
+
+ return xEnum;
+}
+
+// XTimeContainer
+Reference< XAnimationNode > SAL_CALL RandomAnimationNode::insertBefore( const Reference< XAnimationNode >& newChild, const Reference< XAnimationNode >& )
+{
+ return appendChild( newChild );
+}
+
+// XTimeContainer
+Reference< XAnimationNode > SAL_CALL RandomAnimationNode::insertAfter( const Reference< XAnimationNode >& newChild, const Reference< XAnimationNode >& )
+{
+ return appendChild( newChild );
+}
+
+// XTimeContainer
+Reference< XAnimationNode > SAL_CALL RandomAnimationNode::replaceChild( const Reference< XAnimationNode >& newChild, const Reference< XAnimationNode >& )
+{
+ return appendChild( newChild );
+}
+
+// XTimeContainer
+Reference< XAnimationNode > SAL_CALL RandomAnimationNode::removeChild( const Reference< XAnimationNode >& oldChild )
+{
+ return oldChild;
+}
+
+// XTimeContainer
+Reference< XAnimationNode > SAL_CALL RandomAnimationNode::appendChild( const Reference< XAnimationNode >& newChild )
+{
+ Reference< XAnimate > xAnimate( newChild, UNO_QUERY );
+ if( xAnimate.is() )
+ {
+ Any aTarget( xAnimate->getTarget() );
+ if( aTarget.hasValue() )
+ maTarget = aTarget;
+ }
+
+ if( !maTarget.hasValue() && !mxFirstNode.is() )
+ mxFirstNode = xAnimate;
+
+ return newChild;
+}
+
+// XServiceInfo
+OUString RandomAnimationNode::getImplementationName()
+{
+ return "sd::RandomAnimationNode" ;
+}
+
+// XServiceInfo
+sal_Bool RandomAnimationNode::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > RandomAnimationNode::getSupportedServiceNames()
+{
+ return { "com.sun.star.animations.ParallelTimeContainer", "com.sun.star.comp.sd.RandomAnimationNode" };
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+RandomAnimationNode_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::RandomAnimationNode());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/sddetect.cxx b/sd/source/ui/unoidl/sddetect.cxx
new file mode 100644
index 000000000..cfa50d141
--- /dev/null
+++ b/sd/source/ui/unoidl/sddetect.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "sddetect.hxx"
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <vcl/graphicfilter.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <vcl/FilterConfigItem.hxx>
+#include <sot/storage.hxx>
+#include <unotools/mediadescriptor.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using utl::MediaDescriptor;
+
+SdFilterDetect::SdFilterDetect()
+{
+}
+
+SdFilterDetect::~SdFilterDetect()
+{
+}
+
+OUString SAL_CALL SdFilterDetect::detect( Sequence< beans::PropertyValue >& lDescriptor )
+{
+ MediaDescriptor aMediaDesc( lDescriptor );
+ OUString aTypeName = aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_TYPENAME, OUString() );
+ uno::Reference< io::XInputStream > xInStream ( aMediaDesc[MediaDescriptor::PROP_INPUTSTREAM], uno::UNO_QUERY );
+ if ( !xInStream.is() )
+ return OUString();
+
+ SfxMedium aMedium;
+ aMedium.UseInteractionHandler( false );
+ aMedium.setStreamToLoadFrom( xInStream, true );
+
+ SvStream *pInStrm = aMedium.GetInStream();
+ if ( !pInStrm || pInStrm->GetError() )
+ return OUString();
+
+ if ( aTypeName.startsWith( "impress_MS_PowerPoint_97" ) )
+ {
+ // Do not attempt to create an SotStorage on a
+ // 0-length stream as that would create the compound
+ // document header on the stream and effectively write to
+ // disk!
+ pInStrm->Seek( STREAM_SEEK_TO_BEGIN );
+ if ( pInStrm->remainingSize() == 0 )
+ return OUString();
+
+ try
+ {
+ tools::SvRef<SotStorage> aStorage = new SotStorage( pInStrm, false );
+ if ( !aStorage->GetError() && aStorage->IsStream( "PowerPoint Document" ) )
+ return aTypeName;
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ }
+ }
+ else
+ {
+ pInStrm->Seek( STREAM_SEEK_TO_BEGIN );
+
+ const OUString aFileName( aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_URL, OUString() ) );
+ GraphicDescriptor aDesc( *pInStrm, &aFileName );
+ if( !aDesc.Detect() )
+ {
+ INetURLObject aCheckURL( aFileName );
+ if( aCheckURL.getExtension().equalsIgnoreAsciiCase("cgm") )
+ {
+ sal_uInt8 n8;
+ pInStrm->Seek( STREAM_SEEK_TO_BEGIN );
+ pInStrm->ReadUChar( n8 );
+ if ( ( n8 & 0xf0 ) == 0 )
+ // we are supporting binary cgm format only, so
+ // this is a small test to exclude cgm text
+ return "impress_CGM_Computer_Graphics_Metafile";
+ }
+ }
+ else
+ {
+ OUString aShortName( GraphicDescriptor::GetImportFormatShortName( aDesc.GetFileFormat() ) );
+ GraphicFilter &rGrfFilter = GraphicFilter::GetGraphicFilter();
+ const OUString aName( rGrfFilter.GetImportFormatTypeName( rGrfFilter.GetImportFormatNumberForShortName( aShortName ) ) );
+
+ if ( aShortName.equalsIgnoreAsciiCase( "PCD" ) ) // there is a multiple pcd selection possible
+ {
+ sal_Int32 nBase = 2; // default Base0
+ if ( aTypeName == "pcd_Photo_CD_Base4" )
+ nBase = 1;
+ else if ( aTypeName == "pcd_Photo_CD_Base16" )
+ nBase = 0;
+ FilterConfigItem aFilterConfigItem( u"Office.Common/Filter/Graphic/Import/PCD" );
+ aFilterConfigItem.WriteInt32( "Resolution" , nBase );
+ }
+
+ SfxFilterMatcher aMatch("sdraw");
+ std::shared_ptr<const SfxFilter> pFilter = aMatch.GetFilter4FilterName( aName );
+ if ( pFilter )
+ return pFilter->GetRealTypeName();
+ }
+ }
+
+ return OUString();
+}
+
+// XServiceInfo
+OUString SAL_CALL SdFilterDetect::getImplementationName()
+{
+ return "com.sun.star.comp.draw.FormatDetector";
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL SdFilterDetect::supportsService( const OUString& sServiceName )
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > SAL_CALL SdFilterDetect::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ExtendedTypeDetection" };
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_draw_FormatDetector_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SdFilterDetect());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/sddetect.hxx b/sd/source/ui/unoidl/sddetect.hxx
new file mode 100644
index 000000000..3d22cc12c
--- /dev/null
+++ b/sd/source/ui/unoidl/sddetect.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/document/XExtendedFilterDetection.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+
+namespace com::sun::star::beans { struct PropertyValue; }
+
+class SdFilterDetect : public ::cppu::WeakImplHelper< css::document::XExtendedFilterDetection, css::lang::XServiceInfo >
+{
+public:
+ SdFilterDetect();
+ virtual ~SdFilterDetect() override;
+
+ // XServiceInfo
+
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& sServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XExtendedFilterDetect
+
+ virtual OUString SAL_CALL detect( css::uno::Sequence< css::beans::PropertyValue >& lDescriptor ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unocpres.cxx b/sd/source/ui/unoidl/unocpres.cxx
new file mode 100644
index 000000000..cc57b1e79
--- /dev/null
+++ b/sd/source/ui/unoidl/unocpres.cxx
@@ -0,0 +1,450 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <algorithm>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <o3tl/safeint.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/svdpage.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <createunocustomshow.hxx>
+#include <unomodel.hxx>
+#include <drawdoc.hxx>
+#include "unocpres.hxx"
+#include <cusshow.hxx>
+#include <unopage.hxx>
+#include <customshowlist.hxx>
+
+using namespace ::com::sun::star;
+
+uno::Reference< uno::XInterface > createUnoCustomShow( SdCustomShow* pShow )
+{
+ return static_cast<cppu::OWeakObject*>(new SdXCustomPresentation( pShow ));
+}
+
+SdXCustomPresentation::SdXCustomPresentation() noexcept
+: mpSdCustomShow(nullptr), mpModel(nullptr),
+ aDisposeListeners( aDisposeContainerMutex ),
+ bDisposing( false )
+{
+}
+
+SdXCustomPresentation::SdXCustomPresentation( SdCustomShow* pShow) noexcept
+: mpSdCustomShow(pShow), mpModel(nullptr),
+ aDisposeListeners( aDisposeContainerMutex ),
+ bDisposing( false )
+{
+}
+
+SdXCustomPresentation::~SdXCustomPresentation() noexcept
+{
+}
+
+UNO3_GETIMPLEMENTATION_IMPL( SdXCustomPresentation );
+
+// XServiceInfo
+OUString SAL_CALL SdXCustomPresentation::getImplementationName()
+{
+ return "SdXCustomPresentation" ;
+}
+
+sal_Bool SAL_CALL SdXCustomPresentation::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL SdXCustomPresentation::getSupportedServiceNames()
+{
+ return { "com.sun.star.presentation.CustomPresentation" };
+}
+
+// XIndexContainer
+void SAL_CALL SdXCustomPresentation::insertByIndex( sal_Int32 Index, const uno::Any& Element )
+{
+ SolarMutexGuard aGuard;
+
+ if( bDisposing )
+ throw lang::DisposedException();
+
+ if( Index < 0 || o3tl::make_unsigned(Index) > ( mpSdCustomShow ? mpSdCustomShow->PagesVector().size() : 0 ) )
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference< drawing::XDrawPage > xPage;
+ Element >>= xPage;
+
+ if(!xPage.is())
+ throw lang::IllegalArgumentException();
+
+ SdDrawPage* pPage = comphelper::getFromUnoTunnel<SdDrawPage>( xPage );
+
+ if(pPage)
+ {
+ if( nullptr == mpModel )
+ mpModel = pPage->GetModel();
+
+ if( nullptr != mpModel && nullptr == mpSdCustomShow && mpModel->GetDoc() )
+ mpSdCustomShow = new SdCustomShow;
+
+ mpSdCustomShow->PagesVector().insert(mpSdCustomShow->PagesVector().begin() + Index,
+ static_cast<SdPage*>(pPage->GetSdrPage()));
+ }
+
+ if( mpModel )
+ mpModel->SetModified();
+}
+
+void SAL_CALL SdXCustomPresentation::removeByIndex( sal_Int32 Index )
+{
+ SolarMutexGuard aGuard;
+
+ if( bDisposing )
+ throw lang::DisposedException();
+
+ if(mpSdCustomShow)
+ {
+ uno::Reference< drawing::XDrawPage > xPage;
+ getByIndex( Index ) >>= xPage;
+
+ if( xPage.is() )
+ {
+ SvxDrawPage* pPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
+ if(pPage)
+ {
+ SdCustomShow::PageVec::iterator it = std::find(
+ mpSdCustomShow->PagesVector().begin(),
+ mpSdCustomShow->PagesVector().end(),
+ pPage->GetSdrPage());
+ if (it != mpSdCustomShow->PagesVector().end())
+ mpSdCustomShow->PagesVector().erase(it);
+ }
+ }
+ }
+
+ if( mpModel )
+ mpModel->SetModified();
+}
+
+// XIndexReplace
+void SAL_CALL SdXCustomPresentation::replaceByIndex( sal_Int32 Index, const uno::Any& Element )
+{
+ removeByIndex( Index );
+ insertByIndex( Index, Element );
+}
+
+// XElementAccess
+uno::Type SAL_CALL SdXCustomPresentation::getElementType()
+{
+ return cppu::UnoType<drawing::XDrawPage>::get();
+}
+
+sal_Bool SAL_CALL SdXCustomPresentation::hasElements()
+{
+ SolarMutexGuard aGuard;
+
+ if( bDisposing )
+ throw lang::DisposedException();
+
+ return getCount() > 0;
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SdXCustomPresentation::getCount()
+{
+ SolarMutexGuard aGuard;
+ if( bDisposing )
+ throw lang::DisposedException();
+
+ return mpSdCustomShow ? mpSdCustomShow->PagesVector().size() : 0;
+}
+
+uno::Any SAL_CALL SdXCustomPresentation::getByIndex( sal_Int32 Index )
+{
+ SolarMutexGuard aGuard;
+
+ if( bDisposing )
+ throw lang::DisposedException();
+
+ if (Index < 0 || !mpSdCustomShow || o3tl::make_unsigned(Index) >= mpSdCustomShow->PagesVector().size())
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Any aAny;
+ SdrPage * pPage = const_cast<SdPage *>(mpSdCustomShow->PagesVector()[Index]);
+
+ if( pPage )
+ {
+ uno::Reference< drawing::XDrawPage > xRef( pPage->getUnoPage(), uno::UNO_QUERY );
+ aAny <<= xRef;
+ }
+
+ return aAny;
+}
+
+// XNamed
+OUString SAL_CALL SdXCustomPresentation::getName()
+{
+ SolarMutexGuard aGuard;
+
+ if( bDisposing )
+ throw lang::DisposedException();
+
+ if(mpSdCustomShow)
+ return mpSdCustomShow->GetName();
+
+ return OUString();
+}
+
+void SAL_CALL SdXCustomPresentation::setName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ if( bDisposing )
+ throw lang::DisposedException();
+
+ if(mpSdCustomShow)
+ mpSdCustomShow->SetName( aName );
+}
+
+// XComponent
+void SAL_CALL SdXCustomPresentation::dispose()
+{
+ SolarMutexGuard aGuard;
+
+ if( bDisposing )
+ return; // caught a recursion
+
+ bDisposing = true;
+
+ uno::Reference< uno::XInterface > xSource( static_cast<cppu::OWeakObject*>(this) );
+
+ lang::EventObject aEvt;
+ aEvt.Source = xSource;
+ aDisposeListeners.disposeAndClear(aEvt);
+
+ mpSdCustomShow = nullptr;
+}
+
+void SAL_CALL SdXCustomPresentation::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ if( bDisposing )
+ throw lang::DisposedException();
+
+ aDisposeListeners.addInterface(xListener);
+}
+
+void SAL_CALL SdXCustomPresentation::removeEventListener( const uno::Reference< lang::XEventListener >& aListener )
+{
+ if( !bDisposing )
+ aDisposeListeners.removeInterface(aListener);
+}
+
+/*===========================================================================*
+ * class SdXCustomPresentationAccess : public XCustomPresentationAccess, *
+ * public UsrObject *
+ *===========================================================================*/
+
+SdXCustomPresentationAccess::SdXCustomPresentationAccess(SdXImpressDocument& rMyModel) noexcept
+: mrModel(rMyModel)
+{
+}
+
+SdXCustomPresentationAccess::~SdXCustomPresentationAccess() noexcept
+{
+}
+
+// XServiceInfo
+OUString SAL_CALL SdXCustomPresentationAccess::getImplementationName()
+{
+ return "SdXCustomPresentationAccess";
+}
+
+sal_Bool SAL_CALL SdXCustomPresentationAccess::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL SdXCustomPresentationAccess::getSupportedServiceNames()
+{
+ return { "com.sun.star.presentation.CustomPresentationAccess" };
+}
+
+// XSingleServiceFactory
+uno::Reference< uno::XInterface > SAL_CALL SdXCustomPresentationAccess::createInstance()
+{
+ uno::Reference< uno::XInterface > xRef( static_cast<cppu::OWeakObject*>(new SdXCustomPresentation()) );
+ return xRef;
+}
+
+uno::Reference< uno::XInterface > SAL_CALL SdXCustomPresentationAccess::createInstanceWithArguments( const uno::Sequence< uno::Any >& )
+{
+ return createInstance();
+}
+
+// XNameContainer
+void SAL_CALL SdXCustomPresentationAccess::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+
+ // get the documents custom show list
+ SdCustomShowList* pList = nullptr;
+ if(mrModel.GetDoc())
+ pList = mrModel.GetDoc()->GetCustomShowList(true);
+
+ // no list, no cookies
+ if( nullptr == pList)
+ throw uno::RuntimeException();
+
+ // do we have a container::XIndexContainer?
+ SdXCustomPresentation* pXShow = nullptr;
+
+ uno::Reference< container::XIndexContainer > xContainer;
+ if( (aElement >>= xContainer) && xContainer.is() )
+ pXShow = comphelper::getFromUnoTunnel<SdXCustomPresentation>(xContainer);
+
+ if( nullptr == pXShow )
+ throw lang::IllegalArgumentException();
+
+ // get the internal custom show from the api wrapper
+ SdCustomShow* pShow = pXShow->GetSdCustomShow();
+ if( nullptr == pShow )
+ {
+ pShow = new SdCustomShow( xContainer );
+ pXShow->SetSdCustomShow( pShow );
+ }
+ else
+ {
+ if( nullptr == pXShow->GetModel() || *pXShow->GetModel() != mrModel )
+ throw lang::IllegalArgumentException();
+ }
+
+ // give it a name
+ pShow->SetName( aName);
+
+ // check if this or another customshow with the same name already exists
+ for( SdCustomShow* pCompare = pList->First();
+ pCompare;
+ pCompare = pList->Next() )
+ {
+ if( pCompare == pShow || pCompare->GetName() == pShow->GetName() )
+ throw container::ElementExistException();
+ }
+
+ pList->push_back(std::unique_ptr<SdCustomShow>(pShow));
+
+ mrModel.SetModified();
+}
+
+void SAL_CALL SdXCustomPresentationAccess::removeByName( const OUString& Name )
+{
+ SolarMutexGuard aGuard;
+
+ SdCustomShow* pShow = getSdCustomShow(Name);
+
+ SdCustomShowList* pList = GetCustomShowList();
+ if(!pList || !pShow)
+ throw container::NoSuchElementException();
+
+ pList->erase( pShow );
+
+ mrModel.SetModified();
+}
+
+// XNameReplace
+void SAL_CALL SdXCustomPresentationAccess::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ removeByName( aName );
+ insertByName( aName, aElement );
+}
+
+// XNameAccess
+uno::Any SAL_CALL SdXCustomPresentationAccess::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ SdCustomShow* pShow = getSdCustomShow(aName);
+ if(!pShow)
+ {
+ throw container::NoSuchElementException();
+ }
+
+ uno::Reference< container::XIndexContainer > xRef( pShow->getUnoCustomShow(), uno::UNO_QUERY );
+ return uno::Any(xRef);
+}
+
+uno::Sequence< OUString > SAL_CALL SdXCustomPresentationAccess::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ SdCustomShowList* pList = GetCustomShowList();
+ const sal_uInt32 nCount = pList ? pList->size() : 0;
+
+ uno::Sequence< OUString > aSequence( nCount );
+ OUString* pStringList = aSequence.getArray();
+
+ sal_uInt32 nIdx = 0;
+ while( nIdx < nCount )
+ {
+ const SdCustomShow* pShow = (*pList)[nIdx].get();
+ pStringList[nIdx] = pShow->GetName();
+ nIdx++;
+ }
+
+ return aSequence;
+}
+
+sal_Bool SAL_CALL SdXCustomPresentationAccess::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ return getSdCustomShow(aName) != nullptr;
+}
+
+// XElementAccess
+uno::Type SAL_CALL SdXCustomPresentationAccess::getElementType()
+{
+ return cppu::UnoType<container::XIndexContainer>::get();
+}
+
+sal_Bool SAL_CALL SdXCustomPresentationAccess::hasElements()
+{
+ SolarMutexGuard aGuard;
+
+ SdCustomShowList* pList = GetCustomShowList();
+ return pList && !pList->empty();
+}
+
+SdCustomShow * SdXCustomPresentationAccess::getSdCustomShow( std::u16string_view rName ) const noexcept
+{
+ sal_uInt32 nIdx = 0;
+
+ SdCustomShowList* pList = GetCustomShowList();
+ const sal_uInt32 nCount = pList ? pList->size() : 0;
+
+ while( nIdx < nCount )
+ {
+ SdCustomShow* pShow = (*pList)[nIdx].get();
+ if( pShow->GetName() == rName )
+ return pShow;
+ nIdx++;
+ }
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unocpres.hxx b/sd/source/ui/unoidl/unocpres.hxx
new file mode 100644
index 000000000..e32dce956
--- /dev/null
+++ b/sd/source/ui/unoidl/unocpres.hxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <comphelper/interfacecontainer3.hxx>
+#include <osl/mutex.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+
+#include <unomodel.hxx>
+#include <drawdoc.hxx>
+
+
+class SdCustomShow;
+
+class SdXCustomPresentation : public ::cppu::WeakImplHelper< css::container::XIndexContainer,
+ css::container::XNamed,
+ css::lang::XUnoTunnel,
+ css::lang::XComponent,
+ css::lang::XServiceInfo >
+{
+private:
+ SdCustomShow* mpSdCustomShow;
+ SdXImpressDocument* mpModel;
+
+ // for xComponent
+ ::osl::Mutex aDisposeContainerMutex;
+ ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> aDisposeListeners;
+ bool bDisposing;
+
+public:
+ SdXCustomPresentation() noexcept;
+ explicit SdXCustomPresentation( SdCustomShow* mpSdCustomShow ) noexcept;
+ virtual ~SdXCustomPresentation() noexcept override;
+
+ // internal
+ SdCustomShow* GetSdCustomShow() const noexcept { return mpSdCustomShow; }
+ void SetSdCustomShow( SdCustomShow* pShow ) noexcept { mpSdCustomShow = pShow; }
+ SdXImpressDocument* GetModel() const noexcept { return mpModel; }
+
+ // uno helper
+ UNO3_GETIMPLEMENTATION_DECL(SdXCustomPresentation)
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XIndexContainer
+ virtual void SAL_CALL insertByIndex( sal_Int32 Index, const css::uno::Any& Element ) override;
+ virtual void SAL_CALL removeByIndex( sal_Int32 Index ) override;
+
+ // XIndexReplace
+ virtual void SAL_CALL replaceByIndex( sal_Int32 Index, const css::uno::Any& Element ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+};
+
+class SdXCustomPresentationAccess : public ::cppu::WeakImplHelper< css::container::XNameContainer,
+ css::lang::XSingleServiceFactory,
+ css::lang::XServiceInfo >
+{
+private:
+ SdXImpressDocument& mrModel;
+
+ // intern
+ inline SdCustomShowList* GetCustomShowList() const noexcept;
+ SdCustomShow * getSdCustomShow( std::u16string_view Name ) const noexcept;
+
+public:
+ explicit SdXCustomPresentationAccess(SdXImpressDocument& rMyModel) noexcept;
+ virtual ~SdXCustomPresentationAccess() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XSingleServiceFactory
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& aName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& Name ) override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+};
+
+inline SdCustomShowList* SdXCustomPresentationAccess::GetCustomShowList() const noexcept
+{
+ if(mrModel.GetDoc())
+ return mrModel.GetDoc()->GetCustomShowList();
+ else
+ return nullptr;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unodoc.cxx b/sd/source/ui/unoidl/unodoc.cxx
new file mode 100644
index 000000000..cfb97c186
--- /dev/null
+++ b/sd/source/ui/unoidl/unodoc.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 <sfx2/sfxmodelfactory.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+
+#include <sddll.hxx>
+#include <DrawDocShell.hxx>
+#include <GraphicDocShell.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+
+// com.sun.star.comp.Draw.DrawingDocument
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+sd_DrawingDocument_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const& args)
+{
+ SolarMutexGuard aGuard;
+
+ SdDLL::Init();
+
+ css::uno::Reference<css::uno::XInterface> xInterface = sfx2::createSfxModelInstance(args,
+ [](SfxModelFlags _nCreationFlags)
+ {
+ SfxObjectShell* pShell = new ::sd::GraphicDocShell( _nCreationFlags );
+ return uno::Reference< uno::XInterface >( pShell->GetModel() );
+ });
+ xInterface->acquire();
+ return xInterface.get();
+}
+
+
+// com.sun.star.comp.Draw.PresentationDocument
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+sd_PresentationDocument_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const& args)
+{
+ SolarMutexGuard aGuard;
+
+ SdDLL::Init();
+
+ css::uno::Reference<css::uno::XInterface> xInterface = sfx2::createSfxModelInstance(args,
+ [](SfxModelFlags _nCreationFlags)
+ {
+ SfxObjectShell* pShell =
+ new ::sd::DrawDocShell(
+ _nCreationFlags, false, DocumentType::Impress );
+ return pShell->GetModel();
+ });
+ xInterface->acquire();
+ return xInterface.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unolayer.cxx b/sd/source/ui/unoidl/unolayer.cxx
new file mode 100644
index 000000000..c6bc3cdf3
--- /dev/null
+++ b/sd/source/ui/unoidl/unolayer.cxx
@@ -0,0 +1,707 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include "unolayer.hxx"
+
+#include <comphelper/extract.hxx>
+#include <editeng/unoipset.hxx>
+#include <osl/diagnose.h>
+#include <svl/itemprop.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdobj.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+// following ones for InsertSdPage()
+#include <svx/svdlayer.hxx>
+
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <unomodel.hxx>
+#include <unoprnms.hxx>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <svx/svdpool.hxx>
+#include <FrameView.hxx>
+#include <DrawViewShell.hxx>
+#include <View.hxx>
+#include <ViewShell.hxx>
+#include <strings.hrc>
+#include <sdresid.hxx>
+
+#include "unowcntr.hxx"
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+
+// class SdLayer
+#define WID_LAYER_LOCKED 1
+#define WID_LAYER_PRINTABLE 2
+#define WID_LAYER_VISIBLE 3
+#define WID_LAYER_NAME 4
+#define WID_LAYER_TITLE 5
+#define WID_LAYER_DESC 6
+
+static const SvxItemPropertySet* ImplGetSdLayerPropertySet()
+{
+ static const SfxItemPropertyMapEntry aSdLayerPropertyMap_Impl[] =
+ {
+ { u"" UNO_NAME_LAYER_LOCKED, WID_LAYER_LOCKED, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"" UNO_NAME_LAYER_PRINTABLE, WID_LAYER_PRINTABLE,cppu::UnoType<bool>::get(), 0, 0 },
+ { u"" UNO_NAME_LAYER_VISIBLE, WID_LAYER_VISIBLE, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"" UNO_NAME_LAYER_NAME, WID_LAYER_NAME, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"Title", WID_LAYER_TITLE, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"Description", WID_LAYER_DESC, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SvxItemPropertySet aSDLayerPropertySet_Impl( aSdLayerPropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ return &aSDLayerPropertySet_Impl;
+}
+
+SdLayer::SdLayer(SdLayerManager* pLayerManager_, SdrLayer* pSdrLayer_)
+: mxLayerManager(pLayerManager_)
+, pLayer(pSdrLayer_)
+, pPropSet(ImplGetSdLayerPropertySet())
+{
+ // no defaults possible yet, a "set" would overwrite existing information
+ // in view, which is currently needed for saving, because pLayer is not updated
+ // from view.
+}
+
+SdLayer::~SdLayer() noexcept
+{
+}
+
+// uno helper
+UNO3_GETIMPLEMENTATION_IMPL( SdLayer );
+
+// XServiceInfo
+OUString SAL_CALL SdLayer::getImplementationName()
+{
+ return "SdUnoLayer";
+}
+
+sal_Bool SAL_CALL SdLayer::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL SdLayer::getSupportedServiceNames()
+{
+ return { "com.sun.star.drawing.Layer" };
+}
+
+// beans::XPropertySet
+uno::Reference< beans::XPropertySetInfo > SAL_CALL SdLayer::getPropertySetInfo( )
+{
+ SolarMutexGuard aGuard;
+ return pPropSet->getPropertySetInfo();
+}
+
+void SAL_CALL SdLayer::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if(pLayer == nullptr || mxLayerManager == nullptr)
+ throw lang::DisposedException();
+
+ const SfxItemPropertyMapEntry* pEntry = pPropSet->getPropertyMapEntry(aPropertyName);
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case WID_LAYER_LOCKED:
+ {
+ pLayer->SetLockedODF( cppu::any2bool(aValue) );
+ set(LOCKED, cppu::any2bool(aValue)); // changes the View, if any exists
+ break;
+ }
+ case WID_LAYER_PRINTABLE:
+ {
+ pLayer->SetPrintableODF( cppu::any2bool(aValue) );
+ set(PRINTABLE, cppu::any2bool(aValue)); // changes the View, if any exists
+ break;
+ }
+ case WID_LAYER_VISIBLE:
+ {
+ pLayer->SetVisibleODF( cppu::any2bool(aValue) );
+ set(VISIBLE, cppu::any2bool(aValue)); // changes the View, if any exists
+ break;
+ }
+ case WID_LAYER_NAME:
+ {
+ OUString aName;
+ if(!(aValue >>= aName))
+ throw lang::IllegalArgumentException();
+
+ pLayer->SetName(aName);
+ mxLayerManager->UpdateLayerView();
+ break;
+ }
+
+ case WID_LAYER_TITLE:
+ {
+ OUString sTitle;
+ if(!(aValue >>= sTitle))
+ throw lang::IllegalArgumentException();
+
+ pLayer->SetTitle(sTitle);
+ break;
+ }
+
+ case WID_LAYER_DESC:
+ {
+ OUString sDescription;
+ if(!(aValue >>= sDescription))
+ throw lang::IllegalArgumentException();
+
+ pLayer->SetDescription(sDescription);
+ break;
+ }
+
+ default:
+ throw beans::UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ if( mxLayerManager->GetDocShell() )
+ mxLayerManager->GetDocShell()->SetModified();
+}
+
+uno::Any SAL_CALL SdLayer::getPropertyValue( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if(pLayer == nullptr || mxLayerManager == nullptr)
+ throw lang::DisposedException();
+
+ const SfxItemPropertyMapEntry* pEntry = pPropSet->getPropertyMapEntry(PropertyName);
+
+ uno::Any aValue;
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case WID_LAYER_LOCKED:
+ aValue <<= get( LOCKED );
+ break;
+ case WID_LAYER_PRINTABLE:
+ aValue <<= get( PRINTABLE );
+ break;
+ case WID_LAYER_VISIBLE:
+ aValue <<= get( VISIBLE );
+ break;
+ case WID_LAYER_NAME:
+ {
+ OUString aRet(pLayer->GetName());
+ aValue <<= aRet;
+ break;
+ }
+ case WID_LAYER_TITLE:
+ aValue <<= pLayer->GetTitle();
+ break;
+ case WID_LAYER_DESC:
+ aValue <<= pLayer->GetDescription();
+ break;
+ default:
+ throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ return aValue;
+}
+
+void SAL_CALL SdLayer::addPropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& ) {}
+void SAL_CALL SdLayer::removePropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& ) {}
+void SAL_CALL SdLayer::addVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& ) {}
+void SAL_CALL SdLayer::removeVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& ) {}
+
+bool SdLayer::get( LayerAttribute what ) noexcept
+{
+ if(pLayer && mxLayerManager.is())
+ {
+ // Try 1. is an arbitrary page open?
+ ::sd::View *pView = mxLayerManager->GetView();
+ SdrPageView* pSdrPageView = nullptr;
+ if(pView)
+ pSdrPageView = pView->GetSdrPageView();
+
+ if(pSdrPageView)
+ {
+ OUString aLayerName = pLayer->GetName();
+ switch(what)
+ {
+ case VISIBLE: return pSdrPageView->IsLayerVisible(aLayerName);
+ case PRINTABLE: return pSdrPageView->IsLayerPrintable(aLayerName);
+ case LOCKED: return pSdrPageView->IsLayerLocked(aLayerName);
+ }
+ }
+
+ // Try 2. get info from FrameView
+ if(mxLayerManager->GetDocShell())
+ {
+ ::sd::FrameView *pFrameView = mxLayerManager->GetDocShell()->GetFrameView();
+ if(pFrameView)
+ switch(what)
+ {
+ case VISIBLE: return pFrameView->GetVisibleLayers().IsSet(pLayer->GetID());
+ case PRINTABLE: return pFrameView->GetPrintableLayers().IsSet(pLayer->GetID());
+ case LOCKED: return pFrameView->GetLockedLayers().IsSet(pLayer->GetID());
+ }
+ }
+
+ // no view at all, e.g. Draw embedded as OLE in text document, ODF default values
+ switch(what)
+ {
+ case VISIBLE: return true;
+ case PRINTABLE: return true;
+ case LOCKED: return false;
+ }
+
+ }
+ return false; //TODO: uno::Exception?
+}
+
+void SdLayer::set( LayerAttribute what, bool flag ) noexcept
+{
+ if(!(pLayer && mxLayerManager.is()))
+ return;
+
+ // Try 1. is an arbitrary page open?
+ ::sd::View *pView = mxLayerManager->GetView();
+ SdrPageView* pSdrPageView = nullptr;
+ if(pView)
+ pSdrPageView = pView->GetSdrPageView();
+
+ if(pSdrPageView)
+ {
+ OUString aLayerName(pLayer->GetName());
+ switch(what)
+ {
+ case VISIBLE: pSdrPageView->SetLayerVisible(aLayerName,flag);
+ break;
+ case PRINTABLE: pSdrPageView->SetLayerPrintable(aLayerName,flag);
+ break;
+ case LOCKED: pSdrPageView->SetLayerLocked(aLayerName,flag);
+ break;
+ }
+ }
+
+ // Try 2. get info from FrameView
+ if(!mxLayerManager->GetDocShell())
+ return;
+
+ ::sd::FrameView *pFrameView = mxLayerManager->GetDocShell()->GetFrameView();
+
+ if(!pFrameView)
+ return;
+
+ SdrLayerIDSet aNewLayers;
+ switch(what)
+ {
+ case VISIBLE: aNewLayers = pFrameView->GetVisibleLayers();
+ break;
+ case PRINTABLE: aNewLayers = pFrameView->GetPrintableLayers();
+ break;
+ case LOCKED: aNewLayers = pFrameView->GetLockedLayers();
+ break;
+ }
+
+ aNewLayers.Set(pLayer->GetID(),flag);
+
+ switch(what)
+ {
+ case VISIBLE: pFrameView->SetVisibleLayers(aNewLayers);
+ break;
+ case PRINTABLE: pFrameView->SetPrintableLayers(aNewLayers);
+ break;
+ case LOCKED: pFrameView->SetLockedLayers(aNewLayers);
+ break;
+ }
+ return;
+ //TODO: uno::Exception?
+}
+
+// css::container::XChild
+uno::Reference<uno::XInterface> SAL_CALL SdLayer::getParent()
+{
+ SolarMutexGuard aGuard;
+
+ if( !mxLayerManager.is() )
+ throw lang::DisposedException();
+
+ return uno::Reference<uno::XInterface> (static_cast<cppu::OWeakObject*>(mxLayerManager.get()), uno::UNO_QUERY);
+}
+
+void SAL_CALL SdLayer::setParent (const uno::Reference<uno::XInterface >& )
+{
+ throw lang::NoSupportException ();
+}
+
+// XComponent
+void SAL_CALL SdLayer::dispose( )
+{
+ mxLayerManager.clear();
+ pLayer = nullptr;
+}
+
+void SAL_CALL SdLayer::addEventListener( const uno::Reference< lang::XEventListener >& )
+{
+ OSL_FAIL("not implemented!");
+}
+
+void SAL_CALL SdLayer::removeEventListener( const uno::Reference< lang::XEventListener >& )
+{
+ OSL_FAIL("not implemented!");
+}
+
+// class SdLayerManager
+SdLayerManager::SdLayerManager( SdXImpressDocument& rMyModel ) noexcept
+:mpModel( &rMyModel)
+{
+ mpLayers.reset(new SvUnoWeakContainer);
+}
+
+SdLayerManager::~SdLayerManager() noexcept
+{
+ dispose();
+}
+
+// uno helper
+UNO3_GETIMPLEMENTATION_IMPL( SdLayerManager );
+
+// XComponent
+void SAL_CALL SdLayerManager::dispose( )
+{
+ mpModel = nullptr;
+ if( mpLayers )
+ {
+ mpLayers->dispose();
+ mpLayers.reset();
+ }
+}
+
+void SAL_CALL SdLayerManager::addEventListener( const uno::Reference< lang::XEventListener >& )
+{
+ OSL_FAIL("not implemented!");
+}
+
+void SAL_CALL SdLayerManager::removeEventListener( const uno::Reference< lang::XEventListener >& )
+{
+ OSL_FAIL("not implemented!");
+}
+
+// XServiceInfo
+OUString SAL_CALL SdLayerManager::getImplementationName()
+{
+ return "SdUnoLayerManager";
+}
+
+sal_Bool SAL_CALL SdLayerManager::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL SdLayerManager::getSupportedServiceNames()
+{
+ return {"com.sun.star.drawing.LayerManager"};
+}
+
+// XLayerManager
+uno::Reference< drawing::XLayer > SAL_CALL SdLayerManager::insertNewByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel == nullptr )
+ throw lang::DisposedException();
+
+ uno::Reference< drawing::XLayer > xLayer;
+
+ if( mpModel->mpDoc )
+ {
+ SdrLayerAdmin& rLayerAdmin = mpModel->mpDoc->GetLayerAdmin();
+ sal_uInt16 nLayerCnt = rLayerAdmin.GetLayerCount();
+ sal_Int32 nLayer = nLayerCnt - 2 + 1;
+ OUString aLayerName;
+
+ // Test for existing names
+ while( aLayerName.isEmpty() || rLayerAdmin.GetLayer( aLayerName ) )
+ {
+ aLayerName = SdResId(STR_LAYER) + OUString::number(nLayer);
+ ++nLayer;
+ }
+
+ SdrLayerAdmin& rLA=mpModel->mpDoc->GetLayerAdmin();
+ const sal_Int32 nMax=rLA.GetLayerCount();
+ if (nIndex>nMax) nIndex=nMax;
+ xLayer = GetLayer (rLA.NewLayer(aLayerName,static_cast<sal_uInt16>(nIndex)));
+ mpModel->SetModified();
+ }
+ return xLayer;
+}
+
+void SAL_CALL SdLayerManager::remove( const uno::Reference< drawing::XLayer >& xLayer )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel == nullptr )
+ throw lang::DisposedException();
+
+ SdLayer* pSdLayer = comphelper::getFromUnoTunnel<SdLayer>(xLayer);
+
+ if(pSdLayer && GetView())
+ {
+ const SdrLayer* pSdrLayer = pSdLayer->GetSdrLayer();
+ GetView()->DeleteLayer( pSdrLayer->GetName() );
+
+ UpdateLayerView();
+ }
+
+ mpModel->SetModified();
+}
+
+void SAL_CALL SdLayerManager::attachShapeToLayer( const uno::Reference< drawing::XShape >& xShape, const uno::Reference< drawing::XLayer >& xLayer )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel == nullptr )
+ throw lang::DisposedException();
+
+ SdLayer* pSdLayer = comphelper::getFromUnoTunnel<SdLayer>(xLayer);
+ SdrLayer* pSdrLayer = pSdLayer?pSdLayer->GetSdrLayer():nullptr;
+ if(pSdrLayer==nullptr)
+ return;
+
+ SdrObject* pSdrObject = SdrObject::getSdrObjectFromXShape( xShape );
+
+ if(pSdrObject)
+ pSdrObject->SetLayer(pSdrLayer->GetID());
+
+ mpModel->SetModified();
+}
+
+uno::Reference< drawing::XLayer > SAL_CALL SdLayerManager::getLayerForShape( const uno::Reference< drawing::XShape >& xShape )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel == nullptr )
+ throw lang::DisposedException();
+
+ uno::Reference< drawing::XLayer > xLayer;
+
+ if(mpModel->mpDoc)
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape( xShape );
+ if(pObj)
+ {
+ SdrLayerID aId = pObj->GetLayer();
+ SdrLayerAdmin& rLayerAdmin = mpModel->mpDoc->GetLayerAdmin();
+ xLayer = GetLayer (rLayerAdmin.GetLayerPerID(aId));
+ }
+ }
+ return xLayer;
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SdLayerManager::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel == nullptr )
+ throw lang::DisposedException();
+
+ if( mpModel->mpDoc )
+ {
+ SdrLayerAdmin& rLayerAdmin = mpModel->mpDoc->GetLayerAdmin();
+ return rLayerAdmin.GetLayerCount();
+ }
+
+ return 0;
+}
+
+uno::Any SAL_CALL SdLayerManager::getByIndex( sal_Int32 nLayer )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel == nullptr )
+ throw lang::DisposedException();
+
+ if( nLayer >= getCount() || nLayer < 0 )
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Any aAny;
+
+ if( mpModel->mpDoc )
+ {
+ SdrLayerAdmin& rLayerAdmin = mpModel->mpDoc->GetLayerAdmin();
+ uno::Reference<drawing::XLayer> xLayer (GetLayer (rLayerAdmin.GetLayer(static_cast<sal_uInt16>(nLayer))));
+ aAny <<= xLayer;
+ }
+ return aAny;
+}
+
+// XNameAccess
+uno::Any SAL_CALL SdLayerManager::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ if( (mpModel == nullptr) || (mpModel->mpDoc == nullptr ) )
+ throw lang::DisposedException();
+
+ SdrLayerAdmin& rLayerAdmin = mpModel->mpDoc->GetLayerAdmin();
+ SdrLayer* pLayer = rLayerAdmin.GetLayer(aName);
+ if( pLayer == nullptr )
+ throw container::NoSuchElementException();
+
+ return uno::Any( GetLayer (pLayer) );
+}
+
+uno::Sequence< OUString > SAL_CALL SdLayerManager::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel == nullptr )
+ throw lang::DisposedException();
+
+ SdrLayerAdmin& rLayerAdmin = mpModel->mpDoc->GetLayerAdmin();
+ const sal_uInt16 nLayerCount = rLayerAdmin.GetLayerCount();
+
+ uno::Sequence< OUString > aSeq( nLayerCount );
+
+ OUString* pStrings = aSeq.getArray();
+
+ for( sal_uInt16 nLayer = 0; nLayer < nLayerCount; nLayer++ )
+ {
+ SdrLayer* pLayer = rLayerAdmin.GetLayer( nLayer );
+ if( pLayer )
+ *pStrings++ = pLayer->GetName();
+ }
+
+ return aSeq;
+}
+
+sal_Bool SAL_CALL SdLayerManager::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel == nullptr )
+ throw lang::DisposedException();
+
+ SdrLayerAdmin& rLayerAdmin = mpModel->mpDoc->GetLayerAdmin();
+
+ return nullptr != rLayerAdmin.GetLayer(aName);
+}
+
+// XElementAccess
+uno::Type SAL_CALL SdLayerManager::getElementType()
+{
+ return cppu::UnoType<drawing::XLayer>::get();
+}
+
+sal_Bool SAL_CALL SdLayerManager::hasElements()
+{
+ return getCount() > 0;
+}
+
+/**
+ * If something was changed at the layers, this methods takes care that the
+ * changes are made visible in sdbcx::View.
+ */
+void SdLayerManager::UpdateLayerView() const noexcept
+{
+ if(!mpModel->mpDocShell)
+ return;
+
+ ::sd::DrawViewShell* pDrViewSh = dynamic_cast< ::sd::DrawViewShell* >( mpModel->mpDocShell->GetViewShell());
+
+ if(pDrViewSh)
+ {
+ bool bLayerMode = pDrViewSh->IsLayerModeActive();
+ pDrViewSh->ChangeEditMode(pDrViewSh->GetEditMode(), !bLayerMode);
+ pDrViewSh->ChangeEditMode(pDrViewSh->GetEditMode(), bLayerMode);
+ }
+
+ mpModel->mpDoc->SetChanged();
+}
+
+/** */
+::sd::View* SdLayerManager::GetView() const noexcept
+{
+ if( mpModel->mpDocShell )
+ {
+ ::sd::ViewShell* pViewSh = mpModel->mpDocShell->GetViewShell();
+ if(pViewSh)
+ return pViewSh->GetView();
+ }
+ return nullptr;
+}
+
+namespace
+{
+/** Compare two pointers to <type>SdrLayer</type> objects.
+ @param xRef
+ The implementing SdLayer class provides the first pointer by the
+ <member>SdLayer::GetSdrLayer</member> method.
+ @param pSearchData
+ This void pointer is the second pointer to an <type>SdrLayer</type>
+ object.
+ @return
+ Return </True> if both pointers point to the same object.
+*/
+bool compare_layers (const uno::WeakReference<uno::XInterface>& xRef, void const * pSearchData)
+{
+ uno::Reference<uno::XInterface> xLayer (xRef);
+ if (xLayer.is())
+ {
+ SdLayer* pSdLayer = comphelper::getFromUnoTunnel<SdLayer> (xRef);
+ if (pSdLayer != nullptr)
+ {
+ SdrLayer* pSdrLayer = pSdLayer->GetSdrLayer ();
+ if (pSdrLayer == static_cast<SdrLayer const *>(pSearchData))
+ return true;
+ }
+ }
+ return false;
+}
+}
+
+/** Use the <member>mpLayers</member> container of weak references to either
+ retrieve and return a previously created <type>XLayer</type> object for
+ the given <type>SdrLayer</type> object or create and remember a new one.
+*/
+uno::Reference<drawing::XLayer> SdLayerManager::GetLayer (SdrLayer* pLayer)
+{
+ uno::WeakReference<uno::XInterface> xRef;
+ uno::Reference<drawing::XLayer> xLayer;
+
+ // Search existing xLayer for the given pLayer.
+ if (mpLayers->findRef (xRef, static_cast<void*>(pLayer), compare_layers))
+ xLayer.set(xRef, uno::UNO_QUERY);
+
+ // Create the xLayer if necessary.
+ if ( ! xLayer.is())
+ {
+ xLayer = new SdLayer (this, pLayer);
+
+ // Remember the new xLayer for future calls.
+ uno::WeakReference<uno::XInterface> wRef(xLayer);
+ mpLayers->insert(wRef);
+ }
+
+ return xLayer;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unolayer.hxx b/sd/source/ui/unoidl/unolayer.hxx
new file mode 100644
index 000000000..aa7d4891b
--- /dev/null
+++ b/sd/source/ui/unoidl/unolayer.hxx
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/drawing/XLayer.hpp>
+#include <com/sun/star/drawing/XLayerManager.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <rtl/ref.hxx>
+
+#include <unomodel.hxx>
+
+class SdrLayer;
+class SdLayerManager;
+class SvUnoWeakContainer;
+
+namespace sd {
+class View;
+}
+enum LayerAttribute { VISIBLE, PRINTABLE, LOCKED };
+
+/***********************************************************************
+* *
+***********************************************************************/
+class SdLayer : public ::cppu::WeakImplHelper< css::drawing::XLayer,
+ css::lang::XServiceInfo,
+ css::container::XChild,
+ css::lang::XUnoTunnel,
+ css::lang::XComponent >
+{
+public:
+ SdLayer(SdLayerManager* pLayerManager_, SdrLayer* pSdrLayer_);
+ virtual ~SdLayer() noexcept override;
+
+ // intern
+ SdrLayer* GetSdrLayer() const noexcept { return pLayer; }
+
+ // uno helper
+ UNO3_GETIMPLEMENTATION_DECL( SdLayer )
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // css::container::XChild
+
+ /** Returns the layer manager that manages this layer.
+ */
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ /** Not implemented. Always throws an exception.
+ @throws NoSupportException.
+ */
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+private:
+ rtl::Reference<SdLayerManager> mxLayerManager;
+ SdrLayer* pLayer;
+ const SvxItemPropertySet* pPropSet;
+
+ bool get( LayerAttribute what ) noexcept;
+ void set( LayerAttribute what, bool flag ) noexcept;
+
+};
+
+/***********************************************************************
+* *
+***********************************************************************/
+
+class SdLayerManager : public ::cppu::WeakImplHelper< css::drawing::XLayerManager,
+ css::container::XNameAccess,
+ css::lang::XServiceInfo,
+ css::lang::XUnoTunnel,
+ css::lang::XComponent >
+{
+ friend class SdLayer;
+
+public:
+ explicit SdLayerManager( SdXImpressDocument& rMyModel ) noexcept;
+ virtual ~SdLayerManager() noexcept override;
+
+ // uno helper
+ UNO3_GETIMPLEMENTATION_DECL( SdLayerManager )
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XLayerManager
+ virtual css::uno::Reference< css::drawing::XLayer > SAL_CALL insertNewByIndex( sal_Int32 nIndex ) override;
+ virtual void SAL_CALL remove( const css::uno::Reference< css::drawing::XLayer >& xLayer ) override;
+ virtual void SAL_CALL attachShapeToLayer( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::drawing::XLayer >& xLayer ) override;
+ virtual css::uno::Reference< css::drawing::XLayer > SAL_CALL getLayerForShape( const css::uno::Reference< css::drawing::XShape >& xShape ) override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ /** Return the <type>XLayer</type> object that is associated with the
+ given <type>SdrLayer</type> object. If the requested object does
+ not yet exist it is created. All calls with the same argument
+ return the same object.
+ @param pLayer
+ The <type>SdrLayer</type> object for which to return the
+ associated <type>XLayer</type> object.
+ @return
+ The returned value is the unique <type>XLayer</type> object
+ associated with the specified argument. If no layer can be
+ created for the argument than an empty reference is returned.
+ */
+ css::uno::Reference< css::drawing::XLayer> GetLayer (SdrLayer* pLayer);
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+private:
+ SdXImpressDocument* mpModel;
+ std::unique_ptr<SvUnoWeakContainer> mpLayers;
+
+ ::sd::View* GetView() const noexcept;
+ ::sd::DrawDocShell* GetDocShell() const noexcept { return mpModel->mpDocShell; }
+ void UpdateLayerView() const noexcept;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
new file mode 100644
index 000000000..758ce1380
--- /dev/null
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -0,0 +1,3491 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+
+#include <com/sun/star/presentation/XPresentation2.hpp>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/awt/XDevice.hpp>
+#include <com/sun/star/document/IndexedPropertyValues.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <com/sun/star/embed/Aspects.hpp>
+
+#include <officecfg/Office/Common.hxx>
+#include <comphelper/indexedpropertyvalues.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/profilezone.hxx>
+
+#include <sal/log.hxx>
+#include <editeng/unofield.hxx>
+#include <notifydocumentevent.hxx>
+#include <tpaction.hxx>
+#include <unomodel.hxx>
+#include "unopool.hxx"
+#include <sfx2/lokhelper.hxx>
+#include <sfx2/dispatch.hxx>
+#include <vcl/svapp.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+#include <editeng/UnoForbiddenCharsTable.hxx>
+#include <svx/svdoutl.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <svx/UnoNamespaceMap.hxx>
+#include <svx/svdlayer.hxx>
+#include <svx/svdsob.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/unofill.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <editeng/fontitem.hxx>
+#include <toolkit/awt/vclxdevice.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdpagv.hxx>
+#include <svtools/unoimap.hxx>
+#include <svtools/slidesorterbaropt.hxx>
+#include <svx/unoshape.hxx>
+#include <editeng/unonrule.hxx>
+#include <editeng/eeitem.hxx>
+#include <unotools/datetime.hxx>
+#include <xmloff/autolayout.hxx>
+
+// Support creation of GraphicStorageHandler and EmbeddedObjectResolver
+#include <svx/xmleohlp.hxx>
+#include <svx/xmlgrhlp.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShellBase.hxx>
+#include "UnoDocumentSettings.hxx"
+
+#include <Annotation.hxx>
+#include <drawdoc.hxx>
+#include <sdmod.hxx>
+#include <sdresid.hxx>
+#include <sdpage.hxx>
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include "unolayer.hxx"
+#include <unopage.hxx>
+#include "unocpres.hxx"
+#include "unoobj.hxx"
+#include <stlpool.hxx>
+#include "unopback.hxx"
+#include <unokywds.hxx>
+
+#include <FrameView.hxx>
+#include <ClientView.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShell.hxx>
+#include <Window.hxx>
+#include <optsitem.hxx>
+
+#include <vcl/pdfextoutdevdata.hxx>
+#include <com/sun/star/presentation/AnimationSpeed.hpp>
+#include <com/sun/star/presentation/ClickAction.hpp>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+
+#include <com/sun/star/office/XAnnotation.hpp>
+#include <com/sun/star/office/XAnnotationAccess.hpp>
+#include <com/sun/star/office/XAnnotationEnumeration.hpp>
+#include <com/sun/star/geometry/RealPoint2D.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+
+#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
+
+#include <sfx2/lokcomponenthelpers.hxx>
+#include <tools/gen.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/json_writer.hxx>
+#include <tools/UnitConversion.hxx>
+#include <svx/ColorSets.hxx>
+
+#include <app.hrc>
+
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::sd;
+
+TranslateId SdTPAction::GetClickActionSdResId( presentation::ClickAction eCA )
+{
+ switch( eCA )
+ {
+ case presentation::ClickAction_NONE: return STR_CLICK_ACTION_NONE;
+ case presentation::ClickAction_PREVPAGE: return STR_CLICK_ACTION_PREVPAGE;
+ case presentation::ClickAction_NEXTPAGE: return STR_CLICK_ACTION_NEXTPAGE;
+ case presentation::ClickAction_FIRSTPAGE: return STR_CLICK_ACTION_FIRSTPAGE;
+ case presentation::ClickAction_LASTPAGE: return STR_CLICK_ACTION_LASTPAGE;
+ case presentation::ClickAction_BOOKMARK: return STR_CLICK_ACTION_BOOKMARK;
+ case presentation::ClickAction_DOCUMENT: return STR_CLICK_ACTION_DOCUMENT;
+ case presentation::ClickAction_PROGRAM: return STR_CLICK_ACTION_PROGRAM;
+ case presentation::ClickAction_MACRO: return STR_CLICK_ACTION_MACRO;
+ case presentation::ClickAction_SOUND: return STR_CLICK_ACTION_SOUND;
+ case presentation::ClickAction_VERB: return STR_CLICK_ACTION_VERB;
+ case presentation::ClickAction_STOPPRESENTATION: return STR_CLICK_ACTION_STOPPRESENTATION;
+ default: OSL_FAIL( "No StringResource for ClickAction available!" );
+ }
+ return {};
+}
+
+namespace {
+
+class SdUnoForbiddenCharsTable : public SvxUnoForbiddenCharsTable,
+ public SfxListener
+{
+public:
+ explicit SdUnoForbiddenCharsTable(SdrModel* pModel);
+ virtual ~SdUnoForbiddenCharsTable() override;
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) noexcept override;
+protected:
+ virtual void onChange() override;
+
+private:
+ SdrModel* mpModel;
+};
+
+}
+
+SdUnoForbiddenCharsTable::SdUnoForbiddenCharsTable( SdrModel* pModel )
+: SvxUnoForbiddenCharsTable( pModel->GetForbiddenCharsTable() ), mpModel( pModel )
+{
+ StartListening( *pModel );
+}
+
+void SdUnoForbiddenCharsTable::onChange()
+{
+ if( mpModel )
+ {
+ mpModel->ReformatAllTextObjects();
+ }
+}
+
+SdUnoForbiddenCharsTable::~SdUnoForbiddenCharsTable()
+{
+ SolarMutexGuard g;
+
+ if( mpModel )
+ EndListening( *mpModel );
+}
+
+void SdUnoForbiddenCharsTable::Notify( SfxBroadcaster&, const SfxHint& rHint ) noexcept
+{
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>( &rHint );
+ if( SdrHintKind::ModelCleared == pSdrHint->GetKind() )
+ {
+ mpModel = nullptr;
+ }
+}
+
+const sal_uInt16 WID_MODEL_LANGUAGE = 1;
+const sal_uInt16 WID_MODEL_TABSTOP = 2;
+const sal_uInt16 WID_MODEL_VISAREA = 3;
+const sal_uInt16 WID_MODEL_MAPUNIT = 4;
+const sal_uInt16 WID_MODEL_FORBCHARS = 5;
+const sal_uInt16 WID_MODEL_CONTFOCUS = 6;
+const sal_uInt16 WID_MODEL_DSGNMODE = 7;
+const sal_uInt16 WID_MODEL_BASICLIBS = 8;
+const sal_uInt16 WID_MODEL_RUNTIMEUID = 9;
+const sal_uInt16 WID_MODEL_BUILDID = 10;
+const sal_uInt16 WID_MODEL_HASVALIDSIGNATURES = 11;
+const sal_uInt16 WID_MODEL_DIALOGLIBS = 12;
+const sal_uInt16 WID_MODEL_FONTS = 13;
+const sal_uInt16 WID_MODEL_INTEROPGRABBAG = 14;
+const sal_uInt16 WID_MODEL_THEME = 15;
+
+static const SvxItemPropertySet* ImplGetDrawModelPropertySet()
+{
+ // Attention: the first parameter HAS TO BE sorted!!!
+ const static SfxItemPropertyMapEntry aDrawModelPropertyMap_Impl[] =
+ {
+ { u"BuildId", WID_MODEL_BUILDID, ::cppu::UnoType<OUString>::get(), 0, 0},
+ { sUNO_Prop_CharLocale, WID_MODEL_LANGUAGE, ::cppu::UnoType<lang::Locale>::get(), 0, 0},
+ { sUNO_Prop_TabStop, WID_MODEL_TABSTOP, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { sUNO_Prop_VisibleArea, WID_MODEL_VISAREA, ::cppu::UnoType<awt::Rectangle>::get(), 0, 0},
+ { sUNO_Prop_MapUnit, WID_MODEL_MAPUNIT, ::cppu::UnoType<sal_Int16>::get(), beans::PropertyAttribute::READONLY, 0},
+ { sUNO_Prop_ForbiddenCharacters, WID_MODEL_FORBCHARS, cppu::UnoType<i18n::XForbiddenCharacters>::get(), beans::PropertyAttribute::READONLY, 0},
+ { sUNO_Prop_AutomContFocus, WID_MODEL_CONTFOCUS, cppu::UnoType<bool>::get(), 0, 0},
+ { sUNO_Prop_ApplyFrmDsgnMode, WID_MODEL_DSGNMODE, cppu::UnoType<bool>::get(), 0, 0},
+ { u"BasicLibraries", WID_MODEL_BASICLIBS, cppu::UnoType<script::XLibraryContainer>::get(), beans::PropertyAttribute::READONLY, 0},
+ { u"DialogLibraries", WID_MODEL_DIALOGLIBS, cppu::UnoType<script::XLibraryContainer>::get(), beans::PropertyAttribute::READONLY, 0},
+ { sUNO_Prop_RuntimeUID, WID_MODEL_RUNTIMEUID, ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0},
+ { sUNO_Prop_HasValidSignatures, WID_MODEL_HASVALIDSIGNATURES, ::cppu::UnoType<sal_Bool>::get(), beans::PropertyAttribute::READONLY, 0},
+ { u"Fonts", WID_MODEL_FONTS, cppu::UnoType<uno::Sequence<uno::Any>>::get(), beans::PropertyAttribute::READONLY, 0},
+ { sUNO_Prop_InteropGrabBag, WID_MODEL_INTEROPGRABBAG, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get(), 0, 0},
+ { sUNO_Prop_Theme, WID_MODEL_THEME, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SvxItemPropertySet aDrawModelPropertySet_Impl( aDrawModelPropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ return &aDrawModelPropertySet_Impl;
+}
+
+// this ctor is used from the DocShell
+SdXImpressDocument::SdXImpressDocument(::sd::DrawDocShell* pShell, bool bClipBoard)
+: SfxBaseModel( pShell ),
+ mpDocShell( pShell ),
+ mpDoc( pShell ? pShell->GetDoc() : nullptr ),
+ mbDisposed(false),
+ mbImpressDoc( pShell && pShell->GetDoc() && pShell->GetDoc()->GetDocumentType() == DocumentType::Impress ),
+ mbClipBoard( bClipBoard ),
+ mpPropSet( ImplGetDrawModelPropertySet() )
+{
+ if( mpDoc )
+ {
+ StartListening( *mpDoc );
+ }
+ else
+ {
+ OSL_FAIL("DocShell is invalid");
+ }
+}
+
+SdXImpressDocument::SdXImpressDocument(SdDrawDocument* pDoc, bool bClipBoard)
+: SfxBaseModel( nullptr ),
+ mpDocShell( nullptr ),
+ mpDoc( pDoc ),
+ mbDisposed(false),
+ mbImpressDoc( pDoc && pDoc->GetDocumentType() == DocumentType::Impress ),
+ mbClipBoard( bClipBoard ),
+ mpPropSet( ImplGetDrawModelPropertySet() )
+{
+ if( mpDoc )
+ {
+ StartListening( *mpDoc );
+ }
+ else
+ {
+ OSL_FAIL("SdDrawDocument is invalid");
+ }
+}
+
+/***********************************************************************
+* *
+***********************************************************************/
+SdXImpressDocument::~SdXImpressDocument() noexcept
+{
+}
+
+// XInterface
+uno::Any SAL_CALL SdXImpressDocument::queryInterface( const uno::Type & rType )
+{
+ uno::Any aAny;
+
+ if (rType == cppu::UnoType<lang::XServiceInfo>::get())
+ aAny <<= uno::Reference<lang::XServiceInfo>(this);
+ else if (rType == cppu::UnoType<beans::XPropertySet>::get())
+ aAny <<= uno::Reference<beans::XPropertySet>(this);
+ else if (rType == cppu::UnoType<lang::XMultiServiceFactory>::get())
+ aAny <<= uno::Reference<lang::XMultiServiceFactory>(this);
+ else if (rType == cppu::UnoType<drawing::XDrawPageDuplicator>::get())
+ aAny <<= uno::Reference<drawing::XDrawPageDuplicator>(this);
+ else if (rType == cppu::UnoType<drawing::XLayerSupplier>::get())
+ aAny <<= uno::Reference<drawing::XLayerSupplier>(this);
+ else if (rType == cppu::UnoType<drawing::XMasterPagesSupplier>::get())
+ aAny <<= uno::Reference<drawing::XMasterPagesSupplier>(this);
+ else if (rType == cppu::UnoType<drawing::XDrawPagesSupplier>::get())
+ aAny <<= uno::Reference<drawing::XDrawPagesSupplier>(this);
+ else if (rType == cppu::UnoType<presentation::XHandoutMasterSupplier>::get())
+ aAny <<= uno::Reference<presentation::XHandoutMasterSupplier>(this);
+ else if (rType == cppu::UnoType<document::XLinkTargetSupplier>::get())
+ aAny <<= uno::Reference<document::XLinkTargetSupplier>(this);
+ else if (rType == cppu::UnoType<style::XStyleFamiliesSupplier>::get())
+ aAny <<= uno::Reference<style::XStyleFamiliesSupplier>(this);
+ else if (rType == cppu::UnoType<css::ucb::XAnyCompareFactory>::get())
+ aAny <<= uno::Reference<css::ucb::XAnyCompareFactory>(this);
+ else if (rType == cppu::UnoType<view::XRenderable>::get())
+ aAny <<= uno::Reference<view::XRenderable>(this);
+ else if (mbImpressDoc && rType == cppu::UnoType<presentation::XPresentationSupplier>::get())
+ aAny <<= uno::Reference< presentation::XPresentationSupplier >(this);
+ else if (mbImpressDoc && rType == cppu::UnoType<presentation::XCustomPresentationSupplier>::get())
+ aAny <<= uno::Reference< presentation::XCustomPresentationSupplier >(this);
+ else
+ return SfxBaseModel::queryInterface(rType);
+
+ return aAny;
+}
+
+void SAL_CALL SdXImpressDocument::acquire() noexcept
+{
+ SfxBaseModel::acquire();
+}
+
+void SAL_CALL SdXImpressDocument::release() noexcept
+{
+ if (osl_atomic_decrement( &m_refCount ) != 0)
+ return;
+
+ // restore reference count:
+ osl_atomic_increment( &m_refCount );
+ if(!mbDisposed)
+ {
+ try
+ {
+ dispose();
+ }
+ catch (const uno::RuntimeException&)
+ {
+ // don't break throw ()
+ TOOLS_WARN_EXCEPTION( "sd", "" );
+ }
+ }
+ SfxBaseModel::release();
+}
+
+// XUnoTunnel
+const css::uno::Sequence< sal_Int8 > & SdXImpressDocument::getUnoTunnelId() noexcept
+{
+ static const comphelper::UnoIdInit theSdXImpressDocumentUnoTunnelId;
+ return theSdXImpressDocumentUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL SdXImpressDocument::getSomething( const css::uno::Sequence< sal_Int8 >& rIdentifier )
+{
+ if (comphelper::isUnoTunnelId<SdrModel>(rIdentifier))
+ return comphelper::getSomething_cast(mpDoc);
+
+ return comphelper::getSomethingImpl(rIdentifier, this,
+ comphelper::FallbackToGetSomethingOf<SfxBaseModel>{});
+}
+
+// XTypeProvider
+uno::Sequence< uno::Type > SAL_CALL SdXImpressDocument::getTypes( )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( !maTypeSequence.hasElements() )
+ {
+ uno::Sequence< uno::Type > aTypes( SfxBaseModel::getTypes() );
+ aTypes = comphelper::concatSequences(aTypes,
+ uno::Sequence {
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XMultiServiceFactory>::get(),
+ cppu::UnoType<drawing::XDrawPageDuplicator>::get(),
+ cppu::UnoType<drawing::XLayerSupplier>::get(),
+ cppu::UnoType<drawing::XMasterPagesSupplier>::get(),
+ cppu::UnoType<drawing::XDrawPagesSupplier>::get(),
+ cppu::UnoType<document::XLinkTargetSupplier>::get(),
+ cppu::UnoType<style::XStyleFamiliesSupplier>::get(),
+ cppu::UnoType<css::ucb::XAnyCompareFactory>::get(),
+ cppu::UnoType<view::XRenderable>::get() });
+ if( mbImpressDoc )
+ {
+ aTypes = comphelper::concatSequences(aTypes,
+ uno::Sequence {
+ cppu::UnoType<presentation::XPresentationSupplier>::get(),
+ cppu::UnoType<presentation::XCustomPresentationSupplier>::get(),
+ cppu::UnoType<presentation::XHandoutMasterSupplier>::get() });
+ }
+ maTypeSequence = aTypes;
+ }
+
+ return maTypeSequence;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL SdXImpressDocument::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+/***********************************************************************
+* *
+***********************************************************************/
+void SdXImpressDocument::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if( mpDoc )
+ {
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>( &rHint );
+ if( hasEventListeners() )
+ {
+ document::EventObject aEvent;
+ if( SvxUnoDrawMSFactory::createEvent( mpDoc, pSdrHint, aEvent ) )
+ notifyEvent( aEvent );
+ }
+
+ if( pSdrHint->GetKind() == SdrHintKind::ModelCleared )
+ {
+ if( mpDoc )
+ EndListening( *mpDoc );
+ mpDoc = nullptr;
+ mpDocShell = nullptr;
+ }
+ }
+ else
+ {
+ // did our SdDrawDocument just died?
+ if(rHint.GetId() == SfxHintId::Dying)
+ {
+ // yes, so we ask for a new one
+ if( mpDocShell )
+ {
+ SdDrawDocument *pNewDoc = mpDocShell->GetDoc();
+
+ // is there a new one?
+ if( pNewDoc != mpDoc )
+ {
+ mpDoc = pNewDoc;
+ if(mpDoc)
+ StartListening( *mpDoc );
+ }
+ }
+ }
+ }
+ }
+ SfxBaseModel::Notify( rBC, rHint );
+}
+
+/******************************************************************************
+* *
+******************************************************************************/
+SdPage* SdXImpressDocument::InsertSdPage( sal_uInt16 nPage, bool bDuplicate )
+{
+ sal_uInt16 nPageCount = mpDoc->GetSdPageCount( PageKind::Standard );
+ SdrLayerAdmin& rLayerAdmin = mpDoc->GetLayerAdmin();
+ SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+
+ rtl::Reference<SdPage> pStandardPage;
+
+ if( 0 == nPageCount )
+ {
+ // this is only used for clipboard where we only have one page
+ pStandardPage = mpDoc->AllocSdPage(false);
+
+ Size aDefSize(21000, 29700); // A4 portrait orientation
+ pStandardPage->SetSize( aDefSize );
+ mpDoc->InsertPage(pStandardPage.get(), 0);
+ }
+ else
+ {
+ // here we determine the page after which we should insert
+ SdPage* pPreviousStandardPage = mpDoc->GetSdPage( std::min( static_cast<sal_uInt16>(nPageCount - 1), nPage ), PageKind::Standard );
+ SdrLayerIDSet aVisibleLayers = pPreviousStandardPage->TRG_GetMasterPageVisibleLayers();
+ bool bIsPageBack = aVisibleLayers.IsSet( aBckgrnd );
+ bool bIsPageObj = aVisibleLayers.IsSet( aBckgrndObj );
+
+ // AutoLayouts must be ready
+ mpDoc->StopWorkStartupDelay();
+
+ /* First we create a standard page and then a notes page. It is
+ guaranteed, that after a standard page the corresponding notes page
+ follows. */
+
+ sal_uInt16 nStandardPageNum = pPreviousStandardPage->GetPageNum() + 2;
+ SdPage* pPreviousNotesPage = static_cast<SdPage*>( mpDoc->GetPage( nStandardPageNum - 1 ) );
+ sal_uInt16 nNotesPageNum = nStandardPageNum + 1;
+
+ /**************************************************************
+ * standard page
+ **************************************************************/
+ if( bDuplicate )
+ pStandardPage = static_cast<SdPage*>( pPreviousStandardPage->CloneSdrPage(*mpDoc).get() );
+ else
+ pStandardPage = mpDoc->AllocSdPage(false);
+
+ pStandardPage->SetSize( pPreviousStandardPage->GetSize() );
+ pStandardPage->SetBorder( pPreviousStandardPage->GetLeftBorder(),
+ pPreviousStandardPage->GetUpperBorder(),
+ pPreviousStandardPage->GetRightBorder(),
+ pPreviousStandardPage->GetLowerBorder() );
+ pStandardPage->SetOrientation( pPreviousStandardPage->GetOrientation() );
+ pStandardPage->SetName(OUString());
+
+ // insert page after current page
+ mpDoc->InsertPage(pStandardPage.get(), nStandardPageNum);
+
+ if( !bDuplicate )
+ {
+ // use MasterPage of the current page
+ pStandardPage->TRG_SetMasterPage(pPreviousStandardPage->TRG_GetMasterPage());
+ pStandardPage->SetLayoutName( pPreviousStandardPage->GetLayoutName() );
+ pStandardPage->SetAutoLayout(AUTOLAYOUT_NONE, true );
+ }
+
+ aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ aVisibleLayers.Set(aBckgrnd, bIsPageBack);
+ aVisibleLayers.Set(aBckgrndObj, bIsPageObj);
+ pStandardPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+
+ /**************************************************************
+ * notes page
+ **************************************************************/
+ rtl::Reference<SdPage> pNotesPage;
+
+ if( bDuplicate )
+ pNotesPage = static_cast<SdPage*>( pPreviousNotesPage->CloneSdrPage(*mpDoc).get() );
+ else
+ pNotesPage = mpDoc->AllocSdPage(false);
+
+ pNotesPage->SetSize( pPreviousNotesPage->GetSize() );
+ pNotesPage->SetBorder( pPreviousNotesPage->GetLeftBorder(),
+ pPreviousNotesPage->GetUpperBorder(),
+ pPreviousNotesPage->GetRightBorder(),
+ pPreviousNotesPage->GetLowerBorder() );
+ pNotesPage->SetOrientation( pPreviousNotesPage->GetOrientation() );
+ pNotesPage->SetName(OUString());
+ pNotesPage->SetPageKind(PageKind::Notes);
+
+ // insert page after current page
+ mpDoc->InsertPage(pNotesPage.get(), nNotesPageNum);
+
+ if( !bDuplicate )
+ {
+ // use MasterPage of the current page
+ pNotesPage->TRG_SetMasterPage(pPreviousNotesPage->TRG_GetMasterPage());
+ pNotesPage->SetLayoutName( pPreviousNotesPage->GetLayoutName() );
+ pNotesPage->SetAutoLayout(AUTOLAYOUT_NOTES, true );
+ }
+ }
+
+ SetModified();
+
+ return pStandardPage.get();
+}
+
+void SdXImpressDocument::SetModified() noexcept
+{
+ if( mpDoc )
+ mpDoc->SetChanged();
+}
+
+// XModel
+void SAL_CALL SdXImpressDocument::lockControllers( )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ mpDoc->setLock(true);
+}
+
+void SAL_CALL SdXImpressDocument::unlockControllers( )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ if( mpDoc->isLocked() )
+ {
+ mpDoc->setLock(false);
+ }
+}
+
+sal_Bool SAL_CALL SdXImpressDocument::hasControllersLocked( )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ return mpDoc->isLocked();
+}
+
+uno::Reference < container::XIndexAccess > SAL_CALL SdXImpressDocument::getViewData()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ uno::Reference < container::XIndexAccess > xRet( SfxBaseModel::getViewData() );
+
+ if( !xRet.is() )
+ {
+ const std::vector<std::unique_ptr<sd::FrameView>> &rList = mpDoc->GetFrameViewList();
+
+ if( !rList.empty() )
+ {
+ xRet = new comphelper::IndexedPropertyValuesContainer();
+
+ uno::Reference < container::XIndexContainer > xCont( xRet, uno::UNO_QUERY );
+ DBG_ASSERT( xCont.is(), "SdXImpressDocument::getViewData() failed for OLE object" );
+ if( xCont.is() )
+ {
+ for( sal_uInt32 i = 0, n = rList.size(); i < n; i++ )
+ {
+ ::sd::FrameView* pFrameView = rList[ i ].get();
+
+ uno::Sequence< beans::PropertyValue > aSeq;
+ pFrameView->WriteUserDataSequence( aSeq );
+ xCont->insertByIndex( i, uno::Any( aSeq ) );
+ }
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void SAL_CALL SdXImpressDocument::setViewData( const uno::Reference < container::XIndexAccess >& xData )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ SfxBaseModel::setViewData( xData );
+ if( !(mpDocShell && (mpDocShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED) && xData.is()) )
+ return;
+
+ const sal_Int32 nCount = xData->getCount();
+
+ std::vector<std::unique_ptr<sd::FrameView>> &rViews = mpDoc->GetFrameViewList();
+
+ rViews.clear();
+
+ uno::Sequence< beans::PropertyValue > aSeq;
+ for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ if( xData->getByIndex( nIndex ) >>= aSeq )
+ {
+ std::unique_ptr<::sd::FrameView> pFrameView(new ::sd::FrameView( mpDoc ));
+ pFrameView->ReadUserDataSequence( aSeq );
+ rViews.push_back( std::move(pFrameView) );
+ }
+ }
+}
+
+// XDrawPageDuplicator
+uno::Reference< drawing::XDrawPage > SAL_CALL SdXImpressDocument::duplicate( const uno::Reference< drawing::XDrawPage >& xPage )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ // get pPage from xPage and determine the Id (nPos ) afterwards
+ SvxDrawPage* pSvxPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
+ if( pSvxPage )
+ {
+ SdPage* pPage = static_cast<SdPage*>( pSvxPage->GetSdrPage() );
+ sal_uInt16 nPos = pPage->GetPageNum();
+ nPos = ( nPos - 1 ) / 2;
+ pPage = InsertSdPage( nPos, true );
+ if( pPage )
+ {
+ uno::Reference< drawing::XDrawPage > xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
+ return xDrawPage;
+ }
+ }
+
+ uno::Reference< drawing::XDrawPage > xDrawPage;
+ return xDrawPage;
+}
+
+// XDrawPagesSupplier
+uno::Reference< drawing::XDrawPages > SAL_CALL SdXImpressDocument::getDrawPages()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ uno::Reference< drawing::XDrawPages > xDrawPages( mxDrawPagesAccess );
+
+ if( !xDrawPages.is() )
+ {
+ initializeDocument();
+ mxDrawPagesAccess = xDrawPages = new SdDrawPagesAccess(*this);
+ }
+
+ return xDrawPages;
+}
+
+// XMasterPagesSupplier
+uno::Reference< drawing::XDrawPages > SAL_CALL SdXImpressDocument::getMasterPages()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ uno::Reference< drawing::XDrawPages > xMasterPages( mxMasterPagesAccess );
+
+ if( !xMasterPages.is() )
+ {
+ if ( !hasControllersLocked() )
+ initializeDocument();
+ mxMasterPagesAccess = xMasterPages = new SdMasterPagesAccess(*this);
+ }
+
+ return xMasterPages;
+}
+
+// XLayerManagerSupplier
+uno::Reference< container::XNameAccess > SAL_CALL SdXImpressDocument::getLayerManager( )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ uno::Reference< container::XNameAccess > xLayerManager( mxLayerManager );
+
+ if( !xLayerManager.is() )
+ mxLayerManager = xLayerManager = new SdLayerManager(*this);
+
+ return xLayerManager;
+}
+
+// XCustomPresentationSupplier
+uno::Reference< container::XNameContainer > SAL_CALL SdXImpressDocument::getCustomPresentations()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ uno::Reference< container::XNameContainer > xCustomPres( mxCustomPresentationAccess );
+
+ if( !xCustomPres.is() )
+ mxCustomPresentationAccess = xCustomPres = new SdXCustomPresentationAccess(*this);
+
+ return xCustomPres;
+}
+
+// XPresentationSupplier
+uno::Reference< presentation::XPresentation > SAL_CALL SdXImpressDocument::getPresentation()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ return mpDoc->getPresentation();
+}
+
+// XHandoutMasterSupplier
+uno::Reference< drawing::XDrawPage > SAL_CALL SdXImpressDocument::getHandoutMasterPage()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ uno::Reference< drawing::XDrawPage > xPage;
+
+ initializeDocument();
+ SdPage* pPage = mpDoc->GetMasterSdPage(0, PageKind::Handout);
+ if (pPage)
+ xPage.set(pPage->getUnoPage(), uno::UNO_QUERY);
+ return xPage;
+}
+
+// XMultiServiceFactory ( SvxFmMSFactory )
+
+css::uno::Reference<css::uno::XInterface> SdXImpressDocument::create(
+ OUString const & aServiceSpecifier, OUString const & referer)
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ if( aServiceSpecifier == "com.sun.star.drawing.DashTable" )
+ {
+ if( !mxDashTable.is() )
+ mxDashTable = SvxUnoDashTable_createInstance( mpDoc );
+
+ return mxDashTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.GradientTable" )
+ {
+ if( !mxGradientTable.is() )
+ mxGradientTable = SvxUnoGradientTable_createInstance( mpDoc );
+
+ return mxGradientTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.HatchTable" )
+ {
+ if( !mxHatchTable.is() )
+ mxHatchTable = SvxUnoHatchTable_createInstance( mpDoc );
+
+ return mxHatchTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.BitmapTable" )
+ {
+ if( !mxBitmapTable.is() )
+ mxBitmapTable = SvxUnoBitmapTable_createInstance( mpDoc );
+
+ return mxBitmapTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.TransparencyGradientTable" )
+ {
+ if( !mxTransGradientTable.is() )
+ mxTransGradientTable = SvxUnoTransGradientTable_createInstance( mpDoc );
+
+ return mxTransGradientTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.MarkerTable" )
+ {
+ if( !mxMarkerTable.is() )
+ mxMarkerTable = SvxUnoMarkerTable_createInstance( mpDoc );
+
+ return mxMarkerTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.text.NumberingRules" )
+ {
+ return uno::Reference< uno::XInterface >( SvxCreateNumRule( mpDoc ), uno::UNO_QUERY );
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.Background" )
+ {
+ return uno::Reference< uno::XInterface >(
+ static_cast<uno::XWeak*>(new SdUnoPageBackground( mpDoc )));
+ }
+
+ if( aServiceSpecifier == "com.sun.star.drawing.Defaults" )
+ {
+ if( !mxDrawingPool.is() )
+ mxDrawingPool = SdUnoCreatePool( mpDoc );
+
+ return mxDrawingPool;
+
+ }
+
+ if ( aServiceSpecifier == sUNO_Service_ImageMapRectangleObject )
+ {
+ return SvUnoImageMapRectangleObject_createInstance( ImplGetSupportedMacroItems() );
+ }
+
+ if ( aServiceSpecifier == sUNO_Service_ImageMapCircleObject )
+ {
+ return SvUnoImageMapCircleObject_createInstance( ImplGetSupportedMacroItems() );
+ }
+
+ if ( aServiceSpecifier == sUNO_Service_ImageMapPolygonObject )
+ {
+ return SvUnoImageMapPolygonObject_createInstance( ImplGetSupportedMacroItems() );
+ }
+
+ if( aServiceSpecifier == "com.sun.star.document.Settings" ||
+ ( !mbImpressDoc && ( aServiceSpecifier == "com.sun.star.drawing.DocumentSettings" ) ) ||
+ ( mbImpressDoc && ( aServiceSpecifier == "com.sun.star.presentation.DocumentSettings" ) ) )
+ {
+ return sd::DocumentSettings_createInstance( this );
+ }
+
+ if( aServiceSpecifier == "com.sun.star.text.TextField.DateTime" ||
+ aServiceSpecifier == "com.sun.star.text.textfield.DateTime" )
+ {
+ return static_cast<cppu::OWeakObject *>(new SvxUnoTextField( text::textfield::Type::DATE ));
+ }
+
+ if( aServiceSpecifier == "com.sun.star.presentation.TextField.Header" ||
+ aServiceSpecifier == "com.sun.star.presentation.textfield.Header" )
+ {
+ return static_cast<cppu::OWeakObject *>(new SvxUnoTextField( text::textfield::Type::PRESENTATION_HEADER ));
+ }
+
+ if( aServiceSpecifier == "com.sun.star.presentation.TextField.Footer" ||
+ aServiceSpecifier == "com.sun.star.presentation.textfield.Footer" )
+ {
+ return static_cast<cppu::OWeakObject *>(new SvxUnoTextField( text::textfield::Type::PRESENTATION_FOOTER ));
+ }
+
+ if( aServiceSpecifier == "com.sun.star.presentation.TextField.DateTime" ||
+ aServiceSpecifier == "com.sun.star.presentation.textfield.DateTime" )
+ {
+ return static_cast<cppu::OWeakObject *>(new SvxUnoTextField( text::textfield::Type::PRESENTATION_DATE_TIME ));
+ }
+
+ if( aServiceSpecifier == "com.sun.star.text.TextField.PageName" ||
+ aServiceSpecifier == "com.sun.star.text.textfield.PageName" )
+ {
+ return static_cast<cppu::OWeakObject *>(new SvxUnoTextField( text::textfield::Type::PAGE_NAME ));
+ }
+
+ if (aServiceSpecifier == "com.sun.star.text.TextField.DocInfo.Custom" ||
+ aServiceSpecifier == "com.sun.star.text.textfield.DocInfo.Custom")
+ {
+ return static_cast<cppu::OWeakObject *>(new SvxUnoTextField(text::textfield::Type::DOCINFO_CUSTOM));
+ }
+
+ if( aServiceSpecifier == "com.sun.star.xml.NamespaceMap" )
+ {
+ static sal_uInt16 aWhichIds[] = { SDRATTR_XMLATTRIBUTES, EE_CHAR_XMLATTRIBS, EE_PARA_XMLATTRIBS, 0 };
+
+ return svx::NamespaceMap_createInstance( aWhichIds, &mpDoc->GetItemPool() );
+ }
+
+ // Support creation of GraphicStorageHandler and EmbeddedObjectResolver
+ if (aServiceSpecifier == "com.sun.star.document.ExportGraphicStorageHandler")
+ {
+ return static_cast<cppu::OWeakObject *>(new SvXMLGraphicHelper( SvXMLGraphicHelperMode::Write ));
+ }
+
+ if (aServiceSpecifier == "com.sun.star.document.ImportGraphicStorageHandler")
+ {
+ return static_cast<cppu::OWeakObject *>(new SvXMLGraphicHelper( SvXMLGraphicHelperMode::Read ));
+ }
+
+ if( aServiceSpecifier == "com.sun.star.document.ExportEmbeddedObjectResolver" )
+ {
+ comphelper::IEmbeddedHelper* pPersist = mpDoc->GetPersist();
+ if( nullptr == pPersist )
+ throw lang::DisposedException();
+
+ return static_cast<cppu::OWeakObject *>(new SvXMLEmbeddedObjectHelper( *pPersist, SvXMLEmbeddedObjectHelperMode::Write ));
+ }
+
+ if( aServiceSpecifier == "com.sun.star.document.ImportEmbeddedObjectResolver" )
+ {
+ comphelper::IEmbeddedHelper* pPersist = mpDoc->GetPersist();
+ if( nullptr == pPersist )
+ throw lang::DisposedException();
+
+ return static_cast<cppu::OWeakObject *>(new SvXMLEmbeddedObjectHelper( *pPersist, SvXMLEmbeddedObjectHelperMode::Read ));
+ }
+
+ uno::Reference< uno::XInterface > xRet;
+
+ if( aServiceSpecifier.startsWith( "com.sun.star.presentation.") )
+ {
+ const std::u16string_view aType( aServiceSpecifier.subView(26) );
+ rtl::Reference<SvxShape> pShape;
+
+ SdrObjKind nType = SdrObjKind::Text;
+ // create a shape wrapper
+ if( o3tl::starts_with(aType, u"TitleTextShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aType, u"OutlinerShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aType, u"SubtitleShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aType, u"GraphicObjectShape" ) )
+ {
+ nType = SdrObjKind::Graphic;
+ }
+ else if( o3tl::starts_with(aType, u"PageShape" ) )
+ {
+ nType = SdrObjKind::Page;
+ }
+ else if( o3tl::starts_with(aType, u"OLE2Shape" ) )
+ {
+ nType = SdrObjKind::OLE2;
+ }
+ else if( o3tl::starts_with(aType, u"ChartShape" ) )
+ {
+ nType = SdrObjKind::OLE2;
+ }
+ else if( o3tl::starts_with(aType, u"CalcShape" ) )
+ {
+ nType = SdrObjKind::OLE2;
+ }
+ else if( o3tl::starts_with(aType, u"TableShape" ) )
+ {
+ nType = SdrObjKind::Table;
+ }
+ else if( o3tl::starts_with(aType, u"OrgChartShape" ) )
+ {
+ nType = SdrObjKind::OLE2;
+ }
+ else if( o3tl::starts_with(aType, u"NotesShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aType, u"HandoutShape" ) )
+ {
+ nType = SdrObjKind::Page;
+ }
+ else if( o3tl::starts_with(aType, u"FooterShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aType, u"HeaderShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aType, u"SlideNumberShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aType, u"DateTimeShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aType, u"MediaShape" ) )
+ {
+ nType = SdrObjKind::Media;
+ }
+ else
+ {
+ throw lang::ServiceNotRegisteredException();
+ }
+
+ // create the API wrapper
+ pShape = CreateSvxShapeByTypeAndInventor( nType, SdrInventor::Default, referer );
+
+ // set shape type
+ if( pShape && !mbClipBoard )
+ pShape->SetShapeType(aServiceSpecifier);
+
+ xRet = static_cast<uno::XWeak*>(pShape.get());
+ }
+ else if ( aServiceSpecifier == "com.sun.star.drawing.TableShape" )
+ {
+ rtl::Reference<SvxShape> pShape = CreateSvxShapeByTypeAndInventor( SdrObjKind::Table, SdrInventor::Default, referer );
+ if( pShape && !mbClipBoard )
+ pShape->SetShapeType(aServiceSpecifier);
+
+ xRet = static_cast<uno::XWeak*>(pShape.get());
+ }
+ else
+ {
+ xRet = SvxFmMSFactory::createInstance( aServiceSpecifier );
+ }
+
+ uno::Reference< drawing::XShape > xShape( xRet, uno::UNO_QUERY );
+ SvxShape* pShape = xShape.is() ? comphelper::getFromUnoTunnel<SvxShape>(xShape) : nullptr;
+ if (pShape)
+ {
+ xRet.clear();
+ new SdXShape( pShape, this );
+ xRet = xShape;
+ xShape.clear();
+ }
+
+ return xRet;
+}
+
+uno::Reference< uno::XInterface > SAL_CALL SdXImpressDocument::createInstance( const OUString& aServiceSpecifier )
+{
+ return create(aServiceSpecifier, "");
+}
+
+css::uno::Reference<css::uno::XInterface>
+SdXImpressDocument::createInstanceWithArguments(
+ OUString const & ServiceSpecifier,
+ css::uno::Sequence<css::uno::Any> const & Arguments)
+{
+ OUString arg;
+ if ((ServiceSpecifier == "com.sun.star.drawing.GraphicObjectShape"
+ || ServiceSpecifier == "com.sun.star.drawing.MediaShape"
+ || ServiceSpecifier == "com.sun.star.presentation.MediaShape")
+ && Arguments.getLength() == 1 && (Arguments[0] >>= arg))
+ {
+ return create(ServiceSpecifier, arg);
+ }
+ return SvxFmMSFactory::createInstanceWithArguments(
+ ServiceSpecifier, Arguments);
+}
+
+uno::Sequence< OUString > SAL_CALL SdXImpressDocument::getAvailableServiceNames()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ const uno::Sequence< OUString > aSNS_ORG( SvxFmMSFactory::getAvailableServiceNames() );
+
+ uno::Sequence< OUString > aSNS_Common{ "com.sun.star.drawing.DashTable",
+ "com.sun.star.drawing.GradientTable",
+ "com.sun.star.drawing.HatchTable",
+ "com.sun.star.drawing.BitmapTable",
+ "com.sun.star.drawing.TransparencyGradientTable",
+ "com.sun.star.drawing.MarkerTable",
+ "com.sun.star.text.NumberingRules",
+ "com.sun.star.drawing.Background",
+ "com.sun.star.document.Settings",
+ sUNO_Service_ImageMapRectangleObject,
+ sUNO_Service_ImageMapCircleObject,
+ sUNO_Service_ImageMapPolygonObject,
+ "com.sun.star.xml.NamespaceMap",
+
+ // Support creation of GraphicStorageHandler and EmbeddedObjectResolver
+ "com.sun.star.document.ExportGraphicStorageHandler",
+ "com.sun.star.document.ImportGraphicStorageHandler",
+ "com.sun.star.document.ExportEmbeddedObjectResolver",
+ "com.sun.star.document.ImportEmbeddedObjectResolver",
+ "com.sun.star.drawing.TableShape" };
+
+ uno::Sequence< OUString > aSNS_Specific;
+
+ if(mbImpressDoc)
+ aSNS_Specific = { "com.sun.star.presentation.TitleTextShape",
+ "com.sun.star.presentation.OutlinerShape",
+ "com.sun.star.presentation.SubtitleShape",
+ "com.sun.star.presentation.GraphicObjectShape",
+ "com.sun.star.presentation.ChartShape",
+ "com.sun.star.presentation.PageShape",
+ "com.sun.star.presentation.OLE2Shape",
+ "com.sun.star.presentation.TableShape",
+ "com.sun.star.presentation.OrgChartShape",
+ "com.sun.star.presentation.NotesShape",
+ "com.sun.star.presentation.HandoutShape",
+ "com.sun.star.presentation.DocumentSettings",
+ "com.sun.star.presentation.FooterShape",
+ "com.sun.star.presentation.HeaderShape",
+ "com.sun.star.presentation.SlideNumberShape",
+ "com.sun.star.presentation.DateTimeShape",
+ "com.sun.star.presentation.CalcShape",
+ "com.sun.star.presentation.MediaShape" };
+ else
+ aSNS_Specific = { "com.sun.star.drawing.DocumentSettings" };
+
+ return comphelper::concatSequences( aSNS_ORG, aSNS_Common, aSNS_Specific );
+}
+
+// lang::XServiceInfo
+OUString SAL_CALL SdXImpressDocument::getImplementationName()
+{
+ return "SdXImpressDocument";
+ /* // Matching the .component information:
+ return mbImpressDoc
+ ? OUString("com.sun.star.comp.Draw.PresentationDocument")
+ : OUString("com.sun.star.comp.Draw.DrawingDocument");
+ */
+}
+
+sal_Bool SAL_CALL SdXImpressDocument::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL SdXImpressDocument::getSupportedServiceNames()
+{
+ ::SolarMutexGuard aGuard;
+
+ return { "com.sun.star.document.OfficeDocument",
+ "com.sun.star.drawing.GenericDrawingDocument",
+ "com.sun.star.drawing.DrawingDocumentFactory",
+ mbImpressDoc?OUString("com.sun.star.presentation.PresentationDocument"):OUString("com.sun.star.drawing.DrawingDocument") };
+}
+
+// XPropertySet
+uno::Reference< beans::XPropertySetInfo > SAL_CALL SdXImpressDocument::getPropertySetInfo( )
+{
+ ::SolarMutexGuard aGuard;
+ return mpPropSet->getPropertySetInfo();
+}
+
+void SAL_CALL SdXImpressDocument::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ const SfxItemPropertyMapEntry* pEntry = mpPropSet->getPropertyMapEntry(aPropertyName);
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case WID_MODEL_LANGUAGE:
+ {
+ lang::Locale aLocale;
+ if(!(aValue >>= aLocale))
+ throw lang::IllegalArgumentException();
+
+ mpDoc->SetLanguage( LanguageTag::convertToLanguageType(aLocale), EE_CHAR_LANGUAGE );
+ break;
+ }
+ case WID_MODEL_TABSTOP:
+ {
+ sal_Int32 nValue = 0;
+ if(!(aValue >>= nValue) || nValue < 0 )
+ throw lang::IllegalArgumentException();
+
+ mpDoc->SetDefaultTabulator(static_cast<sal_uInt16>(nValue));
+ break;
+ }
+ case WID_MODEL_VISAREA:
+ {
+ SfxObjectShell* pEmbeddedObj = mpDoc->GetDocSh();
+ if( !pEmbeddedObj )
+ break;
+
+ awt::Rectangle aVisArea;
+ if( !(aValue >>= aVisArea) || (aVisArea.Width < 0) || (aVisArea.Height < 0) )
+ throw lang::IllegalArgumentException();
+
+ sal_Int32 nRight, nTop;
+ if (o3tl::checked_add(aVisArea.X, aVisArea.Width, nRight) || o3tl::checked_add(aVisArea.Y, aVisArea.Height, nTop))
+ throw lang::IllegalArgumentException();
+
+ pEmbeddedObj->SetVisArea(::tools::Rectangle(aVisArea.X, aVisArea.Y, nRight, nTop));
+ }
+ break;
+ case WID_MODEL_CONTFOCUS:
+ {
+ bool bFocus = false;
+ if( !(aValue >>= bFocus ) )
+ throw lang::IllegalArgumentException();
+ mpDoc->SetAutoControlFocus( bFocus );
+ }
+ break;
+ case WID_MODEL_DSGNMODE:
+ {
+ bool bMode = false;
+ if( !(aValue >>= bMode ) )
+ throw lang::IllegalArgumentException();
+ mpDoc->SetOpenInDesignMode( bMode );
+ }
+ break;
+ case WID_MODEL_BUILDID:
+ aValue >>= maBuildId;
+ return;
+ case WID_MODEL_MAPUNIT:
+ case WID_MODEL_BASICLIBS:
+ case WID_MODEL_RUNTIMEUID: // is read-only
+ case WID_MODEL_DIALOGLIBS:
+ case WID_MODEL_FONTS:
+ throw beans::PropertyVetoException();
+ case WID_MODEL_INTEROPGRABBAG:
+ setGrabBagItem(aValue);
+ break;
+ case WID_MODEL_THEME:
+ {
+ SdrModel& rModel = getSdrModelFromUnoModel();
+ std::unique_ptr<svx::Theme> pTheme = svx::Theme::FromAny(aValue);
+ rModel.SetTheme(std::move(pTheme));
+ }
+ break;
+ default:
+ throw beans::UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ SetModified();
+}
+
+uno::Any SAL_CALL SdXImpressDocument::getPropertyValue( const OUString& PropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ uno::Any aAny;
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ const SfxItemPropertyMapEntry* pEntry = mpPropSet->getPropertyMapEntry(PropertyName);
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case WID_MODEL_LANGUAGE:
+ {
+ LanguageType eLang = mpDoc->GetLanguage( EE_CHAR_LANGUAGE );
+ aAny <<= LanguageTag::convertToLocale( eLang);
+ break;
+ }
+ case WID_MODEL_TABSTOP:
+ aAny <<= static_cast<sal_Int32>(mpDoc->GetDefaultTabulator());
+ break;
+ case WID_MODEL_VISAREA:
+ {
+ SfxObjectShell* pEmbeddedObj = mpDoc->GetDocSh();
+ if( !pEmbeddedObj )
+ break;
+
+ const ::tools::Rectangle& aRect = pEmbeddedObj->GetVisArea();
+ awt::Rectangle aVisArea( aRect.Left(), aRect.Top(), aRect.getWidth(), aRect.getHeight() );
+ aAny <<= aVisArea;
+ }
+ break;
+ case WID_MODEL_MAPUNIT:
+ {
+ SfxObjectShell* pEmbeddedObj = mpDoc->GetDocSh();
+ if( !pEmbeddedObj )
+ break;
+
+ sal_Int16 nMeasureUnit = 0;
+ SvxMapUnitToMeasureUnit( pEmbeddedObj->GetMapUnit(), nMeasureUnit );
+ aAny <<= nMeasureUnit;
+ }
+ break;
+ case WID_MODEL_FORBCHARS:
+ {
+ aAny <<= getForbiddenCharsTable();
+ }
+ break;
+ case WID_MODEL_CONTFOCUS:
+ aAny <<= mpDoc->GetAutoControlFocus();
+ break;
+ case WID_MODEL_DSGNMODE:
+ aAny <<= mpDoc->GetOpenInDesignMode();
+ break;
+ case WID_MODEL_BASICLIBS:
+ aAny <<= mpDocShell->GetBasicContainer();
+ break;
+ case WID_MODEL_DIALOGLIBS:
+ aAny <<= mpDocShell->GetDialogContainer();
+ break;
+ case WID_MODEL_RUNTIMEUID:
+ aAny <<= getRuntimeUID();
+ break;
+ case WID_MODEL_BUILDID:
+ return uno::Any( maBuildId );
+ case WID_MODEL_HASVALIDSIGNATURES:
+ aAny <<= hasValidSignatures();
+ break;
+ case WID_MODEL_FONTS:
+ {
+ uno::Sequence<uno::Any> aSeq;
+ int nSeqIndex = 0;
+
+ sal_uInt16 const aWhichIds[] { EE_CHAR_FONTINFO, EE_CHAR_FONTINFO_CJK,
+ EE_CHAR_FONTINFO_CTL };
+
+ const SfxItemPool& rPool = mpDoc->GetPool();
+
+ for(sal_uInt16 nWhichId : aWhichIds)
+ {
+ sal_uInt32 nItems = rPool.GetItemCount2( nWhichId );
+
+ aSeq.realloc( aSeq.getLength() + nItems*5 + 5 );
+ auto pSeq = aSeq.getArray();
+
+ for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(nWhichId))
+ {
+ const SvxFontItem *pFont = static_cast<const SvxFontItem *>(pItem);
+
+ pSeq[nSeqIndex++] <<= pFont->GetFamilyName();
+ pSeq[nSeqIndex++] <<= pFont->GetStyleName();
+ pSeq[nSeqIndex++] <<= sal_Int16(pFont->GetFamily());
+ pSeq[nSeqIndex++] <<= sal_Int16(pFont->GetPitch());
+ pSeq[nSeqIndex++] <<= sal_Int16(pFont->GetCharSet());
+ }
+
+ const SvxFontItem& rFont = static_cast<const SvxFontItem&>(rPool.GetDefaultItem( nWhichId ));
+
+ pSeq[nSeqIndex++] <<= rFont.GetFamilyName();
+ pSeq[nSeqIndex++] <<= rFont.GetStyleName();
+ pSeq[nSeqIndex++] <<= sal_Int16(rFont.GetFamily());
+ pSeq[nSeqIndex++] <<= sal_Int16(rFont.GetPitch());
+ pSeq[nSeqIndex++] <<= sal_Int16(rFont.GetCharSet());
+
+ }
+
+ aSeq.realloc( nSeqIndex );
+ aAny <<= aSeq;
+ break;
+ }
+ case WID_MODEL_INTEROPGRABBAG:
+ getGrabBagItem(aAny);
+ break;
+ case WID_MODEL_THEME:
+ {
+ SdrModel& rModel = getSdrModelFromUnoModel();
+ svx::Theme* pTheme = rModel.GetTheme();
+ if (pTheme)
+ {
+ pTheme->ToAny(aAny);
+ }
+ else
+ {
+ beans::PropertyValues aValues;
+ aAny <<= aValues;
+ }
+ break;
+ }
+ default:
+ throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ return aAny;
+}
+
+void SAL_CALL SdXImpressDocument::addPropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& ) {}
+void SAL_CALL SdXImpressDocument::removePropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& ) {}
+void SAL_CALL SdXImpressDocument::addVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& ) {}
+void SAL_CALL SdXImpressDocument::removeVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& ) {}
+
+// XLinkTargetSupplier
+uno::Reference< container::XNameAccess > SAL_CALL SdXImpressDocument::getLinks()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ uno::Reference< container::XNameAccess > xLinks( mxLinks );
+ if( !xLinks.is() )
+ mxLinks = xLinks = new SdDocLinkTargets( *this );
+ return xLinks;
+}
+
+// XStyleFamiliesSupplier
+uno::Reference< container::XNameAccess > SAL_CALL SdXImpressDocument::getStyleFamilies( )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ uno::Reference< container::XNameAccess > xStyles( dynamic_cast< container::XNameAccess* >( mpDoc->GetStyleSheetPool()) );
+ return xStyles;
+}
+
+// XAnyCompareFactory
+uno::Reference< css::ucb::XAnyCompare > SAL_CALL SdXImpressDocument::createAnyCompareByName( const OUString& )
+{
+ return SvxCreateNumRuleCompare();
+}
+
+// XRenderable
+sal_Int32 SAL_CALL SdXImpressDocument::getRendererCount( const uno::Any& rSelection,
+ const uno::Sequence< beans::PropertyValue >& )
+{
+ ::SolarMutexGuard aGuard;
+ sal_Int32 nRet = 0;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ if (mpDocShell)
+ {
+ uno::Reference< frame::XModel > xModel;
+
+ rSelection >>= xModel;
+
+ if( xModel == mpDocShell->GetModel() )
+ nRet = mpDoc->GetSdPageCount( PageKind::Standard );
+ else
+ {
+ uno::Reference< drawing::XShapes > xShapes;
+
+ rSelection >>= xShapes;
+
+ if( xShapes.is() && xShapes->getCount() )
+ nRet = 1;
+ }
+ }
+ return nRet;
+}
+
+uno::Sequence< beans::PropertyValue > SAL_CALL SdXImpressDocument::getRenderer( sal_Int32 , const uno::Any& ,
+ const uno::Sequence< beans::PropertyValue >& rxOptions )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ bool bExportNotesPages = false;
+ for( const auto& rOption : rxOptions )
+ {
+ if ( rOption.Name == "ExportNotesPages" )
+ rOption.Value >>= bExportNotesPages;
+ }
+ uno::Sequence< beans::PropertyValue > aRenderer;
+ if (mpDocShell)
+ {
+ awt::Size aPageSize;
+ if ( bExportNotesPages )
+ {
+ Size aNotesPageSize = mpDoc->GetSdPage( 0, PageKind::Notes )->GetSize();
+ aPageSize = awt::Size( aNotesPageSize.Width(), aNotesPageSize.Height() );
+ }
+ else
+ {
+ const ::tools::Rectangle aVisArea( mpDocShell->GetVisArea( embed::Aspects::MSOLE_DOCPRINT ) );
+ aPageSize = awt::Size( aVisArea.GetWidth(), aVisArea.GetHeight() );
+ }
+ aRenderer = { comphelper::makePropertyValue("PageSize", aPageSize) };
+ }
+ return aRenderer;
+}
+
+namespace {
+
+class ImplRenderPaintProc : public sdr::contact::ViewObjectContactRedirector
+{
+ const SdrLayerAdmin& rLayerAdmin;
+ SdrPageView* pSdrPageView;
+
+public:
+ bool IsVisible ( const SdrObject* pObj ) const;
+ bool IsPrintable( const SdrObject* pObj ) const;
+
+ ImplRenderPaintProc(const SdrLayerAdmin& rLA, SdrPageView* pView);
+
+ // all default implementations just call the same methods at the original. To do something
+ // different, override the method and at least do what the method does.
+ virtual void createRedirectedPrimitive2DSequence(
+ const sdr::contact::ViewObjectContact& rOriginal,
+ const sdr::contact::DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) override;
+};
+
+}
+
+ImplRenderPaintProc::ImplRenderPaintProc(const SdrLayerAdmin& rLA, SdrPageView *const pView)
+ : rLayerAdmin(rLA)
+ , pSdrPageView(pView)
+{
+}
+
+static sal_Int32 ImplPDFGetBookmarkPage( const OUString& rBookmark, SdDrawDocument const & rDoc )
+{
+ sal_Int32 nPage = -1;
+
+ OUString aBookmark( rBookmark );
+
+ if( rBookmark.startsWith("#") )
+ aBookmark = rBookmark.copy( 1 );
+
+ // is the bookmark a page ?
+ bool bIsMasterPage;
+ sal_uInt16 nPgNum = rDoc.GetPageByName( aBookmark, bIsMasterPage );
+
+ if ( nPgNum == SDRPAGE_NOTFOUND )
+ {
+ // is the bookmark an object ?
+ SdrObject* pObj = rDoc.GetObj( aBookmark );
+ if (pObj)
+ nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum();
+ }
+ if ( nPgNum != SDRPAGE_NOTFOUND )
+ nPage = ( nPgNum - 1 ) / 2;
+ return nPage;
+}
+
+static void ImplPDFExportComments( const uno::Reference< drawing::XDrawPage >& xPage, vcl::PDFExtOutDevData& rPDFExtOutDevData )
+{
+ try
+ {
+ uno::Reference< office::XAnnotationAccess > xAnnotationAccess( xPage, uno::UNO_QUERY_THROW );
+ uno::Reference< office::XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() );
+
+ while( xAnnotationEnumeration->hasMoreElements() )
+ {
+ uno::Reference< office::XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement() );
+
+ geometry::RealPoint2D aRealPoint2D( xAnnotation->getPosition() );
+ uno::Reference< text::XText > xText( xAnnotation->getTextRange() );
+
+ vcl::PDFNote aNote;
+ aNote.Title = xAnnotation->getAuthor();
+ aNote.Contents = xText->getString();
+ aNote.maModificationDate = xAnnotation->getDateTime();
+
+ rPDFExtOutDevData.CreateNote( ::tools::Rectangle( Point( static_cast< ::tools::Long >( aRealPoint2D.X * 100 ),
+ static_cast< ::tools::Long >( aRealPoint2D.Y * 100 ) ), Size( 1000, 1000 ) ), aNote );
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+static void ImplPDFExportShapeInteraction( const uno::Reference< drawing::XShape >& xShape, SdDrawDocument& rDoc, vcl::PDFExtOutDevData& rPDFExtOutDevData )
+{
+ if ( xShape->getShapeType() == "com.sun.star.drawing.GroupShape" )
+ {
+ uno::Reference< container::XIndexAccess > xIndexAccess( xShape, uno::UNO_QUERY );
+ if ( xIndexAccess.is() )
+ {
+ sal_Int32 i, nCount = xIndexAccess->getCount();
+ for ( i = 0; i < nCount; i++ )
+ {
+ uno::Reference< drawing::XShape > xSubShape( xIndexAccess->getByIndex( i ), uno::UNO_QUERY );
+ if ( xSubShape.is() )
+ ImplPDFExportShapeInteraction( xSubShape, rDoc, rPDFExtOutDevData );
+ }
+ }
+ }
+ else
+ {
+ uno::Reference< beans::XPropertySet > xShapePropSet( xShape, uno::UNO_QUERY );
+ if( xShapePropSet.is() )
+ {
+ Size aPageSize( rDoc.GetSdPage( 0, PageKind::Standard )->GetSize() );
+ Point aPoint( 0, 0 );
+ ::tools::Rectangle aPageRect( aPoint, aPageSize );
+
+ awt::Point aShapePos( xShape->getPosition() );
+ awt::Size aShapeSize( xShape->getSize() );
+ ::tools::Rectangle aLinkRect( Point( aShapePos.X, aShapePos.Y ), Size( aShapeSize.Width, aShapeSize.Height ) );
+
+ // Handle linked videos.
+ if (xShape->getShapeType() == "com.sun.star.drawing.MediaShape" || xShape->getShapeType() == "com.sun.star.presentation.MediaShape")
+ {
+ OUString aMediaURL;
+ xShapePropSet->getPropertyValue("MediaURL") >>= aMediaURL;
+ if (!aMediaURL.isEmpty())
+ {
+ sal_Int32 nScreenId = rPDFExtOutDevData.CreateScreen(aLinkRect, rPDFExtOutDevData.GetCurrentPageNumber());
+ if (aMediaURL.startsWith("vnd.sun.star.Package:"))
+ {
+ OUString aTempFileURL;
+ xShapePropSet->getPropertyValue("PrivateTempFileURL") >>= aTempFileURL;
+ rPDFExtOutDevData.SetScreenStream(nScreenId, aTempFileURL);
+ }
+ else
+ rPDFExtOutDevData.SetScreenURL(nScreenId, aMediaURL);
+ }
+ }
+
+ presentation::ClickAction eCa;
+ uno::Any aAny( xShapePropSet->getPropertyValue( "OnClick" ) );
+ if ( aAny >>= eCa )
+ {
+ OUString const actionName(SdResId(SdTPAction::GetClickActionSdResId(eCa)));
+ switch ( eCa )
+ {
+ case presentation::ClickAction_LASTPAGE :
+ {
+ sal_Int32 nCount = rDoc.GetSdPageCount( PageKind::Standard );
+ sal_Int32 nDestId = rPDFExtOutDevData.CreateDest( aPageRect, nCount - 1, vcl::PDFWriter::DestAreaType::FitRectangle );
+ sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink(aLinkRect, actionName);
+ rPDFExtOutDevData.SetLinkDest( nLinkId, nDestId );
+ }
+ break;
+ case presentation::ClickAction_FIRSTPAGE :
+ {
+ sal_Int32 nDestId = rPDFExtOutDevData.CreateDest( aPageRect, 0, vcl::PDFWriter::DestAreaType::FitRectangle );
+ sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink(aLinkRect, actionName);
+ rPDFExtOutDevData.SetLinkDest( nLinkId, nDestId );
+ }
+ break;
+ case presentation::ClickAction_PREVPAGE :
+ {
+ sal_Int32 nDestPage = rPDFExtOutDevData.GetCurrentPageNumber();
+ if ( nDestPage )
+ nDestPage--;
+ sal_Int32 nDestId = rPDFExtOutDevData.CreateDest( aPageRect, nDestPage, vcl::PDFWriter::DestAreaType::FitRectangle );
+ sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink(aLinkRect, actionName);
+ rPDFExtOutDevData.SetLinkDest( nLinkId, nDestId );
+ }
+ break;
+ case presentation::ClickAction_NEXTPAGE :
+ {
+ sal_Int32 nDestPage = rPDFExtOutDevData.GetCurrentPageNumber() + 1;
+ sal_Int32 nLastPage = rDoc.GetSdPageCount( PageKind::Standard ) - 1;
+ if ( nDestPage > nLastPage )
+ nDestPage = nLastPage;
+ sal_Int32 nDestId = rPDFExtOutDevData.CreateDest( aPageRect, nDestPage, vcl::PDFWriter::DestAreaType::FitRectangle );
+ sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink(aLinkRect, actionName);
+ rPDFExtOutDevData.SetLinkDest( nLinkId, nDestId );
+ }
+ break;
+
+ case presentation::ClickAction_PROGRAM :
+ case presentation::ClickAction_BOOKMARK :
+ case presentation::ClickAction_DOCUMENT :
+ {
+ OUString aBookmark;
+ xShapePropSet->getPropertyValue( "Bookmark" ) >>= aBookmark;
+ if( !aBookmark.isEmpty() )
+ {
+ switch( eCa )
+ {
+ case presentation::ClickAction_DOCUMENT :
+ case presentation::ClickAction_PROGRAM :
+ {
+ sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink(aLinkRect, actionName);
+ rPDFExtOutDevData.SetLinkURL( nLinkId, aBookmark );
+ }
+ break;
+ case presentation::ClickAction_BOOKMARK :
+ {
+ sal_Int32 nPage = ImplPDFGetBookmarkPage( aBookmark, rDoc );
+ if ( nPage != -1 )
+ {
+ sal_Int32 nDestId = rPDFExtOutDevData.CreateDest( aPageRect, nPage, vcl::PDFWriter::DestAreaType::FitRectangle );
+ sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink(aLinkRect, actionName);
+ rPDFExtOutDevData.SetLinkDest( nLinkId, nDestId );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case presentation::ClickAction_STOPPRESENTATION :
+ case presentation::ClickAction_SOUND :
+ case presentation::ClickAction_INVISIBLE :
+ case presentation::ClickAction_VERB :
+ case presentation::ClickAction_VANISH :
+ case presentation::ClickAction_MACRO :
+ default :
+ break;
+ }
+ }
+ }
+ }
+}
+
+void ImplRenderPaintProc::createRedirectedPrimitive2DSequence(
+ const sdr::contact::ViewObjectContact& rOriginal,
+ const sdr::contact::DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+{
+ SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
+ if(!pObject)
+ {
+ // not an object, maybe a page
+ sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor);
+ return;
+ }
+ SdrPage* pSdrPage(pObject->getSdrPageFromSdrObject());
+ if(!pSdrPage)
+ return;
+ if(!pSdrPage->checkVisibility(rOriginal, rDisplayInfo, false))
+ return;
+ if(!IsVisible(pObject) || !IsPrintable(pObject))
+ return;
+
+ sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor);
+}
+
+bool ImplRenderPaintProc::IsVisible( const SdrObject* pObj ) const
+{
+ bool bVisible = true;
+ SdrLayerID nLayerId = pObj->GetLayer();
+ if( pSdrPageView )
+ {
+ const SdrLayer* pSdrLayer = rLayerAdmin.GetLayerPerID( nLayerId );
+ if ( pSdrLayer )
+ {
+ const OUString& aLayerName = pSdrLayer->GetName();
+ bVisible = pSdrPageView->IsLayerVisible( aLayerName );
+ }
+ }
+ return bVisible;
+}
+bool ImplRenderPaintProc::IsPrintable( const SdrObject* pObj ) const
+{
+ bool bPrintable = true;
+ SdrLayerID nLayerId = pObj->GetLayer();
+ if( pSdrPageView )
+ {
+ const SdrLayer* pSdrLayer = rLayerAdmin.GetLayerPerID( nLayerId );
+ if ( pSdrLayer )
+ {
+ const OUString& aLayerName = pSdrLayer->GetName();
+ bPrintable = pSdrPageView->IsLayerPrintable( aLayerName );
+ }
+ }
+ return bPrintable;
+
+}
+
+namespace
+{
+ sal_Int16 CalcOutputPageNum(vcl::PDFExtOutDevData const * pPDFExtOutDevData, SdDrawDocument const *pDoc, sal_Int16 nPageNumber)
+ {
+ //export all pages, simple one to one case
+ if (pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportHiddenSlides())
+ return nPageNumber-1;
+ //check all preceding pages, and only count non-hidden ones
+ sal_Int16 nRet = 0;
+ for (sal_Int16 i = 0; i < nPageNumber-1; ++i)
+ {
+ if (!pDoc->GetSdPage(i, PageKind::Standard)->IsExcluded())
+ ++nRet;
+ }
+ return nRet;
+ }
+}
+
+void SAL_CALL SdXImpressDocument::render( sal_Int32 nRenderer, const uno::Any& rSelection,
+ const uno::Sequence< beans::PropertyValue >& rxOptions )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpDoc )
+ throw lang::DisposedException();
+
+ if (!mpDocShell)
+ return;
+
+ uno::Reference< awt::XDevice > xRenderDevice;
+ const sal_Int32 nPageNumber = nRenderer + 1;
+ PageKind ePageKind = PageKind::Standard;
+ bool bExportNotesPages = false;
+
+ for( const auto& rOption : rxOptions )
+ {
+ if ( rOption.Name == "RenderDevice" )
+ rOption.Value >>= xRenderDevice;
+ else if ( rOption.Name == "ExportNotesPages" )
+ {
+ rOption.Value >>= bExportNotesPages;
+ if ( bExportNotesPages )
+ ePageKind = PageKind::Notes;
+ }
+ }
+
+ if( !(xRenderDevice.is() && nPageNumber && ( nPageNumber <= mpDoc->GetSdPageCount( ePageKind ) )) )
+ return;
+
+ VCLXDevice* pDevice = comphelper::getFromUnoTunnel<VCLXDevice>( xRenderDevice );
+ VclPtr< OutputDevice> pOut = pDevice ? pDevice->GetOutputDevice() : VclPtr< OutputDevice >();
+
+ if( !pOut )
+ return;
+
+ vcl::PDFExtOutDevData* pPDFExtOutDevData = dynamic_cast<vcl::PDFExtOutDevData* >( pOut->GetExtOutDevData() );
+
+ if ( mpDoc->GetSdPage(static_cast<sal_Int16>(nPageNumber)-1, PageKind::Standard)->IsExcluded() &&
+ !(pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportHiddenSlides()) )
+ return;
+
+ if (pPDFExtOutDevData)
+ {
+ css::lang::Locale const docLocale(Application::GetSettings().GetLanguageTag().getLocale());
+ pPDFExtOutDevData->SetDocumentLocale(docLocale);
+ }
+
+ ::sd::ClientView aView( mpDocShell, pOut );
+ ::tools::Rectangle aVisArea( Point(), mpDoc->GetSdPage( static_cast<sal_uInt16>(nPageNumber) - 1, ePageKind )->GetSize() );
+ vcl::Region aRegion( aVisArea );
+
+ ::sd::ViewShell* pOldViewSh = mpDocShell->GetViewShell();
+ ::sd::View* pOldSdView = pOldViewSh ? pOldViewSh->GetView() : nullptr;
+
+ if ( pOldSdView )
+ pOldSdView->SdrEndTextEdit();
+
+ aView.SetHlplVisible( false );
+ aView.SetGridVisible( false );
+ aView.SetBordVisible( false );
+ aView.SetPageVisible( false );
+ aView.SetGlueVisible( false );
+
+ pOut->SetMapMode(MapMode(MapUnit::Map100thMM));
+ pOut->IntersectClipRegion( aVisArea );
+
+ uno::Reference< frame::XModel > xModel;
+ rSelection >>= xModel;
+
+ if( xModel == mpDocShell->GetModel() )
+ {
+ aView.ShowSdrPage( mpDoc->GetSdPage( static_cast<sal_uInt16>(nPageNumber) - 1, ePageKind ));
+ SdrPageView* pPV = aView.GetSdrPageView();
+
+ if( pOldSdView )
+ {
+ SdrPageView* pOldPV = pOldSdView->GetSdrPageView();
+ if( pPV && pOldPV )
+ {
+ pPV->SetVisibleLayers( pOldPV->GetVisibleLayers() );
+ pPV->SetPrintableLayers( pOldPV->GetPrintableLayers() );
+ }
+ }
+
+ ImplRenderPaintProc aImplRenderPaintProc( mpDoc->GetLayerAdmin(),
+ pPV);
+
+ // background color for outliner :o
+ SdPage* pPage = pPV ? static_cast<SdPage*>(pPV->GetPage()) : nullptr;
+ if( pPage )
+ {
+ SdrOutliner& rOutl = mpDoc->GetDrawOutliner();
+ bool bScreenDisplay(true);
+
+ // #i75566# printing; suppress AutoColor BackgroundColor generation
+ // for visibility reasons by giving GetPageBackgroundColor()
+ // the needed hint
+ // #i75566# PDF export; suppress AutoColor BackgroundColor generation (see printing)
+ if (pOut && ((OUTDEV_PRINTER == pOut->GetOutDevType())
+ || (OUTDEV_PDF == pOut->GetOutDevType())))
+ bScreenDisplay = false;
+
+ // #i75566# Name change GetBackgroundColor -> GetPageBackgroundColor and
+ // hint value if screen display. Only then the AutoColor mechanisms shall be applied
+ rOutl.SetBackgroundColor( pPage->GetPageBackgroundColor( pPV, bScreenDisplay ) );
+ }
+ aView.SdrPaintView::CompleteRedraw( pOut, aRegion, &aImplRenderPaintProc );
+
+ if ( pPDFExtOutDevData && pPage )
+ {
+ try
+ {
+ uno::Any aAny;
+ uno::Reference< drawing::XDrawPage > xPage( uno::Reference< drawing::XDrawPage >::query( pPage->getUnoPage() ) );
+ if ( xPage.is() )
+ {
+ if ( pPDFExtOutDevData->GetIsExportNotes() )
+ ImplPDFExportComments( xPage, *pPDFExtOutDevData );
+ uno::Reference< beans::XPropertySet > xPagePropSet( xPage, uno::UNO_QUERY );
+ if( xPagePropSet.is() )
+ {
+ // exporting object interactions to pdf
+
+ // if necessary, the master page interactions will be exported first
+ bool bIsBackgroundObjectsVisible = false; // #i39428# IsBackgroundObjectsVisible not available for Draw
+ if ( mbImpressDoc && xPagePropSet->getPropertySetInfo()->hasPropertyByName( "IsBackgroundObjectsVisible" ) )
+ xPagePropSet->getPropertyValue( "IsBackgroundObjectsVisible" ) >>= bIsBackgroundObjectsVisible;
+ if ( bIsBackgroundObjectsVisible && !pPDFExtOutDevData->GetIsExportNotesPages() )
+ {
+ uno::Reference< drawing::XMasterPageTarget > xMasterPageTarget( xPage, uno::UNO_QUERY );
+ if ( xMasterPageTarget.is() )
+ {
+ uno::Reference< drawing::XDrawPage > xMasterPage = xMasterPageTarget->getMasterPage();
+ if ( xMasterPage.is() )
+ {
+ sal_Int32 i, nCount = xMasterPage->getCount();
+ for ( i = 0; i < nCount; i++ )
+ {
+ aAny = xMasterPage->getByIndex( i );
+ uno::Reference< drawing::XShape > xShape;
+ if ( aAny >>= xShape )
+ ImplPDFExportShapeInteraction( xShape, *mpDoc, *pPDFExtOutDevData );
+ }
+ }
+ }
+ }
+
+ // exporting slide page object interactions
+ sal_Int32 i, nCount = xPage->getCount();
+ for ( i = 0; i < nCount; i++ )
+ {
+ aAny = xPage->getByIndex( i );
+ uno::Reference< drawing::XShape > xShape;
+ if ( aAny >>= xShape )
+ ImplPDFExportShapeInteraction( xShape, *mpDoc, *pPDFExtOutDevData );
+ }
+
+ // exporting transition effects to pdf
+ if ( mbImpressDoc && !pPDFExtOutDevData->GetIsExportNotesPages() && pPDFExtOutDevData->GetIsExportTransitionEffects() )
+ {
+ static const OUStringLiteral sEffect( u"Effect" );
+ static const OUStringLiteral sSpeed ( u"Speed" );
+ sal_Int32 nTime = 800;
+ presentation::AnimationSpeed aAs;
+ if ( xPagePropSet->getPropertySetInfo( )->hasPropertyByName( sSpeed ) )
+ {
+ aAny = xPagePropSet->getPropertyValue( sSpeed );
+ if ( aAny >>= aAs )
+ {
+ switch( aAs )
+ {
+ case presentation::AnimationSpeed_SLOW : nTime = 1500; break;
+ case presentation::AnimationSpeed_FAST : nTime = 300; break;
+ default:
+ case presentation::AnimationSpeed_MEDIUM : nTime = 800;
+ }
+ }
+ }
+ presentation::FadeEffect eFe;
+ vcl::PDFWriter::PageTransition eType = vcl::PDFWriter::PageTransition::Regular;
+ if ( xPagePropSet->getPropertySetInfo( )->hasPropertyByName( sEffect ) )
+ {
+ aAny = xPagePropSet->getPropertyValue( sEffect );
+ if ( aAny >>= eFe )
+ {
+ switch( eFe )
+ {
+ case presentation::FadeEffect_HORIZONTAL_LINES :
+ case presentation::FadeEffect_HORIZONTAL_CHECKERBOARD :
+ case presentation::FadeEffect_HORIZONTAL_STRIPES : eType = vcl::PDFWriter::PageTransition::BlindsHorizontal; break;
+
+ case presentation::FadeEffect_VERTICAL_LINES :
+ case presentation::FadeEffect_VERTICAL_CHECKERBOARD :
+ case presentation::FadeEffect_VERTICAL_STRIPES : eType = vcl::PDFWriter::PageTransition::BlindsVertical; break;
+
+ case presentation::FadeEffect_UNCOVER_TO_RIGHT :
+ case presentation::FadeEffect_UNCOVER_TO_UPPERRIGHT :
+ case presentation::FadeEffect_ROLL_FROM_LEFT :
+ case presentation::FadeEffect_FADE_FROM_UPPERLEFT :
+ case presentation::FadeEffect_MOVE_FROM_UPPERLEFT :
+ case presentation::FadeEffect_FADE_FROM_LEFT :
+ case presentation::FadeEffect_MOVE_FROM_LEFT : eType = vcl::PDFWriter::PageTransition::WipeLeftToRight; break;
+
+ case presentation::FadeEffect_UNCOVER_TO_BOTTOM :
+ case presentation::FadeEffect_UNCOVER_TO_LOWERRIGHT :
+ case presentation::FadeEffect_ROLL_FROM_TOP :
+ case presentation::FadeEffect_FADE_FROM_UPPERRIGHT :
+ case presentation::FadeEffect_MOVE_FROM_UPPERRIGHT :
+ case presentation::FadeEffect_FADE_FROM_TOP :
+ case presentation::FadeEffect_MOVE_FROM_TOP : eType = vcl::PDFWriter::PageTransition::WipeTopToBottom; break;
+
+ case presentation::FadeEffect_UNCOVER_TO_LEFT :
+ case presentation::FadeEffect_UNCOVER_TO_LOWERLEFT :
+ case presentation::FadeEffect_ROLL_FROM_RIGHT :
+
+ case presentation::FadeEffect_FADE_FROM_LOWERRIGHT :
+ case presentation::FadeEffect_MOVE_FROM_LOWERRIGHT :
+ case presentation::FadeEffect_FADE_FROM_RIGHT :
+ case presentation::FadeEffect_MOVE_FROM_RIGHT : eType = vcl::PDFWriter::PageTransition::WipeRightToLeft; break;
+
+ case presentation::FadeEffect_UNCOVER_TO_TOP :
+ case presentation::FadeEffect_UNCOVER_TO_UPPERLEFT :
+ case presentation::FadeEffect_ROLL_FROM_BOTTOM :
+ case presentation::FadeEffect_FADE_FROM_LOWERLEFT :
+ case presentation::FadeEffect_MOVE_FROM_LOWERLEFT :
+ case presentation::FadeEffect_FADE_FROM_BOTTOM :
+ case presentation::FadeEffect_MOVE_FROM_BOTTOM : eType = vcl::PDFWriter::PageTransition::WipeBottomToTop; break;
+
+ case presentation::FadeEffect_OPEN_VERTICAL : eType = vcl::PDFWriter::PageTransition::SplitHorizontalInward; break;
+ case presentation::FadeEffect_CLOSE_HORIZONTAL : eType = vcl::PDFWriter::PageTransition::SplitHorizontalOutward; break;
+
+ case presentation::FadeEffect_OPEN_HORIZONTAL : eType = vcl::PDFWriter::PageTransition::SplitVerticalInward; break;
+ case presentation::FadeEffect_CLOSE_VERTICAL : eType = vcl::PDFWriter::PageTransition::SplitVerticalOutward; break;
+
+ case presentation::FadeEffect_FADE_TO_CENTER : eType = vcl::PDFWriter::PageTransition::BoxInward; break;
+ case presentation::FadeEffect_FADE_FROM_CENTER : eType = vcl::PDFWriter::PageTransition::BoxOutward; break;
+
+ case presentation::FadeEffect_NONE : eType = vcl::PDFWriter::PageTransition::Regular; break;
+
+ case presentation::FadeEffect_RANDOM :
+ case presentation::FadeEffect_DISSOLVE :
+ default: eType = vcl::PDFWriter::PageTransition::Dissolve; break;
+ }
+ }
+ }
+
+ if ( xPagePropSet->getPropertySetInfo( )->hasPropertyByName( sEffect ) ||
+ xPagePropSet->getPropertySetInfo( )->hasPropertyByName( sSpeed ) )
+ {
+ pPDFExtOutDevData->SetPageTransition( eType, nTime );
+ }
+ }
+ }
+ }
+
+ Size aPageSize( mpDoc->GetSdPage( 0, PageKind::Standard )->GetSize() );
+ Point aPoint( 0, 0 );
+ ::tools::Rectangle aPageRect( aPoint, aPageSize );
+
+ // resolving links found in this page by the method ImpEditEngine::Paint
+ std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks();
+ for ( const auto& rBookmark : rBookmarks )
+ {
+ sal_Int32 nPage = ImplPDFGetBookmarkPage( rBookmark.aBookmark, *mpDoc );
+ if ( nPage != -1 )
+ {
+ if ( rBookmark.nLinkId != -1 )
+ pPDFExtOutDevData->SetLinkDest( rBookmark.nLinkId, pPDFExtOutDevData->CreateDest( aPageRect, nPage, vcl::PDFWriter::DestAreaType::FitRectangle ) );
+ else
+ pPDFExtOutDevData->DescribeRegisteredDest( rBookmark.nDestId, aPageRect, nPage, vcl::PDFWriter::DestAreaType::FitRectangle );
+ }
+ else
+ pPDFExtOutDevData->SetLinkURL( rBookmark.nLinkId, rBookmark.aBookmark );
+ }
+ rBookmarks.clear();
+ //---> #i56629, #i40318
+ //get the page name, will be used as outline element in PDF bookmark pane
+ OUString aPageName = mpDoc->GetSdPage( static_cast<sal_uInt16>(nPageNumber) - 1 , PageKind::Standard )->GetName();
+ if( !aPageName.isEmpty() )
+ {
+ // Destination PageNum
+ const sal_Int32 nDestPageNum = CalcOutputPageNum(pPDFExtOutDevData, mpDoc, nPageNumber);
+
+ // insert the bookmark to this page into the NamedDestinations
+ if( pPDFExtOutDevData->GetIsExportNamedDestinations() )
+ pPDFExtOutDevData->CreateNamedDest(aPageName, aPageRect, nDestPageNum);
+
+ // add the name to the outline, (almost) same code as in sc/source/ui/unoobj/docuno.cxx
+ // issue #i40318.
+
+ if( pPDFExtOutDevData->GetIsExportBookmarks() )
+ {
+ // Destination Export
+ const sal_Int32 nDestId =
+ pPDFExtOutDevData->CreateDest(aPageRect , nDestPageNum);
+
+ // Create a new outline item:
+ pPDFExtOutDevData->CreateOutlineItem( -1 , aPageName, nDestId );
+ }
+ }
+ //<--- #i56629, #i40318
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ }
+ }
+ else
+ {
+ uno::Reference< drawing::XShapes > xShapes;
+ rSelection >>= xShapes;
+
+ if( xShapes.is() && xShapes->getCount() )
+ {
+ SdrPageView* pPV = nullptr;
+
+ ImplRenderPaintProc aImplRenderPaintProc( mpDoc->GetLayerAdmin(),
+ pOldSdView ? pOldSdView->GetSdrPageView() : nullptr);
+
+ for( sal_uInt32 i = 0, nCount = xShapes->getCount(); i < nCount; i++ )
+ {
+ uno::Reference< drawing::XShape > xShape;
+ xShapes->getByIndex( i ) >>= xShape;
+
+ if( xShape.is() )
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape( xShape );
+ if( pObj && pObj->getSdrPageFromSdrObject()
+ && aImplRenderPaintProc.IsVisible( pObj )
+ && aImplRenderPaintProc.IsPrintable( pObj ) )
+ {
+ if( !pPV )
+ pPV = aView.ShowSdrPage( pObj->getSdrPageFromSdrObject() );
+
+ if( pPV )
+ aView.MarkObj( pObj, pPV );
+ }
+ }
+ }
+ aView.DrawMarkedObj(*pOut);
+ }
+ }
+}
+
+DrawViewShell* SdXImpressDocument::GetViewShell()
+{
+ DrawViewShell* pViewSh = dynamic_cast<DrawViewShell*>(mpDocShell->GetViewShell());
+ if (!pViewSh)
+ {
+ SAL_WARN("sd", "DrawViewShell not available!");
+ return nullptr;
+ }
+ return pViewSh;
+}
+
+void SdXImpressDocument::paintTile( VirtualDevice& rDevice,
+ int nOutputWidth, int nOutputHeight,
+ int nTilePosX, int nTilePosY,
+ ::tools::Long nTileWidth, ::tools::Long nTileHeight )
+{
+ DrawViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ // Setup drawing layer to work properly. Since we use a custom VirtualDevice
+ // for the drawing, SdrPaintView::BeginCompleteRedraw() will call FindPaintWindow()
+ // unsuccessfully and use a temporary window that doesn't keep state. So patch
+ // the existing SdrPageWindow to use a temporary, and this way the state will be kept.
+ // Well, at least that's how I understand it based on Writer's RenderContextGuard,
+ // as the drawing layer classes lack documentation.
+ SdrPageWindow* patchedPageWindow = nullptr;
+ SdrPaintWindow* previousPaintWindow = nullptr;
+ std::unique_ptr<SdrPaintWindow> temporaryPaintWindow;
+ if(SdrView* pDrawView = pViewSh->GetDrawView())
+ {
+ if(SdrPageView* pSdrPageView = pDrawView->GetSdrPageView())
+ {
+ patchedPageWindow = pSdrPageView->FindPageWindow(*getDocWindow()->GetOutDev());
+ temporaryPaintWindow.reset(new SdrPaintWindow(*pDrawView, rDevice));
+ if (patchedPageWindow)
+ previousPaintWindow = patchedPageWindow->patchPaintWindow(*temporaryPaintWindow);
+ }
+ }
+
+ // Scaling. Must convert from pixels to twips. We know
+ // that VirtualDevices use a DPI of 96.
+ // We specifically calculate these scales first as we're still
+ // in TWIPs, and might as well minimize the number of conversions.
+ const Fraction scale = conversionFract(o3tl::Length::px, o3tl::Length::twip);
+ Fraction scaleX = Fraction(nOutputWidth, nTileWidth) * scale;
+ Fraction scaleY = Fraction(nOutputHeight, nTileHeight) * scale;
+
+ // svx seems to be the only component that works natively in
+ // 100th mm rather than TWIP. It makes most sense just to
+ // convert here and in getDocumentSize, and leave the tiled
+ // rendering API working in TWIPs.
+ ::tools::Long nTileWidthHMM = convertTwipToMm100( nTileWidth );
+ ::tools::Long nTileHeightHMM = convertTwipToMm100( nTileHeight );
+ int nTilePosXHMM = convertTwipToMm100( nTilePosX );
+ int nTilePosYHMM = convertTwipToMm100( nTilePosY );
+
+ MapMode aMapMode = rDevice.GetMapMode();
+ aMapMode.SetMapUnit( MapUnit::Map100thMM );
+ aMapMode.SetOrigin( Point( -nTilePosXHMM,
+ -nTilePosYHMM) );
+ aMapMode.SetScaleX( scaleX );
+ aMapMode.SetScaleY( scaleY );
+
+ rDevice.SetMapMode( aMapMode );
+
+ rDevice.SetOutputSizePixel( Size(nOutputWidth, nOutputHeight) );
+
+ Point aPoint(nTilePosXHMM, nTilePosYHMM);
+ Size aSize(nTileWidthHMM, nTileHeightHMM);
+ ::tools::Rectangle aRect(aPoint, aSize);
+
+ pViewSh->GetView()->CompleteRedraw(&rDevice, vcl::Region(aRect));
+
+ LokChartHelper::PaintAllChartsOnTile(rDevice, nOutputWidth, nOutputHeight,
+ nTilePosX, nTilePosY, nTileWidth, nTileHeight);
+
+ if(patchedPageWindow != nullptr)
+ patchedPageWindow->unpatchPaintWindow(previousPaintWindow);
+}
+
+void SdXImpressDocument::selectPart(int nPart, int nSelect)
+{
+ DrawViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ pViewSh->SelectPage(nPart, nSelect);
+}
+
+void SdXImpressDocument::moveSelectedParts(int nPosition, bool bDuplicate)
+{
+ // Duplicating is currently unsupported.
+ if (!bDuplicate)
+ mpDoc->MovePages(nPosition);
+}
+
+OUString SdXImpressDocument::getPartInfo(int nPart)
+{
+ DrawViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return OUString();
+
+ const bool bIsVisible = pViewSh->IsVisible(nPart);
+ const bool bIsSelected = pViewSh->IsSelected(nPart);
+ const sal_Int16 nMasterPageCount= pViewSh->GetDoc()->GetMasterSdPageCount(pViewSh->GetPageKind());
+
+ OUString aPartInfo = "{ \"visible\": \"" +
+ OUString::number(static_cast<unsigned int>(bIsVisible)) +
+ "\", \"selected\": \"" +
+ OUString::number(static_cast<unsigned int>(bIsSelected)) +
+ "\", \"masterPageCount\": \"" +
+ OUString::number(nMasterPageCount) +
+ "\" }";
+ return aPartInfo;
+}
+
+void SdXImpressDocument::setPart( int nPart, bool bAllowChangeFocus )
+{
+ DrawViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ pViewSh->SwitchPage( nPart, bAllowChangeFocus );
+}
+
+int SdXImpressDocument::getParts()
+{
+ if (!mpDoc)
+ return 0;
+
+ if (isMasterViewMode())
+ return mpDoc->GetMasterSdPageCount(PageKind::Standard);
+
+ return mpDoc->GetSdPageCount(PageKind::Standard);
+}
+
+int SdXImpressDocument::getPart()
+{
+ DrawViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return 0;
+
+ return pViewSh->GetViewShellBase().getPart();
+}
+
+OUString SdXImpressDocument::getPartName(int nPart)
+{
+ SdPage* pPage;
+ if (isMasterViewMode())
+ pPage = mpDoc->GetMasterSdPage(nPart, PageKind::Standard);
+ else
+ pPage = mpDoc->GetSdPage(nPart, PageKind::Standard);
+
+ if (!pPage)
+ {
+ SAL_WARN("sd", "DrawViewShell not available!");
+ return OUString();
+ }
+
+ return pPage->GetName();
+}
+
+OUString SdXImpressDocument::getPartHash(int nPart)
+{
+ SdPage* pPage;
+ if (isMasterViewMode())
+ pPage = mpDoc->GetMasterSdPage(nPart, PageKind::Standard);
+ else
+ pPage = mpDoc->GetSdPage(nPart, PageKind::Standard);
+
+ if (!pPage)
+ {
+ SAL_WARN("sd", "DrawViewShell not available!");
+ return OUString();
+ }
+
+ return OUString::number(pPage->GetHashCode());
+}
+
+bool SdXImpressDocument::isMasterViewMode()
+{
+ DrawViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return false;
+
+ if (pViewSh->GetDispatcher())
+ {
+ const SfxBoolItem* isMasterViewMode = nullptr;
+ pViewSh->GetDispatcher()->QueryState(SID_SLIDE_MASTER_MODE, isMasterViewMode);
+ if (isMasterViewMode && isMasterViewMode->GetValue())
+ return true;
+ }
+ return false;
+}
+
+VclPtr<vcl::Window> SdXImpressDocument::getDocWindow()
+{
+ SolarMutexGuard aGuard;
+ DrawViewShell* pViewShell = GetViewShell();
+ VclPtr<vcl::Window> pWindow;
+ if (pViewShell)
+ pWindow = pViewShell->GetActiveWindow();
+
+ LokChartHelper aChartHelper(pViewShell->GetViewShell());
+ VclPtr<vcl::Window> pChartWindow = aChartHelper.GetWindow();
+ if (pChartWindow)
+ pWindow = pChartWindow;
+
+ return pWindow;
+}
+
+void SdXImpressDocument::setPartMode( int nPartMode )
+{
+ DrawViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ PageKind aPageKind( PageKind::Standard );
+ switch ( nPartMode )
+ {
+ case LOK_PARTMODE_SLIDES:
+ break;
+ case LOK_PARTMODE_NOTES:
+ aPageKind = PageKind::Notes;
+ break;
+ }
+ pViewSh->SetPageKind( aPageKind );
+}
+
+Size SdXImpressDocument::getDocumentSize()
+{
+ DrawViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return Size();
+
+ SdrView *pSdrView = pViewSh->GetView();
+ if (!pSdrView)
+ return Size();
+
+ SdrPageView* pCurPageView = pSdrView->GetSdrPageView();
+ if (!pCurPageView)
+ return Size();
+
+ Size aSize = pCurPageView->GetPageRect().GetSize();
+ // Convert the size in 100th mm to TWIP
+ // See paintTile above for further info.
+ return o3tl::convert(aSize, o3tl::Length::mm100, o3tl::Length::twip);
+}
+
+void SdXImpressDocument::getPostIts(::tools::JsonWriter& rJsonWriter)
+{
+ auto commentsNode = rJsonWriter.startNode("comments");
+ // Return annotations on master pages too ?
+ const sal_uInt16 nMaxPages = mpDoc->GetPageCount();
+ SdPage* pPage;
+ for (sal_uInt16 nPage = 0; nPage < nMaxPages; ++nPage)
+ {
+ pPage = static_cast<SdPage*>(mpDoc->GetPage(nPage));
+ const sd::AnnotationVector& aPageAnnotations = pPage->getAnnotations();
+
+ for (const uno::Reference<office::XAnnotation>& xAnnotation : aPageAnnotations)
+ {
+ sal_uInt32 nID = sd::getAnnotationId(xAnnotation);
+ OString nodeName = "comment" + OString::number(nID);
+ auto commentNode = rJsonWriter.startNode(nodeName.getStr());
+ rJsonWriter.put("id", nID);
+ rJsonWriter.put("author", xAnnotation->getAuthor());
+ rJsonWriter.put("dateTime", utl::toISO8601(xAnnotation->getDateTime()));
+ uno::Reference<text::XText> xText(xAnnotation->getTextRange());
+ rJsonWriter.put("text", xText->getString());
+ rJsonWriter.put("parthash", pPage->GetHashCode());
+ geometry::RealPoint2D const & rPoint = xAnnotation->getPosition();
+ geometry::RealSize2D const & rSize = xAnnotation->getSize();
+ ::tools::Rectangle aRectangle(Point(rPoint.X * 100.0, rPoint.Y * 100.0), Size(rSize.Width * 100.0, rSize.Height * 100.0));
+ aRectangle = o3tl::toTwips(aRectangle, o3tl::Length::mm100);
+ OString sRectangle = aRectangle.toString();
+ rJsonWriter.put("rectangle", sRectangle.getStr());
+ }
+ }
+}
+
+void SdXImpressDocument::initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments)
+{
+ SolarMutexGuard aGuard;
+
+ if (DrawViewShell* pViewShell = GetViewShell())
+ {
+ DrawView* pDrawView = pViewShell->GetDrawView();
+ for (const beans::PropertyValue& rValue : rArguments)
+ {
+ if (rValue.Name == ".uno:ShowBorderShadow" && rValue.Value.has<bool>())
+ pDrawView->SetPageShadowVisible(rValue.Value.get<bool>());
+ else if (rValue.Name == ".uno:Author" && rValue.Value.has<OUString>())
+ pDrawView->SetAuthor(rValue.Value.get<OUString>());
+ else if (rValue.Name == ".uno:SpellOnline" && rValue.Value.has<bool>())
+ mpDoc->SetOnlineSpell(rValue.Value.get<bool>());
+ }
+
+ // Disable comments if requested
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(mpDoc->GetDocumentType());
+ pOptions->SetShowComments(comphelper::LibreOfficeKit::isTiledAnnotations());
+
+ pViewShell->SetRuler(false);
+ pViewShell->SetScrollBarsVisible(false);
+
+ if (sd::Window* pWindow = pViewShell->GetActiveWindow())
+ {
+ // get the full page size in pixels
+ pWindow->EnableMapMode();
+ Size aSize(pWindow->LogicToPixel(pDrawView->GetSdrPageView()->GetPage()->GetSize()));
+ // Disable map mode, so that it's possible to send mouse event
+ // coordinates in logic units
+ pWindow->EnableMapMode(false);
+
+ // arrange UI elements again with new view size
+ pViewShell->GetParentWindow()->SetSizePixel(aSize);
+ pViewShell->Resize();
+ }
+
+ // Forces all images to be swapped in synchronously, this
+ // ensures that images are available when paintTile is called
+ // (whereas with async loading images start being loaded after
+ // we have painted the tile, resulting in an invalidate, followed
+ // by the tile being rerendered - which is wasteful and ugly).
+ pDrawView->SetSwapAsynchron(false);
+ }
+
+ // when the "This document may contain formatting or content that cannot
+ // be saved..." dialog appears, it is auto-cancelled with tiled rendering,
+ // causing 'Save' being disabled; so let's always save to the original
+ // format
+ auto xChanges = comphelper::ConfigurationChanges::create();
+ officecfg::Office::Common::Save::Document::WarnAlienFormat::set(false, xChanges);
+ xChanges->commit();
+
+ if (!getenv("LO_TESTNAME"))
+ SvtSlideSorterBarOptions().SetVisibleImpressView(true);
+}
+
+void SdXImpressDocument::postKeyEvent(int nType, int nCharCode, int nKeyCode)
+{
+ SolarMutexGuard aGuard;
+ SfxLokHelper::postKeyEventAsync(getDocWindow(), nType, nCharCode, nKeyCode);
+}
+
+void SdXImpressDocument::postMouseEvent(int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
+{
+ SolarMutexGuard aGuard;
+
+ DrawViewShell* pViewShell = GetViewShell();
+ if (!pViewShell)
+ return;
+
+ constexpr double fScale = o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::px);
+
+ // check if user hit a chart which is being edited by him
+ LokChartHelper aChartHelper(pViewShell->GetViewShell());
+ if (aChartHelper.postMouseEvent(nType, nX, nY,
+ nCount, nButtons, nModifier,
+ fScale, fScale))
+ return;
+
+ // check if the user hit a chart which is being edited by someone else
+ // and, if so, skip current mouse event
+ if (nType != LOK_MOUSEEVENT_MOUSEMOVE)
+ {
+ if (LokChartHelper::HitAny(Point(nX, nY)))
+ return;
+ }
+
+ const Point aPos(Point(convertTwipToMm100(nX), convertTwipToMm100(nY)));
+ LokMouseEventData aMouseEventData(nType, aPos, nCount, MouseEventModifiers::SIMPLECLICK,
+ nButtons, nModifier);
+ SfxLokHelper::postMouseEventAsync(pViewShell->GetActiveWindow(), aMouseEventData);
+}
+
+void SdXImpressDocument::setTextSelection(int nType, int nX, int nY)
+{
+ SolarMutexGuard aGuard;
+
+ DrawViewShell* pViewShell = GetViewShell();
+ if (!pViewShell)
+ return;
+
+ LokChartHelper aChartHelper(pViewShell->GetViewShell());
+ if (aChartHelper.setTextSelection(nType, nX, nY))
+ return;
+
+ Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
+ switch (nType)
+ {
+ case LOK_SETTEXTSELECTION_START:
+ pViewShell->SetCursorMm100Position(aPoint, /*bPoint=*/false, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_END:
+ pViewShell->SetCursorMm100Position(aPoint, /*bPoint=*/true, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_RESET:
+ pViewShell->SetCursorMm100Position(aPoint, /*bPoint=*/true, /*bClearMark=*/true);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+uno::Reference<datatransfer::XTransferable> SdXImpressDocument::getSelection()
+{
+ SolarMutexGuard aGuard;
+
+ DrawViewShell* pViewShell = GetViewShell();
+ if (!pViewShell)
+ return uno::Reference<datatransfer::XTransferable>();
+
+ return pViewShell->GetSelectionTransferrable();
+}
+
+void SdXImpressDocument::setGraphicSelection(int nType, int nX, int nY)
+{
+ SolarMutexGuard aGuard;
+
+ DrawViewShell* pViewShell = GetViewShell();
+ if (!pViewShell)
+ return;
+
+ constexpr double fScale = o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::px);
+
+ LokChartHelper aChartHelper(pViewShell->GetViewShell());
+ if (aChartHelper.setGraphicSelection(nType, nX, nY, fScale, fScale))
+ return;
+
+ Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
+ switch (nType)
+ {
+ case LOK_SETGRAPHICSELECTION_START:
+ pViewShell->SetGraphicMm100Position(/*bStart=*/true, aPoint);
+ break;
+ case LOK_SETGRAPHICSELECTION_END:
+ pViewShell->SetGraphicMm100Position(/*bStart=*/false, aPoint);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+void SdXImpressDocument::resetSelection()
+{
+ SolarMutexGuard aGuard;
+
+ DrawViewShell* pViewShell = GetViewShell();
+ if (!pViewShell)
+ return;
+
+ SdrView* pSdrView = pViewShell->GetView();
+ if (!pSdrView)
+ return;
+
+ if (pSdrView->IsTextEdit())
+ {
+ // Reset the editeng selection.
+ pSdrView->UnmarkAll();
+ // Finish editing.
+ pSdrView->SdrEndTextEdit();
+ }
+ // Reset graphic selection.
+ pSdrView->UnmarkAll();
+}
+
+void SdXImpressDocument::setClientVisibleArea(const ::tools::Rectangle& rRectangle)
+{
+ SolarMutexGuard aGuard;
+
+ DrawViewShell* pViewShell = GetViewShell();
+ if (!pViewShell)
+ return;
+
+ pViewShell->GetViewShellBase().setLOKVisibleArea(rRectangle);
+}
+
+void SdXImpressDocument::setClipboard(const uno::Reference<datatransfer::clipboard::XClipboard>& xClipboard)
+{
+ SolarMutexGuard aGuard;
+
+ DrawViewShell* pViewShell = GetViewShell();
+ if (!pViewShell)
+ return;
+
+ pViewShell->GetActiveWindow()->SetClipboard(xClipboard);
+}
+
+bool SdXImpressDocument::isMimeTypeSupported()
+{
+ SolarMutexGuard aGuard;
+ DrawViewShell* pViewShell = GetViewShell();
+ if (!pViewShell)
+ return false;
+
+ TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromSystemClipboard(pViewShell->GetActiveWindow()));
+ return EditEngine::HasValidData(aDataHelper.GetTransferable());
+}
+
+PointerStyle SdXImpressDocument::getPointer()
+{
+ SolarMutexGuard aGuard;
+ DrawViewShell* pViewShell = GetViewShell();
+ if (!pViewShell)
+ return PointerStyle::Arrow;
+
+ Window* pWindow = pViewShell->GetActiveWindow();
+ if (!pWindow)
+ return PointerStyle::Arrow;
+
+ return pWindow->GetPointer();
+}
+
+uno::Reference< i18n::XForbiddenCharacters > SdXImpressDocument::getForbiddenCharsTable()
+{
+ uno::Reference< i18n::XForbiddenCharacters > xForb(mxForbiddenCharacters);
+
+ if( !xForb.is() )
+ mxForbiddenCharacters = xForb = new SdUnoForbiddenCharsTable( mpDoc );
+
+ return xForb;
+}
+
+void SdXImpressDocument::initializeDocument()
+{
+ if( mbClipBoard )
+ return;
+
+ switch( mpDoc->GetPageCount() )
+ {
+ case 1:
+ {
+ // nasty hack to detect clipboard document
+ mbClipBoard = true;
+ break;
+ }
+ case 0:
+ {
+ mpDoc->CreateFirstPages();
+ mpDoc->StopWorkStartupDelay();
+ break;
+ }
+ }
+}
+
+SdrModel& SdXImpressDocument::getSdrModelFromUnoModel() const
+{
+ OSL_ENSURE(GetDoc(), "No SdrModel in draw/Impress, should not happen");
+ return *GetDoc(); // TTTT should be reference
+}
+
+void SAL_CALL SdXImpressDocument::dispose()
+{
+ if( mbDisposed )
+ return;
+
+ ::SolarMutexGuard aGuard;
+
+ if( mpDoc )
+ {
+ EndListening( *mpDoc );
+ mpDoc = nullptr;
+ }
+
+ // Call the base class dispose() before setting the mbDisposed flag
+ // to true. The reason for this is that if close() has not yet been
+ // called this is done in SfxBaseModel::dispose(). At the end of
+ // that dispose() is called again. It is important to forward this
+ // second dispose() to the base class, too.
+ // As a consequence the following code has to be able to be run twice.
+ SfxBaseModel::dispose();
+ mbDisposed = true;
+
+ uno::Reference< container::XNameAccess > xLinks( mxLinks );
+ if( xLinks.is() )
+ {
+ uno::Reference< lang::XComponent > xComp( xLinks, uno::UNO_QUERY );
+ if( xComp.is() )
+ xComp->dispose();
+
+ xLinks = nullptr;
+ }
+
+ uno::Reference< drawing::XDrawPages > xDrawPagesAccess( mxDrawPagesAccess );
+ if( xDrawPagesAccess.is() )
+ {
+ uno::Reference< lang::XComponent > xComp( xDrawPagesAccess, uno::UNO_QUERY );
+ if( xComp.is() )
+ xComp->dispose();
+
+ xDrawPagesAccess = nullptr;
+ }
+
+ uno::Reference< drawing::XDrawPages > xMasterPagesAccess( mxMasterPagesAccess );
+ if( xDrawPagesAccess.is() )
+ {
+ uno::Reference< lang::XComponent > xComp( xMasterPagesAccess, uno::UNO_QUERY );
+ if( xComp.is() )
+ xComp->dispose();
+
+ xDrawPagesAccess = nullptr;
+ }
+
+ uno::Reference< container::XNameAccess > xLayerManager( mxLayerManager );
+ if( xLayerManager.is() )
+ {
+ uno::Reference< lang::XComponent > xComp( xLayerManager, uno::UNO_QUERY );
+ if( xComp.is() )
+ xComp->dispose();
+
+ xLayerManager = nullptr;
+ }
+
+ uno::Reference< container::XNameContainer > xCustomPresentationAccess( mxCustomPresentationAccess );
+ if( xCustomPresentationAccess.is() )
+ {
+ uno::Reference< lang::XComponent > xComp( xCustomPresentationAccess, uno::UNO_QUERY );
+ if( xComp.is() )
+ xComp->dispose();
+
+ xCustomPresentationAccess = nullptr;
+ }
+
+ mxDashTable = nullptr;
+ mxGradientTable = nullptr;
+ mxHatchTable = nullptr;
+ mxBitmapTable = nullptr;
+ mxTransGradientTable = nullptr;
+ mxMarkerTable = nullptr;
+ mxDrawingPool = nullptr;
+}
+
+
+SdDrawPagesAccess::SdDrawPagesAccess( SdXImpressDocument& rMyModel ) noexcept
+: mpModel( &rMyModel)
+{
+}
+
+SdDrawPagesAccess::~SdDrawPagesAccess() noexcept
+{
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SdDrawPagesAccess::getCount()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ return mpModel->mpDoc->GetSdPageCount( PageKind::Standard );
+}
+
+uno::Any SAL_CALL SdDrawPagesAccess::getByIndex( sal_Int32 Index )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ uno::Any aAny;
+
+ if( (Index < 0) || (Index >= mpModel->mpDoc->GetSdPageCount( PageKind::Standard ) ) )
+ throw lang::IndexOutOfBoundsException();
+
+ SdPage* pPage = mpModel->mpDoc->GetSdPage( static_cast<sal_uInt16>(Index), PageKind::Standard );
+ if( pPage )
+ {
+ uno::Reference< drawing::XDrawPage > xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
+ aAny <<= xDrawPage;
+ }
+
+ return aAny;
+}
+
+// XNameAccess
+uno::Any SAL_CALL SdDrawPagesAccess::getByName( const OUString& aName )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ if( !aName.isEmpty() )
+ {
+ const sal_uInt16 nCount = mpModel->mpDoc->GetSdPageCount( PageKind::Standard );
+ sal_uInt16 nPage;
+ for( nPage = 0; nPage < nCount; nPage++ )
+ {
+ SdPage* pPage = mpModel->mpDoc->GetSdPage( nPage, PageKind::Standard );
+ if(nullptr == pPage)
+ continue;
+
+ if( aName == SdDrawPage::getPageApiName( pPage ) )
+ {
+ uno::Any aAny;
+ uno::Reference< drawing::XDrawPage > xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
+ aAny <<= xDrawPage;
+ return aAny;
+ }
+ }
+ }
+
+ throw container::NoSuchElementException();
+}
+
+uno::Sequence< OUString > SAL_CALL SdDrawPagesAccess::getElementNames()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ const sal_uInt16 nCount = mpModel->mpDoc->GetSdPageCount( PageKind::Standard );
+ uno::Sequence< OUString > aNames( nCount );
+ OUString* pNames = aNames.getArray();
+
+ sal_uInt16 nPage;
+ for( nPage = 0; nPage < nCount; nPage++ )
+ {
+ SdPage* pPage = mpModel->mpDoc->GetSdPage( nPage, PageKind::Standard );
+ *pNames++ = SdDrawPage::getPageApiName( pPage );
+ }
+
+ return aNames;
+}
+
+sal_Bool SAL_CALL SdDrawPagesAccess::hasByName( const OUString& aName )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ const sal_uInt16 nCount = mpModel->mpDoc->GetSdPageCount( PageKind::Standard );
+ sal_uInt16 nPage;
+ for( nPage = 0; nPage < nCount; nPage++ )
+ {
+ SdPage* pPage = mpModel->mpDoc->GetSdPage( nPage, PageKind::Standard );
+ if(nullptr == pPage)
+ continue;
+
+ if( aName == SdDrawPage::getPageApiName( pPage ) )
+ return true;
+ }
+
+ return false;
+}
+
+// XElementAccess
+uno::Type SAL_CALL SdDrawPagesAccess::getElementType()
+{
+ return cppu::UnoType<drawing::XDrawPage>::get();
+}
+
+sal_Bool SAL_CALL SdDrawPagesAccess::hasElements()
+{
+ return getCount() > 0;
+}
+
+// XDrawPages
+
+/**
+ * Creates a new page with model at the specified position.
+ * @returns corresponding SdDrawPage
+ */
+uno::Reference< drawing::XDrawPage > SAL_CALL SdDrawPagesAccess::insertNewByIndex( sal_Int32 nIndex )
+{
+ ::SolarMutexGuard aGuard;
+ comphelper::ProfileZone aZone("insertNewByIndex");
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ if( mpModel->mpDoc )
+ {
+ SdPage* pPage = mpModel->InsertSdPage( static_cast<sal_uInt16>(nIndex), false );
+ if( pPage )
+ {
+ uno::Reference< drawing::XDrawPage > xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
+ return xDrawPage;
+ }
+ }
+ uno::Reference< drawing::XDrawPage > xDrawPage;
+ return xDrawPage;
+}
+
+/**
+ * Removes the specified SdDrawPage from the model and the internal list. It
+ * only works, if there is at least one *normal* page in the model after
+ * removing this page.
+ */
+void SAL_CALL SdDrawPagesAccess::remove( const uno::Reference< drawing::XDrawPage >& xPage )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel || mpModel->mpDoc == nullptr )
+ throw lang::DisposedException();
+
+ SdDrawDocument& rDoc = *mpModel->mpDoc;
+
+ sal_uInt16 nPageCount = rDoc.GetSdPageCount( PageKind::Standard );
+ if( nPageCount > 1 )
+ {
+ // get pPage from xPage and determine the Id (nPos ) afterwards
+ SdDrawPage* pSvxPage = comphelper::getFromUnoTunnel<SdDrawPage>( xPage );
+ if( pSvxPage )
+ {
+ SdPage* pPage = static_cast<SdPage*>(pSvxPage->GetSdrPage());
+ if(pPage && ( pPage->GetPageKind() == PageKind::Standard ) )
+ {
+ sal_uInt16 nPage = pPage->GetPageNum();
+
+ SdPage* pNotesPage = static_cast< SdPage* >( rDoc.GetPage( nPage+1 ) );
+
+ bool bUndo = rDoc.IsUndoEnabled();
+ if( bUndo )
+ {
+ // Add undo actions and delete the pages. The order of adding
+ // the undo actions is important.
+ rDoc.BegUndo( SdResId( STR_UNDO_DELETEPAGES ) );
+ rDoc.AddUndo(rDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pNotesPage));
+ rDoc.AddUndo(rDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
+ }
+
+ rDoc.RemovePage( nPage ); // the page
+ rDoc.RemovePage( nPage ); // the notes page
+
+ if( bUndo )
+ {
+ rDoc.EndUndo();
+ }
+ }
+ }
+ }
+
+ mpModel->SetModified();
+}
+
+// XServiceInfo
+
+OUString SAL_CALL SdDrawPagesAccess::getImplementationName( )
+{
+ return "SdDrawPagesAccess";
+}
+
+sal_Bool SAL_CALL SdDrawPagesAccess::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL SdDrawPagesAccess::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.DrawPages" };
+}
+
+// XComponent
+void SAL_CALL SdDrawPagesAccess::dispose( )
+{
+ mpModel = nullptr;
+}
+
+void SAL_CALL SdDrawPagesAccess::addEventListener( const uno::Reference< lang::XEventListener >& )
+{
+ OSL_FAIL( "not implemented!" );
+}
+
+void SAL_CALL SdDrawPagesAccess::removeEventListener( const uno::Reference< lang::XEventListener >& )
+{
+ OSL_FAIL( "not implemented!" );
+}
+
+
+SdMasterPagesAccess::SdMasterPagesAccess( SdXImpressDocument& rMyModel ) noexcept
+: mpModel(&rMyModel)
+{
+}
+
+SdMasterPagesAccess::~SdMasterPagesAccess() noexcept
+{
+}
+
+// XComponent
+void SAL_CALL SdMasterPagesAccess::dispose( )
+{
+ mpModel = nullptr;
+}
+
+void SAL_CALL SdMasterPagesAccess::addEventListener( const uno::Reference< lang::XEventListener >& )
+{
+ OSL_FAIL( "not implemented!" );
+}
+
+void SAL_CALL SdMasterPagesAccess::removeEventListener( const uno::Reference< lang::XEventListener >& )
+{
+ OSL_FAIL( "not implemented!" );
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SdMasterPagesAccess::getCount()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel->mpDoc )
+ throw lang::DisposedException();
+
+ return mpModel->mpDoc->GetMasterSdPageCount(PageKind::Standard);
+}
+
+/**
+ * Provides a drawing::XDrawPage interface for accessing the Masterpage at the
+ * specified position in the model.
+ */
+uno::Any SAL_CALL SdMasterPagesAccess::getByIndex( sal_Int32 Index )
+{
+ ::SolarMutexGuard aGuard;
+ comphelper::ProfileZone aZone("SdMasterPagesAccess::getByIndex");
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ uno::Any aAny;
+
+ if( (Index < 0) || (Index >= mpModel->mpDoc->GetMasterSdPageCount( PageKind::Standard ) ) )
+ throw lang::IndexOutOfBoundsException();
+
+ SdPage* pPage = mpModel->mpDoc->GetMasterSdPage( static_cast<sal_uInt16>(Index), PageKind::Standard );
+ if( pPage )
+ {
+ uno::Reference< drawing::XDrawPage > xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
+ aAny <<= xDrawPage;
+ }
+
+ return aAny;
+}
+
+// XElementAccess
+uno::Type SAL_CALL SdMasterPagesAccess::getElementType()
+{
+ return cppu::UnoType<drawing::XDrawPage>::get();
+}
+
+sal_Bool SAL_CALL SdMasterPagesAccess::hasElements()
+{
+ return getCount() > 0;
+}
+
+// XDrawPages
+uno::Reference< drawing::XDrawPage > SAL_CALL SdMasterPagesAccess::insertNewByIndex( sal_Int32 nInsertPos )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ uno::Reference< drawing::XDrawPage > xDrawPage;
+
+ SdDrawDocument* pDoc = mpModel->mpDoc;
+ if( pDoc )
+ {
+ // calculate internal index and check for range errors
+ const sal_Int32 nMPageCount = pDoc->GetMasterPageCount();
+ nInsertPos = nInsertPos * 2 + 1;
+ if( nInsertPos < 0 || nInsertPos > nMPageCount )
+ nInsertPos = nMPageCount;
+
+ // now generate a unique name for the new masterpage
+ const OUString aStdPrefix( SdResId(STR_LAYOUT_DEFAULT_NAME) );
+ OUString aPrefix( aStdPrefix );
+
+ bool bUnique = true;
+
+ std::vector<OUString> aPageNames;
+ for (sal_Int32 nMaster = 1; nMaster < nMPageCount; ++nMaster)
+ {
+ const SdPage* pPage = static_cast<const SdPage*>(pDoc->GetMasterPage(static_cast<sal_uInt16>(nMaster)));
+ if (!pPage)
+ continue;
+ aPageNames.push_back(pPage->GetName());
+ if (aPageNames.back() == aPrefix)
+ bUnique = false;
+ }
+
+ sal_Int32 i = 0;
+ while (!bUnique)
+ {
+ aPrefix = aStdPrefix + " " + OUString::number(++i);
+ bUnique = std::find(aPageNames.begin(), aPageNames.end(), aPrefix) == aPageNames.end();
+ }
+
+ OUString aLayoutName = aPrefix + SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE;
+
+ // create styles
+ static_cast<SdStyleSheetPool*>(pDoc->GetStyleSheetPool())->CreateLayoutStyleSheets( aPrefix );
+
+ // get the first page for initial size and border settings
+ SdPage* pPage = mpModel->mpDoc->GetSdPage( sal_uInt16(0), PageKind::Standard );
+ SdPage* pRefNotesPage = mpModel->mpDoc->GetSdPage( sal_uInt16(0), PageKind::Notes);
+
+ // create and insert new draw masterpage
+ rtl::Reference<SdPage> pMPage = mpModel->mpDoc->AllocSdPage(true);
+ pMPage->SetSize( pPage->GetSize() );
+ pMPage->SetBorder( pPage->GetLeftBorder(),
+ pPage->GetUpperBorder(),
+ pPage->GetRightBorder(),
+ pPage->GetLowerBorder() );
+ pMPage->SetLayoutName( aLayoutName );
+ pDoc->InsertMasterPage(pMPage.get(), static_cast<sal_uInt16>(nInsertPos));
+
+ {
+ // ensure default MasterPage fill
+ pMPage->EnsureMasterPageDefaultBackground();
+ }
+
+ xDrawPage.set( pMPage->getUnoPage(), uno::UNO_QUERY );
+
+ // create and insert new notes masterpage
+ rtl::Reference<SdPage> pMNotesPage = mpModel->mpDoc->AllocSdPage(true);
+ pMNotesPage->SetSize( pRefNotesPage->GetSize() );
+ pMNotesPage->SetPageKind(PageKind::Notes);
+ pMNotesPage->SetBorder( pRefNotesPage->GetLeftBorder(),
+ pRefNotesPage->GetUpperBorder(),
+ pRefNotesPage->GetRightBorder(),
+ pRefNotesPage->GetLowerBorder() );
+ pMNotesPage->SetLayoutName( aLayoutName );
+ pDoc->InsertMasterPage(pMNotesPage.get(), static_cast<sal_uInt16>(nInsertPos) + 1);
+ pMNotesPage->SetAutoLayout(AUTOLAYOUT_NOTES, true, true);
+ mpModel->SetModified();
+ }
+
+ return xDrawPage;
+}
+
+/**
+ * Removes the specified SdMasterPage from the model and the internal list. It
+ * only works, if there is no *normal* page using this page as MasterPage in
+ * the model.
+ */
+void SAL_CALL SdMasterPagesAccess::remove( const uno::Reference< drawing::XDrawPage >& xPage )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel || mpModel->mpDoc == nullptr )
+ throw lang::DisposedException();
+
+ SdMasterPage* pSdPage = comphelper::getFromUnoTunnel<SdMasterPage>( xPage );
+ if(pSdPage == nullptr)
+ return;
+
+ SdPage* pPage = dynamic_cast< SdPage* > (pSdPage->GetSdrPage());
+
+ DBG_ASSERT( pPage && pPage->IsMasterPage(), "SdMasterPage is not masterpage?");
+
+ if( !pPage || !pPage->IsMasterPage() || (mpModel->mpDoc->GetMasterPageUserCount(pPage) > 0))
+ return; //Todo: this should be excepted
+
+ // only standard pages can be removed directly
+ if( pPage->GetPageKind() != PageKind::Standard )
+ return;
+
+ sal_uInt16 nPage = pPage->GetPageNum();
+
+ SdDrawDocument& rDoc = *mpModel->mpDoc;
+
+ SdPage* pNotesPage = static_cast< SdPage* >( rDoc.GetMasterPage( nPage+1 ) );
+
+ bool bUndo = rDoc.IsUndoEnabled();
+ if( bUndo )
+ {
+ // Add undo actions and delete the pages. The order of adding
+ // the undo actions is important.
+ rDoc.BegUndo( SdResId( STR_UNDO_DELETEPAGES ) );
+ rDoc.AddUndo(rDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pNotesPage));
+ rDoc.AddUndo(rDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
+ }
+
+ // remove both pages
+ rDoc.RemoveMasterPage( nPage );
+ rDoc.RemoveMasterPage( nPage );
+
+ if( bUndo )
+ {
+ rDoc.EndUndo();
+ }
+}
+
+// XServiceInfo
+
+OUString SAL_CALL SdMasterPagesAccess::getImplementationName( )
+{
+ return "SdMasterPagesAccess";
+}
+
+sal_Bool SAL_CALL SdMasterPagesAccess::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL SdMasterPagesAccess::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.MasterPages" };
+}
+
+
+SdDocLinkTargets::SdDocLinkTargets( SdXImpressDocument& rMyModel ) noexcept
+: mpModel( &rMyModel )
+{
+}
+
+SdDocLinkTargets::~SdDocLinkTargets() noexcept
+{
+}
+
+// XComponent
+void SAL_CALL SdDocLinkTargets::dispose( )
+{
+ mpModel = nullptr;
+}
+
+void SAL_CALL SdDocLinkTargets::addEventListener( const uno::Reference< lang::XEventListener >& )
+{
+ OSL_FAIL( "not implemented!" );
+}
+
+void SAL_CALL SdDocLinkTargets::removeEventListener( const uno::Reference< lang::XEventListener >& )
+{
+ OSL_FAIL( "not implemented!" );
+}
+
+// XNameAccess
+uno::Any SAL_CALL SdDocLinkTargets::getByName( const OUString& aName )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ SdPage* pPage = FindPage( aName );
+
+ if( pPage == nullptr )
+ throw container::NoSuchElementException();
+
+ uno::Any aAny;
+
+ uno::Reference< beans::XPropertySet > xProps( pPage->getUnoPage(), uno::UNO_QUERY );
+ if( xProps.is() )
+ aAny <<= xProps;
+
+ return aAny;
+}
+
+uno::Sequence< OUString > SAL_CALL SdDocLinkTargets::getElementNames()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ SdDrawDocument* pDoc = mpModel->GetDoc();
+ if( pDoc == nullptr )
+ {
+ return { };
+ }
+
+ if( pDoc->GetDocumentType() == DocumentType::Draw )
+ {
+ const sal_uInt16 nMaxPages = pDoc->GetSdPageCount( PageKind::Standard );
+ const sal_uInt16 nMaxMasterPages = pDoc->GetMasterSdPageCount( PageKind::Standard );
+
+ uno::Sequence< OUString > aSeq( nMaxPages + nMaxMasterPages );
+ OUString* pStr = aSeq.getArray();
+
+ sal_uInt16 nPage;
+ // standard pages
+ for( nPage = 0; nPage < nMaxPages; nPage++ )
+ *pStr++ = pDoc->GetSdPage( nPage, PageKind::Standard )->GetName();
+
+ // master pages
+ for( nPage = 0; nPage < nMaxMasterPages; nPage++ )
+ *pStr++ = pDoc->GetMasterSdPage( nPage, PageKind::Standard )->GetName();
+ return aSeq;
+ }
+ else
+ {
+ const sal_uInt16 nMaxPages = pDoc->GetPageCount();
+ const sal_uInt16 nMaxMasterPages = pDoc->GetMasterPageCount();
+
+ uno::Sequence< OUString > aSeq( nMaxPages + nMaxMasterPages );
+ OUString* pStr = aSeq.getArray();
+
+ sal_uInt16 nPage;
+ // standard pages
+ for( nPage = 0; nPage < nMaxPages; nPage++ )
+ *pStr++ = static_cast<SdPage*>(pDoc->GetPage( nPage ))->GetName();
+
+ // master pages
+ for( nPage = 0; nPage < nMaxMasterPages; nPage++ )
+ *pStr++ = static_cast<SdPage*>(pDoc->GetMasterPage( nPage ))->GetName();
+ return aSeq;
+ }
+}
+
+sal_Bool SAL_CALL SdDocLinkTargets::hasByName( const OUString& aName )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ return FindPage( aName ) != nullptr;
+}
+
+// container::XElementAccess
+uno::Type SAL_CALL SdDocLinkTargets::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL SdDocLinkTargets::hasElements()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpModel )
+ throw lang::DisposedException();
+
+ return mpModel->GetDoc() != nullptr;
+}
+
+SdPage* SdDocLinkTargets::FindPage( std::u16string_view rName ) const
+{
+ SdDrawDocument* pDoc = mpModel->GetDoc();
+ if( pDoc == nullptr )
+ return nullptr;
+
+ const sal_uInt16 nMaxPages = pDoc->GetPageCount();
+ const sal_uInt16 nMaxMasterPages = pDoc->GetMasterPageCount();
+
+ sal_uInt16 nPage;
+ SdPage* pPage;
+
+ const bool bDraw = pDoc->GetDocumentType() == DocumentType::Draw;
+
+ // standard pages
+ for( nPage = 0; nPage < nMaxPages; nPage++ )
+ {
+ pPage = static_cast<SdPage*>(pDoc->GetPage( nPage ));
+ if( (pPage->GetName() == rName) && (!bDraw || (pPage->GetPageKind() == PageKind::Standard)) )
+ return pPage;
+ }
+
+ // master pages
+ for( nPage = 0; nPage < nMaxMasterPages; nPage++ )
+ {
+ pPage = static_cast<SdPage*>(pDoc->GetMasterPage( nPage ));
+ if( (pPage->GetName() == rName) && (!bDraw || (pPage->GetPageKind() == PageKind::Standard)) )
+ return pPage;
+ }
+
+ return nullptr;
+}
+
+// XServiceInfo
+OUString SAL_CALL SdDocLinkTargets::getImplementationName()
+{
+ return "SdDocLinkTargets";
+}
+
+sal_Bool SAL_CALL SdDocLinkTargets::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL SdDocLinkTargets::getSupportedServiceNames()
+{
+ return { "com.sun.star.document.LinkTargets" };
+}
+
+rtl::Reference< SdXImpressDocument > SdXImpressDocument::GetModel( SdDrawDocument const & rDocument )
+{
+ rtl::Reference< SdXImpressDocument > xRet;
+ ::sd::DrawDocShell* pDocShell(rDocument.GetDocSh());
+ if( pDocShell )
+ {
+ uno::Reference<frame::XModel> xModel(pDocShell->GetModel());
+
+ xRet.set( dynamic_cast< SdXImpressDocument* >( xModel.get() ) );
+ }
+
+ return xRet;
+}
+
+void NotifyDocumentEvent( SdDrawDocument const & rDocument, const OUString& rEventName )
+{
+ rtl::Reference< SdXImpressDocument > xModel( SdXImpressDocument::GetModel( rDocument ) );
+
+ if( xModel.is() )
+ {
+ uno::Reference< uno::XInterface > xSource( static_cast<uno::XWeak*>( xModel.get() ) );
+ css::document::EventObject aEvent( xSource, rEventName );
+ xModel->notifyEvent(aEvent );
+ }
+}
+
+void NotifyDocumentEvent( SdDrawDocument const & rDocument, const OUString& rEventName, const uno::Reference< uno::XInterface >& xSource )
+{
+ rtl::Reference< SdXImpressDocument > xModel( SdXImpressDocument::GetModel( rDocument ) );
+
+ if( xModel.is() )
+ {
+ css::document::EventObject aEvent( xSource, rEventName );
+ xModel->notifyEvent(aEvent );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unomodule.cxx b/sd/source/ui/unoidl/unomodule.cxx
new file mode 100644
index 000000000..d862f7c9d
--- /dev/null
+++ b/sd/source/ui/unoidl/unomodule.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/frame/DispatchResultState.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <sddll.hxx>
+#include <sdmod.hxx>
+#include "unomodule.hxx"
+#include <sfx2/objface.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+
+ // XNotifyingDispatch
+void SAL_CALL SdUnoModule::dispatchWithNotification( const util::URL& aURL, const uno::Sequence< beans::PropertyValue >& aArgs, const uno::Reference< frame::XDispatchResultListener >& xListener )
+{
+ // there is no guarantee, that we are holded alive during this method!
+ // May the outside dispatch container will be updated by a CONTEXT_CHANGED
+ // asynchronous ...
+ uno::Reference< uno::XInterface > xThis(static_cast< frame::XNotifyingDispatch* >(this));
+
+ SolarMutexGuard aGuard;
+ SdDLL::Init();
+ const SfxSlot* pSlot = SD_MOD()->GetInterface()->GetSlot( aURL.Complete );
+
+ sal_Int16 aState = frame::DispatchResultState::DONTKNOW;
+ if ( !pSlot )
+ aState = frame::DispatchResultState::FAILURE;
+ else
+ {
+ SfxRequest aReq( pSlot, aArgs, SfxCallMode::SYNCHRON, SD_MOD()->GetPool() );
+ const SfxPoolItem* pResult = SD_MOD()->ExecuteSlot( aReq );
+ if ( pResult )
+ aState = frame::DispatchResultState::SUCCESS;
+ else
+ aState = frame::DispatchResultState::FAILURE;
+ }
+
+ if ( xListener.is() )
+ {
+ xListener->dispatchFinished(
+ frame::DispatchResultEvent(
+ xThis, aState, uno::Any()));
+ }
+}
+ // XDispatch
+void SAL_CALL SdUnoModule::dispatch( const util::URL& aURL, const uno::Sequence< beans::PropertyValue >& aArgs )
+{
+ dispatchWithNotification(aURL, aArgs, uno::Reference< frame::XDispatchResultListener >());
+}
+
+void SAL_CALL SdUnoModule::addStatusListener(const uno::Reference< frame::XStatusListener > &, const util::URL&)
+{
+}
+
+void SAL_CALL SdUnoModule::removeStatusListener(const uno::Reference< frame::XStatusListener > &, const util::URL&)
+{
+}
+
+uno::Sequence< uno::Reference< frame::XDispatch > > SAL_CALL SdUnoModule::queryDispatches( const uno::Sequence< frame::DispatchDescriptor >& seqDescripts )
+{
+ sal_Int32 nCount = seqDescripts.getLength();
+ uno::Sequence< uno::Reference< frame::XDispatch > > lDispatcher( nCount );
+
+ std::transform(seqDescripts.begin(), seqDescripts.end(), lDispatcher.getArray(),
+ [this](const frame::DispatchDescriptor& rDescr) -> uno::Reference<frame::XDispatch> {
+ return queryDispatch(rDescr.FeatureURL, rDescr.FrameName, rDescr.SearchFlags); });
+
+ return lDispatcher;
+}
+
+// XDispatchProvider
+uno::Reference< frame::XDispatch > SAL_CALL SdUnoModule::queryDispatch( const util::URL& aURL, const OUString&, sal_Int32 )
+{
+ SolarMutexGuard aGuard;
+ SdDLL::Init();
+ const SfxSlot* pSlot = SD_MOD()->GetInterface()->GetSlot( aURL.Complete );
+
+ uno::Reference< frame::XDispatch > xSlot;
+ if ( pSlot )
+ xSlot = this;
+
+ return xSlot;
+}
+
+// XServiceInfo
+OUString SAL_CALL SdUnoModule::getImplementationName( )
+{
+ return "com.sun.star.comp.Draw.DrawingModule";
+}
+
+sal_Bool SAL_CALL SdUnoModule::supportsService( const OUString& sServiceName )
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL SdUnoModule::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.ModuleDispatcher" };
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_DrawingModule_get_implementation(css::uno::XComponentContext* ,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+
+ return cppu::acquire(new SdUnoModule);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unomodule.hxx b/sd/source/ui/unoidl/unomodule.hxx
new file mode 100644
index 000000000..bc78c6b19
--- /dev/null
+++ b/sd/source/ui/unoidl/unomodule.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XNotifyingDispatch.hpp>
+#include <com/sun/star/uno/Reference.h>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace com::sun::star::beans { struct PropertyValue; }
+namespace com::sun::star::frame { struct DispatchDescriptor; }
+
+class SdUnoModule : public ::cppu::WeakImplHelper< css::frame::XDispatchProvider, css::frame::XNotifyingDispatch, css::lang::XServiceInfo >
+{
+public:
+ SdUnoModule() {}
+
+ // XnotifyingDispatch
+ virtual void SAL_CALL dispatchWithNotification( const css::util::URL& URL, const css::uno::Sequence< css::beans::PropertyValue >& Arguments, const css::uno::Reference< css::frame::XDispatchResultListener >& Listener ) override;
+
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& aArgs ) override;
+ virtual void SAL_CALL addStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override;
+ virtual void SAL_CALL removeStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override;
+
+ // XDispatchProvider
+ virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& seqDescriptor ) override ;
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch( const css::util::URL & aURL ,
+ const OUString & sTargetFrameName,
+ sal_Int32 eSearchFlags ) override;
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unoobj.cxx b/sd/source/ui/unoidl/unoobj.cxx
new file mode 100644
index 000000000..6ed6729f9
--- /dev/null
+++ b/sd/source/ui/unoidl/unoobj.cxx
@@ -0,0 +1,1627 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+#include <string_view>
+#include <utility>
+
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/presentation/ClickAction.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <svl/itemprop.hxx>
+#include <svl/style.hxx>
+#include <svx/svdpool.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/app.hxx>
+#include <svtools/unoimap.hxx>
+#include <svtools/unoevent.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/event.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <comphelper/extract.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <filter/msfilter/msdffimp.hxx>
+#include <svl/instrm.hxx>
+#include <editeng/outlobj.hxx>
+#include <Outliner.hxx>
+#include <comphelper/sequence.hxx>
+#include <svx/svdogrp.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/debug.hxx>
+
+#include <anminfo.hxx>
+#include "unoobj.hxx"
+#include <unoprnms.hxx>
+#include <unomodel.hxx>
+#include <drawdoc.hxx>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+#include <ViewShell.hxx>
+#include <unopage.hxx>
+#include <DrawDocShell.hxx>
+#include <EffectMigration.hxx>
+
+using namespace ::sd;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::animations;
+
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::drawing::XShape;
+
+#define WID_EFFECT 1
+#define WID_SPEED 2
+#define WID_TEXTEFFECT 3
+#define WID_BOOKMARK 4
+#define WID_CLICKACTION 5
+#define WID_PLAYFULL 6
+#define WID_SOUNDFILE 7
+#define WID_SOUNDON 8
+#define WID_BLUESCREEN 9
+#define WID_VERB 10
+#define WID_DIMCOLOR 11
+#define WID_DIMHIDE 12
+#define WID_DIMPREV 13
+#define WID_PRESORDER 14
+#define WID_STYLE 15
+#define WID_ANIMPATH 16
+#define WID_IMAGEMAP 17
+#define WID_ISANIMATION 18
+#define WID_THAT_NEED_ANIMINFO 19
+
+#define WID_ISEMPTYPRESOBJ 20
+#define WID_ISPRESOBJ 21
+#define WID_MASTERDEPEND 22
+
+#define WID_NAVORDER 23
+#define WID_PLACEHOLDERTEXT 24
+#define WID_LEGACYFRAGMENT 25
+
+#define IMPRESS_MAP_ENTRIES \
+ { u"" UNO_NAME_OBJ_LEGACYFRAGMENT,WID_LEGACYFRAGMENT, cppu::UnoType<drawing::XShape>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_ANIMATIONPATH, WID_ANIMPATH, cppu::UnoType<drawing::XShape>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_BOOKMARK, WID_BOOKMARK, cppu::UnoType<OUString>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_DIMCOLOR, WID_DIMCOLOR, cppu::UnoType<sal_Int32>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_DIMHIDE, WID_DIMHIDE, cppu::UnoType<bool>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_DIMPREV, WID_DIMPREV, cppu::UnoType<bool>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_EFFECT, WID_EFFECT, cppu::UnoType<presentation::AnimationEffect>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_ISEMPTYPRESOBJ,WID_ISEMPTYPRESOBJ, cppu::UnoType<bool>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_ISPRESOBJ, WID_ISPRESOBJ, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY, 0},\
+ { u"" UNO_NAME_OBJ_MASTERDEPENDENT,WID_MASTERDEPEND, cppu::UnoType<bool>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_CLICKACTION, WID_CLICKACTION, cppu::UnoType<presentation::ClickAction>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_PLAYFULL, WID_PLAYFULL, cppu::UnoType<bool>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_PRESORDER, WID_PRESORDER, cppu::UnoType<sal_Int32>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_STYLE, WID_STYLE, cppu::UnoType<style::XStyle>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},\
+ { u"" UNO_NAME_OBJ_SOUNDFILE, WID_SOUNDFILE, cppu::UnoType<OUString>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_SOUNDON, WID_SOUNDON, cppu::UnoType<bool>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_SPEED, WID_SPEED, cppu::UnoType<presentation::AnimationSpeed>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_TEXTEFFECT, WID_TEXTEFFECT, cppu::UnoType<presentation::AnimationEffect>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_BLUESCREEN, WID_BLUESCREEN, cppu::UnoType<sal_Int32>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_VERB, WID_VERB, cppu::UnoType<sal_Int32>::get(), 0, 0},\
+ { u"IsAnimation", WID_ISANIMATION, cppu::UnoType<bool>::get(), 0, 0},\
+ { u"NavigationOrder", WID_NAVORDER, cppu::UnoType<sal_Int32>::get(), 0, 0},\
+ { u"PlaceholderText", WID_PLACEHOLDERTEXT, cppu::UnoType<OUString>::get(), 0, 0},\
+ { u"", 0, css::uno::Type(), 0, 0 }
+
+ static const SfxItemPropertyMapEntry* lcl_GetImpress_SdXShapePropertyGraphicMap_Impl()
+ {
+
+ static const SfxItemPropertyMapEntry aImpress_SdXShapePropertyGraphicMap_Impl[] =
+ {
+ { u"ImageMap", WID_IMAGEMAP, cppu::UnoType<container::XIndexContainer>::get(), 0, 0 },
+ IMPRESS_MAP_ENTRIES
+ };
+ return aImpress_SdXShapePropertyGraphicMap_Impl;
+ }
+
+ static const SfxItemPropertyMapEntry* lcl_GetImpress_SdXShapePropertySimpleMap_Impl()
+ {
+
+ static const SfxItemPropertyMapEntry aImpress_SdXShapePropertySimpleMap_Impl[] =
+ {
+ IMPRESS_MAP_ENTRIES
+ };
+ return aImpress_SdXShapePropertySimpleMap_Impl;
+ }
+
+ #define DRAW_MAP_ENTRIES\
+ { u"" UNO_NAME_OBJ_BOOKMARK, WID_BOOKMARK, cppu::UnoType<OUString>::get(), 0, 0},\
+ { u"" UNO_NAME_OBJ_CLICKACTION, WID_CLICKACTION, cppu::UnoType<presentation::ClickAction>::get(),0, 0},\
+ { u"" UNO_NAME_OBJ_STYLE, WID_STYLE, cppu::UnoType<style::XStyle>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},\
+ { u"NavigationOrder", WID_NAVORDER, cppu::UnoType<sal_Int32>::get(), 0, 0},\
+ { u"", 0, css::uno::Type(), 0, 0 }
+
+ static const SfxItemPropertyMapEntry* lcl_GetDraw_SdXShapePropertySimpleMap_Impl()
+ {
+ static const SfxItemPropertyMapEntry aDraw_SdXShapePropertyMap_Impl[] =
+ {
+ DRAW_MAP_ENTRIES
+ };
+ return aDraw_SdXShapePropertyMap_Impl;
+ }
+ static const SfxItemPropertyMapEntry* lcl_GetDraw_SdXShapePropertyGraphicMap_Impl()
+ {
+ static const SfxItemPropertyMapEntry aDraw_SdXShapePropertyGraphicMap_Impl[] =
+ {
+ { u"ImageMap", WID_IMAGEMAP, cppu::UnoType<container::XIndexContainer>::get(), 0, 0 },
+ DRAW_MAP_ENTRIES
+ };
+ return aDraw_SdXShapePropertyGraphicMap_Impl;
+ }
+ static const SfxItemPropertyMapEntry* lcl_ImplGetShapePropertyMap( bool bImpress, bool bGraphicObj )
+ {
+ const SfxItemPropertyMapEntry* pRet = nullptr;
+ if( bImpress )
+ {
+ if( bGraphicObj )
+ pRet = lcl_GetImpress_SdXShapePropertyGraphicMap_Impl();
+ else
+ pRet = lcl_GetImpress_SdXShapePropertySimpleMap_Impl();
+ }
+ else
+ {
+ if( bGraphicObj )
+ pRet = lcl_GetDraw_SdXShapePropertyGraphicMap_Impl();
+ else
+ pRet = lcl_GetDraw_SdXShapePropertySimpleMap_Impl();
+ }
+ return pRet;
+
+ }
+ static const SvxItemPropertySet* lcl_ImplGetShapePropertySet( bool bImpress, bool bGraphicObj )
+ {
+ const SvxItemPropertySet* pRet = nullptr;
+ if( bImpress )
+ {
+ if( bGraphicObj )
+ {
+ static SvxItemPropertySet aImpress_SdXShapePropertyGraphicSet_Impl( lcl_GetImpress_SdXShapePropertyGraphicMap_Impl(), SdrObject::GetGlobalDrawObjectItemPool());
+ pRet = &aImpress_SdXShapePropertyGraphicSet_Impl;
+ }
+ else
+ {
+ static SvxItemPropertySet aImpress_SdXShapePropertySet_Impl(lcl_GetImpress_SdXShapePropertySimpleMap_Impl(), SdrObject::GetGlobalDrawObjectItemPool());
+ pRet = &aImpress_SdXShapePropertySet_Impl;
+ }
+ }
+ else
+ {
+ if( bGraphicObj )
+ {
+ static SvxItemPropertySet aDraw_SdXShapePropertyGraphicSet_Impl(lcl_GetDraw_SdXShapePropertyGraphicMap_Impl(), SdrObject::GetGlobalDrawObjectItemPool());
+ pRet = &aDraw_SdXShapePropertyGraphicSet_Impl;
+ }
+ else
+ {
+ static SvxItemPropertySet aDraw_SdXShapePropertySet_Impl( lcl_GetDraw_SdXShapePropertySimpleMap_Impl(), SdrObject::GetGlobalDrawObjectItemPool());
+ pRet = &aDraw_SdXShapePropertySet_Impl;
+ }
+ }
+ return pRet;
+ }
+ static const SfxItemPropertyMapEntry* lcl_GetEmpty_SdXShapePropertyMap_Impl()
+ {
+ static const SfxItemPropertyMapEntry aEmpty_SdXShapePropertyMap_Impl[] =
+ {
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aEmpty_SdXShapePropertyMap_Impl;
+ }
+
+ static const SvxItemPropertySet* lcl_GetEmpty_SdXShapePropertySet_Impl()
+ {
+ static SvxItemPropertySet aEmptyPropSet( lcl_GetEmpty_SdXShapePropertyMap_Impl(), SdrObject::GetGlobalDrawObjectItemPool() );
+ return &aEmptyPropSet;
+ }
+const SvEventDescription* ImplGetSupportedMacroItems()
+{
+ static const SvEventDescription aMacroDescriptionsImpl[] =
+ {
+ { SvMacroItemId::OnMouseOver, "OnMouseOver" },
+ { SvMacroItemId::OnMouseOut, "OnMouseOut" },
+ { SvMacroItemId::NONE, nullptr }
+ };
+
+ return aMacroDescriptionsImpl;
+}
+
+SdXShape::SdXShape(SvxShape* pShape, SdXImpressDocument* pModel)
+: mpShape( pShape ),
+ mpPropSet( pModel?
+ lcl_ImplGetShapePropertySet(pModel->IsImpressDocument(), pShape->getShapeKind() == SdrObjKind::Graphic )
+ : lcl_GetEmpty_SdXShapePropertySet_Impl() ),
+ mpMap( pModel?
+ lcl_ImplGetShapePropertyMap(pModel->IsImpressDocument(), pShape->getShapeKind() == SdrObjKind::Graphic )
+ : lcl_GetEmpty_SdXShapePropertyMap_Impl() ),
+ mpModel(pModel)
+{
+
+ pShape->setMaster( this );
+}
+
+SdXShape::~SdXShape() noexcept
+{
+}
+
+void SdXShape::dispose()
+{
+ mpShape->setMaster( nullptr );
+ delete this;
+}
+
+uno::Any SAL_CALL SdXShape::queryInterface( const uno::Type & rType )
+{
+ return mpShape->queryInterface( rType );
+}
+
+void SAL_CALL SdXShape::acquire() noexcept
+{
+ mpShape->acquire();
+}
+
+void SAL_CALL SdXShape::release() noexcept
+{
+ mpShape->release();
+}
+
+bool SdXShape::queryAggregation( const css::uno::Type & rType, css::uno::Any& aAny )
+{
+ if( mpModel && mpModel ->IsImpressDocument() )
+ {
+ if( rType == cppu::UnoType<document::XEventsSupplier>::get())
+ {
+ aAny <<= uno::Reference< document::XEventsSupplier >(this);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+uno::Sequence< uno::Type > SAL_CALL SdXShape::getTypes()
+{
+ if( mpModel && !mpModel->IsImpressDocument() )
+ {
+ return mpShape->_getTypes();
+ }
+ else
+ {
+ SdrObjKind nObjId = mpShape->getShapeKind();
+ uno::Sequence< uno::Type > aTypes;
+ SdTypesCache& gImplTypesCache = SD_MOD()->gImplTypesCache;
+ SdTypesCache::iterator aIter( gImplTypesCache.find( nObjId ) );
+ if( aIter == gImplTypesCache.end() )
+ {
+ aTypes = mpShape->_getTypes();
+ sal_uInt32 nCount = aTypes.getLength();
+ aTypes.realloc( nCount+1 );
+ aTypes.getArray()[nCount] = cppu::UnoType<lang::XTypeProvider>::get();
+
+ gImplTypesCache.insert(std::make_pair(nObjId, aTypes));
+ }
+ else
+ {
+ // use the already computed implementation id
+ aTypes = (*aIter).second;
+ }
+ return aTypes;
+ }
+}
+
+// XPropertyState
+beans::PropertyState SAL_CALL SdXShape::getPropertyState( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpPropSet->getPropertyMapEntry(PropertyName) )
+ {
+ return beans::PropertyState_DIRECT_VALUE;
+ }
+ else
+ {
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if( pObj == nullptr || ( pObj->getSdrPageFromSdrObject()->IsMasterPage() && pObj->IsEmptyPresObj() ) )
+ return beans::PropertyState_DEFAULT_VALUE;
+
+ return mpShape->_getPropertyState( PropertyName );
+ }
+}
+
+void SAL_CALL SdXShape::setPropertyToDefault( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpPropSet->getPropertyMapEntry(PropertyName) )
+ {
+ return;
+ }
+ else
+ {
+ mpShape->_setPropertyToDefault(PropertyName);
+ }
+}
+
+uno::Any SAL_CALL SdXShape::getPropertyDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpPropSet->getPropertyMapEntry(aPropertyName) )
+ {
+ return getPropertyValue( aPropertyName );
+ }
+ else
+ {
+ uno::Any aRet( mpShape->_getPropertyDefault(aPropertyName) );
+ return aRet;
+ }
+}
+
+//XPropertySet
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL SdXShape::getPropertySetInfo()
+{
+ SfxItemPropertyMapEntry const * nObjId = mpShape->getPropertyMapEntries();
+ css::uno::Reference<css::beans::XPropertySetInfo> pInfo;
+
+ SdExtPropertySetInfoCache& rCache = (mpModel && mpModel->IsImpressDocument()) ?
+ SD_MOD()->gImplImpressPropertySetInfoCache : SD_MOD()->gImplDrawPropertySetInfoCache;
+
+ SdExtPropertySetInfoCache::iterator aIter( rCache.find( nObjId ) );
+ if( aIter == rCache.end() )
+ {
+ uno::Reference< beans::XPropertySetInfo > xInfo( mpShape->_getPropertySetInfo() );
+ pInfo = new SfxExtItemPropertySetInfo( mpMap, xInfo->getProperties() );
+
+ rCache.insert(std::make_pair(nObjId, pInfo));
+ }
+ else
+ {
+ // use the already computed implementation id
+ pInfo = (*aIter).second;
+ }
+
+ return pInfo;
+}
+
+void SAL_CALL SdXShape::setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pEntry = mpPropSet->getPropertyMapEntry(aPropertyName);
+
+ if( pEntry )
+ {
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if( pObj )
+ {
+ SdAnimationInfo* pInfo = GetAnimationInfo(pEntry->nWID <= WID_THAT_NEED_ANIMINFO);
+
+ switch(pEntry->nWID)
+ {
+ case WID_NAVORDER:
+ {
+ sal_Int32 nNavOrder = 0;
+ if(!(aValue >>= nNavOrder))
+ throw lang::IllegalArgumentException();
+
+ SdrObjList* pObjList = pObj->getParentSdrObjListFromSdrObject();
+ if( pObjList )
+ pObjList->SetObjectNavigationPosition( *pObj, (nNavOrder < 0) ? SAL_MAX_UINT32 : static_cast< sal_uInt32 >( nNavOrder ) );
+ break;
+ }
+
+ case WID_EFFECT:
+ {
+ AnimationEffect eEffect;
+ if(!(aValue >>= eEffect))
+ throw lang::IllegalArgumentException();
+
+ EffectMigration::SetAnimationEffect( mpShape, eEffect );
+ break;
+ }
+ case WID_TEXTEFFECT:
+ {
+ AnimationEffect eEffect;
+ if(!(aValue >>= eEffect))
+ throw lang::IllegalArgumentException();
+
+ EffectMigration::SetTextAnimationEffect( mpShape, eEffect );
+ break;
+ }
+ case WID_SPEED:
+ {
+ AnimationSpeed eSpeed;
+ if(!(aValue>>=eSpeed))
+ throw lang::IllegalArgumentException();
+
+ EffectMigration::SetAnimationSpeed( mpShape, eSpeed );
+ break;
+ }
+ case WID_ISANIMATION:
+ {
+ bool bIsAnimation(false);
+
+ if(!(aValue >>= bIsAnimation))
+ {
+ throw lang::IllegalArgumentException();
+ }
+
+ if(bIsAnimation)
+ {
+ SdrObjGroup* pGroup = dynamic_cast< SdrObjGroup* >(pObj);
+ SdPage* pPage = pGroup ? dynamic_cast< SdPage* >(pGroup->getSdrPageFromSdrObject()) : nullptr;
+
+ if (pPage)
+ {
+ // #i42894# Animated Group object, migrate that effect
+ EffectMigration::CreateAnimatedGroup(*pGroup, *pPage);
+
+ // #i42894# unfortunately when doing this all group members have to
+ // be moved to the page as direct members, else the currently
+ // available forms of animation do not work. If it succeeds,
+ // the group is empty and can be removed and deleted
+ if(!pGroup->GetSubList()->GetObjCount())
+ {
+ pPage->NbcRemoveObject(pGroup->GetOrdNum());
+
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pGroup);
+ SdrObject::Free(pTemp);
+ }
+ }
+ }
+ //pInfo->mbIsMovie = bIsAnimation;
+ break;
+ }
+ case WID_BOOKMARK:
+ {
+ OUString aString;
+ if(!(aValue >>= aString))
+ throw lang::IllegalArgumentException();
+
+ pInfo->SetBookmark( SdDrawPage::getUiNameFromPageApiName( aString ) );
+ break;
+ }
+ case WID_CLICKACTION:
+ ::cppu::any2enum< presentation::ClickAction >( pInfo->meClickAction, aValue);
+ break;
+
+// TODO: WID_PLAYFULL:
+ case WID_SOUNDFILE:
+ {
+ OUString aString;
+ if(!(aValue >>= aString))
+ throw lang::IllegalArgumentException();
+ pInfo->maSoundFile = aString;
+ EffectMigration::UpdateSoundEffect( mpShape, pInfo );
+ break;
+ }
+
+ case WID_SOUNDON:
+ {
+ if( !(aValue >>= pInfo->mbSoundOn) )
+ throw lang::IllegalArgumentException();
+ EffectMigration::UpdateSoundEffect( mpShape, pInfo );
+ break;
+ }
+ case WID_VERB:
+ {
+ sal_Int32 nVerb = 0;
+ if(!(aValue >>= nVerb))
+ throw lang::IllegalArgumentException();
+
+ pInfo->mnVerb = static_cast<sal_uInt16>(nVerb);
+ break;
+ }
+ case WID_DIMCOLOR:
+ {
+ sal_Int32 nColor = 0;
+
+ if( !(aValue >>= nColor) )
+ throw lang::IllegalArgumentException();
+
+ EffectMigration::SetDimColor( mpShape, nColor );
+ break;
+ }
+ case WID_DIMHIDE:
+ {
+ bool bDimHide = false;
+ if( !(aValue >>= bDimHide) )
+ throw lang::IllegalArgumentException();
+
+ EffectMigration::SetDimHide( mpShape, bDimHide );
+ break;
+ }
+ case WID_DIMPREV:
+ {
+ bool bDimPrevious = false;
+ if( !(aValue >>= bDimPrevious) )
+ throw lang::IllegalArgumentException();
+
+ EffectMigration::SetDimPrevious( mpShape, bDimPrevious );
+ break;
+ }
+ case WID_PRESORDER:
+ {
+ sal_Int32 nNewPos = 0;
+ if( !(aValue >>= nNewPos) )
+ throw lang::IllegalArgumentException();
+
+ EffectMigration::SetPresentationOrder( mpShape, nNewPos );
+ break;
+ }
+ case WID_STYLE:
+ SetStyleSheet( aValue );
+ break;
+ case WID_ISEMPTYPRESOBJ:
+ SetEmptyPresObj( ::cppu::any2bool(aValue) );
+ break;
+ case WID_MASTERDEPEND:
+ SetMasterDepend( ::cppu::any2bool(aValue) );
+ break;
+
+ case WID_LEGACYFRAGMENT:
+ {
+ uno::Reference< io::XInputStream > xInputStream;
+ aValue >>= xInputStream;
+ if( xInputStream.is() )
+ {
+ SvInputStream aStream( xInputStream );
+ SdrObject* pObject = mpShape->GetSdrObject();
+ SvxMSDffManager::ReadObjText( aStream, pObject );
+ }
+ }
+ break;
+
+ case WID_ANIMPATH:
+ {
+ uno::Reference< drawing::XShape > xShape( aValue, uno::UNO_QUERY );
+ SdrPathObj* pObj2 = xShape.is() ? dynamic_cast<SdrPathObj*>(SdrObject::getSdrObjectFromXShape(xShape)) : nullptr;
+
+ if( pObj2 == nullptr )
+ throw lang::IllegalArgumentException();
+
+ EffectMigration::SetAnimationPath( mpShape, pObj2 );
+ break;
+ }
+ case WID_IMAGEMAP:
+ {
+ SdDrawDocument* pDoc = mpModel?mpModel->GetDoc():nullptr;
+ if( pDoc )
+ {
+ ImageMap aImageMap;
+ uno::Reference< uno::XInterface > xImageMap;
+ aValue >>= xImageMap;
+
+ if( !xImageMap.is() || !SvUnoImageMap_fillImageMap( xImageMap, aImageMap ) )
+ throw lang::IllegalArgumentException();
+
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(pObj);
+ if( pIMapInfo )
+ {
+ // replace existing image map
+ pIMapInfo->SetImageMap( aImageMap );
+ }
+ else
+ {
+ // insert new user data with image map
+ pObj->AppendUserData(std::unique_ptr<SdrObjUserData>(new SvxIMapInfo(aImageMap) ));
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ mpShape->_setPropertyValue(aPropertyName, aValue);
+ }
+
+ if( mpModel )
+ mpModel->SetModified();
+}
+
+css::uno::Any SAL_CALL SdXShape::getPropertyValue( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aRet;
+
+ const SfxItemPropertyMapEntry* pEntry = mpPropSet->getPropertyMapEntry(PropertyName);
+
+ if( pEntry && mpShape->GetSdrObject() )
+ {
+ SdAnimationInfo* pInfo = GetAnimationInfo();
+
+ switch(pEntry->nWID)
+ {
+ case WID_NAVORDER:
+ {
+ const sal_uInt32 nNavOrder = mpShape->GetSdrObject()->GetNavigationPosition();
+ aRet <<= nNavOrder == SAL_MAX_UINT32 ? static_cast<sal_Int32>(-1) : static_cast< sal_Int32 >(nNavOrder);
+ }
+ break;
+ case WID_EFFECT:
+ aRet <<= EffectMigration::GetAnimationEffect( mpShape );
+ break;
+ case WID_TEXTEFFECT:
+ aRet <<= EffectMigration::GetTextAnimationEffect( mpShape );
+ break;
+ case WID_ISPRESOBJ:
+ aRet <<= IsPresObj();
+ break;
+ case WID_ISEMPTYPRESOBJ:
+ aRet <<= IsEmptyPresObj();
+ break;
+ case WID_MASTERDEPEND:
+ aRet <<= IsMasterDepend();
+ break;
+ case WID_SPEED:
+ aRet <<= EffectMigration::GetAnimationSpeed( mpShape );
+ break;
+ case WID_ISANIMATION:
+ aRet <<= (pInfo && pInfo->mbIsMovie);
+ break;
+ case WID_PLACEHOLDERTEXT:
+ aRet <<= GetPlaceholderText();
+ break;
+ case WID_BOOKMARK:
+ {
+ OUString aString;
+ SdDrawDocument* pDoc = mpModel ? mpModel->GetDoc() : nullptr;
+ if (pInfo && pDoc)
+ {
+ // is the bookmark a page?
+ bool bIsMasterPage;
+ if(pDoc->GetPageByName( pInfo->GetBookmark(), bIsMasterPage ) != SDRPAGE_NOTFOUND)
+ {
+ aString = SdDrawPage::getPageApiNameFromUiName( pInfo->GetBookmark() );
+ }
+ else
+ {
+ aString = pInfo->GetBookmark() ;
+ sal_Int32 nPos = aString.lastIndexOf( '#' );
+ if( nPos >= 0 )
+ {
+ OUString aURL( aString.copy( 0, nPos+1 ) );
+ OUString aName( aString.copy( nPos+1 ) );
+ if(pDoc->GetPageByName( aName, bIsMasterPage ) != SDRPAGE_NOTFOUND)
+ {
+ aURL += SdDrawPage::getPageApiNameFromUiName( aName );
+ aString = aURL;
+ }
+ }
+ }
+ }
+
+ aRet <<= aString;
+ break;
+ }
+ case WID_CLICKACTION:
+ aRet <<= ( pInfo?pInfo->meClickAction:presentation::ClickAction_NONE );
+ break;
+ case WID_PLAYFULL:
+ aRet <<= ( pInfo && pInfo->mbPlayFull );
+ break;
+ case WID_SOUNDFILE:
+ aRet <<= EffectMigration::GetSoundFile( mpShape );
+ break;
+ case WID_SOUNDON:
+ aRet <<= EffectMigration::GetSoundOn( mpShape );
+ break;
+ case WID_BLUESCREEN:
+ aRet <<= pInfo ? pInfo->maBlueScreen : Color(0x00ffffff);
+ break;
+ case WID_VERB:
+ aRet <<= static_cast<sal_Int32>( pInfo?pInfo->mnVerb:0 );
+ break;
+ case WID_DIMCOLOR:
+ aRet <<= EffectMigration::GetDimColor( mpShape );
+ break;
+ case WID_DIMHIDE:
+ aRet <<= EffectMigration::GetDimHide( mpShape );
+ break;
+ case WID_DIMPREV:
+ aRet <<= EffectMigration::GetDimPrevious( mpShape );
+ break;
+ case WID_PRESORDER:
+ aRet <<= EffectMigration::GetPresentationOrder( mpShape );
+ break;
+ case WID_STYLE:
+ aRet = GetStyleSheet();
+ break;
+ case WID_IMAGEMAP:
+ {
+ uno::Reference< uno::XInterface > xImageMap;
+
+ SdDrawDocument* pDoc = mpModel?mpModel->GetDoc():nullptr;
+ if( pDoc )
+ {
+
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(mpShape->GetSdrObject());
+ if( pIMapInfo )
+ {
+ const ImageMap& rIMap = pIMapInfo->GetImageMap();
+ xImageMap = SvUnoImageMap_createInstance( rIMap, ImplGetSupportedMacroItems() );
+ }
+ else
+ {
+ xImageMap = SvUnoImageMap_createInstance();
+ }
+ }
+
+ aRet <<= uno::Reference< container::XIndexContainer >::query( xImageMap );
+ break;
+ }
+ }
+ }
+ else
+ {
+ aRet = mpShape->_getPropertyValue(PropertyName);
+ }
+
+ return aRet;
+}
+
+/** */
+SdAnimationInfo* SdXShape::GetAnimationInfo( bool bCreate ) const
+{
+ SdAnimationInfo* pInfo = nullptr;
+
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if(pObj)
+ pInfo = SdDrawDocument::GetShapeUserData(*pObj, bCreate);
+
+ return pInfo;
+}
+
+uno::Sequence< OUString > SAL_CALL SdXShape::getSupportedServiceNames()
+{
+ std::vector<std::u16string_view> aAdd{ u"com.sun.star.presentation.Shape",
+ u"com.sun.star.document.LinkTarget" };
+
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if(pObj && pObj->GetObjInventor() == SdrInventor::Default )
+ {
+ SdrObjKind nInventor = pObj->GetObjIdentifier();
+ switch( nInventor )
+ {
+ case SdrObjKind::TitleText:
+ aAdd.emplace_back(u"com.sun.star.presentation.TitleTextShape");
+ break;
+ case SdrObjKind::OutlineText:
+ aAdd.emplace_back(u"com.sun.star.presentation.OutlinerShape");
+ break;
+ default: ;
+ }
+ }
+ return comphelper::concatSequences(mpShape->_getSupportedServiceNames(), aAdd);
+}
+
+/** checks if this is a presentation object
+ */
+bool SdXShape::IsPresObj() const
+{
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if(pObj)
+ {
+ SdPage* pPage = dynamic_cast<SdPage* >(pObj->getSdrPageFromSdrObject());
+ if(pPage)
+ return pPage->GetPresObjKind(pObj) != PresObjKind::NONE;
+ }
+ return false;
+}
+
+/** checks if this presentation object is empty
+ */
+bool SdXShape::IsEmptyPresObj() const
+{
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if( (pObj != nullptr) && pObj->IsEmptyPresObj() )
+ {
+ // check if the object is in edit, then if it's temporarily not empty
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObj );
+ if( pTextObj == nullptr )
+ return true;
+
+ return !pTextObj->CanCreateEditOutlinerParaObject();
+ }
+
+ return false;
+}
+
+OUString SdXShape::GetPlaceholderText() const
+{
+ // only possible if this actually *is* a presentation object
+ if( !IsPresObj() )
+ return OUString();
+
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if( pObj == nullptr )
+ return OUString();
+
+ SdPage* pPage = dynamic_cast< SdPage* >(pObj->getSdrPageFromSdrObject());
+ DBG_ASSERT( pPage, "no page?" );
+ if( pPage == nullptr )
+ return OUString();
+
+ return pPage->GetPresObjText( pPage->GetPresObjKind(pObj) );
+}
+
+/** sets/reset the empty status of a presentation object
+*/
+void SdXShape::SetEmptyPresObj(bool bEmpty)
+{
+ // only possible if this actually *is* a presentation object
+ if( !IsPresObj() )
+ return;
+
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if( pObj == nullptr )
+ return;
+
+ if( pObj->IsEmptyPresObj() == bEmpty )
+ return;
+
+ if(!bEmpty)
+ {
+ OutlinerParaObject* pOutlinerParaObject = pObj->GetOutlinerParaObject();
+ const bool bVertical = pOutlinerParaObject && pOutlinerParaObject->IsEffectivelyVertical();
+
+ // really delete SdrOutlinerObj at pObj
+ pObj->NbcSetOutlinerParaObject(std::nullopt);
+ if( bVertical )
+ if (auto pTextObj = dynamic_cast<SdrTextObj*>( pObj ) )
+ pTextObj->SetVerticalWriting( true );
+
+ SdrGrafObj* pGraphicObj = dynamic_cast<SdrGrafObj*>( pObj );
+ if( pGraphicObj )
+ {
+ Graphic aEmpty;
+ pGraphicObj->SetGraphic(aEmpty);
+ }
+ else
+ {
+ SdrOle2Obj* pOleObj = dynamic_cast< SdrOle2Obj* >( pObj );
+ if( pOleObj )
+ {
+ pOleObj->ClearGraphic();
+ }
+ }
+ }
+ else
+ {
+ // now set an empty OutlinerParaObject at pObj without
+ // any content but with the style of the old OutlinerParaObjects
+ // first paragraph
+ do
+ {
+ SdDrawDocument* pDoc = mpModel?mpModel->GetDoc():nullptr;
+ DBG_ASSERT( pDoc, "no document?" );
+ if( pDoc == nullptr)
+ break;
+
+ SdOutliner* pOutliner = pDoc->GetInternalOutliner();
+ DBG_ASSERT( pOutliner, "no outliner?" );
+ if( pOutliner == nullptr )
+ break;
+
+ SdPage* pPage = dynamic_cast< SdPage* >(pObj->getSdrPageFromSdrObject());
+ DBG_ASSERT( pPage, "no page?" );
+ if( pPage == nullptr )
+ break;
+
+ OutlinerParaObject* pOutlinerParaObject = pObj->GetOutlinerParaObject();
+ pOutliner->SetText( *pOutlinerParaObject );
+ const bool bVertical = pOutliner->IsVertical();
+
+ pOutliner->Clear();
+ pOutliner->SetVertical( bVertical );
+ pOutliner->SetStyleSheetPool( static_cast<SfxStyleSheetPool*>(pDoc->GetStyleSheetPool()) );
+ pOutliner->SetStyleSheet( 0, pPage->GetTextStyleSheetForObject( pObj ) );
+ pOutliner->Insert( pPage->GetPresObjText( pPage->GetPresObjKind(pObj) ) );
+ pObj->SetOutlinerParaObject( pOutliner->CreateParaObject() );
+ pOutliner->Clear();
+ }
+ while(false);
+ }
+
+ pObj->SetEmptyPresObj(bEmpty);
+}
+
+bool SdXShape::IsMasterDepend() const noexcept
+{
+ SdrObject* pObj = mpShape->GetSdrObject();
+ return pObj && pObj->GetUserCall() != nullptr;
+}
+
+void SdXShape::SetMasterDepend( bool bDepend ) noexcept
+{
+ if( IsMasterDepend() == bDepend )
+ return;
+
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if( pObj )
+ {
+ if( bDepend )
+ {
+ SdPage* pPage = dynamic_cast< SdPage* >(pObj->getSdrPageFromSdrObject());
+ pObj->SetUserCall( pPage );
+ }
+ else
+ {
+ pObj->SetUserCall( nullptr );
+ }
+ }
+}
+
+void SdXShape::SetStyleSheet( const uno::Any& rAny )
+{
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if( pObj == nullptr )
+ throw beans::UnknownPropertyException();
+
+ uno::Reference< style::XStyle > xStyle( rAny, uno::UNO_QUERY );
+ SfxStyleSheet* pStyleSheet = SfxUnoStyleSheet::getUnoStyleSheet( xStyle );
+
+ const SfxStyleSheet* pOldStyleSheet = pObj->GetStyleSheet();
+ if( pOldStyleSheet == pStyleSheet )
+ return;
+
+ if( pStyleSheet == nullptr || (pStyleSheet->GetFamily() != SfxStyleFamily::Para && pStyleSheet->GetFamily() != SfxStyleFamily::Page) )
+ throw lang::IllegalArgumentException();
+
+ pObj->SetStyleSheet( pStyleSheet, false );
+
+ SdDrawDocument* pDoc = mpModel? mpModel->GetDoc() : nullptr;
+ if( pDoc )
+ {
+ ::sd::DrawDocShell* pDocSh = pDoc->GetDocSh();
+ ::sd::ViewShell* pViewSh = pDocSh ? pDocSh->GetViewShell() : nullptr;
+
+ if( pViewSh )
+ pViewSh->GetViewFrame()->GetBindings().Invalidate( SID_STYLE_FAMILY2 );
+ }
+}
+
+uno::Any SdXShape::GetStyleSheet() const
+{
+ SdrObject* pObj = mpShape->GetSdrObject();
+ if( pObj == nullptr )
+ throw beans::UnknownPropertyException();
+
+ SfxStyleSheet* pStyleSheet = pObj->GetStyleSheet();
+ // it is possible for shapes inside a draw to have a presentation style
+ // but we don't want this for the api
+ if( (pStyleSheet == nullptr) || ((pStyleSheet->GetFamily() != SfxStyleFamily::Para) && !mpModel->IsImpressDocument()) )
+ return Any();
+
+ return Any( uno::Reference< style::XStyle >( dynamic_cast< SfxUnoStyleSheet* >( pStyleSheet ) ) );
+}
+
+class SdUnoEventsAccess : public cppu::WeakImplHelper< css::container::XNameReplace, css::lang::XServiceInfo >
+{
+private:
+ SdXShape* mpShape;
+
+public:
+ explicit SdUnoEventsAccess(SdXShape* pShape) noexcept;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+// XEventsSupplier
+uno::Reference< container::XNameReplace > SAL_CALL SdXShape::getEvents( )
+{
+ return new SdUnoEventsAccess( this );
+}
+
+constexpr OUStringLiteral gaStrOnClick( u"OnClick" );
+constexpr OUStringLiteral gaStrServiceName( u"com.sun.star.documents.Events" );
+constexpr OUStringLiteral gaStrEventType( u"EventType" );
+constexpr OUStringLiteral gaStrPresentation( u"Presentation" );
+constexpr OUStringLiteral gaStrLibrary(u"Library");
+constexpr OUStringLiteral gaStrMacroName(u"MacroName");
+constexpr OUStringLiteral gaStrClickAction( u"ClickAction" );
+constexpr OUStringLiteral gaStrBookmark( u"Bookmark" );
+constexpr OUStringLiteral gaStrEffect( u"Effect" );
+constexpr OUStringLiteral gaStrPlayFull( u"PlayFull" );
+constexpr OUStringLiteral gaStrVerb( u"Verb" );
+constexpr OUStringLiteral gaStrSoundURL( u"SoundURL" );
+constexpr OUStringLiteral gaStrSpeed( u"Speed" );
+constexpr OUStringLiteral gaStrStarBasic( u"StarBasic" );
+constexpr OUStringLiteral gaStrScript( u"Script" );
+
+SdUnoEventsAccess::SdUnoEventsAccess( SdXShape* pShape ) noexcept
+ : mpShape( pShape )
+{
+}
+
+namespace {
+
+enum class FoundFlags {
+ NONE = 0x0000,
+ ClickAction = 0x0001,
+ Bookmark = 0x0002,
+ Effect = 0x0004,
+ PlayFull = 0x0008,
+ Verb = 0x0010,
+ SoundUrl = 0x0020,
+ Speed = 0x0040,
+ EventType = 0x0080,
+ Macro = 0x0100,
+ Library = 0x0200,
+};
+
+}
+
+namespace o3tl {
+ template<> struct typed_flags<FoundFlags> : is_typed_flags<FoundFlags, 0x03ff> {};
+}
+
+static void clearEventsInAnimationInfo( SdAnimationInfo* pInfo )
+{
+ pInfo->SetBookmark( "" );
+ pInfo->mbSecondSoundOn = false;
+ pInfo->mbSecondPlayFull = false;
+ pInfo->meClickAction = presentation::ClickAction_NONE;
+ pInfo->meSecondEffect = presentation::AnimationEffect_NONE;
+ pInfo->meSecondSpeed = presentation::AnimationSpeed_MEDIUM;
+ pInfo->mnVerb = 0;
+}
+
+// XNameReplace
+void SAL_CALL SdUnoEventsAccess::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ if( mpShape == nullptr || aName != gaStrOnClick )
+ throw container::NoSuchElementException();
+
+ uno::Sequence< beans::PropertyValue > aProperties;
+ if( !aElement.hasValue() || aElement.getValueType() != getElementType() || !(aElement >>= aProperties) )
+ throw lang::IllegalArgumentException();
+
+ FoundFlags nFound = FoundFlags::NONE;
+
+ OUString aStrEventType;
+ presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
+ presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE;
+ presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_MEDIUM;
+ OUString aStrSoundURL;
+ bool bPlayFull = false;
+ sal_Int32 nVerb = 0;
+ OUString aStrMacro;
+ OUString aStrLibrary;
+ OUString aStrBookmark;
+
+ for( const beans::PropertyValue& rProperty : std::as_const(aProperties) )
+ {
+ if( !( nFound & FoundFlags::EventType ) && rProperty.Name == gaStrEventType )
+ {
+ if( rProperty.Value >>= aStrEventType )
+ {
+ nFound |= FoundFlags::EventType;
+ continue;
+ }
+ }
+ else if( !( nFound & FoundFlags::ClickAction ) && rProperty.Name == gaStrClickAction )
+ {
+ if( rProperty.Value >>= eClickAction )
+ {
+ nFound |= FoundFlags::ClickAction;
+ continue;
+ }
+ }
+ else if( !( nFound & FoundFlags::Macro ) && ( rProperty.Name == gaStrMacroName || rProperty.Name == gaStrScript ) )
+ {
+ if( rProperty.Value >>= aStrMacro )
+ {
+ nFound |= FoundFlags::Macro;
+ continue;
+ }
+ }
+ else if( !( nFound & FoundFlags::Library ) && rProperty.Name == gaStrLibrary )
+ {
+ if( rProperty.Value >>= aStrLibrary )
+ {
+ nFound |= FoundFlags::Library;
+ continue;
+ }
+ }
+ else if( !( nFound & FoundFlags::Effect ) && rProperty.Name == gaStrEffect )
+ {
+ if( rProperty.Value >>= eEffect )
+ {
+ nFound |= FoundFlags::Effect;
+ continue;
+ }
+ }
+ else if( !( nFound & FoundFlags::Bookmark ) && rProperty.Name == gaStrBookmark )
+ {
+ if( rProperty.Value >>= aStrBookmark )
+ {
+ nFound |= FoundFlags::Bookmark;
+ continue;
+ }
+ }
+ else if( !( nFound & FoundFlags::Speed ) && rProperty.Name == gaStrSpeed )
+ {
+ if( rProperty.Value >>= eSpeed )
+ {
+ nFound |= FoundFlags::Speed;
+ continue;
+ }
+ }
+ else if( !( nFound & FoundFlags::SoundUrl ) && rProperty.Name == gaStrSoundURL )
+ {
+ if( rProperty.Value >>= aStrSoundURL )
+ {
+ nFound |= FoundFlags::SoundUrl;
+ continue;
+ }
+ }
+ else if( !( nFound & FoundFlags::PlayFull ) && rProperty.Name == gaStrPlayFull )
+ {
+ if( rProperty.Value >>= bPlayFull )
+ {
+ nFound |= FoundFlags::PlayFull;
+ continue;
+ }
+ }
+ else if( !( nFound & FoundFlags::Verb ) && rProperty.Name == gaStrVerb )
+ {
+ if( rProperty.Value >>= nVerb )
+ {
+ nFound |= FoundFlags::Verb;
+ continue;
+ }
+ }
+
+ throw lang::IllegalArgumentException();
+ }
+
+ bool bOk = false;
+ do
+ {
+ if( !( nFound & FoundFlags::EventType ) )
+ break;
+
+ if( aStrEventType == gaStrPresentation )
+ {
+ if( !( nFound & FoundFlags::ClickAction ) )
+ break;
+
+ SdAnimationInfo* pInfo = mpShape->GetAnimationInfo();
+ if( presentation::ClickAction_NONE == eClickAction && nullptr == pInfo )
+ {
+ bOk = true;
+ break;
+ }
+
+ if( nullptr == pInfo )
+ pInfo = mpShape->GetAnimationInfo( true );
+
+ DBG_ASSERT( pInfo, "shape animation info could not be created!" );
+ if( nullptr == pInfo )
+ break;
+
+ clearEventsInAnimationInfo( pInfo );
+ pInfo->meClickAction = eClickAction;
+
+ switch( eClickAction )
+ {
+ case presentation::ClickAction_NONE:
+ case presentation::ClickAction_PREVPAGE:
+ case presentation::ClickAction_NEXTPAGE:
+ case presentation::ClickAction_FIRSTPAGE:
+ case presentation::ClickAction_LASTPAGE:
+ case presentation::ClickAction_INVISIBLE:
+ case presentation::ClickAction_STOPPRESENTATION:
+ {
+ bOk = true;
+ }
+ break;
+
+ case presentation::ClickAction_PROGRAM:
+ case presentation::ClickAction_BOOKMARK:
+ case presentation::ClickAction_DOCUMENT:
+ if( nFound & FoundFlags::Bookmark )
+ {
+ if( eClickAction == presentation::ClickAction_BOOKMARK )
+ {
+ aStrBookmark = getUiNameFromPageApiNameImpl( aStrBookmark );
+ }
+ else if( eClickAction == presentation::ClickAction_DOCUMENT )
+ {
+ sal_Int32 nPos = aStrBookmark.lastIndexOf( '#' );
+ if( nPos >= 0 )
+ {
+ OUString aURL = aStrBookmark.subView( 0, nPos+1 )
+ + getUiNameFromPageApiNameImpl( aStrBookmark.copy( nPos+1 ) );
+ aStrBookmark = aURL;
+ }
+ }
+
+ pInfo->SetBookmark( aStrBookmark );
+ bOk = true;
+ }
+ break;
+
+ case presentation::ClickAction_MACRO:
+ if( nFound & FoundFlags::Macro )
+ {
+ pInfo->SetBookmark( aStrMacro );
+ bOk = true;
+ }
+ break;
+
+ case presentation::ClickAction_VERB:
+ if( nFound & FoundFlags::Verb )
+ {
+ pInfo->mnVerb = static_cast<sal_uInt16>(nVerb);
+ bOk = true;
+ }
+ break;
+
+ case presentation::ClickAction_VANISH:
+ if( !( nFound & FoundFlags::Effect ) )
+ break;
+
+ pInfo->meSecondEffect = eEffect;
+ pInfo->meSecondSpeed = nFound & FoundFlags::Speed ? eSpeed : presentation::AnimationSpeed_MEDIUM;
+
+ bOk = true;
+
+ [[fallthrough]];
+
+ case presentation::ClickAction_SOUND:
+ if( nFound & FoundFlags::SoundUrl )
+ {
+ pInfo->SetBookmark( aStrSoundURL );
+ if( eClickAction != presentation::ClickAction_SOUND )
+ pInfo->mbSecondSoundOn = !aStrSoundURL.isEmpty();
+ pInfo->mbSecondPlayFull = (nFound & FoundFlags::PlayFull) && bPlayFull;
+
+ bOk = true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ SdAnimationInfo* pInfo = mpShape->GetAnimationInfo( true );
+
+ DBG_ASSERT( pInfo, "shape animation info could not be created!" );
+ if( nullptr == pInfo )
+ break;
+
+ clearEventsInAnimationInfo( pInfo );
+ pInfo->meClickAction = presentation::ClickAction_MACRO;
+
+ if ( SfxApplication::IsXScriptURL( aStrMacro ) )
+ {
+ pInfo->SetBookmark( aStrMacro );
+ }
+ else
+ {
+ sal_Int32 nIdx{ 0 };
+ const std::u16string_view aLibName = o3tl::getToken(aStrMacro, 0, '.', nIdx);
+ const std::u16string_view aModulName = o3tl::getToken(aStrMacro, 0, '.', nIdx);
+ const std::u16string_view aMacroName = o3tl::getToken(aStrMacro, 0, '.', nIdx);
+
+ OUStringBuffer sBuffer(
+ OUString::Concat(aMacroName) + OUStringChar('.') + aModulName + OUStringChar('.') + aLibName + OUStringChar('.') );
+
+ if ( aStrLibrary == "StarOffice" )
+ {
+ sBuffer.append( "BASIC" );
+ }
+ else
+ {
+ sBuffer.append( aStrLibrary );
+ }
+
+ pInfo->SetBookmark( sBuffer.makeStringAndClear() );
+ }
+ bOk = true;
+ }
+ }
+ while(false);
+
+ if( !bOk )
+ throw lang::IllegalArgumentException();
+}
+
+// XNameAccess
+uno::Any SAL_CALL SdUnoEventsAccess::getByName( const OUString& aName )
+{
+ if( mpShape == nullptr || aName != gaStrOnClick )
+ throw container::NoSuchElementException();
+
+ SdAnimationInfo* pInfo = mpShape->GetAnimationInfo();
+
+ presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
+ if( pInfo )
+ eClickAction = pInfo->meClickAction;
+
+ sal_Int32 nPropertyCount = 2;
+ switch( eClickAction )
+ {
+ case presentation::ClickAction_NONE:
+ case presentation::ClickAction_PREVPAGE:
+ case presentation::ClickAction_NEXTPAGE:
+ case presentation::ClickAction_FIRSTPAGE:
+ case presentation::ClickAction_LASTPAGE:
+ case presentation::ClickAction_INVISIBLE:
+ case presentation::ClickAction_STOPPRESENTATION:
+ break;
+ case presentation::ClickAction_PROGRAM:
+ case presentation::ClickAction_VERB:
+ case presentation::ClickAction_BOOKMARK:
+ case presentation::ClickAction_DOCUMENT:
+ case presentation::ClickAction_MACRO:
+ if ( !SfxApplication::IsXScriptURL( pInfo->GetBookmark() ) )
+ nPropertyCount += 1;
+ break;
+
+ case presentation::ClickAction_SOUND:
+ nPropertyCount += 2;
+ break;
+
+ case presentation::ClickAction_VANISH:
+ nPropertyCount += 4;
+ break;
+ default:
+ break;
+ }
+
+ uno::Sequence< beans::PropertyValue > aProperties( nPropertyCount );
+ beans::PropertyValue* pProperties = aProperties.getArray();
+
+ uno::Any aAny;
+
+ if( eClickAction == presentation::ClickAction_MACRO )
+ {
+ if ( SfxApplication::IsXScriptURL( pInfo->GetBookmark() ) )
+ {
+ // Scripting Framework URL
+ aAny <<= OUString(gaStrScript);
+ pProperties->Name = gaStrEventType;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ pProperties++;
+
+ aAny <<= pInfo->GetBookmark();
+ pProperties->Name = gaStrScript;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ pProperties++;
+ }
+ else
+ {
+ // Old Basic macro URL
+ aAny <<= OUString(gaStrStarBasic);
+ pProperties->Name = gaStrEventType;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ pProperties++;
+
+ OUString aMacro = pInfo->GetBookmark();
+
+ // aMacro has got following format:
+ // "Macroname.Modulname.Libname.Documentname" or
+ // "Macroname.Modulname.Libname.Applicationname"
+ sal_Int32 nIdx{ 0 };
+ const std::u16string_view aMacroName = o3tl::getToken(aMacro, 0, '.', nIdx);
+ const std::u16string_view aModulName = o3tl::getToken(aMacro, 0, '.', nIdx);
+ const std::u16string_view aLibName = o3tl::getToken(aMacro, 0, '.', nIdx);
+
+ OUString sBuffer = OUString::Concat(aLibName) +
+ "." +
+ aModulName +
+ "." +
+ aMacroName;
+
+ aAny <<= sBuffer;
+ pProperties->Name = gaStrMacroName;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ pProperties++;
+
+ aAny <<= OUString( "StarOffice" );
+ pProperties->Name = gaStrLibrary;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ }
+ }
+ else
+ {
+ aAny <<= OUString(gaStrPresentation);
+ pProperties->Name = gaStrEventType;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ pProperties++;
+
+ aAny <<= eClickAction;
+ pProperties->Name = gaStrClickAction;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ pProperties++;
+
+ switch( eClickAction )
+ {
+ case presentation::ClickAction_NONE:
+ case presentation::ClickAction_PREVPAGE:
+ case presentation::ClickAction_NEXTPAGE:
+ case presentation::ClickAction_FIRSTPAGE:
+ case presentation::ClickAction_LASTPAGE:
+ case presentation::ClickAction_INVISIBLE:
+ case presentation::ClickAction_STOPPRESENTATION:
+ break;
+ case presentation::ClickAction_BOOKMARK:
+ {
+ const OUString aStrBookmark( getPageApiNameFromUiName( pInfo->GetBookmark()) );
+ pProperties->Name = gaStrBookmark;
+ pProperties->Handle = -1;
+ pProperties->Value <<= aStrBookmark;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ }
+ break;
+
+ case presentation::ClickAction_DOCUMENT:
+ case presentation::ClickAction_PROGRAM:
+ {
+ OUString aString( pInfo->GetBookmark());
+ sal_Int32 nPos = aString.lastIndexOf( '#' );
+ if( nPos >= 0 )
+ {
+ OUString aURL = aString.subView( 0, nPos+1 ) +
+ getPageApiNameFromUiName( aString.copy( nPos+1 ) );
+ aString = aURL;
+ }
+ pProperties->Name = gaStrBookmark;
+ pProperties->Handle = -1;
+ pProperties->Value <<= aString;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ }
+ break;
+
+ case presentation::ClickAction_VANISH:
+ aAny <<= pInfo->meSecondEffect;
+ pProperties->Name = gaStrEffect;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ pProperties++;
+
+ aAny <<= pInfo->meSecondSpeed;
+ pProperties->Name = gaStrSpeed;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ pProperties++;
+
+ [[fallthrough]];
+
+ case presentation::ClickAction_SOUND:
+ if( eClickAction == presentation::ClickAction_SOUND || pInfo->mbSecondSoundOn )
+ {
+ aAny <<= pInfo->GetBookmark();
+ pProperties->Name = gaStrSoundURL;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ pProperties++;
+
+ pProperties->Name = gaStrPlayFull;
+ pProperties->Handle = -1;
+ pProperties->Value <<= pInfo->mbSecondPlayFull;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ }
+ break;
+
+ case presentation::ClickAction_VERB:
+ aAny <<= static_cast<sal_Int32>(pInfo->mnVerb);
+ pProperties->Name = gaStrVerb;
+ pProperties->Handle = -1;
+ pProperties->Value = aAny;
+ pProperties->State = beans::PropertyState_DIRECT_VALUE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ aAny <<= aProperties;
+ return aAny;
+}
+
+uno::Sequence< OUString > SAL_CALL SdUnoEventsAccess::getElementNames( )
+{
+ return { gaStrOnClick };
+}
+
+sal_Bool SAL_CALL SdUnoEventsAccess::hasByName( const OUString& aName )
+{
+ return aName == gaStrOnClick;
+}
+
+// XElementAccess
+uno::Type SAL_CALL SdUnoEventsAccess::getElementType( )
+{
+ return cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get();
+}
+
+sal_Bool SAL_CALL SdUnoEventsAccess::hasElements( )
+{
+ return true;
+}
+
+// XServiceInfo
+OUString SAL_CALL SdUnoEventsAccess::getImplementationName( )
+{
+ return "SdUnoEventsAccess";
+}
+
+sal_Bool SAL_CALL SdUnoEventsAccess::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL SdUnoEventsAccess::getSupportedServiceNames( )
+{
+ return { gaStrServiceName };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unoobj.hxx b/sd/source/ui/unoidl/unoobj.hxx
new file mode 100644
index 000000000..3f01cbed1
--- /dev/null
+++ b/sd/source/ui/unoidl/unoobj.hxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/document/XEventsSupplier.hpp>
+#include <svx/unomaster.hxx>
+
+namespace com::sun::star::beans { class XPropertySetInfo; }
+
+class SdXImpressDocument;
+class SdAnimationInfo;
+class SvxItemPropertySet;
+class SvxShape;
+struct SfxItemPropertyMapEntry;
+
+class SdXShape : public SvxShapeMaster,
+ public css::document::XEventsSupplier
+{
+ friend class SdUnoEventsAccess;
+
+private:
+ SvxShape* mpShape;
+ const SvxItemPropertySet* mpPropSet;
+ const SfxItemPropertyMapEntry* mpMap;
+ SdXImpressDocument* mpModel;
+
+ /// @throws css::lang::IllegalArgumentException
+ /// @throws css::beans::UnknownPropertyException
+ /// @throws css::uno::RuntimeException
+ void SetStyleSheet( const css::uno::Any& rAny );
+ /// @throws css::beans::UnknownPropertyException
+ css::uno::Any GetStyleSheet() const;
+
+ // Intern
+ /// @throws std::exception
+ SdAnimationInfo* GetAnimationInfo( bool bCreate = false ) const;
+ /// @throws std::exception
+ bool IsPresObj() const;
+
+ bool IsEmptyPresObj() const;
+ void SetEmptyPresObj(bool bEmpty);
+
+ bool IsMasterDepend() const noexcept;
+ void SetMasterDepend( bool bDepend ) noexcept;
+
+ OUString GetPlaceholderText() const;
+
+public:
+ SdXShape(SvxShape* pShape, SdXImpressDocument* pModel);
+ virtual ~SdXShape() noexcept;
+
+ virtual bool queryAggregation( const css::uno::Type & rType, css::uno::Any& aAny ) override;
+ virtual void dispose() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ //XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+
+ //XPropertyState
+ virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override;
+ virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override;
+ virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XEventsSupplier
+ virtual css::uno::Reference< css::container::XNameReplace > SAL_CALL getEvents( ) override;
+};
+
+struct SvEventDescription;
+const SvEventDescription* ImplGetSupportedMacroItems();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unopage.cxx b/sd/source/ui/unoidl/unopage.cxx
new file mode 100644
index 000000000..8a9549c51
--- /dev/null
+++ b/sd/source/ui/unoidl/unopage.cxx
@@ -0,0 +1,3056 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <initializer_list>
+#include <string_view>
+
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/presentation/FadeEffect.hpp>
+#include <com/sun/star/presentation/AnimationSpeed.hpp>
+#include <com/sun/star/view/PaperOrientation.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/profilezone.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/filter/SvmWriter.hxx>
+#include <vcl/metaact.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+#include <AnnotationEnumeration.hxx>
+#include <createunopageimpl.hxx>
+#include <unomodel.hxx>
+#include <unopage.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svdmodel.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <sdpage.hxx>
+#include <unoprnms.hxx>
+#include <drawdoc.hxx>
+#include <svx/unoshape.hxx>
+#include <svl/style.hxx>
+#include <comphelper/extract.hxx>
+#include <comphelper/sequence.hxx>
+#include <svx/svditer.hxx>
+#include <vcl/wmf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdview.hxx>
+#include <svx/xfillit0.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <DrawViewShell.hxx>
+#include <editeng/unoprnms.hxx>
+#include "unoobj.hxx"
+
+#include <strings.hxx>
+#include <bitmaps.hlst>
+#include <unokywds.hxx>
+#include "unopback.hxx"
+#include <vcl/dibtools.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <o3tl/string_view.hxx>
+
+using ::com::sun::star::animations::XAnimationNode;
+using ::com::sun::star::animations::XAnimationNodeSupplier;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::office;
+
+namespace {
+
+// this are the ids for page properties
+enum WID_PAGE
+{
+ WID_PAGE_LEFT, WID_PAGE_RIGHT, WID_PAGE_TOP, WID_PAGE_BOTTOM, WID_PAGE_WIDTH,
+ WID_PAGE_HEIGHT, WID_PAGE_EFFECT, WID_PAGE_CHANGE, WID_PAGE_SPEED, WID_PAGE_NUMBER,
+ WID_PAGE_ORIENT, WID_PAGE_LAYOUT, WID_PAGE_DURATION, WID_PAGE_HIGHRESDURATION, WID_PAGE_LDNAME, WID_PAGE_LDBITMAP,
+ WID_PAGE_BACK, WID_PAGE_PREVIEW, WID_PAGE_PREVIEWBITMAP, WID_PAGE_VISIBLE, WID_PAGE_SOUNDFILE, WID_PAGE_BACKFULL,
+ WID_PAGE_BACKVIS, WID_PAGE_BACKOBJVIS, WID_PAGE_USERATTRIBS, WID_PAGE_BOOKMARK, WID_PAGE_ISDARK,
+ WID_PAGE_HEADERVISIBLE, WID_PAGE_HEADERTEXT, WID_PAGE_FOOTERVISIBLE, WID_PAGE_FOOTERTEXT,
+ WID_PAGE_PAGENUMBERVISIBLE, WID_PAGE_DATETIMEVISIBLE, WID_PAGE_DATETIMEFIXED,
+ WID_PAGE_DATETIMETEXT, WID_PAGE_DATETIMEFORMAT, WID_TRANSITION_TYPE, WID_TRANSITION_SUBTYPE,
+ WID_TRANSITION_DIRECTION, WID_TRANSITION_FADE_COLOR, WID_TRANSITION_DURATION, WID_LOOP_SOUND,
+ WID_NAVORDER, WID_PAGE_PREVIEWMETAFILE, WID_PAGE_THEME
+};
+
+}
+
+constexpr OUStringLiteral sEmptyPageName = u"page";
+
+// this function stores the property maps for draw pages in impress and draw
+static const SvxItemPropertySet* ImplGetDrawPagePropertySet( bool bImpress, PageKind ePageKind )
+{
+ static const SfxItemPropertyMapEntry aDrawPagePropertyMap_Impl[] =
+ {
+ { u"" UNO_NAME_PAGE_BACKGROUND, WID_PAGE_BACK, cppu::UnoType<beans::XPropertySet>::get(), beans::PropertyAttribute::MAYBEVOID,0},
+ { u"" UNO_NAME_PAGE_BOTTOM, WID_PAGE_BOTTOM, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_LEFT, WID_PAGE_LEFT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_RIGHT, WID_PAGE_RIGHT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_TOP, WID_PAGE_TOP, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_CHANGE, WID_PAGE_CHANGE, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_DURATION, WID_PAGE_DURATION, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_EFFECT, WID_PAGE_EFFECT, ::cppu::UnoType<presentation::FadeEffect>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_HEIGHT, WID_PAGE_HEIGHT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_LAYOUT, WID_PAGE_LAYOUT, ::cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { UNO_NAME_LINKDISPLAYBITMAP, WID_PAGE_LDBITMAP, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_LINKDISPLAYNAME, WID_PAGE_LDNAME, ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0},
+ { u"" UNO_NAME_PAGE_NUMBER, WID_PAGE_NUMBER, ::cppu::UnoType<sal_Int16>::get(), beans::PropertyAttribute::READONLY, 0},
+ { u"" UNO_NAME_PAGE_ORIENTATION, WID_PAGE_ORIENT, ::cppu::UnoType<view::PaperOrientation>::get(),0, 0},
+ { u"" UNO_NAME_PAGE_SPEED, WID_PAGE_SPEED, ::cppu::UnoType<presentation::AnimationSpeed>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_WIDTH, WID_PAGE_WIDTH, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_PREVIEW, WID_PAGE_PREVIEW, cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"" UNO_NAME_PAGE_PREVIEWBITMAP, WID_PAGE_PREVIEWBITMAP, cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"" UNO_NAME_PAGE_PREVIEWMETAFILE, WID_PAGE_PREVIEWMETAFILE, cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"" UNO_NAME_PAGE_VISIBLE, WID_PAGE_VISIBLE, cppu::UnoType<bool>::get(), 0, 0},
+ { u"" UNO_NAME_OBJ_SOUNDFILE, WID_PAGE_SOUNDFILE, cppu::UnoType<Any>::get(), 0, 0},
+ { sUNO_Prop_IsBackgroundVisible, WID_PAGE_BACKVIS, cppu::UnoType<bool>::get(), 0, 0},
+ { sUNO_Prop_IsBackgroundObjectsVisible, WID_PAGE_BACKOBJVIS, cppu::UnoType<bool>::get(), 0, 0},
+ { sUNO_Prop_UserDefinedAttributes,WID_PAGE_USERATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { sUNO_Prop_BookmarkURL, WID_PAGE_BOOKMARK, ::cppu::UnoType<OUString>::get(), 0, 0},
+ { u"HighResDuration", WID_PAGE_HIGHRESDURATION, ::cppu::UnoType<double>::get(), 0, 0},
+ { u"IsBackgroundDark" , WID_PAGE_ISDARK, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
+ { u"IsFooterVisible", WID_PAGE_FOOTERVISIBLE, cppu::UnoType<bool>::get(), 0, 0},
+ { u"FooterText", WID_PAGE_FOOTERTEXT, ::cppu::UnoType<OUString>::get(), 0, 0},
+ { u"IsPageNumberVisible", WID_PAGE_PAGENUMBERVISIBLE, cppu::UnoType<bool>::get(), 0, 0},
+ { u"IsDateTimeVisible", WID_PAGE_DATETIMEVISIBLE, cppu::UnoType<bool>::get(), 0, 0},
+ { u"IsDateTimeFixed", WID_PAGE_DATETIMEFIXED, cppu::UnoType<bool>::get(), 0, 0},
+ { u"DateTimeText", WID_PAGE_DATETIMETEXT, ::cppu::UnoType<OUString>::get(), 0, 0},
+ { u"DateTimeFormat", WID_PAGE_DATETIMEFORMAT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"TransitionType", WID_TRANSITION_TYPE, ::cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { u"TransitionSubtype", WID_TRANSITION_SUBTYPE, ::cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { u"TransitionDirection", WID_TRANSITION_DIRECTION, ::cppu::UnoType<sal_Bool>::get(), 0, 0},
+ { u"TransitionFadeColor", WID_TRANSITION_FADE_COLOR, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_TRANSITION_DURATION, WID_TRANSITION_DURATION, ::cppu::UnoType<double>::get(), 0, 0},
+ { u"LoopSound", WID_LOOP_SOUND, cppu::UnoType<bool>::get(), 0, 0},
+ { u"NavigationOrder", WID_NAVORDER, cppu::UnoType<css::container::XIndexAccess>::get(),0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+#define DRAW_PAGE_NOTES_PROPERTIES \
+ { u"" UNO_NAME_PAGE_BOTTOM, WID_PAGE_BOTTOM, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"" UNO_NAME_PAGE_LEFT, WID_PAGE_LEFT, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"" UNO_NAME_PAGE_RIGHT, WID_PAGE_RIGHT, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"" UNO_NAME_PAGE_TOP, WID_PAGE_TOP, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"" UNO_NAME_PAGE_HEIGHT, WID_PAGE_HEIGHT, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"" UNO_NAME_PAGE_LAYOUT, WID_PAGE_LAYOUT, ::cppu::UnoType<sal_Int16>::get(), 0, 0}, \
+ { UNO_NAME_LINKDISPLAYBITMAP, WID_PAGE_LDBITMAP, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0}, \
+ { UNO_NAME_LINKDISPLAYNAME, WID_PAGE_LDNAME, ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0}, \
+ { u"" UNO_NAME_PAGE_NUMBER, WID_PAGE_NUMBER, ::cppu::UnoType<sal_Int16>::get(), beans::PropertyAttribute::READONLY, 0}, \
+ { u"" UNO_NAME_PAGE_ORIENTATION, WID_PAGE_ORIENT, ::cppu::UnoType<view::PaperOrientation>::get(),0, 0}, \
+ { u"" UNO_NAME_PAGE_WIDTH, WID_PAGE_WIDTH, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { sUNO_Prop_UserDefinedAttributes,WID_PAGE_USERATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},\
+ { u"IsHeaderVisible", WID_PAGE_HEADERVISIBLE, cppu::UnoType<bool>::get(), 0, 0}, \
+ { u"HeaderText", WID_PAGE_HEADERTEXT, ::cppu::UnoType<OUString>::get(), 0, 0}, \
+ { u"IsBackgroundDark", WID_PAGE_ISDARK, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0}, \
+ { u"IsFooterVisible", WID_PAGE_FOOTERVISIBLE, cppu::UnoType<bool>::get(), 0, 0}, \
+ { u"FooterText", WID_PAGE_FOOTERTEXT, ::cppu::UnoType<OUString>::get(), 0, 0}, \
+ { u"IsPageNumberVisible", WID_PAGE_PAGENUMBERVISIBLE, cppu::UnoType<bool>::get(), 0, 0}, \
+ { u"IsDateTimeVisible", WID_PAGE_DATETIMEVISIBLE, cppu::UnoType<bool>::get(), 0, 0}, \
+ { u"IsDateTimeFixed", WID_PAGE_DATETIMEFIXED, cppu::UnoType<bool>::get(), 0, 0}, \
+ { u"DateTimeText", WID_PAGE_DATETIMETEXT, ::cppu::UnoType<OUString>::get(), 0, 0}, \
+ { u"DateTimeFormat", WID_PAGE_DATETIMEFORMAT, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"NavigationOrder", WID_NAVORDER, cppu::UnoType<css::container::XIndexAccess>::get(),0, 0}, \
+ { u"", 0, css::uno::Type(), 0, 0 }
+
+ static const SfxItemPropertyMapEntry aDrawPageNotesHandoutPropertyMap_Impl[] =
+ {
+ // this must be the first two entries so they can be excluded for PageKind::Standard
+ { u"" UNO_NAME_PAGE_BACKGROUND, WID_PAGE_BACK, cppu::UnoType<beans::XPropertySet>::get(), beans::PropertyAttribute::MAYBEVOID,0},
+ DRAW_PAGE_NOTES_PROPERTIES
+ };
+ static const SfxItemPropertyMapEntry aDrawPageNotesHandoutPropertyNoBackMap_Impl[] =
+ {
+ DRAW_PAGE_NOTES_PROPERTIES
+ };
+
+#define GRAPHIC_PAGE_PROPERTIES \
+ { u"" UNO_NAME_PAGE_BOTTOM, WID_PAGE_BOTTOM, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"" UNO_NAME_PAGE_LEFT, WID_PAGE_LEFT, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"" UNO_NAME_PAGE_RIGHT, WID_PAGE_RIGHT, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"" UNO_NAME_PAGE_TOP, WID_PAGE_TOP, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"" UNO_NAME_PAGE_HEIGHT, WID_PAGE_HEIGHT, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { UNO_NAME_LINKDISPLAYBITMAP, WID_PAGE_LDBITMAP, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0}, \
+ { UNO_NAME_LINKDISPLAYNAME, WID_PAGE_LDNAME, ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0}, \
+ { u"" UNO_NAME_PAGE_NUMBER, WID_PAGE_NUMBER, ::cppu::UnoType<sal_Int16>::get(), beans::PropertyAttribute::READONLY, 0}, \
+ { u"" UNO_NAME_PAGE_ORIENTATION, WID_PAGE_ORIENT, ::cppu::UnoType<view::PaperOrientation>::get(),0, 0}, \
+ { u"" UNO_NAME_PAGE_WIDTH, WID_PAGE_WIDTH, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
+ { u"" UNO_NAME_PAGE_PREVIEW, WID_PAGE_PREVIEW, cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(), css::beans::PropertyAttribute::READONLY, 0}, \
+ { u"" UNO_NAME_PAGE_PREVIEWBITMAP, WID_PAGE_PREVIEWBITMAP, cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(), css::beans::PropertyAttribute::READONLY, 0},\
+ { u"" UNO_NAME_PAGE_PREVIEWMETAFILE, WID_PAGE_PREVIEWMETAFILE, cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(), css::beans::PropertyAttribute::READONLY, 0},\
+ { sUNO_Prop_UserDefinedAttributes,WID_PAGE_USERATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0}, \
+ { sUNO_Prop_BookmarkURL, WID_PAGE_BOOKMARK, ::cppu::UnoType<OUString>::get(), 0, 0}, \
+ { u"IsBackgroundDark", WID_PAGE_ISDARK, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0}, \
+ { u"NavigationOrder", WID_NAVORDER, cppu::UnoType<css::container::XIndexAccess>::get(),0, 0}, \
+ { u"", 0, css::uno::Type(), 0, 0 }
+
+ static const SfxItemPropertyMapEntry aGraphicPagePropertyMap_Impl[] =
+ {
+ { u"" UNO_NAME_PAGE_BACKGROUND, WID_PAGE_BACK, cppu::UnoType<beans::XPropertySet>::get(), beans::PropertyAttribute::MAYBEVOID,0},
+ GRAPHIC_PAGE_PROPERTIES
+ };
+ static const SfxItemPropertyMapEntry aGraphicPagePropertyNoBackMap_Impl[] =
+ {
+ GRAPHIC_PAGE_PROPERTIES
+ };
+
+ bool bWithoutBackground = ePageKind != PageKind::Standard && ePageKind != PageKind::Handout;
+ const SvxItemPropertySet* pRet = nullptr;
+ if( bImpress )
+ {
+ if( ePageKind == PageKind::Standard )
+ {
+ //PageKind::Standard always has a background property
+ static SvxItemPropertySet aDrawPagePropertySet_Impl( aDrawPagePropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ pRet = &aDrawPagePropertySet_Impl;
+ }
+ else
+ {
+ if(bWithoutBackground)
+ {
+ static SvxItemPropertySet aDrawPageNotesHandoutPropertyNoBackSet_Impl( aDrawPageNotesHandoutPropertyNoBackMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ pRet = &aDrawPageNotesHandoutPropertyNoBackSet_Impl;
+ }
+ else
+ {
+ static SvxItemPropertySet aDrawPageNotesHandoutPropertySet_Impl( aDrawPageNotesHandoutPropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ pRet = &aDrawPageNotesHandoutPropertySet_Impl;
+ }
+ }
+ }
+ else
+ {
+ if(bWithoutBackground)
+ {
+ static SvxItemPropertySet aGraphicPagePropertyNoBackSet_Impl( aGraphicPagePropertyNoBackMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ pRet = &aGraphicPagePropertyNoBackSet_Impl;
+ }
+ else
+ {
+ static SvxItemPropertySet aGraphicPagePropertySet_Impl( aGraphicPagePropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ pRet = &aGraphicPagePropertySet_Impl;
+ }
+ }
+ return pRet;
+}
+
+/** this function stores the property map for master pages in impress and draw */
+static const SvxItemPropertySet* ImplGetMasterPagePropertySet( PageKind ePageKind )
+{
+ static const SfxItemPropertyMapEntry aMasterPagePropertyMap_Impl[] =
+ {
+ { u"" UNO_NAME_PAGE_BACKGROUND, WID_PAGE_BACK, cppu::UnoType<beans::XPropertySet>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_BOTTOM, WID_PAGE_BOTTOM, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_LEFT, WID_PAGE_LEFT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_RIGHT, WID_PAGE_RIGHT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_TOP, WID_PAGE_TOP, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_HEIGHT, WID_PAGE_HEIGHT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { UNO_NAME_LINKDISPLAYBITMAP, WID_PAGE_LDBITMAP, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_LINKDISPLAYNAME, WID_PAGE_LDNAME, ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0},
+ { u"" UNO_NAME_PAGE_NUMBER, WID_PAGE_NUMBER, ::cppu::UnoType<sal_Int16>::get(), beans::PropertyAttribute::READONLY, 0},
+ { u"" UNO_NAME_PAGE_ORIENTATION, WID_PAGE_ORIENT, ::cppu::UnoType<view::PaperOrientation>::get(),0, 0},
+ { u"" UNO_NAME_PAGE_WIDTH, WID_PAGE_WIDTH, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"BackgroundFullSize", WID_PAGE_BACKFULL, cppu::UnoType<bool>::get(), 0, 0},
+ { sUNO_Prop_UserDefinedAttributes,WID_PAGE_USERATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"IsBackgroundDark", WID_PAGE_ISDARK, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
+ { u"Theme", WID_PAGE_THEME, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ static const SfxItemPropertyMapEntry aHandoutMasterPagePropertyMap_Impl[] =
+ {
+ { u"" UNO_NAME_PAGE_BOTTOM, WID_PAGE_BOTTOM, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_LEFT, WID_PAGE_LEFT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_RIGHT, WID_PAGE_RIGHT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_TOP, WID_PAGE_TOP, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_HEIGHT, WID_PAGE_HEIGHT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_ORIENTATION, WID_PAGE_ORIENT, ::cppu::UnoType<view::PaperOrientation>::get(),0, 0},
+ { u"" UNO_NAME_PAGE_NUMBER, WID_PAGE_NUMBER, ::cppu::UnoType<sal_Int16>::get(), beans::PropertyAttribute::READONLY, 0},
+ { u"" UNO_NAME_PAGE_WIDTH, WID_PAGE_WIDTH, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"" UNO_NAME_PAGE_LAYOUT, WID_PAGE_LAYOUT, ::cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { sUNO_Prop_UserDefinedAttributes,WID_PAGE_USERATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"IsBackgroundDark", WID_PAGE_ISDARK, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
+ { u"IsHeaderVisible", WID_PAGE_HEADERVISIBLE, cppu::UnoType<bool>::get(), 0, 0},
+ { u"HeaderText", WID_PAGE_HEADERTEXT, ::cppu::UnoType<OUString>::get(), 0, 0},
+ { u"IsFooterVisible", WID_PAGE_FOOTERVISIBLE, cppu::UnoType<bool>::get(), 0, 0},
+ { u"FooterText", WID_PAGE_FOOTERTEXT, ::cppu::UnoType<OUString>::get(), 0, 0},
+ { u"IsPageNumberVisible", WID_PAGE_PAGENUMBERVISIBLE, cppu::UnoType<bool>::get(), 0, 0},
+ { u"IsDateTimeVisible", WID_PAGE_DATETIMEVISIBLE, cppu::UnoType<bool>::get(), 0, 0},
+ { u"IsDateTimeFixed", WID_PAGE_DATETIMEFIXED, cppu::UnoType<bool>::get(), 0, 0},
+ { u"DateTimeText", WID_PAGE_DATETIMETEXT, ::cppu::UnoType<OUString>::get(), 0, 0},
+ { u"DateTimeFormat", WID_PAGE_DATETIMEFORMAT, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ const SvxItemPropertySet* pRet = nullptr;
+ if( ePageKind == PageKind::Handout )
+ {
+ static SvxItemPropertySet aHandoutMasterPagePropertySet_Impl( aHandoutMasterPagePropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ pRet = &aHandoutMasterPagePropertySet_Impl;
+ }
+ else
+ {
+ static SvxItemPropertySet aMasterPagePropertySet_Impl( aMasterPagePropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ pRet = &aMasterPagePropertySet_Impl;
+ }
+ return pRet;
+}
+
+const css::uno::Sequence< sal_Int8 > & SdGenericDrawPage::getUnoTunnelId() noexcept
+{
+ static const comphelper::UnoIdInit theSdGenericDrawPageUnoTunnelId;
+ return theSdGenericDrawPageUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL SdGenericDrawPage::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<SvxFmDrawPage>{});
+}
+
+SdGenericDrawPage::SdGenericDrawPage(SdXImpressDocument* _pModel, SdPage* pInPage, const SvxItemPropertySet* _pSet)
+: SvxFmDrawPage( static_cast<SdrPage*>(pInPage) ),
+ SdUnoSearchReplaceShape(this),
+ mpDocModel( _pModel ),
+ mpSdrModel(nullptr),
+ mbIsImpressDocument(false),
+ mnTempPageNumber(0),
+ mpPropSet ( _pSet )
+{
+ mpSdrModel = SvxFmDrawPage::mpModel;
+ if( mpDocModel )
+ mbIsImpressDocument = mpDocModel->IsImpressDocument();
+
+}
+
+SdGenericDrawPage::~SdGenericDrawPage() noexcept
+{
+}
+
+void SdGenericDrawPage::throwIfDisposed() const
+{
+ if( (SvxFmDrawPage::mpModel == nullptr) || (mpDocModel == nullptr) || (SvxFmDrawPage::mpPage == nullptr) )
+ throw lang::DisposedException();
+}
+
+SdXImpressDocument* SdGenericDrawPage::GetModel() const
+{
+ if( mpSdrModel != SvxFmDrawPage::mpModel )
+ const_cast<SdGenericDrawPage*>(this)->UpdateModel();
+ return mpDocModel;
+}
+
+bool SdGenericDrawPage::IsImpressDocument() const
+{
+ if( mpSdrModel != SvxFmDrawPage::mpModel )
+ const_cast<SdGenericDrawPage*>(this)->UpdateModel();
+ return mbIsImpressDocument;
+}
+
+
+void SdGenericDrawPage::UpdateModel()
+{
+ mpSdrModel = SvxFmDrawPage::mpModel;
+ if( mpSdrModel )
+ {
+ uno::Reference< uno::XInterface > xModel( SvxFmDrawPage::mpModel->getUnoModel() );
+ mpDocModel = comphelper::getFromUnoTunnel<SdXImpressDocument>( xModel );
+ }
+ else
+ {
+ mpDocModel = nullptr;
+ }
+ mbIsImpressDocument = mpDocModel && mpDocModel->IsImpressDocument();
+}
+
+// this is called whenever a SdrObject must be created for an empty api shape wrapper
+SdrObject * SdGenericDrawPage::CreateSdrObject_( const Reference< drawing::XShape >& xShape )
+{
+ if( nullptr == SvxFmDrawPage::mpPage || !xShape.is() )
+ return nullptr;
+
+ OUString aType( xShape->getShapeType() );
+ static const OUStringLiteral aPrefix( u"com.sun.star.presentation." );
+ if( !aType.startsWith( aPrefix ) )
+ {
+ SdrObject* pObj = SvxFmDrawPage::CreateSdrObject_( xShape );
+ return pObj;
+ }
+
+ aType = aType.copy( aPrefix.getLength() );
+
+ PresObjKind eObjKind = PresObjKind::NONE;
+
+ if( aType == "TitleTextShape" )
+ {
+ eObjKind = PresObjKind::Title;
+ }
+ else if( aType == "OutlinerShape" )
+ {
+ eObjKind = PresObjKind::Outline;
+ }
+ else if( aType == "SubtitleShape" )
+ {
+ eObjKind = PresObjKind::Text;
+ }
+ else if( aType == "OLE2Shape" )
+ {
+ eObjKind = PresObjKind::Object;
+ }
+ else if( aType == "ChartShape" )
+ {
+ eObjKind = PresObjKind::Chart;
+ }
+ else if( aType == "CalcShape" )
+ {
+ eObjKind = PresObjKind::Calc;
+ }
+ else if( aType == "TableShape" )
+ {
+ eObjKind = PresObjKind::Table;
+ }
+ else if( aType == "GraphicObjectShape" )
+ {
+ eObjKind = PresObjKind::Graphic;
+ }
+ else if( aType == "OrgChartShape" )
+ {
+ eObjKind = PresObjKind::OrgChart;
+ }
+ else if( aType == "PageShape" )
+ {
+ if( GetPage()->GetPageKind() == PageKind::Notes && GetPage()->IsMasterPage() )
+ eObjKind = PresObjKind::Title;
+ else
+ eObjKind = PresObjKind::Page;
+ }
+ else if( aType == "NotesShape" )
+ {
+ eObjKind = PresObjKind::Notes;
+ }
+ else if( aType == "HandoutShape" )
+ {
+ eObjKind = PresObjKind::Handout;
+ }
+ else if( aType == "FooterShape" )
+ {
+ eObjKind = PresObjKind::Footer;
+ }
+ else if( aType == "HeaderShape" )
+ {
+ eObjKind = PresObjKind::Header;
+ }
+ else if( aType == "SlideNumberShape" )
+ {
+ eObjKind = PresObjKind::SlideNumber;
+ }
+ else if( aType == "DateTimeShape" )
+ {
+ eObjKind = PresObjKind::DateTime;
+ }
+ else if( aType == "MediaShape" )
+ {
+ eObjKind = PresObjKind::Media;
+ }
+
+ ::tools::Rectangle aRect( eObjKind == PresObjKind::Title ? GetPage()->GetTitleRect() : GetPage()->GetLayoutRect() );
+
+ const awt::Point aPos( aRect.Left(), aRect.Top() );
+ xShape->setPosition( aPos );
+
+ const awt::Size aSize( aRect.GetWidth(), aRect.GetHeight() );
+ xShape->setSize( aSize );
+
+ SdrObject *pPresObj = nullptr;
+ if( (eObjKind == PresObjKind::Table) || (eObjKind == PresObjKind::Media) )
+ {
+ pPresObj = SvxFmDrawPage::CreateSdrObject_( xShape );
+ if( pPresObj )
+ {
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(GetPage()->getSdrModelFromSdrPage()));
+ pPresObj->NbcSetStyleSheet(rDoc.GetDefaultStyleSheet(), true);
+ GetPage()->InsertPresObj( pPresObj, eObjKind );
+ }
+ }
+ else
+ {
+ pPresObj = GetPage()->CreatePresObj( eObjKind, false, aRect );
+ }
+
+ if( pPresObj )
+ pPresObj->SetUserCall( GetPage() );
+
+ return pPresObj;
+}
+
+// XInterface
+Any SAL_CALL SdGenericDrawPage::queryInterface( const uno::Type & rType )
+{
+ Any aAny;
+
+ if (rType == cppu::UnoType<beans::XPropertySet>::get())
+ {
+ aAny <<= Reference<beans::XPropertySet>(this);
+ }
+ else if (rType == cppu::UnoType<container::XNamed>::get())
+ {
+ aAny <<= Reference<container::XNamed>(this);
+ }
+ else if (rType == cppu::UnoType<util::XReplaceable>::get())
+ {
+ aAny <<= Reference<util::XReplaceable>(this);
+ }
+ else if (rType == cppu::UnoType<util::XSearchable>::get())
+ {
+ aAny <<= Reference<util::XSearchable>(this);
+ }
+ else if (rType == cppu::UnoType<document::XLinkTargetSupplier>::get())
+ {
+ aAny <<= Reference<document::XLinkTargetSupplier>(this);
+ }
+ else if (rType == cppu::UnoType<drawing::XShapeCombiner>::get())
+ {
+ aAny <<= Reference<drawing::XShapeCombiner>(this);
+ }
+ else if (rType == cppu::UnoType<drawing::XShapeBinder>::get())
+ {
+ aAny <<= Reference<drawing::XShapeBinder>(this);
+ }
+ else if (rType == cppu::UnoType<beans::XMultiPropertySet>::get())
+ {
+ aAny <<= Reference<beans::XMultiPropertySet>(this);
+ }
+ else if (rType == cppu::UnoType<office::XAnnotationAccess>::get())
+ {
+ aAny <<= Reference<office::XAnnotationAccess>(this);
+ }
+ else if (IsImpressDocument() && rType == cppu::UnoType<XAnimationNodeSupplier>::get())
+ {
+ const PageKind ePageKind = GetPage() ? GetPage()->GetPageKind() : PageKind::Standard;
+
+ if( ePageKind == PageKind::Standard )
+ return Any( Reference< XAnimationNodeSupplier >( this ) );
+ }
+ else
+ return SvxDrawPage::queryInterface( rType );
+
+ return aAny;
+}
+
+// XPropertySet
+Reference< beans::XPropertySetInfo > SAL_CALL SdGenericDrawPage::getPropertySetInfo()
+{
+ ::SolarMutexGuard aGuard;
+ throwIfDisposed();
+ return mpPropSet->getPropertySetInfo();
+}
+
+void SAL_CALL SdGenericDrawPage::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ const SfxItemPropertyMapEntry* pEntry = mpPropSet->getPropertyMapEntry(aPropertyName);
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case WID_NAVORDER:
+ setNavigationOrder( aValue );
+ break;
+ case WID_PAGE_LEFT:
+ case WID_PAGE_RIGHT:
+ case WID_PAGE_TOP:
+ case WID_PAGE_BOTTOM:
+ case WID_PAGE_LAYOUT:
+ case WID_PAGE_DURATION:
+ case WID_PAGE_CHANGE:
+ {
+ sal_Int32 nValue = 0;
+ if(!(aValue >>= nValue))
+ throw lang::IllegalArgumentException();
+
+ switch( pEntry->nWID )
+ {
+ case WID_PAGE_LEFT:
+ SetLeftBorder(nValue);
+ break;
+ case WID_PAGE_RIGHT:
+ SetRightBorder( nValue );
+ break;
+ case WID_PAGE_TOP:
+ SetUpperBorder( nValue );
+ break;
+ case WID_PAGE_BOTTOM:
+ SetLowerBorder( nValue );
+ break;
+ case WID_PAGE_CHANGE:
+ GetPage()->SetPresChange( static_cast<PresChange>(nValue) );
+ break;
+ case WID_PAGE_LAYOUT:
+ GetPage()->SetAutoLayout( static_cast<AutoLayout>(nValue), true );
+ break;
+ case WID_PAGE_DURATION:
+ GetPage()->SetTime(nValue);
+ break;
+ }
+ break;
+ }
+ case WID_PAGE_HIGHRESDURATION:
+ {
+ double fValue = 0;
+ if(!(aValue >>= fValue))
+ throw lang::IllegalArgumentException();
+
+ GetPage()->SetTime(fValue);
+ break;
+ }
+ case WID_PAGE_WIDTH:
+ {
+ sal_Int32 nWidth = 0;
+ if(!(aValue >>= nWidth))
+ throw lang::IllegalArgumentException();
+
+ SetWidth( nWidth );
+ break;
+ }
+ case WID_PAGE_HEIGHT:
+ {
+ sal_Int32 nHeight = 0;
+ if(!(aValue >>= nHeight))
+ throw lang::IllegalArgumentException();
+
+ SetHeight( nHeight );
+ break;
+ }
+ case WID_PAGE_ORIENT:
+ {
+ sal_Int32 nEnum = 0;
+ if(!::cppu::enum2int( nEnum, aValue ))
+ throw lang::IllegalArgumentException();
+
+ Orientation eOri = (static_cast<view::PaperOrientation>(nEnum) == view::PaperOrientation_PORTRAIT)?Orientation::Portrait:Orientation::Landscape;
+
+ if( eOri != GetPage()->GetOrientation() )
+ {
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(GetPage()->getSdrModelFromSdrPage()));
+ const PageKind ePageKind = GetPage()->GetPageKind();
+
+ sal_uInt16 i, nPageCnt = rDoc.GetMasterSdPageCount(ePageKind);
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetMasterSdPage(i, ePageKind);
+ pPage->SetOrientation( eOri );
+ }
+
+ nPageCnt = rDoc.GetSdPageCount(ePageKind);
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetSdPage(i, ePageKind);
+ pPage->SetOrientation( eOri );
+ }
+ }
+ break;
+ }
+ case WID_PAGE_EFFECT:
+ {
+ sal_Int32 nEnum = 0;
+ if(!::cppu::enum2int( nEnum, aValue ))
+ throw lang::IllegalArgumentException();
+
+ GetPage()->SetFadeEffect( static_cast<presentation::FadeEffect>(nEnum) );
+ break;
+ }
+ case WID_PAGE_BACK:
+ setBackground( aValue );
+ break;
+ case WID_PAGE_SPEED:
+ {
+ sal_Int32 nEnum = 0;
+ if(!::cppu::enum2int( nEnum, aValue ))
+ throw lang::IllegalArgumentException();
+
+ GetPage()->setTransitionDuration( nEnum == 0 ? 3.0 : (nEnum == 1 ? 2.0 : 1.0 ) );
+ break;
+ }
+ case WID_PAGE_VISIBLE :
+ {
+ bool bVisible = false;
+ if( ! ( aValue >>= bVisible ) )
+ throw lang::IllegalArgumentException();
+ GetPage()->SetExcluded( !bVisible );
+ break;
+ }
+ case WID_PAGE_SOUNDFILE :
+ {
+ OUString aURL;
+ if( aValue >>= aURL )
+ {
+ GetPage()->SetSoundFile( aURL );
+ GetPage()->SetSound( !aURL.isEmpty() );
+ break;
+ }
+ else
+ {
+ bool bStopSound = false;
+ if( aValue >>= bStopSound )
+ {
+ GetPage()->SetStopSound( bStopSound );
+ break;
+ }
+ }
+
+ throw lang::IllegalArgumentException();
+ }
+ case WID_LOOP_SOUND:
+ {
+ bool bLoop = false;
+ if( ! (aValue >>= bLoop) )
+ throw lang::IllegalArgumentException();
+
+ GetPage()->SetLoopSound( bLoop );
+ break;
+ }
+ case WID_PAGE_BACKFULL:
+ {
+ bool bFullSize = false;
+ if( ! ( aValue >>= bFullSize ) )
+ throw lang::IllegalArgumentException();
+ GetPage()->SetBackgroundFullSize( bFullSize );
+ break;
+ }
+ case WID_PAGE_BACKVIS:
+ {
+ bool bVisible = false;
+ if( ! ( aValue >>= bVisible ) )
+ throw lang::IllegalArgumentException();
+
+ SdrPage* pPage = GetPage();
+ if( pPage )
+ {
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
+ if( rDoc.GetMasterPageCount() )
+ {
+ SdrLayerAdmin& rLayerAdmin = rDoc.GetLayerAdmin();
+ SdrLayerIDSet aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers();
+ aVisibleLayers.Set(rLayerAdmin.GetLayerID(sUNO_LayerName_background), bVisible);
+ pPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+ }
+ }
+ break;
+ }
+ case WID_PAGE_BACKOBJVIS:
+ {
+ bool bVisible = false;
+ if( ! ( aValue >>= bVisible ) )
+ throw lang::IllegalArgumentException();
+
+ SdrPage* pPage = GetPage();
+ if( pPage )
+ {
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
+ if( rDoc.GetMasterPageCount() )
+ {
+ SdrLayerAdmin& rLayerAdmin = rDoc.GetLayerAdmin();
+ SdrLayerIDSet aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers();
+ aVisibleLayers.Set(rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects), bVisible);
+ pPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+ }
+ }
+
+ break;
+ }
+ case WID_PAGE_USERATTRIBS:
+ {
+ if( !GetPage()->setAlienAttributes( aValue ) )
+ throw lang::IllegalArgumentException();
+ break;
+ }
+ case WID_PAGE_BOOKMARK:
+ {
+ OUString aBookmarkURL;
+ if( ! ( aValue >>= aBookmarkURL ) )
+ throw lang::IllegalArgumentException();
+
+ setBookmarkURL( aBookmarkURL );
+ break;
+ }
+
+ case WID_PAGE_HEADERVISIBLE:
+ case WID_PAGE_HEADERTEXT:
+ case WID_PAGE_FOOTERVISIBLE:
+ case WID_PAGE_FOOTERTEXT:
+ case WID_PAGE_PAGENUMBERVISIBLE:
+ case WID_PAGE_DATETIMEVISIBLE:
+ case WID_PAGE_DATETIMEFIXED:
+ case WID_PAGE_DATETIMETEXT:
+ case WID_PAGE_DATETIMEFORMAT:
+ {
+ sd::HeaderFooterSettings aHeaderFooterSettings( GetPage()->getHeaderFooterSettings() );
+
+ switch( pEntry->nWID )
+ {
+ case WID_PAGE_HEADERVISIBLE:
+ {
+ bool bVisible = false;
+ if( ! ( aValue >>= bVisible ) )
+ throw lang::IllegalArgumentException();
+
+ aHeaderFooterSettings.mbHeaderVisible = bVisible;
+ break;
+ }
+ case WID_PAGE_HEADERTEXT:
+ {
+ OUString aText;
+ if( ! ( aValue >>= aText ) )
+ throw lang::IllegalArgumentException();
+
+ aHeaderFooterSettings.maHeaderText = aText;
+ break;
+ }
+ case WID_PAGE_FOOTERVISIBLE:
+ {
+ bool bVisible = false;
+ if( ! ( aValue >>= bVisible ) )
+ throw lang::IllegalArgumentException();
+
+ aHeaderFooterSettings.mbFooterVisible = bVisible;
+ break;
+ }
+ case WID_PAGE_FOOTERTEXT:
+ {
+ OUString aText;
+ if( ! ( aValue >>= aText ) )
+ throw lang::IllegalArgumentException();
+
+ aHeaderFooterSettings.maFooterText = aText;
+ break;
+ }
+ case WID_PAGE_PAGENUMBERVISIBLE:
+ {
+ bool bVisible = false;
+ if( ! ( aValue >>= bVisible ) )
+ throw lang::IllegalArgumentException();
+
+ aHeaderFooterSettings.mbSlideNumberVisible = bVisible;
+ break;
+ }
+ case WID_PAGE_DATETIMEVISIBLE:
+ {
+ bool bVisible = false;
+ if( ! ( aValue >>= bVisible ) )
+ throw lang::IllegalArgumentException();
+
+ aHeaderFooterSettings.mbDateTimeVisible = bVisible;
+ break;
+ }
+ case WID_PAGE_DATETIMEFIXED:
+ {
+ bool bVisible = false;
+ if( ! ( aValue >>= bVisible ) )
+ throw lang::IllegalArgumentException();
+
+ aHeaderFooterSettings.mbDateTimeIsFixed = bVisible;
+ break;
+ }
+ case WID_PAGE_DATETIMETEXT:
+ {
+ OUString aText;
+ if( ! ( aValue >>= aText ) )
+ throw lang::IllegalArgumentException();
+
+ aHeaderFooterSettings.maDateTimeText = aText;
+ break;
+ }
+ case WID_PAGE_DATETIMEFORMAT:
+ {
+ sal_Int32 nValue = 0;
+ if( ! ( aValue >>= nValue ) )
+ throw lang::IllegalArgumentException();
+
+ aHeaderFooterSettings.meDateFormat = static_cast<SvxDateFormat>(nValue & 0x0f);
+ aHeaderFooterSettings.meTimeFormat = static_cast<SvxTimeFormat>((nValue >> 4) & 0x0f);
+ break;
+ }
+ }
+
+ if( !(aHeaderFooterSettings == GetPage()->getHeaderFooterSettings()) )
+ GetPage()->setHeaderFooterSettings( aHeaderFooterSettings );
+
+ break;
+ }
+
+ case WID_PAGE_NUMBER:
+ if( (GetPage()->GetPageKind() == PageKind::Handout) && !GetPage()->IsMasterPage() )
+ {
+ if( !(aValue >>= mnTempPageNumber) )
+ throw lang::IllegalArgumentException();
+
+ break;
+ }
+ throw beans::PropertyVetoException();
+
+ case WID_PAGE_LDBITMAP:
+ case WID_PAGE_LDNAME:
+ case WID_PAGE_ISDARK:
+ throw beans::PropertyVetoException();
+
+ case WID_TRANSITION_TYPE:
+ {
+ sal_Int16 nValue = 0;
+ if( ! ( aValue >>= nValue ) )
+ throw lang::IllegalArgumentException();
+
+ GetPage()->setTransitionType( nValue );
+ break;
+ }
+
+ case WID_TRANSITION_SUBTYPE:
+ {
+ sal_Int16 nValue = 0;
+ if( ! ( aValue >>= nValue ) )
+ throw lang::IllegalArgumentException();
+
+ GetPage()->setTransitionSubtype( nValue );
+ break;
+ }
+
+ case WID_TRANSITION_DIRECTION:
+ {
+ bool bValue = false;
+ if( ! ( aValue >>= bValue ) )
+ throw lang::IllegalArgumentException();
+
+ GetPage()->setTransitionDirection( bValue );
+ break;
+ }
+
+ case WID_TRANSITION_FADE_COLOR:
+ {
+ sal_Int32 nValue = 0;
+ if( ! ( aValue >>= nValue ) )
+ throw lang::IllegalArgumentException();
+
+ GetPage()->setTransitionFadeColor( nValue );
+ break;
+ }
+
+ case WID_TRANSITION_DURATION:
+ {
+ double fValue = 0.0;
+ if( ! ( aValue >>= fValue ) )
+ throw lang::IllegalArgumentException();
+
+ GetPage()->setTransitionDuration( fValue );
+ break;
+ }
+
+ case WID_PAGE_THEME:
+ {
+ SdrPage* pPage = GetPage();
+ std::unique_ptr<svx::Theme> pTheme = svx::Theme::FromAny(aValue);
+ pPage->getSdrPageProperties().SetTheme(std::move(pTheme));
+ break;
+ }
+
+ default:
+ throw beans::UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ GetModel()->SetModified();
+}
+
+Any SAL_CALL SdGenericDrawPage::getPropertyValue( const OUString& PropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ uno::Any aAny;
+
+ const SfxItemPropertyMapEntry* pEntry = mpPropSet->getPropertyMapEntry(PropertyName);
+
+ sal_Int16 nEntry = pEntry ? pEntry->nWID : -1;
+ switch (nEntry)
+ {
+ case WID_NAVORDER:
+ aAny = getNavigationOrder();
+ break;
+ case WID_PAGE_LEFT:
+ aAny <<= GetPage()->GetLeftBorder();
+ break;
+ case WID_PAGE_RIGHT:
+ aAny <<= GetPage()->GetRightBorder();
+ break;
+ case WID_PAGE_TOP:
+ aAny <<= GetPage()->GetUpperBorder();
+ break;
+ case WID_PAGE_BOTTOM:
+ aAny <<= GetPage()->GetLowerBorder();
+ break;
+ case WID_PAGE_WIDTH:
+ aAny <<= static_cast<sal_Int32>( GetPage()->GetSize().getWidth() );
+ break;
+ case WID_PAGE_HEIGHT:
+ aAny <<= static_cast<sal_Int32>( GetPage()->GetSize().getHeight() );
+ break;
+ case WID_PAGE_ORIENT:
+ aAny <<=
+ GetPage()->GetOrientation() == Orientation::Portrait
+ ? view::PaperOrientation_PORTRAIT
+ : view::PaperOrientation_LANDSCAPE;
+ break;
+ case WID_PAGE_EFFECT:
+ aAny <<= GetPage()->GetFadeEffect();
+ break;
+ case WID_PAGE_CHANGE:
+ aAny <<= static_cast<sal_Int32>( GetPage()->GetPresChange() );
+ break;
+ case WID_PAGE_SPEED:
+ {
+ const double fDuration = GetPage()->getTransitionDuration();
+ aAny <<= presentation::AnimationSpeed(
+ fDuration < 2.0 ? 2 : fDuration > 2.0 ? 0 : 1);
+ }
+ break;
+ case WID_PAGE_LAYOUT:
+ aAny <<= static_cast<sal_Int16>( GetPage()->GetAutoLayout() );
+ break;
+ case WID_PAGE_NUMBER:
+ {
+ const sal_uInt16 nPageNumber(GetPage()->GetPageNum());
+
+ if(nPageNumber > 0)
+ {
+ // for all other pages calculate the number
+ aAny <<= static_cast<sal_Int16>(static_cast<sal_uInt16>((nPageNumber-1)>>1) + 1);
+ }
+ else
+ {
+ aAny <<= mnTempPageNumber;
+ }
+ }
+ break;
+ case WID_PAGE_DURATION:
+ aAny <<= static_cast<sal_Int32>( GetPage()->GetTime() + .5 );
+ break;
+ case WID_PAGE_HIGHRESDURATION:
+ aAny <<= GetPage()->GetTime();
+ break;
+ case WID_PAGE_LDNAME:
+ {
+ const OUString aName( GetPage()->GetName() );
+ aAny <<= aName;
+ break;
+ }
+ case WID_PAGE_LDBITMAP:
+ {
+ Reference< awt::XBitmap > xBitmap(VCLUnoHelper::CreateBitmap(BitmapEx(BMP_PAGE)));
+ aAny <<= xBitmap;
+ }
+ break;
+ case WID_PAGE_BACK:
+ getBackground( aAny );
+ break;
+ case WID_PAGE_PREVIEW :
+ case WID_PAGE_PREVIEWMETAFILE :
+ {
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(GetPage()->getSdrModelFromSdrPage()));
+ ::sd::DrawDocShell* pDocShell = rDoc.GetDocSh();
+ if ( pDocShell )
+ {
+ sal_uInt16 nPgNum = 0;
+ sal_uInt16 nPageCount = rDoc.GetSdPageCount( PageKind::Standard );
+ sal_uInt16 nPageNumber = static_cast<sal_uInt16>( ( GetPage()->GetPageNum() - 1 ) >> 1 );
+ while( nPgNum < nPageCount )
+ {
+ rDoc.SetSelected( rDoc.GetSdPage( nPgNum, PageKind::Standard ), nPgNum == nPageNumber );
+ nPgNum++;
+ }
+ std::shared_ptr<GDIMetaFile> xMetaFile = pDocShell->GetPreviewMetaFile();
+ if (xMetaFile)
+ {
+ Size aSize( GetPage()->GetSize() );
+ xMetaFile->AddAction( new MetaFillColorAction( COL_WHITE, true ), 0 );
+ xMetaFile->AddAction( new MetaRectAction( ::tools::Rectangle( Point(), aSize ) ), 1 );
+ xMetaFile->SetPrefMapMode(MapMode(MapUnit::Map100thMM));
+ xMetaFile->SetPrefSize( aSize );
+
+ SvMemoryStream aDestStrm( 65535, 65535 );
+ if (nEntry == WID_PAGE_PREVIEW)
+ // Preview: WMF format.
+ ConvertGDIMetaFileToWMF(*xMetaFile, aDestStrm, nullptr, false);
+ else
+ {
+ // PreviewMetafile: SVM format.
+ SvmWriter aWriter(aDestStrm);
+ aWriter.Write(*xMetaFile);
+ }
+ Sequence<sal_Int8> aSeq( static_cast<sal_Int8 const *>(aDestStrm.GetData()), aDestStrm.Tell() );
+ aAny <<= aSeq;
+ }
+ }
+ }
+ break;
+
+ case WID_PAGE_PREVIEWBITMAP :
+ {
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(GetPage()->getSdrModelFromSdrPage()));
+ ::sd::DrawDocShell* pDocShell = rDoc.GetDocSh();
+ if ( pDocShell )
+ {
+ sal_uInt16 nPgNum = 0;
+ sal_uInt16 nPageCount = rDoc.GetSdPageCount( PageKind::Standard );
+ sal_uInt16 nPageNumber = static_cast<sal_uInt16>( ( GetPage()->GetPageNum() - 1 ) >> 1 );
+ while( nPgNum < nPageCount )
+ {
+ rDoc.SetSelected( rDoc.GetSdPage( nPgNum, PageKind::Standard ), nPgNum == nPageNumber );
+ nPgNum++;
+ }
+ std::shared_ptr<GDIMetaFile> xMetaFile = pDocShell->GetPreviewMetaFile();
+ BitmapEx aBitmap;
+ if (xMetaFile && xMetaFile->CreateThumbnail(aBitmap))
+ {
+ SvMemoryStream aMemStream;
+ WriteDIB(aBitmap.GetBitmap(), aMemStream, false, false);
+ uno::Sequence<sal_Int8> aSeq( static_cast<sal_Int8 const *>(aMemStream.GetData()), aMemStream.Tell() );
+ aAny <<= aSeq;
+ }
+ }
+ }
+ break;
+
+ case WID_PAGE_VISIBLE :
+ {
+ bool bVisible = !GetPage()->IsExcluded();
+ aAny <<= bVisible;
+ break;
+ }
+
+ case WID_PAGE_SOUNDFILE :
+ {
+ if( GetPage()->IsStopSound() )
+ {
+ aAny <<= true;
+ }
+ else
+ {
+ OUString aURL;
+ if( GetPage()->IsSoundOn() )
+ aURL = GetPage()->GetSoundFile();
+ aAny <<= aURL;
+ }
+ break;
+ }
+ case WID_LOOP_SOUND:
+ {
+ aAny <<= GetPage()->IsLoopSound();
+ break;
+ }
+ case WID_PAGE_BACKFULL:
+ {
+ bool bFullSize = GetPage()->IsBackgroundFullSize();
+ aAny <<= bFullSize;
+ break;
+ }
+ case WID_PAGE_BACKVIS:
+ {
+ SdrPage* pPage = GetPage();
+ if( pPage )
+ {
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
+ if( rDoc.GetMasterPageCount() )
+ {
+ SdrLayerAdmin& rLayerAdmin = rDoc.GetLayerAdmin();
+ SdrLayerIDSet aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers();
+ aAny <<= aVisibleLayers.IsSet(rLayerAdmin.GetLayerID(sUNO_LayerName_background));
+ }
+ else
+ {
+ aAny <<= false;
+ }
+ }
+ break;
+ }
+ case WID_PAGE_BACKOBJVIS:
+ {
+ SdrPage* pPage = GetPage();
+ if( pPage )
+ {
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
+ if( rDoc.GetMasterPageCount() )
+ {
+ SdrLayerAdmin& rLayerAdmin = rDoc.GetLayerAdmin();
+ SdrLayerIDSet aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers();
+ aAny <<= aVisibleLayers.IsSet(rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects));
+ }
+ else
+ {
+ aAny <<= false;
+ }
+ }
+ break;
+ }
+ case WID_PAGE_USERATTRIBS:
+ {
+ GetPage()->getAlienAttributes( aAny );
+ break;
+ }
+ case WID_PAGE_BOOKMARK:
+ {
+ aAny <<= getBookmarkURL();
+ break;
+ }
+ case WID_PAGE_ISDARK:
+ {
+ aAny <<= GetPage()->GetPageBackgroundColor().IsDark();
+ break;
+ }
+ case WID_PAGE_HEADERVISIBLE:
+ aAny <<= GetPage()->getHeaderFooterSettings().mbHeaderVisible;
+ break;
+ case WID_PAGE_HEADERTEXT:
+ {
+ const OUString aText( GetPage()->getHeaderFooterSettings().maHeaderText );
+ aAny <<= aText;
+ }
+ break;
+ case WID_PAGE_FOOTERVISIBLE:
+ aAny <<= GetPage()->getHeaderFooterSettings().mbFooterVisible;
+ break;
+ case WID_PAGE_FOOTERTEXT:
+ {
+ const OUString aText( GetPage()->getHeaderFooterSettings().maFooterText );
+ aAny <<= aText;
+ }
+ break;
+ case WID_PAGE_PAGENUMBERVISIBLE:
+ aAny <<= GetPage()->getHeaderFooterSettings().mbSlideNumberVisible;
+ break;
+ case WID_PAGE_DATETIMEVISIBLE:
+ aAny <<= GetPage()->getHeaderFooterSettings().mbDateTimeVisible;
+ break;
+ case WID_PAGE_DATETIMEFIXED:
+ aAny <<= GetPage()->getHeaderFooterSettings().mbDateTimeIsFixed;
+ break;
+ case WID_PAGE_DATETIMETEXT:
+ {
+ const OUString aText( GetPage()->getHeaderFooterSettings().maDateTimeText );
+ aAny <<= aText;
+ }
+ break;
+ case WID_PAGE_DATETIMEFORMAT:
+ {
+ auto const & rSettings = GetPage()->getHeaderFooterSettings();
+ sal_Int32 x = static_cast<sal_Int32>(rSettings.meDateFormat) | (static_cast<sal_Int32>(rSettings.meTimeFormat) << 4);
+ aAny <<= x;
+ }
+ break;
+
+ case WID_TRANSITION_TYPE:
+ aAny <<= GetPage()->getTransitionType();
+ break;
+
+ case WID_TRANSITION_SUBTYPE:
+ aAny <<= GetPage()->getTransitionSubtype();
+ break;
+
+ case WID_TRANSITION_DIRECTION:
+ aAny <<= GetPage()->getTransitionDirection();
+ break;
+
+ case WID_TRANSITION_FADE_COLOR:
+ aAny <<= GetPage()->getTransitionFadeColor();
+ break;
+
+ case WID_TRANSITION_DURATION:
+ aAny <<= GetPage()->getTransitionDuration();
+ break;
+
+ case WID_PAGE_THEME:
+ {
+ SdrPage* pPage = GetPage();
+ svx::Theme* pTheme = pPage->getSdrPageProperties().GetTheme();
+ if (pTheme)
+ {
+ pTheme->ToAny(aAny);
+ }
+ else
+ {
+ beans::PropertyValues aValues;
+ aAny <<= aValues;
+ }
+ break;
+ }
+
+ default:
+ throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+ return aAny;
+}
+
+void SAL_CALL SdGenericDrawPage::addPropertyChangeListener( const OUString& , const Reference< beans::XPropertyChangeListener >& ) {}
+void SAL_CALL SdGenericDrawPage::removePropertyChangeListener( const OUString& , const Reference< beans::XPropertyChangeListener >& ) {}
+void SAL_CALL SdGenericDrawPage::addVetoableChangeListener( const OUString& , const Reference< beans::XVetoableChangeListener >& ) {}
+void SAL_CALL SdGenericDrawPage::removeVetoableChangeListener( const OUString& , const Reference< beans::XVetoableChangeListener >& ) {}
+
+// XMultiPropertySet
+void SAL_CALL SdGenericDrawPage::setPropertyValues( const Sequence< OUString >& aPropertyNames, const Sequence< Any >& aValues )
+{
+ if( aPropertyNames.getLength() != aValues.getLength() )
+ throw lang::IllegalArgumentException();
+
+ const OUString* pNames = aPropertyNames.getConstArray();
+ const Any* pValues = aValues.getConstArray();
+ sal_uInt32 nCount = aValues.getLength();
+ while( nCount-- )
+ {
+ try
+ {
+ setPropertyValue( *pNames++, *pValues++ );
+ }
+ catch( beans::UnknownPropertyException& )
+ {
+ // ignore for multi property set
+ // todo: optimize this!
+ }
+ }
+}
+
+Sequence< Any > SAL_CALL SdGenericDrawPage::getPropertyValues( const Sequence< OUString >& aPropertyNames )
+{
+ sal_Int32 nCount = aPropertyNames.getLength();
+ Sequence< Any > aValues( nCount );
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aValues.getArray(),
+ [this](const OUString& rName) -> Any {
+ Any aValue;
+ try
+ {
+ aValue = getPropertyValue(rName);
+ }
+ catch( beans::UnknownPropertyException& )
+ {
+ // ignore for multi property set
+ // todo: optimize this!
+ }
+ return aValue;
+ });
+ return aValues;
+}
+
+void SAL_CALL SdGenericDrawPage::addPropertiesChangeListener( const Sequence< OUString >& , const Reference< beans::XPropertiesChangeListener >& )
+{
+}
+
+void SAL_CALL SdGenericDrawPage::removePropertiesChangeListener( const Reference< beans::XPropertiesChangeListener >& )
+{
+}
+
+void SAL_CALL SdGenericDrawPage::firePropertiesChangeEvent( const Sequence< OUString >& , const Reference< beans::XPropertiesChangeListener >& )
+{
+}
+
+Reference< drawing::XShape > SdGenericDrawPage::CreateShape(SdrObject *pObj) const
+{
+ DBG_ASSERT( GetPage(), "SdGenericDrawPage::CreateShape(), can't create shape for disposed page!" );
+ DBG_ASSERT( pObj, "SdGenericDrawPage::CreateShape(), invalid call with pObj == 0!" );
+
+ if (!pObj)
+ return Reference< drawing::XShape >();
+
+ if (GetPage())
+ {
+ PresObjKind eKind = GetPage()->GetPresObjKind(pObj);
+
+ rtl::Reference<SvxShape> pShape;
+
+ if(pObj->GetObjInventor() == SdrInventor::Default)
+ {
+ SdrObjKind nInventor = pObj->GetObjIdentifier();
+ switch( nInventor )
+ {
+ case SdrObjKind::TitleText:
+ pShape = new SvxShapeText( pObj );
+ if( GetPage()->GetPageKind() == PageKind::Notes && GetPage()->IsMasterPage() )
+ {
+ // fake an empty PageShape if it's a title shape on the master page
+ pShape->SetShapeType("com.sun.star.presentation.PageShape");
+ }
+ else
+ {
+ pShape->SetShapeType("com.sun.star.presentation.TitleTextShape");
+ }
+ eKind = PresObjKind::NONE;
+ break;
+ case SdrObjKind::OutlineText:
+ pShape = new SvxShapeText( pObj );
+ pShape->SetShapeType("com.sun.star.presentation.OutlinerShape");
+ eKind = PresObjKind::NONE;
+ break;
+ default: ;
+ }
+ }
+
+ Reference< drawing::XShape > xShape( pShape );
+
+ if(!xShape.is())
+ xShape = SvxFmDrawPage::CreateShape( pObj );
+
+ if( eKind != PresObjKind::NONE )
+ {
+ OUString aShapeType("com.sun.star.presentation.");
+
+ switch( eKind )
+ {
+ case PresObjKind::Title:
+ aShapeType += "TitleTextShape";
+ break;
+ case PresObjKind::Outline:
+ aShapeType += "OutlinerShape";
+ break;
+ case PresObjKind::Text:
+ aShapeType += "SubtitleShape";
+ break;
+ case PresObjKind::Graphic:
+ aShapeType += "GraphicObjectShape";
+ break;
+ case PresObjKind::Object:
+ aShapeType += "OLE2Shape";
+ break;
+ case PresObjKind::Chart:
+ aShapeType += "ChartShape";
+ break;
+ case PresObjKind::OrgChart:
+ aShapeType += "OrgChartShape";
+ break;
+ case PresObjKind::Calc:
+ aShapeType += "CalcShape";
+ break;
+ case PresObjKind::Table:
+ aShapeType += "TableShape";
+ break;
+ case PresObjKind::Media:
+ aShapeType += "MediaShape";
+ break;
+ case PresObjKind::Page:
+ aShapeType += "PageShape";
+ break;
+ case PresObjKind::Handout:
+ aShapeType += "HandoutShape";
+ break;
+ case PresObjKind::Notes:
+ aShapeType += "NotesShape";
+ break;
+ case PresObjKind::Footer:
+ aShapeType += "FooterShape";
+ break;
+ case PresObjKind::Header:
+ aShapeType += "HeaderShape";
+ break;
+ case PresObjKind::SlideNumber:
+ aShapeType += "SlideNumberShape";
+ break;
+ case PresObjKind::DateTime:
+ aShapeType += "DateTimeShape";
+ break;
+ // coverity[dead_error_begin] - following conditions exist to avoid compiler warning
+ case PresObjKind::NONE:
+ break;
+ }
+
+ if( !pShape )
+ pShape = comphelper::getFromUnoTunnel<SvxShape>( xShape );
+
+ if( pShape )
+ pShape->SetShapeType( aShapeType );
+ }
+
+ SvxShape *pSdShape = comphelper::getFromUnoTunnel<SvxShape>(xShape);
+ if (pSdShape)
+ {
+ // SdXShape aggregates SvxShape
+ new SdXShape(pSdShape, GetModel());
+ }
+ return xShape;
+ }
+ else
+ {
+ return SvxFmDrawPage::CreateShape( pObj );
+ }
+
+}
+
+// XServiceInfo
+Sequence< OUString > SAL_CALL SdGenericDrawPage::getSupportedServiceNames()
+{
+ return comphelper::concatSequences(
+ SvxFmDrawPage::getSupportedServiceNames(),
+ std::initializer_list<std::u16string_view>{ u"com.sun.star.drawing.GenericDrawPage",
+ u"com.sun.star.document.LinkTarget",
+ u"com.sun.star.document.LinkTargetSupplier" });
+}
+
+// XLinkTargetSupplier
+Reference< container::XNameAccess > SAL_CALL SdGenericDrawPage::getLinks( )
+{
+ return new SdPageLinkTargets( this );
+}
+
+void SdGenericDrawPage::setBackground( const Any& )
+{
+ OSL_FAIL( "Don't call me, I'm useless!" );
+}
+
+void SdGenericDrawPage::getBackground( Any& )
+{
+ OSL_FAIL( "Don't call me, I'm useless!" );
+}
+
+OUString SdGenericDrawPage::getBookmarkURL() const
+{
+ OUStringBuffer aRet;
+ if( SvxFmDrawPage::mpPage )
+ {
+ OUString aFileName( static_cast<SdPage*>(SvxFmDrawPage::mpPage)->GetFileName() );
+ if( !aFileName.isEmpty() )
+ {
+ const OUString aBookmarkName( SdDrawPage::getPageApiNameFromUiName( static_cast<SdPage*>(SvxFmDrawPage::mpPage)->GetBookmarkName() ) );
+ aRet.append( aFileName );
+ aRet.append( '#' );
+ aRet.append( aBookmarkName );
+ }
+ }
+
+ return aRet.makeStringAndClear();
+}
+
+void SdGenericDrawPage::setBookmarkURL( std::u16string_view rURL )
+{
+ if( !SvxFmDrawPage::mpPage )
+ return;
+
+ size_t nIndex = rURL.find( '#' );
+ if( nIndex == std::u16string_view::npos )
+ return;
+
+ const OUString aFileName( rURL.substr( 0, nIndex ) );
+ const OUString aBookmarkName( SdDrawPage::getUiNameFromPageApiName( OUString(rURL.substr( nIndex+1 )) ) );
+
+ if( !aFileName.isEmpty() && !aBookmarkName.isEmpty() )
+ {
+ static_cast<SdPage*>(SvxFmDrawPage::mpPage)->DisconnectLink();
+ static_cast<SdPage*>(SvxFmDrawPage::mpPage)->SetFileName( aFileName );
+ static_cast<SdPage*>(SvxFmDrawPage::mpPage)->SetBookmarkName( aBookmarkName );
+ static_cast<SdPage*>(SvxFmDrawPage::mpPage)->ConnectLink();
+ }
+}
+
+Reference< drawing::XShape > SAL_CALL SdGenericDrawPage::combine( const Reference< drawing::XShapes >& xShapes )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ DBG_ASSERT(SvxFmDrawPage::mpPage,"SdrPage is NULL! [CL]");
+ DBG_ASSERT(mpView, "SdrView is NULL! [CL]");
+
+ Reference< drawing::XShape > xShape;
+ if(mpView==nullptr||!xShapes.is()||GetPage()==nullptr)
+ return xShape;
+
+ SdrPageView* pPageView = mpView->ShowSdrPage( GetPage() );
+
+ SelectObjectsInView( xShapes, pPageView );
+
+ mpView->CombineMarkedObjects( false );
+
+ mpView->AdjustMarkHdl();
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if( pObj )
+ xShape.set( pObj->getUnoShape(), UNO_QUERY );
+ }
+
+ mpView->HideSdrPage();
+
+ GetModel()->SetModified();
+
+ return xShape;
+}
+
+void SAL_CALL SdGenericDrawPage::split( const Reference< drawing::XShape >& xGroup )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if(mpView==nullptr||!xGroup.is()||GetPage()==nullptr)
+ return;
+
+ SdrPageView* pPageView = mpView->ShowSdrPage( GetPage() );
+ SelectObjectInView( xGroup, pPageView );
+ mpView->DismantleMarkedObjects();
+ mpView->HideSdrPage();
+
+ GetModel()->SetModified();
+}
+
+Reference< drawing::XShape > SAL_CALL SdGenericDrawPage::bind( const Reference< drawing::XShapes >& xShapes )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ uno::Reference< drawing::XShape > xShape;
+ if(mpView==nullptr||!xShapes.is()||GetPage()==nullptr)
+ return xShape;
+
+ SdrPageView* pPageView = mpView->ShowSdrPage( GetPage() );
+
+ SelectObjectsInView( xShapes, pPageView );
+
+ mpView->CombineMarkedObjects();
+
+ mpView->AdjustMarkHdl();
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if( pObj )
+ xShape.set( pObj->getUnoShape(), UNO_QUERY );
+ }
+
+ mpView->HideSdrPage();
+
+ GetModel()->SetModified();
+
+ return xShape;
+}
+
+void SAL_CALL SdGenericDrawPage::unbind( const Reference< drawing::XShape >& xShape )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if(mpView==nullptr||!xShape.is()||GetPage()==nullptr)
+ return;
+
+ SdrPageView* pPageView = mpView->ShowSdrPage( GetPage() );
+ SelectObjectInView( xShape, pPageView );
+ mpView->DismantleMarkedObjects( true );
+ mpView->HideSdrPage();
+
+ GetModel()->SetModified();
+}
+
+void SdGenericDrawPage::SetLeftBorder( sal_Int32 nValue )
+{
+ if( nValue == GetPage()->GetLeftBorder() )
+ return;
+
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(GetPage()->getSdrModelFromSdrPage()));
+ const PageKind ePageKind = GetPage()->GetPageKind();
+
+ sal_uInt16 i, nPageCnt = rDoc.GetMasterSdPageCount(ePageKind);
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetMasterSdPage(i, ePageKind);
+ pPage->SetLeftBorder( nValue );
+ }
+
+ nPageCnt = rDoc.GetSdPageCount(ePageKind);
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetSdPage(i, ePageKind);
+ pPage->SetLeftBorder( nValue );
+ }
+}
+
+void SdGenericDrawPage::SetRightBorder( sal_Int32 nValue )
+{
+ if( nValue == GetPage()->GetRightBorder() )
+ return;
+
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(GetPage()->getSdrModelFromSdrPage()));
+ const PageKind ePageKind = GetPage()->GetPageKind();
+
+ sal_uInt16 i, nPageCnt = rDoc.GetMasterSdPageCount(ePageKind);
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetMasterSdPage(i, ePageKind);
+ pPage->SetRightBorder( nValue );
+ }
+
+ nPageCnt = rDoc.GetSdPageCount(ePageKind);
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetSdPage(i, ePageKind);
+ pPage->SetRightBorder( nValue );
+ }
+}
+
+void SdGenericDrawPage::SetUpperBorder( sal_Int32 nValue )
+{
+ if( nValue == GetPage()->GetUpperBorder() )
+ return;
+
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(GetPage()->getSdrModelFromSdrPage()));
+ const PageKind ePageKind = GetPage()->GetPageKind();
+
+ sal_uInt16 i, nPageCnt = rDoc.GetMasterSdPageCount(ePageKind);
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetMasterSdPage(i, ePageKind);
+ pPage->SetUpperBorder( nValue );
+ }
+
+ nPageCnt = rDoc.GetSdPageCount(ePageKind);
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetSdPage(i, ePageKind);
+ pPage->SetUpperBorder( nValue );
+ }
+}
+
+void SdGenericDrawPage::SetLowerBorder( sal_Int32 nValue )
+{
+ if( nValue == GetPage()->GetLowerBorder() )
+ return;
+
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(GetPage()->getSdrModelFromSdrPage()));
+ const PageKind ePageKind = GetPage()->GetPageKind();
+
+ sal_uInt16 i, nPageCnt = rDoc.GetMasterSdPageCount(ePageKind);
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetMasterSdPage(i, ePageKind);
+ pPage->SetLowerBorder( nValue );
+ }
+
+ nPageCnt = rDoc.GetSdPageCount(ePageKind);
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetSdPage(i, ePageKind);
+ pPage->SetLowerBorder( nValue );
+ }
+}
+
+static void refreshpage( SdDrawDocument* pDoc, const PageKind ePageKind )
+{
+ ::sd::DrawDocShell* pDocShell = pDoc->GetDocSh();
+ if ( !pDocShell )
+ return;
+
+ ::sd::ViewShell* pViewSh = pDocShell->GetViewShell();
+
+ if( !pViewSh )
+ return;
+
+ if( auto pDrawViewShell = dynamic_cast<::sd::DrawViewShell* >(pViewSh) )
+ pDrawViewShell->ResetActualPage();
+
+ Size aPageSize = pDoc->GetSdPage(0, ePageKind)->GetSize();
+ const tools::Long nWidth = aPageSize.Width();
+ const tools::Long nHeight = aPageSize.Height();
+
+ Point aPageOrg(nWidth, nHeight / 2);
+ Size aViewSize(nWidth * 3, nHeight * 2);
+
+ pDoc->SetMaxObjSize(aViewSize);
+
+ pViewSh->InitWindows(aPageOrg, aViewSize, Point(-1, -1), true);
+
+ pViewSh->UpdateScrollBars();
+}
+
+void SdGenericDrawPage::SetWidth( sal_Int32 nWidth )
+{
+ Size aSize( GetPage()->GetSize() );
+ if( aSize.getWidth() == nWidth )
+ return;
+
+ aSize.setWidth( nWidth );
+
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(GetPage()->getSdrModelFromSdrPage()));
+ const PageKind ePageKind = GetPage()->GetPageKind();
+
+ sal_uInt16 i, nPageCnt = rDoc.GetMasterSdPageCount(ePageKind);
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetMasterSdPage(i, ePageKind);
+ pPage->SetSize(aSize);
+ }
+
+ nPageCnt = rDoc.GetSdPageCount(ePageKind);
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetSdPage(i, ePageKind);
+ pPage->SetSize(aSize);
+ }
+
+ refreshpage( &rDoc, ePageKind );
+}
+
+void SdGenericDrawPage::SetHeight( sal_Int32 nHeight )
+{
+ Size aSize( GetPage()->GetSize() );
+ if( aSize.getHeight() == nHeight )
+ return;
+
+ aSize.setHeight( nHeight );
+
+ SdDrawDocument& rDoc(static_cast< SdDrawDocument& >(GetPage()->getSdrModelFromSdrPage()));
+ const PageKind ePageKind = GetPage()->GetPageKind();
+
+ sal_uInt16 i, nPageCnt = rDoc.GetMasterSdPageCount(ePageKind);
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetMasterSdPage(i, ePageKind);
+ pPage->SetSize(aSize);
+ }
+
+ nPageCnt = rDoc.GetSdPageCount(ePageKind);
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = rDoc.GetSdPage(i, ePageKind);
+ pPage->SetSize(aSize);
+ }
+
+ refreshpage( &rDoc, ePageKind );
+}
+
+// XInterface
+void SdGenericDrawPage::release() noexcept
+{
+
+ OWeakAggObject::release();
+}
+
+// XComponent
+void SdGenericDrawPage::disposing() noexcept
+{
+ mpDocModel = nullptr;
+ SvxFmDrawPage::disposing();
+}
+
+// XAnimationNodeSupplier
+Reference< XAnimationNode > SAL_CALL SdGenericDrawPage::getAnimationNode()
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ SdPage *pSdPage = static_cast<SdPage*>(SvxFmDrawPage::mpPage);
+
+ return pSdPage->getAnimationNode();
+}
+
+// SdPageLinkTargets
+SdPageLinkTargets::SdPageLinkTargets( SdGenericDrawPage* pUnoPage ) noexcept
+{
+ mxPage = pUnoPage;
+ mpUnoPage = pUnoPage;
+}
+
+SdPageLinkTargets::~SdPageLinkTargets() noexcept
+{
+}
+
+// XElementAccess
+uno::Type SAL_CALL SdPageLinkTargets::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL SdPageLinkTargets::hasElements()
+{
+ ::SolarMutexGuard aGuard;
+
+ SdPage* pPage = mpUnoPage->GetPage();
+ if( pPage != nullptr )
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+
+ while( aIter.IsMore() )
+ {
+ SdrObject* pObj = aIter.Next();
+ OUString aStr( pObj->GetName() );
+ if( aStr.isEmpty() )
+ if (auto pOleObj = dynamic_cast< const SdrOle2Obj *>( pObj ))
+ aStr = pOleObj->GetPersistName();
+ if( !aStr.isEmpty() )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// container::XNameAccess
+
+// XNameAccess
+Any SAL_CALL SdPageLinkTargets::getByName( const OUString& aName )
+{
+ ::SolarMutexGuard aGuard;
+
+ SdPage* pPage = mpUnoPage->GetPage();
+ if( pPage != nullptr )
+ {
+ SdrObject* pObj = FindObject( aName );
+ if( pObj )
+ {
+ Reference< beans::XPropertySet > aRef( pObj->getUnoShape(), uno::UNO_QUERY );
+ return Any( aRef );
+ }
+ }
+
+ throw container::NoSuchElementException();
+}
+
+Sequence< OUString > SAL_CALL SdPageLinkTargets::getElementNames()
+{
+ ::SolarMutexGuard aGuard;
+
+ sal_uInt32 nObjCount = 0;
+
+ SdPage* pPage = mpUnoPage->GetPage();
+ if( pPage != nullptr )
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ while( aIter.IsMore() )
+ {
+ SdrObject* pObj = aIter.Next();
+ OUString aStr( pObj->GetName() );
+ if( aStr.isEmpty() )
+ if (auto pOleObj = dynamic_cast< const SdrOle2Obj *>( pObj ))
+ aStr = pOleObj->GetPersistName();
+ if( !aStr.isEmpty() )
+ nObjCount++;
+ }
+ }
+
+ Sequence< OUString > aSeq( nObjCount );
+ if( nObjCount > 0 )
+ {
+ OUString* pStr = aSeq.getArray();
+
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ while( aIter.IsMore() )
+ {
+ SdrObject* pObj = aIter.Next();
+ OUString aStr( pObj->GetName() );
+ if( aStr.isEmpty() )
+ if (auto pOleObj = dynamic_cast< const SdrOle2Obj *>( pObj ))
+ aStr = pOleObj->GetPersistName();
+ if( !aStr.isEmpty() )
+ *pStr++ = aStr;
+ }
+ }
+
+ return aSeq;
+}
+
+sal_Bool SAL_CALL SdPageLinkTargets::hasByName( const OUString& aName )
+{
+ ::SolarMutexGuard aGuard;
+
+ return FindObject( aName ) != nullptr;
+}
+
+SdrObject* SdPageLinkTargets::FindObject( std::u16string_view rName ) const noexcept
+{
+ SdPage* pPage = mpUnoPage->GetPage();
+ if( pPage == nullptr )
+ return nullptr;
+
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+
+ while( aIter.IsMore() )
+ {
+ SdrObject* pObj = aIter.Next();
+ OUString aStr( pObj->GetName() );
+ if( aStr.isEmpty() )
+ if (auto pOleObj = dynamic_cast< const SdrOle2Obj *>( pObj ))
+ aStr = pOleObj->GetPersistName();
+ if( !aStr.isEmpty() && (aStr == rName) )
+ return pObj;
+ }
+
+ return nullptr;
+}
+
+// XServiceInfo
+OUString SAL_CALL SdPageLinkTargets::getImplementationName()
+{
+ return "SdPageLinkTargets";
+}
+
+sal_Bool SAL_CALL SdPageLinkTargets::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+Sequence< OUString > SAL_CALL SdPageLinkTargets::getSupportedServiceNames()
+{
+ return { "com.sun.star.document.LinkTargets" };
+}
+
+// SdDrawPage
+SdDrawPage::SdDrawPage(SdXImpressDocument* pModel, SdPage* pPage)
+ : SdGenericDrawPage( pModel, pPage, ImplGetDrawPagePropertySet( pModel->IsImpressDocument(), pPage->GetPageKind() ) )
+{
+}
+
+SdDrawPage::~SdDrawPage() noexcept
+{
+}
+
+// XInterface
+Any SAL_CALL SdDrawPage::queryInterface( const uno::Type & rType )
+{
+ if( rType == cppu::UnoType<drawing::XMasterPageTarget>::get() )
+ {
+ return Any( Reference< drawing::XMasterPageTarget >( this ) );
+ }
+ else if( IsImpressDocument()
+ && rType == cppu::UnoType<presentation::XPresentationPage>::get() )
+ {
+ SdPage * p = dynamic_cast<SdPage *>(SvxDrawPage::mpPage);
+ if( p == nullptr || p->GetPageKind() != PageKind::Handout )
+ {
+ return Any( Reference< presentation::XPresentationPage >( this ) );
+ }
+ }
+
+ return SdGenericDrawPage::queryInterface( rType );
+}
+
+void SAL_CALL SdDrawPage::acquire() noexcept
+{
+ SvxDrawPage::acquire();
+}
+
+void SAL_CALL SdDrawPage::release() noexcept
+{
+ SvxDrawPage::release();
+}
+
+UNO3_GETIMPLEMENTATION2_IMPL( SdDrawPage, SdGenericDrawPage );
+
+// XTypeProvider
+Sequence< uno::Type > SAL_CALL SdDrawPage::getTypes()
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if( !maTypeSequence.hasElements() )
+ {
+ const PageKind ePageKind = GetPage() ? GetPage()->GetPageKind() : PageKind::Standard;
+ bool bPresPage = IsImpressDocument() && ePageKind != PageKind::Handout;
+
+ // Collect the types of this class.
+ ::std::vector<uno::Type> aTypes;
+ aTypes.reserve(13);
+ aTypes.push_back(cppu::UnoType<drawing::XDrawPage>::get());
+ aTypes.push_back(cppu::UnoType<beans::XPropertySet>::get());
+ aTypes.push_back(cppu::UnoType<container::XNamed>::get());
+ aTypes.push_back(cppu::UnoType<drawing::XMasterPageTarget>::get());
+ aTypes.push_back(cppu::UnoType<lang::XServiceInfo>::get());
+ aTypes.push_back(cppu::UnoType<util::XReplaceable>::get());
+ aTypes.push_back(cppu::UnoType<document::XLinkTargetSupplier>::get());
+ aTypes.push_back(cppu::UnoType<drawing::XShapeCombiner>::get());
+ aTypes.push_back(cppu::UnoType<drawing::XShapeBinder>::get());
+ aTypes.push_back(cppu::UnoType<office::XAnnotationAccess>::get());
+ aTypes.push_back(cppu::UnoType<beans::XMultiPropertySet>::get());
+ if( bPresPage )
+ aTypes.push_back(cppu::UnoType<presentation::XPresentationPage>::get());
+ if( bPresPage && ePageKind == PageKind::Standard )
+ aTypes.push_back(cppu::UnoType<XAnimationNodeSupplier>::get());
+
+ // Get types of base class.
+ // Join those types in a sequence.
+ return comphelper::concatSequences(
+ comphelper::containerToSequence(aTypes),
+ SdGenericDrawPage::getTypes() );
+ }
+
+ return maTypeSequence;
+}
+
+Sequence< sal_Int8 > SAL_CALL SdDrawPage::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+OUString SdDrawPage::getPageApiName( SdPage const * pPage )
+{
+ return ::getPageApiName( pPage );
+}
+
+OUString getPageApiName( SdPage const * pPage )
+{
+ OUString aPageName;
+
+ if(pPage)
+ {
+ aPageName = pPage->GetRealName();
+
+ if( aPageName.isEmpty() )
+ {
+ const sal_Int32 nPageNum = ( ( pPage->GetPageNum() - 1 ) >> 1 ) + 1;
+ aPageName = sEmptyPageName + OUString::number( nPageNum );
+ }
+ }
+
+ return aPageName;
+}
+
+OUString getPageApiNameFromUiName( const OUString& rUIName )
+{
+ OUString aApiName;
+
+ OUString aDefPageName(SdResId(STR_PAGE) + " ");
+
+ if( rUIName.startsWith( aDefPageName ) )
+ {
+ aApiName = OUString::Concat(sEmptyPageName) + rUIName.subView( aDefPageName.getLength() );
+ }
+ else
+ {
+ aApiName = rUIName;
+ }
+
+ return aApiName;
+}
+
+OUString SdDrawPage::getPageApiNameFromUiName( const OUString& rUIName )
+{
+ return ::getPageApiNameFromUiName( rUIName );
+}
+
+OUString getUiNameFromPageApiNameImpl( const OUString& rApiName )
+{
+ const OUString aDefPageName( sEmptyPageName );
+ if( rApiName.startsWith( aDefPageName ) )
+ {
+ std::u16string_view aNumber( rApiName.subView( aDefPageName.getLength() ) );
+
+ // create the page number
+ sal_Int32 nPageNumber = o3tl::toInt32(aNumber);
+
+ // check if there are non number characters in the number part
+ const size_t nChars = aNumber.size();
+ const sal_Unicode* pString = aNumber.data();
+ for( size_t nChar = 0; nChar < nChars; nChar++, pString++ )
+ {
+ if((*pString < '0') || (*pString > '9'))
+ {
+ // found a non number character, so this is not the default
+ // name for this page
+ nPageNumber = -1;
+ break;
+ }
+ }
+
+ if( nPageNumber != -1)
+ {
+ return SdResId(STR_PAGE) + " " + aNumber;
+ }
+ }
+
+ return rApiName;
+}
+
+OUString SdDrawPage::getUiNameFromPageApiName( const OUString& rApiName )
+{
+ return getUiNameFromPageApiNameImpl( rApiName );
+}
+
+// XServiceInfo
+OUString SAL_CALL SdDrawPage::getImplementationName()
+{
+ return "SdDrawPage";
+}
+
+Sequence< OUString > SAL_CALL SdDrawPage::getSupportedServiceNames()
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ std::vector<std::u16string_view> aAdd{ u"com.sun.star.drawing.DrawPage" };
+
+ if( IsImpressDocument() )
+ aAdd.emplace_back(u"com.sun.star.presentation.DrawPage");
+
+ return comphelper::concatSequences(SdGenericDrawPage::getSupportedServiceNames(), aAdd);
+}
+
+sal_Bool SAL_CALL SdDrawPage::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+// XNamed
+void SAL_CALL SdDrawPage::setName( const OUString& rName )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ DBG_ASSERT( GetPage() && !GetPage()->IsMasterPage(), "Don't call base implementation for masterpages!" );
+
+ OUString aName( rName );
+
+ if(!(GetPage() && GetPage()->GetPageKind() != PageKind::Notes))
+ return;
+
+ // check if this is the default 'page1234' name
+ OUString aNumber;
+ if(aName.startsWith( sEmptyPageName, &aNumber ))
+ {
+ // ok, it maybe is, aNumber is the number part after 'page'
+
+ // create the page number
+ sal_Int32 nPageNumber = aNumber.toInt32();
+
+ // check if there are non number characters in the number part
+ const sal_Int32 nChars = aNumber.getLength();
+ const sal_Unicode* pString = aNumber.getStr();
+ sal_Int32 nChar;
+ for( nChar = 0; nChar < nChars; nChar++, pString++ )
+ {
+ if((*pString < '0') || (*pString > '9'))
+ {
+ // found a non number character, so this is not the default
+ // name for this page
+ nPageNumber = -1;
+ break;
+ }
+ }
+
+ if( nPageNumber == ( ( GetPage()->GetPageNum() - 1 ) >> 1 ) + 1 )
+ aName.clear();
+ }
+ else
+ {
+ OUString aDefaultPageName( SdResId(STR_PAGE) + " " );
+ if( aName.startsWith( aDefaultPageName ) )
+ aName.clear();
+ }
+
+ GetPage()->SetName( aName );
+
+ sal_uInt16 nNotesPageNum = (GetPage()->GetPageNum()-1)>>1;
+ if( GetModel()->GetDoc()->GetSdPageCount( PageKind::Notes ) > nNotesPageNum )
+ {
+ SdPage* pNotesPage = GetModel()->GetDoc()->GetSdPage( nNotesPageNum, PageKind::Notes );
+ if( pNotesPage )
+ pNotesPage->SetName(aName);
+ }
+
+ // fake a mode change to repaint the page tab bar
+ ::sd::DrawDocShell* pDocSh = GetModel()->GetDocShell();
+ ::sd::ViewShell* pViewSh = pDocSh ? pDocSh->GetViewShell() : nullptr;
+ if( auto pDrawViewSh = dynamic_cast<::sd::DrawViewShell* >(pViewSh) )
+ {
+ EditMode eMode = pDrawViewSh->GetEditMode();
+ if( eMode == EditMode::Page )
+ {
+ bool bLayer = pDrawViewSh->IsLayerModeActive();
+
+ pDrawViewSh->ChangeEditMode( eMode, !bLayer );
+ pDrawViewSh->ChangeEditMode( eMode, bLayer );
+ }
+ }
+
+ GetModel()->SetModified();
+}
+
+OUString SAL_CALL SdDrawPage::getName()
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ return getPageApiName( GetPage() );
+}
+
+// XMasterPageTarget
+Reference< drawing::XDrawPage > SAL_CALL SdDrawPage::getMasterPage( )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if(GetPage())
+ {
+ Reference< drawing::XDrawPage > xPage;
+
+ if(SvxFmDrawPage::mpPage->TRG_HasMasterPage())
+ {
+ SdrPage& rMasterPage = SvxFmDrawPage::mpPage->TRG_GetMasterPage();
+ xPage.set( rMasterPage.getUnoPage(), uno::UNO_QUERY );
+ }
+
+ return xPage;
+ }
+ return nullptr;
+}
+
+void SAL_CALL SdDrawPage::setMasterPage( const Reference< drawing::XDrawPage >& xMasterPage )
+{
+ ::SolarMutexGuard aGuard;
+ comphelper::ProfileZone aZone("setMasterPage");
+
+ throwIfDisposed();
+
+ if(!SvxFmDrawPage::mpPage)
+ return;
+
+ SdMasterPage* pMasterPage = comphelper::getFromUnoTunnel<SdMasterPage>( xMasterPage );
+ if( !(pMasterPage && pMasterPage->isValid()) )
+ return;
+
+ SvxFmDrawPage::mpPage->TRG_ClearMasterPage();
+
+ SdPage* pSdPage = static_cast<SdPage*>(pMasterPage->GetSdrPage());
+ SvxFmDrawPage::mpPage->TRG_SetMasterPage(*pSdPage);
+
+ SvxFmDrawPage::mpPage->SetBorder(pSdPage->GetLeftBorder(),pSdPage->GetUpperBorder(),
+ pSdPage->GetRightBorder(),pSdPage->GetLowerBorder() );
+
+ SvxFmDrawPage::mpPage->SetSize( pSdPage->GetSize() );
+ SvxFmDrawPage::mpPage->SetOrientation( pSdPage->GetOrientation() );
+ static_cast<SdPage*>(SvxFmDrawPage::mpPage)->SetLayoutName( pSdPage->GetLayoutName() );
+
+ // set notes master also
+ SdPage* pNotesPage = GetModel()->GetDoc()->GetSdPage( (SvxFmDrawPage::mpPage->GetPageNum()-1)>>1, PageKind::Notes );
+
+ pNotesPage->TRG_ClearMasterPage();
+ sal_uInt16 nNum = SvxFmDrawPage::mpPage->TRG_GetMasterPage().GetPageNum() + 1;
+ pNotesPage->TRG_SetMasterPage(*SvxFmDrawPage::mpPage->getSdrModelFromSdrPage().GetMasterPage(nNum));
+ pNotesPage->SetLayoutName( pSdPage->GetLayoutName() );
+
+ GetModel()->SetModified();
+}
+
+// XPresentationPage
+Reference< drawing::XDrawPage > SAL_CALL SdDrawPage::getNotesPage()
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if(SvxFmDrawPage::mpPage && GetModel()->GetDoc() && SvxFmDrawPage::mpPage->GetPageNum() )
+ {
+ SdPage* pNotesPage = GetModel()->GetDoc()->GetSdPage( (SvxFmDrawPage::mpPage->GetPageNum()-1)>>1, PageKind::Notes );
+ if( pNotesPage )
+ {
+ Reference< drawing::XDrawPage > xPage( pNotesPage->getUnoPage(), uno::UNO_QUERY );
+ return xPage;
+ }
+ }
+ return nullptr;
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SdDrawPage::getCount()
+{
+ return SdGenericDrawPage::getCount();
+}
+
+Any SAL_CALL SdDrawPage::getByIndex( sal_Int32 Index )
+{
+ return SdGenericDrawPage::getByIndex( Index );
+}
+
+// XElementAccess
+uno::Type SAL_CALL SdDrawPage::getElementType()
+{
+ return SdGenericDrawPage::getElementType();
+}
+
+sal_Bool SAL_CALL SdDrawPage::hasElements()
+{
+ return SdGenericDrawPage::hasElements();
+}
+
+// XShapes
+void SAL_CALL SdDrawPage::add( const Reference< drawing::XShape >& xShape )
+{
+ SdGenericDrawPage::add( xShape );
+}
+
+void SAL_CALL SdDrawPage::remove( const Reference< drawing::XShape >& xShape )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape( xShape );
+ if( pObj )
+ {
+ GetPage()->RemovePresObj(pObj);
+ pObj->SetUserCall(nullptr);
+ }
+
+ SdGenericDrawPage::remove( xShape );
+}
+
+void SdDrawPage::setBackground( const Any& rValue )
+{
+ Reference< beans::XPropertySet > xSet;
+
+ if( !(rValue >>= xSet) && !rValue.hasValue() )
+ throw lang::IllegalArgumentException();
+
+ if( !xSet.is() )
+ {
+ // the easy case, no background set. Set drawing::FillStyle_NONE to represent this
+ GetPage()->getSdrPageProperties().PutItem(XFillStyleItem(drawing::FillStyle_NONE));
+ return;
+ }
+
+ // is it our own implementation?
+ SdUnoPageBackground* pBack = comphelper::getFromUnoTunnel<SdUnoPageBackground>( xSet );
+
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aSet( GetModel()->GetDoc()->GetPool() );
+
+ if( pBack )
+ {
+ pBack->fillItemSet( static_cast<SdDrawDocument*>(&GetPage()->getSdrModelFromSdrPage()), aSet );
+ }
+ else
+ {
+ rtl::Reference<SdUnoPageBackground> pBackground = new SdUnoPageBackground();
+
+ Reference< beans::XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
+ Reference< beans::XPropertySetInfo > xDestSetInfo( pBackground->getPropertySetInfo() );
+
+ const Sequence< beans::Property > aProperties( xDestSetInfo->getProperties() );
+
+ for( const beans::Property& rProp : aProperties )
+ {
+ const OUString aPropName( rProp.Name );
+ if( xSetInfo->hasPropertyByName( aPropName ) )
+ pBackground->setPropertyValue( aPropName,
+ xSet->getPropertyValue( aPropName ) );
+ }
+
+ pBackground->fillItemSet( static_cast<SdDrawDocument*>(&GetPage()->getSdrModelFromSdrPage()), aSet );
+ }
+
+ if( aSet.Count() == 0 )
+ {
+ // no background fill, represent by setting drawing::FillStyle_NONE
+ GetPage()->getSdrPageProperties().PutItem(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ else
+ {
+ // background fill, set at page (not sure if ClearItem is needed)
+ GetPage()->getSdrPageProperties().ClearItem();
+ GetPage()->getSdrPageProperties().PutItemSet(aSet);
+ }
+
+ // repaint only
+ SvxFmDrawPage::mpPage->ActionChanged();
+}
+
+// XAnnotationAccess:
+Reference< XAnnotation > SAL_CALL SdGenericDrawPage::createAndInsertAnnotation()
+{
+ if( !GetPage() )
+ throw DisposedException();
+
+ Reference< XAnnotation > xRet;
+ GetPage()->createAnnotation(xRet);
+ return xRet;
+}
+
+void SAL_CALL SdGenericDrawPage::removeAnnotation(const Reference< XAnnotation > & annotation)
+{
+ GetPage()->removeAnnotation(annotation);
+}
+
+Reference< XAnnotationEnumeration > SAL_CALL SdGenericDrawPage::createAnnotationEnumeration()
+{
+ return ::sd::createAnnotationEnumeration( std::vector(GetPage()->getAnnotations()) );
+}
+
+void SdDrawPage::getBackground(Any& rValue)
+{
+ const SfxItemSet& rFillAttributes = GetPage()->getSdrPageProperties().GetItemSet();
+
+ if(drawing::FillStyle_NONE == rFillAttributes.Get(XATTR_FILLSTYLE).GetValue())
+ {
+ // no fill set (switched off by drawing::FillStyle_NONE), clear rValue to represent this
+ rValue.clear();
+ }
+ else
+ {
+ // there is a fill set, export to rValue
+ Reference< beans::XPropertySet > xSet(new SdUnoPageBackground(
+ GetModel()->GetDoc(),
+ &GetPage()->getSdrPageProperties().GetItemSet()));
+ rValue <<= xSet;
+ }
+}
+
+void SdGenericDrawPage::setNavigationOrder( const Any& rValue )
+{
+ Reference< XIndexAccess > xIA( rValue, UNO_QUERY );
+ if( xIA.is() )
+ {
+ if( dynamic_cast< SdDrawPage* >( xIA.get() ) == this )
+ {
+ if( GetPage()->HasObjectNavigationOrder() )
+ GetPage()->ClearObjectNavigationOrder();
+
+ return;
+ }
+ else if( static_cast<size_t>(xIA->getCount()) == GetPage()->GetObjCount() )
+ {
+ GetPage()->SetNavigationOrder(xIA);
+ return;
+ }
+ }
+ throw IllegalArgumentException();
+}
+
+namespace {
+
+class SdNavigationOrderAccess : public ::cppu::WeakImplHelper< XIndexAccess >
+{
+public:
+ explicit SdNavigationOrderAccess(SdrPage const * pPage);
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+private:
+ std::vector< Reference< XShape > > maShapes;
+};
+
+}
+
+SdNavigationOrderAccess::SdNavigationOrderAccess( SdrPage const * pPage )
+: maShapes( pPage ? pPage->GetObjCount() : 0 )
+{
+ if( pPage )
+ {
+ const size_t nCount = pPage->GetObjCount();
+ for( size_t nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ SdrObject* pObj = pPage->GetObj( nIndex );
+ sal_uInt32 nNavPos = pObj->GetNavigationPosition();
+ DBG_ASSERT( !maShapes[nNavPos].is(), "sd::SdNavigationOrderAccess::SdNavigationOrderAccess(), duplicate navigation positions from core!" );
+ maShapes[nNavPos].set( pObj->getUnoShape(), UNO_QUERY );
+ }
+ }
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SdNavigationOrderAccess::getCount( )
+{
+ return static_cast< sal_Int32 >( maShapes.size() );
+}
+
+Any SAL_CALL SdNavigationOrderAccess::getByIndex( sal_Int32 Index )
+{
+ if( (Index < 0) || (Index > getCount()) )
+ throw IndexOutOfBoundsException();
+
+ return Any( maShapes[Index] );
+}
+
+// XElementAccess
+Type SAL_CALL SdNavigationOrderAccess::getElementType( )
+{
+ return cppu::UnoType<XShape>::get();
+}
+
+sal_Bool SAL_CALL SdNavigationOrderAccess::hasElements( )
+{
+ return !maShapes.empty();
+}
+
+Any SdGenericDrawPage::getNavigationOrder()
+{
+ if( GetPage()->HasObjectNavigationOrder() )
+ {
+ return Any( Reference< XIndexAccess >( new SdNavigationOrderAccess( GetPage() ) ) );
+ }
+ else
+ {
+ return Any( Reference< XIndexAccess >( this ) );
+ }
+}
+
+SdMasterPage::SdMasterPage(SdXImpressDocument* pModel, SdPage* pPage)
+ : SdGenericDrawPage(pModel, pPage, ImplGetMasterPagePropertySet(pPage->GetPageKind()))
+{
+}
+
+SdMasterPage::~SdMasterPage() noexcept
+{
+}
+
+// XInterface
+Any SAL_CALL SdMasterPage::queryInterface( const uno::Type & rType )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ uno::Any aAny;
+
+ if( rType == cppu::UnoType<container::XIndexAccess>::get() )
+ aAny <<= Reference< container::XIndexAccess >(static_cast<presentation::XPresentationPage*>(this));
+ else if( rType == cppu::UnoType<container::XElementAccess>::get() )
+ aAny <<= Reference< container::XElementAccess >(static_cast<presentation::XPresentationPage*>(this));
+ else if( rType == cppu::UnoType<container::XNamed>::get() )
+ aAny <<= Reference< container::XNamed >(this);
+ else if( rType == cppu::UnoType<presentation::XPresentationPage>::get() &&
+ ( IsImpressDocument() &&
+ GetPage() && GetPage()->GetPageKind() != PageKind::Handout) )
+ aAny <<= Reference< presentation::XPresentationPage >( this );
+ else
+ return SdGenericDrawPage::queryInterface( rType );
+
+ return aAny;
+}
+
+void SAL_CALL SdMasterPage::acquire() noexcept
+{
+ SvxDrawPage::acquire();
+}
+
+void SAL_CALL SdMasterPage::release() noexcept
+{
+ SvxDrawPage::release();
+}
+
+UNO3_GETIMPLEMENTATION2_IMPL( SdMasterPage, SdGenericDrawPage );
+
+// XTypeProvider
+Sequence< uno::Type > SAL_CALL SdMasterPage::getTypes()
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if( !maTypeSequence.hasElements() )
+ {
+ const PageKind ePageKind = GetPage() ? GetPage()->GetPageKind() : PageKind::Standard;
+ bool bPresPage = IsImpressDocument() && SvxFmDrawPage::mpPage && ePageKind != PageKind::Handout;
+
+ // Collect the types of this class.
+ ::std::vector<uno::Type> aTypes;
+ aTypes.reserve(12);
+ aTypes.push_back(cppu::UnoType<drawing::XDrawPage>::get());
+ aTypes.push_back(cppu::UnoType<beans::XPropertySet>::get());
+ aTypes.push_back(cppu::UnoType<container::XNamed>::get());
+ aTypes.push_back(cppu::UnoType<lang::XServiceInfo>::get());
+ aTypes.push_back(cppu::UnoType<util::XReplaceable>::get());
+ aTypes.push_back(cppu::UnoType<document::XLinkTargetSupplier>::get());
+ aTypes.push_back(cppu::UnoType<drawing::XShapeCombiner>::get());
+ aTypes.push_back(cppu::UnoType<drawing::XShapeBinder>::get());
+ aTypes.push_back(cppu::UnoType<office::XAnnotationAccess>::get());
+ aTypes.push_back(cppu::UnoType<beans::XMultiPropertySet>::get());
+ if( bPresPage )
+ aTypes.push_back(cppu::UnoType<presentation::XPresentationPage>::get());
+ if( bPresPage && ePageKind == PageKind::Standard )
+ aTypes.push_back(cppu::UnoType<XAnimationNodeSupplier>::get());
+
+ // Get types of base class.
+ // Join those types in a sequence.
+ return comphelper::concatSequences(
+ comphelper::containerToSequence(aTypes),
+ SdGenericDrawPage::getTypes() );
+ }
+
+ return maTypeSequence;
+}
+
+Sequence< sal_Int8 > SAL_CALL SdMasterPage::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XServiceInfo
+OUString SAL_CALL SdMasterPage::getImplementationName()
+{
+ return "SdMasterPage";
+}
+
+Sequence< OUString > SAL_CALL SdMasterPage::getSupportedServiceNames()
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ std::vector<std::u16string_view> aAdd{ u"com.sun.star.drawing.MasterPage" };
+
+ if( SvxFmDrawPage::mpPage && static_cast<SdPage*>(SvxFmDrawPage::mpPage)->GetPageKind() == PageKind::Handout )
+ aAdd.emplace_back(u"com.sun.star.presentation.HandoutMasterPage");
+
+ return comphelper::concatSequences(SdGenericDrawPage::getSupportedServiceNames(), aAdd);
+}
+
+sal_Bool SAL_CALL SdMasterPage::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+// XElementAccess
+sal_Bool SAL_CALL SdMasterPage::hasElements()
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if( SvxFmDrawPage::mpPage == nullptr )
+ return false;
+
+ return SvxFmDrawPage::mpPage->GetObjCount() > 0;
+}
+
+uno::Type SAL_CALL SdMasterPage::getElementType()
+{
+ return SdGenericDrawPage::getElementType();
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SdMasterPage::getCount()
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ return SdGenericDrawPage::getCount();
+}
+
+Any SAL_CALL SdMasterPage::getByIndex( sal_Int32 Index )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ return SdGenericDrawPage::getByIndex(Index);
+}
+
+// intern
+void SdMasterPage::setBackground( const Any& rValue )
+{
+ // we need at least a beans::XPropertySet
+ Reference< beans::XPropertySet > xInputSet( rValue, UNO_QUERY );
+ if( !xInputSet.is() )
+ throw lang::IllegalArgumentException();
+
+ try
+ {
+ if( GetModel() && IsImpressDocument() )
+ {
+ Reference< container::XNameAccess > xFamilies( GetModel()->getStyleFamilies(), UNO_SET_THROW );
+ Reference< container::XNameAccess > xFamily( xFamilies->getByName( getName() ), UNO_QUERY_THROW ) ;
+
+ Reference< beans::XPropertySet > xStyleSet( xFamily->getByName( sUNO_PseudoSheet_Background ), UNO_QUERY_THROW );
+
+ Reference< beans::XPropertySetInfo > xSetInfo( xInputSet->getPropertySetInfo(), UNO_SET_THROW );
+ Reference< beans::XPropertyState > xSetStates( xInputSet, UNO_QUERY );
+
+ for( const auto pProp : ImplGetPageBackgroundPropertySet()->getPropertyMap().getPropertyEntries() )
+ {
+ const OUString& rPropName = pProp->aName;
+ if( xSetInfo->hasPropertyByName( rPropName ) )
+ {
+ if( !xSetStates.is() || xSetStates->getPropertyState( rPropName ) == beans::PropertyState_DIRECT_VALUE )
+ xStyleSet->setPropertyValue( rPropName, xInputSet->getPropertyValue( rPropName ) );
+ else
+ xSetStates->setPropertyToDefault( rPropName );
+ }
+ }
+ }
+ else
+ {
+ // first fill an item set
+ // is it our own implementation?
+ SdUnoPageBackground* pBack = comphelper::getFromUnoTunnel<SdUnoPageBackground>( xInputSet );
+
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aSet( GetModel()->GetDoc()->GetPool() );
+
+ if( pBack )
+ {
+ pBack->fillItemSet( static_cast<SdDrawDocument*>(&GetPage()->getSdrModelFromSdrPage()), aSet );
+ }
+ else
+ {
+ rtl::Reference<SdUnoPageBackground> pBackground = new SdUnoPageBackground();
+
+ Reference< beans::XPropertySetInfo > xInputSetInfo( xInputSet->getPropertySetInfo(), UNO_SET_THROW );
+ Reference< beans::XPropertySetInfo > xDestSetInfo( pBackground->getPropertySetInfo(), UNO_SET_THROW );
+
+ const uno::Sequence< beans::Property> aProperties( xDestSetInfo->getProperties() );
+
+ for( const beans::Property& rProp : aProperties )
+ {
+ const OUString aPropName( rProp.Name );
+ if( xInputSetInfo->hasPropertyByName( aPropName ) )
+ pBackground->setPropertyValue( aPropName, xInputSet->getPropertyValue( aPropName ) );
+ }
+
+ pBackground->fillItemSet( static_cast<SdDrawDocument*>(&SvxFmDrawPage::mpPage->getSdrModelFromSdrPage()), aSet );
+ }
+
+ // if we find the background style, copy the set to the background
+ SdDrawDocument* pDoc = static_cast<SdDrawDocument*>(&SvxFmDrawPage::mpPage->getSdrModelFromSdrPage());
+ SfxStyleSheetBasePool* pSSPool = pDoc->GetStyleSheetPool();
+ if(pSSPool)
+ {
+ OUString aLayoutName( static_cast< SdPage* >( SvxFmDrawPage::mpPage )->GetLayoutName() );
+ aLayoutName = OUString::Concat(aLayoutName.subView(0, aLayoutName.indexOf(SD_LT_SEPARATOR)+4)) +
+ STR_LAYOUT_BACKGROUND;
+ SfxStyleSheetBase* pStyleSheet = pSSPool->Find( aLayoutName, SfxStyleFamily::Page );
+
+ if( pStyleSheet )
+ {
+ pStyleSheet->GetItemSet().Put( aSet );
+
+ // repaint only
+ SvxFmDrawPage::mpPage->ActionChanged();
+ return;
+ }
+ }
+
+ // if no background style is available, set at page directly. This
+ // is an error and should NOT happen (and will be asserted from the SdrPage)
+ GetPage()->getSdrPageProperties().PutItemSet(aSet);
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SdMasterPage::setBackground()");
+ }
+}
+
+void SdMasterPage::getBackground( Any& rValue )
+{
+ if( !GetModel() )
+ return;
+
+ try
+ {
+ if( IsImpressDocument() )
+ {
+ Reference< container::XNameAccess > xFamilies( GetModel()->getStyleFamilies(), UNO_SET_THROW );
+ Reference< container::XNameAccess > xFamily( xFamilies->getByName( getName() ), UNO_QUERY_THROW );
+
+ rValue <<= Reference< beans::XPropertySet >( xFamily->getByName( sUNO_PseudoSheet_Background ), UNO_QUERY_THROW );
+ }
+ else
+ {
+ SdDrawDocument* pDoc = static_cast<SdDrawDocument*>(&SvxFmDrawPage::mpPage->getSdrModelFromSdrPage());
+ SfxStyleSheetBasePool* pSSPool = pDoc->GetStyleSheetPool();
+ if(pSSPool)
+ {
+ OUString aLayoutName( static_cast< SdPage* >(SvxFmDrawPage::mpPage)->GetLayoutName() );
+ aLayoutName = OUString::Concat(aLayoutName.subView(0, aLayoutName.indexOf(SD_LT_SEPARATOR)+4)) +
+ STR_LAYOUT_BACKGROUND;
+ SfxStyleSheetBase* pStyleSheet = pSSPool->Find( aLayoutName, SfxStyleFamily::Page );
+
+ if( pStyleSheet )
+ {
+ SfxItemSet aStyleSet( pStyleSheet->GetItemSet());
+ if( aStyleSet.Count() )
+ {
+ rValue <<= Reference< beans::XPropertySet >( new SdUnoPageBackground( pDoc, &aStyleSet ) );
+ return;
+ }
+ }
+ }
+
+ // No style found, use fill attributes from page background. This
+ // should NOT happen and is an error
+ const SfxItemSet& rFallbackItemSet(SvxFmDrawPage::mpPage->getSdrPageProperties().GetItemSet());
+
+ if(drawing::FillStyle_NONE == rFallbackItemSet.Get(XATTR_FILLSTYLE).GetValue())
+ {
+ rValue <<= Reference< beans::XPropertySet >(
+ new SdUnoPageBackground(GetModel()->GetDoc(), &rFallbackItemSet));
+ }
+ else
+ {
+ rValue.clear();
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::SdMasterPage::getBackground()");
+ rValue.clear();
+ }
+}
+
+// XNamed
+void SAL_CALL SdMasterPage::setName( const OUString& rName )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if(!(SvxFmDrawPage::mpPage && GetPage()->GetPageKind() != PageKind::Notes))
+ return;
+
+ SdDrawDocument* pDoc = GetModel()->GetDoc();
+ bool bOutDummy;
+
+ // Slide Name has to be unique
+ if( pDoc && pDoc->GetPageByName( rName, bOutDummy ) != SDRPAGE_NOTFOUND )
+ return; // throw Exception ?
+
+ GetPage()->SetName( rName );
+
+ if( pDoc )
+ pDoc->RenameLayoutTemplate( GetPage()->GetLayoutName(), rName );
+
+ // fake a mode change to repaint the page tab bar
+ ::sd::DrawDocShell* pDocSh = GetModel()->GetDocShell();
+ ::sd::ViewShell* pViewSh = pDocSh ? pDocSh->GetViewShell() : nullptr;
+ if( auto pDrawViewSh = dynamic_cast< ::sd::DrawViewShell* >(pViewSh) )
+ {
+ EditMode eMode = pDrawViewSh->GetEditMode();
+ if( eMode == EditMode::MasterPage )
+ {
+ bool bLayer = pDrawViewSh->IsLayerModeActive();
+
+ pDrawViewSh->ChangeEditMode( eMode, !bLayer );
+ pDrawViewSh->ChangeEditMode( eMode, bLayer );
+ }
+ }
+
+ GetModel()->SetModified();
+}
+
+OUString SAL_CALL SdMasterPage::getName( )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if(SvxFmDrawPage::mpPage)
+ {
+ OUString aLayoutName( GetPage()->GetLayoutName() );
+ return aLayoutName.copy(0, aLayoutName.indexOf(SD_LT_SEPARATOR));
+ }
+
+ return OUString();
+}
+
+// XPresentationPage
+Reference< drawing::XDrawPage > SAL_CALL SdMasterPage::getNotesPage()
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ if(SvxFmDrawPage::mpPage && GetModel()->GetDoc() )
+ {
+ SdPage* pNotesPage = GetModel()->GetDoc()->GetMasterSdPage( (SvxFmDrawPage::mpPage->GetPageNum()-1)>>1, PageKind::Notes );
+ if( pNotesPage )
+ {
+ Reference< drawing::XDrawPage > xPage( pNotesPage->getUnoPage(), uno::UNO_QUERY );
+ return xPage;
+ }
+ }
+ return nullptr;
+}
+
+// XShapes
+void SAL_CALL SdMasterPage::add( const Reference< drawing::XShape >& xShape )
+{
+ SdGenericDrawPage::add( xShape );
+}
+
+void SAL_CALL SdMasterPage::remove( const Reference< drawing::XShape >& xShape )
+{
+ ::SolarMutexGuard aGuard;
+
+ throwIfDisposed();
+
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape( xShape );
+ if( pObj && GetPage()->IsPresObj( pObj ) )
+ GetPage()->RemovePresObj(pObj);
+
+ SdGenericDrawPage::remove( xShape );
+}
+
+Reference< uno::XInterface > createUnoPageImpl( SdPage* pPage )
+{
+ Reference< uno::XInterface > xPage;
+
+ if( pPage )
+ {
+ SdXImpressDocument* pModel = comphelper::getFromUnoTunnel<SdXImpressDocument>( pPage->getSdrModelFromSdrPage().getUnoModel() );
+ if( pModel )
+ {
+ if( pPage->IsMasterPage() )
+ {
+ xPage = static_cast<cppu::OWeakObject*>(new SdMasterPage( pModel, pPage ));
+ }
+ else
+ {
+ xPage = static_cast<cppu::OWeakObject*>(new SdDrawPage( pModel, pPage ));
+ }
+ }
+ }
+
+ return xPage;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unopback.cxx b/sd/source/ui/unoidl/unopback.cxx
new file mode 100644
index 000000000..508b1f866
--- /dev/null
+++ b/sd/source/ui/unoidl/unopback.cxx
@@ -0,0 +1,410 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/BitmapMode.hpp>
+#include <vcl/svapp.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svdpool.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/unoshprp.hxx>
+
+#include "unopback.hxx"
+#include <drawdoc.hxx>
+#include <unokywds.hxx>
+
+using namespace ::com::sun::star;
+
+const SvxItemPropertySet* ImplGetPageBackgroundPropertySet()
+{
+ static const SfxItemPropertyMapEntry aPageBackgroundPropertyMap_Impl[] =
+ {
+ FILL_PROPERTIES
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ static SvxItemPropertySet aPageBackgroundPropertySet_Impl( aPageBackgroundPropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ return &aPageBackgroundPropertySet_Impl;
+}
+
+UNO3_GETIMPLEMENTATION_IMPL( SdUnoPageBackground );
+
+SdUnoPageBackground::SdUnoPageBackground(
+ SdDrawDocument* pDoc /* = NULL */,
+ const SfxItemSet* pSet /* = NULL */)
+: mpPropSet(ImplGetPageBackgroundPropertySet()),
+ mpDoc(pDoc)
+{
+ if( pDoc )
+ {
+ StartListening( *pDoc );
+ mpSet = std::make_unique<SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>>( pDoc->GetPool() );
+
+ if( pSet )
+ mpSet->Put(*pSet);
+ }
+}
+
+SdUnoPageBackground::~SdUnoPageBackground() noexcept
+{
+ SolarMutexGuard g;
+
+ if( mpDoc )
+ EndListening( *mpDoc );
+}
+
+void SdUnoPageBackground::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>( &rHint );
+
+ // delete item set if document is dying because then the pool
+ // will also die
+ if( pSdrHint->GetKind() == SdrHintKind::ModelCleared )
+ {
+ mpSet.reset();
+ mpDoc = nullptr;
+ }
+}
+
+void SdUnoPageBackground::fillItemSet( SdDrawDocument* pDoc, SfxItemSet& rSet )
+{
+ rSet.ClearItem();
+
+ if( mpSet == nullptr )
+ {
+ StartListening( *pDoc );
+ mpDoc = pDoc;
+
+ mpSet = std::make_unique<SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>>( *rSet.GetPool() );
+
+ if( maUsrAnys.AreThereOwnUsrAnys() )
+ {
+ for( const auto pProp : mpPropSet->getPropertyMap().getPropertyEntries() )
+ {
+ uno::Any* pAny = maUsrAnys.GetUsrAnyForID( *pProp );
+ if( pAny )
+ {
+ const OUString & aPropertyName = pProp->aName;
+ switch( pProp->nWID )
+ {
+ case XATTR_FILLFLOATTRANSPARENCE :
+ case XATTR_FILLGRADIENT :
+ {
+ if ( ( pAny->getValueType() == ::cppu::UnoType< css::awt::Gradient>::get() )
+ && ( pProp->nMemberId == MID_FILLGRADIENT ) )
+ {
+ setPropertyValue( aPropertyName, *pAny );
+ }
+ else if ( ( pAny->getValueType() == ::cppu::UnoType<OUString>::get() ) &&
+ ( pProp->nMemberId == MID_NAME ) )
+ {
+ setPropertyValue( aPropertyName, *pAny );
+ }
+ }
+ break;
+ case XATTR_FILLHATCH :
+ {
+ if ( ( pAny->getValueType() == ::cppu::UnoType< css::drawing::Hatch>::get() )
+ && ( pProp->nMemberId == MID_FILLHATCH ) )
+ {
+ setPropertyValue( aPropertyName, *pAny );
+ }
+ else if ( ( pAny->getValueType() == ::cppu::UnoType<OUString>::get() ) &&
+ ( pProp->nMemberId == MID_NAME ) )
+ {
+ setPropertyValue( aPropertyName, *pAny );
+ }
+ }
+ break;
+ case XATTR_FILLBITMAP :
+ {
+ if (pProp->nMemberId == MID_BITMAP &&
+ (pAny->getValueType() == cppu::UnoType<css::awt::XBitmap>::get() ||
+ pAny->getValueType() == cppu::UnoType<css::graphic::XGraphic>::get()))
+ {
+ setPropertyValue( aPropertyName, *pAny );
+ }
+ else if (pAny->getValueType() == ::cppu::UnoType<OUString>::get() && pProp->nMemberId == MID_NAME)
+ {
+ setPropertyValue( aPropertyName, *pAny );
+ }
+ }
+ break;
+
+ default:
+ setPropertyValue( aPropertyName, *pAny );
+ }
+ }
+ }
+ }
+ }
+
+ rSet.Put( *mpSet );
+}
+
+// XServiceInfo
+OUString SAL_CALL SdUnoPageBackground::getImplementationName()
+{
+ return "SdUnoPageBackground";
+}
+
+sal_Bool SAL_CALL SdUnoPageBackground::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL SdUnoPageBackground::getSupportedServiceNames()
+{
+ return { sUNO_Service_PageBackground, sUNO_Service_FillProperties };
+}
+
+// XPropertySet
+uno::Reference< beans::XPropertySetInfo > SAL_CALL SdUnoPageBackground::getPropertySetInfo()
+{
+ return mpPropSet->getPropertySetInfo();
+}
+
+void SAL_CALL SdUnoPageBackground::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pEntry = getPropertyMapEntry( aPropertyName );
+
+ if( pEntry == nullptr )
+ {
+ throw beans::UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ if( mpSet )
+ {
+ if( pEntry->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ drawing::BitmapMode eMode;
+ if( aValue >>= eMode )
+ {
+ mpSet->Put( XFillBmpStretchItem( eMode == drawing::BitmapMode_STRETCH ) );
+ mpSet->Put( XFillBmpTileItem( eMode == drawing::BitmapMode_REPEAT ) );
+ return;
+ }
+ throw lang::IllegalArgumentException();
+ }
+
+ SfxItemPool& rPool = *mpSet->GetPool();
+ SfxItemSet aSet( rPool, pEntry->nWID, pEntry->nWID);
+ aSet.Put( *mpSet );
+
+ if( !aSet.Count() )
+ aSet.Put( rPool.GetDefaultItem( pEntry->nWID ) );
+
+ if( pEntry->nMemberId == MID_NAME && ( pEntry->nWID == XATTR_FILLBITMAP || pEntry->nWID == XATTR_FILLGRADIENT || pEntry->nWID == XATTR_FILLHATCH || pEntry->nWID == XATTR_FILLFLOATTRANSPARENCE ) )
+ {
+ OUString aName;
+ if(!(aValue >>= aName ))
+ throw lang::IllegalArgumentException();
+
+ SvxShape::SetFillAttribute( pEntry->nWID, aName, aSet );
+ }
+ else
+ {
+ SvxItemPropertySet_setPropertyValue( pEntry, aValue, aSet );
+ }
+
+ mpSet->Put( aSet );
+ }
+ else
+ {
+ if(pEntry->nWID)
+ SvxItemPropertySet::setPropertyValue( pEntry, aValue, maUsrAnys );
+ }
+}
+
+uno::Any SAL_CALL SdUnoPageBackground::getPropertyValue( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aAny;
+ const SfxItemPropertyMapEntry* pEntry = getPropertyMapEntry(PropertyName);
+
+ if( pEntry == nullptr )
+ {
+ throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ if( mpSet )
+ {
+ if( pEntry->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ const XFillBmpStretchItem* pStretchItem = mpSet->GetItem<XFillBmpStretchItem>(XATTR_FILLBMP_STRETCH);
+ const XFillBmpTileItem* pTileItem = mpSet->GetItem<XFillBmpTileItem>(XATTR_FILLBMP_TILE);
+
+ if( pStretchItem && pTileItem )
+ {
+ if( pTileItem->GetValue() )
+ aAny <<= drawing::BitmapMode_REPEAT;
+ else if( pStretchItem->GetValue() )
+ aAny <<= drawing::BitmapMode_STRETCH;
+ else
+ aAny <<= drawing::BitmapMode_NO_REPEAT;
+ }
+ }
+ else
+ {
+ SfxItemPool& rPool = *mpSet->GetPool();
+ SfxItemSet aSet( rPool, pEntry->nWID, pEntry->nWID);
+ aSet.Put( *mpSet );
+
+ if( !aSet.Count() )
+ aSet.Put( rPool.GetDefaultItem( pEntry->nWID ) );
+
+ // get value from ItemSet
+ aAny = SvxItemPropertySet_getPropertyValue( pEntry, aSet );
+ }
+ }
+ else
+ {
+ if(pEntry->nWID)
+ aAny = mpPropSet->getPropertyValue( pEntry, maUsrAnys );
+ }
+ return aAny;
+}
+
+void SAL_CALL SdUnoPageBackground::addPropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& ) {}
+void SAL_CALL SdUnoPageBackground::removePropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& ) {}
+void SAL_CALL SdUnoPageBackground::addVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& ) {}
+void SAL_CALL SdUnoPageBackground::removeVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& ) {}
+
+// XPropertyState
+beans::PropertyState SAL_CALL SdUnoPageBackground::getPropertyState( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pEntry = getPropertyMapEntry(PropertyName);
+
+ if( pEntry == nullptr )
+ throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+
+ if( mpSet )
+ {
+ if( pEntry->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ if( mpSet->GetItemState( XATTR_FILLBMP_STRETCH, false ) == SfxItemState::SET ||
+ mpSet->GetItemState( XATTR_FILLBMP_TILE, false ) == SfxItemState::SET )
+ {
+ return beans::PropertyState_DIRECT_VALUE;
+ }
+ else
+ {
+ return beans::PropertyState_AMBIGUOUS_VALUE;
+ }
+ }
+
+ switch( mpSet->GetItemState( pEntry->nWID, false ) )
+ {
+ case SfxItemState::SET:
+ return beans::PropertyState_DIRECT_VALUE;
+ case SfxItemState::DEFAULT:
+ return beans::PropertyState_DEFAULT_VALUE;
+ default:
+// case SfxItemState::DONTCARE:
+// case SfxItemState::DISABLED:
+ return beans::PropertyState_AMBIGUOUS_VALUE;
+ }
+ }
+ else
+ {
+ if( nullptr == maUsrAnys.GetUsrAnyForID(*pEntry) )
+ return beans::PropertyState_DEFAULT_VALUE;
+ else
+ return beans::PropertyState_DIRECT_VALUE;
+ }
+}
+
+uno::Sequence< beans::PropertyState > SAL_CALL SdUnoPageBackground::getPropertyStates( const uno::Sequence< OUString >& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nCount = aPropertyName.getLength();
+
+ uno::Sequence< beans::PropertyState > aPropertyStateSequence( nCount );
+
+ std::transform(aPropertyName.begin(), aPropertyName.end(), aPropertyStateSequence.getArray(),
+ [this](const OUString& rName) -> beans::PropertyState { return getPropertyState(rName); });
+
+ return aPropertyStateSequence;
+}
+
+void SAL_CALL SdUnoPageBackground::setPropertyToDefault( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pEntry = getPropertyMapEntry(PropertyName);
+
+ if( pEntry == nullptr )
+ throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+
+ if( mpSet )
+ {
+ if( pEntry->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ mpSet->ClearItem( XATTR_FILLBMP_STRETCH );
+ mpSet->ClearItem( XATTR_FILLBMP_TILE );
+ }
+ else
+ {
+ mpSet->ClearItem( pEntry->nWID );
+ }
+ }
+}
+
+uno::Any SAL_CALL SdUnoPageBackground::getPropertyDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pEntry = getPropertyMapEntry(aPropertyName);
+ if( pEntry == nullptr || mpSet == nullptr )
+ throw beans::UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+
+ uno::Any aAny;
+ if (pEntry->nWID == OWN_ATTR_FILLBMP_MODE)
+ {
+ aAny <<= drawing::BitmapMode_REPEAT;
+ }
+ else
+ {
+ SfxItemPool& rPool = *mpSet->GetPool();
+ SfxItemSet aSet(rPool, pEntry->nWID, pEntry->nWID);
+ aSet.Put(rPool.GetDefaultItem(pEntry->nWID));
+
+ aAny = SvxItemPropertySet_getPropertyValue(pEntry, aSet);
+ }
+ return aAny;
+}
+
+/** this is used because our property map is not sorted yet */
+const SfxItemPropertyMapEntry* SdUnoPageBackground::getPropertyMapEntry( std::u16string_view rPropertyName ) const noexcept
+{
+ return mpPropSet->getPropertyMap().getByName(rPropertyName);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unopback.hxx b/sd/source/ui/unoidl/unopback.hxx
new file mode 100644
index 000000000..c70cc2fea
--- /dev/null
+++ b/sd/source/ui/unoidl/unopback.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+
+#include <svl/lstner.hxx>
+#include <comphelper/servicehelper.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <editeng/unoipset.hxx>
+
+class SdDrawDocument;
+class SdrModel;
+class SfxItemSet;
+class SvxItemPropertySet;
+struct SfxItemPropertyMapEntry;
+
+const SvxItemPropertySet* ImplGetPageBackgroundPropertySet();
+
+class SdUnoPageBackground final : public ::cppu::WeakImplHelper<
+ css::beans::XPropertySet,
+ css::lang::XServiceInfo,
+ css::beans::XPropertyState,
+ css::lang::XUnoTunnel>,
+ public SfxListener
+{
+ const SvxItemPropertySet* mpPropSet;
+ SvxItemPropertySetUsrAnys maUsrAnys;
+ std::unique_ptr<SfxItemSet> mpSet;
+ SdrModel* mpDoc;
+
+ const SfxItemPropertyMapEntry* getPropertyMapEntry( std::u16string_view rPropertyName ) const noexcept;
+public:
+ SdUnoPageBackground( SdDrawDocument* pDoc = nullptr, const SfxItemSet* pSet = nullptr);
+ virtual ~SdUnoPageBackground() noexcept override;
+
+ // internal
+ void fillItemSet( SdDrawDocument* pDoc, SfxItemSet& rSet );
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ // uno helper
+ UNO3_GETIMPLEMENTATION_DECL( SdUnoPageBackground )
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // XPropertyState
+ virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override;
+ virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( const css::uno::Sequence< OUString >& aPropertyName ) override;
+ virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override;
+ virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unopool.cxx b/sd/source/ui/unoidl/unopool.cxx
new file mode 100644
index 000000000..7345dc45d
--- /dev/null
+++ b/sd/source/ui/unoidl/unopool.cxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <i18nlangtag/languagetag.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/unopool.hxx>
+
+#include <drawdoc.hxx>
+#include "unopool.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::cppu;
+using namespace ::comphelper;
+
+static LanguageType SdUnoGetLanguage( const lang::Locale& rLocale )
+{
+ // empty language -> LANGUAGE_SYSTEM
+ if ( rLocale.Language.getLength() == 0 )
+ return LANGUAGE_SYSTEM;
+
+ LanguageType eRet = LanguageTag::convertToLanguageType( rLocale, false);
+ if ( eRet == LANGUAGE_NONE )
+ eRet = LANGUAGE_SYSTEM; //! or throw an exception?
+
+ return eRet;
+}
+
+namespace {
+
+class SdUnoDrawPool : public SvxUnoDrawPool
+{
+public:
+ explicit SdUnoDrawPool(SdDrawDocument* pModel);
+
+protected:
+ virtual void putAny( SfxItemPool* pPool, const PropertyMapEntry* pEntry, const uno::Any& rValue ) override;
+
+private:
+ SdDrawDocument* mpDrawModel;
+};
+
+}
+
+SdUnoDrawPool::SdUnoDrawPool(SdDrawDocument* pModel)
+: SvxUnoDrawPool( pModel ), mpDrawModel( pModel )
+{
+}
+
+void SdUnoDrawPool::putAny( SfxItemPool* pPool, const comphelper::PropertyMapEntry* pEntry, const uno::Any& rValue )
+{
+ switch( pEntry->mnHandle )
+ {
+ case EE_CHAR_LANGUAGE:
+ case EE_CHAR_LANGUAGE_CJK:
+ case EE_CHAR_LANGUAGE_CTL:
+ {
+ lang::Locale aLocale;
+ if( rValue >>= aLocale )
+ mpDrawModel->SetLanguage(
+ SdUnoGetLanguage( aLocale ),
+ static_cast<sal_uInt16>(pEntry->mnHandle) );
+ }
+ }
+ SvxUnoDrawPool::putAny( pPool, pEntry, rValue );
+}
+
+uno::Reference< uno::XInterface > SdUnoCreatePool( SdDrawDocument* pDrawModel )
+{
+ return static_cast<uno::XAggregation*>(new SdUnoDrawPool( pDrawModel ));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unopool.hxx b/sd/source/ui/unoidl/unopool.hxx
new file mode 100644
index 000000000..4188e80a9
--- /dev/null
+++ b/sd/source/ui/unoidl/unopool.hxx
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <drawdoc.hxx>
+
+css::uno::Reference<css::uno::XInterface> SdUnoCreatePool(SdDrawDocument* pDrawModel);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unosrch.cxx b/sd/source/ui/unoidl/unosrch.cxx
new file mode 100644
index 000000000..f1005819d
--- /dev/null
+++ b/sd/source/ui/unoidl/unosrch.cxx
@@ -0,0 +1,778 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <vcl/svapp.hxx>
+
+#include <svx/svdobj.hxx>
+#include <svx/svdpool.hxx>
+#include <editeng/unoipset.hxx>
+#include <editeng/unotext.hxx>
+#include <tools/debug.hxx>
+
+#include <unoprnms.hxx>
+#include <unosrch.hxx>
+
+using namespace ::com::sun::star;
+
+#define WID_SEARCH_BACKWARDS 0
+#define WID_SEARCH_CASE 1
+#define WID_SEARCH_WORDS 2
+
+static const SfxItemPropertyMapEntry* ImplGetSearchPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aSearchPropertyMap_Impl[] =
+ {
+ { u"" UNO_NAME_SEARCH_BACKWARDS, WID_SEARCH_BACKWARDS, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"" UNO_NAME_SEARCH_CASE, WID_SEARCH_CASE, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"" UNO_NAME_SEARCH_WORDS, WID_SEARCH_WORDS, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aSearchPropertyMap_Impl;
+}
+
+namespace {
+
+class SearchContext_impl
+{
+ uno::Reference< drawing::XShapes > mxShapes;
+ sal_Int32 mnIndex;
+
+public:
+ SearchContext_impl(uno::Reference<drawing::XShapes> const& xShapes)
+ : mxShapes( xShapes ), mnIndex( -1 ) {}
+
+ uno::Reference< drawing::XShape > firstShape()
+ {
+ mnIndex = -1;
+ return nextShape();
+ }
+
+ uno::Reference< drawing::XShape > nextShape()
+ {
+ uno::Reference< drawing::XShape > xShape;
+ mnIndex++;
+ if( mxShapes.is() && mxShapes->getCount() > mnIndex )
+ {
+ mxShapes->getByIndex( mnIndex ) >>= xShape;
+ }
+ return xShape;
+ }
+};
+
+}
+
+/* ================================================================= */
+/** this class implements a search or replace operation on a given
+ page or a given sdrobj
+ */
+
+SdUnoSearchReplaceShape::SdUnoSearchReplaceShape( drawing::XDrawPage* pPage ) noexcept
+ : mpPage(pPage)
+{
+}
+
+SdUnoSearchReplaceShape::~SdUnoSearchReplaceShape() noexcept
+{
+}
+
+// util::XReplaceable
+uno::Reference< util::XReplaceDescriptor > SAL_CALL SdUnoSearchReplaceShape::createReplaceDescriptor()
+{
+ return new SdUnoSearchReplaceDescriptor;
+}
+
+sal_Int32 SAL_CALL SdUnoSearchReplaceShape::replaceAll( const uno::Reference< util::XSearchDescriptor >& xDesc )
+{
+ SdUnoSearchReplaceDescriptor* pDescr = comphelper::getFromUnoTunnel<SdUnoSearchReplaceDescriptor>( xDesc );
+ if( pDescr == nullptr )
+ return 0;
+
+ sal_Int32 nFound = 0;
+
+ uno::Reference< drawing::XShapes > xShapes;
+ uno::Reference< drawing::XShape > xShape;
+
+ std::vector<SearchContext_impl> aContexts;
+ if(mpPage)
+ {
+ xShapes = mpPage;
+
+ if( xShapes->getCount() )
+ {
+ aContexts.push_back(SearchContext_impl(xShapes));
+ xShape = aContexts.back().firstShape();
+ }
+ else
+ {
+ xShapes = nullptr;
+ }
+ }
+
+ while( xShape.is() )
+ {
+ // replace in xShape
+ uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY);
+ uno::Reference< text::XTextRange > xRange = xText;
+ uno::Reference< text::XTextRange > xFound;
+
+ while( xRange.is() )
+ {
+ xFound = Search( xRange, pDescr );
+ if( !xFound.is() )
+ break;
+
+ xFound->setString( pDescr->getReplaceString() );
+ xRange = xFound->getEnd();
+ nFound++;
+ }
+ // done with xShape -> get next shape
+
+ // test if it's a group
+ uno::Reference< drawing::XShapes > xGroupShape( xShape, uno::UNO_QUERY );
+ if( xGroupShape.is() && ( xGroupShape->getCount() > 0 ) )
+ {
+ aContexts.push_back(SearchContext_impl(xGroupShape));
+ xShape = aContexts.back().firstShape();
+ }
+ else
+ {
+ if (!aContexts.empty())
+ xShape = aContexts.back().nextShape();
+ else
+ xShape = nullptr;
+ }
+
+ // test parent contexts for next shape if none
+ // is found in the current context
+ while (!aContexts.empty() && !xShape.is())
+ {
+ aContexts.pop_back();
+ if (!aContexts.empty())
+ xShape = aContexts.back().nextShape();
+ }
+ }
+
+ return nFound;
+}
+
+// XSearchable
+uno::Reference< css::util::XSearchDescriptor > SAL_CALL SdUnoSearchReplaceShape::createSearchDescriptor( )
+{
+ return new SdUnoSearchReplaceDescriptor;
+}
+
+uno::Reference< css::container::XIndexAccess > SAL_CALL SdUnoSearchReplaceShape::findAll( const css::uno::Reference< css::util::XSearchDescriptor >& xDesc )
+{
+ SdUnoSearchReplaceDescriptor* pDescr = comphelper::getFromUnoTunnel<SdUnoSearchReplaceDescriptor>( xDesc );
+ if( pDescr == nullptr )
+ return uno::Reference< container::XIndexAccess > ();
+
+ sal_Int32 nSequence = 32;
+ sal_Int32 nFound = 0;
+
+ uno::Sequence < uno::Reference< uno::XInterface > > aSeq( nSequence );
+
+ uno::Reference< uno::XInterface > * pArray = aSeq.getArray();
+
+ uno::Reference< drawing::XShapes > xShapes;
+ uno::Reference< drawing::XShape > xShape;
+
+ std::vector<SearchContext_impl> aContexts;
+ if(mpPage)
+ {
+ xShapes = mpPage;
+
+ if( xShapes->getCount() > 0 )
+ {
+ aContexts.push_back(SearchContext_impl(xShapes));
+ xShape = aContexts.back().firstShape();
+ }
+ else
+ {
+ xShapes = nullptr;
+ }
+ }
+
+ while( xShape.is() )
+ {
+ // find in xShape
+ uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY);
+ uno::Reference< text::XTextRange > xRange = xText;
+ uno::Reference< text::XTextRange > xFound;
+
+ while( xRange.is() )
+ {
+ xFound = Search( xRange, pDescr );
+ if( !xFound.is() )
+ break;
+
+ if( nFound >= nSequence )
+ {
+ nSequence += 32;
+ aSeq.realloc( nSequence );
+ pArray = aSeq.getArray();
+ }
+
+ pArray[nFound++] = xFound;
+
+ xRange = xFound->getEnd();
+ }
+ // done with shape -> get next shape
+
+ // test if it's a group
+ uno::Reference< drawing::XShapes > xGroupShape;
+ xGroupShape.set( xShape, uno::UNO_QUERY );
+
+ if( xGroupShape.is() && xGroupShape->getCount() > 0 )
+ {
+ aContexts.push_back(SearchContext_impl(xGroupShape));
+ xShape = aContexts.back().firstShape();
+ }
+ else
+ {
+ if (!aContexts.empty())
+ xShape = aContexts.back().nextShape();
+ else
+ xShape = nullptr;
+ }
+
+ // test parent contexts for next shape if none
+ // is found in the current context
+ while (!aContexts.empty() && !xShape.is())
+ {
+ aContexts.pop_back();
+ if (!aContexts.empty())
+ xShape = aContexts.back().nextShape();
+ }
+ }
+
+ if( nFound != nSequence )
+ aSeq.realloc( nFound );
+
+ uno::Reference<css::container::XIndexAccess> xRet(new SdUnoFindAllAccess(aSeq));
+ return xRet;
+}
+
+uno::Reference< css::uno::XInterface > SAL_CALL SdUnoSearchReplaceShape::findFirst( const css::uno::Reference< css::util::XSearchDescriptor >& xDesc )
+{
+ uno::Reference< text::XTextRange > xRange( GetCurrentShape(), uno::UNO_QUERY );
+ if( xRange.is() )
+ return findNext( xRange, xDesc );
+
+ return uno::Reference< uno::XInterface > ();
+}
+
+uno::Reference< drawing::XShape > SdUnoSearchReplaceShape::GetCurrentShape() const noexcept
+{
+ uno::Reference< drawing::XShape > xShape;
+
+ if( mpPage && mpPage->getCount() > 0)
+ mpPage->getByIndex(0) >>= xShape;
+
+ return xShape;
+
+}
+
+uno::Reference< css::uno::XInterface > SAL_CALL SdUnoSearchReplaceShape::findNext( const css::uno::Reference< css::uno::XInterface >& xStartAt, const css::uno::Reference< css::util::XSearchDescriptor >& xDesc )
+{
+ SdUnoSearchReplaceDescriptor* pDescr = comphelper::getFromUnoTunnel<SdUnoSearchReplaceDescriptor>( xDesc );
+
+ uno::Reference< uno::XInterface > xFound;
+
+ uno::Reference< text::XTextRange > xRange( xStartAt, uno::UNO_QUERY );
+ if(pDescr && xRange.is() )
+ {
+
+ uno::Reference< text::XTextRange > xCurrentRange( xStartAt, uno::UNO_QUERY );
+
+ uno::Reference< drawing::XShape > xCurrentShape( GetShape( xCurrentRange ) );
+
+ while(!xFound.is() && xRange.is())
+ {
+ xFound = Search( xRange, pDescr );
+ if(!xFound.is())
+ {
+ // we need a new starting range now
+ xRange = nullptr;
+
+ if(mpPage)
+ {
+ // we do a page wide search, so skip to the next shape here
+ // get next shape on our page
+ uno::Reference< drawing::XShape > xFound2( GetNextShape( mpPage, xCurrentShape ) );
+ if( xFound2.is() && (xFound2.get() != xCurrentShape.get()) )
+ xCurrentShape = xFound2;
+ else
+ xCurrentShape = nullptr;
+
+ xRange.set( xCurrentShape, uno::UNO_QUERY );
+ if(!(xCurrentShape.is() && (xRange.is())))
+ xRange = nullptr;
+ }
+ else
+ {
+ // we search only in this shape, so end search if we have
+ // not found anything
+ }
+ }
+ }
+ }
+ return xFound;
+}
+
+/** this method returns the shape that follows xCurrentShape in the shape collection xShapes.
+ It steps recursive into groupshapes and returns the xCurrentShape if it is the last
+ shape in this collection */
+uno::Reference< drawing::XShape > SdUnoSearchReplaceShape::GetNextShape( const uno::Reference< container::XIndexAccess >& xShapes, const uno::Reference< drawing::XShape >& xCurrentShape ) noexcept
+{
+ uno::Reference< drawing::XShape > xFound;
+
+ if(xShapes.is() && xCurrentShape.is())
+ {
+ const sal_Int32 nCount = xShapes->getCount();
+ for( sal_Int32 i = 0; i < nCount; i++ )
+ {
+ uno::Reference< drawing::XShape > xSearchShape;
+ xShapes->getByIndex(i) >>= xSearchShape;
+
+ if( xSearchShape.is() )
+ {
+ uno::Reference< container::XIndexAccess > xGroup( xSearchShape, uno::UNO_QUERY );
+
+ if( xCurrentShape.get() == xSearchShape.get() )
+ {
+ if( xGroup.is() && xGroup->getCount() > 0 )
+ {
+ xGroup->getByIndex( 0 ) >>= xFound;
+ }
+ else
+ {
+ i++;
+ if( i < nCount )
+ xShapes->getByIndex( i ) >>= xFound;
+ else
+ xFound = xCurrentShape;
+ }
+
+ break;
+ }
+ else if( xGroup.is() )
+ {
+ xFound = GetNextShape( xGroup, xCurrentShape );
+ if( xFound.is() )
+ {
+ if( xFound.get() == xCurrentShape.get() )
+ {
+ // the current shape was found at the end of the group
+ i++;
+ if( i < nCount )
+ {
+ xShapes->getByIndex(i) >>= xFound;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return xFound;
+}
+
+uno::Reference< text::XTextRange > SdUnoSearchReplaceShape::Search( const uno::Reference< text::XTextRange >& xText, SdUnoSearchReplaceDescriptor* pDescr )
+{
+ if(!xText.is())
+ return uno::Reference< text::XTextRange > ();
+
+ uno::Reference< text::XText > xParent( xText->getText() );
+
+ if( !xParent.is() )
+ {
+ xParent.set( xText, uno::UNO_QUERY );
+ }
+
+ const OUString aText( xParent->getString() );
+
+ const sal_Int32 nTextLen = aText.getLength();
+
+ std::unique_ptr<sal_Int32[]> pConvertPos( new sal_Int32[nTextLen+2] );
+ std::unique_ptr<sal_Int32[]> pConvertPara( new sal_Int32[nTextLen+2] );
+
+ sal_Int32* pPos = pConvertPos.get();
+ sal_Int32* pPara = pConvertPara.get();
+
+ sal_Int32 nLastPos = 0, nLastPara = 0;
+
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( xParent, uno::UNO_QUERY );
+
+ // first we fill the arrays with the position and paragraph for every character
+ // inside the text
+ if( xEnumAccess.is() )
+ {
+ uno::Reference< container::XEnumeration > xParaEnum( xEnumAccess->createEnumeration() );
+
+ while(xParaEnum->hasMoreElements())
+ {
+ int ndbg = 0;
+ uno::Reference< text::XTextContent > xParagraph( xParaEnum->nextElement(), uno::UNO_QUERY );
+ if( xParagraph.is() )
+ xEnumAccess.set(xParagraph, css::uno::UNO_QUERY);
+ else
+ xEnumAccess.clear();
+
+ if( xEnumAccess.is() )
+ {
+ uno::Reference< container::XEnumeration > xPortionEnum( xEnumAccess->createEnumeration() );
+ if( xPortionEnum.is() )
+ {
+ while(xPortionEnum->hasMoreElements())
+ {
+ uno::Reference< text::XTextRange > xPortion( xPortionEnum->nextElement(), uno::UNO_QUERY );
+ if( xPortion.is() )
+ {
+ const OUString aPortion( xPortion->getString() );
+ const sal_Int32 nLen = aPortion.getLength();
+
+ ESelection aStartSel( GetSelection( xPortion->getStart() ) );
+ ESelection aEndSel( GetSelection( xPortion->getEnd() ) );
+
+ // special case for empty portions with content or length one portions with content (fields)
+ if( (aStartSel.nStartPos == aEndSel.nStartPos) || ( (aStartSel.nStartPos == (aEndSel.nStartPos - 1)) && (nLen > 1) ) )
+ {
+ for( sal_Int32 i = 0; i < nLen; i++ )
+ {
+ if( ndbg < (nTextLen+2) )
+ {
+ *pPos++ = aStartSel.nStartPos;
+ *pPara++ = aStartSel.nStartPara;
+
+ ndbg += 1;
+ }
+ else
+ {
+ OSL_FAIL( "array overflow while searching" );
+ }
+ }
+
+ nLastPos = aStartSel.nStartPos;
+ }
+ // normal case
+ else
+ {
+ for( sal_Int32 i = 0; i < nLen; i++ )
+ {
+ if( ndbg < (nTextLen+2) )
+ {
+ *pPos++ = aStartSel.nStartPos++;
+ *pPara++ = aStartSel.nStartPara;
+
+ ndbg += 1;
+ }
+ else
+ {
+ OSL_FAIL( "array overflow while searching" );
+ }
+ }
+
+ nLastPos = aStartSel.nStartPos - 1;
+ DBG_ASSERT( aEndSel.nStartPos == aStartSel.nStartPos, "Search is not working" );
+ }
+ nLastPara = aStartSel.nStartPara;
+ }
+ }
+ }
+ }
+
+ if( ndbg < (nTextLen+2) )
+ {
+ *pPos++ = nLastPos + 1;
+ *pPara++ = nLastPara;
+ }
+ else
+ {
+ OSL_FAIL( "array overflow while searching" );
+ }
+ }
+ }
+
+ uno::Reference< text::XTextRange > xFound;
+ ESelection aSel;
+
+ if( xText.is() )
+ aSel = GetSelection( xText );
+
+ sal_Int32 nStartPos;
+ sal_Int32 nEndPos = 0;
+ for( nStartPos = 0; nStartPos < nTextLen; nStartPos++ )
+ {
+ if( pConvertPara[nStartPos] == aSel.nStartPara && pConvertPos[nStartPos] == aSel.nStartPos )
+ break;
+ }
+
+ if( Search( aText, nStartPos, nEndPos, pDescr ) )
+ {
+ if( nStartPos <= nTextLen && nEndPos <= nTextLen )
+ {
+ ESelection aSelection( pConvertPara[nStartPos], pConvertPos[nStartPos],
+ pConvertPara[nEndPos], pConvertPos[nEndPos] );
+
+ SvxUnoTextBase* pParent = comphelper::getFromUnoTunnel<SvxUnoTextBase>( xParent );
+
+ if(pParent)
+ {
+ rtl::Reference<SvxUnoTextRange> pRange = new SvxUnoTextRange( *pParent );
+ xFound = pRange;
+ pRange->SetSelection(aSelection);
+ }
+ }
+ else
+ {
+ OSL_FAIL("Array overflow while searching!");
+ }
+ }
+
+ return xFound;
+}
+
+bool SdUnoSearchReplaceShape::Search( const OUString& rText, sal_Int32& nStartPos, sal_Int32& nEndPos, SdUnoSearchReplaceDescriptor* pDescr ) noexcept
+{
+ OUString aSearchStr( pDescr->getSearchString() );
+ OUString aText( rText );
+
+ if( !pDescr->IsCaseSensitive() )
+ {
+ aText = aText.toAsciiLowerCase();
+ aSearchStr = aSearchStr.toAsciiLowerCase();
+ }
+
+ sal_Int32 nFound = aText.indexOf( aSearchStr, nStartPos );
+ if( nFound != -1 )
+ {
+ nStartPos = nFound;
+ nEndPos = nFound + aSearchStr.getLength();
+
+ if(pDescr->IsWords())
+ {
+ if( (nStartPos > 0 && aText[nStartPos-1] > ' ') ||
+ (nEndPos < aText.getLength() && aText[nEndPos] > ' ') )
+ {
+ nStartPos++;
+ return Search( aText, nStartPos, nEndPos, pDescr );
+ }
+ }
+
+ return true;
+ }
+ else
+ return false;
+}
+
+ESelection SdUnoSearchReplaceShape::GetSelection( const uno::Reference< text::XTextRange >& xTextRange ) noexcept
+{
+ ESelection aSel;
+ SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( xTextRange );
+
+ if(pRange)
+ aSel = pRange->GetSelection();
+
+ return aSel;
+}
+
+uno::Reference< drawing::XShape > SdUnoSearchReplaceShape::GetShape( const uno::Reference< text::XTextRange >& xTextRange ) noexcept
+{
+ uno::Reference< drawing::XShape > xShape;
+
+ if(xTextRange.is())
+ {
+ uno::Reference< text::XText > xText( xTextRange->getText() );
+
+ if(xText.is())
+ {
+ do
+ {
+ xShape.set( xText, uno::UNO_QUERY );
+ if(!xShape.is())
+ {
+ uno::Reference< text::XText > xParent( xText->getText() );
+ if(!xParent.is() || xText.get() == xParent.get())
+ return xShape;
+
+ xText = xParent;
+ }
+ } while( !xShape.is() );
+ }
+ }
+
+ return xShape;
+}
+
+/* ================================================================= */
+/** this class holds the parameters and status of a search or replace
+ operation performed by class SdUnoSearchReplaceShape
+ */
+
+UNO3_GETIMPLEMENTATION_IMPL( SdUnoSearchReplaceDescriptor );
+
+SdUnoSearchReplaceDescriptor::SdUnoSearchReplaceDescriptor()
+{
+ mpPropSet.reset( new SvxItemPropertySet(ImplGetSearchPropertyMap(), SdrObject::GetGlobalDrawObjectItemPool()) );
+
+ mbBackwards = false;
+ mbCaseSensitive = false;
+ mbWords = false;
+}
+
+SdUnoSearchReplaceDescriptor::~SdUnoSearchReplaceDescriptor() noexcept
+{
+}
+
+// XSearchDescriptor
+OUString SAL_CALL SdUnoSearchReplaceDescriptor::getSearchString()
+{
+ return maSearchStr;
+}
+
+void SAL_CALL SdUnoSearchReplaceDescriptor::setSearchString( const OUString& aString )
+{
+ maSearchStr = aString;
+}
+
+// XReplaceDescriptor
+OUString SAL_CALL SdUnoSearchReplaceDescriptor::getReplaceString()
+{
+ return maReplaceStr;
+}
+
+void SAL_CALL SdUnoSearchReplaceDescriptor::setReplaceString( const OUString& aReplaceString )
+{
+ maReplaceStr = aReplaceString;
+}
+
+// XPropertySet
+uno::Reference< css::beans::XPropertySetInfo > SAL_CALL SdUnoSearchReplaceDescriptor::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ return mpPropSet->getPropertySetInfo();
+}
+
+void SAL_CALL SdUnoSearchReplaceDescriptor::setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pEntry = mpPropSet->getPropertyMapEntry(aPropertyName);
+
+ bool bOk = false;
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case WID_SEARCH_BACKWARDS:
+ bOk = (aValue >>= mbBackwards);
+ break;
+ case WID_SEARCH_CASE:
+ bOk = (aValue >>= mbCaseSensitive);
+ break;
+ case WID_SEARCH_WORDS:
+ bOk = (aValue >>= mbWords);
+ break;
+ default:
+ throw beans::UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ if( !bOk )
+ throw lang::IllegalArgumentException();
+}
+
+uno::Any SAL_CALL SdUnoSearchReplaceDescriptor::getPropertyValue( const OUString& PropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aAny;
+
+ const SfxItemPropertyMapEntry* pEntry = mpPropSet->getPropertyMapEntry(PropertyName);
+
+ switch( pEntry ? pEntry->nWID : -1 )
+ {
+ case WID_SEARCH_BACKWARDS:
+ aAny <<= mbBackwards;
+ break;
+ case WID_SEARCH_CASE:
+ aAny <<= mbCaseSensitive;
+ break;
+ case WID_SEARCH_WORDS:
+ aAny <<= mbWords;
+ break;
+ default:
+ throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ return aAny;
+}
+
+void SAL_CALL SdUnoSearchReplaceDescriptor::addPropertyChangeListener( const OUString& , const css::uno::Reference< css::beans::XPropertyChangeListener >& ) {}
+void SAL_CALL SdUnoSearchReplaceDescriptor::removePropertyChangeListener( const OUString& , const css::uno::Reference< css::beans::XPropertyChangeListener >& ) {}
+void SAL_CALL SdUnoSearchReplaceDescriptor::addVetoableChangeListener( const OUString& , const css::uno::Reference< css::beans::XVetoableChangeListener >& ) {}
+void SAL_CALL SdUnoSearchReplaceDescriptor::removeVetoableChangeListener( const OUString& , const css::uno::Reference< css::beans::XVetoableChangeListener >& ) {}
+
+/* ================================================================= */
+
+SdUnoFindAllAccess::SdUnoFindAllAccess( uno::Sequence< uno::Reference< uno::XInterface > > const & rSequence ) noexcept
+:maSequence( rSequence )
+{
+}
+
+SdUnoFindAllAccess::~SdUnoFindAllAccess() noexcept
+{
+}
+
+// XElementAccess
+uno::Type SAL_CALL SdUnoFindAllAccess::getElementType()
+{
+ return cppu::UnoType<text::XTextRange>::get();
+}
+
+sal_Bool SAL_CALL SdUnoFindAllAccess::hasElements()
+{
+ return maSequence.hasElements();
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SdUnoFindAllAccess::getCount()
+{
+ return maSequence.getLength();
+}
+
+uno::Any SAL_CALL SdUnoFindAllAccess::getByIndex( sal_Int32 Index )
+{
+ if( Index < 0 || Index >= getCount() )
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Any aAny;
+ aAny <<= maSequence[Index];
+ return aAny;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unowcntr.cxx b/sd/source/ui/unoidl/unowcntr.cxx
new file mode 100644
index 000000000..1079477ef
--- /dev/null
+++ b/sd/source/ui/unoidl/unowcntr.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/XComponent.hpp>
+
+#include "unowcntr.hxx"
+
+using namespace ::com::sun::star;
+
+SvUnoWeakContainer::SvUnoWeakContainer() noexcept
+{
+}
+
+SvUnoWeakContainer::~SvUnoWeakContainer() noexcept
+{
+}
+
+/** inserts the given ref into this container */
+void SvUnoWeakContainer::insert( const uno::WeakReference< uno::XInterface >& xRef ) noexcept
+{
+ for ( auto it = maVector.begin(); it != maVector.end(); )
+ {
+ uno::WeakReference< uno::XInterface > & rWeakRef = *it;
+ uno::Reference< uno::XInterface > xTestRef( rWeakRef );
+ if ( !xTestRef.is() )
+ {
+ it = maVector.erase( it );
+ }
+ else
+ {
+ if ( rWeakRef == xRef )
+ return;
+ ++it;
+ }
+ }
+ maVector.emplace_back( xRef );
+}
+
+/** searches the container for a ref that returns true on the given
+ search function
+*/
+bool SvUnoWeakContainer::findRef(
+ uno::WeakReference< uno::XInterface >& rRef,
+ void const * pSearchData,
+ weakref_searchfunc pSearchFunc
+)
+{
+ for ( auto it = maVector.begin(); it != maVector.end(); )
+ {
+ uno::WeakReference< uno::XInterface > & itRef = *it;
+ uno::Reference< uno::XInterface > xTestRef( itRef );
+ if ( !xTestRef.is() )
+ {
+ it = maVector.erase( it );
+ }
+ else
+ {
+ if( (*pSearchFunc)( itRef, pSearchData ) )
+ {
+ rRef = itRef;
+ return true;
+ }
+ ++it;
+ }
+ }
+ return false;
+}
+
+void SvUnoWeakContainer::dispose()
+{
+ for (auto const& elem : maVector)
+ {
+ uno::Reference< uno::XInterface > xTestRef( elem );
+ if ( xTestRef.is() )
+ {
+ uno::Reference< lang::XComponent > xComp( xTestRef, uno::UNO_QUERY );
+ if( xComp.is() )
+ xComp->dispose();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/unoidl/unowcntr.hxx b/sd/source/ui/unoidl/unowcntr.hxx
new file mode 100644
index 000000000..a863f0929
--- /dev/null
+++ b/sd/source/ui/unoidl/unowcntr.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/weakref.hxx>
+#include <vector>
+
+typedef bool (*weakref_searchfunc)( const css::uno::WeakReference< css::uno::XInterface >& xRef, void const * pSearchData );
+
+class SvUnoWeakContainer
+{
+private:
+ std::vector< css::uno::WeakReference< css::uno::XInterface > > maVector;
+
+public:
+ SvUnoWeakContainer() noexcept;
+ ~SvUnoWeakContainer() noexcept;
+
+ /** inserts the given ref into this container */
+ void insert( const css::uno::WeakReference< css::uno::XInterface >& xRef ) noexcept;
+
+ /** searches the container for a ref that returns true on the given
+ search function
+ */
+ bool findRef( css::uno::WeakReference< css::uno::XInterface >& rRef, void const * pSearchData, weakref_searchfunc pSearchFunc );
+
+ void dispose();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/DocumentRenderer.cxx b/sd/source/ui/view/DocumentRenderer.cxx
new file mode 100644
index 000000000..eee1a759e
--- /dev/null
+++ b/sd/source/ui/view/DocumentRenderer.cxx
@@ -0,0 +1,2256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <DocumentRenderer.hxx>
+#include <DocumentRenderer.hrc>
+#include <ViewShellBase.hxx>
+
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <drawview.hxx>
+#include <DrawViewShell.hxx>
+#include <FrameView.hxx>
+#include <Outliner.hxx>
+#include <OutlineViewShell.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <DrawDocShell.hxx>
+
+#include <tools/multisel.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <toolkit/awt/vclxdevice.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/print.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <xmloff/autolayout.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <officecfg/Office/Draw.hxx>
+#include <officecfg/Office/Impress.hxx>
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+namespace {
+
+ /** Convenience class to extract values from the sequence of properties
+ given to one of the XRenderable methods.
+ */
+ class PrintOptions
+ {
+ public:
+ PrintOptions (
+ const vcl::PrinterOptionsHelper& rHelper,
+ std::vector<sal_Int32>&& rSlidesPerPage)
+ : mrProperties(rHelper),
+ maSlidesPerPage(std::move(rSlidesPerPage))
+ {
+ }
+
+ bool IsWarningOrientation() const
+ {
+ return GetBoolValue(nullptr, true);
+ }
+
+ bool IsPrintPageName() const
+ {
+ return GetBoolValue("IsPrintName", false);
+ }
+
+ bool IsDate() const
+ {
+ return GetBoolValue("IsPrintDateTime", false);
+ }
+
+ bool IsTime() const
+ {
+ return GetBoolValue("IsPrintDateTime", false);
+ }
+
+ bool IsHiddenPages() const
+ {
+ return GetBoolValue("IsPrintHidden", false);
+ }
+
+ bool IsHandoutHorizontal() const
+ {
+ return GetBoolValue("SlidesPerPageOrder", sal_Int32(0));
+ }
+
+ sal_Int32 GetHandoutPageCount() const
+ {
+ sal_uInt32 nIndex = static_cast<sal_Int32>(mrProperties.getIntValue("SlidesPerPage", sal_Int32(0)));
+ if (nIndex<maSlidesPerPage.size())
+ return maSlidesPerPage[nIndex];
+ else if ( ! maSlidesPerPage.empty())
+ return maSlidesPerPage[0];
+ else
+ return 0;
+ }
+
+ bool IsDraw() const
+ {
+ return GetBoolValue("PageContentType", sal_Int32(0));
+ }
+
+ bool IsHandout() const
+ {
+ return GetBoolValue("PageContentType", sal_Int32(1));
+ }
+
+ bool IsNotes() const
+ {
+ return GetBoolValue("PageContentType", sal_Int32(2));
+ }
+
+ bool IsOutline() const
+ {
+ return GetBoolValue("PageContentType", sal_Int32(3));
+ }
+
+ sal_uLong GetOutputQuality() const
+ {
+ sal_Int32 nQuality = static_cast<sal_Int32>(mrProperties.getIntValue( "Quality", sal_Int32(0) ));
+ return nQuality;
+ }
+
+ bool IsPageSize() const
+ {
+ return GetBoolValue("PageOptions", sal_Int32(1));
+ }
+
+ bool IsTilePage() const
+ {
+ return GetBoolValue("PageOptions", sal_Int32(2)) || GetBoolValue("PageOptions", sal_Int32(3));
+ }
+
+ bool IsCutPage() const
+ {
+ return GetBoolValue("PageOptions", sal_Int32(0));
+ }
+
+ bool IsBooklet() const
+ {
+ return GetBoolValue("PrintProspect", false);
+ }
+
+ bool IsPrinterPreferred(DocumentType eDocType) const
+ {
+ bool bIsDraw = eDocType == DocumentType::Draw;
+ return IsTilePage() || IsPageSize() || IsBooklet() || (!bIsDraw && !IsNotes());
+ }
+
+ bool IsPrintExcluded() const
+ {
+ return (IsNotes() || IsDraw() || IsHandout()) && IsHiddenPages();
+ }
+
+ bool IsPrintFrontPage() const
+ {
+ sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 ));
+ return nInclude != 2;
+ }
+
+ bool IsPrintBackPage() const
+ {
+ sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 ));
+ return nInclude != 1;
+ }
+
+ bool IsPaperBin() const
+ {
+ return GetBoolValue("PrintPaperFromSetup", false);
+ }
+
+ bool IsPrintMarkedOnly() const
+ {
+ return GetBoolValue("PrintContent", sal_Int32(4));
+ }
+
+ OUString GetPrinterSelection (sal_Int32 nPageCount, sal_Int32 nCurrentPageIndex) const
+ {
+ sal_Int32 nContent = static_cast<sal_Int32>(mrProperties.getIntValue( "PrintContent", 0 ));
+ OUString sFullRange = "1-" + OUString::number(nPageCount);
+
+ if (nContent == 0) // all pages/slides
+ {
+ return sFullRange;
+ }
+
+ if (nContent == 1) // range
+ {
+ OUString sValue = mrProperties.getStringValue("PageRange");
+ return sValue.isEmpty() ? sFullRange : sValue;
+ }
+
+ if (nContent == 2 && // selection
+ nCurrentPageIndex >= 0)
+ {
+ return OUString::number(nCurrentPageIndex + 1);
+ }
+
+ return OUString();
+ }
+
+ private:
+ const vcl::PrinterOptionsHelper& mrProperties;
+ const std::vector<sal_Int32> maSlidesPerPage;
+
+ /** When the value of the property with name pName is a boolean then
+ return its value. When the property is unknown then
+ bDefaultValue is returned. Otherwise <FALSE/> is returned.
+ */
+ bool GetBoolValue (
+ const char* pName,
+ const bool bDefaultValue) const
+ {
+ bool bValue = mrProperties.getBoolValue( pName, bDefaultValue );
+ return bValue;
+ }
+
+ /** Return <TRUE/> when the value of the property with name pName is
+ an integer and its value is nTriggerValue. Otherwise <FALSE/> is
+ returned.
+ */
+ bool GetBoolValue (
+ const char* pName,
+ const sal_Int32 nTriggerValue) const
+ {
+ sal_Int32 nValue = static_cast<sal_Int32>(mrProperties.getIntValue( pName, 0 ));
+ return nValue == nTriggerValue;
+ }
+ };
+
+ /** A collection of values that helps to reduce the number of arguments
+ given to some functions. Note that not all values are set at the
+ same time.
+ */
+ class PrintInfo
+ {
+ public:
+ PrintInfo (
+ Printer* pPrinter,
+ const bool bPrintMarkedOnly)
+ : mpPrinter(pPrinter),
+ mnDrawMode(DrawModeFlags::Default),
+ maPrintSize(0,0),
+ maPageSize(0,0),
+ meOrientation(Orientation::Portrait),
+ mbPrintMarkedOnly(bPrintMarkedOnly)
+ {}
+
+ const VclPtr<Printer> mpPrinter;
+ DrawModeFlags mnDrawMode;
+ OUString msTimeDate;
+ OUString msPageString;
+ Size maPrintSize;
+ Size maPageSize;
+ Orientation meOrientation;
+ MapMode maMap;
+ const bool mbPrintMarkedOnly;
+ };
+
+ /** Output one page of the document to the given printer. Note that
+ more than one document page may be output to one printer page.
+ */
+ void PrintPage (
+ Printer& rPrinter,
+ ::sd::View& rPrintView,
+ SdPage& rPage,
+ View const * pView,
+ const bool bPrintMarkedOnly,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers)
+ {
+ rPrintView.ShowSdrPage(&rPage);
+
+ const MapMode aOriginalMapMode (rPrinter.GetMapMode());
+
+ // Set the visible layers
+ SdrPageView* pPageView = rPrintView.GetSdrPageView();
+ OSL_ASSERT(pPageView!=nullptr);
+ pPageView->SetVisibleLayers(rVisibleLayers);
+ pPageView->SetPrintableLayers(rPrintableLayers);
+
+ if (pView!=nullptr && bPrintMarkedOnly)
+ pView->DrawMarkedObj(rPrinter);
+ else
+ rPrintView.CompleteRedraw(&rPrinter,
+ vcl::Region(::tools::Rectangle(Point(0,0), rPage.GetSize())));
+
+ rPrinter.SetMapMode(aOriginalMapMode);
+
+ rPrintView.HideSdrPage();
+ }
+
+ /** Output a string (that typically is not part of a document page) to
+ the given printer.
+ */
+ void PrintMessage (
+ Printer& rPrinter,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset)
+ {
+ const vcl::Font aOriginalFont (rPrinter.OutputDevice::GetFont());
+ rPrinter.SetFont(vcl::Font(FAMILY_SWISS, Size(0, 423)));
+ rPrinter.DrawText(rPageStringOffset, rsPageString);
+ rPrinter.SetFont(aOriginalFont);
+ }
+
+ /** Read the resources and process then into a sequence of properties
+ that can be passed to the printing dialog.
+ */
+ class DialogCreator
+ {
+ public:
+ DialogCreator (ViewShellBase &rBase, bool bImpress, sal_Int32 nCurPage)
+ : mrBase(rBase)
+ , mbImpress(bImpress)
+ , mnCurPage(nCurPage)
+ {
+ ProcessResource();
+ }
+
+ const std::vector< beans::PropertyValue >& GetDialogControls() const
+ {
+ return maProperties;
+ }
+
+ const std::vector<sal_Int32>& GetSlidesPerPage() const
+ {
+ return maSlidesPerPage;
+ }
+
+ private:
+ ViewShellBase &mrBase;
+ std::vector<beans::PropertyValue> maProperties;
+ std::vector<sal_Int32> maSlidesPerPage;
+ bool mbImpress;
+ sal_Int32 mnCurPage;
+
+ void ProcessResource()
+ {
+ // load the writer PrinterOptions into the custom tab
+ beans::PropertyValue aOptionsUIFile;
+ aOptionsUIFile.Name = "OptionsUIFile";
+ if( mbImpress )
+ aOptionsUIFile.Value <<= OUString("modules/simpress/ui/impressprinteroptions.ui");
+ else
+ aOptionsUIFile.Value <<= OUString("modules/sdraw/ui/drawprinteroptions.ui");
+ maProperties.push_back(aOptionsUIFile);
+
+ SvtModuleOptions aOpt;
+ OUString aAppGroupname(SdResId(STR_IMPRESS_PRINT_UI_GROUP_NAME));
+ aAppGroupname = aAppGroupname.replaceFirst("%s", aOpt.GetModuleName(
+ mbImpress ? SvtModuleOptions::EModule::IMPRESS : SvtModuleOptions::EModule::DRAW));
+ AddDialogControl(vcl::PrinterOptionsHelper::setGroupControlOpt("tabcontrol-page2", aAppGroupname, ".HelpID:vcl:PrintDialog:TabPage:AppPage"));
+
+ uno::Sequence< OUString > aHelpIds, aWidgetIds;
+ if( mbImpress )
+ {
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PageContentType:ListBox" };
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
+ "impressdocument",
+ SdResId(STR_IMPRESS_PRINT_UI_CONTENT),
+ aHelpIds,
+ "PageContentType" ,
+ CreateChoice(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES)),
+ 0)
+ );
+
+ aHelpIds = { ".HelpID:vcl:PrintDialog:SlidesPerPage:ListBox" };
+ vcl::PrinterOptionsHelper::UIControlOptions aContentOpt( "PageContentType" , 1 );
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
+ "slidesperpage",
+ SdResId(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE),
+ aHelpIds,
+ "SlidesPerPage" ,
+ GetSlidesPerPageSequence(),
+ 0,
+ Sequence< sal_Bool >(),
+ aContentOpt
+ )
+ );
+
+ aHelpIds = { ".HelpID:vcl:PrintDialog:SlidesPerPageOrder:ListBox" };
+ vcl::PrinterOptionsHelper::UIControlOptions aSlidesPerPageOpt( "SlidesPerPage" , -1, true );
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
+ "slidesperpageorder",
+ SdResId(STR_IMPRESS_PRINT_UI_ORDER),
+ aHelpIds,
+ "SlidesPerPageOrder" ,
+ CreateChoice(STR_IMPRESS_PRINT_UI_ORDER_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_ORDER_CHOICES)),
+ 0,
+ Sequence< sal_Bool >(),
+ aSlidesPerPageOpt )
+ );
+ }
+
+ AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("contents",
+ SdResId(STR_IMPRESS_PRINT_UI_INCLUDE_CONTENT), "" ) );
+
+ if( mbImpress )
+ {
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printname",
+ SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_NAME),
+ ".HelpID:vcl:PrintDialog:IsPrintName:CheckBox" ,
+ "IsPrintName" ,
+ officecfg::Office::Impress::Print::Other::PageName::get()
+ )
+ );
+ }
+ else
+ {
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printname",
+ SdResId(STR_DRAW_PRINT_UI_IS_PRINT_NAME),
+ ".HelpID:vcl:PrintDialog:IsPrintName:CheckBox" ,
+ "IsPrintName" ,
+ officecfg::Office::Draw::Print::Other::PageName::get()
+ )
+ );
+ }
+
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printdatetime",
+ SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_DATE),
+ ".HelpID:vcl:PrintDialog:IsPrintDateTime:CheckBox" ,
+ "IsPrintDateTime" ,
+ // Separate settings for time and date in Impress/Draw -> Print page, check that both are set
+ mbImpress ?
+ officecfg::Office::Impress::Print::Other::Date::get() &&
+ officecfg::Office::Impress::Print::Other::Time::get() :
+ officecfg::Office::Draw::Print::Other::Date::get() &&
+ officecfg::Office::Draw::Print::Other::Time::get()
+ )
+ );
+
+ if( mbImpress )
+ {
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printhidden",
+ SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_HIDDEN),
+ ".HelpID:vcl:PrintDialog:IsPrintHidden:CheckBox" ,
+ "IsPrintHidden" ,
+ officecfg::Office::Impress::Print::Other::HiddenPage::get()
+ )
+ );
+ }
+
+ AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("color",
+ SdResId(STR_IMPRESS_PRINT_UI_QUALITY), "" ) );
+
+ aHelpIds = { ".HelpID:vcl:PrintDialog:Quality:RadioButton:0",
+ ".HelpID:vcl:PrintDialog:Quality:RadioButton:1",
+ ".HelpID:vcl:PrintDialog:Quality:RadioButton:2" };
+ aWidgetIds = { "originalcolors", "grayscale", "blackandwhite" };
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(
+ aWidgetIds,
+ "",
+ aHelpIds,
+ "Quality" ,
+ CreateChoice(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES)),
+ mbImpress ? officecfg::Office::Impress::Print::Other::Quality::get() :
+ officecfg::Office::Draw::Print::Other::Quality::get() )
+
+ );
+
+ AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("pagesizes",
+ SdResId(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS), "" ) );
+
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:0",
+ ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:1",
+ ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:2",
+ ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:3" };
+ aWidgetIds = { "originalsize", "fittoprintable", "distributeonmultiple", "tilesheet" };
+
+ // Mutually exclusive page options settings are stored in separate config keys...
+ // TODO: There is no config key to set the distributeonmultiple option as default
+ sal_Int32 nDefaultChoice = 0;
+ if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageSize::get() :
+ officecfg::Office::Draw::Print::Page::PageSize::get() )
+ {
+ nDefaultChoice = 1;
+ }
+ else if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageTile::get() :
+ officecfg::Office::Draw::Print::Page::PageTile::get() )
+ {
+ nDefaultChoice = 3;
+ }
+ vcl::PrinterOptionsHelper::UIControlOptions aPageOptionsOpt("PrintProspect", 0);
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(
+ aWidgetIds,
+ "",
+ aHelpIds,
+ "PageOptions" ,
+ mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES)) :
+ CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW)),
+ nDefaultChoice,
+ Sequence< sal_Bool >(),
+ aPageOptionsOpt
+ )
+ );
+
+ vcl::PrinterOptionsHelper::UIControlOptions aBrochureOpt;
+ aBrochureOpt.maGroupHint = "LayoutPage" ;
+ AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("pagesides",
+ SdResId(STR_IMPRESS_PRINT_UI_PAGE_SIDES), "",
+ aBrochureOpt ) );
+
+ // brochure printing
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("brochure",
+ SdResId(STR_IMPRESS_PRINT_UI_BROCHURE),
+ ".HelpID:vcl:PrintDialog:PrintProspect:CheckBox" ,
+ "PrintProspect" ,
+ mbImpress ? officecfg::Office::Impress::Print::Page::Booklet::get() :
+ officecfg::Office::Draw::Print::Page::Booklet::get(),
+ aBrochureOpt
+ )
+ );
+
+ vcl::PrinterOptionsHelper::UIControlOptions
+ aIncludeOpt( "PrintProspect" , -1, false );
+ aIncludeOpt.maGroupHint = "LayoutPage" ;
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PrintProspectInclude:ListBox" };
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
+ "brochureinclude",
+ SdResId(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE),
+ aHelpIds,
+ "PrintProspectInclude" ,
+ CreateChoice(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE_LIST, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE_LIST)),
+ 0,
+ Sequence< sal_Bool >(),
+ aIncludeOpt
+ )
+ );
+
+ // paper tray (on options page)
+ vcl::PrinterOptionsHelper::UIControlOptions aPaperTrayOpt;
+ aPaperTrayOpt.maGroupHint = "OptionsPageOptGroup" ;
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printpaperfromsetup",
+ SdResId(STR_IMPRESS_PRINT_UI_PAPER_TRAY),
+ ".HelpID:vcl:PrintDialog:PrintPaperFromSetup:CheckBox" ,
+ "PrintPaperFromSetup" ,
+ false,
+ aPaperTrayOpt
+ )
+ );
+ // print range selection
+ vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt;
+ aPrintRangeOpt.mbInternalOnly = true;
+ aPrintRangeOpt.maGroupHint = "PrintRange" ;
+ AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("printrange",
+ mbImpress ? SdResId(STR_IMPRESS_PRINT_UI_SLIDE_RANGE) : SdResId(STR_IMPRESS_PRINT_UI_PAGE_RANGE),
+ "",
+ aPrintRangeOpt )
+ );
+
+ // check if there is a selection of slides
+ OUString aPageRange(OUString::number(mnCurPage + 1));
+ int nPrintRange(0);
+ using sd::slidesorter::SlideSorterViewShell;
+ SlideSorterViewShell* const pSSViewSh(SlideSorterViewShell::GetSlideSorter(mrBase));
+ if (pSSViewSh)
+ {
+ const std::shared_ptr<SlideSorterViewShell::PageSelection> pPageSelection(pSSViewSh->GetPageSelection());
+ if (bool(pPageSelection) && pPageSelection->size() > 1)
+ {
+ OUStringBuffer aBuf;
+ // TODO: this could be improved by writing ranges instead of consecutive page
+ // numbers if appropriate. Do we have a helper function for that somewhere?
+ bool bFirst(true);
+ for (auto pPage: *pPageSelection)
+ {
+ if (bFirst)
+ bFirst = false;
+ else
+ aBuf.append(',');
+ aBuf.append(static_cast<sal_Int32>(pPage->GetPageNum() / 2 + 1));
+ }
+ aPageRange = aBuf.makeStringAndClear();
+ nPrintRange = 1;
+ }
+ }
+/*
+ OUString aPrintRangeName( "PrintContent" );
+ aHelpIds.realloc( 1 );
+ aHelpIds[0] = ".HelpID:vcl:PrintDialog:PageContentType:ListBox";
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt( "printpagesbox", OUString(),
+ aHelpIds, aPrintRangeName,
+ mbImpress ? CreateChoice( STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE ) ) :
+ CreateChoice( STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE ) ),
+ nPrintRange ) );
+*/
+ OUString aPrintRangeName( "PrintContent" );
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:0",
+ ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:1",
+ ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:2" };
+ aWidgetIds = { "rbAllPages", "rbRangePages", "rbRangeSelection" };
+
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(aWidgetIds, OUString(),
+ aHelpIds, aPrintRangeName,
+ mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE)) :
+ CreateChoice(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE)),
+ nPrintRange )
+ );
+ // create an Edit dependent on "Pages" selected
+ vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, true );
+ AddDialogControl(vcl::PrinterOptionsHelper::setEditControlOpt("pagerange", "",
+ ".HelpID:vcl:PrintDialog:PageRange:Edit", "PageRange",
+ aPageRange, aPageRangeOpt));
+ vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintRangeName, -1, true);
+ AddDialogControl(vcl::PrinterOptionsHelper::setChoiceListControlOpt("evenoddbox", "",
+ uno::Sequence<OUString>(), "EvenOdd", uno::Sequence<OUString>(),
+ 0, uno::Sequence<sal_Bool>(), aEvenOddOpt));
+ }
+
+ void AddDialogControl( const Any& i_rCtrl )
+ {
+ beans::PropertyValue aVal;
+ aVal.Value = i_rCtrl;
+ maProperties.push_back( aVal );
+ }
+
+ static Sequence<OUString> CreateChoice(const TranslateId* pResourceId, size_t nCount)
+ {
+ Sequence<OUString> aChoices (nCount);
+ std::transform(pResourceId, pResourceId + nCount, aChoices.getArray(),
+ [](const auto& id) { return SdResId(id); });
+ return aChoices;
+ }
+
+ Sequence<OUString> GetSlidesPerPageSequence()
+ {
+ const Sequence<OUString> aChoice (
+ CreateChoice(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES)));
+ maSlidesPerPage.clear();
+ maSlidesPerPage.push_back(0); // first is using the default
+ std::transform(std::next(aChoice.begin()), aChoice.end(), std::back_inserter(maSlidesPerPage),
+ [](const OUString& rChoice) -> sal_Int32 { return rChoice.toInt32(); });
+ return aChoice;
+ }
+ };
+
+ /** The Prepare... methods of the DocumentRenderer::Implementation class
+ create a set of PrinterPage objects that contain all necessary
+ information to do the actual printing. There is one PrinterPage
+ object per printed page. Derived classes implement the actual, mode
+ specific printing.
+
+ This and all derived classes support the asynchronous printing
+ process by not storing pointers to any data with lifetime shorter
+ than the PrinterPage objects, i.e. slides, shapes, (one of) the
+ outliner (of the document).
+ */
+ class PrinterPage
+ {
+ public:
+ PrinterPage (
+ const PageKind ePageKind,
+ const MapMode& rMapMode,
+ const bool bPrintMarkedOnly,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : mePageKind(ePageKind),
+ maMap(rMapMode),
+ mbPrintMarkedOnly(bPrintMarkedOnly),
+ msPageString(rsPageString),
+ maPageStringOffset(rPageStringOffset),
+ mnDrawMode(nDrawMode),
+ meOrientation(eOrientation),
+ mnPaperTray(nPaperTray)
+ {
+ }
+
+ virtual ~PrinterPage() {}
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell& rViewShell,
+ View* pView,
+ DrawView& rPrintView,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers) const = 0;
+
+ DrawModeFlags GetDrawMode() const { return mnDrawMode; }
+ Orientation GetOrientation() const { return meOrientation; }
+ sal_uInt16 GetPaperTray() const { return mnPaperTray; }
+
+ protected:
+ const PageKind mePageKind;
+ const MapMode maMap;
+ const bool mbPrintMarkedOnly;
+ const OUString msPageString;
+ const Point maPageStringOffset;
+ const DrawModeFlags mnDrawMode;
+ const Orientation meOrientation;
+ const sal_uInt16 mnPaperTray;
+ };
+
+ /** The RegularPrinterPage is used for printing one regular slide (no
+ notes, handout, or outline) to one printer page.
+ */
+ class RegularPrinterPage : public PrinterPage
+ {
+ public:
+ RegularPrinterPage (
+ const sal_uInt16 nPageIndex,
+ const PageKind ePageKind,
+ const MapMode& rMapMode,
+ const bool bPrintMarkedOnly,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, rsPageString,
+ rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
+ mnPageIndex(nPageIndex)
+ {
+ }
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell&,
+ View* pView,
+ DrawView& rPrintView,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers) const override
+ {
+ SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
+ rPrinter.SetMapMode(maMap);
+ PrintPage(
+ rPrinter,
+ rPrintView,
+ *pPageToPrint,
+ pView,
+ mbPrintMarkedOnly,
+ rVisibleLayers,
+ rPrintableLayers);
+ PrintMessage(
+ rPrinter,
+ msPageString,
+ maPageStringOffset);
+ }
+
+ private:
+ const sal_uInt16 mnPageIndex;
+ };
+
+ /** Print one slide multiple times on a printer page so that the whole
+ printer page is covered.
+ */
+ class TiledPrinterPage : public PrinterPage
+ {
+ public:
+ TiledPrinterPage (
+ const sal_uInt16 nPageIndex,
+ const PageKind ePageKind,
+ const bool bPrintMarkedOnly,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : PrinterPage(ePageKind, MapMode(), bPrintMarkedOnly, rsPageString,
+ rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
+ mnPageIndex(nPageIndex)
+ {
+ }
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell&,
+ View* pView,
+ DrawView& rPrintView,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers) const override
+ {
+ SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
+ if (pPageToPrint==nullptr)
+ return;
+ MapMode aMap (rPrinter.GetMapMode());
+
+ const Size aPageSize (pPageToPrint->GetSize());
+ const Size aPrintSize (rPrinter.GetOutputSize());
+
+ const sal_Int32 nPageWidth (aPageSize.Width() + mnGap
+ - pPageToPrint->GetLeftBorder() - pPageToPrint->GetRightBorder());
+ const sal_Int32 nPageHeight (aPageSize.Height() + mnGap
+ - pPageToPrint->GetUpperBorder() - pPageToPrint->GetLowerBorder());
+ if (nPageWidth<=0 || nPageHeight<=0)
+ return;
+
+ // Print at least two rows and columns. More if the document
+ // page fits completely onto the printer page.
+ const sal_Int32 nColumnCount (std::max(sal_Int32(2),
+ sal_Int32(aPrintSize.Width() / nPageWidth)));
+ const sal_Int32 nRowCount (std::max(sal_Int32(2),
+ sal_Int32(aPrintSize.Height() / nPageHeight)));
+ for (sal_Int32 nRow=0; nRow<nRowCount; ++nRow)
+ for (sal_Int32 nColumn=0; nColumn<nColumnCount; ++nColumn)
+ {
+ aMap.SetOrigin(Point(nColumn*nPageWidth,nRow*nPageHeight));
+ rPrinter.SetMapMode(aMap);
+ PrintPage(
+ rPrinter,
+ rPrintView,
+ *pPageToPrint,
+ pView,
+ mbPrintMarkedOnly,
+ rVisibleLayers,
+ rPrintableLayers);
+ }
+
+ PrintMessage(
+ rPrinter,
+ msPageString,
+ maPageStringOffset);
+ }
+
+ private:
+ const sal_uInt16 mnPageIndex;
+ static const sal_Int32 mnGap = 500;
+ };
+
+ /** Print two slides to one printer page so that the resulting pages
+ form a booklet.
+ */
+ class BookletPrinterPage : public PrinterPage
+ {
+ public:
+ BookletPrinterPage (
+ const sal_uInt16 nFirstPageIndex,
+ const sal_uInt16 nSecondPageIndex,
+ const Point& rFirstOffset,
+ const Point& rSecondOffset,
+ const PageKind ePageKind,
+ const MapMode& rMapMode,
+ const bool bPrintMarkedOnly,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, "",
+ Point(), nDrawMode, eOrientation, nPaperTray),
+ mnFirstPageIndex(nFirstPageIndex),
+ mnSecondPageIndex(nSecondPageIndex),
+ maFirstOffset(rFirstOffset),
+ maSecondOffset(rSecondOffset)
+ {
+ }
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell&,
+ View* pView,
+ DrawView& rPrintView,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers) const override
+ {
+ MapMode aMap (maMap);
+ SdPage* pPageToPrint = rDocument.GetSdPage(mnFirstPageIndex, mePageKind);
+ if (pPageToPrint)
+ {
+ aMap.SetOrigin(maFirstOffset);
+ rPrinter.SetMapMode(aMap);
+ PrintPage(
+ rPrinter,
+ rPrintView,
+ *pPageToPrint,
+ pView,
+ mbPrintMarkedOnly,
+ rVisibleLayers,
+ rPrintableLayers);
+ }
+
+ pPageToPrint = rDocument.GetSdPage(mnSecondPageIndex, mePageKind);
+ if( !pPageToPrint )
+ return;
+
+ aMap.SetOrigin(maSecondOffset);
+ rPrinter.SetMapMode(aMap);
+ PrintPage(
+ rPrinter,
+ rPrintView,
+ *pPageToPrint,
+ pView,
+ mbPrintMarkedOnly,
+ rVisibleLayers,
+ rPrintableLayers);
+ }
+
+ private:
+ const sal_uInt16 mnFirstPageIndex;
+ const sal_uInt16 mnSecondPageIndex;
+ const Point maFirstOffset;
+ const Point maSecondOffset;
+ };
+
+ /** One handout page displays one to nine slides.
+ */
+ class HandoutPrinterPage : public PrinterPage
+ {
+ public:
+ HandoutPrinterPage (
+ const sal_uInt16 nHandoutPageIndex,
+ std::vector<sal_uInt16>&& rPageIndices,
+ const MapMode& rMapMode,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString,
+ rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
+ mnHandoutPageIndex(nHandoutPageIndex),
+ maPageIndices(std::move(rPageIndices))
+ {
+ }
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell& rViewShell,
+ View* pView,
+ DrawView& rPrintView,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers) const override
+ {
+ SdPage& rHandoutPage (*rDocument.GetSdPage(0, PageKind::Handout));
+
+ Reference< css::beans::XPropertySet > xHandoutPage( rHandoutPage.getUnoPage(), UNO_QUERY );
+ static const OUStringLiteral sPageNumber( u"Number" );
+
+ // Collect the page objects of the handout master.
+ std::vector<SdrPageObj*> aHandoutPageObjects;
+ SdrObjListIter aShapeIter (&rHandoutPage);
+ while (aShapeIter.IsMore())
+ {
+ SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next());
+ if (pPageObj)
+ aHandoutPageObjects.push_back(pPageObj);
+ }
+ if (aHandoutPageObjects.empty())
+ return;
+
+ // Connect page objects with pages.
+ std::vector<SdrPageObj*>::iterator aPageObjIter (aHandoutPageObjects.begin());
+ for (std::vector<sal_uInt16>::const_iterator
+ iPageIndex(maPageIndices.begin()),
+ iEnd(maPageIndices.end());
+ iPageIndex!=iEnd && aPageObjIter!=aHandoutPageObjects.end();
+ ++iPageIndex)
+ {
+ // Check if the page still exists.
+ if (*iPageIndex >= rDocument.GetSdPageCount(PageKind::Standard))
+ continue;
+
+ SdrPageObj* pPageObj = *aPageObjIter++;
+ pPageObj->SetReferencedPage(rDocument.GetSdPage(*iPageIndex, PageKind::Standard));
+ }
+
+ // if there are more page objects than pages left, set the rest to invisible
+ int nHangoverCount = 0;
+ while (aPageObjIter != aHandoutPageObjects.end())
+ {
+ (*aPageObjIter++)->SetReferencedPage(nullptr);
+ nHangoverCount++;
+ }
+
+ // Hide outlines for objects that have pages attached.
+ if (nHangoverCount > 0)
+ {
+ int nSkip = aHandoutPageObjects.size() - nHangoverCount;
+ aShapeIter.Reset();
+ while (aShapeIter.IsMore())
+ {
+ SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next());
+ if (pPathObj)
+ {
+ if (nSkip > 0)
+ --nSkip;
+ else
+ pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ }
+ }
+ }
+
+ if( xHandoutPage.is() ) try
+ {
+ xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(mnHandoutPageIndex) ) );
+ }
+ catch( Exception& )
+ {
+ }
+ rViewShell.SetPrintedHandoutPageNum( mnHandoutPageIndex + 1 );
+
+ rPrinter.SetMapMode(maMap);
+
+ PrintPage(
+ rPrinter,
+ rPrintView,
+ rHandoutPage,
+ pView,
+ false,
+ rVisibleLayers,
+ rPrintableLayers);
+ PrintMessage(
+ rPrinter,
+ msPageString,
+ maPageStringOffset);
+
+ if( xHandoutPage.is() ) try
+ {
+ xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(0) ) );
+ }
+ catch( Exception& )
+ {
+ }
+ rViewShell.SetPrintedHandoutPageNum(1);
+
+ // Restore outlines.
+ if (nHangoverCount > 0)
+ {
+ aShapeIter.Reset();
+ while (aShapeIter.IsMore())
+ {
+ SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next());
+ if (pPathObj != nullptr)
+ pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
+ }
+ }
+
+ }
+
+ private:
+ const sal_uInt16 mnHandoutPageIndex;
+ const std::vector<sal_uInt16> maPageIndices;
+ };
+
+ /** The outline information (title, subtitle, outline objects) of the
+ document. There is no fixed mapping of slides to printer pages.
+ */
+ class OutlinerPrinterPage : public PrinterPage
+ {
+ public:
+ OutlinerPrinterPage (
+ std::optional<OutlinerParaObject> pParaObject,
+ const MapMode& rMapMode,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString,
+ rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
+ mpParaObject(std::move(pParaObject))
+ {
+ }
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell&,
+ View*,
+ DrawView&,
+ const SdrLayerIDSet&,
+ const SdrLayerIDSet&) const override
+ {
+ // Set up the printer.
+ rPrinter.SetMapMode(maMap);
+
+ // Get and set up the outliner.
+ const ::tools::Rectangle aOutRect (rPrinter.GetPageOffset(), rPrinter.GetOutputSize());
+ Outliner* pOutliner = rDocument.GetInternalOutliner();
+ const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode());
+ const bool bSavedUpdateMode (pOutliner->IsUpdateLayout());
+ const Size aSavedPaperSize (pOutliner->GetPaperSize());
+
+ pOutliner->Init(OutlinerMode::OutlineView);
+ pOutliner->SetPaperSize(aOutRect.GetSize());
+ pOutliner->SetUpdateLayout(true);
+ pOutliner->Clear();
+ pOutliner->SetText(*mpParaObject);
+
+ pOutliner->Draw(rPrinter, aOutRect);
+
+ PrintMessage(
+ rPrinter,
+ msPageString,
+ maPageStringOffset);
+
+ // Restore outliner and printer.
+ pOutliner->Clear();
+ pOutliner->SetUpdateLayout(bSavedUpdateMode);
+ pOutliner->SetPaperSize(aSavedPaperSize);
+ pOutliner->Init(nSavedOutlMode);
+ }
+
+ private:
+ std::optional<OutlinerParaObject> mpParaObject;
+ };
+}
+
+//===== DocumentRenderer::Implementation ======================================
+
+class DocumentRenderer::Implementation
+ : public SfxListener,
+ public vcl::PrinterOptionsHelper
+{
+public:
+ explicit Implementation (ViewShellBase& rBase)
+ : mxObjectShell(rBase.GetDocShell())
+ , mrBase(rBase)
+ , mbIsDisposed(false)
+ , mpPrinter(nullptr)
+ , mbHasOrientationWarningBeenShown(false)
+ {
+ DialogCreator aCreator( mrBase, mrBase.GetDocShell()->GetDocumentType() == DocumentType::Impress, GetCurrentPageIndex() );
+ m_aUIProperties = aCreator.GetDialogControls();
+ maSlidesPerPage = aCreator.GetSlidesPerPage();
+
+ StartListening(mrBase);
+ }
+
+ virtual ~Implementation() override
+ {
+ EndListening(mrBase);
+ }
+
+ virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override
+ {
+ if (&rBroadcaster != &static_cast<SfxBroadcaster&>(mrBase))
+ return;
+
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ mbIsDisposed = true;
+ }
+ }
+
+ /** Process the sequence of properties given to one of the XRenderable
+ methods.
+ */
+ void ProcessProperties (const css::uno::Sequence<css::beans::PropertyValue >& rOptions)
+ {
+ OSL_ASSERT(!mbIsDisposed);
+ if (mbIsDisposed)
+ return;
+
+ bool bIsValueChanged = processProperties( rOptions );
+ bool bIsPaperChanged = false;
+
+ // The RenderDevice property is handled specially: its value is
+ // stored in mpPrinter instead of being retrieved on demand.
+ Any aDev( getValue( "RenderDevice" ) );
+ Reference<awt::XDevice> xRenderDevice;
+
+ if (aDev >>= xRenderDevice)
+ {
+ VCLXDevice* pDevice = comphelper::getFromUnoTunnel<VCLXDevice>(xRenderDevice);
+ VclPtr< OutputDevice > pOut = pDevice ? pDevice->GetOutputDevice()
+ : VclPtr< OutputDevice >();
+ mpPrinter = dynamic_cast<Printer*>(pOut.get());
+ Size aPageSizePixel = mpPrinter ? mpPrinter->GetPaperSizePixel() : Size();
+ if( aPageSizePixel != maPrinterPageSizePixel )
+ {
+ bIsPaperChanged = true;
+ maPrinterPageSizePixel = aPageSizePixel;
+ }
+ }
+
+ if (bIsValueChanged && ! mpOptions )
+ mpOptions.reset(new PrintOptions(*this, std::vector(maSlidesPerPage)));
+ if( bIsValueChanged || bIsPaperChanged )
+ PreparePages();
+ }
+
+ /** Return the number of pages that are to be printed.
+ */
+ sal_Int32 GetPrintPageCount() const
+ {
+ OSL_ASSERT(!mbIsDisposed);
+ if (mbIsDisposed)
+ return 0;
+ else
+ return maPrinterPages.size();
+ }
+
+ /** Return a sequence of properties that can be returned by the
+ XRenderable::getRenderer() method.
+ */
+ css::uno::Sequence<css::beans::PropertyValue> GetProperties () const
+ {
+ css::uno::Sequence<css::beans::PropertyValue> aProperties{
+ comphelper::makePropertyValue("ExtraPrintUIOptions",
+ comphelper::containerToSequence(m_aUIProperties)),
+ comphelper::makePropertyValue("PageSize", maPrintSize),
+ // FIXME: is this always true ?
+ comphelper::makePropertyValue("PageIncludesNonprintableArea", true)
+ };
+
+ return aProperties;
+ }
+
+ /** Print one of the prepared pages.
+ */
+ void PrintPage (const sal_Int32 nIndex)
+ {
+ OSL_ASSERT(!mbIsDisposed);
+ if (mbIsDisposed)
+ return;
+
+ Printer& rPrinter (*mpPrinter);
+
+ std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
+ if ( ! pViewShell)
+ return;
+
+ SdDrawDocument* pDocument = pViewShell->GetDoc();
+ OSL_ASSERT(pDocument!=nullptr);
+
+ std::shared_ptr<DrawViewShell> pDrawViewShell(
+ std::dynamic_pointer_cast<DrawViewShell>(mrBase.GetMainViewShell()));
+
+ if (!mpPrintView)
+ mpPrintView.reset(new DrawView(mrBase.GetDocShell(), &rPrinter, nullptr));
+
+ if (nIndex<0 || sal::static_int_cast<sal_uInt32>(nIndex)>=maPrinterPages.size())
+ return;
+
+ const std::shared_ptr<PrinterPage> pPage (maPrinterPages[nIndex]);
+ OSL_ASSERT(pPage);
+ if ( ! pPage)
+ return;
+
+ const Orientation eSavedOrientation (rPrinter.GetOrientation());
+ const DrawModeFlags nSavedDrawMode (rPrinter.GetDrawMode());
+ const MapMode aSavedMapMode (rPrinter.GetMapMode());
+ const sal_uInt16 nSavedPaperBin (rPrinter.GetPaperBin());
+
+ // Set page orientation.
+ if ( ! rPrinter.SetOrientation(pPage->GetOrientation()))
+ {
+ if ( ! mbHasOrientationWarningBeenShown
+ && mpOptions->IsWarningOrientation())
+ {
+ mbHasOrientationWarningBeenShown = true;
+ // Show warning that the orientation could not be set.
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(
+ pViewShell->GetFrameWeld(), VclMessageType::Warning, VclButtonsType::OkCancel,
+ SdResId(STR_WARN_PRINTFORMAT_FAILURE)));
+ xWarn->set_default_response(RET_CANCEL);
+ if (xWarn->run() != RET_OK)
+ return;
+ }
+ }
+
+ // Set the draw mode.
+ rPrinter.SetDrawMode(pPage->GetDrawMode());
+
+ // Set paper tray.
+ rPrinter.SetPaperBin(pPage->GetPaperTray());
+
+ // Print the actual page.
+ pPage->Print(
+ rPrinter,
+ *pDocument,
+ *pViewShell,
+ pDrawViewShell ? pDrawViewShell->GetView() : nullptr,
+ *mpPrintView,
+ pViewShell->GetFrameView()->GetVisibleLayers(),
+ pViewShell->GetFrameView()->GetPrintableLayers());
+
+ rPrinter.SetOrientation(eSavedOrientation);
+ rPrinter.SetDrawMode(nSavedDrawMode);
+ rPrinter.SetMapMode(aSavedMapMode);
+ rPrinter.SetPaperBin(nSavedPaperBin);
+ }
+
+private:
+ // rhbz#657394: keep the document alive: prevents crash when
+ SfxObjectShellRef mxObjectShell; // destroying mpPrintView
+ ViewShellBase& mrBase;
+ bool mbIsDisposed;
+ VclPtr<Printer> mpPrinter;
+ Size maPrinterPageSizePixel;
+ std::unique_ptr<PrintOptions> mpOptions;
+ std::vector< std::shared_ptr< ::sd::PrinterPage> > maPrinterPages;
+ std::unique_ptr<DrawView> mpPrintView;
+ bool mbHasOrientationWarningBeenShown;
+ std::vector<sal_Int32> maSlidesPerPage;
+ awt::Size maPrintSize;
+
+ sal_Int32 GetCurrentPageIndex() const
+ {
+ const ViewShell *pShell = mrBase.GetMainViewShell().get();
+ const SdPage *pCurrentPage = pShell ? pShell->getCurrentPage() : nullptr;
+ return pCurrentPage ? (pCurrentPage->GetPageNum()-1)/2 : -1;
+ }
+
+ /** Determine and set the paper orientation.
+ */
+ void SetupPaperOrientation (
+ const PageKind ePageKind,
+ PrintInfo& rInfo)
+ {
+ SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
+ rInfo.meOrientation = Orientation::Portrait;
+
+ if( ! mpOptions->IsBooklet())
+ {
+ rInfo.meOrientation = pDocument->GetSdPage(0, ePageKind)->GetOrientation();
+ }
+ else if (rInfo.maPageSize.Width() < rInfo.maPageSize.Height())
+ rInfo.meOrientation = Orientation::Landscape;
+
+ // Draw and Notes should usually abide by their specified paper size
+ Size aPaperSize;
+ if (!mpOptions->IsPrinterPreferred(pDocument->GetDocumentType()))
+ {
+ aPaperSize.setWidth(rInfo.maPageSize.Width());
+ aPaperSize.setHeight(rInfo.maPageSize.Height());
+ }
+ else
+ {
+ aPaperSize.setWidth(rInfo.mpPrinter->GetPaperSize().Width());
+ aPaperSize.setHeight(rInfo.mpPrinter->GetPaperSize().Height());
+ }
+
+ maPrintSize = awt::Size(aPaperSize.Width(), aPaperSize.Height());
+
+ if (mpOptions->IsPrinterPreferred(pDocument->GetDocumentType()))
+ {
+ if( (rInfo.meOrientation == Orientation::Landscape &&
+ (aPaperSize.Width() < aPaperSize.Height()))
+ ||
+ (rInfo.meOrientation == Orientation::Portrait &&
+ (aPaperSize.Width() > aPaperSize.Height()))
+ )
+ {
+ maPrintSize = awt::Size(aPaperSize.Height(), aPaperSize.Width());
+ }
+ }
+ }
+
+ /** Top most method for preparing printer pages. In this and the other
+ Prepare... methods the various special cases are detected and
+ handled.
+ For every page that is to be printed (that may contain several
+ slides) one PrinterPage object is created and inserted into
+ maPrinterPages.
+ */
+ void PreparePages()
+ {
+ mpPrintView.reset();
+ maPrinterPages.clear();
+ mbHasOrientationWarningBeenShown = false;
+
+ ViewShell* pShell = mrBase.GetMainViewShell().get();
+
+ PrintInfo aInfo (mpPrinter, mpOptions->IsPrintMarkedOnly());
+
+ if (aInfo.mpPrinter==nullptr || pShell==nullptr)
+ return;
+
+ MapMode aMap (aInfo.mpPrinter->GetMapMode());
+ aMap.SetMapUnit(MapUnit::Map100thMM);
+ aInfo.maMap = aMap;
+ mpPrinter->SetMapMode(aMap);
+
+ ::Outliner& rOutliner = mrBase.GetDocument()->GetDrawOutliner();
+ const EEControlBits nSavedControlWord (rOutliner.GetControlWord());
+ EEControlBits nCntrl = nSavedControlWord;
+ nCntrl &= ~EEControlBits::MARKFIELDS;
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+ rOutliner.SetControlWord( nCntrl );
+
+ // When in outline view then apply all pending changes to the model.
+ if( auto pOutlineViewShell = dynamic_cast< OutlineViewShell *>( pShell ) )
+ pOutlineViewShell->PrepareClose (false);
+
+ // Collect some frequently used data.
+ if (mpOptions->IsDate())
+ {
+ aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData()->getDate( Date( Date::SYSTEM ) );
+ aInfo.msTimeDate += " ";
+ }
+
+ if (mpOptions->IsTime())
+ aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData()->getTime( ::tools::Time( ::tools::Time::SYSTEM ), false );
+
+ // Draw and Notes should usually use specified paper size when printing
+ if (!mpOptions->IsPrinterPreferred(mrBase.GetDocShell()->GetDocumentType()))
+ {
+ aInfo.maPrintSize = mrBase.GetDocument()->GetSdPage(0, PageKind::Standard)->GetSize();
+ maPrintSize = awt::Size(aInfo.maPrintSize.Width(),
+ aInfo.maPrintSize.Height());
+ }
+ else
+ {
+ aInfo.maPrintSize = aInfo.mpPrinter->GetOutputSize();
+ maPrintSize = awt::Size(
+ aInfo.mpPrinter->GetPaperSize().Width(),
+ aInfo.mpPrinter->GetPaperSize().Height());
+ }
+
+ switch (mpOptions->GetOutputQuality())
+ {
+ case 1: // Grayscale
+ aInfo.mnDrawMode = DrawModeFlags::GrayLine | DrawModeFlags::GrayFill
+ | DrawModeFlags::GrayText | DrawModeFlags::GrayBitmap
+ | DrawModeFlags::GrayGradient;
+ break;
+
+ case 2: // Black & White
+ aInfo.mnDrawMode = DrawModeFlags::BlackLine | DrawModeFlags::WhiteFill
+ | DrawModeFlags::BlackText | DrawModeFlags::GrayBitmap
+ | DrawModeFlags::WhiteGradient;
+ break;
+
+ default:
+ aInfo.mnDrawMode = DrawModeFlags::Default;
+ }
+
+ if (mpOptions->IsDraw())
+ PrepareStdOrNotes(PageKind::Standard, aInfo);
+ if (mpOptions->IsNotes())
+ PrepareStdOrNotes(PageKind::Notes, aInfo);
+ if (mpOptions->IsHandout())
+ {
+ InitHandoutTemplate();
+ PrepareHandout(aInfo);
+ }
+ if (mpOptions->IsOutline())
+ PrepareOutline(aInfo);
+
+ rOutliner.SetControlWord(nSavedControlWord);
+ }
+
+ /** Create the page objects of the handout template. When the actual
+ printing takes place then the page objects are assigned different
+ sets of slides for each printed page (see HandoutPrinterPage::Print).
+ */
+ void InitHandoutTemplate()
+ {
+ const sal_Int32 nSlidesPerHandout (mpOptions->GetHandoutPageCount());
+ const bool bHandoutHorizontal (mpOptions->IsHandoutHorizontal());
+
+ AutoLayout eLayout = AUTOLAYOUT_HANDOUT6;
+ switch (nSlidesPerHandout)
+ {
+ case 0: eLayout = AUTOLAYOUT_NONE; break; // AUTOLAYOUT_HANDOUT1; break;
+ case 1: eLayout = AUTOLAYOUT_HANDOUT1; break;
+ case 2: eLayout = AUTOLAYOUT_HANDOUT2; break;
+ case 3: eLayout = AUTOLAYOUT_HANDOUT3; break;
+ case 4: eLayout = AUTOLAYOUT_HANDOUT4; break;
+ default:
+ case 6: eLayout = AUTOLAYOUT_HANDOUT6; break;
+ case 9: eLayout = AUTOLAYOUT_HANDOUT9; break;
+ }
+
+ if( !mrBase.GetDocument() )
+ return;
+
+ SdDrawDocument& rModel = *mrBase.GetDocument();
+
+ // first, prepare handout page (not handout master)
+
+ SdPage* pHandout = rModel.GetSdPage(0, PageKind::Handout);
+ if( !pHandout )
+ return;
+
+ // delete all previous shapes from handout page
+ while( pHandout->GetObjCount() )
+ {
+ SdrObject* pObj = pHandout->NbcRemoveObject(0);
+ if( pObj )
+ SdrObject::Free( pObj );
+ }
+
+ const bool bDrawLines (eLayout == AUTOLAYOUT_HANDOUT3);
+
+ std::vector< ::tools::Rectangle > aAreas;
+ SdPage::CalculateHandoutAreas( rModel, eLayout, bHandoutHorizontal, aAreas );
+
+ std::vector< ::tools::Rectangle >::iterator iter( aAreas.begin() );
+ while( iter != aAreas.end() )
+ {
+ pHandout->NbcInsertObject(
+ new SdrPageObj(
+ rModel,
+ (*iter++)));
+
+ if( bDrawLines && (iter != aAreas.end()) )
+ {
+ ::tools::Rectangle aRect( *iter++ );
+
+ basegfx::B2DPolygon aPoly;
+ aPoly.insert(0, basegfx::B2DPoint( aRect.Left(), aRect.Top() ) );
+ aPoly.insert(1, basegfx::B2DPoint( aRect.Right(), aRect.Top() ) );
+
+ basegfx::B2DHomMatrix aMatrix;
+ aMatrix.translate( 0.0, static_cast< double >( aRect.GetHeight() / 7 ) );
+
+ basegfx::B2DPolyPolygon aPathPoly;
+ for( sal_uInt16 nLine = 0; nLine < 7; nLine++ )
+ {
+ aPoly.transform( aMatrix );
+ aPathPoly.append( aPoly );
+ }
+
+ SdrPathObj* pPathObj = new SdrPathObj(
+ rModel,
+ SdrObjKind::PathLine,
+ aPathPoly);
+ pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
+ pPathObj->SetMergedItem(XLineColorItem(OUString(), COL_BLACK));
+
+ pHandout->NbcInsertObject( pPathObj );
+ }
+ }
+ }
+
+ /** Detect whether the specified slide is to be printed.
+ @return
+ When the slide is not to be printed then <NULL/> is returned.
+ Otherwise a pointer to the slide is returned.
+ */
+ SdPage* GetFilteredPage (
+ const sal_Int32 nPageIndex,
+ const PageKind ePageKind) const
+ {
+ OSL_ASSERT(mrBase.GetDocument() != nullptr);
+ OSL_ASSERT(nPageIndex>=0);
+ SdPage* pPage = mrBase.GetDocument()->GetSdPage(
+ sal::static_int_cast<sal_uInt16>(nPageIndex),
+ ePageKind);
+ if (pPage == nullptr)
+ return nullptr;
+ if ( ! pPage->IsExcluded() || mpOptions->IsPrintExcluded())
+ return pPage;
+ else
+ return nullptr;
+ }
+
+ /** Prepare the outline of the document for printing. There is no fixed
+ number of slides whose outline data is put onto one printer page.
+ If the current printer page has enough room for the outline of the
+ current slide then that is added. Otherwise a new printer page is
+ started.
+ */
+ void PrepareOutline (PrintInfo const & rInfo)
+ {
+ MapMode aMap (rInfo.maMap);
+ Point aPageOfs (rInfo.mpPrinter->GetPageOffset() );
+ aMap.SetScaleX(Fraction(1,2));
+ aMap.SetScaleY(Fraction(1,2));
+ mpPrinter->SetMapMode(aMap);
+
+ ::tools::Rectangle aOutRect(aPageOfs, rInfo.mpPrinter->GetOutputSize());
+ if( aOutRect.GetWidth() > aOutRect.GetHeight() )
+ {
+ Size aPaperSize( rInfo.mpPrinter->PixelToLogic( rInfo.mpPrinter->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) ) );
+ maPrintSize.Width = aPaperSize.Height();
+ maPrintSize.Height = aPaperSize.Width();
+ const auto nRotatedWidth = aOutRect.GetHeight();
+ const auto nRotatedHeight = aOutRect.GetWidth();
+ const auto nRotatedX = aPageOfs.Y();
+ const auto nRotatedY = aPageOfs.X();
+ aOutRect = ::tools::Rectangle(Point( nRotatedX, nRotatedY),
+ Size(nRotatedWidth, nRotatedHeight));
+ }
+
+ Outliner* pOutliner = mrBase.GetDocument()->GetInternalOutliner();
+ pOutliner->Init(OutlinerMode::OutlineView);
+ const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode());
+ const bool bSavedUpdateMode (pOutliner->IsUpdateLayout());
+ const Size aSavedPaperSize (pOutliner->GetPaperSize());
+ const MapMode aSavedMapMode (pOutliner->GetRefMapMode());
+ pOutliner->SetPaperSize(aOutRect.GetSize());
+ pOutliner->SetUpdateLayout(true);
+
+ ::tools::Long nPageH = aOutRect.GetHeight();
+
+ std::vector< sal_Int32 > aPages;
+ sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
+ StringRangeEnumerator::getRangesFromString(
+ mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
+ aPages, 0, nPageCount-1);
+
+ for (size_t nIndex = 0, nCount = aPages.size(); nIndex < nCount;)
+ {
+ pOutliner->Clear();
+
+ Paragraph* pPara = nullptr;
+ ::tools::Long nH (0);
+ while (nH < nPageH && nIndex<nCount)
+ {
+ SdPage* pPage = GetFilteredPage(aPages[nIndex], PageKind::Standard);
+ ++nIndex;
+ if (pPage == nullptr)
+ continue;
+
+ SdrTextObj* pTextObj = nullptr;
+ size_t nObj (0);
+
+ while (pTextObj==nullptr && nObj < pPage->GetObjCount())
+ {
+ SdrObject* pObj = pPage->GetObj(nObj++);
+ if (pObj->GetObjInventor() == SdrInventor::Default
+ && pObj->GetObjIdentifier() == SdrObjKind::TitleText)
+ {
+ pTextObj = dynamic_cast<SdrTextObj*>(pObj);
+ }
+ }
+
+ pPara = pOutliner->GetParagraph(pOutliner->GetParagraphCount() - 1);
+
+ if (pTextObj!=nullptr
+ && !pTextObj->IsEmptyPresObj()
+ && pTextObj->GetOutlinerParaObject())
+ {
+ pOutliner->AddText(*(pTextObj->GetOutlinerParaObject()));
+ }
+ else
+ pOutliner->Insert(OUString());
+
+ pTextObj = nullptr;
+ nObj = 0;
+
+ while (pTextObj==nullptr && nObj<pPage->GetObjCount())
+ {
+ SdrObject* pObj = pPage->GetObj(nObj++);
+ if (pObj->GetObjInventor() == SdrInventor::Default
+ && pObj->GetObjIdentifier() == SdrObjKind::OutlineText)
+ {
+ pTextObj = dynamic_cast<SdrTextObj*>(pObj);
+ }
+ }
+
+ bool bSubTitle (false);
+ if (!pTextObj)
+ {
+ bSubTitle = true;
+ pTextObj = dynamic_cast<SdrTextObj*>(pPage->GetPresObj(PresObjKind::Text)); // is there a subtitle?
+ }
+
+ sal_Int32 nParaCount1 = pOutliner->GetParagraphCount();
+
+ if (pTextObj!=nullptr
+ && !pTextObj->IsEmptyPresObj()
+ && pTextObj->GetOutlinerParaObject())
+ {
+ pOutliner->AddText(*(pTextObj->GetOutlinerParaObject()));
+ }
+
+ if (bSubTitle )
+ {
+ const sal_Int32 nParaCount2 (pOutliner->GetParagraphCount());
+ for (sal_Int32 nPara=nParaCount1; nPara<nParaCount2; ++nPara)
+ {
+ Paragraph* pP = pOutliner->GetParagraph(nPara);
+ if (pP!=nullptr && pOutliner->GetDepth(nPara) > 0)
+ pOutliner->SetDepth(pP, 0);
+ }
+ }
+
+ nH = pOutliner->GetTextHeight();
+ }
+
+ // Remove the last paragraph when that does not fit completely on
+ // the current page.
+ if (nH > nPageH && pPara!=nullptr)
+ {
+ sal_Int32 nCnt = pOutliner->GetAbsPos(
+ pOutliner->GetParagraph( pOutliner->GetParagraphCount() - 1 ) );
+ sal_Int32 nParaPos = pOutliner->GetAbsPos( pPara );
+ nCnt -= nParaPos;
+ pPara = pOutliner->GetParagraph( ++nParaPos );
+ if ( nCnt && pPara )
+ {
+ pOutliner->Remove(pPara, nCnt);
+ --nIndex;
+ }
+ }
+
+ if ( CheckForFrontBackPages( nIndex ) )
+ {
+ maPrinterPages.push_back(
+ std::make_shared<OutlinerPrinterPage>(
+ pOutliner->CreateParaObject(),
+ aMap,
+ rInfo.msTimeDate,
+ aPageOfs,
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ rInfo.mpPrinter->GetPaperBin()));
+ }
+ }
+
+ pOutliner->SetRefMapMode(aSavedMapMode);
+ pOutliner->SetUpdateLayout(bSavedUpdateMode);
+ pOutliner->SetPaperSize(aSavedPaperSize);
+ pOutliner->Init(nSavedOutlMode);
+ }
+
+ /** Prepare handout pages for slides that are to be printed.
+ */
+ void PrepareHandout (PrintInfo& rInfo)
+ {
+ SdDrawDocument* pDocument = mrBase.GetDocument();
+ OSL_ASSERT(pDocument != nullptr);
+ SdPage& rHandoutPage (*pDocument->GetSdPage(0, PageKind::Handout));
+
+ const bool bScalePage (mpOptions->IsPageSize());
+
+ sal_uInt16 nPaperBin;
+ if ( ! mpOptions->IsPaperBin())
+ nPaperBin = rHandoutPage.GetPaperBin();
+ else
+ nPaperBin = rInfo.mpPrinter->GetPaperBin();
+
+ // Change orientation?
+ SdPage& rMaster (dynamic_cast<SdPage&>(rHandoutPage.TRG_GetMasterPage()));
+ rInfo.meOrientation = rMaster.GetOrientation();
+
+ const Size aPaperSize (rInfo.mpPrinter->GetPaperSize());
+ if( (rInfo.meOrientation == Orientation::Landscape &&
+ (aPaperSize.Width() < aPaperSize.Height()))
+ ||
+ (rInfo.meOrientation == Orientation::Portrait &&
+ (aPaperSize.Width() > aPaperSize.Height()))
+ )
+ {
+ maPrintSize = awt::Size(aPaperSize.Height(), aPaperSize.Width());
+ }
+ else
+ {
+ maPrintSize = awt::Size(aPaperSize.Width(), aPaperSize.Height());
+ }
+
+ MapMode aMap (rInfo.maMap);
+ const Point aPageOfs (rInfo.mpPrinter->GetPageOffset());
+
+ if ( bScalePage )
+ {
+ const Size aPageSize (rHandoutPage.GetSize());
+ const Size aPrintSize (rInfo.mpPrinter->GetOutputSize());
+
+ const double fHorz = static_cast<double>(aPrintSize.Width()) / aPageSize.Width();
+ const double fVert = static_cast<double>(aPrintSize.Height()) / aPageSize.Height();
+
+ Fraction aFract;
+ if ( fHorz < fVert )
+ aFract = Fraction(aPrintSize.Width(), aPageSize.Width());
+ else
+ aFract = Fraction(aPrintSize.Height(), aPageSize.Height());
+
+ aMap.SetScaleX(aFract);
+ aMap.SetScaleY(aFract);
+ aMap.SetOrigin(Point());
+ }
+
+ std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
+ pViewShell->WriteFrameViewData();
+
+ // Count page shapes.
+ sal_uInt32 nShapeCount (0);
+ SdrObjListIter aShapeIter (&rHandoutPage);
+ while (aShapeIter.IsMore())
+ {
+ SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next());
+ if (pPageObj)
+ ++nShapeCount;
+ }
+
+ const sal_uInt16 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
+ const sal_uInt16 nHandoutPageCount = nShapeCount ? (nPageCount + nShapeCount - 1) / nShapeCount : 0;
+ pViewShell->SetPrintedHandoutPageCount( nHandoutPageCount );
+ mrBase.GetDocument()->setHandoutPageCount( nHandoutPageCount );
+
+ // Distribute pages to handout pages.
+ StringRangeEnumerator aRangeEnum(
+ mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
+ 0, nPageCount-1);
+ std::vector<sal_uInt16> aPageIndices;
+ sal_uInt16 nPrinterPageIndex = 0;
+ StringRangeEnumerator::Iterator it = aRangeEnum.begin(), itEnd = aRangeEnum.end();
+ bool bLastLoop = (it == itEnd);
+ while (!bLastLoop)
+ {
+ sal_Int32 nPageIndex = *it;
+ ++it;
+ bLastLoop = (it == itEnd);
+
+ if (GetFilteredPage(nPageIndex, PageKind::Standard))
+ aPageIndices.push_back(nPageIndex);
+ else if (!bLastLoop)
+ continue;
+
+ // Create a printer page when we have found one page for each
+ // placeholder or when this is the last (and special) loop.
+ if ( !aPageIndices.empty() && CheckForFrontBackPages( nPageIndex )
+ && (aPageIndices.size() == nShapeCount || bLastLoop) )
+ {
+ maPrinterPages.push_back(
+ std::make_shared<HandoutPrinterPage>(
+ nPrinterPageIndex++,
+ std::move(aPageIndices),
+ aMap,
+ rInfo.msTimeDate,
+ aPageOfs,
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ nPaperBin));
+ aPageIndices.clear();
+ }
+ }
+ }
+
+ /** Prepare the notes pages or regular slides.
+ */
+ void PrepareStdOrNotes (
+ const PageKind ePageKind,
+ PrintInfo& rInfo)
+ {
+ OSL_ASSERT(rInfo.mpPrinter != nullptr);
+
+ // Fill in page kind specific data.
+ SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
+ if (pDocument->GetSdPageCount(ePageKind) == 0)
+ return;
+ SdPage* pRefPage = pDocument->GetSdPage(0, ePageKind);
+ rInfo.maPageSize = pRefPage->GetSize();
+
+ SetupPaperOrientation(ePageKind, rInfo);
+
+ MapMode aMap (rInfo.maMap);
+ rInfo.maMap = aMap;
+
+ if (mpOptions->IsBooklet())
+ PrepareBooklet(ePageKind, rInfo);
+ else
+ PrepareRegularPages(ePageKind, rInfo);
+ }
+
+ /** Prepare slides in a non-booklet way: one slide per one to many
+ printer pages.
+ */
+ void PrepareRegularPages (
+ const PageKind ePageKind,
+ PrintInfo& rInfo)
+ {
+ std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
+ pViewShell->WriteFrameViewData();
+
+ sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
+ StringRangeEnumerator aRangeEnum(
+ mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
+ 0, nPageCount-1);
+ for (StringRangeEnumerator::Iterator
+ it = aRangeEnum.begin(),
+ itEnd = aRangeEnum.end();
+ it != itEnd;
+ ++it)
+ {
+ SdPage* pPage = GetFilteredPage(*it, ePageKind);
+ if (pPage == nullptr)
+ continue;
+
+ MapMode aMap (rInfo.maMap);
+ // is it possible that the page size changed?
+ const Size aPageSize = pPage->GetSize();
+
+ if (mpOptions->IsPageSize())
+ {
+ const double fHorz (static_cast<double>(rInfo.maPrintSize.Width()) / aPageSize.Width());
+ const double fVert (static_cast<double>(rInfo.maPrintSize.Height()) / aPageSize.Height());
+
+ Fraction aFract;
+ if (fHorz < fVert)
+ aFract = Fraction(rInfo.maPrintSize.Width(), aPageSize.Width());
+ else
+ aFract = Fraction(rInfo.maPrintSize.Height(), aPageSize.Height());
+
+ aMap.SetScaleX(aFract);
+ aMap.SetScaleY(aFract);
+ aMap.SetOrigin(Point());
+ }
+
+ if (mpOptions->IsPrintPageName())
+ {
+ rInfo.msPageString = pPage->GetName() + " ";
+ }
+ else
+ rInfo.msPageString.clear();
+ rInfo.msPageString += rInfo.msTimeDate;
+
+ ::tools::Long aPageWidth = aPageSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder();
+ ::tools::Long aPageHeight = aPageSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder();
+ // Bugfix for 44530:
+ // if it was implicitly changed (Landscape/Portrait),
+ // this is considered for tiling, respectively for the splitting up
+ // (Poster)
+ if( ( rInfo.maPrintSize.Width() > rInfo.maPrintSize.Height()
+ && aPageWidth < aPageHeight )
+ || ( rInfo.maPrintSize.Width() < rInfo.maPrintSize.Height()
+ && aPageWidth > aPageHeight ) )
+ {
+ const sal_Int32 nTmp (rInfo.maPrintSize.Width());
+ rInfo.maPrintSize.setWidth( rInfo.maPrintSize.Height() );
+ rInfo.maPrintSize.setHeight( nTmp );
+ }
+
+ if (mpOptions->IsTilePage()
+ && aPageWidth < rInfo.maPrintSize.Width()
+ && aPageHeight < rInfo.maPrintSize.Height())
+ {
+ // Put multiple slides on one printer page.
+ PrepareTiledPage(*it, *pPage, ePageKind, rInfo);
+ }
+ else
+ {
+ rInfo.maMap = aMap;
+ PrepareScaledPage(*it, *pPage, ePageKind, rInfo);
+ }
+ }
+ }
+
+ /** Put two slides on one printer page.
+ */
+ void PrepareBooklet (
+ const PageKind ePageKind,
+ const PrintInfo& rInfo)
+ {
+ MapMode aStdMap (rInfo.maMap);
+ Point aOffset;
+ Size aPrintSize_2 (rInfo.maPrintSize);
+ Size aPageSize_2 (rInfo.maPageSize);
+
+ if (rInfo.meOrientation == Orientation::Landscape)
+ aPrintSize_2.setWidth( aPrintSize_2.Width() >> 1 );
+ else
+ aPrintSize_2.setHeight( aPrintSize_2.Height() >> 1 );
+
+ const double fPageWH = static_cast<double>(aPageSize_2.Width()) / aPageSize_2.Height();
+ const double fPrintWH = static_cast<double>(aPrintSize_2.Width()) / aPrintSize_2.Height();
+
+ if( fPageWH < fPrintWH )
+ {
+ aPageSize_2.setWidth( static_cast<::tools::Long>( aPrintSize_2.Height() * fPageWH ) );
+ aPageSize_2.setHeight( aPrintSize_2.Height() );
+ }
+ else
+ {
+ aPageSize_2.setWidth( aPrintSize_2.Width() );
+ aPageSize_2.setHeight( static_cast<::tools::Long>( aPrintSize_2.Width() / fPageWH ) );
+ }
+
+ MapMode aMap (rInfo.maMap);
+ aMap.SetScaleX( Fraction( aPageSize_2.Width(), rInfo.maPageSize.Width() ) );
+ aMap.SetScaleY( Fraction( aPageSize_2.Height(), rInfo.maPageSize.Height() ) );
+
+ // calculate adjusted print size
+ const Size aAdjustedPrintSize (OutputDevice::LogicToLogic(
+ rInfo.maPrintSize,
+ aStdMap,
+ aMap));
+
+ if (rInfo.meOrientation == Orientation::Landscape)
+ {
+ aOffset.setX( ( ( aAdjustedPrintSize.Width() >> 1 ) - rInfo.maPageSize.Width() ) >> 1 );
+ aOffset.setY( ( aAdjustedPrintSize.Height() - rInfo.maPageSize.Height() ) >> 1 );
+ }
+ else
+ {
+ aOffset.setX( ( aAdjustedPrintSize.Width() - rInfo.maPageSize.Width() ) >> 1 );
+ aOffset.setY( ( ( aAdjustedPrintSize.Height() >> 1 ) - rInfo.maPageSize.Height() ) >> 1 );
+ }
+
+ // create vector of pages to print
+ sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(ePageKind);
+ StringRangeEnumerator aRangeEnum(
+ mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
+ 0, nPageCount-1);
+ std::vector< sal_uInt16 > aPageVector;
+ for (StringRangeEnumerator::Iterator
+ it = aRangeEnum.begin(),
+ itEnd = aRangeEnum.end();
+ it != itEnd;
+ ++it)
+ {
+ SdPage* pPage = GetFilteredPage(*it, ePageKind);
+ if (pPage != nullptr)
+ aPageVector.push_back(*it);
+ }
+
+ // create pairs of pages to print on each page
+ std::vector< std::pair< sal_uInt16, sal_uInt16 > > aPairVector;
+ if ( ! aPageVector.empty())
+ {
+ sal_uInt32 nFirstIndex = 0, nLastIndex = aPageVector.size() - 1;
+
+ if( aPageVector.size() & 1 )
+ aPairVector.emplace_back( sal_uInt16(65535), aPageVector[ nFirstIndex++ ] );
+ else
+ aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] );
+
+ while( nFirstIndex < nLastIndex )
+ {
+ if( nFirstIndex & 1 )
+ aPairVector.emplace_back( aPageVector[ nFirstIndex++ ], aPageVector[ nLastIndex-- ] );
+ else
+ aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] );
+ }
+ }
+
+ for (sal_uInt32
+ nIndex=0,
+ nCount=aPairVector.size();
+ nIndex < nCount;
+ ++nIndex)
+ {
+ if ( CheckForFrontBackPages( nIndex ) )
+ {
+ const std::pair<sal_uInt16, sal_uInt16> aPair (aPairVector[nIndex]);
+ Point aSecondOffset (aOffset);
+ if (rInfo.meOrientation == Orientation::Landscape)
+ aSecondOffset.AdjustX( aAdjustedPrintSize.Width() / 2 );
+ else
+ aSecondOffset.AdjustY( aAdjustedPrintSize.Height() / 2 );
+ maPrinterPages.push_back(
+ std::make_shared<BookletPrinterPage>(
+ aPair.first,
+ aPair.second,
+ aOffset,
+ aSecondOffset,
+ ePageKind,
+ aMap,
+ rInfo.mbPrintMarkedOnly,
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ rInfo.mpPrinter->GetPaperBin()));
+
+ }
+ }
+ }
+
+ /** Print one slide multiple times on one printer page so that the whole
+ printer page is covered.
+ */
+ void PrepareTiledPage (
+ const sal_Int32 nPageIndex,
+ const SdPage& rPage,
+ const PageKind ePageKind,
+ const PrintInfo& rInfo)
+ {
+ sal_uInt16 nPaperBin;
+ if ( ! mpOptions->IsPaperBin())
+ nPaperBin = rPage.GetPaperBin();
+ else
+ nPaperBin = rInfo.mpPrinter->GetPaperBin();
+
+ if ( !CheckForFrontBackPages( nPageIndex ) )
+ return;
+
+ maPrinterPages.push_back(
+ std::make_shared<TiledPrinterPage>(
+ sal::static_int_cast<sal_uInt16>(nPageIndex),
+ ePageKind,
+ rInfo.mbPrintMarkedOnly,
+ rInfo.msPageString,
+ rInfo.mpPrinter->GetPageOffset(),
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ nPaperBin));
+ }
+
+ /** Print one standard slide or notes page on one to many printer
+ pages. More than on printer page is used when the slide is larger
+ than the printable area.
+ */
+ void PrepareScaledPage (
+ const sal_Int32 nPageIndex,
+ const SdPage& rPage,
+ const PageKind ePageKind,
+ const PrintInfo& rInfo)
+ {
+ const Point aPageOffset (rInfo.mpPrinter->GetPageOffset());
+
+ sal_uInt16 nPaperBin;
+ if ( ! mpOptions->IsPaperBin())
+ nPaperBin = rPage.GetPaperBin();
+ else
+ nPaperBin = rInfo.mpPrinter->GetPaperBin();
+
+ // For pages larger then the printable area there
+ // are three options:
+ // 1. Scale down to the page to the printable area.
+ // 2. Print only the upper left part of the page
+ // (without the unprintable borders).
+ // 3. Split the page into parts of the size of the
+ // printable area.
+ const bool bScalePage (mpOptions->IsPageSize());
+ const bool bCutPage (mpOptions->IsCutPage());
+ MapMode aMap (rInfo.maMap);
+ if ( (bScalePage || bCutPage) && CheckForFrontBackPages( nPageIndex ) )
+ {
+ // Handle 1 and 2.
+
+ // if CutPage is set then do not move it, otherwise move the
+ // scaled page to printable area
+ maPrinterPages.push_back(
+ std::make_shared<RegularPrinterPage>(
+ sal::static_int_cast<sal_uInt16>(nPageIndex),
+ ePageKind,
+ aMap,
+ rInfo.mbPrintMarkedOnly,
+ rInfo.msPageString,
+ aPageOffset,
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ nPaperBin));
+ }
+ else
+ {
+ // Handle 3. Print parts of the page in the size of the
+ // printable area until the whole page is covered.
+
+ // keep the page content at its position if it fits, otherwise
+ // move it to the printable area
+ const ::tools::Long nPageWidth (
+ rInfo.maPageSize.Width() - rPage.GetLeftBorder() - rPage.GetRightBorder());
+ const ::tools::Long nPageHeight (
+ rInfo.maPageSize.Height() - rPage.GetUpperBorder() - rPage.GetLowerBorder());
+
+ Point aOrigin ( 0, 0 );
+
+ for (Point aPageOrigin = aOrigin;
+ -aPageOrigin.Y()<nPageHeight;
+ aPageOrigin.AdjustY( -rInfo.maPrintSize.Height() ))
+ {
+ for (aPageOrigin.setX(aOrigin.X());
+ -aPageOrigin.X()<nPageWidth;
+ aPageOrigin.AdjustX(-rInfo.maPrintSize.Width()))
+ {
+ if ( CheckForFrontBackPages( nPageIndex ) )
+ {
+ aMap.SetOrigin(aPageOrigin);
+ maPrinterPages.push_back(
+ std::make_shared<RegularPrinterPage>(
+ sal::static_int_cast<sal_uInt16>(nPageIndex),
+ ePageKind,
+ aMap,
+ rInfo.mbPrintMarkedOnly,
+ rInfo.msPageString,
+ aPageOffset,
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ nPaperBin));
+ }
+ }
+ }
+ }
+ }
+
+bool CheckForFrontBackPages( sal_Int32 nPage )
+{
+ const bool bIsIndexOdd(nPage & 1);
+ if ((!bIsIndexOdd && mpOptions->IsPrintFrontPage())
+ || (bIsIndexOdd && mpOptions->IsPrintBackPage()))
+ {
+ return true;
+ }
+ else
+ return false;
+}
+};
+
+//===== DocumentRenderer ======================================================
+
+DocumentRenderer::DocumentRenderer (ViewShellBase& rBase)
+ : mpImpl(new Implementation(rBase))
+{
+}
+
+DocumentRenderer::~DocumentRenderer()
+{
+}
+
+//----- XRenderable -----------------------------------------------------------
+
+sal_Int32 SAL_CALL DocumentRenderer::getRendererCount (
+ const css::uno::Any&,
+ const css::uno::Sequence<css::beans::PropertyValue >& rOptions)
+{
+ mpImpl->ProcessProperties(rOptions);
+ return mpImpl->GetPrintPageCount();
+}
+
+Sequence<beans::PropertyValue> SAL_CALL DocumentRenderer::getRenderer (
+ sal_Int32,
+ const css::uno::Any&,
+ const css::uno::Sequence<css::beans::PropertyValue>& rOptions)
+{
+ mpImpl->ProcessProperties(rOptions);
+ return mpImpl->GetProperties();
+}
+
+void SAL_CALL DocumentRenderer::render (
+ sal_Int32 nRenderer,
+ const css::uno::Any&,
+ const css::uno::Sequence<css::beans::PropertyValue>& rOptions)
+{
+ mpImpl->ProcessProperties(rOptions);
+ mpImpl->PrintPage(nRenderer);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/FormShellManager.cxx b/sd/source/ui/view/FormShellManager.cxx
new file mode 100644
index 000000000..3efa9bed7
--- /dev/null
+++ b/sd/source/ui/view/FormShellManager.cxx
@@ -0,0 +1,319 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <FormShellManager.hxx>
+
+#include <EventMultiplexer.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <Window.hxx>
+#include <vcl/vclevent.hxx>
+#include <svx/fmshell.hxx>
+#include <osl/diagnose.h>
+
+namespace sd {
+
+namespace {
+
+/** This factory is responsible for creating and deleting the FmFormShell.
+*/
+class FormShellManagerFactory
+ : public ::sd::ShellFactory<SfxShell>
+{
+public:
+ FormShellManagerFactory (ViewShell& rViewShell, FormShellManager& rManager);
+ virtual FmFormShell* CreateShell (ShellId nId) override;
+ virtual void ReleaseShell (SfxShell* pShell) override;
+
+private:
+ ::sd::ViewShell& mrViewShell;
+ FormShellManager& mrFormShellManager;
+};
+
+} // end of anonymous namespace
+
+FormShellManager::FormShellManager (ViewShellBase& rBase)
+ : mrBase(rBase),
+ mpFormShell(nullptr),
+ mbFormShellAboveViewShell(false),
+ mbIsMainViewChangePending(false),
+ mpMainViewShellWindow(nullptr)
+{
+ // Register at the EventMultiplexer to be informed about changes in the
+ // center pane.
+ Link<sd::tools::EventMultiplexerEvent&,void> aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler));
+ mrBase.GetEventMultiplexer()->AddEventListener(aLink);
+
+ RegisterAtCenterPane();
+}
+
+FormShellManager::~FormShellManager()
+{
+ SetFormShell(nullptr);
+ UnregisterAtCenterPane();
+
+ // Unregister from the EventMultiplexer.
+ Link<sd::tools::EventMultiplexerEvent&,void> aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler));
+ mrBase.GetEventMultiplexer()->RemoveEventListener(aLink);
+
+ if (mpSubShellFactory)
+ {
+ ViewShell* pShell = mrBase.GetMainViewShell().get();
+ if (pShell != nullptr)
+ mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell,mpSubShellFactory);
+ }
+}
+
+void FormShellManager::SetFormShell (FmFormShell* pFormShell)
+{
+ if (mpFormShell == pFormShell)
+ return;
+
+ // Disconnect from the old form shell.
+ if (mpFormShell != nullptr)
+ {
+ mpFormShell->SetControlActivationHandler(Link<LinkParamNone*,void>());
+ EndListening(*mpFormShell);
+ mpFormShell->SetView(nullptr);
+ }
+
+ mpFormShell = pFormShell;
+
+ // Connect to the new form shell.
+ if (mpFormShell != nullptr)
+ {
+ mpFormShell->SetControlActivationHandler(
+ LINK(
+ this,
+ FormShellManager,
+ FormControlActivated));
+ StartListening(*mpFormShell);
+
+ ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
+ if (pMainViewShell != nullptr)
+ {
+ // Prevent setting the view twice at the FmFormShell.
+ FmFormView* pFormView = pMainViewShell->GetView();
+ if (mpFormShell->GetFormView() != pFormView)
+ mpFormShell->SetView(pFormView);
+ }
+ }
+
+ // Tell the ViewShellManager where on the stack to place the form shell.
+ mrBase.GetViewShellManager()->SetFormShell(
+ mrBase.GetMainViewShell().get(),
+ mpFormShell,
+ mbFormShellAboveViewShell);
+}
+
+void FormShellManager::RegisterAtCenterPane()
+{
+ ViewShell* pShell = mrBase.GetMainViewShell().get();
+ if (pShell == nullptr)
+ return;
+
+ // No form shell for the slide sorter. Besides that it is not
+ // necessary, using both together results in crashes.
+ if (pShell->GetShellType() == ViewShell::ST_SLIDE_SORTER)
+ return;
+
+ mpMainViewShellWindow = pShell->GetActiveWindow();
+ if (mpMainViewShellWindow == nullptr)
+ return;
+
+ // Register at the window to get informed when to move the form
+ // shell to the bottom of the shell stack.
+ mpMainViewShellWindow->AddEventListener(
+ LINK(
+ this,
+ FormShellManager,
+ WindowEventHandler));
+
+ // Create a shell factory and with it activate the form shell.
+ OSL_ASSERT(!mpSubShellFactory);
+ mpSubShellFactory = std::make_shared<FormShellManagerFactory>(*pShell, *this);
+ mrBase.GetViewShellManager()->AddSubShellFactory(pShell,mpSubShellFactory);
+ mrBase.GetViewShellManager()->ActivateSubShell(*pShell, ToolbarId::FormLayer_Toolbox);
+}
+
+void FormShellManager::UnregisterAtCenterPane()
+{
+ if (mpMainViewShellWindow != nullptr)
+ {
+ // Unregister from the window.
+ mpMainViewShellWindow->RemoveEventListener(
+ LINK(
+ this,
+ FormShellManager,
+ WindowEventHandler));
+ mpMainViewShellWindow = nullptr;
+ }
+
+ // Unregister form at the form shell.
+ SetFormShell(nullptr);
+
+ // Deactivate the form shell and destroy the shell factory.
+ ViewShell* pShell = mrBase.GetMainViewShell().get();
+ if (pShell != nullptr)
+ {
+ mrBase.GetViewShellManager()->DeactivateSubShell(*pShell, ToolbarId::FormLayer_Toolbox);
+ mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell, mpSubShellFactory);
+ }
+
+ mpSubShellFactory.reset();
+}
+
+IMPL_LINK_NOARG(FormShellManager, FormControlActivated, LinkParamNone*, void)
+{
+ // The form shell has been activated. To give it priority in reacting to
+ // slot calls the form shell is moved to the top of the object bar shell
+ // stack.
+ ViewShell* pShell = mrBase.GetMainViewShell().get();
+ if (pShell!=nullptr && !mbFormShellAboveViewShell)
+ {
+ mbFormShellAboveViewShell = true;
+
+ ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager());
+ mrBase.GetViewShellManager()->SetFormShell(pShell,mpFormShell,mbFormShellAboveViewShell);
+ }
+}
+
+IMPL_LINK(FormShellManager, ConfigurationUpdateHandler, sd::tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ case EventMultiplexerEventId::MainViewRemoved:
+ UnregisterAtCenterPane();
+ break;
+
+ case EventMultiplexerEventId::MainViewAdded:
+ mbIsMainViewChangePending = true;
+ break;
+
+ case EventMultiplexerEventId::ConfigurationUpdated:
+ if (mbIsMainViewChangePending)
+ {
+ mbIsMainViewChangePending = false;
+ RegisterAtCenterPane();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+IMPL_LINK(FormShellManager, WindowEventHandler, VclWindowEvent&, rEvent, void)
+{
+ switch (rEvent.GetId())
+ {
+ case VclEventId::WindowGetFocus:
+ {
+ // The window of the center pane got the focus. Therefore
+ // the form shell is moved to the bottom of the object bar
+ // stack.
+ ViewShell* pShell = mrBase.GetMainViewShell().get();
+ if (pShell!=nullptr && mbFormShellAboveViewShell)
+ {
+ mbFormShellAboveViewShell = false;
+ ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager());
+ mrBase.GetViewShellManager()->SetFormShell(
+ pShell,
+ mpFormShell,
+ mbFormShellAboveViewShell);
+ }
+ }
+ break;
+
+ case VclEventId::WindowLoseFocus:
+ // We follow the sloppy focus policy. Losing the focus is
+ // ignored. We wait for the focus to be placed either in
+ // the window or the form shell. The later, however, is
+ // notified over the FormControlActivated handler, not this
+ // one.
+ break;
+
+ case VclEventId::ObjectDying:
+ mpMainViewShellWindow = nullptr;
+ break;
+
+ default: break;
+ }
+}
+
+void FormShellManager::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId()!=SfxHintId::Dying)
+ return;
+
+ // If all goes well this listener is called after the
+ // FormShellManager was notified about the dying form shell by the
+ // FormShellManagerFactory.
+ OSL_ASSERT(mpFormShell==nullptr);
+ if (mpFormShell != nullptr)
+ {
+ mpFormShell = nullptr;
+ mrBase.GetViewShellManager()->SetFormShell(
+ mrBase.GetMainViewShell().get(),
+ nullptr,
+ false);
+ }
+}
+
+//===== FormShellManagerFactory ===============================================
+
+namespace {
+
+FormShellManagerFactory::FormShellManagerFactory (
+ ::sd::ViewShell& rViewShell,
+ FormShellManager& rManager)
+ : mrViewShell(rViewShell),
+ mrFormShellManager(rManager)
+{
+}
+
+FmFormShell* FormShellManagerFactory::CreateShell( ::sd::ShellId nId )
+{
+ FmFormShell* pShell = nullptr;
+
+ ::sd::View* pView = mrViewShell.GetView();
+ if (nId == ToolbarId::FormLayer_Toolbox)
+ {
+ pShell = new FmFormShell(&mrViewShell.GetViewShellBase(), pView);
+ mrFormShellManager.SetFormShell(pShell);
+ }
+
+ return pShell;
+}
+
+void FormShellManagerFactory::ReleaseShell (SfxShell* pShell)
+{
+ if (pShell != nullptr)
+ {
+ mrFormShellManager.SetFormShell(nullptr);
+ delete pShell;
+ }
+}
+
+} // end of anonymous namespace
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/GraphicObjectBar.cxx b/sd/source/ui/view/GraphicObjectBar.cxx
new file mode 100644
index 000000000..60cab73f7
--- /dev/null
+++ b/sd/source/ui/view/GraphicObjectBar.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <GraphicObjectBar.hxx>
+
+#include <sfx2/shell.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/request.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/grfflt.hxx>
+#include <svx/grafctrl.hxx>
+
+#include <sfx2/objface.hxx>
+
+#include <strings.hrc>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <sdresid.hxx>
+
+using namespace sd;
+#define ShellClass_GraphicObjectBar
+#include <sdslots.hxx>
+
+namespace sd {
+
+
+SFX_IMPL_INTERFACE(GraphicObjectBar, SfxShell)
+
+void GraphicObjectBar::InitInterface_Impl()
+{
+}
+
+
+GraphicObjectBar::GraphicObjectBar (
+ const ViewShell* pSdViewShell,
+ ::sd::View* pSdView )
+ : SfxShell (pSdViewShell->GetViewShell()),
+ mpView ( pSdView )
+{
+ DrawDocShell* pDocShell = pSdViewShell->GetDocSh();
+
+ SetPool( &pDocShell->GetPool() );
+ SetUndoManager( pDocShell->GetUndoManager() );
+ SetRepeatTarget( mpView );
+ SetName( "Graphic objectbar");
+}
+
+GraphicObjectBar::~GraphicObjectBar()
+{
+ SetRepeatTarget( nullptr );
+}
+
+void GraphicObjectBar::GetAttrState( SfxItemSet& rSet )
+{
+ if( mpView )
+ SvxGrafAttrHelper::GetGrafAttrState( rSet, *mpView );
+}
+
+void GraphicObjectBar::Execute( SfxRequest& rReq )
+{
+ if( mpView )
+ {
+ SvxGrafAttrHelper::ExecuteGrafAttr( rReq, *mpView );
+ Invalidate();
+ }
+}
+
+void GraphicObjectBar::GetFilterState( SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ bool bEnable = false;
+
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGrafObj = dynamic_cast< SdrGrafObj *>( pObj ) )
+ if( pGrafObj->GetGraphicType() == GraphicType::Bitmap )
+ bEnable = true;
+ }
+
+ if( !bEnable )
+ SvxGraphicFilter::DisableGraphicFilterSlots( rSet );
+}
+
+void GraphicObjectBar::ExecuteFilter( SfxRequest const & rReq )
+{
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGrafObj = dynamic_cast< SdrGrafObj *>( pObj ) )
+ if( pGrafObj->GetGraphicType() == GraphicType::Bitmap )
+ {
+ GraphicObject aFilterObj( pGrafObj->GetGraphicObject() );
+
+ if( SvxGraphicFilterResult::NONE ==
+ SvxGraphicFilter::ExecuteGrfFilterSlot( rReq, aFilterObj ) )
+ {
+ SdrPageView* pPageView = mpView->GetSdrPageView();
+
+ if( pPageView )
+ {
+ SdrGrafObj* pFilteredObj = static_cast<SdrGrafObj*>( pObj->CloneSdrObject(pObj->getSdrModelFromSdrObject()) );
+ OUString aStr = mpView->GetDescriptionOfMarkedObjects() +
+ " " + SdResId(STR_UNDO_GRAFFILTER);
+ mpView->BegUndo( aStr );
+ pFilteredObj->SetGraphicObject( aFilterObj );
+ ::sd::View* const pView = mpView;
+ pView->ReplaceObjectAtView( pObj, *pPageView, pFilteredObj );
+ pView->EndUndo();
+ return;
+ }
+ }
+ }
+ }
+
+ Invalidate();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/GraphicViewShellBase.cxx b/sd/source/ui/view/GraphicViewShellBase.cxx
new file mode 100644
index 000000000..d58c8a0d2
--- /dev/null
+++ b/sd/source/ui/view/GraphicViewShellBase.cxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <GraphicViewShellBase.hxx>
+
+#include <GraphicDocShell.hxx>
+#include <app.hrc>
+#include <framework/DrawModule.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfac.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+
+namespace sd
+{
+// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a
+// new GraphicViewShellBase object has been constructed.
+
+SfxViewFactory* GraphicViewShellBase::s_pFactory;
+SfxViewShell* GraphicViewShellBase::CreateInstance(SfxViewFrame* pFrame, SfxViewShell* pOldView)
+{
+ GraphicViewShellBase* pBase = new GraphicViewShellBase(pFrame, pOldView);
+ pBase->LateInit(framework::FrameworkHelper::msDrawViewURL);
+ return pBase;
+}
+void GraphicViewShellBase::RegisterFactory(SfxInterfaceId nPrio)
+{
+ s_pFactory = new SfxViewFactory(&CreateInstance, nPrio, "Default");
+ InitFactory();
+}
+void GraphicViewShellBase::InitFactory() { SFX_VIEW_REGISTRATION(GraphicDocShell); }
+
+GraphicViewShellBase::GraphicViewShellBase(SfxViewFrame* _pFrame, SfxViewShell* pOldShell)
+ : ViewShellBase(_pFrame, pOldShell)
+{
+}
+
+GraphicViewShellBase::~GraphicViewShellBase() {}
+
+void GraphicViewShellBase::Execute(SfxRequest& rRequest)
+{
+ sal_uInt16 nSlotId = rRequest.GetSlot();
+
+ switch (nSlotId)
+ {
+ case SID_NOTES_WINDOW:
+ case SID_SLIDE_SORTER_MULTI_PANE_GUI:
+ case SID_SLIDE_SORTER_MODE:
+ case SID_SLIDE_MASTER_MODE:
+ case SID_OUTLINE_MODE:
+ case SID_NOTES_MODE:
+ case SID_NOTES_MASTER_MODE:
+ case SID_HANDOUT_MASTER_MODE:
+ // Prevent some Impress-only slots from being executed.
+ rRequest.Cancel();
+ break;
+
+ case SID_SWITCH_SHELL:
+ case SID_LEFT_PANE_DRAW:
+ case SID_LEFT_PANE_IMPRESS:
+ default:
+ // The remaining requests are forwarded to our base class.
+ ViewShellBase::Execute(rRequest);
+ break;
+ }
+}
+
+void GraphicViewShellBase::InitializeFramework()
+{
+ css::uno::Reference<css::frame::XController> xController(GetController());
+ sd::framework::DrawModule::Initialize(xController);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/ImpressViewShellBase.cxx b/sd/source/ui/view/ImpressViewShellBase.cxx
new file mode 100644
index 000000000..96b0b5aa9
--- /dev/null
+++ b/sd/source/ui/view/ImpressViewShellBase.cxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ImpressViewShellBase.hxx>
+
+#include <DrawDocShell.hxx>
+#include <app.hrc>
+#include <framework/FrameworkHelper.hxx>
+#include <framework/ImpressModule.hxx>
+#include <MasterPageObserver.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfac.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <comphelper/lok.hxx>
+
+namespace sd {
+
+
+// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a
+// new ImpressViewShellBase object has been constructed.
+
+SfxViewFactory* ImpressViewShellBase::s_pFactory;
+SfxViewShell* ImpressViewShellBase::CreateInstance (
+ SfxViewFrame *pFrame, SfxViewShell *pOldView)
+{
+ ImpressViewShellBase* pBase = new ImpressViewShellBase(pFrame, pOldView);
+ pBase->LateInit(comphelper::LibreOfficeKit::isActive() ? framework::FrameworkHelper::msImpressViewURL : "");
+ return pBase;
+}
+void ImpressViewShellBase::RegisterFactory( SfxInterfaceId nPrio )
+{
+ s_pFactory = new SfxViewFactory(&CreateInstance,nPrio,"Default");
+ InitFactory();
+}
+void ImpressViewShellBase::InitFactory()
+{
+ SFX_VIEW_REGISTRATION(DrawDocShell);
+}
+
+ImpressViewShellBase::ImpressViewShellBase (
+ SfxViewFrame* _pFrame,
+ SfxViewShell* pOldShell)
+ : ViewShellBase (_pFrame, pOldShell)
+{
+ MasterPageObserver::Instance().RegisterDocument (*GetDocShell()->GetDoc());
+}
+
+ImpressViewShellBase::~ImpressViewShellBase()
+{
+ MasterPageObserver::Instance().UnregisterDocument (*GetDocShell()->GetDoc());
+}
+
+void ImpressViewShellBase::Execute (SfxRequest& rRequest)
+{
+ sal_uInt16 nSlotId = rRequest.GetSlot();
+
+ switch (nSlotId)
+ {
+ case SID_LEFT_PANE_DRAW:
+ // Prevent a Draw-only slots from being executed.
+ rRequest.Cancel();
+ break;
+
+ default:
+ // The remaining requests are forwarded to our base class.
+ ViewShellBase::Execute(rRequest);
+ break;
+ }
+}
+
+void ImpressViewShellBase::InitializeFramework()
+{
+ css::uno::Reference<css::frame::XController>
+ xController (GetController());
+ sd::framework::ImpressModule::Initialize(xController);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/MediaObjectBar.cxx b/sd/source/ui/view/MediaObjectBar.cxx
new file mode 100644
index 000000000..232535240
--- /dev/null
+++ b/sd/source/ui/view/MediaObjectBar.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <MediaObjectBar.hxx>
+#include <avmedia/mediaitem.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/objface.hxx>
+#include <svx/MediaShellHelpers.hxx>
+
+#include <strings.hrc>
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+
+using namespace sd;
+using namespace svx;
+
+#define ShellClass_MediaObjectBar
+#include <sdslots.hxx>
+
+namespace sd
+{
+SFX_IMPL_INTERFACE(MediaObjectBar, SfxShell)
+
+void MediaObjectBar::InitInterface_Impl() {}
+
+MediaObjectBar::MediaObjectBar(const ViewShell* pSdViewShell, ::sd::View* pSdView)
+ : SfxShell(pSdViewShell->GetViewShell())
+ , mpView(pSdView)
+{
+ DrawDocShell* pDocShell = pSdViewShell->GetDocSh();
+
+ SetPool(&pDocShell->GetPool());
+ SetUndoManager(pDocShell->GetUndoManager());
+ SetRepeatTarget(mpView);
+ SetName(SdResId(RID_DRAW_MEDIA_TOOLBOX));
+}
+
+MediaObjectBar::~MediaObjectBar() { SetRepeatTarget(nullptr); }
+
+void MediaObjectBar::GetState(SfxItemSet& rSet) { MediaShellHelpers::GetState(mpView, rSet); }
+
+void MediaObjectBar::Execute(SfxRequest const& rReq)
+{
+ const ::avmedia::MediaItem* pMediaItem = MediaShellHelpers::Execute(mpView, rReq);
+ if (!pMediaItem)
+ return;
+
+ //if only changing state then don't set modified flag (e.g. playing a video)
+ if (!(pMediaItem->getMaskSet() & AVMediaSetMask::STATE))
+ {
+ //fdo #32598: after changing playback opts, set document's modified flag
+ SdDrawDocument& rDoc = mpView->GetDoc();
+ rDoc.SetChanged();
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/OutlineViewShellBase.cxx b/sd/source/ui/view/OutlineViewShellBase.cxx
new file mode 100644
index 000000000..8da1bcbca
--- /dev/null
+++ b/sd/source/ui/view/OutlineViewShellBase.cxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <OutlineViewShellBase.hxx>
+#include <DrawDocShell.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <sfx2/viewfac.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+
+namespace sd {
+
+class DrawDocShell;
+
+
+// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a
+// new OutlineViewShellBase object has been constructed.
+
+SfxViewFactory* OutlineViewShellBase::s_pFactory;
+SfxViewShell* OutlineViewShellBase::CreateInstance (
+ SfxViewFrame *pFrame, SfxViewShell *pOldView)
+{
+ OutlineViewShellBase* pBase = new OutlineViewShellBase(pFrame, pOldView);
+ pBase->LateInit(framework::FrameworkHelper::msOutlineViewURL);
+ return pBase;
+}
+void OutlineViewShellBase::RegisterFactory( SfxInterfaceId nPrio )
+{
+ s_pFactory = new SfxViewFactory(&CreateInstance,nPrio,"Outline");
+ InitFactory();
+}
+void OutlineViewShellBase::InitFactory()
+{
+ SFX_VIEW_REGISTRATION(DrawDocShell);
+}
+
+OutlineViewShellBase::OutlineViewShellBase (
+ SfxViewFrame* _pFrame,
+ SfxViewShell* pOldShell)
+ : ImpressViewShellBase (_pFrame, pOldShell)
+{
+}
+
+OutlineViewShellBase::~OutlineViewShellBase()
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx
new file mode 100644
index 000000000..a63337692
--- /dev/null
+++ b/sd/source/ui/view/Outliner.cxx
@@ -0,0 +1,2066 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <Outliner.hxx>
+#include <boost/property_tree/json_parser.hpp>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+#include <svl/srchitem.hxx>
+#include <svl/intitem.hxx>
+#include <editeng/editstat.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdograf.hxx>
+#include <editeng/unolingu.hxx>
+#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
+#include <svx/srchdlg.hxx>
+#include <unotools/linguprops.hxx>
+#include <unotools/lingucfg.hxx>
+#include <editeng/editeng.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <strings.hrc>
+#include <editeng/outliner.hxx>
+#include <sdmod.hxx>
+#include <Window.hxx>
+#include <sdresid.hxx>
+#include <DrawViewShell.hxx>
+#include <OutlineView.hxx>
+#include <OutlineViewShell.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <drawview.hxx>
+#include <ViewShellBase.hxx>
+#include <SpellDialogChildWindow.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <svx/svxids.hrc>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/string.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <VectorGraphicSearchContext.hxx>
+#include <fusearch.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::linguistic2;
+
+class SfxStyleSheetPool;
+
+class SdOutliner::Implementation
+{
+public:
+ /** The original edit mode directly after switching to a different view
+ mode. Used for restoring the edit mode when leaving that view mode
+ again.
+ */
+ EditMode meOriginalEditMode;
+
+ Implementation();
+ ~Implementation();
+
+ /** Return the OutlinerView that was provided by the last call to
+ ProvideOutlinerView() (or NULL when there was no such call.)
+ */
+ OutlinerView* GetOutlinerView() { return mpOutlineView;}
+
+ /** Provide in the member mpOutlineView an instance of OutlinerView that
+ is either taken from the ViewShell, when it is an OutlineViewShell,
+ or is created. When an OutlinerView already exists it is initialized.
+ */
+ void ProvideOutlinerView (
+ Outliner& rOutliner,
+ const std::shared_ptr<sd::ViewShell>& rpViewShell,
+ vcl::Window* pWindow);
+
+ /** This method is called when the OutlinerView is no longer used.
+ */
+ void ReleaseOutlinerView();
+
+ sd::VectorGraphicSearchContext& getVectorGraphicSearchContext() { return maVectorGraphicSearchContext; }
+
+private:
+ /** Flag that specifies whether we own the outline view pointed to by
+ <member>mpOutlineView</member> and thus have to
+ delete it in <member>EndSpelling()</member>.
+ */
+ bool mbOwnOutlineView;
+
+ /** The outline view used for searching and spelling. If searching or
+ spell checking an outline view this data member points to that view.
+ For all other views an instance is created. The
+ <member>mbOwnOutlineView</member> distinguishes between both cases.
+ */
+ OutlinerView* mpOutlineView;
+
+ sd::VectorGraphicSearchContext maVectorGraphicSearchContext;
+};
+
+namespace
+{
+
+sd::ViewShellBase* getViewShellBase()
+{
+ return dynamic_cast<sd::ViewShellBase*>(SfxViewShell::Current());
+}
+
+} // end anonymous namespace
+
+SdOutliner::SdOutliner( SdDrawDocument* pDoc, OutlinerMode nMode )
+ : SdrOutliner( &pDoc->GetItemPool(), nMode ),
+ mpImpl(new Implementation()),
+ meMode(SEARCH),
+ mpView(nullptr),
+ mpWindow(nullptr),
+ mpDrawDocument(pDoc),
+ mnConversionLanguage(LANGUAGE_NONE),
+ mnIgnoreCurrentPageChangesLevel(0),
+ mbStringFound(false),
+ mbMatchMayExist(false),
+ mnPageCount(0),
+ mbEndOfSearch(false),
+ mbFoundObject(false),
+ mbDirectionIsForward(true),
+ mbRestrictSearchToSelection(false),
+ mpObj(nullptr),
+ mpFirstObj(nullptr),
+ mpSearchSpellTextObj(nullptr),
+ mnText(0),
+ mpParaObj(nullptr),
+ meStartViewMode(PageKind::Standard),
+ meStartEditMode(EditMode::Page),
+ mnStartPageIndex(sal_uInt16(-1)),
+ mpStartEditedObject(nullptr),
+ mbPrepareSpellingPending(true)
+{
+ SetStyleSheetPool(static_cast<SfxStyleSheetPool*>( mpDrawDocument->GetStyleSheetPool() ));
+ SetEditTextObjectPool( &pDoc->GetItemPool() );
+ SetCalcFieldValueHdl(LINK(SD_MOD(), SdModule, CalcFieldValueHdl));
+ SetForbiddenCharsTable( pDoc->GetForbiddenCharsTable() );
+
+ EEControlBits nCntrl = GetControlWord();
+ nCntrl |= EEControlBits::ALLOWBIGOBJS;
+ nCntrl |= EEControlBits::MARKFIELDS;
+ nCntrl |= EEControlBits::AUTOCORRECT;
+
+ bool bOnlineSpell = false;
+
+ sd::DrawDocShell* pDocSh = mpDrawDocument->GetDocSh();
+
+ if (pDocSh)
+ {
+ bOnlineSpell = mpDrawDocument->GetOnlineSpell();
+ }
+ else
+ {
+ bOnlineSpell = false;
+
+ try
+ {
+ const SvtLinguConfig aLinguConfig;
+ Any aAny = aLinguConfig.GetProperty( UPN_IS_SPELL_AUTO );
+ aAny >>= bOnlineSpell;
+ }
+ catch( ... )
+ {
+ OSL_FAIL( "Ill. type in linguistic property" );
+ }
+ }
+
+ if (bOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+
+ SetControlWord(nCntrl);
+
+ Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() );
+ if ( xSpellChecker.is() )
+ SetSpeller( xSpellChecker );
+
+ Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() );
+ if( xHyphenator.is() )
+ SetHyphenator( xHyphenator );
+
+ SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
+}
+
+/// Nothing spectacular in the destructor.
+SdOutliner::~SdOutliner()
+{
+}
+
+OutlinerView* SdOutliner::getOutlinerView()
+{
+ return mpImpl->GetOutlinerView();
+}
+
+/** Prepare find&replace or spellchecking. This distinguishes between three
+ cases:
+ <ol>
+ <li>The current shell is a <type>DrawViewShell</type>: Create a
+ <type>OutlinerView</type> object and search all objects of (i) the
+ current mark list, (ii) of the current view, or (iii) of all the view
+ combinations:
+ <ol>
+ <li>Draw view, slide view</li>
+ <li>Draw view, background view</li>
+ <li>Notes view, slide view</li>
+ <li>Notes view, background view</li>
+ <li>Handout view, slide view</li>
+ <li>Handout view, background view</li>
+ </ol>
+
+ <li>When the current shell is a <type>SdOutlineViewShell</type> then
+ directly operate on it. No switching into other views takes place.</li>
+ </ol>
+*/
+void SdOutliner::PrepareSpelling()
+{
+ mbPrepareSpellingPending = false;
+
+ sd::ViewShellBase* pBase = getViewShellBase();
+ if (pBase != nullptr)
+ SetViewShell (pBase->GetMainViewShell());
+ SetRefDevice( SD_MOD()->GetVirtualRefDevice() );
+
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if (pViewShell)
+ {
+ mbStringFound = false;
+
+ // Supposed that we are not located at the very beginning/end of
+ // the document then there may be a match in the document
+ // prior/after the current position.
+ mbMatchMayExist = true;
+
+ maObjectIterator = sd::outliner::Iterator();
+ maSearchStartPosition = sd::outliner::Iterator();
+ RememberStartPosition();
+
+ mpImpl->ProvideOutlinerView(*this, pViewShell, mpWindow);
+
+ HandleChangedSelection ();
+ }
+ ClearModifyFlag();
+}
+
+void SdOutliner::StartSpelling()
+{
+ meMode = SPELL;
+ mbDirectionIsForward = true;
+ mpSearchItem.reset();
+}
+
+/** Free all resources acquired during the search/spell check. After a
+ spell check the start position is restored here.
+*/
+void SdOutliner::EndSpelling()
+{
+ // Keep old view shell alive until we release the outliner view.
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ std::shared_ptr<sd::ViewShell> pOldViewShell (pViewShell);
+
+ sd::ViewShellBase* pBase = getViewShellBase();
+ if (pBase != nullptr)
+ pViewShell = pBase->GetMainViewShell();
+ else
+ pViewShell.reset();
+ mpWeakViewShell = pViewShell;
+
+ // When in <member>PrepareSpelling()</member> a new outline view has
+ // been created then delete it here.
+ bool bViewIsDrawViewShell(dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() ));
+ if (bViewIsDrawViewShell)
+ {
+ SetStatusEventHdl(Link<EditStatus&,void>());
+ mpView = pViewShell->GetView();
+ mpView->UnmarkAllObj (mpView->GetSdrPageView());
+ mpView->SdrEndTextEdit();
+ // Make FuSelection the current function.
+ pViewShell->GetDispatcher()->Execute(
+ SID_OBJECT_SELECT,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD);
+
+ // Remove and, if previously created by us, delete the outline
+ // view.
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (pOutlinerView != nullptr)
+ {
+ RemoveView(pOutlinerView);
+ mpImpl->ReleaseOutlinerView();
+ }
+
+ SetUpdateLayout(true);
+ }
+
+ // Before clearing the modify flag use it as a hint that
+ // changes were done at SpellCheck
+ if(IsModified())
+ {
+ if(auto pOutlineView = dynamic_cast<sd::OutlineView *>( mpView ))
+ pOutlineView->PrepareClose();
+ if(mpDrawDocument && !mpDrawDocument->IsChanged())
+ mpDrawDocument->SetChanged();
+ }
+
+ // Now clear the modify flag to have a specified state of
+ // Outliner
+ ClearModifyFlag();
+
+ // When spell checking then restore the start position.
+ if (meMode==SPELL || meMode==TEXT_CONVERSION)
+ RestoreStartPosition ();
+
+ mpWeakViewShell.reset();
+ mpView = nullptr;
+ mpWindow = nullptr;
+ mnStartPageIndex = sal_uInt16(-1);
+}
+
+bool SdOutliner::SpellNextDocument()
+{
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
+ {
+ // When doing a spell check in the outline view then there is
+ // only one document.
+ mbEndOfSearch = true;
+ EndOfSearch ();
+ }
+ else
+ {
+ if( auto pOutlineView = dynamic_cast<sd::OutlineView *>( mpView ))
+ pOutlineView->PrepareClose();
+ mpDrawDocument->GetDocSh()->SetWaitCursor( true );
+
+ Initialize (true);
+
+ mpWindow = pViewShell->GetActiveWindow();
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (pOutlinerView != nullptr)
+ pOutlinerView->SetWindow(mpWindow);
+ ProvideNextTextObject ();
+
+ mpDrawDocument->GetDocSh()->SetWaitCursor( false );
+ ClearModifyFlag();
+ }
+
+ return !mbEndOfSearch;
+}
+
+/**
+ * check next text object
+ */
+svx::SpellPortions SdOutliner::GetNextSpellSentence()
+{
+ svx::SpellPortions aResult;
+
+ DetectChange();
+ // Iterate over sentences and text shapes until a sentence with a
+ // spelling error has been found. If no such sentence can be
+ // found the loop is left through a break.
+ // It is the responsibility of the sd outliner object to correctly
+ // iterate over all text shapes, i.e. switch between views, wrap
+ // around at the end of the document, stop when all text shapes
+ // have been examined exactly once.
+ bool bFoundNextSentence = false;
+ while ( ! bFoundNextSentence)
+ {
+ OutlinerView* pOutlinerView = GetView(0);
+ if (pOutlinerView != nullptr)
+ {
+ ESelection aCurrentSelection (pOutlinerView->GetSelection());
+ if ( ! mbMatchMayExist
+ && maStartSelection < aCurrentSelection)
+ EndOfSearch();
+
+ // Advance to the next sentence.
+ bFoundNextSentence = SpellSentence( pOutlinerView->GetEditView(), aResult);
+ }
+
+ // When no sentence with spelling errors has been found in the
+ // currently selected text shape or there is no selected text
+ // shape then advance to the next text shape.
+ if ( ! bFoundNextSentence)
+ if ( ! SpellNextDocument())
+ // All text objects have been processed so exit the
+ // loop and return an empty portions list.
+ break;
+ }
+
+ return aResult;
+}
+
+/** Go to next match.
+*/
+bool SdOutliner::StartSearchAndReplace (const SvxSearchItem* pSearchItem)
+{
+ bool bEndOfSearch = true;
+
+ // clear the search toolbar entry
+ SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty);
+
+ mpDrawDocument->GetDocSh()->SetWaitCursor( true );
+
+ // Since REPLACE is really a replaceAndSearchNext instead of a searchAndReplace,
+ // make sure that the search portion has not changed since the last FIND.
+ if (!mbPrepareSpellingPending && mpSearchItem
+ && pSearchItem->GetCommand() == SvxSearchCmd::REPLACE
+ && !mpSearchItem->equalsIgnoring(*pSearchItem, /*bIgnoreReplace=*/true,
+ /*bIgnoreCommand=*/true))
+ {
+ EndSpelling();
+ mbPrepareSpellingPending = true;
+ }
+
+ if (mbPrepareSpellingPending)
+ PrepareSpelling();
+ sd::ViewShellBase* pBase = getViewShellBase();
+ // Determine whether we have to abort the search. This is necessary
+ // when the main view shell does not support searching.
+ bool bAbort = false;
+ if (pBase != nullptr)
+ {
+ std::shared_ptr<sd::ViewShell> pShell (pBase->GetMainViewShell());
+ SetViewShell(pShell);
+ if (pShell == nullptr)
+ bAbort = true;
+ else
+ switch (pShell->GetShellType())
+ {
+ case sd::ViewShell::ST_DRAW:
+ case sd::ViewShell::ST_IMPRESS:
+ case sd::ViewShell::ST_NOTES:
+ case sd::ViewShell::ST_HANDOUT:
+ case sd::ViewShell::ST_OUTLINE:
+ bAbort = false;
+ break;
+ default:
+ bAbort = true;
+ break;
+ }
+ }
+
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if ( ! pViewShell)
+ {
+ OSL_ASSERT(pViewShell);
+ return true;
+ }
+
+ if ( ! bAbort)
+ {
+ meMode = SEARCH;
+ mpSearchItem.reset(pSearchItem->Clone());
+
+ mbFoundObject = false;
+
+ Initialize ( ! mpSearchItem->GetBackward());
+
+ const SvxSearchCmd nCommand (mpSearchItem->GetCommand());
+ if (nCommand == SvxSearchCmd::FIND_ALL || nCommand == SvxSearchCmd::REPLACE_ALL)
+ {
+ bEndOfSearch = SearchAndReplaceAll ();
+ }
+ else
+ {
+ RememberStartPosition ();
+ bEndOfSearch = SearchAndReplaceOnce ();
+ // restore start position if nothing was found
+ if(!mbStringFound)
+ {
+ RestoreStartPosition ();
+ // Nothing was changed, no need to restart the spellchecker.
+ if (nCommand == SvxSearchCmd::FIND)
+ bEndOfSearch = false;
+ }
+ mnStartPageIndex = sal_uInt16(-1);
+ }
+ }
+
+ mpDrawDocument->GetDocSh()->SetWaitCursor( false );
+
+ return bEndOfSearch;
+}
+
+void SdOutliner::Initialize (bool bDirectionIsForward)
+{
+ const bool bIsAtEnd (maObjectIterator == sd::outliner::OutlinerContainer(this).end());
+ const bool bOldDirectionIsForward = mbDirectionIsForward;
+ mbDirectionIsForward = bDirectionIsForward;
+
+ if (maObjectIterator == sd::outliner::Iterator())
+ {
+ // Initialize a new search.
+ maObjectIterator = sd::outliner::OutlinerContainer(this).current();
+ maCurrentPosition = *maObjectIterator;
+
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if ( ! pViewShell)
+ {
+ OSL_ASSERT(pViewShell);
+ return;
+ }
+
+ // In case we are searching in an outline view then first remove the
+ // current selection and place cursor at its start or end.
+ if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
+ {
+ ESelection aSelection = getOutlinerView()->GetSelection ();
+ if (mbDirectionIsForward)
+ {
+ aSelection.nEndPara = aSelection.nStartPara;
+ aSelection.nEndPos = aSelection.nStartPos;
+ }
+ else
+ {
+ aSelection.nStartPara = aSelection.nEndPara;
+ aSelection.nStartPos = aSelection.nEndPos;
+ }
+ getOutlinerView()->SetSelection (aSelection);
+ }
+
+ // When not beginning the search at the beginning of the search area
+ // then there may be matches before the current position.
+ mbMatchMayExist = (maObjectIterator!=sd::outliner::OutlinerContainer(this).begin());
+ }
+ else if (bOldDirectionIsForward != mbDirectionIsForward)
+ {
+ // Requested iteration direction has changed. Turn around the iterator.
+ maObjectIterator.Reverse();
+ if (bIsAtEnd)
+ {
+ // The iterator has pointed to end(), which after the search
+ // direction is reversed, becomes begin().
+ maObjectIterator = sd::outliner::OutlinerContainer(this).begin();
+ }
+ else
+ {
+ // The iterator has pointed to the object one ahead/before the current
+ // one. Now move it to the one before/ahead the current one.
+ ++maObjectIterator;
+ if (maObjectIterator != sd::outliner::OutlinerContainer(this).end())
+ {
+ ++maObjectIterator;
+ }
+ }
+
+ mbMatchMayExist = true;
+ }
+
+ // Initialize the last valid position with where the search starts so
+ // that it always points to a valid position.
+ maLastValidPosition = *sd::outliner::OutlinerContainer(this).current();
+}
+
+bool SdOutliner::SearchAndReplaceAll()
+{
+ bool bRet = true;
+
+ // Save the current position to be restored after having replaced all
+ // matches.
+ RememberStartPosition ();
+
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if ( ! pViewShell)
+ {
+ OSL_ASSERT(pViewShell);
+ return true;
+ }
+
+ std::vector<sd::SearchSelection> aSelections;
+ if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
+ {
+ // Put the cursor to the beginning/end of the outliner.
+ getOutlinerView()->SetSelection (GetSearchStartPosition ());
+
+ // The outliner does all the work for us when we are in this mode.
+ SearchAndReplaceOnce();
+ }
+ else if( nullptr != dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() ))
+ {
+ // Disable selection change notifications during search all.
+ SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase();
+ rSfxViewShell.setTiledSearching(true);
+ comphelper::ScopeGuard aGuard([&rSfxViewShell]()
+ {
+ rSfxViewShell.setTiledSearching(false);
+ });
+
+ // Go to beginning/end of document.
+ maObjectIterator = sd::outliner::OutlinerContainer(this).begin();
+ // Switch to the first object which contains the search string.
+ ProvideNextTextObject();
+ if( !mbStringFound )
+ {
+ RestoreStartPosition ();
+ mnStartPageIndex = sal_uInt16(-1);
+ return true;
+ }
+ // Reset the iterator back to the beginning
+ maObjectIterator = sd::outliner::OutlinerContainer(this).begin();
+
+ // Search/replace until the end of the document is reached.
+ bool bFoundMatch;
+ do
+ {
+ bFoundMatch = ! SearchAndReplaceOnce(&aSelections);
+ if (mpSearchItem->GetCommand() == SvxSearchCmd::FIND_ALL && comphelper::LibreOfficeKit::isActive() && bFoundMatch && aSelections.size() == 1)
+ {
+ // Without this, RememberStartPosition() will think it already has a remembered position.
+ mnStartPageIndex = sal_uInt16(-1);
+
+ RememberStartPosition();
+
+ // So when RestoreStartPosition() restores the first match, then spellchecker doesn't kill the selection.
+ bRet = false;
+ }
+ }
+ while (bFoundMatch);
+
+ if (mpSearchItem->GetCommand() == SvxSearchCmd::FIND_ALL && comphelper::LibreOfficeKit::isActive() && !aSelections.empty())
+ {
+ boost::property_tree::ptree aTree;
+ aTree.put("searchString", mpSearchItem->GetSearchString().toUtf8().getStr());
+ aTree.put("highlightAll", true);
+
+ boost::property_tree::ptree aChildren;
+ for (const sd::SearchSelection& rSelection : aSelections)
+ {
+ boost::property_tree::ptree aChild;
+ aChild.put("part", OString::number(rSelection.m_nPage).getStr());
+ aChild.put("rectangles", rSelection.m_aRectangles.getStr());
+ aChildren.push_back(std::make_pair("", aChild));
+ }
+ aTree.add_child("searchResultSelection", aChildren);
+
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aTree);
+ OString aPayload = aStream.str().c_str();
+ rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload.getStr());
+ }
+ }
+
+ RestoreStartPosition ();
+
+ if (mpSearchItem->GetCommand() == SvxSearchCmd::FIND_ALL && comphelper::LibreOfficeKit::isActive() && !bRet)
+ {
+ // Find-all, tiled rendering and we have at least one match.
+ OString aPayload = OString::number(mnStartPageIndex);
+ SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase();
+ rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload.getStr());
+
+ // Emit a selection callback here:
+ // 1) The original one is no longer valid, as we there was a SET_PART in between
+ // 2) The underlying editeng will only talk about the first match till
+ // it doesn't support multi-selection.
+ std::vector<OString> aRectangles;
+ for (const sd::SearchSelection& rSelection : aSelections)
+ {
+ if (rSelection.m_nPage == mnStartPageIndex)
+ aRectangles.push_back(rSelection.m_aRectangles);
+ }
+ OString sRectangles = comphelper::string::join("; ", aRectangles);
+ rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRectangles.getStr());
+ }
+
+ mnStartPageIndex = sal_uInt16(-1);
+
+ return bRet;
+}
+
+namespace
+{
+
+basegfx::B2DRectangle getPDFSelection(const std::unique_ptr<VectorGraphicSearch> & rVectorGraphicSearch,
+ const SdrObject* pObject)
+{
+ basegfx::B2DRectangle aSelection;
+
+ auto const & rTextRectangles = rVectorGraphicSearch->getTextRectangles();
+ if (rTextRectangles.empty())
+ return aSelection;
+
+ basegfx::B2DSize aPdfPageSizeHMM = rVectorGraphicSearch->pageSize();
+
+ basegfx::B2DRectangle aObjectB2DRectHMM(vcl::unotools::b2DRectangleFromRectangle(pObject->GetLogicRect()));
+
+ // Setup coordinate conversion matrix to convert the inner PDF
+ // coordinates to the page relative coordinates
+ basegfx::B2DHomMatrix aB2DMatrix;
+
+ aB2DMatrix.scale(aObjectB2DRectHMM.getWidth() / aPdfPageSizeHMM.getX(),
+ aObjectB2DRectHMM.getHeight() / aPdfPageSizeHMM.getY());
+
+ aB2DMatrix.translate(aObjectB2DRectHMM.getMinX(), aObjectB2DRectHMM.getMinY());
+
+
+ for (auto const & rRectangle : rVectorGraphicSearch->getTextRectangles())
+ {
+ basegfx::B2DRectangle aRectangle(rRectangle);
+ aRectangle *= aB2DMatrix;
+
+ if (aSelection.isEmpty())
+ aSelection = aRectangle;
+ else
+ aSelection.expand(aRectangle);
+ }
+
+ return aSelection;
+}
+
+} // end namespace
+
+void SdOutliner::sendLOKSearchResultCallback(const std::shared_ptr<sd::ViewShell> & pViewShell,
+ const OutlinerView* pOutlinerView,
+ std::vector<sd::SearchSelection>* pSelections)
+{
+ std::vector<::tools::Rectangle> aLogicRects;
+ auto& rVectorGraphicSearchContext = mpImpl->getVectorGraphicSearchContext();
+ if (rVectorGraphicSearchContext.mbCurrentIsVectorGraphic)
+ {
+ basegfx::B2DRectangle aSelectionHMM = getPDFSelection(rVectorGraphicSearchContext.mpVectorGraphicSearch, mpObj);
+
+ tools::Rectangle aSelection(Point(aSelectionHMM.getMinX(), aSelectionHMM.getMinY()),
+ Size(aSelectionHMM.getWidth(), aSelectionHMM.getHeight()));
+ aSelection = o3tl::convert(aSelection, o3tl::Length::mm100, o3tl::Length::twip);
+ aLogicRects.push_back(aSelection);
+ }
+ else
+ {
+ pOutlinerView->GetSelectionRectangles(aLogicRects);
+
+ // convert to twips if in 100thmm (seems as if LibreOfficeKit is based on twips?). Do this
+ // here where we have the only place needing this, *not* in ImpEditView::GetSelectionRectangles
+ // which makes that method unusable for others
+ if (pOutlinerView->GetWindow() && MapUnit::Map100thMM == pOutlinerView->GetWindow()->GetMapMode().GetMapUnit())
+ {
+ for (tools::Rectangle& rRectangle : aLogicRects)
+ {
+ rRectangle = o3tl::convert(rRectangle, o3tl::Length::mm100, o3tl::Length::twip);
+ }
+ }
+ }
+
+ std::vector<OString> aLogicRectStrings;
+ std::transform(aLogicRects.begin(), aLogicRects.end(), std::back_inserter(aLogicRectStrings),
+ [](const ::tools::Rectangle& rRectangle)
+ {
+ return rRectangle.toString();
+ });
+
+ OString sRectangles = comphelper::string::join("; ", aLogicRectStrings);
+
+ if (!pSelections)
+ {
+ // notify LibreOfficeKit about changed page
+ OString aPayload = OString::number(maCurrentPosition.mnPageIndex);
+ SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase();
+ rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload.getStr());
+
+ // also about search result selections
+ boost::property_tree::ptree aTree;
+ aTree.put("searchString", mpSearchItem->GetSearchString().toUtf8().getStr());
+ aTree.put("highlightAll", false);
+
+ boost::property_tree::ptree aChildren;
+ boost::property_tree::ptree aChild;
+ aChild.put("part", OString::number(maCurrentPosition.mnPageIndex).getStr());
+ aChild.put("rectangles", sRectangles.getStr());
+ aChildren.push_back(std::make_pair("", aChild));
+ aTree.add_child("searchResultSelection", aChildren);
+
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aTree);
+ aPayload = aStream.str().c_str();
+ rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload.getStr());
+
+ if (rVectorGraphicSearchContext.mbCurrentIsVectorGraphic)
+ {
+ rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRectangles.getStr());
+ }
+ }
+ else
+ {
+ sd::SearchSelection aSelection(maCurrentPosition.mnPageIndex, sRectangles);
+ bool bDuplicate = !pSelections->empty() && pSelections->back() == aSelection;
+ if (!bDuplicate)
+ pSelections->push_back(aSelection);
+ }
+}
+
+bool SdOutliner::SearchAndReplaceOnce(std::vector<sd::SearchSelection>* pSelections)
+{
+ DetectChange ();
+
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+
+ if (!getOutlinerView() || !GetEditEngine().HasView(&getOutlinerView()->GetEditView()))
+ {
+ std::shared_ptr<sd::DrawViewShell> pDrawViewShell (
+ std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell));
+
+ // Perhaps the user switched to a different page/slide between searches.
+ // If so, reset the starting search position to the current slide like DetectChange does
+ if (pDrawViewShell && pDrawViewShell->GetCurPagePos() != maCurrentPosition.mnPageIndex)
+ maObjectIterator = sd::outliner::OutlinerContainer(this).current();
+
+ mpImpl->ProvideOutlinerView(*this, pViewShell, mpWindow);
+ }
+
+ if (pViewShell)
+ {
+ mpView = pViewShell->GetView();
+ mpWindow = pViewShell->GetActiveWindow();
+ getOutlinerView()->SetWindow(mpWindow);
+ auto& rVectorGraphicSearchContext = mpImpl->getVectorGraphicSearchContext();
+ if (nullptr != dynamic_cast<const sd::DrawViewShell*>(pViewShell.get()))
+ {
+ sal_uLong nMatchCount = 0;
+
+ if (rVectorGraphicSearchContext.mbCurrentIsVectorGraphic)
+ {
+ OUString const & rString = mpSearchItem->GetSearchString();
+ bool bBackwards = mpSearchItem->GetBackward();
+
+ VectorGraphicSearchOptions aOptions;
+ aOptions.meStartPosition = bBackwards ? SearchStartPosition::End : SearchStartPosition::Begin;
+ aOptions.mbMatchCase = mpSearchItem->GetExact();
+ aOptions.mbMatchWholeWord = mpSearchItem->GetWordOnly();
+
+ bool bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->search(rString, aOptions);
+
+ if (bResult)
+ {
+ if (bBackwards)
+ bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->previous();
+ else
+ bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->next();
+ }
+
+ if (bResult)
+ {
+ nMatchCount = 1;
+
+ SdrPageView* pPageView = mpView->GetSdrPageView();
+ mpView->UnmarkAllObj(pPageView);
+
+ std::vector<basegfx::B2DRectangle> aSubSelections;
+ basegfx::B2DRectangle aSubSelection = getPDFSelection(rVectorGraphicSearchContext.mpVectorGraphicSearch, mpObj);
+ if (!aSubSelection.isEmpty())
+ aSubSelections.push_back(aSubSelection);
+ mpView->MarkObj(mpObj, pPageView, false, false, std::move(aSubSelections));
+ }
+ else
+ {
+ rVectorGraphicSearchContext.reset();
+ }
+ }
+ else
+ {
+ // When replacing we first check if there is a selection
+ // indicating a match. If there is then replace it. The
+ // following call to StartSearchAndReplace will then search for
+ // the next match.
+ if (meMode == SEARCH && mpSearchItem->GetCommand() == SvxSearchCmd::REPLACE)
+ {
+ if (getOutlinerView()->GetSelection().HasRange())
+ getOutlinerView()->StartSearchAndReplace(*mpSearchItem);
+ }
+
+ // Search for the next match.
+ if (mpSearchItem->GetCommand() != SvxSearchCmd::REPLACE_ALL)
+ {
+ nMatchCount = getOutlinerView()->StartSearchAndReplace(*mpSearchItem);
+ }
+ }
+
+ // Go to the next text object when there have been no matches in
+ // the current object or the whole object has already been
+ // processed.
+ if (nMatchCount==0 || mpSearchItem->GetCommand()==SvxSearchCmd::REPLACE_ALL)
+ {
+ ProvideNextTextObject ();
+
+ if (!mbEndOfSearch && !rVectorGraphicSearchContext.mbCurrentIsVectorGraphic)
+ {
+ // Remember the current position as the last one with a
+ // text object.
+ maLastValidPosition = maCurrentPosition;
+
+ // Now that the mbEndOfSearch flag guards this block the
+ // following assertion and return should not be
+ // necessary anymore.
+ DBG_ASSERT(GetEditEngine().HasView(&getOutlinerView()->GetEditView() ),
+ "SearchAndReplace without valid view!" );
+ if ( ! GetEditEngine().HasView( &getOutlinerView()->GetEditView() ) )
+ {
+ mpDrawDocument->GetDocSh()->SetWaitCursor( false );
+ return true;
+ }
+
+ if (meMode == SEARCH)
+ getOutlinerView()->StartSearchAndReplace(*mpSearchItem);
+ }
+ }
+ }
+ else if (nullptr != dynamic_cast<const sd::OutlineViewShell*>(pViewShell.get()))
+ {
+ mpDrawDocument->GetDocSh()->SetWaitCursor(false);
+ // The following loop is executed more than once only when a
+ // wrap around search is done.
+ while (true)
+ {
+ int nResult = getOutlinerView()->StartSearchAndReplace(*mpSearchItem);
+ if (nResult == 0)
+ {
+ if (HandleFailedSearch ())
+ {
+ getOutlinerView()->SetSelection (GetSearchStartPosition ());
+ continue;
+ }
+ }
+ else
+ mbStringFound = true;
+ break;
+ }
+ }
+ }
+
+ mpDrawDocument->GetDocSh()->SetWaitCursor( false );
+
+ if (pViewShell && comphelper::LibreOfficeKit::isActive() && mbStringFound)
+ {
+ sendLOKSearchResultCallback(pViewShell, getOutlinerView(), pSelections);
+ }
+
+ return mbEndOfSearch;
+}
+
+/** Try to detect whether the document or the view (shell) has changed since
+ the last time <member>StartSearchAndReplace()</member> has been called.
+*/
+void SdOutliner::DetectChange()
+{
+ sd::outliner::IteratorPosition aPosition (maCurrentPosition);
+
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ std::shared_ptr<sd::DrawViewShell> pDrawViewShell (
+ std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell));
+
+ // Detect whether the view has been switched from the outside.
+ if (pDrawViewShell != nullptr
+ && (aPosition.meEditMode != pDrawViewShell->GetEditMode()
+ || aPosition.mePageKind != pDrawViewShell->GetPageKind()))
+ {
+ // Either the edit mode or the page kind has changed.
+ SetStatusEventHdl(Link<EditStatus&,void>());
+
+ SdrPageView* pPageView = mpView->GetSdrPageView();
+ if (pPageView != nullptr)
+ mpView->UnmarkAllObj (pPageView);
+ mpView->SdrEndTextEdit();
+ SetUpdateLayout(false);
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (pOutlinerView != nullptr)
+ pOutlinerView->SetOutputArea( ::tools::Rectangle( Point(), Size(1, 1) ) );
+ if (meMode == SPELL)
+ SetPaperSize( Size(1, 1) );
+ SetText(OUString(), GetParagraph(0));
+
+ RememberStartPosition ();
+
+ mnPageCount = mpDrawDocument->GetSdPageCount(pDrawViewShell->GetPageKind());
+ maObjectIterator = sd::outliner::OutlinerContainer(this).current();
+ }
+
+ // Detect change of the set of selected objects. If their number has
+ // changed start again with the first selected object.
+ else if (DetectSelectionChange())
+ {
+ HandleChangedSelection ();
+ maObjectIterator = sd::outliner::OutlinerContainer(this).current();
+ }
+
+ // Detect change of page count. Restart search at first/last page in
+ // that case.
+ else if (aPosition.meEditMode == EditMode::Page
+ && mpDrawDocument->GetSdPageCount(aPosition.mePageKind) != mnPageCount)
+ {
+ // The number of pages has changed.
+ mnPageCount = mpDrawDocument->GetSdPageCount(aPosition.mePageKind);
+ maObjectIterator = sd::outliner::OutlinerContainer(this).current();
+ }
+ else if (aPosition.meEditMode == EditMode::MasterPage
+ && mpDrawDocument->GetSdPageCount(aPosition.mePageKind) != mnPageCount)
+ {
+ // The number of master pages has changed.
+ mnPageCount = mpDrawDocument->GetSdPageCount(aPosition.mePageKind);
+ maObjectIterator = sd::outliner::OutlinerContainer(this).current();
+ }
+}
+
+bool SdOutliner::DetectSelectionChange()
+{
+ bool bSelectionHasChanged = false;
+
+ // If mpObj is NULL then we have not yet found our first match.
+ // Detecting a change makes no sense.
+ if (mpObj != nullptr)
+ {
+ const size_t nMarkCount = mpView ? mpView->GetMarkedObjectList().GetMarkCount() : 0;
+ switch (nMarkCount)
+ {
+ case 0:
+ // The selection has changed when previously there have been
+ // selected objects.
+ bSelectionHasChanged = mbRestrictSearchToSelection;
+ break;
+ case 1:
+ // Check if the only selected object is not the one that we
+ // had selected.
+ if (mpView != nullptr)
+ {
+ SdrMark* pMark = mpView->GetMarkedObjectList().GetMark(0);
+ if (pMark != nullptr)
+ bSelectionHasChanged = (mpObj != pMark->GetMarkedSdrObj ());
+ }
+ break;
+ default:
+ // We had selected exactly one object.
+ bSelectionHasChanged = true;
+ break;
+ }
+ }
+
+ return bSelectionHasChanged;
+}
+
+void SdOutliner::RememberStartPosition()
+{
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if ( ! pViewShell)
+ {
+ OSL_ASSERT(pViewShell);
+ return;
+ }
+
+ if ( mnStartPageIndex != sal_uInt16(-1) )
+ return;
+
+ if( nullptr != dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() ))
+ {
+ std::shared_ptr<sd::DrawViewShell> pDrawViewShell (
+ std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell));
+ if (pDrawViewShell != nullptr)
+ {
+ meStartViewMode = pDrawViewShell->GetPageKind();
+ meStartEditMode = pDrawViewShell->GetEditMode();
+ mnStartPageIndex = pDrawViewShell->GetCurPagePos();
+ }
+
+ if (mpView != nullptr)
+ {
+ mpStartEditedObject = mpView->GetTextEditObject();
+ if (mpStartEditedObject != nullptr)
+ {
+ // Try to retrieve current caret position only when there is an
+ // edited object.
+ ::Outliner* pOutliner =
+ static_cast<sd::DrawView*>(mpView)->GetTextEditOutliner();
+ if (pOutliner!=nullptr && pOutliner->GetViewCount()>0)
+ {
+ OutlinerView* pOutlinerView = pOutliner->GetView(0);
+ maStartSelection = pOutlinerView->GetSelection();
+ }
+ }
+ }
+ }
+ else if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
+ {
+ // Remember the current cursor position.
+ OutlinerView* pView = GetView(0);
+ if (pView != nullptr)
+ pView->GetSelection();
+ }
+ else
+ {
+ mnStartPageIndex = sal_uInt16(-1);
+ }
+}
+
+void SdOutliner::RestoreStartPosition()
+{
+ bool bRestore = true;
+ // Take a negative start page index as indicator that restoring the
+ // start position is not requested.
+ if (mnStartPageIndex == sal_uInt16(-1) )
+ bRestore = false;
+ // Don't restore when the view shell is not valid.
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if (pViewShell == nullptr)
+ bRestore = false;
+
+ if (!bRestore)
+ return;
+
+ if( nullptr != dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() ))
+ {
+ std::shared_ptr<sd::DrawViewShell> pDrawViewShell (
+ std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell));
+ SetViewMode (meStartViewMode);
+ if (pDrawViewShell != nullptr)
+ {
+ SetPage (meStartEditMode, mnStartPageIndex);
+ mpObj = mpStartEditedObject;
+ if (mpObj)
+ {
+ PutTextIntoOutliner();
+ EnterEditMode(false);
+ if (getOutlinerView())
+ getOutlinerView()->SetSelection(maStartSelection);
+ }
+ }
+ }
+ else if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
+ {
+ // Set cursor to its old position.
+ OutlinerView* pView = GetView(0);
+ if (pView != nullptr)
+ pView->SetSelection (maStartSelection);
+ }
+}
+
+namespace
+{
+
+bool lclIsValidTextObject(const sd::outliner::IteratorPosition& rPosition)
+{
+ auto* pObject = dynamic_cast< SdrTextObj* >( rPosition.mxObject.get() );
+ return (pObject != nullptr) && pObject->HasText() && ! pObject->IsEmptyPresObj();
+}
+
+bool isValidVectorGraphicObject(const sd::outliner::IteratorPosition& rPosition)
+{
+ auto* pGraphicObject = dynamic_cast<SdrGrafObj*>(rPosition.mxObject.get());
+ if (pGraphicObject)
+ {
+ auto const& pVectorGraphicData = pGraphicObject->GetGraphic().getVectorGraphicData();
+ if (pVectorGraphicData && VectorGraphicDataType::Pdf == pVectorGraphicData->getType())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // end anonymous namespace
+
+
+/** The main purpose of this method is to iterate over all shape objects of
+ the search area (current selection, current view, or whole document)
+ until a text object has been found that contains at least one match or
+ until no such object can be found anymore. These two conditions are
+ expressed by setting one of the flags <member>mbFoundObject</member> or
+ <member>mbEndOfSearch</member> to <TRUE/>.
+*/
+void SdOutliner::ProvideNextTextObject()
+{
+ mbEndOfSearch = false;
+ mbFoundObject = false;
+
+ // reset the vector search
+ auto& rVectorGraphicSearchContext = mpImpl->getVectorGraphicSearchContext();
+ rVectorGraphicSearchContext.reset();
+
+ mpView->UnmarkAllObj (mpView->GetSdrPageView());
+ try
+ {
+ mpView->SdrEndTextEdit();
+ }
+ catch (const css::uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd.view");
+ }
+ SetUpdateLayout(false);
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (pOutlinerView != nullptr)
+ pOutlinerView->SetOutputArea( ::tools::Rectangle( Point(), Size(1, 1) ) );
+ if (meMode == SPELL)
+ SetPaperSize( Size(1, 1) );
+ SetText(OUString(), GetParagraph(0));
+
+ mpSearchSpellTextObj = nullptr;
+
+ // Iterate until a valid text object has been found or the search ends.
+ do
+ {
+ mpObj = nullptr;
+ mpParaObj = nullptr;
+
+ if (maObjectIterator != sd::outliner::OutlinerContainer(this).end())
+ {
+ maCurrentPosition = *maObjectIterator;
+
+ // LOK: do not descent to notes or master pages when searching
+ bool bForbiddenPage = comphelper::LibreOfficeKit::isActive() && (maCurrentPosition.mePageKind != PageKind::Standard || maCurrentPosition.meEditMode != EditMode::Page);
+
+ rVectorGraphicSearchContext.reset();
+
+ if (!bForbiddenPage)
+ {
+ // Switch to the current object only if it is a valid text object.
+ if (lclIsValidTextObject(maCurrentPosition))
+ {
+ // Don't set yet in case of searching: the text object may not match.
+ if (meMode != SEARCH)
+ mpObj = SetObject(maCurrentPosition);
+ else
+ mpObj = maCurrentPosition.mxObject.get();
+ }
+ // Or if the object is a valid graphic object which contains vector graphic
+ else if (meMode == SEARCH && isValidVectorGraphicObject(maCurrentPosition))
+ {
+ mpObj = maCurrentPosition.mxObject.get();
+ rVectorGraphicSearchContext.mbCurrentIsVectorGraphic = true;
+ }
+ }
+
+ // Advance to the next object
+ ++maObjectIterator;
+
+ if (mpObj)
+ {
+ if (rVectorGraphicSearchContext.mbCurrentIsVectorGraphic)
+ {
+ // We know here the object is a SdrGrafObj and that it
+ // contains a vector graphic
+ auto* pGraphicObject = static_cast<SdrGrafObj*>(mpObj);
+ OUString const & rString = mpSearchItem->GetSearchString();
+ bool bBackwards = mpSearchItem->GetBackward();
+
+ VectorGraphicSearchOptions aOptions;
+ aOptions.meStartPosition = bBackwards ? SearchStartPosition::End : SearchStartPosition::Begin;
+ aOptions.mbMatchCase = mpSearchItem->GetExact();
+ aOptions.mbMatchWholeWord = mpSearchItem->GetWordOnly();
+
+ rVectorGraphicSearchContext.mpVectorGraphicSearch = std::make_unique<VectorGraphicSearch>(pGraphicObject->GetGraphic());
+
+ bool bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->search(rString, aOptions);
+ if (bResult)
+ {
+ if (bBackwards)
+ bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->previous();
+ else
+ bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->next();
+ }
+
+ if (bResult)
+ {
+ mpObj = SetObject(maCurrentPosition);
+
+ mbStringFound = true;
+ mbMatchMayExist = true;
+ mbFoundObject = true;
+
+ SdrPageView* pPageView = mpView->GetSdrPageView();
+ mpView->UnmarkAllObj(pPageView);
+
+ std::vector<basegfx::B2DRectangle> aSubSelections;
+ basegfx::B2DRectangle aSubSelection = getPDFSelection(rVectorGraphicSearchContext.mpVectorGraphicSearch, mpObj);
+ if (!aSubSelection.isEmpty())
+ aSubSelections.push_back(aSubSelection);
+
+ mpView->MarkObj(mpObj, pPageView, false, false, std::move(aSubSelections));
+
+ mpDrawDocument->GetDocSh()->SetWaitCursor( false );
+ }
+ else
+ {
+ rVectorGraphicSearchContext.reset();
+ }
+ }
+ else
+ {
+ PutTextIntoOutliner();
+
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if (pViewShell != nullptr)
+ {
+ switch (meMode)
+ {
+ case SEARCH:
+ PrepareSearchAndReplace ();
+ break;
+ case SPELL:
+ PrepareSpellCheck ();
+ break;
+ case TEXT_CONVERSION:
+ PrepareConversion();
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ rVectorGraphicSearchContext.reset();
+
+ if (meMode == SEARCH)
+ // Instead of doing a full-blown SetObject(), which would do the same -- but would also possibly switch pages.
+ mbStringFound = false;
+
+ mbEndOfSearch = true;
+ EndOfSearch ();
+ }
+ }
+ while ( ! (mbFoundObject || mbEndOfSearch));
+}
+
+void SdOutliner::EndOfSearch()
+{
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if ( ! pViewShell)
+ {
+ OSL_ASSERT(pViewShell);
+ return;
+ }
+
+ // Before we display a dialog we first jump to where the last valid text
+ // object was found. All page and view mode switching since then was
+ // temporary and should not be visible to the user.
+ if( nullptr == dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
+ SetObject (maLastValidPosition);
+
+ if (mbRestrictSearchToSelection)
+ ShowEndOfSearchDialog ();
+ else
+ {
+ // When no match has been found so far then terminate the search.
+ if ( ! mbMatchMayExist)
+ {
+ ShowEndOfSearchDialog ();
+ mbEndOfSearch = true;
+ }
+ // Ask the user whether to wrap around and continue the search or
+ // to terminate.
+ else if (meMode==TEXT_CONVERSION || ShowWrapAroundDialog ())
+ {
+ mbMatchMayExist = false;
+ // Everything back to beginning (or end?) of the document.
+ maObjectIterator = sd::outliner::OutlinerContainer(this).begin();
+ if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
+ {
+ // Set cursor to first character of the document.
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (pOutlinerView != nullptr)
+ pOutlinerView->SetSelection (GetSearchStartPosition ());
+ }
+
+ mbEndOfSearch = false;
+ }
+ else
+ {
+ // No wrap around.
+ mbEndOfSearch = true;
+ }
+ }
+}
+
+void SdOutliner::ShowEndOfSearchDialog()
+{
+ if (meMode == SEARCH)
+ {
+ if (!mbStringFound)
+ {
+ SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
+ std::shared_ptr<sd::ViewShell> pViewShell(mpWeakViewShell.lock());
+ if (pViewShell)
+ {
+ SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase();
+ rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, mpSearchItem->GetSearchString().toUtf8().getStr());
+ }
+ }
+
+ // don't do anything else for search
+ return;
+ }
+
+ OUString aString;
+ if (mpView->AreObjectsMarked())
+ aString = SdResId(STR_END_SPELLING_OBJ);
+ else
+ aString = SdResId(STR_END_SPELLING);
+
+ // Show the message in an info box that is modal with respect to the whole application.
+ weld::Window* pParent = GetMessageBoxParent();
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Info, VclButtonsType::Ok, aString));
+ xInfoBox->run();
+}
+
+bool SdOutliner::ShowWrapAroundDialog()
+{
+ // Determine whether to show the dialog.
+ if (mpSearchItem)
+ {
+ // When searching display the dialog only for single find&replace.
+ const SvxSearchCmd nCommand(mpSearchItem->GetCommand());
+ if (nCommand == SvxSearchCmd::REPLACE || nCommand == SvxSearchCmd::FIND)
+ {
+ if (mbDirectionIsForward)
+ SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End);
+ else
+ SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Start);
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+ // show dialog only for spelling
+ if (meMode != SPELL)
+ return false;
+
+ // The question text depends on the search direction.
+ bool bImpress = mpDrawDocument && mpDrawDocument->GetDocumentType() == DocumentType::Impress;
+
+ TranslateId pStringId;
+ if (mbDirectionIsForward)
+ pStringId = bImpress ? STR_SAR_WRAP_FORWARD : STR_SAR_WRAP_FORWARD_DRAW;
+ else
+ pStringId = bImpress ? STR_SAR_WRAP_BACKWARD : STR_SAR_WRAP_BACKWARD_DRAW;
+
+ // Pop up question box that asks the user whether to wrap around.
+ // The dialog is made modal with respect to the whole application.
+ weld::Window* pParent = GetMessageBoxParent();
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Question, VclButtonsType::YesNo, SdResId(pStringId)));
+ sal_uInt16 nBoxResult = xQueryBox->run();
+
+ return (nBoxResult == RET_YES);
+}
+
+void SdOutliner::PutTextIntoOutliner()
+{
+ mpSearchSpellTextObj = dynamic_cast<SdrTextObj*>( mpObj );
+ if ( mpSearchSpellTextObj && mpSearchSpellTextObj->HasText() && !mpSearchSpellTextObj->IsEmptyPresObj() )
+ {
+ SdrText* pText = mpSearchSpellTextObj->getText( maCurrentPosition.mnText );
+ mpParaObj = pText ? pText->GetOutlinerParaObject() : nullptr;
+
+ if (mpParaObj != nullptr)
+ {
+ SetText(*mpParaObj);
+
+ ClearModifyFlag();
+ }
+ }
+ else
+ {
+ mpSearchSpellTextObj = nullptr;
+ }
+}
+
+void SdOutliner::PrepareSpellCheck()
+{
+ EESpellState eState = HasSpellErrors();
+ DBG_ASSERT(eState != EESpellState::NoSpeller, "No SpellChecker");
+
+ if (eState == EESpellState::Ok)
+ return;
+
+ // When spell checking we have to test whether we have processed the
+ // whole document and have reached the start page again.
+ if (meMode == SPELL)
+ {
+ if (maSearchStartPosition == sd::outliner::Iterator())
+ // Remember the position of the first text object so that we
+ // know when we have processed the whole document.
+ maSearchStartPosition = maObjectIterator;
+ else if (maSearchStartPosition == maObjectIterator)
+ {
+ mbEndOfSearch = true;
+ }
+ }
+
+ EnterEditMode( false );
+}
+
+void SdOutliner::PrepareSearchAndReplace()
+{
+ if (!HasText( *mpSearchItem ))
+ return;
+
+ // Set the object now that we know it matches.
+ mpObj = SetObject(maCurrentPosition);
+
+ mbStringFound = true;
+ mbMatchMayExist = true;
+
+ EnterEditMode(false);
+
+ mpDrawDocument->GetDocSh()->SetWaitCursor( false );
+ // Start search at the right end of the current object's text
+ // depending on the search direction.
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (pOutlinerView != nullptr)
+ pOutlinerView->SetSelection (GetSearchStartPosition ());
+}
+
+void SdOutliner::SetViewMode (PageKind ePageKind)
+{
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ std::shared_ptr<sd::DrawViewShell> pDrawViewShell(
+ std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell));
+ if (pDrawViewShell == nullptr || ePageKind == pDrawViewShell->GetPageKind())
+ return;
+
+ // Restore old edit mode.
+ pDrawViewShell->ChangeEditMode(mpImpl->meOriginalEditMode, false);
+
+ SetStatusEventHdl(Link<EditStatus&,void>());
+ OUString sViewURL;
+ switch (ePageKind)
+ {
+ case PageKind::Standard:
+ default:
+ sViewURL = sd::framework::FrameworkHelper::msImpressViewURL;
+ break;
+ case PageKind::Notes:
+ sViewURL = sd::framework::FrameworkHelper::msNotesViewURL;
+ break;
+ case PageKind::Handout:
+ sViewURL = sd::framework::FrameworkHelper::msHandoutViewURL;
+ break;
+ }
+ // The text object iterator is destroyed when the shells are
+ // switched but we need it so save it and restore it afterwards.
+ sd::outliner::Iterator aIterator (maObjectIterator);
+ bool bMatchMayExist = mbMatchMayExist;
+
+ sd::ViewShellBase& rBase = pViewShell->GetViewShellBase();
+
+ rtl::Reference<sd::FuSearch> xFuSearch;
+ if (pViewShell->GetView())
+ xFuSearch = pViewShell->GetView()->getSearchContext().getFunctionSearch();
+
+ SetViewShell(std::shared_ptr<sd::ViewShell>());
+ sd::framework::FrameworkHelper::Instance(rBase)->RequestView(
+ sViewURL,
+ sd::framework::FrameworkHelper::msCenterPaneURL);
+
+ // Force (well, request) a synchronous update of the configuration.
+ // In a better world we would handle the asynchronous view update
+ // instead. But that would involve major restructuring of the
+ // Outliner code.
+ sd::framework::FrameworkHelper::Instance(rBase)->RequestSynchronousUpdate();
+
+ auto pNewViewShell = rBase.GetMainViewShell();
+ SetViewShell(pNewViewShell);
+ if (xFuSearch.is() && pNewViewShell->GetView())
+ pNewViewShell->GetView()->getSearchContext().setSearchFunction(xFuSearch);
+
+ // Switching to another view shell has intermediatly called
+ // EndSpelling(). A PrepareSpelling() is pending, so call that now.
+ PrepareSpelling();
+
+ // Update the number of pages so that
+ // <member>DetectChange()</member> has the correct value to compare
+ // to.
+ mnPageCount = mpDrawDocument->GetSdPageCount(ePageKind);
+
+ maObjectIterator = aIterator;
+ mbMatchMayExist = bMatchMayExist;
+
+ // Save edit mode so that it can be restored when switching the view
+ // shell again.
+ pDrawViewShell = std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell);
+ OSL_ASSERT(pDrawViewShell != nullptr);
+ if (pDrawViewShell != nullptr)
+ mpImpl->meOriginalEditMode = pDrawViewShell->GetEditMode();
+}
+
+void SdOutliner::SetPage (EditMode eEditMode, sal_uInt16 nPageIndex)
+{
+ if ( ! mbRestrictSearchToSelection)
+ {
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ std::shared_ptr<sd::DrawViewShell> pDrawViewShell(
+ std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell));
+ OSL_ASSERT(pDrawViewShell != nullptr);
+ if (pDrawViewShell != nullptr)
+ {
+ pDrawViewShell->ChangeEditMode(eEditMode, false);
+ pDrawViewShell->SwitchPage(nPageIndex);
+ }
+ }
+}
+
+void SdOutliner::EnterEditMode (bool bGrabFocus)
+{
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (!(pOutlinerView && mpSearchSpellTextObj))
+ return;
+
+ pOutlinerView->SetOutputArea( ::tools::Rectangle( Point(), Size(1, 1)));
+ SetPaperSize( mpSearchSpellTextObj->GetLogicRect().GetSize() );
+ SdrPageView* pPV = mpView->GetSdrPageView();
+
+ // Make FuText the current function.
+ SfxUInt16Item aItem (SID_TEXTEDIT, 1);
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if (!(pViewShell && pViewShell->GetDispatcher()))
+ return;
+
+ pViewShell->GetDispatcher()->ExecuteList(
+ SID_TEXTEDIT, SfxCallMode::SYNCHRON | SfxCallMode::RECORD, {&aItem});
+
+ if (mpView->IsTextEdit())
+ {
+ // end text edition before starting it again
+ mpView->SdrEndTextEdit();
+ }
+
+ // To be consistent with the usual behaviour in the Office the text
+ // object that is put into edit mode would have also to be selected.
+ // Starting the text edit mode is not enough so we do it here by
+ // hand.
+ mpView->UnmarkAllObj(pPV);
+ mpView->MarkObj(mpSearchSpellTextObj, pPV);
+
+ mpSearchSpellTextObj->setActiveText(mnText);
+
+ // Turn on the edit mode for the text object.
+ SetUpdateLayout(true);
+ mpView->SdrBeginTextEdit(mpSearchSpellTextObj, pPV, mpWindow, true, this,
+ pOutlinerView, true, true, bGrabFocus);
+
+ mbFoundObject = true;
+}
+
+ESelection SdOutliner::GetSearchStartPosition() const
+{
+ ESelection aPosition;
+ if (mbDirectionIsForward)
+ {
+ // The default constructor uses the beginning of the text as default.
+ aPosition = ESelection ();
+ }
+ else
+ {
+ // Retrieve the position after the last character in the last
+ // paragraph.
+ sal_Int32 nParagraphCount = GetParagraphCount();
+ if (nParagraphCount == 0)
+ aPosition = ESelection();
+ else
+ {
+ sal_Int32 nLastParagraphLength = GetEditEngine().GetTextLen (
+ nParagraphCount-1);
+ aPosition = ESelection (nParagraphCount-1, nLastParagraphLength);
+ }
+ }
+
+ return aPosition;
+}
+
+bool SdOutliner::HasNoPreviousMatch()
+{
+ OutlinerView* pOutlinerView = getOutlinerView();
+
+ DBG_ASSERT (pOutlinerView!=nullptr, "outline view in SdOutliner::HasNoPreviousMatch is NULL");
+
+ // Detect whether the cursor stands at the beginning
+ // resp. at the end of the text.
+ return pOutlinerView->GetSelection() == GetSearchStartPosition();
+}
+
+bool SdOutliner::HandleFailedSearch()
+{
+ bool bContinueSearch = false;
+
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (pOutlinerView && mpSearchItem)
+ {
+ // Detect whether there is/may be a prior match. If there is then
+ // ask the user whether to wrap around. Otherwise tell the user
+ // that there is no match.
+ if (HasNoPreviousMatch ())
+ {
+ // No match found in the whole presentation.
+ SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
+ }
+
+ else
+ {
+ // No further matches found. Ask the user whether to wrap
+ // around and start again.
+ bContinueSearch = ShowWrapAroundDialog();
+ }
+ }
+
+ return bContinueSearch;
+}
+
+SdrObject* SdOutliner::SetObject (
+ const sd::outliner::IteratorPosition& rPosition)
+{
+ SetViewMode (rPosition.mePageKind);
+ SetPage (rPosition.meEditMode, static_cast<sal_uInt16>(rPosition.mnPageIndex));
+ mnText = rPosition.mnText;
+ return rPosition.mxObject.get();
+}
+
+void SdOutliner::SetViewShell (const std::shared_ptr<sd::ViewShell>& rpViewShell)
+{
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if (pViewShell == rpViewShell)
+ return;
+
+ // Set the new view shell.
+ mpWeakViewShell = rpViewShell;
+ // When the outline view is not owned by us then we have to clear
+ // that pointer so that the current one for the new view shell will
+ // be used (in ProvideOutlinerView).
+ if (rpViewShell)
+ {
+ mpView = rpViewShell->GetView();
+
+ mpWindow = rpViewShell->GetActiveWindow();
+
+ mpImpl->ProvideOutlinerView(*this, rpViewShell, mpWindow);
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (pOutlinerView != nullptr)
+ pOutlinerView->SetWindow(mpWindow);
+ }
+ else
+ {
+ mpView = nullptr;
+ mpWindow = nullptr;
+ }
+}
+
+void SdOutliner::HandleChangedSelection()
+{
+ maMarkListCopy.clear();
+ mbRestrictSearchToSelection = mpView->AreObjectsMarked();
+ if (!mbRestrictSearchToSelection)
+ return;
+
+ // Make a copy of the current mark list.
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+ if (nCount > 0)
+ {
+ maMarkListCopy.clear();
+ maMarkListCopy.reserve (nCount);
+ for (size_t i=0; i<nCount; ++i)
+ maMarkListCopy.emplace_back(rMarkList.GetMark(i)->GetMarkedSdrObj ());
+ }
+ else
+ // No marked object. Is this case possible?
+ mbRestrictSearchToSelection = false;
+}
+
+void SdOutliner::StartConversion( LanguageType nSourceLanguage, LanguageType nTargetLanguage,
+ const vcl::Font *pTargetFont, sal_Int32 nOptions, bool bIsInteractive )
+{
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ bool bMultiDoc = nullptr != dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() );
+
+ meMode = TEXT_CONVERSION;
+ mbDirectionIsForward = true;
+ mpSearchItem.reset();
+ mnConversionLanguage = nSourceLanguage;
+
+ BeginConversion();
+
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (pOutlinerView != nullptr)
+ {
+ pOutlinerView->StartTextConversion(
+ GetMessageBoxParent(),
+ nSourceLanguage,
+ nTargetLanguage,
+ pTargetFont,
+ nOptions,
+ bIsInteractive,
+ bMultiDoc);
+ }
+
+ EndConversion();
+}
+
+/** Prepare to do a text conversion on the current text object. This
+ includes putting it into edit mode.
+*/
+void SdOutliner::PrepareConversion()
+{
+ SetUpdateLayout(true);
+ if( HasConvertibleTextPortion( mnConversionLanguage ) )
+ {
+ SetUpdateLayout(false);
+ mbStringFound = true;
+ mbMatchMayExist = true;
+
+ EnterEditMode(true);
+
+ mpDrawDocument->GetDocSh()->SetWaitCursor( false );
+ // Start search at the right end of the current object's text
+ // depending on the search direction.
+ }
+ else
+ {
+ SetUpdateLayout(false);
+ }
+}
+
+void SdOutliner::BeginConversion()
+{
+ SetRefDevice( SD_MOD()->GetVirtualRefDevice() );
+
+ sd::ViewShellBase* pBase = getViewShellBase();
+ if (pBase != nullptr)
+ SetViewShell (pBase->GetMainViewShell());
+
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if (pViewShell)
+ {
+ mbStringFound = false;
+
+ // Supposed that we are not located at the very beginning/end of the
+ // document then there may be a match in the document prior/after
+ // the current position.
+ mbMatchMayExist = true;
+
+ maObjectIterator = sd::outliner::Iterator();
+ maSearchStartPosition = sd::outliner::Iterator();
+ RememberStartPosition();
+
+ mpImpl->ProvideOutlinerView(*this, pViewShell, mpWindow);
+
+ HandleChangedSelection ();
+ }
+ ClearModifyFlag();
+}
+
+void SdOutliner::EndConversion()
+{
+ EndSpelling();
+}
+
+bool SdOutliner::ConvertNextDocument()
+{
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ if (dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ) )
+ return false;
+
+ mpDrawDocument->GetDocSh()->SetWaitCursor( true );
+
+ Initialize ( true );
+
+ OutlinerView* pOutlinerView = getOutlinerView();
+ if (pOutlinerView != nullptr)
+ {
+ mpWindow = pViewShell->GetActiveWindow();
+ pOutlinerView->SetWindow(mpWindow);
+ }
+ ProvideNextTextObject ();
+
+ mpDrawDocument->GetDocSh()->SetWaitCursor( false );
+ ClearModifyFlag();
+
+ // for text conversion we automatically wrap around one
+ // time and stop at the start shape
+ if( mpFirstObj )
+ {
+ if( (mnText == 0) && (mpFirstObj == mpObj) )
+ return false;
+ }
+ else
+ {
+ mpFirstObj = mpObj;
+ }
+
+ return !mbEndOfSearch;
+}
+
+weld::Window* SdOutliner::GetMessageBoxParent()
+{
+ // We assume that the parent of the given message box is NULL, i.e. it is
+ // modal with respect to the top application window. However, this
+ // does not affect the search dialog. Therefore we have to lock it here
+ // while the message box is being shown. We also have to take into
+ // account that we are called during a spell check and the search dialog
+ // is not available.
+ weld::Window* pSearchDialog = nullptr;
+ SfxChildWindow* pChildWindow = nullptr;
+ switch (meMode)
+ {
+ case SEARCH:
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ pChildWindow = pViewFrm->GetChildWindow(
+ SvxSearchDialogWrapper::GetChildWindowId());
+ break;
+
+ case SPELL:
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ pChildWindow = pViewFrm->GetChildWindow(
+ sd::SpellDialogChildWindow::GetChildWindowId());
+ break;
+
+ case TEXT_CONVERSION:
+ // There should no messages boxes be displayed while doing the
+ // hangul hanja conversion.
+ break;
+ }
+
+ if (pChildWindow != nullptr)
+ {
+ auto xController = pChildWindow->GetController();
+ pSearchDialog = xController ? xController->getDialog() : nullptr;
+ }
+
+ if (pSearchDialog)
+ return pSearchDialog;
+
+ std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
+ auto pWin = pViewShell->GetActiveWindow();
+ return pWin ? pWin->GetFrameWeld() : nullptr;
+}
+
+//===== SdOutliner::Implementation ==============================================
+
+SdOutliner::Implementation::Implementation()
+ : meOriginalEditMode(EditMode::Page),
+ mbOwnOutlineView(false),
+ mpOutlineView(nullptr)
+{
+}
+
+SdOutliner::Implementation::~Implementation()
+{
+ if (mbOwnOutlineView && mpOutlineView!=nullptr)
+ {
+ mpOutlineView->SetWindow(nullptr);
+ delete mpOutlineView;
+ mpOutlineView = nullptr;
+ }
+}
+
+/** We try to create a new OutlinerView only when there is none available,
+ either from an OutlinerViewShell or a previous call to
+ ProvideOutlinerView(). This is necessary to support the spell checker
+ which can not cope with exchanging the OutlinerView.
+*/
+void SdOutliner::Implementation::ProvideOutlinerView (
+ Outliner& rOutliner,
+ const std::shared_ptr<sd::ViewShell>& rpViewShell,
+ vcl::Window* pWindow)
+{
+ if (rpViewShell == nullptr)
+ return;
+
+ switch (rpViewShell->GetShellType())
+ {
+ case sd::ViewShell::ST_DRAW:
+ case sd::ViewShell::ST_IMPRESS:
+ case sd::ViewShell::ST_NOTES:
+ case sd::ViewShell::ST_HANDOUT:
+ {
+ // Create a new outline view to do the search on.
+ bool bInsert = false;
+ if (mpOutlineView != nullptr && !mbOwnOutlineView)
+ mpOutlineView = nullptr;
+
+ if (mpOutlineView == nullptr || !rOutliner.GetEditEngine().HasView(&mpOutlineView->GetEditView()))
+ {
+ delete mpOutlineView;
+ mpOutlineView = new OutlinerView(&rOutliner, pWindow);
+ mbOwnOutlineView = true;
+ bInsert = true;
+ }
+ else
+ mpOutlineView->SetWindow(pWindow);
+
+ EVControlBits nStat = mpOutlineView->GetControlWord();
+ nStat &= ~EVControlBits::AUTOSCROLL;
+ mpOutlineView->SetControlWord(nStat);
+
+ if (bInsert)
+ rOutliner.InsertView( mpOutlineView );
+
+ rOutliner.SetUpdateLayout(false);
+ mpOutlineView->SetOutputArea (::tools::Rectangle (Point(), Size(1, 1)));
+ rOutliner.SetPaperSize( Size(1, 1) );
+ rOutliner.SetText(OUString(), rOutliner.GetParagraph(0));
+
+ meOriginalEditMode =
+ std::static_pointer_cast<sd::DrawViewShell>(rpViewShell)->GetEditMode();
+ }
+ break;
+
+ case sd::ViewShell::ST_OUTLINE:
+ {
+ if (mpOutlineView!=nullptr && mbOwnOutlineView)
+ delete mpOutlineView;
+ mpOutlineView = rOutliner.GetView(0);
+ mbOwnOutlineView = false;
+ }
+ break;
+
+ default:
+ case sd::ViewShell::ST_NONE:
+ case sd::ViewShell::ST_PRESENTATION:
+ // Ignored
+ break;
+ }
+}
+
+void SdOutliner::Implementation::ReleaseOutlinerView()
+{
+ if (mbOwnOutlineView)
+ {
+ OutlinerView* pView = mpOutlineView;
+ mpOutlineView = nullptr;
+ mbOwnOutlineView = false;
+ if (pView != nullptr)
+ {
+ pView->SetWindow(nullptr);
+ delete pView;
+ }
+ }
+ else
+ {
+ mpOutlineView = nullptr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/OutlinerIterator.cxx b/sd/source/ui/view/OutlinerIterator.cxx
new file mode 100644
index 000000000..8cdb29330
--- /dev/null
+++ b/sd/source/ui/view/OutlinerIterator.cxx
@@ -0,0 +1,798 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <OutlinerIterator.hxx>
+#include <OutlinerIteratorImpl.hxx>
+#include <svx/svditer.hxx>
+#include <tools/debug.hxx>
+#include <osl/diagnose.h>
+#include <Outliner.hxx>
+
+#include <drawdoc.hxx>
+#include <DrawViewShell.hxx>
+#include <sdpage.hxx>
+
+namespace sd::outliner {
+
+//===== IteratorPosition ======================================================
+
+IteratorPosition::IteratorPosition()
+: mnText(0)
+, mnPageIndex(-1)
+, mePageKind(PageKind::Standard)
+, meEditMode(EditMode::Page)
+{
+}
+
+bool IteratorPosition::operator== (const IteratorPosition& aPosition) const
+{
+ return mxObject.get() == aPosition.mxObject.get()
+ && mnText == aPosition.mnText
+ && mnPageIndex == aPosition.mnPageIndex
+ && mePageKind == aPosition.mePageKind
+ && meEditMode == aPosition.meEditMode;
+}
+
+//===== Iterator ==============================================================
+
+Iterator::Iterator()
+{
+}
+
+Iterator::Iterator (const Iterator& rIterator)
+ : mxIterator(rIterator.mxIterator ? rIterator.mxIterator->Clone() : nullptr)
+{
+}
+
+Iterator::Iterator(Iterator&& rIterator) noexcept
+ : mxIterator(std::move(rIterator.mxIterator))
+{
+}
+
+Iterator::Iterator (std::unique_ptr<IteratorImplBase> pObject)
+ : mxIterator(std::move(pObject))
+{
+}
+
+Iterator::~Iterator()
+{
+}
+
+Iterator& Iterator::operator= (const Iterator& rIterator)
+{
+ if (this != &rIterator)
+ {
+ if (rIterator.mxIterator)
+ mxIterator.reset(rIterator.mxIterator->Clone());
+ else
+ mxIterator.reset();
+ }
+ return *this;
+}
+
+Iterator& Iterator::operator=(Iterator&& rIterator) noexcept
+{
+ mxIterator = std::move(rIterator.mxIterator);
+ return *this;
+}
+
+const IteratorPosition& Iterator::operator* () const
+{
+ DBG_ASSERT (mxIterator, "::sd::outliner::Iterator::operator* : missing implementation object");
+ return mxIterator->GetPosition();
+}
+
+Iterator& Iterator::operator++ ()
+{
+ if (mxIterator)
+ mxIterator->GotoNextText();
+ return *this;
+}
+
+bool Iterator::operator== (const Iterator& rIterator) const
+{
+ if (!mxIterator || !rIterator.mxIterator)
+ return mxIterator.get() == rIterator.mxIterator.get();
+ else
+ return *mxIterator == *rIterator.mxIterator;
+}
+
+bool Iterator::operator!= (const Iterator& rIterator) const
+{
+ return ! operator==(rIterator);
+}
+
+void Iterator::Reverse()
+{
+ if (mxIterator)
+ mxIterator->Reverse();
+}
+
+//===== IteratorFactory =======================================================
+
+OutlinerContainer::OutlinerContainer (SdOutliner* pOutliner)
+: mpOutliner(pOutliner)
+{
+}
+
+Iterator OutlinerContainer::begin()
+{
+ return CreateIterator (BEGIN);
+}
+
+Iterator OutlinerContainer::end()
+{
+ return CreateIterator (END);
+}
+
+Iterator OutlinerContainer::current()
+{
+ return CreateIterator (CURRENT);
+}
+
+Iterator OutlinerContainer::CreateIterator (IteratorLocation aLocation)
+{
+ // Decide on certain features of the outliner which kind of iterator to
+ // use.
+ if (mpOutliner->mbRestrictSearchToSelection)
+ // There is a selection. Search only in this.
+ return CreateSelectionIterator (
+ mpOutliner->maMarkListCopy,
+ mpOutliner->mpDrawDocument,
+ mpOutliner->mpWeakViewShell.lock(),
+ mpOutliner->mbDirectionIsForward,
+ aLocation);
+ else
+ // Search in the whole document.
+ return CreateDocumentIterator (
+ mpOutliner->mpDrawDocument,
+ mpOutliner->mpWeakViewShell.lock(),
+ mpOutliner->mbDirectionIsForward,
+ aLocation);
+}
+
+Iterator OutlinerContainer::CreateSelectionIterator (
+ const ::std::vector<::tools::WeakReference<SdrObject>>& rObjectList,
+ SdDrawDocument* pDocument,
+ const std::shared_ptr<ViewShell>& rpViewShell,
+ bool bDirectionIsForward,
+ IteratorLocation aLocation)
+{
+ OSL_ASSERT(rpViewShell);
+
+ sal_Int32 nObjectIndex;
+
+ if (bDirectionIsForward)
+ switch (aLocation)
+ {
+ case CURRENT:
+ case BEGIN:
+ default:
+ nObjectIndex = 0;
+ break;
+ case END:
+ nObjectIndex = rObjectList.size();
+ break;
+ }
+ else
+ switch (aLocation)
+ {
+ case CURRENT:
+ case BEGIN:
+ default:
+ nObjectIndex = rObjectList.size()-1;
+ break;
+ case END:
+ nObjectIndex = -1;
+ break;
+ }
+
+ return Iterator (std::make_unique<SelectionIteratorImpl> (
+ rObjectList, nObjectIndex, pDocument, rpViewShell, bDirectionIsForward));
+}
+
+Iterator OutlinerContainer::CreateDocumentIterator (
+ SdDrawDocument* pDocument,
+ const std::shared_ptr<ViewShell>& rpViewShell,
+ bool bDirectionIsForward,
+ IteratorLocation aLocation)
+{
+ OSL_ASSERT(rpViewShell);
+
+ PageKind ePageKind;
+ EditMode eEditMode;
+
+ switch (aLocation)
+ {
+ case BEGIN:
+ default:
+ if (bDirectionIsForward)
+ {
+ ePageKind = PageKind::Standard;
+ eEditMode = EditMode::Page;
+ }
+ else
+ {
+ ePageKind = PageKind::Handout;
+ eEditMode = EditMode::MasterPage;
+ }
+ break;
+
+ case END:
+ if (bDirectionIsForward)
+ {
+ ePageKind = PageKind::Handout;
+ eEditMode = EditMode::MasterPage;
+ }
+ else
+ {
+ ePageKind = PageKind::Standard;
+ eEditMode = EditMode::Page;
+ }
+ break;
+
+ case CURRENT:
+ const std::shared_ptr<DrawViewShell> pDrawViewShell(
+ std::dynamic_pointer_cast<DrawViewShell>(rpViewShell));
+ if (pDrawViewShell)
+ {
+ ePageKind = pDrawViewShell->GetPageKind();
+ eEditMode = pDrawViewShell->GetEditMode();
+ }
+ else
+ {
+ ePageKind = PageKind::Standard;
+ eEditMode = EditMode::Page;
+ }
+ break;
+ }
+
+ sal_Int32 nPageIndex = GetPageIndex (pDocument, rpViewShell,
+ ePageKind, eEditMode, bDirectionIsForward, aLocation);
+
+ return Iterator (
+ std::make_unique<DocumentIteratorImpl> (nPageIndex, ePageKind, eEditMode,
+ pDocument, rpViewShell, bDirectionIsForward));
+}
+
+sal_Int32 OutlinerContainer::GetPageIndex (
+ SdDrawDocument const * pDocument,
+ const std::shared_ptr<ViewShell>& rpViewShell,
+ PageKind ePageKind,
+ EditMode eEditMode,
+ bool bDirectionIsForward,
+ IteratorLocation aLocation)
+{
+ OSL_ASSERT(rpViewShell);
+
+ sal_Int32 nPageIndex;
+ sal_Int32 nPageCount;
+
+ const std::shared_ptr<DrawViewShell> pDrawViewShell(
+ std::dynamic_pointer_cast<DrawViewShell>(rpViewShell));
+
+ switch (eEditMode)
+ {
+ case EditMode::Page:
+ nPageCount = pDocument->GetSdPageCount (ePageKind);
+ break;
+ case EditMode::MasterPage:
+ nPageCount = pDocument->GetMasterSdPageCount(ePageKind);
+ break;
+ default:
+ nPageCount = 0;
+ }
+
+ switch (aLocation)
+ {
+ case CURRENT:
+ if (pDrawViewShell)
+ nPageIndex = pDrawViewShell->GetCurPagePos();
+ else
+ {
+ const SdPage* pPage = rpViewShell->GetActualPage();
+ if (pPage != nullptr)
+ nPageIndex = (pPage->GetPageNum()-1)/2;
+ else
+ nPageIndex = 0;
+ }
+ break;
+
+ case BEGIN:
+ default:
+ if (bDirectionIsForward)
+ nPageIndex = 0;
+ else
+ nPageIndex = nPageCount-1;
+ break;
+
+ case END:
+ if (bDirectionIsForward)
+ nPageIndex = nPageCount;
+ else
+ nPageIndex = -1;
+ break;
+ }
+
+ return nPageIndex;
+}
+
+//===== IteratorImplBase ====================================================
+
+IteratorImplBase::IteratorImplBase(SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward)
+: mpDocument (pDocument)
+, mpViewShellWeak (rpViewShellWeak)
+, mbDirectionIsForward (bDirectionIsForward)
+{
+ std::shared_ptr<DrawViewShell> pDrawViewShell;
+ if ( ! mpViewShellWeak.expired())
+ pDrawViewShell = std::dynamic_pointer_cast<DrawViewShell>(rpViewShellWeak.lock());
+
+ if (pDrawViewShell)
+ {
+ maPosition.mePageKind = pDrawViewShell->GetPageKind();
+ maPosition.meEditMode = pDrawViewShell->GetEditMode();
+ }
+ else
+ {
+ maPosition.mePageKind = PageKind::Standard;
+ maPosition.meEditMode = EditMode::Page;
+ }
+}
+
+IteratorImplBase::IteratorImplBase( SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward, PageKind ePageKind, EditMode eEditMode)
+: mpDocument (pDocument)
+, mpViewShellWeak (rpViewShellWeak)
+, mbDirectionIsForward (bDirectionIsForward)
+{
+ maPosition.mePageKind = ePageKind;
+ maPosition.meEditMode = eEditMode;
+}
+
+IteratorImplBase::~IteratorImplBase()
+{}
+
+bool IteratorImplBase::operator== (const IteratorImplBase& rIterator) const
+{
+ return maPosition == rIterator.maPosition;
+}
+
+bool IteratorImplBase::IsEqualSelection(const IteratorImplBase& rIterator) const
+{
+ // When this method is executed instead of the ones from derived classes
+ // then the argument is of another type then the object itself. In this
+ // just compare the position objects.
+ return maPosition == rIterator.maPosition;
+}
+
+const IteratorPosition& IteratorImplBase::GetPosition()
+{
+ return maPosition;
+}
+
+IteratorImplBase* IteratorImplBase::Clone (IteratorImplBase* pObject) const
+{
+ if (pObject != nullptr)
+ {
+ pObject->maPosition = maPosition;
+ pObject->mpDocument = mpDocument;
+ pObject->mpViewShellWeak = mpViewShellWeak;
+ pObject->mbDirectionIsForward = mbDirectionIsForward;
+ }
+ return pObject;
+}
+
+void IteratorImplBase::Reverse()
+{
+ mbDirectionIsForward = ! mbDirectionIsForward;
+}
+
+//===== SelectionIteratorImpl ===========================================
+
+SelectionIteratorImpl::SelectionIteratorImpl (
+ const ::std::vector<::tools::WeakReference<SdrObject>>& rObjectList,
+ sal_Int32 nObjectIndex,
+ SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward)
+ : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward),
+ mrObjectList(rObjectList),
+ mnObjectIndex(nObjectIndex)
+{
+}
+
+SelectionIteratorImpl::~SelectionIteratorImpl()
+{}
+
+IteratorImplBase* SelectionIteratorImpl::Clone (IteratorImplBase* pObject) const
+{
+ SelectionIteratorImpl* pIterator = static_cast<SelectionIteratorImpl*>(pObject);
+ if (pIterator == nullptr)
+ pIterator = new SelectionIteratorImpl (
+ mrObjectList, mnObjectIndex, mpDocument, mpViewShellWeak, mbDirectionIsForward);
+ return pIterator;
+}
+
+void SelectionIteratorImpl::GotoNextText()
+{
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mrObjectList.at(mnObjectIndex).get() );
+ if (mbDirectionIsForward)
+ {
+ if( pTextObj )
+ {
+ ++maPosition.mnText;
+ if( maPosition.mnText >= pTextObj->getTextCount() )
+ {
+ maPosition.mnText = 0;
+ ++mnObjectIndex;
+ }
+ }
+ else
+ {
+ ++mnObjectIndex;
+ }
+ }
+ else
+ {
+ if( pTextObj )
+ {
+ --maPosition.mnText;
+ if( maPosition.mnText < 0 )
+ {
+ maPosition.mnText = -1;
+ --mnObjectIndex;
+ }
+ }
+ else
+ {
+ --mnObjectIndex;
+ maPosition.mnText = -1;
+ }
+
+ if( (maPosition.mnText == -1) && (mnObjectIndex >= 0) )
+ {
+ pTextObj = dynamic_cast< SdrTextObj* >( mrObjectList.at(mnObjectIndex).get() );
+ if( pTextObj )
+ maPosition.mnText = pTextObj->getTextCount() - 1;
+ }
+
+ if( maPosition.mnText == -1 )
+ maPosition.mnText = 0;
+ }
+}
+
+const IteratorPosition& SelectionIteratorImpl::GetPosition()
+{
+ maPosition.mxObject = mrObjectList.at(mnObjectIndex);
+
+ return maPosition;
+}
+
+bool SelectionIteratorImpl::operator== (const IteratorImplBase& rIterator) const
+{
+ return rIterator.IsEqualSelection(*this);
+}
+
+bool SelectionIteratorImpl::IsEqualSelection(const IteratorImplBase& rIterator) const
+{
+ const SelectionIteratorImpl* pSelectionIterator =
+ static_cast<const SelectionIteratorImpl*>(&rIterator);
+ return mpDocument == pSelectionIterator->mpDocument
+ && mnObjectIndex == pSelectionIterator->mnObjectIndex;
+}
+
+//===== ViewIteratorImpl ================================================
+
+ViewIteratorImpl::ViewIteratorImpl (
+ sal_Int32 nPageIndex,
+ SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward)
+ : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward),
+ mbPageChangeOccurred(false),
+ mpPage(nullptr)
+{
+ SetPage (nPageIndex);
+}
+
+ViewIteratorImpl::ViewIteratorImpl (
+ sal_Int32 nPageIndex,
+ SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward,
+ PageKind ePageKind,
+ EditMode eEditMode)
+ : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward, ePageKind, eEditMode),
+ mbPageChangeOccurred(false),
+ mpPage(nullptr)
+{
+ SetPage (nPageIndex);
+}
+
+ViewIteratorImpl::~ViewIteratorImpl()
+{
+}
+
+IteratorImplBase* ViewIteratorImpl::Clone (IteratorImplBase* pObject) const
+{
+
+ ViewIteratorImpl* pIterator = static_cast<ViewIteratorImpl*>(pObject);
+ if (pIterator == nullptr)
+ pIterator = new ViewIteratorImpl (
+ maPosition.mnPageIndex, mpDocument, mpViewShellWeak, mbDirectionIsForward);
+
+ IteratorImplBase::Clone (pObject);
+
+ if (mpObjectIterator != nullptr)
+ {
+ pIterator->mpObjectIterator.reset( new SdrObjListIter(mpPage, SdrIterMode::DeepNoGroups, !mbDirectionIsForward) );
+
+ // No direct way to set the object iterator to the current object.
+ pIterator->maPosition.mxObject.reset(nullptr);
+ while (pIterator->mpObjectIterator->IsMore() && pIterator->maPosition.mxObject!=maPosition.mxObject)
+ pIterator->maPosition.mxObject.reset(pIterator->mpObjectIterator->Next());
+ }
+ else
+ pIterator->mpObjectIterator.reset();
+
+ return pIterator;
+}
+
+void ViewIteratorImpl::GotoNextText()
+{
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( maPosition.mxObject.get() );
+ if( pTextObj )
+ {
+ if (mbDirectionIsForward)
+ {
+ ++maPosition.mnText;
+ if( maPosition.mnText < pTextObj->getTextCount() )
+ return;
+ }
+ else
+ {
+ --maPosition.mnText;
+ if( maPosition.mnText >= 0 )
+ return;
+ }
+ }
+
+ if (mpObjectIterator != nullptr && mpObjectIterator->IsMore())
+ maPosition.mxObject.reset(mpObjectIterator->Next());
+ else
+ maPosition.mxObject.reset(nullptr);
+
+ if (!maPosition.mxObject.is() )
+ {
+ if (mbDirectionIsForward)
+ SetPage (maPosition.mnPageIndex+1);
+ else
+ SetPage (maPosition.mnPageIndex-1);
+
+ if (mpPage != nullptr)
+ mpObjectIterator.reset( new SdrObjListIter(mpPage, SdrIterMode::DeepNoGroups, !mbDirectionIsForward) );
+ if (mpObjectIterator!=nullptr && mpObjectIterator->IsMore())
+ maPosition.mxObject.reset(mpObjectIterator->Next());
+ else
+ maPosition.mxObject.reset(nullptr);
+ }
+
+ maPosition.mnText = 0;
+ if( !mbDirectionIsForward && maPosition.mxObject.is() )
+ {
+ pTextObj = dynamic_cast< SdrTextObj* >( maPosition.mxObject.get() );
+ if( pTextObj )
+ maPosition.mnText = pTextObj->getTextCount() - 1;
+ }
+}
+
+void ViewIteratorImpl::SetPage (sal_Int32 nPageIndex)
+{
+ mbPageChangeOccurred = (maPosition.mnPageIndex!=nPageIndex);
+ if (mbPageChangeOccurred)
+ {
+ maPosition.mnPageIndex = nPageIndex;
+
+ sal_Int32 nPageCount;
+ if (maPosition.meEditMode == EditMode::Page)
+ nPageCount = mpDocument->GetSdPageCount(maPosition.mePageKind);
+ else
+ nPageCount = mpDocument->GetMasterSdPageCount(
+ maPosition.mePageKind);
+
+ // Get page pointer. Here we have three cases: regular pages,
+ // master pages and invalid page indices. The later ones are not
+ // errors but the effect of the iterator advancing to the next page
+ // and going past the last one. This dropping of the rim at the far
+ // side is detected here and has to be reacted to by the caller.
+ if (nPageIndex>=0 && nPageIndex < nPageCount)
+ {
+ if (maPosition.meEditMode == EditMode::Page)
+ mpPage = mpDocument->GetSdPage (
+ static_cast<sal_uInt16>(nPageIndex),
+ maPosition.mePageKind);
+ else
+ mpPage = mpDocument->GetMasterSdPage (
+ static_cast<sal_uInt16>(nPageIndex),
+ maPosition.mePageKind);
+ }
+ else
+ mpPage = nullptr;
+ }
+
+ // Set up object list iterator.
+ if (mpPage != nullptr)
+ mpObjectIterator.reset( new SdrObjListIter(mpPage, SdrIterMode::DeepNoGroups, ! mbDirectionIsForward) );
+ else
+ mpObjectIterator.reset();
+
+ // Get object pointer.
+ if (mpObjectIterator!=nullptr && mpObjectIterator->IsMore())
+ maPosition.mxObject.reset( mpObjectIterator->Next() );
+ else
+ maPosition.mxObject.reset(nullptr);
+
+ maPosition.mnText = 0;
+ if( !mbDirectionIsForward && maPosition.mxObject.is() )
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( maPosition.mxObject.get() );
+ if( pTextObj )
+ maPosition.mnText = pTextObj->getTextCount() - 1;
+ }
+
+}
+
+void ViewIteratorImpl::Reverse()
+{
+ IteratorImplBase::Reverse ();
+
+ // Create reversed object list iterator.
+ if (mpPage != nullptr)
+ mpObjectIterator.reset( new SdrObjListIter(mpPage, SdrIterMode::DeepNoGroups, ! mbDirectionIsForward) );
+ else
+ mpObjectIterator.reset();
+
+ // Move iterator to the current object.
+ ::tools::WeakReference<SdrObject> xObject = std::move(maPosition.mxObject);
+
+ if (!mpObjectIterator)
+ return;
+
+ while (mpObjectIterator->IsMore() && maPosition.mxObject != xObject)
+ maPosition.mxObject.reset(mpObjectIterator->Next());
+}
+
+//===== DocumentIteratorImpl ============================================
+
+DocumentIteratorImpl::DocumentIteratorImpl (
+ sal_Int32 nPageIndex,
+ PageKind ePageKind, EditMode eEditMode,
+ SdDrawDocument* pDocument,
+ const std::weak_ptr<ViewShell>& rpViewShellWeak,
+ bool bDirectionIsForward)
+ : ViewIteratorImpl (nPageIndex, pDocument, rpViewShellWeak, bDirectionIsForward,
+ ePageKind, eEditMode)
+{
+ if (eEditMode == EditMode::Page)
+ mnPageCount = pDocument->GetSdPageCount (ePageKind);
+ else
+ mnPageCount = pDocument->GetMasterSdPageCount(ePageKind);
+}
+
+DocumentIteratorImpl::~DocumentIteratorImpl()
+{}
+
+IteratorImplBase* DocumentIteratorImpl::Clone (IteratorImplBase* pObject) const
+{
+ DocumentIteratorImpl* pIterator = static_cast<DocumentIteratorImpl*>(pObject);
+ if (pIterator == nullptr)
+ pIterator = new DocumentIteratorImpl (
+ maPosition.mnPageIndex, maPosition.mePageKind, maPosition.meEditMode,
+ mpDocument, mpViewShellWeak, mbDirectionIsForward);
+ // Finish the cloning.
+ return ViewIteratorImpl::Clone (pIterator);
+}
+
+void DocumentIteratorImpl::GotoNextText()
+{
+ bool bSetToOnePastLastPage = false;
+ bool bViewChanged = false;
+
+ ViewIteratorImpl::GotoNextText();
+
+ if (mbDirectionIsForward)
+ {
+ if (maPosition.mnPageIndex >= mnPageCount)
+ {
+ // Switch to master page.
+ if (maPosition.meEditMode == EditMode::Page)
+ {
+ maPosition.meEditMode = EditMode::MasterPage;
+ SetPage (0);
+ }
+
+ // Switch to next view mode.
+ else
+ {
+ if (maPosition.mePageKind == PageKind::Handout)
+ // Not really necessary but makes things more clear.
+ bSetToOnePastLastPage = true;
+ else
+ {
+ maPosition.meEditMode = EditMode::Page;
+ if (maPosition.mePageKind == PageKind::Standard)
+ maPosition.mePageKind = PageKind::Notes;
+ else if (maPosition.mePageKind == PageKind::Notes)
+ maPosition.mePageKind = PageKind::Handout;
+ SetPage (0);
+ }
+ }
+ bViewChanged = true;
+ }
+ }
+ else
+ if (maPosition.mnPageIndex < 0)
+ {
+ // Switch from master pages to draw pages.
+ if (maPosition.meEditMode == EditMode::MasterPage)
+ {
+ maPosition.meEditMode = EditMode::Page;
+ bSetToOnePastLastPage = true;
+ }
+
+ // Switch to previous view mode.
+ else
+ {
+ if (maPosition.mePageKind == PageKind::Standard)
+ SetPage (-1);
+ else
+ {
+ maPosition.meEditMode = EditMode::MasterPage;
+ if (maPosition.mePageKind == PageKind::Handout)
+ maPosition.mePageKind = PageKind::Notes;
+ else if (maPosition.mePageKind == PageKind::Notes)
+ maPosition.mePageKind = PageKind::Standard;
+ bSetToOnePastLastPage = true;
+ }
+ }
+ bViewChanged = true;
+ }
+
+ if (!bViewChanged)
+ return;
+
+ // Get new page count;
+ sal_Int32 nPageCount;
+ if (maPosition.meEditMode == EditMode::Page)
+ nPageCount = mpDocument->GetSdPageCount (maPosition.mePageKind);
+ else
+ nPageCount = mpDocument->GetMasterSdPageCount(maPosition.mePageKind);
+
+ // Now that we know the number of pages we can set the current page index.
+ if (bSetToOnePastLastPage)
+ SetPage (nPageCount);
+}
+
+} // end of namespace ::sd::outliner
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/PresentationViewShellBase.cxx b/sd/source/ui/view/PresentationViewShellBase.cxx
new file mode 100644
index 000000000..789afbbdd
--- /dev/null
+++ b/sd/source/ui/view/PresentationViewShellBase.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 <PresentationViewShellBase.hxx>
+#include <DrawDocShell.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <framework/PresentationModule.hxx>
+
+#include <sfx2/viewfac.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+class DrawDocShell;
+
+
+// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a
+// new PresentationViewShellBase object has been constructed.
+
+SfxViewFactory* PresentationViewShellBase::s_pFactory;
+SfxViewShell* PresentationViewShellBase::CreateInstance (
+ SfxViewFrame *_pFrame, SfxViewShell *pOldView)
+{
+ PresentationViewShellBase* pBase =
+ new PresentationViewShellBase(_pFrame, pOldView);
+ pBase->LateInit(framework::FrameworkHelper::msPresentationViewURL);
+ return pBase;
+}
+void PresentationViewShellBase::RegisterFactory( SfxInterfaceId nPrio )
+{
+ s_pFactory = new SfxViewFactory(
+ &CreateInstance,nPrio,"FullScreenPresentation");
+ InitFactory();
+}
+void PresentationViewShellBase::InitFactory()
+{
+ SFX_VIEW_REGISTRATION(DrawDocShell);
+}
+
+PresentationViewShellBase::PresentationViewShellBase (
+ SfxViewFrame* _pFrame,
+ SfxViewShell* pOldShell)
+ : ViewShellBase (_pFrame, pOldShell)
+{
+ // Hide the automatic (non-context sensitive) tool bars.
+ Reference<beans::XPropertySet> xFrameSet (
+ _pFrame->GetFrame().GetFrameInterface(),
+ UNO_QUERY);
+ if (xFrameSet.is())
+ {
+ Reference<beans::XPropertySet> xLayouterSet(xFrameSet->getPropertyValue("LayoutManager"), UNO_QUERY);
+ if (xLayouterSet.is())
+ {
+ xLayouterSet->setPropertyValue("AutomaticToolbars", Any(false));
+ }
+ }
+}
+
+PresentationViewShellBase::~PresentationViewShellBase()
+{
+}
+
+void PresentationViewShellBase::InitializeFramework()
+{
+ css::uno::Reference<css::frame::XController>
+ xController (GetController());
+ sd::framework::PresentationModule::Initialize(xController);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/SlideSorterViewShellBase.cxx b/sd/source/ui/view/SlideSorterViewShellBase.cxx
new file mode 100644
index 000000000..ecf679c98
--- /dev/null
+++ b/sd/source/ui/view/SlideSorterViewShellBase.cxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <SlideSorterViewShellBase.hxx>
+#include <DrawDocShell.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <sfx2/viewfac.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+
+namespace sd {
+
+class DrawDocShell;
+
+
+// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a
+// new SlideSorterViewShellBase object has been constructed.
+
+SfxViewFactory* SlideSorterViewShellBase::s_pFactory;
+SfxViewShell* SlideSorterViewShellBase::CreateInstance (
+ SfxViewFrame *pFrame, SfxViewShell *pOldView)
+{
+ SlideSorterViewShellBase* pBase = new SlideSorterViewShellBase(pFrame, pOldView);
+ pBase->LateInit(framework::FrameworkHelper::msSlideSorterURL);
+ return pBase;
+}
+
+void SlideSorterViewShellBase::RegisterFactory( SfxInterfaceId nPrio )
+{
+ s_pFactory = new SfxViewFactory(&CreateInstance,nPrio,"SlideSorter");
+ InitFactory();
+}
+
+void SlideSorterViewShellBase::InitFactory()
+{
+ SFX_VIEW_REGISTRATION(DrawDocShell);
+}
+
+SlideSorterViewShellBase::SlideSorterViewShellBase (
+ SfxViewFrame* _pFrame,
+ SfxViewShell* pOldShell)
+ : ImpressViewShellBase (_pFrame, pOldShell)
+{
+}
+
+SlideSorterViewShellBase::~SlideSorterViewShellBase()
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/ToolBarManager.cxx b/sd/source/ui/view/ToolBarManager.cxx
new file mode 100644
index 000000000..0bb0f9528
--- /dev/null
+++ b/sd/source/ui/view/ToolBarManager.cxx
@@ -0,0 +1,1375 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ToolBarManager.hxx>
+
+#include <DrawViewShell.hxx>
+#include <EventMultiplexer.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+#include <o3tl/deleter.hxx>
+#include <o3tl/enumrange.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/toolbarids.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/eitem.hxx>
+#include <svx/svxids.hrc>
+#include <svx/extrusionbar.hxx>
+#include <svx/fontworkbar.hxx>
+#include <tools/debug.hxx>
+#include <tools/link.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+
+#include <map>
+#include <utility>
+#include <memory>
+#include <string_view>
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+using namespace sd;
+
+class ToolBarRules;
+
+/** Lock of the frame::XLayoutManager.
+*/
+class LayouterLock
+{
+ Reference<frame::XLayoutManager> mxLayouter;
+public:
+ explicit LayouterLock (const Reference<frame::XLayoutManager>& rxLayouter);
+ ~LayouterLock();
+ bool is() const { return mxLayouter.is(); }
+};
+
+/** Store a list of tool bars for each of the tool bar groups. From
+ this the list of requested tool bars is built.
+*/
+class ToolBarList
+{
+public:
+ ToolBarList();
+
+ void ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup);
+ void AddToolBar (sd::ToolBarManager::ToolBarGroup eGroup, const OUString& rsName);
+ bool RemoveToolBar (sd::ToolBarManager::ToolBarGroup eGroup, const OUString& rsName);
+
+ void GetToolBarsToActivate (std::vector<OUString>& rToolBars) const;
+ void GetToolBarsToDeactivate (std::vector<OUString>& rToolBars) const;
+
+ void MarkToolBarAsActive (const OUString& rsName);
+ void MarkToolBarAsNotActive (const OUString& rsName);
+ void MarkAllToolBarsAsNotActive();
+
+private:
+ typedef ::std::map<sd::ToolBarManager::ToolBarGroup, std::vector<OUString> > Groups;
+ Groups maGroups;
+ std::vector<OUString> maActiveToolBars;
+
+ void MakeRequestedToolBarList (std::vector<OUString>& rToolBars) const;
+};
+
+/** Manage tool bars that are implemented as sub shells of a view shell.
+ The typical procedure of updating the sub shells of a view shell is to
+ rebuild a list of sub shells that the caller would like to have active.
+ The methods ClearGroup() and AddShellId() allow the caller to do that. A
+ final call to UpdateShells() activates the requested shells that are not
+ active and deactivates the active shells that are not requested .
+
+ This is done by maintaining two lists. One (the current list)
+ reflects the current state. The other (the requested list) contains the
+ currently requested shells. UpdateShells() makes the requested
+ list the current list and clears the current list.
+
+ Each shell belongs to one group. Different groups can be modified
+ separately.
+*/
+class ToolBarShellList
+{
+public:
+ /** Create a new object with an empty current list and an empty
+ requested list.
+ */
+ ToolBarShellList();
+
+ /** Remove all shells from a group. Calling this method should normally
+ not be necessary because after the construction or after a call to
+ UpdateShells() the requested list is empty.
+ @param eGroup
+ The group to clear. Shells in other groups are not modified.
+ */
+ void ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup);
+
+ /** Add a shell. When the specified shell has already been requested
+ for another group then it is moved to this group.
+ @param eGroup
+ The group to which to add the shell.
+ @param nId
+ The id of the shell to add.
+ */
+ void AddShellId (sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nId);
+
+ /** Releasing all shells means that the given ToolBarRules object is
+ informed that every shell managed by the called ToolBarShellList is
+ about to be removed and that the associated framework tool bars can
+ be removed as well. The caller still has to call UpdateShells().
+ */
+ void ReleaseAllShells (ToolBarRules& rRules);
+
+ /** The requested list is made the current list by activating all
+ shells in the requested list and by deactivating the shells in the
+ current list that are not in the requested list.
+ @param pMainViewShell
+ The shells that are activated or deactivated are sub shells of
+ this view shell.
+ @param rManager
+ This ViewShellManager is used to activate or deactivate shells.
+ */
+ void UpdateShells (
+ const std::shared_ptr<ViewShell>& rpMainViewShell,
+ const std::shared_ptr<ViewShellManager>& rpManager);
+
+private:
+ class ShellDescriptor
+ {public:
+ ShellDescriptor (ShellId nId,sd::ToolBarManager::ToolBarGroup eGroup);
+ ShellId mnId;
+ sd::ToolBarManager::ToolBarGroup meGroup;
+ friend bool operator<(const ShellDescriptor& r1, const ShellDescriptor& r2)
+ { return r1.mnId < r2.mnId; }
+ };
+
+ /** The requested list of tool bar shells that will be active after the
+ next call to UpdateShells().
+ */
+ typedef ::std::set<ShellDescriptor> GroupedShellList;
+ GroupedShellList maNewList;
+
+ /** The list of tool bar shells that are currently on the shell stack.
+ Using a GroupedShellList is not strictly necessary but it makes
+ things easier and does not waste too much memory.
+ */
+ GroupedShellList maCurrentList;
+};
+
+/** This class concentrates the knowledge about when to show what tool bars
+ in one place.
+*/
+class ToolBarRules
+{
+public:
+ ToolBarRules (
+ const std::shared_ptr<ToolBarManager>& rpToolBarManager,
+ const std::shared_ptr<ViewShellManager>& rpViewShellManager);
+
+ /** This method calls MainViewShellChanged() and SelectionHasChanged()
+ for the current main view shell and its view.
+ */
+ void Update (ViewShellBase const & rBase);
+
+ /** Reset all tool bars in all groups and add tool bars and tool bar
+ shells to the ToolBarGroup::Permanent group for the specified ViewShell type.
+ */
+ void MainViewShellChanged (ViewShell::ShellType nShellType);
+
+ /** Reset all tool bars in all groups and add tool bars and tool bar
+ shells to the ToolBarGroup::Permanent group for the specified ViewShell.
+ */
+ void MainViewShellChanged (const ViewShell& rMainViewShell);
+
+ /** Reset all tool bars in the ToolBarGroup::Function group and add tool bars and tool bar
+ shells to this group for the current selection.
+ */
+ void SelectionHasChanged (
+ const ::sd::ViewShell& rViewShell,
+ const SdrView& rView);
+
+ /** Add a tool bar for the specified tool bar shell.
+ */
+ void SubShellAdded (
+ ::sd::ToolBarManager::ToolBarGroup eGroup,
+ sd::ShellId nShellId);
+
+ /** Remove a tool bar for the specified tool bar shell.
+ */
+ void SubShellRemoved (
+ ::sd::ToolBarManager::ToolBarGroup eGroup,
+ sd::ShellId nShellId);
+
+private:
+ std::shared_ptr<ToolBarManager> mpToolBarManager;
+ std::shared_ptr<ViewShellManager> mpViewShellManager;
+};
+
+} // end of anonymous namespace
+
+namespace sd {
+
+//===== ToolBarManager::Implementation ========================================
+
+class ToolBarManager::Implementation
+{
+public:
+ /** This constructor takes three arguments even though the
+ ToolBarManager could be taken from the ViewShellBase. This is so to
+ state explicitly which information has to be present when this
+ constructor is called. The ViewShellBase may not have been fully
+ initialized at this point and must not be asked for this values.
+ */
+ Implementation (
+ ViewShellBase& rBase,
+ const std::shared_ptr<sd::tools::EventMultiplexer>& rpMultiplexer,
+ const std::shared_ptr<ViewShellManager>& rpViewShellManager,
+ const std::shared_ptr<ToolBarManager>& rpToolBarManager);
+ ~Implementation();
+
+ void SetValid (bool bValid);
+
+ void ResetToolBars (ToolBarGroup eGroup);
+ void ResetAllToolBars();
+ void AddToolBar (ToolBarGroup eGroup, const OUString& rsToolBarName);
+ void AddToolBarShell (ToolBarGroup eGroup, ShellId nToolBarId);
+ void RemoveToolBar (ToolBarGroup eGroup, const OUString& rsToolBarName);
+
+ /** Release all tool bar shells and the associated framework tool bars.
+ Typically called when the main view shell is being replaced by
+ another, all tool bar shells are released. In that process the
+ shells are destroyed anyway and without calling this method they
+ would still be referenced.
+ */
+ void ReleaseAllToolBarShells();
+
+ void ToolBarsDestroyed();
+
+ void RequestUpdate();
+
+ void PreUpdate();
+ void PostUpdate();
+ /** Tell the XLayoutManager about the tool bars that we would like to be
+ shown.
+ @param rpLayouterLock
+ This typically is the mpSynchronousLayouterLock that is used in
+ this method and that is either released at its end or assigned
+ to mpAsynchronousLock in order to be unlocked later.
+ */
+ void Update (::std::unique_ptr<LayouterLock> pLayouterLock);
+
+ class UpdateLockImplementation
+ {
+ public:
+ explicit UpdateLockImplementation (Implementation& rImplementation)
+ : mrImplementation(rImplementation) { mrImplementation.LockUpdate(); }
+ ~UpdateLockImplementation() { mrImplementation.UnlockUpdate(); }
+ private:
+ Implementation& mrImplementation;
+ };
+
+ void LockViewShellManager();
+ void LockUpdate();
+ void UnlockUpdate();
+
+ ToolBarRules& GetToolBarRules() { return maToolBarRules;}
+
+private:
+ mutable ::osl::Mutex maMutex;
+ ViewShellBase& mrBase;
+ std::shared_ptr<sd::tools::EventMultiplexer> mpEventMultiplexer;
+ bool mbIsValid;
+ ToolBarList maToolBarList;
+ ToolBarShellList maToolBarShellList;
+ Reference<frame::XLayoutManager> mxLayouter;
+ sal_Int32 mnLockCount;
+ bool mbPreUpdatePending;
+ bool mbPostUpdatePending;
+ /** The layouter locks manage the locking of the XLayoutManager. The
+ lock() and unlock() functions are not called directly because the
+ (final) unlocking is usually done asynchronously *after* the
+ list of requested toolbars is updated.
+ */
+ ::std::unique_ptr<LayouterLock> mpSynchronousLayouterLock;
+ ::std::unique_ptr<LayouterLock> mpAsynchronousLayouterLock;
+ ::std::unique_ptr<ViewShellManager::UpdateLock, o3tl::default_delete<ViewShellManager::UpdateLock>> mpViewShellManagerLock;
+ ImplSVEvent * mnPendingUpdateCall;
+ ImplSVEvent * mnPendingSetValidCall;
+ ToolBarRules maToolBarRules;
+
+ static OUString GetToolBarResourceName (std::u16string_view rsBaseName);
+ bool CheckPlugInMode (std::u16string_view rsName) const;
+
+ DECL_LINK(UpdateCallback, void *, void);
+ DECL_LINK(EventMultiplexerCallback, sd::tools::EventMultiplexerEvent&, void);
+ DECL_LINK(SetValidCallback, void*, void);
+};
+
+//===== ToolBarManager ========================================================
+
+std::shared_ptr<ToolBarManager> ToolBarManager::Create (
+ ViewShellBase& rBase,
+ const std::shared_ptr<sd::tools::EventMultiplexer>& rpMultiplexer,
+ const std::shared_ptr<ViewShellManager>& rpViewShellManager)
+{
+ std::shared_ptr<ToolBarManager> pManager (new ToolBarManager());
+ pManager->mpImpl.reset(
+ new Implementation(rBase,rpMultiplexer,rpViewShellManager,pManager));
+ return pManager;
+}
+
+ToolBarManager::ToolBarManager()
+{
+}
+
+ToolBarManager::~ToolBarManager()
+{
+}
+
+void ToolBarManager::Shutdown()
+{
+ if (mpImpl != nullptr)
+ mpImpl.reset();
+}
+
+void ToolBarManager::ResetToolBars (ToolBarGroup eGroup)
+{
+ if (mpImpl != nullptr)
+ {
+ UpdateLock aLock (shared_from_this());
+ mpImpl->ResetToolBars(eGroup);
+ }
+}
+
+void ToolBarManager::ResetAllToolBars()
+{
+ if (mpImpl != nullptr)
+ {
+ UpdateLock aLock (shared_from_this());
+ mpImpl->ResetAllToolBars();
+ }
+}
+
+void ToolBarManager::AddToolBar (
+ ToolBarGroup eGroup,
+ const OUString& rsToolBarName)
+{
+ if (mpImpl != nullptr)
+ {
+ UpdateLock aLock (shared_from_this());
+ mpImpl->AddToolBar(eGroup,rsToolBarName);
+ }
+}
+
+void ToolBarManager::AddToolBarShell (
+ ToolBarGroup eGroup,
+ ShellId nToolBarId)
+{
+ if (mpImpl != nullptr)
+ {
+ UpdateLock aLock (shared_from_this());
+ mpImpl->AddToolBarShell(eGroup,nToolBarId);
+ }
+}
+
+void ToolBarManager::RemoveToolBar (
+ ToolBarGroup eGroup,
+ const OUString& rsToolBarName)
+{
+ if (mpImpl != nullptr)
+ {
+ UpdateLock aLock (shared_from_this());
+ mpImpl->RemoveToolBar(eGroup,rsToolBarName);
+ }
+}
+
+void ToolBarManager::SetToolBar (
+ ToolBarGroup eGroup,
+ const OUString& rsToolBarName)
+{
+ if (mpImpl != nullptr)
+ {
+ UpdateLock aLock (shared_from_this());
+ mpImpl->ResetToolBars(eGroup);
+ mpImpl->AddToolBar(eGroup,rsToolBarName);
+ }
+}
+
+void ToolBarManager::SetToolBarShell (
+ ToolBarGroup eGroup,
+ ShellId nToolBarId)
+{
+ if (mpImpl != nullptr)
+ {
+ UpdateLock aLock (shared_from_this());
+ mpImpl->ResetToolBars(eGroup);
+ mpImpl->AddToolBarShell(eGroup,nToolBarId);
+ }
+}
+
+void ToolBarManager::PreUpdate()
+{
+ if (mpImpl != nullptr)
+ mpImpl->PreUpdate();
+}
+
+void ToolBarManager::RequestUpdate()
+{
+ if (mpImpl != nullptr)
+ mpImpl->RequestUpdate();
+}
+
+void ToolBarManager::LockViewShellManager()
+{
+ if (mpImpl != nullptr)
+ mpImpl->LockViewShellManager();
+}
+
+void ToolBarManager::LockUpdate()
+{
+ if (mpImpl != nullptr)
+ mpImpl->LockUpdate();
+}
+
+void ToolBarManager::UnlockUpdate()
+{
+ if (mpImpl != nullptr)
+ mpImpl->UnlockUpdate();
+}
+
+void ToolBarManager::MainViewShellChanged ()
+{
+ if (mpImpl != nullptr)
+ {
+ mpImpl->ReleaseAllToolBarShells();
+ mpImpl->GetToolBarRules().MainViewShellChanged(ViewShell::ST_NONE);
+ }
+}
+
+void ToolBarManager::MainViewShellChanged (const ViewShell& rMainViewShell)
+{
+ if (mpImpl != nullptr)
+ {
+ mpImpl->ReleaseAllToolBarShells();
+ mpImpl->GetToolBarRules().MainViewShellChanged(rMainViewShell);
+ }
+}
+
+void ToolBarManager::SelectionHasChanged (
+ const ViewShell& rViewShell,
+ const SdrView& rView)
+{
+ if (mpImpl != nullptr)
+ mpImpl->GetToolBarRules().SelectionHasChanged(rViewShell,rView);
+}
+
+void ToolBarManager::ToolBarsDestroyed()
+{
+ if (mpImpl != nullptr)
+ mpImpl->ToolBarsDestroyed();
+}
+
+//===== ToolBarManager::Implementation =======================================
+
+ToolBarManager::Implementation::Implementation (
+ ViewShellBase& rBase,
+ const std::shared_ptr<sd::tools::EventMultiplexer>& rpMultiplexer,
+ const std::shared_ptr<ViewShellManager>& rpViewShellManager,
+ const std::shared_ptr<ToolBarManager>& rpToolBarManager)
+ : mrBase(rBase),
+ mpEventMultiplexer(rpMultiplexer),
+ mbIsValid(false),
+ mnLockCount(0),
+ mbPreUpdatePending(false),
+ mbPostUpdatePending(false),
+ mnPendingUpdateCall(nullptr),
+ mnPendingSetValidCall(nullptr),
+ maToolBarRules(rpToolBarManager,rpViewShellManager)
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this,ToolBarManager::Implementation,EventMultiplexerCallback));
+ mpEventMultiplexer->AddEventListener( aLink );
+}
+
+/** The order of statements is important.
+ First unregister listeners, which may post user events.
+ Then remove pending user events.
+*/
+ToolBarManager::Implementation::~Implementation()
+{
+ // Unregister at broadcasters.
+ Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this,ToolBarManager::Implementation,EventMultiplexerCallback));
+ mpEventMultiplexer->RemoveEventListener(aLink);
+
+ // Abort pending user calls.
+ if (mnPendingUpdateCall != nullptr)
+ Application::RemoveUserEvent(mnPendingUpdateCall);
+ if (mnPendingSetValidCall != nullptr)
+ Application::RemoveUserEvent(mnPendingSetValidCall);
+}
+
+void ToolBarManager::Implementation::ToolBarsDestroyed()
+{
+ maToolBarList.MarkAllToolBarsAsNotActive();
+}
+
+void ToolBarManager::Implementation::SetValid (bool bValid)
+{
+ ::osl::MutexGuard aGuard(maMutex);
+
+ if (mbIsValid == bValid)
+ return;
+
+ UpdateLockImplementation aUpdateLock (*this);
+
+ mbIsValid = bValid;
+ if (mbIsValid)
+ {
+ Reference<frame::XFrame> xFrame;
+ if (mrBase.GetViewFrame() != nullptr)
+ xFrame = mrBase.GetViewFrame()->GetFrame().GetFrameInterface();
+ try
+ {
+ Reference<beans::XPropertySet> xFrameProperties (xFrame, UNO_QUERY_THROW);
+ Any aValue (xFrameProperties->getPropertyValue("LayoutManager"));
+ aValue >>= mxLayouter;
+ // tdf#119997 if mpSynchronousLayouterLock was created before mxLayouter was
+ // set then update it now that its available
+ if (mpSynchronousLayouterLock && !mpSynchronousLayouterLock->is())
+ mpSynchronousLayouterLock.reset(new LayouterLock(mxLayouter));
+ }
+ catch (const RuntimeException&)
+ {
+ }
+
+ GetToolBarRules().Update(mrBase);
+ }
+ else
+ {
+ ResetAllToolBars();
+ mxLayouter = nullptr;
+ }
+}
+
+void ToolBarManager::Implementation::ResetToolBars (ToolBarGroup eGroup)
+{
+ ::osl::MutexGuard aGuard(maMutex);
+
+ maToolBarList.ClearGroup(eGroup);
+ maToolBarShellList.ClearGroup(eGroup);
+
+ mbPreUpdatePending = true;
+}
+
+void ToolBarManager::Implementation::ResetAllToolBars()
+{
+ SAL_INFO("sd.view", __func__ << ": resetting all tool bars");
+ for (auto i : o3tl::enumrange<ToolBarGroup>())
+ ResetToolBars(i);
+}
+
+void ToolBarManager::Implementation::AddToolBar (
+ ToolBarGroup eGroup,
+ const OUString& rsToolBarName)
+{
+ ::osl::MutexGuard aGuard(maMutex);
+
+ if (CheckPlugInMode(rsToolBarName))
+ {
+ maToolBarList.AddToolBar(eGroup,rsToolBarName);
+
+ mbPostUpdatePending = true;
+ if (mnLockCount == 0)
+ PostUpdate();
+ }
+}
+
+void ToolBarManager::Implementation::RemoveToolBar (
+ ToolBarGroup eGroup,
+ const OUString& rsToolBarName)
+{
+ ::osl::MutexGuard aGuard(maMutex);
+
+ if (maToolBarList.RemoveToolBar(eGroup,rsToolBarName))
+ {
+ mbPreUpdatePending = true;
+ if (mnLockCount == 0)
+ PreUpdate();
+ }
+}
+
+void ToolBarManager::Implementation::AddToolBarShell (
+ ToolBarGroup eGroup,
+ ShellId nToolBarId)
+{
+ ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
+ if (pMainViewShell != nullptr)
+ {
+ maToolBarShellList.AddShellId(eGroup,nToolBarId);
+ GetToolBarRules().SubShellAdded(eGroup, nToolBarId);
+ }
+}
+
+void ToolBarManager::Implementation::ReleaseAllToolBarShells()
+{
+ maToolBarShellList.ReleaseAllShells(GetToolBarRules());
+ maToolBarShellList.UpdateShells(mrBase.GetMainViewShell(), mrBase.GetViewShellManager());
+}
+
+void ToolBarManager::Implementation::RequestUpdate()
+{
+ if (mnPendingUpdateCall == nullptr)
+ {
+ mnPendingUpdateCall = Application::PostUserEvent(
+ LINK(this,ToolBarManager::Implementation,UpdateCallback));
+ }
+}
+
+void ToolBarManager::Implementation::PreUpdate()
+{
+ ::osl::MutexGuard aGuard(maMutex);
+
+ if (!(mbIsValid
+ && mbPreUpdatePending
+ && mxLayouter.is()))
+ return;
+
+ mbPreUpdatePending = false;
+
+ SAL_INFO("sd.view", __func__ << ": ToolBarManager::PreUpdate [");
+
+ // Get the list of tool bars that are not used anymore and are to be
+ // deactivated.
+ std::vector<OUString> aToolBars;
+ maToolBarList.GetToolBarsToDeactivate(aToolBars);
+
+ // Turn off the tool bars.
+ for (const auto& aToolBar : aToolBars)
+ {
+ OUString sFullName (GetToolBarResourceName(aToolBar));
+ SAL_INFO("sd.view", __func__ << ": turning off tool bar " << sFullName);
+ mxLayouter->destroyElement(sFullName);
+ maToolBarList.MarkToolBarAsNotActive(aToolBar);
+ }
+
+ SAL_INFO("sd.view", __func__ << ": ToolBarManager::PreUpdate ]");
+}
+
+void ToolBarManager::Implementation::PostUpdate()
+{
+ ::osl::MutexGuard aGuard(maMutex);
+
+ if (!(mbIsValid
+ && mbPostUpdatePending
+ && mxLayouter.is()))
+ return;
+
+ mbPostUpdatePending = false;
+
+ // Create the list of requested tool bars.
+ std::vector<OUString> aToolBars;
+ maToolBarList.GetToolBarsToActivate(aToolBars);
+
+ SAL_INFO("sd.view", __func__ << ": ToolBarManager::PostUpdate [");
+
+ // Turn on the tool bars that are visible in the new context.
+ for (const auto& aToolBar : aToolBars)
+ {
+ OUString sFullName (GetToolBarResourceName(aToolBar));
+ SAL_INFO("sd.view", __func__ << ": turning on tool bar " << sFullName);
+ mxLayouter->requestElement(sFullName);
+ maToolBarList.MarkToolBarAsActive(aToolBar);
+ }
+
+ SAL_INFO("sd.view", __func__ << ": ToolBarManager::PostUpdate ]");
+}
+
+void ToolBarManager::Implementation::LockViewShellManager()
+{
+ if (mpViewShellManagerLock == nullptr)
+ mpViewShellManagerLock.reset(
+ new ViewShellManager::UpdateLock(mrBase.GetViewShellManager()));
+}
+
+void ToolBarManager::Implementation::LockUpdate()
+{
+ SAL_INFO("sd.view", __func__ << ": LockUpdate " << mnLockCount);
+ ::osl::MutexGuard aGuard(maMutex);
+
+ DBG_ASSERT(mnLockCount<100, "ToolBarManager lock count unusually high");
+ if (mnLockCount == 0)
+ {
+ OSL_ASSERT(mpSynchronousLayouterLock == nullptr);
+
+ mpSynchronousLayouterLock.reset(new LayouterLock(mxLayouter));
+ }
+ ++mnLockCount;
+}
+
+void ToolBarManager::Implementation::UnlockUpdate()
+{
+ SAL_INFO("sd.view", __func__ << ": UnlockUpdate " << mnLockCount);
+ ::osl::MutexGuard aGuard(maMutex);
+
+ OSL_ASSERT(mnLockCount>0);
+ --mnLockCount;
+ if (mnLockCount == 0)
+ {
+ Update(std::move(mpSynchronousLayouterLock));
+ }
+}
+
+void ToolBarManager::Implementation::Update (
+ ::std::unique_ptr<LayouterLock> pLocalLayouterLock)
+{
+ // When the lock is released and there are pending changes to the set of
+ // tool bars then update this set now.
+ if (mnLockCount != 0)
+ return;
+
+ // During creation of ViewShellBase we may have the situation that
+ // the controller has already been created and attached to the frame
+ // but that the ToolBarManager has not yet completed its
+ // initialization (by initializing the mxLayouter member.) We do
+ // this here so that we do not have to wait for the next Update()
+ // call to show the tool bars.
+ if (mnPendingSetValidCall != nullptr)
+ {
+ Application::RemoveUserEvent(mnPendingSetValidCall);
+ mnPendingSetValidCall = nullptr;
+ SetValid(true);
+ }
+
+ if (mbIsValid && mxLayouter.is() && (mbPreUpdatePending || mbPostUpdatePending))
+ {
+ // 1) Release UNO tool bars that are no longer used. Do this
+ // now so that they are not updated when the SFX shell stack is
+ // modified.
+ if (mbPreUpdatePending)
+ PreUpdate();
+
+ // 2) Update the requested shells that represent tool bar
+ // functionality. Those that are not used anymore are
+ // deactivated now. Those that are missing are activated in the
+ // next step together with the view shells.
+ if (mpViewShellManagerLock == nullptr)
+ mpViewShellManagerLock.reset(
+ new ViewShellManager::UpdateLock(mrBase.GetViewShellManager()));
+ maToolBarShellList.UpdateShells(
+ mrBase.GetMainViewShell(),
+ mrBase.GetViewShellManager());
+
+ // 3) Unlock the ViewShellManager::UpdateLock. This updates the
+ // shell stack.
+ mpViewShellManagerLock.reset();
+
+ // 4) Make the UNO tool bars visible. The outstanding call to
+ // PostUpdate() is done via PostUserEvent() so that it is
+ // guaranteed to be executed when the SFX shell stack has been
+ // updated (under the assumption that our lock to the
+ // ViewShellManager was the only one open. If that is not the
+ // case then all should still be well but not as fast.)
+
+ // Note that the lock count may have been increased since
+ // entering this method. In that case one of the next
+ // UnlockUpdate() calls will post the UpdateCallback.
+ if (mnLockCount==0)
+ {
+ mpAsynchronousLayouterLock = std::move(pLocalLayouterLock);
+ if (mnPendingUpdateCall==nullptr)
+ {
+ mnPendingUpdateCall = Application::PostUserEvent(
+ LINK(this,ToolBarManager::Implementation,UpdateCallback));
+ }
+ }
+ }
+ else
+ {
+ mpViewShellManagerLock.reset();
+ pLocalLayouterLock.reset();
+ }
+}
+
+IMPL_LINK_NOARG(ToolBarManager::Implementation, UpdateCallback, void*, void)
+{
+ mnPendingUpdateCall = nullptr;
+ if (mnLockCount == 0)
+ {
+ if (mbPreUpdatePending)
+ PreUpdate();
+ if (mbPostUpdatePending)
+ PostUpdate();
+ if (mbIsValid && mxLayouter.is())
+ mpAsynchronousLayouterLock.reset();
+ }
+}
+
+IMPL_LINK(ToolBarManager::Implementation,EventMultiplexerCallback,
+ sd::tools::EventMultiplexerEvent&, rEvent, void)
+{
+ SolarMutexGuard g;
+ switch (rEvent.meEventId)
+ {
+ case EventMultiplexerEventId::ControllerAttached:
+ if (mnPendingSetValidCall == nullptr)
+ mnPendingSetValidCall
+ = Application::PostUserEvent(LINK(this,Implementation,SetValidCallback));
+ break;
+
+ case EventMultiplexerEventId::ControllerDetached:
+ SetValid(false);
+ break;
+
+ default: break;
+ }
+}
+
+IMPL_LINK_NOARG(ToolBarManager::Implementation, SetValidCallback, void*, void)
+{
+ mnPendingSetValidCall = nullptr;
+ SetValid(true);
+}
+
+OUString ToolBarManager::Implementation::GetToolBarResourceName (
+ std::u16string_view rsBaseName)
+{
+ return OUString::Concat("private:resource/toolbar/") + rsBaseName;
+}
+
+bool ToolBarManager::Implementation::CheckPlugInMode (std::u16string_view rsName) const
+{
+ bool bValid (false);
+
+ // Determine the plug in mode.
+ bool bIsPlugInMode (false);
+ do
+ {
+ SfxObjectShell* pObjectShell = mrBase.GetObjectShell();
+ if (pObjectShell == nullptr)
+ break;
+
+ SfxMedium* pMedium = pObjectShell->GetMedium();
+ if (pMedium == nullptr)
+ break;
+
+ const SfxBoolItem* pViewOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_VIEWONLY, false);
+ if (pViewOnlyItem == nullptr)
+ break;
+
+ bIsPlugInMode = pViewOnlyItem->GetValue();
+ }
+ while (false);
+
+ if (rsName == msViewerToolBar)
+ bValid = bIsPlugInMode;
+ else
+ bValid = ! bIsPlugInMode;
+
+ return bValid;
+}
+
+} // end of namespace sd
+
+namespace {
+
+using namespace ::sd;
+
+//===== LayouterLock ==========================================================
+
+LayouterLock::LayouterLock (const Reference<frame::XLayoutManager>& rxLayouter)
+ : mxLayouter(rxLayouter)
+{
+ SAL_INFO("sd.view", __func__ << ": LayouterLock " << (mxLayouter.is() ? 1 :0));
+ if (mxLayouter.is())
+ mxLayouter->lock();
+}
+
+LayouterLock::~LayouterLock()
+{
+ SAL_INFO("sd.view", __func__ << ": ~LayouterLock " << (mxLayouter.is() ? 1 :0));
+ if (mxLayouter.is())
+ mxLayouter->unlock();
+}
+
+//===== ToolBarRules ==========================================================
+
+ToolBarRules::ToolBarRules (
+ const std::shared_ptr<sd::ToolBarManager>& rpToolBarManager,
+ const std::shared_ptr<sd::ViewShellManager>& rpViewShellManager)
+ : mpToolBarManager(rpToolBarManager),
+ mpViewShellManager(rpViewShellManager)
+{
+}
+
+void ToolBarRules::Update (ViewShellBase const & rBase)
+{
+ ViewShell* pMainViewShell = rBase.GetMainViewShell().get();
+ if (pMainViewShell != nullptr)
+ {
+ MainViewShellChanged(pMainViewShell->GetShellType());
+ if (pMainViewShell->GetView())
+ SelectionHasChanged (*pMainViewShell, *pMainViewShell->GetView());
+ }
+ else
+ MainViewShellChanged(ViewShell::ST_NONE);
+}
+
+void ToolBarRules::MainViewShellChanged (ViewShell::ShellType nShellType)
+{
+ ::sd::ToolBarManager::UpdateLock aToolBarManagerLock (mpToolBarManager);
+ ::sd::ViewShellManager::UpdateLock aViewShellManagerLock (mpViewShellManager);
+
+ mpToolBarManager->ResetAllToolBars();
+
+ switch(nShellType)
+ {
+ case ::sd::ViewShell::ST_IMPRESS:
+ case ::sd::ViewShell::ST_NOTES:
+ case ::sd::ViewShell::ST_HANDOUT:
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msToolBar);
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msOptionsToolBar);
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msViewerToolBar);
+ break;
+
+ case ::sd::ViewShell::ST_DRAW:
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msToolBar);
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msOptionsToolBar);
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msViewerToolBar);
+ break;
+
+ case ViewShell::ST_OUTLINE:
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msOutlineToolBar);
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msViewerToolBar);
+ mpToolBarManager->AddToolBarShell(
+ ToolBarManager::ToolBarGroup::Permanent, ToolbarId::Draw_Text_Toolbox_Sd);
+ break;
+
+ case ViewShell::ST_SLIDE_SORTER:
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msViewerToolBar);
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msSlideSorterToolBar);
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::Permanent,
+ ToolBarManager::msSlideSorterObjectBar);
+ break;
+
+ case ViewShell::ST_NONE:
+ case ViewShell::ST_PRESENTATION:
+ case ViewShell::ST_SIDEBAR:
+ default:
+ break;
+ }
+}
+
+void ToolBarRules::MainViewShellChanged (const ViewShell& rMainViewShell)
+{
+ ::sd::ToolBarManager::UpdateLock aToolBarManagerLock (mpToolBarManager);
+ ::sd::ViewShellManager::UpdateLock aViewShellManagerLock (mpViewShellManager);
+
+ MainViewShellChanged(rMainViewShell.GetShellType());
+ switch(rMainViewShell.GetShellType())
+ {
+ case ::sd::ViewShell::ST_IMPRESS:
+ case ::sd::ViewShell::ST_DRAW:
+ case ::sd::ViewShell::ST_NOTES:
+ {
+ const DrawViewShell* pDrawViewShell
+ = dynamic_cast<const DrawViewShell*>(&rMainViewShell);
+ if (pDrawViewShell != nullptr)
+ {
+ if (pDrawViewShell->GetEditMode() == EditMode::MasterPage)
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::MasterMode,
+ ToolBarManager::msMasterViewToolBar);
+ else if ( rMainViewShell.GetShellType() != ::sd::ViewShell::ST_DRAW )
+ mpToolBarManager->AddToolBar(
+ ToolBarManager::ToolBarGroup::CommonTask,
+ ToolBarManager::msCommonTaskToolBar);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void ToolBarRules::SelectionHasChanged (
+ const ::sd::ViewShell& rViewShell,
+ const SdrView& rView)
+{
+ ::sd::ToolBarManager::UpdateLock aLock (mpToolBarManager);
+ mpToolBarManager->LockViewShellManager();
+ bool bTextEdit = rView.IsTextEdit();
+
+ mpToolBarManager->ResetToolBars(ToolBarManager::ToolBarGroup::Function);
+
+ switch (rView.GetContext())
+ {
+ case SdrViewContext::Graphic:
+ if( !bTextEdit )
+ mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Graf_Toolbox);
+ break;
+
+ case SdrViewContext::Media:
+ if( !bTextEdit )
+ mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Media_Toolbox);
+ break;
+
+ case SdrViewContext::Table:
+ mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Table_Toolbox);
+ bTextEdit = true;
+ break;
+
+ case SdrViewContext::Standard:
+ default:
+ if( !bTextEdit )
+ {
+ switch(rViewShell.GetShellType())
+ {
+ case ::sd::ViewShell::ST_IMPRESS:
+ case ::sd::ViewShell::ST_DRAW:
+ case ::sd::ViewShell::ST_NOTES:
+ case ::sd::ViewShell::ST_HANDOUT:
+ mpToolBarManager->SetToolBar(
+ ToolBarManager::ToolBarGroup::Function,
+ ToolBarManager::msDrawingObjectToolBar);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ if( bTextEdit )
+ mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Text_Toolbox_Sd);
+
+ SdrView* pView = &const_cast<SdrView&>(rView);
+ // Check if the extrusion tool bar and the fontwork tool bar have to
+ // be activated.
+ if (svx::checkForSelectedCustomShapes(pView, true /* bOnlyExtruded */ ))
+ mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Svx_Extrusion_Bar);
+
+ if (svx::checkForSelectedFontWork(pView))
+ mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Svx_Fontwork_Bar);
+
+ // Switch on additional context-sensitive tool bars.
+ if (rView.GetContext() == SdrViewContext::PointEdit)
+ mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Bezier_Toolbox_Sd);
+}
+
+void ToolBarRules::SubShellAdded (
+ ::sd::ToolBarManager::ToolBarGroup eGroup,
+ sd::ShellId nShellId)
+{
+ // For some tool bar shells (those defined in sd) we have to add the
+ // actual tool bar here.
+ switch (nShellId)
+ {
+ case ToolbarId::Draw_Graf_Toolbox:
+ mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msGraphicObjectBar);
+ break;
+
+ case ToolbarId::Draw_Media_Toolbox:
+ mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msMediaObjectBar);
+ break;
+
+ case ToolbarId::Draw_Text_Toolbox_Sd:
+ mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msTextObjectBar);
+ break;
+
+ case ToolbarId::Bezier_Toolbox_Sd:
+ mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msBezierObjectBar);
+ break;
+
+ case ToolbarId::Draw_Table_Toolbox:
+ mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msTableObjectBar);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void ToolBarRules::SubShellRemoved (
+ ::sd::ToolBarManager::ToolBarGroup eGroup,
+ sd::ShellId nShellId)
+{
+ // For some tool bar shells (those defined in sd) we have to add the
+ // actual tool bar here.
+ switch (nShellId)
+ {
+ case ToolbarId::Draw_Graf_Toolbox:
+ mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msGraphicObjectBar);
+ break;
+
+ case ToolbarId::Draw_Media_Toolbox:
+ mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msMediaObjectBar);
+ break;
+
+ case ToolbarId::Draw_Text_Toolbox_Sd:
+ mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msTextObjectBar);
+ break;
+
+ case ToolbarId::Bezier_Toolbox_Sd:
+ mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msBezierObjectBar);
+ break;
+
+ case ToolbarId::Draw_Table_Toolbox:
+ mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msTableObjectBar);
+ break;
+
+ default:
+ break;
+ }
+}
+
+//===== ToolBarList ===========================================================
+
+ToolBarList::ToolBarList()
+{
+}
+
+void ToolBarList::ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup)
+{
+ Groups::iterator iGroup (maGroups.find(eGroup));
+ if (iGroup != maGroups.end())
+ {
+ iGroup->second.clear();
+ }
+}
+
+void ToolBarList::AddToolBar (
+ sd::ToolBarManager::ToolBarGroup eGroup,
+ const OUString& rsName)
+{
+ Groups::iterator iGroup (maGroups.find(eGroup));
+ if (iGroup == maGroups.end())
+ iGroup = maGroups.emplace(eGroup,std::vector<OUString>()).first;
+
+ if (iGroup != maGroups.end())
+ {
+ auto iBar (std::find(iGroup->second.cbegin(),iGroup->second.cend(),rsName));
+ if (iBar == iGroup->second.cend())
+ {
+ iGroup->second.push_back(rsName);
+ }
+ }
+}
+
+bool ToolBarList::RemoveToolBar (
+ sd::ToolBarManager::ToolBarGroup eGroup,
+ const OUString& rsName)
+{
+ Groups::iterator iGroup (maGroups.find(eGroup));
+ if (iGroup != maGroups.end())
+ {
+ auto iBar (std::find(iGroup->second.begin(),iGroup->second.end(),rsName));
+ if (iBar != iGroup->second.end())
+ {
+ iGroup->second.erase(iBar);
+ return true;
+ }
+ }
+ return false;
+}
+
+void ToolBarList::MakeRequestedToolBarList (std::vector<OUString>& rRequestedToolBars) const
+{
+ for (auto eGroup : o3tl::enumrange<sd::ToolBarManager::ToolBarGroup>())
+ {
+ Groups::const_iterator iGroup (maGroups.find(eGroup));
+ if (iGroup != maGroups.end())
+ rRequestedToolBars.insert( rRequestedToolBars.end(),
+ iGroup->second.begin(),
+ iGroup->second.end() );
+ }
+}
+
+void ToolBarList::GetToolBarsToActivate (std::vector<OUString>& rToolBars) const
+{
+ std::vector<OUString> aRequestedToolBars;
+ MakeRequestedToolBarList(aRequestedToolBars);
+
+ for (const auto& aToolBar : aRequestedToolBars)
+ {
+ if (::std::find(maActiveToolBars.begin(),maActiveToolBars.end(),aToolBar)
+ == maActiveToolBars.end())
+ {
+ rToolBars.push_back(aToolBar);
+ }
+ }
+}
+
+void ToolBarList::GetToolBarsToDeactivate (std::vector<OUString>& rToolBars) const
+{
+ std::vector<OUString> aRequestedToolBars;
+ MakeRequestedToolBarList(aRequestedToolBars);
+
+ for (auto& aToolBar : maActiveToolBars)
+ {
+ if (::std::find(aRequestedToolBars.begin(),aRequestedToolBars.end(),aToolBar)
+ == aRequestedToolBars.end())
+ {
+ rToolBars.push_back(aToolBar);
+ }
+ }
+}
+
+void ToolBarList::MarkToolBarAsActive (const OUString& rsName)
+{
+ maActiveToolBars.push_back(rsName);
+}
+
+void ToolBarList::MarkToolBarAsNotActive (const OUString& rsName)
+{
+ maActiveToolBars.erase(
+ ::std::find(maActiveToolBars.begin(),maActiveToolBars.end(), rsName));
+}
+
+void ToolBarList::MarkAllToolBarsAsNotActive()
+{
+ maActiveToolBars.clear();
+}
+
+//===== ToolBarShellList ======================================================
+
+ToolBarShellList::ShellDescriptor::ShellDescriptor (
+ ShellId nId,
+ sd::ToolBarManager::ToolBarGroup eGroup)
+ : mnId(nId),
+ meGroup(eGroup)
+{
+}
+
+ToolBarShellList::ToolBarShellList()
+{
+}
+
+void ToolBarShellList::ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup)
+{
+ for (GroupedShellList::iterator iDescriptor = maNewList.begin(); iDescriptor != maNewList.end(); )
+ if (iDescriptor->meGroup == eGroup)
+ iDescriptor = maNewList.erase(iDescriptor);
+ else
+ ++iDescriptor;
+}
+
+void ToolBarShellList::AddShellId (sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nId)
+{
+ // Make sure that the shell is not added twice (and possibly in
+ // different groups.)
+ ShellDescriptor aDescriptor (nId,eGroup);
+ GroupedShellList::iterator iDescriptor (maNewList.find(aDescriptor));
+ if (iDescriptor != maNewList.end())
+ {
+ // The shell is already requested.
+ if (iDescriptor->meGroup != eGroup)
+ {
+ // It is now being requested for another group.
+ // (Is this an error?)
+ // Move it to that group.
+ maNewList.erase(iDescriptor);
+ maNewList.insert(aDescriptor);
+ }
+ // else nothing to do.
+ }
+ else
+ maNewList.insert(aDescriptor);
+}
+
+void ToolBarShellList::ReleaseAllShells (ToolBarRules& rRules)
+{
+ // Release the currently active tool bars.
+ GroupedShellList aList (maCurrentList);
+ for (const auto& rDescriptor : aList)
+ {
+ rRules.SubShellRemoved(rDescriptor.meGroup, rDescriptor.mnId);
+ }
+
+ // Clear the list of requested tool bars.
+ maNewList.clear();
+}
+
+void ToolBarShellList::UpdateShells (
+ const std::shared_ptr<ViewShell>& rpMainViewShell,
+ const std::shared_ptr<ViewShellManager>& rpManager)
+{
+ if (rpMainViewShell == nullptr)
+ return;
+
+ GroupedShellList aList;
+
+ // Deactivate shells that are in maCurrentList, but not in
+ // maNewList.
+ ::std::set_difference(maCurrentList.begin(), maCurrentList.end(),
+ maNewList.begin(), maNewList.end(),
+ std::insert_iterator<GroupedShellList>(aList,aList.begin()));
+ for (const auto& rShell : aList)
+ {
+ SAL_INFO("sd.view", __func__ << ": deactivating tool bar shell " << static_cast<sal_uInt32>(rShell.mnId));
+ rpManager->DeactivateSubShell(*rpMainViewShell, rShell.mnId);
+ }
+
+ // Activate shells that are in maNewList, but not in
+ // maCurrentList.
+ aList.clear();
+ ::std::set_difference(maNewList.begin(), maNewList.end(),
+ maCurrentList.begin(), maCurrentList.end(),
+ std::insert_iterator<GroupedShellList>(aList,aList.begin()));
+ for (const auto& rShell : aList)
+ {
+ SAL_INFO("sd.view", __func__ << ": activating tool bar shell " << static_cast<sal_uInt32>(rShell.mnId));
+ rpManager->ActivateSubShell(*rpMainViewShell, rShell.mnId);
+ }
+
+ // The maNewList now reflects the current state and thus is made
+ // maCurrentList.
+ maCurrentList = maNewList;
+}
+
+} // end of anonymous namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/ViewClipboard.cxx b/sd/source/ui/view/ViewClipboard.cxx
new file mode 100644
index 000000000..c17bf7de1
--- /dev/null
+++ b/sd/source/ui/view/ViewClipboard.cxx
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ViewClipboard.hxx>
+
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <View.hxx>
+#include <ViewShell.hxx>
+#include <Window.hxx>
+
+#include <drawdoc.hxx>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+#include <sdxfer.hxx>
+#include <strings.hxx>
+
+#include <svx/svdpagv.hxx>
+#include <vcl/svapp.hxx>
+
+namespace sd {
+
+ViewClipboard::ViewClipboard (::sd::View& rView)
+ : mrView(rView)
+{
+}
+
+ViewClipboard::~ViewClipboard()
+{
+}
+
+void ViewClipboard::HandlePageDrop (const SdTransferable& rTransferable)
+{
+ // Determine whether to insert the given set of slides or to assign a
+ // given master page.
+ // tdf#113405 only assign master pages to normal pages, don't attempt to assign a master
+ // page to a master page
+ sd::DrawViewShell* pDrawViewShell = dynamic_cast<::sd::DrawViewShell*>(mrView.GetViewShell());
+ SdPage* pMasterPage = (pDrawViewShell && pDrawViewShell->GetEditMode() == EditMode::Page) ? GetFirstMasterPage(rTransferable) : nullptr;
+ if (pMasterPage)
+ AssignMasterPage (rTransferable, pMasterPage);
+ else
+ InsertSlides (rTransferable, DetermineInsertPosition ());
+}
+
+SdPage* ViewClipboard::GetFirstMasterPage (const SdTransferable& rTransferable)
+{
+ SdPage* pFirstMasterPage = nullptr;
+
+ if (rTransferable.HasPageBookmarks())
+ {
+ do
+ {
+ const std::vector<OUString> &rBookmarks = rTransferable.GetPageBookmarks();
+
+ if (rBookmarks.empty())
+ break;
+
+ DrawDocShell* pDocShell = rTransferable.GetPageDocShell();
+ if (pDocShell == nullptr)
+ break;
+
+ SdDrawDocument* pDocument = pDocShell->GetDoc();
+ if (pDocument == nullptr)
+ break;
+
+ for (const OUString& sName : rBookmarks)
+ {
+ bool bIsMasterPage;
+
+ // SdPage* GetMasterSdPage(sal_uInt16 nPgNum, PageKind ePgKind);
+ // sal_uInt16 GetMasterSdPageCount(PageKind ePgKind) const;
+
+ sal_uInt16 nBMPage = pDocument->GetPageByName (
+ sName, bIsMasterPage);
+ if ( ! bIsMasterPage)
+ {
+ // At least one regular slide: return NULL to indicate
+ // that not all bookmarks point to master pages.
+ pFirstMasterPage = nullptr;
+ break;
+ }
+ else if (pFirstMasterPage == nullptr)
+ {
+ // Remember the first master page for later.
+ if (nBMPage != SDRPAGE_NOTFOUND)
+ pFirstMasterPage = static_cast<SdPage*>(
+ pDocument->GetMasterPage(nBMPage));
+ }
+ }
+ }
+ while (false);
+ }
+
+ return pFirstMasterPage;
+}
+
+void ViewClipboard::AssignMasterPage (
+ const SdTransferable& rTransferable,
+ SdPage const * pMasterPage)
+{
+ if (pMasterPage == nullptr)
+ return;
+
+ // Get the target page to which the master page is assigned.
+ SdrPageView* pPageView = mrView.GetSdrPageView();
+ if (pPageView == nullptr)
+ return;
+
+ SdPage* pPage = static_cast<SdPage*>(pPageView->GetPage());
+ if (pPage == nullptr)
+ return;
+
+ SdDrawDocument& rDocument = mrView.GetDoc();
+
+ if ( ! rTransferable.HasPageBookmarks())
+ return;
+
+ DrawDocShell* pDataDocShell = rTransferable.GetPageDocShell();
+ if (pDataDocShell == nullptr)
+ return;
+
+ SdDrawDocument* pSourceDocument = pDataDocShell->GetDoc();
+ if (pSourceDocument == nullptr)
+ return;
+
+ // We have to remove the layout suffix from the layout name which is
+ // appended again by SetMasterPage() to the given name. Don't ask.
+ OUString sLayoutSuffix = SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE;
+ sal_Int32 nLength = sLayoutSuffix.getLength();
+ OUString sLayoutName = pMasterPage->GetLayoutName();
+ if (sLayoutName.endsWith(sLayoutSuffix))
+ sLayoutName = sLayoutName.copy(0, sLayoutName.getLength() - nLength);
+
+ rDocument.SetMasterPage (
+ pPage->GetPageNum() / 2,
+ sLayoutName,
+ pSourceDocument,
+ false, // Exchange the master page of only the target page.
+ false // Keep unused master pages.
+ );
+}
+
+sal_uInt16 ViewClipboard::DetermineInsertPosition ()
+{
+ SdDrawDocument& rDoc = mrView.GetDoc();
+ sal_uInt16 nPgCnt = rDoc.GetSdPageCount( PageKind::Standard );
+
+ // Insert position is the behind the last selected page or behind the
+ // last page when the selection is empty.
+ sal_uInt16 nInsertPos = rDoc.GetSdPageCount( PageKind::Standard ) * 2 + 1;
+ for( sal_uInt16 nPage = 0; nPage < nPgCnt; nPage++ )
+ {
+ SdPage* pPage = rDoc.GetSdPage( nPage, PageKind::Standard );
+
+ if( pPage->IsSelected() )
+ nInsertPos = nPage * 2 + 3;
+ }
+
+ return nInsertPos;
+}
+
+sal_uInt16 ViewClipboard::InsertSlides (
+ const SdTransferable& rTransferable,
+ sal_uInt16 nInsertPosition)
+{
+ SdDrawDocument& rDoc = mrView.GetDoc();
+
+ sal_uInt16 nInsertPgCnt = 0;
+ bool bMergeMasterPages = !rTransferable.HasSourceDoc( &rDoc );
+
+ // Prepare the insertion.
+ const std::vector<OUString> *pBookmarkList = nullptr;
+ DrawDocShell* pDataDocSh;
+ if (rTransferable.HasPageBookmarks())
+ {
+ // When the transferable contains page bookmarks then the referenced
+ // pages are inserted.
+ pBookmarkList = &rTransferable.GetPageBookmarks();
+ pDataDocSh = rTransferable.GetPageDocShell();
+ nInsertPgCnt = static_cast<sal_uInt16>(pBookmarkList->size());
+ }
+ else
+ {
+ // Otherwise all pages of the document of the transferable are
+ // inserted.
+ SfxObjectShell* pShell = rTransferable.GetDocShell().get();
+ pDataDocSh = static_cast<DrawDocShell*>(pShell);
+ SdDrawDocument* pDataDoc = pDataDocSh->GetDoc();
+
+ if (pDataDoc!=nullptr && pDataDoc->GetSdPageCount(PageKind::Standard))
+ nInsertPgCnt = pDataDoc->GetSdPageCount(PageKind::Standard);
+ }
+ if (nInsertPgCnt > 0)
+ {
+ const SolarMutexGuard aGuard;
+ ::sd::Window* pWin = mrView.GetViewShell()->GetActiveWindow();
+ const bool bWait = pWin && pWin->IsWait();
+
+ if( bWait )
+ pWin->LeaveWait();
+
+ rDoc.InsertBookmarkAsPage(
+ pBookmarkList ? *pBookmarkList : std::vector<OUString>(),
+ nullptr,
+ false,
+ false,
+ nInsertPosition,
+ (&rTransferable == SD_MOD()->pTransferDrag),
+ pDataDocSh,
+ true,
+ bMergeMasterPages,
+ false);
+
+ if( bWait )
+ pWin->EnterWait();
+ }
+
+ return nInsertPgCnt;
+}
+
+} // end of namespace ::sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/ViewShellBase.cxx b/sd/source/ui/view/ViewShellBase.cxx
new file mode 100644
index 000000000..26245971f
--- /dev/null
+++ b/sd/source/ui/view/ViewShellBase.cxx
@@ -0,0 +1,1456 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/processfactory.hxx>
+
+#include <ViewShellBase.hxx>
+#include <algorithm>
+#include <EventMultiplexer.hxx>
+#include <cache/SlsPageCacheManager.hxx>
+#include <app.hrc>
+#include <slideshow.hxx>
+#include <unokywds.hxx>
+#include <svx/svxids.hrc>
+#include <DrawDocShell.hxx>
+#include <ViewShellManager.hxx>
+#include <DrawController.hxx>
+#include <FrameView.hxx>
+#include <ViewTabBar.hxx>
+#include <sfx2/event.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/printer.hxx>
+#include <DrawViewShell.hxx>
+#include <FormShellManager.hxx>
+#include <ToolBarManager.hxx>
+#include <Window.hxx>
+#include <framework/ConfigurationController.hxx>
+#include <DocumentRenderer.hxx>
+#include <optsitem.hxx>
+#include <sdmod.hxx>
+
+#include <com/sun/star/document/XViewDataSupplier.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <com/sun/star/drawing/framework/ResourceId.hpp>
+#include <framework/FrameworkHelper.hxx>
+
+#include <sal/log.hxx>
+#include <rtl/ref.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/whiter.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+#include <sfx2/notebookbar/SfxNotebookBar.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <sfx2/lokhelper.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <editeng/editview.hxx>
+#include <tools/svborder.hxx>
+
+#include <fubullet.hxx>
+#include <drawview.hxx>
+
+using namespace sd;
+#define ShellClass_ViewShellBase
+#include <sdslots.hxx>
+
+using ::sd::framework::FrameworkHelper;
+
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+using namespace com::sun::star::drawing::framework;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+
+namespace {
+
+class CurrentPageSetter
+{
+public:
+ explicit CurrentPageSetter (ViewShellBase& rBase);
+ void operator () (bool);
+private:
+ ViewShellBase& mrBase;
+};
+
+} // end of anonymous namespace
+
+namespace sd {
+
+class ViewShellBase::Implementation
+{
+public:
+ /** Main controller of the view shell. During the switching from one
+ stacked shell to another this pointer may be NULL.
+ */
+ ::rtl::Reference<DrawController> mpController;
+
+ /** The view tab bar is the control for switching between different
+ views in one pane.
+ */
+ ::rtl::Reference<ViewTabBar> mpViewTabBar;
+
+ // contains the complete area of the current view relative to the frame window
+ ::tools::Rectangle maClientArea;
+
+ // This is set to true when PrepareClose() is called.
+ bool mbIsClosing;
+
+ /** The view window is the parent of all UI elements that belong to the
+ view or ViewShell. This comprises the rulers, the scroll bars, and
+ the content window.
+ It does not include the ViewTabBar.
+ */
+ VclPtr<vcl::Window> mpViewWindow;
+ std::shared_ptr<ToolBarManager> mpToolBarManager;
+ std::shared_ptr<ViewShellManager> mpViewShellManager;
+ std::shared_ptr<tools::EventMultiplexer> mpEventMultiplexer;
+ std::shared_ptr<FormShellManager> mpFormShellManager;
+
+ explicit Implementation (ViewShellBase& rBase);
+ ~Implementation();
+
+ void LateInit();
+
+ /** Show or hide the ViewTabBar.
+ @param bShow
+ When <TRUE/> then the ViewTabBar is shown, otherwise it is hidden.
+ */
+ void ShowViewTabBar (bool bShow);
+
+ void SetUserWantsTabBar(bool inValue);
+ bool GetUserWantsTabBar() const { return mbUserWantsTabBar; }
+
+ /** Common code of ViewShellBase::OuterResizePixel() and
+ ViewShellBase::InnerResizePixel().
+ */
+ void ResizePixel (
+ const Point& rOrigin,
+ const Size& rSize,
+ bool bOuterResize);
+
+ /** Show or hide the specified pane. The visibility state is taken
+ from the given request.
+ @param rRequest
+ The request determines the new visibility state. The state can
+ either be toggled or be set to a given value.
+ @param rsPaneURL
+ This URL specifies the pane whose visibility state to set.
+ @param rsViewURL
+ When the pane becomes visible then this view URL specifies which
+ type of view to show in it.
+ */
+ void SetPaneVisibility (
+ const SfxRequest& rRequest,
+ const OUString& rsPaneURL,
+ const OUString& rsViewURL);
+
+ void GetSlotState (SfxItemSet& rSet);
+
+ void ProcessRestoreEditingViewSlot();
+
+private:
+ ViewShellBase& mrBase;
+ bool mbUserWantsTabBar;
+ bool mbTabBarShouldBeVisible;
+ /** Hold a reference to the page cache manager of the slide sorter in
+ order to ensure that it stays alive while the ViewShellBase is
+ alive.
+ */
+ std::shared_ptr<slidesorter::cache::PageCacheManager> mpPageCacheManager;
+};
+
+namespace {
+/** The only task of this window is to forward key presses to the content
+ window of the main view shell. With the key press it forwards the focus
+ so that it is not called very often.
+*/
+class FocusForwardingWindow : public vcl::Window
+{
+public:
+ FocusForwardingWindow (vcl::Window& rParentWindow, ViewShellBase& rBase);
+ virtual ~FocusForwardingWindow() override;
+ virtual void dispose() override;
+ virtual void KeyInput (const KeyEvent& rEvent) override;
+ virtual void Command (const CommandEvent& rEvent) override;
+
+private:
+ ViewShellBase& mrBase;
+};
+} // end of anonymous namespace
+
+//===== ViewShellBase =========================================================
+
+
+// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a
+// new ViewShellBase object has been constructed.
+
+SFX_IMPL_SUPERCLASS_INTERFACE(ViewShellBase, SfxViewShell)
+
+void ViewShellBase::InitInterface_Impl()
+{
+}
+
+ViewShellBase::ViewShellBase (
+ SfxViewFrame* _pFrame,
+ SfxViewShell*)
+ : SfxViewShell (_pFrame, SfxViewShellFlags::HAS_PRINTOPTIONS),
+ mpDocShell (nullptr),
+ mpDocument (nullptr)
+{
+ mpImpl.reset(new Implementation(*this));
+ mpImpl->mpViewWindow = VclPtr<FocusForwardingWindow>::Create(_pFrame->GetWindow(),*this);
+ mpImpl->mpViewWindow->SetBackground(Wallpaper());
+
+ _pFrame->GetWindow().SetBackground(Application::GetSettings().GetStyleSettings().GetLightColor());
+
+ // Set up the members in the correct order.
+ if (auto pDrawDocShell = dynamic_cast< DrawDocShell *>( GetViewFrame()->GetObjectShell() ))
+ mpDocShell = pDrawDocShell;
+ if (mpDocShell != nullptr)
+ mpDocument = mpDocShell->GetDoc();
+ mpImpl->mpViewShellManager = std::make_shared<ViewShellManager>(*this);
+
+ SetWindow(mpImpl->mpViewWindow.get());
+
+ // Hide the window to avoid complaints from Sfx...SwitchViewShell...
+ _pFrame->GetWindow().Hide();
+}
+
+/** In this destructor the order in which some of the members are destroyed
+ (and/or being prepared to being destroyed) is important. Change it only
+ when you know what you are doing.
+*/
+ViewShellBase::~ViewShellBase()
+{
+ // Notify other LOK views that we are going away.
+ SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", "false");
+ SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "");
+ SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY");
+
+ sfx2::SfxNotebookBar::CloseMethod(GetFrame()->GetBindings());
+
+ rtl::Reference<SlideShow> xSlideShow(SlideShow::GetSlideShow(*this));
+ if (xSlideShow.is() && xSlideShow->dependsOn(this))
+ SlideShow::Stop(*this);
+ xSlideShow.clear();
+
+ // Tell the controller that the ViewShellBase is not available anymore.
+ if (mpImpl->mpController)
+ mpImpl->mpController->ReleaseViewShellBase();
+
+ // We have to hide the main window to prevent SFX complaining after a
+ // reload about it being already visible.
+ ViewShell* pShell = GetMainViewShell().get();
+ if (pShell!=nullptr
+ && pShell->GetActiveWindow()!=nullptr
+ && pShell->GetActiveWindow()->GetParent()!=nullptr)
+ {
+ pShell->GetActiveWindow()->GetParent()->Hide();
+ }
+
+ mpImpl->mpToolBarManager->Shutdown();
+ mpImpl->mpViewShellManager->Shutdown();
+
+ EndListening(*GetViewFrame());
+ EndListening(*GetDocShell());
+
+ SetWindow(nullptr);
+
+ mpImpl->mpFormShellManager.reset();
+}
+
+void ViewShellBase::LateInit (const OUString& rsDefaultView)
+{
+ StartListening(*GetViewFrame(), DuplicateHandling::Prevent);
+ StartListening(*GetDocShell(), DuplicateHandling::Prevent);
+ mpImpl->LateInit();
+ InitializeFramework();
+
+ mpImpl->mpEventMultiplexer = std::make_shared<tools::EventMultiplexer>(*this);
+
+ mpImpl->mpFormShellManager = std::make_shared<FormShellManager>(*this);
+
+ mpImpl->mpToolBarManager = ToolBarManager::Create(
+ *this,
+ mpImpl->mpEventMultiplexer,
+ mpImpl->mpViewShellManager);
+
+ try
+ {
+ Reference<XControllerManager> xControllerManager (GetDrawController(), UNO_QUERY_THROW);
+ Reference<XConfigurationController> xConfigurationController (
+ xControllerManager->getConfigurationController());
+ if (xConfigurationController.is())
+ {
+ OUString sView (rsDefaultView);
+ if (sView.isEmpty())
+ sView = GetInitialViewShellType();
+
+ FrameworkHelper::Instance(*this);
+
+ // Create the resource ids for the center pane and view.
+ const Reference<drawing::framework::XResourceId> xCenterPaneId (
+ FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL));
+ const Reference<drawing::framework::XResourceId> xCenterViewId (
+ FrameworkHelper::CreateResourceId(sView, xCenterPaneId));
+
+ // Request center pane and view.
+ xConfigurationController->requestResourceActivation(xCenterPaneId, ResourceActivationMode_ADD);
+ xConfigurationController->requestResourceActivation(xCenterViewId, ResourceActivationMode_REPLACE);
+
+ // Process configuration events synchronously until the center view
+ // has been created.
+ sd::framework::ConfigurationController* pConfigurationController
+ = dynamic_cast<sd::framework::ConfigurationController*>(xConfigurationController.get());
+ if (pConfigurationController != nullptr)
+ {
+ while (
+ ! pConfigurationController->getResource(xCenterViewId).is()
+ && pConfigurationController->hasPendingRequests())
+ {
+ pConfigurationController->ProcessEvent();
+ }
+ }
+ }
+ }
+ catch (const RuntimeException&)
+ {
+ }
+
+ // AutoLayouts have to be ready.
+ GetDocument()->StopWorkStartupDelay();
+
+ UpdateBorder();
+
+ // Remember the type of the current main view shell in the frame view.
+ ViewShell* pViewShell = GetMainViewShell().get();
+ if (pViewShell != nullptr)
+ {
+ FrameView* pFrameView = pViewShell->GetFrameView();
+ if (pFrameView != nullptr)
+ pFrameView->SetViewShellTypeOnLoad(pViewShell->GetShellType());
+ }
+ // Show/Hide the TabBar
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDocument()->GetDocumentType());
+ bool bIsTabBarVisible = pOptions->IsTabBarVisible();
+ mpImpl->SetUserWantsTabBar( bIsTabBarVisible );
+}
+
+std::shared_ptr<ViewShellManager> const & ViewShellBase::GetViewShellManager() const
+{
+ return mpImpl->mpViewShellManager;
+}
+
+std::shared_ptr<ViewShell> ViewShellBase::GetMainViewShell() const
+{
+ std::shared_ptr<ViewShell> pMainViewShell (
+ framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this))
+ ->GetViewShell(framework::FrameworkHelper::msCenterPaneURL));
+ if (pMainViewShell == nullptr)
+ pMainViewShell = framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this))
+ ->GetViewShell(framework::FrameworkHelper::msFullScreenPaneURL);
+ return pMainViewShell;
+}
+
+ViewShellBase* ViewShellBase::GetViewShellBase (SfxViewFrame const * pViewFrame)
+{
+ ViewShellBase* pBase = nullptr;
+
+ if (pViewFrame != nullptr)
+ {
+ // Get the view shell for the frame and cast it to
+ // sd::ViewShellBase.
+ SfxViewShell* pSfxViewShell = pViewFrame->GetViewShell();
+ pBase = dynamic_cast< ::sd::ViewShellBase *>( pSfxViewShell );
+ }
+
+ return pBase;
+}
+
+void ViewShellBase::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ SfxViewShell::Notify(rBC, rHint);
+
+ const SfxEventHint* pEventHint = dynamic_cast<const SfxEventHint*>(&rHint);
+ if (pEventHint)
+ {
+ switch (pEventHint->GetEventId())
+ {
+ case SfxEventHintId::OpenDoc:
+ if( GetDocument() && GetDocument()->IsStartWithPresentation() )
+ {
+ if( GetViewFrame() )
+ {
+ GetViewFrame()->GetDispatcher()->Execute(
+ SID_PRESENTATION, SfxCallMode::ASYNCHRON );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ const SfxHintId nSlot = rHint.GetId();
+ switch ( nSlot )
+ {
+ case SfxHintId::LanguageChanged:
+ {
+ GetViewFrame()->GetBindings().Invalidate(SID_LANGUAGE_STATUS);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void ViewShellBase::InitializeFramework()
+{
+}
+
+OUString ViewShellBase::GetSelectionText(bool bCompleteWords, bool /*bOnlyASample*/)
+{
+ std::shared_ptr<ViewShell> const pMainShell(GetMainViewShell());
+ DrawViewShell *const pDrawViewShell(
+ dynamic_cast<DrawViewShell*>(pMainShell.get()));
+ return pDrawViewShell
+ ? pDrawViewShell->GetSelectionText(bCompleteWords)
+ : SfxViewShell::GetSelectionText(bCompleteWords);
+}
+
+bool ViewShellBase::HasSelection(bool bText) const
+{
+ std::shared_ptr<ViewShell> const pMainShell(GetMainViewShell());
+ DrawViewShell *const pDrawViewShell(
+ dynamic_cast<DrawViewShell*>(pMainShell.get()));
+ return pDrawViewShell
+ ? pDrawViewShell->HasSelection(bText)
+ : SfxViewShell::HasSelection(bText);
+}
+
+void ViewShellBase::InnerResizePixel (const Point& rOrigin, const Size &rSize, bool)
+{
+ Size aObjSize = GetObjectShell()->GetVisArea().GetSize();
+ if ( !aObjSize.IsEmpty() )
+ {
+ SvBorder aBorder( GetBorderPixel() );
+ Size aSize( rSize );
+ aSize.AdjustWidth( -(aBorder.Left() + aBorder.Right()) );
+ aSize.AdjustHeight( -(aBorder.Top() + aBorder.Bottom()) );
+ Size aObjSizePixel = mpImpl->mpViewWindow->LogicToPixel(aObjSize, MapMode(MapUnit::Map100thMM));
+ SfxViewShell::SetZoomFactor(
+ Fraction( aSize.Width(), std::max( aObjSizePixel.Width(), static_cast<::tools::Long>(1) ) ),
+ Fraction( aSize.Height(), std::max( aObjSizePixel.Height(), static_cast<::tools::Long>(1)) ) );
+ }
+
+ mpImpl->ResizePixel(rOrigin, rSize, false);
+}
+
+void ViewShellBase::OuterResizePixel (const Point& rOrigin, const Size &rSize)
+{
+ mpImpl->ResizePixel (rOrigin, rSize, true);
+}
+
+void ViewShellBase::Rearrange()
+{
+ OSL_ASSERT(GetViewFrame()!=nullptr);
+
+ // There is a bug in the communication between embedded objects and the
+ // framework::LayoutManager that leads to missing resize updates. The
+ // following workaround enforces such an update by cycling the border to
+ // zero and back to the current value.
+ if (GetWindow() != nullptr)
+ {
+ SetBorderPixel(SvBorder());
+ UpdateBorder(true);
+ }
+ else
+ {
+ SAL_WARN("sd.view", "Rearrange: window missing");
+ }
+
+ GetViewFrame()->Resize(true);
+}
+
+ErrCode ViewShellBase::DoVerb(sal_Int32 nVerb)
+{
+ ErrCode aResult = ERRCODE_NONE;
+
+ ::sd::ViewShell* pShell = GetMainViewShell().get();
+ if (pShell != nullptr)
+ aResult = pShell->DoVerb(nVerb);
+
+ return aResult;
+}
+
+Reference<view::XRenderable> ViewShellBase::GetRenderable()
+{
+ // Create a new DocumentRenderer on every call. It observes the life
+ // time of this ViewShellBase object.
+ return Reference<view::XRenderable>(new DocumentRenderer(*this));
+}
+
+SfxPrinter* ViewShellBase::GetPrinter (bool bCreate)
+{
+ OSL_ASSERT(mpImpl != nullptr);
+
+ return GetDocShell()->GetPrinter (bCreate);
+}
+
+sal_uInt16 ViewShellBase::SetPrinter (
+ SfxPrinter* pNewPrinter,
+ SfxPrinterChangeFlags nDiffFlags)
+{
+ OSL_ASSERT(mpImpl != nullptr);
+
+ GetDocShell()->SetPrinter(pNewPrinter);
+
+ if ( (nDiffFlags & SfxPrinterChangeFlags::CHG_ORIENTATION ||
+ nDiffFlags & SfxPrinterChangeFlags::CHG_SIZE) && pNewPrinter )
+ {
+ MapMode aMap = pNewPrinter->GetMapMode();
+ aMap.SetMapUnit(MapUnit::Map100thMM);
+ MapMode aOldMap = pNewPrinter->GetMapMode();
+ pNewPrinter->SetMapMode(aMap);
+ Size aNewSize = pNewPrinter->GetOutputSize();
+
+ std::shared_ptr<DrawViewShell> pDrawViewShell (
+ std::dynamic_pointer_cast<DrawViewShell>(GetMainViewShell()));
+ if (pDrawViewShell)
+ {
+ SdPage* pPage = GetDocument()->GetSdPage(
+ 0, PageKind::Standard );
+ pDrawViewShell->SetPageSizeAndBorder (
+ pDrawViewShell->GetPageKind(),
+ aNewSize,
+ -1,-1,-1,-1,
+ false/*bScaleAll*/,
+ pNewPrinter->GetOrientation(),
+ pPage->GetPaperBin(),
+ pPage->IsBackgroundFullSize());
+ }
+
+ pNewPrinter->SetMapMode(aOldMap);
+ }
+
+ return 0;
+}
+
+void ViewShellBase::UIActivating( SfxInPlaceClient* pClient )
+{
+ mpImpl->ShowViewTabBar(false);
+
+ ViewShell* pViewShell = GetMainViewShell().get();
+ if ( pViewShell )
+ pViewShell->UIActivating( pClient );
+
+ SfxViewShell::UIActivating( pClient );
+}
+
+void ViewShellBase::UIDeactivated( SfxInPlaceClient* pClient )
+{
+ SfxViewShell::UIDeactivated( pClient );
+
+ mpImpl->ShowViewTabBar(true);
+
+ ViewShell* pViewShell = GetMainViewShell().get();
+ if ( pViewShell )
+ pViewShell->UIDeactivated( pClient );
+}
+
+SvBorder ViewShellBase::GetBorder (bool )
+{
+ int nTop = 0;
+ if (mpImpl->mpViewTabBar.is() && mpImpl->mpViewTabBar->GetTabControl()->IsVisible())
+ nTop = mpImpl->mpViewTabBar->GetHeight();
+ return SvBorder(0,nTop,0,0);
+}
+
+void ViewShellBase::Execute (SfxRequest& rRequest)
+{
+ sal_uInt16 nSlotId = rRequest.GetSlot();
+
+ switch (nSlotId)
+ {
+ case SID_SWITCH_SHELL:
+ {
+ Reference<XControllerManager> xControllerManager (GetController(), UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ Reference<XConfigurationController> xConfigurationController (
+ xControllerManager->getConfigurationController());
+ if (xConfigurationController.is())
+ xConfigurationController->update();
+ }
+ }
+ break;
+
+ case SID_LEFT_PANE_DRAW:
+ mpImpl->SetPaneVisibility(
+ rRequest,
+ framework::FrameworkHelper::msLeftDrawPaneURL,
+ framework::FrameworkHelper::msSlideSorterURL);
+ break;
+
+ case SID_LEFT_PANE_IMPRESS:
+ mpImpl->SetPaneVisibility(
+ rRequest,
+ framework::FrameworkHelper::msLeftImpressPaneURL,
+ framework::FrameworkHelper::msSlideSorterURL);
+ break;
+
+ case SID_TOGGLE_TABBAR_VISIBILITY:
+ {
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDocument()->GetDocumentType());
+ bool bIsTabBarVisible = pOptions->IsTabBarVisible();
+ pOptions->SetTabBarVisible( !bIsTabBarVisible );
+ mpImpl->SetUserWantsTabBar( !bIsTabBarVisible );
+ rRequest.Done();
+ }
+ break;
+
+ // draw
+ case SID_DRAWINGMODE:
+ // impress normal
+ case SID_NORMAL_MULTI_PANE_GUI:
+ case SID_NOTES_MODE:
+ case SID_OUTLINE_MODE:
+ case SID_SLIDE_SORTER_MULTI_PANE_GUI:
+ case SID_SLIDE_SORTER_MODE:
+ // impress master
+ case SID_SLIDE_MASTER_MODE:
+ case SID_NOTES_MASTER_MODE:
+ case SID_HANDOUT_MASTER_MODE:
+ framework::FrameworkHelper::Instance(*this)->HandleModeChangeSlot(nSlotId, rRequest);
+ break;
+
+ case SID_WIN_FULLSCREEN:
+ // The full screen mode is not supported. Ignore the request.
+ break;
+
+ case SID_RESTORE_EDITING_VIEW:
+ mpImpl->ProcessRestoreEditingViewSlot();
+ break;
+
+ default:
+ // Ignore any other slot.
+ rRequest.Ignore ();
+ break;
+ }
+}
+
+void ViewShellBase::GetState (SfxItemSet& rSet)
+{
+ mpImpl->GetSlotState(rSet);
+
+ FuBullet::GetSlotState( rSet, nullptr, GetViewFrame() );
+}
+
+void ViewShellBase::WriteUserDataSequence (
+ css::uno::Sequence< css::beans::PropertyValue >& rSequence)
+{
+ // Forward call to main sub shell.
+ ViewShell* pShell = GetMainViewShell().get();
+ if (pShell != nullptr)
+ pShell->WriteUserDataSequence (rSequence);
+}
+
+void ViewShellBase::ReadUserDataSequence (
+ const css::uno::Sequence< css::beans::PropertyValue >& rSequence)
+{
+ // Forward call to main sub shell.
+ ViewShell* pShell = GetMainViewShell().get();
+ if (pShell == nullptr)
+ return;
+
+ pShell->ReadUserDataSequence (rSequence);
+
+ // For certain shell types ReadUserDataSequence may have changed the
+ // type to another one. Make sure that the center pane shows the
+ // right view shell.
+ switch (pShell->GetShellType())
+ {
+ case ViewShell::ST_IMPRESS:
+ case ViewShell::ST_NOTES:
+ case ViewShell::ST_HANDOUT:
+ {
+ OUString sViewURL;
+ switch (dynamic_cast<DrawViewShell&>(*pShell).GetPageKind())
+ {
+ default:
+ case PageKind::Standard:
+ sViewURL = framework::FrameworkHelper::msImpressViewURL;
+ break;
+ case PageKind::Notes:
+ sViewURL = framework::FrameworkHelper::msNotesViewURL;
+ break;
+ case PageKind::Handout:
+ sViewURL = framework::FrameworkHelper::msHandoutViewURL;
+ break;
+ }
+ if (!sViewURL.isEmpty())
+ framework::FrameworkHelper::Instance(*this)->RequestView(
+ sViewURL,
+ framework::FrameworkHelper::msCenterPaneURL);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void ViewShellBase::Activate (bool bIsMDIActivate)
+{
+ SfxViewShell::Activate(bIsMDIActivate);
+
+ Reference<XControllerManager> xControllerManager (GetController(), UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ Reference<XConfigurationController> xConfigurationController (
+ xControllerManager->getConfigurationController());
+ if (xConfigurationController.is())
+ xConfigurationController->update();
+ }
+ GetToolBarManager()->RequestUpdate();
+}
+
+void ViewShellBase::SetZoomFactor (
+ const Fraction &rZoomX,
+ const Fraction &rZoomY)
+{
+ SfxViewShell::SetZoomFactor (rZoomX, rZoomY);
+ // Forward call to main sub shell.
+ ViewShell* pShell = GetMainViewShell().get();
+ if (pShell != nullptr)
+ pShell->SetZoomFactor (rZoomX, rZoomY);
+}
+
+bool ViewShellBase::PrepareClose (bool bUI)
+{
+ bool bResult = SfxViewShell::PrepareClose (bUI);
+
+ if (bResult)
+ {
+ mpImpl->mbIsClosing = true;
+
+ // Forward call to main sub shell.
+ ViewShell* pShell = GetMainViewShell().get();
+ if (pShell != nullptr)
+ bResult = pShell->PrepareClose (bUI);
+ }
+
+ return bResult;
+}
+
+void ViewShellBase::WriteUserData (OUString& rString, bool bBrowse)
+{
+ SfxViewShell::WriteUserData (rString, bBrowse);
+
+ // Forward call to main sub shell.
+ ViewShell* pShell = GetMainViewShell().get();
+ if (pShell != nullptr)
+ pShell->WriteUserData();
+}
+
+void ViewShellBase::ReadUserData (const OUString& rString, bool bBrowse)
+{
+ SfxViewShell::ReadUserData (rString, bBrowse);
+
+ // Forward call to main sub shell.
+ ViewShell* pShell = GetMainViewShell().get();
+ if (pShell != nullptr)
+ pShell->ReadUserData();
+}
+
+SdrView* ViewShellBase::GetDrawView() const
+{
+ // Forward call to main sub shell.
+ ViewShell* pShell = GetMainViewShell().get();
+ if (pShell != nullptr)
+ return pShell->GetDrawView ();
+ else
+ return SfxViewShell::GetDrawView();
+}
+
+void ViewShellBase::SetBusyState (bool bBusy)
+{
+ if (GetDocShell() != nullptr)
+ GetDocShell()->SetWaitCursor (bBusy);
+}
+
+void ViewShellBase::UpdateBorder ( bool bForce /* = false */ )
+{
+ // The following calls to SetBorderPixel() and InvalidateBorder() are
+ // made only for the main view shell. This not only avoids unnecessary
+ // calls for the views in side panes but prevents calling an already
+ // dying SfxViewShell base class.
+ // We have to check the existence of the window, too.
+ // The SfxViewFrame accesses the window without checking it.
+ ViewShell* pMainViewShell = GetMainViewShell().get();
+ if (pMainViewShell == nullptr || GetWindow()==nullptr)
+ return;
+
+ SvBorder aCurrentBorder (GetBorderPixel());
+ bool bOuterResize ( ! GetDocShell()->IsInPlaceActive());
+ SvBorder aBorder (GetBorder(bOuterResize));
+ aBorder += pMainViewShell->GetBorder();
+
+ if (bForce || (aBorder != aCurrentBorder))
+ {
+ SetBorderPixel (aBorder);
+ InvalidateBorder();
+ }
+}
+
+void ViewShellBase::ShowUIControls (bool bVisible)
+{
+ mpImpl->ShowViewTabBar(bVisible);
+
+ ViewShell* pMainViewShell = GetMainViewShell().get();
+ if (pMainViewShell != nullptr)
+ pMainViewShell->ShowUIControls (bVisible);
+
+ UpdateBorder();
+ if (bVisible)
+ Rearrange();
+}
+
+OUString ViewShellBase::GetInitialViewShellType() const
+{
+ OUString sRequestedView (FrameworkHelper::msImpressViewURL);
+
+ do
+ {
+ Reference<document::XViewDataSupplier> xViewDataSupplier (
+ GetDocShell()->GetModel(), UNO_QUERY);
+ if ( ! xViewDataSupplier.is())
+ break;
+
+ Reference<container::XIndexAccess> xViewData (xViewDataSupplier->getViewData());
+ if ( ! xViewData.is())
+ break;
+ if (xViewData->getCount() == 0)
+ break;
+
+ css::uno::Any aAny = xViewData->getByIndex(0);
+ Sequence<beans::PropertyValue> aProperties;
+ if ( ! (aAny >>= aProperties))
+ break;
+
+ // Search the properties for the one that tells us what page kind to
+ // use.
+ auto pProperty = std::find_if(std::cbegin(aProperties), std::cend(aProperties),
+ [](const beans::PropertyValue& rProperty) { return rProperty.Name == sUNO_View_PageKind; });
+ if (pProperty != std::cend(aProperties))
+ {
+ sal_Int16 nPageKind = 0;
+ pProperty->Value >>= nPageKind;
+ switch (static_cast<PageKind>(nPageKind))
+ {
+ case PageKind::Standard:
+ sRequestedView = FrameworkHelper::msImpressViewURL;
+ break;
+
+ case PageKind::Handout:
+ sRequestedView = FrameworkHelper::msHandoutViewURL;
+ break;
+
+ case PageKind::Notes:
+ sRequestedView = FrameworkHelper::msNotesViewURL;
+ break;
+
+ default:
+ // The page kind is invalid. This is probably an
+ // error by the caller. We use the standard type to
+ // keep things going.
+ SAL_WARN( "sd.view", "ViewShellBase::GetInitialViewShellType: invalid page kind");
+ sRequestedView = FrameworkHelper::msImpressViewURL;
+ break;
+ }
+ }
+ }
+ while (false);
+
+ return sRequestedView;
+}
+
+std::shared_ptr<tools::EventMultiplexer> const & ViewShellBase::GetEventMultiplexer() const
+{
+ OSL_ASSERT(mpImpl != nullptr);
+ OSL_ASSERT(mpImpl->mpEventMultiplexer != nullptr);
+
+ return mpImpl->mpEventMultiplexer;
+}
+
+const ::tools::Rectangle& ViewShellBase::getClientRectangle() const
+{
+ return mpImpl->maClientArea;
+}
+
+std::shared_ptr<ToolBarManager> const & ViewShellBase::GetToolBarManager() const
+{
+ OSL_ASSERT(mpImpl != nullptr);
+ OSL_ASSERT(mpImpl->mpToolBarManager != nullptr);
+
+ return mpImpl->mpToolBarManager;
+}
+
+std::shared_ptr<FormShellManager> const & ViewShellBase::GetFormShellManager() const
+{
+ OSL_ASSERT(mpImpl != nullptr);
+ OSL_ASSERT(mpImpl->mpFormShellManager != nullptr);
+
+ return mpImpl->mpFormShellManager;
+}
+
+DrawController& ViewShellBase::GetDrawController() const
+{
+ OSL_ASSERT(mpImpl != nullptr);
+
+ return *mpImpl->mpController;
+}
+
+void ViewShellBase::SetViewTabBar (const ::rtl::Reference<ViewTabBar>& rViewTabBar)
+{
+ OSL_ASSERT(mpImpl != nullptr);
+
+ mpImpl->mpViewTabBar = rViewTabBar;
+}
+
+vcl::Window* ViewShellBase::GetViewWindow()
+{
+ OSL_ASSERT(mpImpl != nullptr);
+
+ return mpImpl->mpViewWindow.get();
+}
+
+OUString ViewShellBase::RetrieveLabelFromCommand( const OUString& aCmdURL ) const
+{
+ OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(GetMainViewShell()->GetViewFrame()->GetFrame().GetFrameInterface()));
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCmdURL, aModuleName);
+ return vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
+}
+
+int ViewShellBase::getPart() const
+{
+ ViewShell* pViewShell = framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this))->GetViewShell(FrameworkHelper::msCenterPaneURL).get();
+
+ if (DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pViewShell))
+ {
+ return pDrawViewShell->GetCurPagePos();
+ }
+
+ return 0;
+}
+
+void ViewShellBase::NotifyCursor(SfxViewShell* pOtherShell) const
+{
+ ViewShell* pThisShell = framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this))->GetViewShell(FrameworkHelper::msCenterPaneURL).get();
+
+ DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pThisShell);
+ if (!pDrawViewShell)
+ return;
+
+ if (this == pOtherShell)
+ return;
+
+ DrawView* pDrawView = pDrawViewShell->GetDrawView();
+ if (!pDrawView)
+ return;
+
+ if (pDrawView->GetTextEditObject())
+ {
+ // Blinking cursor.
+ EditView& rEditView = pDrawView->GetTextEditOutlinerView()->GetEditView();
+ rEditView.RegisterOtherShell(pOtherShell);
+ rEditView.ShowCursor();
+ rEditView.RegisterOtherShell(nullptr);
+ // Text selection, if any.
+ rEditView.DrawSelectionXOR(pOtherShell);
+
+ // Shape text lock.
+ if (OutlinerView* pOutlinerView = pDrawView->GetTextEditOutlinerView())
+ {
+ ::tools::Rectangle aRectangle = pOutlinerView->GetOutputArea();
+ vcl::Window* pWin = pThisShell->GetActiveWindow();
+ if (pWin && pWin->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ aRectangle = o3tl::toTwips(aRectangle, o3tl::Length::mm100);
+ OString sRectangle = aRectangle.toString();
+ SfxLokHelper::notifyOtherView(&pDrawViewShell->GetViewShellBase(), pOtherShell, LOK_CALLBACK_VIEW_LOCK, "rectangle", sRectangle);
+ }
+ }
+ else
+ {
+ // Graphic selection.
+ pDrawView->AdjustMarkHdl(pOtherShell);
+ }
+}
+
+//===== ViewShellBase::Implementation =========================================
+
+ViewShellBase::Implementation::Implementation (ViewShellBase& rBase)
+ : mbIsClosing(false),
+ mrBase(rBase),
+ mbUserWantsTabBar(false),
+ mbTabBarShouldBeVisible(true),
+ mpPageCacheManager(slidesorter::cache::PageCacheManager::Instance())
+{
+}
+
+ViewShellBase::Implementation::~Implementation()
+{
+ mpController = nullptr;
+ mpViewTabBar = nullptr;
+ mpViewWindow.disposeAndClear();
+ mpToolBarManager.reset();
+}
+
+void ViewShellBase::Implementation::LateInit()
+{
+ mpController = new DrawController(mrBase);
+}
+
+void ViewShellBase::Implementation::ProcessRestoreEditingViewSlot()
+{
+ ViewShell* pViewShell = mrBase.GetMainViewShell().get();
+ if (pViewShell == nullptr)
+ return;
+
+ FrameView* pFrameView = pViewShell->GetFrameView();
+ if (pFrameView == nullptr)
+ return;
+
+ // Set view shell, edit mode, and page kind.
+ // pFrameView->SetViewShEditMode(
+ // pFrameView->GetViewShEditModeOnLoad(),
+ // pFrameView->GetPageKindOnLoad());
+ pFrameView->SetViewShEditMode(
+ pFrameView->GetViewShEditModeOnLoad() );
+ pFrameView->SetPageKind(
+ pFrameView->GetPageKindOnLoad());
+ std::shared_ptr<FrameworkHelper> pHelper (FrameworkHelper::Instance(mrBase));
+ pHelper->RequestView(
+ FrameworkHelper::GetViewURL(pFrameView->GetViewShellTypeOnLoad()),
+ FrameworkHelper::msCenterPaneURL);
+ pHelper->RunOnConfigurationEvent("ConfigurationUpdateEnd", CurrentPageSetter(mrBase));
+}
+
+void ViewShellBase::Implementation::SetUserWantsTabBar(bool inValue)
+{
+ mbUserWantsTabBar = inValue;
+ // Call ShowViewTabBar to refresh the TabBar visibility
+ ShowViewTabBar(mbTabBarShouldBeVisible);
+}
+
+void ViewShellBase::Implementation::ShowViewTabBar (bool bShow)
+{
+ mbTabBarShouldBeVisible = bShow;
+ bShow = bShow && mbUserWantsTabBar;
+
+ if (mpViewTabBar.is()
+ && mpViewTabBar->GetTabControl()->IsVisible() != bShow)
+ {
+ mpViewTabBar->GetTabControl()->Show(bShow);
+ mrBase.Rearrange();
+ }
+}
+
+void ViewShellBase::Implementation::ResizePixel (
+ const Point& rOrigin,
+ const Size &rSize,
+ bool bOuterResize)
+{
+ if (mbIsClosing)
+ return;
+
+ // Forward the call to both the base class and the main stacked sub
+ // shell only when main sub shell exists.
+ ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
+
+ // Set the ViewTabBar temporarily to full size so that, when asked
+ // later, it can return its true height.
+ mrBase.SetWindow (mpViewWindow.get());
+ if (mpViewTabBar.is() && mpViewTabBar->GetTabControl()->IsVisible())
+ mpViewTabBar->GetTabControl()->SetPosSizePixel (rOrigin, rSize);
+
+ // Calculate and set the border before the controls are placed.
+ SvBorder aBorder;
+ if (pMainViewShell != nullptr)
+ aBorder = pMainViewShell->GetBorder();
+ aBorder += mrBase.GetBorder(bOuterResize);
+ if (mrBase.GetBorderPixel() != aBorder)
+ mrBase.SetBorderPixel(aBorder);
+
+ // Place the ViewTabBar at the top. It is part of the border.
+ SvBorder aBaseBorder;
+ if (mpViewTabBar.is() && mpViewTabBar->GetTabControl()->IsVisible())
+ {
+ aBaseBorder.Top() = mpViewTabBar->GetHeight();
+ mpViewTabBar->GetTabControl()->SetPosSizePixel(
+ rOrigin, Size(rSize.Width(),aBaseBorder.Top()));
+ }
+
+ // The view window gets the remaining space.
+ Point aViewWindowPosition (
+ rOrigin.X()+aBaseBorder.Left(),
+ rOrigin.Y()+aBaseBorder.Top());
+
+ Size aViewWindowSize (
+ rSize.Width() - aBaseBorder.Left() - aBaseBorder.Right(),
+ rSize.Height() - aBaseBorder.Top() - aBaseBorder.Bottom());
+ mpViewWindow->SetPosSizePixel(aViewWindowPosition, aViewWindowSize);
+
+ maClientArea = ::tools::Rectangle(Point(0,0), aViewWindowSize);
+}
+
+void ViewShellBase::Implementation::SetPaneVisibility (
+ const SfxRequest& rRequest,
+ const OUString& rsPaneURL,
+ const OUString& rsViewURL)
+{
+ try
+ {
+ Reference<XControllerManager> xControllerManager (mrBase.GetController(), UNO_QUERY_THROW);
+
+ const Reference< XComponentContext > xContext(
+ ::comphelper::getProcessComponentContext() );
+ Reference<XResourceId> xPaneId (ResourceId::create(
+ xContext, rsPaneURL));
+ Reference<XResourceId> xViewId (ResourceId::createWithAnchorURL(
+ xContext, rsViewURL, rsPaneURL));
+
+ // Determine the new visibility state.
+ const SfxItemSet* pArguments = rRequest.GetArgs();
+ bool bShowChildWindow;
+ sal_uInt16 nSlotId = rRequest.GetSlot();
+ if (pArguments != nullptr)
+ bShowChildWindow = static_cast<const SfxBoolItem&>(
+ pArguments->Get(nSlotId)).GetValue();
+ else
+ {
+ Reference<XConfigurationController> xConfigurationController (
+ xControllerManager->getConfigurationController());
+ if ( ! xConfigurationController.is())
+ throw RuntimeException();
+ Reference<XConfiguration> xConfiguration (
+ xConfigurationController->getRequestedConfiguration());
+ if ( ! xConfiguration.is())
+ throw RuntimeException();
+
+ bShowChildWindow = ! xConfiguration->hasResource(xPaneId);
+ }
+
+ // Set the desired visibility state at the current configuration
+ // and update it accordingly.
+ Reference<XConfigurationController> xConfigurationController (
+ xControllerManager->getConfigurationController());
+ if ( ! xConfigurationController.is())
+ throw RuntimeException();
+ if (bShowChildWindow)
+ {
+ xConfigurationController->requestResourceActivation(
+ xPaneId,
+ ResourceActivationMode_ADD);
+ xConfigurationController->requestResourceActivation(
+ xViewId,
+ ResourceActivationMode_REPLACE);
+ }
+ else
+ xConfigurationController->requestResourceDeactivation(
+ xPaneId);
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd.view");
+ }
+}
+
+void ViewShellBase::Implementation::GetSlotState (SfxItemSet& rSet)
+{
+ try
+ {
+ // Get some frequently used values.
+ Reference<XControllerManager> xControllerManager (mrBase.GetController(), UNO_QUERY_THROW);
+ Reference<XConfigurationController> xConfigurationController (
+ xControllerManager->getConfigurationController());
+ if ( ! xConfigurationController.is())
+ throw RuntimeException();
+ Reference<XConfiguration> xConfiguration (
+ xConfigurationController->getRequestedConfiguration());
+ if ( ! xConfiguration.is())
+ throw RuntimeException();
+
+ const Reference< XComponentContext > xContext(
+ ::comphelper::getProcessComponentContext() );
+ SfxWhichIter aSetIterator (rSet);
+ sal_uInt16 nItemId (aSetIterator.FirstWhich());
+
+ while (nItemId > 0)
+ {
+ bool bState (false);
+ Reference<XResourceId> xResourceId;
+ try
+ {
+ // Check if the right view is active
+ switch (nItemId)
+ {
+ case SID_LEFT_PANE_IMPRESS:
+ xResourceId = ResourceId::create(
+ xContext, FrameworkHelper::msLeftImpressPaneURL);
+ bState = xConfiguration->hasResource(xResourceId);
+ break;
+
+ case SID_LEFT_PANE_DRAW:
+ xResourceId = ResourceId::create(
+ xContext, FrameworkHelper::msLeftDrawPaneURL);
+ bState = xConfiguration->hasResource(xResourceId);
+ break;
+
+ case SID_DRAWINGMODE:
+ case SID_NORMAL_MULTI_PANE_GUI:
+ case SID_SLIDE_MASTER_MODE:
+ xResourceId = ResourceId::createWithAnchorURL(
+ xContext, FrameworkHelper::msImpressViewURL,
+ FrameworkHelper::msCenterPaneURL);
+ bState = xConfiguration->hasResource(xResourceId);
+ break;
+
+ case SID_SLIDE_SORTER_MULTI_PANE_GUI:
+ case SID_SLIDE_SORTER_MODE:
+ xResourceId = ResourceId::createWithAnchorURL(
+ xContext,
+ FrameworkHelper::msSlideSorterURL,
+ FrameworkHelper::msCenterPaneURL);
+ bState = xConfiguration->hasResource(xResourceId);
+ break;
+
+ case SID_OUTLINE_MODE:
+ xResourceId = ResourceId::createWithAnchorURL(
+ xContext,
+ FrameworkHelper::msOutlineViewURL,
+ FrameworkHelper::msCenterPaneURL);
+ bState = xConfiguration->hasResource(xResourceId);
+ break;
+
+ case SID_HANDOUT_MASTER_MODE:
+ xResourceId = ResourceId::createWithAnchorURL(
+ xContext, FrameworkHelper::msHandoutViewURL,
+ FrameworkHelper::msCenterPaneURL);
+ bState = xConfiguration->hasResource(xResourceId);
+ break;
+
+ case SID_NOTES_MODE:
+ case SID_NOTES_MASTER_MODE:
+ xResourceId = ResourceId::createWithAnchorURL(
+ xContext, FrameworkHelper::msNotesViewURL,
+ FrameworkHelper::msCenterPaneURL);
+ bState = xConfiguration->hasResource(xResourceId);
+ break;
+
+ case SID_TOGGLE_TABBAR_VISIBILITY:
+ bState = GetUserWantsTabBar();
+ break;
+
+ default:
+ // Ignore all other items. They are not meant to be
+ // handled by us.
+ break;
+ }
+ }
+ catch (const DeploymentException&)
+ {
+ }
+
+ // Check if edit mode fits too
+ if (bState)
+ {
+ ViewShell* const pCenterViewShell = FrameworkHelper::Instance(mrBase)->GetViewShell(
+ FrameworkHelper::msCenterPaneURL).get();
+ DrawViewShell* const pShell = dynamic_cast<DrawViewShell*>(pCenterViewShell);
+ if (pShell)
+ {
+ switch (nItemId)
+ {
+ case SID_DRAWINGMODE:
+ case SID_NORMAL_MULTI_PANE_GUI:
+ case SID_NOTES_MODE:
+ bState = pShell->GetEditMode() == EditMode::Page;
+ break;
+ case SID_SLIDE_MASTER_MODE:
+ case SID_NOTES_MASTER_MODE:
+ bState = pShell->GetEditMode() == EditMode::MasterPage;
+ break;
+ }
+ }
+ }
+
+ // And finally set the state.
+ rSet.Put(SfxBoolItem(nItemId, bState));
+
+ nItemId = aSetIterator.NextWhich();
+ }
+ }
+ catch (const RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd.view");
+ }
+
+}
+
+} // end of namespace sd
+
+//===== CurrentPageSetter ===========================================
+
+namespace {
+
+CurrentPageSetter::CurrentPageSetter (ViewShellBase& rBase)
+ : mrBase(rBase)
+{
+}
+
+void CurrentPageSetter::operator() (bool)
+{
+ FrameView* pFrameView = nullptr;
+
+ if (mrBase.GetMainViewShell() != nullptr)
+ {
+ pFrameView = mrBase.GetMainViewShell()->GetFrameView();
+ }
+
+ if (pFrameView==nullptr)
+ return;
+
+ try
+ {
+ // Get the current page either from the DrawPagesSupplier or the
+ // MasterPagesSupplier.
+ Any aPage;
+ if (pFrameView->GetViewShEditModeOnLoad() == EditMode::Page)
+ {
+ Reference<drawing::XDrawPagesSupplier> xPagesSupplier (
+ mrBase.GetController()->getModel(), UNO_QUERY_THROW);
+ Reference<container::XIndexAccess> xPages (
+ xPagesSupplier->getDrawPages(), UNO_QUERY_THROW);
+ aPage = xPages->getByIndex(pFrameView->GetSelectedPageOnLoad());
+ }
+ else
+ {
+ Reference<drawing::XMasterPagesSupplier> xPagesSupplier (
+ mrBase.GetController()->getModel(), UNO_QUERY_THROW);
+ Reference<container::XIndexAccess> xPages (
+ xPagesSupplier->getMasterPages(), UNO_QUERY_THROW);
+ aPage = xPages->getByIndex(pFrameView->GetSelectedPageOnLoad());
+ }
+ // Switch to the page last edited by setting the CurrentPage
+ // property.
+ Reference<beans::XPropertySet> xSet (mrBase.GetController(), UNO_QUERY_THROW);
+ xSet->setPropertyValue ("CurrentPage", aPage);
+ }
+ catch (const RuntimeException&)
+ {
+ // We have not been able to set the current page at the main view.
+ // This is sad but still leaves us in a valid state. Therefore,
+ // this exception is silently ignored.
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ SAL_WARN("sd.view", "CurrentPage property unknown");
+ }
+}
+
+} // end of anonymous namespace
+
+//===== FocusForwardingWindow =================================================
+
+namespace sd {
+namespace {
+
+FocusForwardingWindow::FocusForwardingWindow (
+ vcl::Window& rParentWindow,
+ ViewShellBase& rBase)
+ : vcl::Window(&rParentWindow, WinBits(WB_CLIPCHILDREN | WB_DIALOGCONTROL)),
+ mrBase(rBase)
+{
+ SAL_INFO("sd.view", "created FocusForwardingWindow at " << this);
+}
+
+FocusForwardingWindow::~FocusForwardingWindow()
+{
+ disposeOnce();
+}
+
+void FocusForwardingWindow::dispose()
+{
+ SAL_INFO("sd.view", "destroyed FocusForwardingWindow at " << this);
+ vcl::Window::dispose();
+}
+
+void FocusForwardingWindow::KeyInput (const KeyEvent& rKEvt)
+{
+ std::shared_ptr<ViewShell> pViewShell = mrBase.GetMainViewShell();
+ if (pViewShell != nullptr)
+ {
+ vcl::Window* pWindow = pViewShell->GetActiveWindow();
+ if (pWindow != nullptr)
+ {
+ // Forward the focus so that the window is called directly the
+ // next time.
+ pWindow->GrabFocus();
+ // Forward the key press as well.
+ pWindow->KeyInput(rKEvt);
+ }
+ }
+}
+
+void FocusForwardingWindow::Command (const CommandEvent& rEvent)
+{
+ std::shared_ptr<ViewShell> pViewShell = mrBase.GetMainViewShell();
+ if (pViewShell != nullptr)
+ {
+ vcl::Window* pWindow = pViewShell->GetActiveWindow();
+ if (pWindow != nullptr)
+ {
+ pWindow->Command(rEvent);
+ }
+ }
+}
+
+} // end of anonymous namespace
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/ViewShellHint.cxx b/sd/source/ui/view/ViewShellHint.cxx
new file mode 100644
index 000000000..b86cbaa32
--- /dev/null
+++ b/sd/source/ui/view/ViewShellHint.cxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ViewShellHint.hxx>
+
+namespace sd
+{
+ViewShellHint::ViewShellHint(HintId eHintId)
+ : meHintId(eHintId)
+{
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/ViewShellImplementation.cxx b/sd/source/ui/view/ViewShellImplementation.cxx
new file mode 100644
index 000000000..a0c025ce5
--- /dev/null
+++ b/sd/source/ui/view/ViewShellImplementation.cxx
@@ -0,0 +1,379 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <ViewShellImplementation.hxx>
+
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <sdresid.hxx>
+#include <unokywds.hxx>
+#include <strings.hrc>
+#include <app.hrc>
+#include <unmodpg.hxx>
+#include <DrawDocShell.hxx>
+#include <FactoryIds.hxx>
+#include <ViewShellBase.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <svx/imapdlg.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/sberrors.hxx>
+#include <xmloff/autolayout.hxx>
+#include <vcl/svapp.hxx>
+
+#include <undo/undoobjects.hxx>
+
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd {
+
+ViewShell::Implementation::Implementation (ViewShell& rViewShell)
+ : mbIsMainViewShell(false),
+ mbIsInitialized(false),
+ mbArrangeActive(false),
+ mrViewShell(rViewShell)
+{
+}
+
+ViewShell::Implementation::~Implementation() COVERITY_NOEXCEPT_FALSE
+{
+ if ( ! mpUpdateLockForMouse.expired())
+ {
+ std::shared_ptr<ToolBarManagerLock> pLock(mpUpdateLockForMouse);
+ if (pLock != nullptr)
+ {
+ // Force the ToolBarManagerLock to be released even when the
+ // IsUICaptured() returns <TRUE/>.
+ pLock->Release(true);
+ }
+ }
+}
+
+void ViewShell::Implementation::ProcessModifyPageSlot (
+ SfxRequest& rRequest,
+ SdPage* pCurrentPage,
+ PageKind ePageKind)
+{
+ SdDrawDocument* pDocument = mrViewShell.GetDoc();
+ SdrLayerAdmin& rLayerAdmin = pDocument->GetLayerAdmin();
+ SdrLayerIDSet aVisibleLayers;
+ bool bHandoutMode = false;
+ SdPage* pHandoutMPage = nullptr;
+ OUString aNewName;
+
+ AutoLayout aNewAutoLayout;
+
+ bool bBVisible;
+ bool bBObjsVisible;
+ const SfxItemSet* pArgs = rRequest.GetArgs();
+
+ if (pCurrentPage != nullptr && pCurrentPage->TRG_HasMasterPage())
+ aVisibleLayers = pCurrentPage->TRG_GetMasterPageVisibleLayers();
+ else
+ aVisibleLayers.SetAll();
+
+ do
+ {
+ if (pCurrentPage == nullptr)
+ break;
+
+ if (!pArgs || pArgs->Count() == 1 || pArgs->Count() == 2 )
+ {
+ // First make sure that the sidebar is visible
+ mrViewShell.GetDrawView()->SdrEndTextEdit();
+ mrViewShell.GetDrawView()->UnmarkAll();
+ mrViewShell.GetViewFrame()->ShowChildWindow(SID_SIDEBAR);
+ sfx2::sidebar::Sidebar::TogglePanel(
+ u"SdLayoutsPanel",
+ mrViewShell.GetViewFrame()->GetFrame().GetFrameInterface());
+ break;
+ }
+ else if (pArgs->Count() == 4)
+ {
+ const SfxStringItem* pNewName = rRequest.GetArg<SfxStringItem>(ID_VAL_PAGENAME);
+ const SfxUInt32Item* pNewAutoLayout = rRequest.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYOUT);
+ const SfxBoolItem* pBVisible = rRequest.GetArg<SfxBoolItem>(ID_VAL_ISPAGEBACK);
+ const SfxBoolItem* pBObjsVisible = rRequest.GetArg<SfxBoolItem>(ID_VAL_ISPAGEOBJ);
+ AutoLayout aLayout (static_cast<AutoLayout>(pNewAutoLayout->GetValue ()));
+ if (aLayout >= AUTOLAYOUT_START
+ && aLayout < AUTOLAYOUT_END)
+ {
+ aNewName = pNewName->GetValue ();
+ aNewAutoLayout = static_cast<AutoLayout>(pNewAutoLayout->GetValue ());
+ bBVisible = pBVisible->GetValue ();
+ bBObjsVisible = pBObjsVisible->GetValue ();
+ }
+ else
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE);
+#endif
+ rRequest.Ignore ();
+ break;
+ }
+ if (ePageKind == PageKind::Handout)
+ {
+ bHandoutMode = true;
+ pHandoutMPage = pDocument->GetMasterSdPage(0, PageKind::Handout);
+ }
+ }
+ else
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ rRequest.Ignore ();
+ break;
+ }
+
+ SdPage* pUndoPage =
+ bHandoutMode ? pHandoutMPage : pCurrentPage;
+
+ SfxUndoManager* pUndoManager = mrViewShell.GetDocSh()->GetUndoManager();
+ DBG_ASSERT(pUndoManager, "No UNDO MANAGER ?!?");
+
+ if( pUndoManager )
+ {
+ OUString aComment( SdResId(STR_UNDO_MODIFY_PAGE) );
+ pUndoManager->EnterListAction(aComment, aComment, 0, mrViewShell.GetViewShellBase().GetViewShellId());
+ pUndoManager->AddUndoAction(
+ std::make_unique<ModifyPageUndoAction>(
+ pDocument, pUndoPage, aNewName, aNewAutoLayout, bBVisible, bBObjsVisible));
+
+ // Clear the selection because the selected object may be removed as
+ // a result of the assignment of the layout.
+ mrViewShell.GetDrawView()->UnmarkAll();
+
+ if (!bHandoutMode)
+ {
+ if (pCurrentPage->GetName() != aNewName)
+ {
+ pCurrentPage->SetName(aNewName);
+
+ if (ePageKind == PageKind::Standard)
+ {
+ sal_uInt16 nPage = (pCurrentPage->GetPageNum()-1) / 2;
+ SdPage* pNotesPage = pDocument->GetSdPage(nPage, PageKind::Notes);
+ if (pNotesPage != nullptr)
+ pNotesPage->SetName(aNewName);
+ }
+ }
+
+ pCurrentPage->SetAutoLayout(aNewAutoLayout, true);
+
+ SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ aVisibleLayers.Set(aBckgrnd, bBVisible);
+ aVisibleLayers.Set(aBckgrndObj, bBObjsVisible);
+ pCurrentPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+ }
+ else
+ {
+ pHandoutMPage->SetAutoLayout(aNewAutoLayout, true);
+ }
+
+ mrViewShell.GetViewFrame()->GetDispatcher()->Execute(SID_SWITCHPAGE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+
+ bool bSetModified = true;
+
+ if (pArgs->Count() == 1)
+ {
+ bSetModified = static_cast<const SfxBoolItem&>(pArgs->Get(SID_MODIFYPAGE)).GetValue();
+ }
+
+ pUndoManager->AddUndoAction( std::make_unique<UndoAutoLayoutPosAndSize>( *pUndoPage ) );
+ pUndoManager->LeaveListAction();
+
+ pDocument->SetChanged(bSetModified);
+ }
+ }
+ while (false);
+
+ mrViewShell.Cancel();
+ rRequest.Done ();
+}
+
+void ViewShell::Implementation::AssignLayout ( SfxRequest const & rRequest, PageKind ePageKind )
+{
+ const SfxUInt32Item* pWhatPage = rRequest.GetArg<SfxUInt32Item>(ID_VAL_WHATPAGE);
+ const SfxUInt32Item* pWhatLayout = rRequest.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYOUT);
+
+ SdDrawDocument* pDocument = mrViewShell.GetDoc();
+ if( !pDocument )
+ return;
+
+ SdPage* pPage = nullptr;
+ if( pWhatPage )
+ {
+ pPage = pDocument->GetSdPage(static_cast<sal_uInt16>(pWhatPage->GetValue()), ePageKind);
+ }
+
+ if( pPage == nullptr )
+ pPage = mrViewShell.getCurrentPage();
+
+ if( !pPage )
+ return;
+
+ AutoLayout eLayout = pPage->GetAutoLayout();
+
+ if( pWhatLayout )
+ eLayout = static_cast< AutoLayout >( pWhatLayout->GetValue() );
+
+ // Transform the given request into the four argument form that is
+ // understood by ProcessModifyPageSlot().
+ SdrLayerAdmin& rLayerAdmin (mrViewShell.GetViewShellBase().GetDocument()->GetLayerAdmin());
+ SdrLayerID aBackground (rLayerAdmin.GetLayerID(sUNO_LayerName_background));
+ SdrLayerID aBackgroundObject (rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects));
+
+ SdrLayerIDSet aVisibleLayers;
+
+ if( pPage->GetPageKind() == PageKind::Handout )
+ aVisibleLayers.SetAll();
+ else
+ aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers();
+
+ SfxRequest aRequest (mrViewShell.GetViewShellBase().GetViewFrame(), SID_MODIFYPAGE);
+ aRequest.AppendItem(SfxStringItem (ID_VAL_PAGENAME, pPage->GetName()));
+ aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATLAYOUT, eLayout));
+ aRequest.AppendItem(SfxBoolItem(ID_VAL_ISPAGEBACK, aVisibleLayers.IsSet(aBackground)));
+ aRequest.AppendItem(SfxBoolItem(ID_VAL_ISPAGEOBJ, aVisibleLayers.IsSet(aBackgroundObject)));
+
+ // Forward the call with the new arguments.
+ ProcessModifyPageSlot( aRequest, pPage, pPage->GetPageKind());
+}
+
+SfxInterfaceId ViewShell::Implementation::GetViewId() const
+{
+ switch (mrViewShell.GetShellType())
+ {
+ case ViewShell::ST_IMPRESS:
+ case ViewShell::ST_NOTES:
+ case ViewShell::ST_HANDOUT:
+ return IMPRESS_FACTORY_ID;
+
+ case ViewShell::ST_DRAW:
+ return DRAW_FACTORY_ID;
+
+ case ViewShell::ST_OUTLINE:
+ return OUTLINE_FACTORY_ID;
+
+ case ViewShell::ST_SLIDE_SORTER:
+ return SLIDE_SORTER_FACTORY_ID;
+
+ case ViewShell::ST_PRESENTATION:
+ return PRESENTATION_FACTORY_ID;
+
+ // Since we have to return a view id for every possible shell type
+ // and there is not (yet) a proper ViewShellBase sub class for the
+ // remaining types we chose the Impress factory as a fall back.
+ case ViewShell::ST_SIDEBAR:
+ case ViewShell::ST_NONE:
+ default:
+ return IMPRESS_FACTORY_ID;
+ }
+}
+
+SvxIMapDlg* ViewShell::Implementation::GetImageMapDialog()
+{
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (!pViewFrm)
+ return nullptr;
+
+ SfxChildWindow* pChildWindow = pViewFrm->GetChildWindow(
+ SvxIMapDlgChildWindow::GetChildWindowId());
+ if (pChildWindow == nullptr)
+ return nullptr;
+
+ return dynamic_cast<SvxIMapDlg*>(pChildWindow->GetController().get());
+}
+
+//===== ToolBarManagerLock ====================================================
+
+class ViewShell::Implementation::ToolBarManagerLock::Deleter { public:
+ void operator() (ToolBarManagerLock* pObject) { delete pObject; }
+};
+
+std::shared_ptr<ViewShell::Implementation::ToolBarManagerLock>
+ ViewShell::Implementation::ToolBarManagerLock::Create (
+ const std::shared_ptr<ToolBarManager>& rpManager)
+{
+ std::shared_ptr<ToolBarManagerLock> pLock (
+ new ViewShell::Implementation::ToolBarManagerLock(rpManager),
+ ViewShell::Implementation::ToolBarManagerLock::Deleter());
+ pLock->mpSelf = pLock;
+ return pLock;
+}
+
+ViewShell::Implementation::ToolBarManagerLock::ToolBarManagerLock (
+ const std::shared_ptr<ToolBarManager>& rpManager)
+ : mpLock(new ToolBarManager::UpdateLock(rpManager)),
+ maTimer("sd ToolBarManagerLock maTimer")
+{
+ // Start a timer that will unlock the ToolBarManager update lock when
+ // that is not done explicitly by calling Release().
+ maTimer.SetInvokeHandler(LINK(this,ToolBarManagerLock,TimeoutCallback));
+ maTimer.SetTimeout(100);
+ maTimer.Start();
+}
+
+IMPL_LINK_NOARG(ViewShell::Implementation::ToolBarManagerLock, TimeoutCallback, Timer *, void)
+{
+ // If possible then release the lock now. Otherwise start the timer
+ // and try again later.
+ if (Application::IsUICaptured())
+ {
+ maTimer.Start();
+ }
+ else
+ {
+ mpSelf.reset();
+ }
+}
+
+void ViewShell::Implementation::ToolBarManagerLock::Release (bool bForce)
+{
+ // If possible then release the lock now. Otherwise try again when the
+ // timer expires.
+ if (bForce || ! Application::IsUICaptured())
+ {
+ mpSelf.reset();
+ }
+}
+
+ViewShell::Implementation::ToolBarManagerLock::~ToolBarManagerLock()
+{
+ mpLock.reset();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/ViewShellManager.cxx b/sd/source/ui/view/ViewShellManager.cxx
new file mode 100644
index 000000000..db2ee5f8f
--- /dev/null
+++ b/sd/source/ui/view/ViewShellManager.cxx
@@ -0,0 +1,1168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ViewShellManager.hxx>
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+#include <Window.hxx>
+#include <DrawDocShell.hxx>
+
+#include <sal/log.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svxids.hrc>
+#include <svx/fmshell.hxx>
+#include <vcl/vclevent.hxx>
+#include <osl/diagnose.h>
+
+#include <iterator>
+#include <list>
+#include <unordered_map>
+
+namespace sd {
+
+namespace {
+
+/** The ShellDescriptor class is used to shells together with their ids and
+ the factory that was used to create the shell.
+
+ The shell pointer may be NULL. In that case the shell is created on
+ demand by a factory.
+
+ The factory pointer may be NULL. In that case the shell pointer is
+ given to the ViewShellManager.
+
+ Shell pointer and factory pointer can but should not be NULL at the same
+ time.
+*/
+class ShellDescriptor {
+public:
+ SfxShell* mpShell;
+ ShellId mnId;
+ ViewShellManager::SharedShellFactory mpFactory;
+ bool mbIsListenerAddedToWindow;
+
+ ShellDescriptor ();
+ explicit ShellDescriptor (ShellId nId);
+ vcl::Window* GetWindow() const;
+};
+
+/** This functor can be used to search for a shell in an STL container when the
+ shell pointer is given.
+*/
+class IsShell
+{
+public:
+ explicit IsShell (const SfxShell* pShell) : mpShell(pShell) {}
+ bool operator() (const ShellDescriptor& rDescriptor)
+ { return rDescriptor.mpShell == mpShell; }
+private:
+ const SfxShell* mpShell;
+};
+
+/** This functor can be used to search for a shell in an STL container when the
+ id of the shell is given.
+*/
+class IsId
+{
+public:
+ explicit IsId (ShellId nId) : mnId(nId) {}
+ bool operator() (const ShellDescriptor& rDescriptor)
+ { return rDescriptor.mnId == mnId; }
+private:
+ ShellId mnId;
+};
+
+} // end of anonymous namespace
+
+class ViewShellManager::Implementation
+{
+public:
+ Implementation (
+ ViewShellBase& rBase);
+ ~Implementation() COVERITY_NOEXCEPT_FALSE;
+
+ void AddShellFactory (
+ const SfxShell* pViewShell,
+ const SharedShellFactory& rpFactory);
+ void RemoveShellFactory (
+ const SfxShell* pViewShell,
+ const SharedShellFactory& rpFactory);
+ void ActivateViewShell (
+ ViewShell* pViewShell);
+ void DeactivateViewShell (const ViewShell& rShell);
+ void ActivateShell (SfxShell& rShell);
+ void DeactivateShell (const SfxShell& rShell);
+ void ActivateShell (const ShellDescriptor& rDescriptor);
+ void SetFormShell (const ViewShell* pViewShell, FmFormShell* pFormShell, bool bAbove);
+ void ActivateSubShell (const SfxShell& rParentShell, ShellId nId);
+ void DeactivateSubShell (const SfxShell& rParentShell, ShellId nId);
+ void MoveToTop (const SfxShell& rParentShell);
+ SfxShell* GetShell (ShellId nId) const;
+ SfxShell* GetTopShell() const;
+ SfxShell* GetTopViewShell() const;
+ void Shutdown();
+ void InvalidateAllSubShells (const SfxShell* pParentShell);
+
+ /** Remove all shells from the SFX stack above and including the given
+ shell.
+ */
+ void TakeShellsFromStack (const SfxShell* pShell);
+
+ class UpdateLock
+ {
+ public:
+ explicit UpdateLock (Implementation& rImpl) : mrImpl(rImpl) {mrImpl.LockUpdate();}
+ ~UpdateLock() COVERITY_NOEXCEPT_FALSE {mrImpl.UnlockUpdate();}
+ private:
+ Implementation& mrImpl;
+ };
+
+ /** Prevent updates of the shell stack. While the sub shell manager is
+ locked it will update its internal data structures but not alter the
+ shell stack. Use this method when there are several modifications
+ to the shell stack to prevent multiple rebuilds of the shell stack
+ and resulting broadcasts.
+ */
+ void LockUpdate();
+
+ /** Allow updates of the shell stack. This method has to be called the
+ same number of times as LockUpdate() to really allow a rebuild of
+ the shell stack.
+ */
+ void UnlockUpdate();
+
+private:
+ ViewShellBase& mrBase;
+ mutable ::osl::Mutex maMutex;
+
+ class ShellHash { public: size_t operator()(const SfxShell* p) const { return reinterpret_cast<size_t>(p);} };
+ typedef std::unordered_multimap<const SfxShell*,SharedShellFactory,ShellHash>
+ FactoryList;
+ FactoryList maShellFactories;
+
+ /** List of the active view shells. In order to create gather all shells
+ to put on the shell stack each view shell in this list is asked for
+ its sub-shells (typically toolbars).
+ */
+ typedef std::list<ShellDescriptor> ActiveShellList;
+ ActiveShellList maActiveViewShells;
+
+ typedef std::list<ShellDescriptor> SubShellSubList;
+ typedef std::unordered_map<const SfxShell*,SubShellSubList,ShellHash> SubShellList;
+ SubShellList maActiveSubShells;
+
+ /** In this member we remember what shells we have pushed on the shell
+ stack.
+ */
+ typedef ::std::vector<SfxShell*> ShellStack;
+
+ int mnUpdateLockCount;
+
+ /** The UpdateShellStack() method can be called recursively. This flag
+ is used to communicate between different levels of invocation: if
+ the stack has been updated in an inner call the outer call can (has
+ to) stop and return immediately.
+ */
+ bool mbShellStackIsUpToDate;
+
+ SfxShell* mpFormShell;
+ const ViewShell* mpFormShellParent;
+ bool mbFormShellAboveParent;
+
+ SfxShell* mpTopShell;
+ SfxShell* mpTopViewShell;
+
+
+ void UpdateShellStack();
+
+ void CreateShells();
+
+ /** This method rebuilds the stack of shells that are stacked upon the
+ view shell base.
+ */
+ void CreateTargetStack (ShellStack& rStack) const;
+
+ DECL_LINK(WindowEventHandler, VclWindowEvent&, void);
+
+#if OSL_DEBUG_LEVEL >= 2
+ void DumpShellStack (const ShellStack& rStack);
+ void DumpSfxShellStack();
+#endif
+
+ /** To be called before a shell is taken from the SFX shell stack. This
+ method deactivates an active text editing to avoid problems with
+ undo managers.
+ Afterwards the Deactivate() of the shell is called.
+ */
+ static void Deactivate (SfxShell* pShell);
+
+ ShellDescriptor CreateSubShell (
+ SfxShell const * pShell,
+ ShellId nShellId);
+ void DestroyViewShell (ShellDescriptor& rDescriptor);
+ static void DestroySubShell (const ShellDescriptor& rDescriptor);
+};
+
+//===== ViewShellManager ======================================================
+
+ViewShellManager::ViewShellManager (ViewShellBase& rBase)
+ : mpImpl(new Implementation(rBase)),
+ mbValid(true)
+{
+}
+
+ViewShellManager::~ViewShellManager()
+{
+}
+
+void ViewShellManager::AddSubShellFactory (
+ ViewShell const * pViewShell,
+ const SharedShellFactory& rpFactory)
+{
+ if (mbValid)
+ mpImpl->AddShellFactory(pViewShell, rpFactory);
+}
+
+void ViewShellManager::RemoveSubShellFactory (
+ ViewShell const * pViewShell,
+ const SharedShellFactory& rpFactory)
+{
+ if (mbValid)
+ mpImpl->RemoveShellFactory(pViewShell, rpFactory);
+}
+
+void ViewShellManager::ActivateViewShell (ViewShell* pViewShell)
+{
+ if (mbValid)
+ return mpImpl->ActivateViewShell(pViewShell);
+}
+
+void ViewShellManager::DeactivateViewShell (const ViewShell* pShell)
+{
+ if (mbValid && pShell!=nullptr)
+ mpImpl->DeactivateViewShell(*pShell);
+}
+
+void ViewShellManager::SetFormShell (
+ const ViewShell* pParentShell,
+ FmFormShell* pFormShell,
+ bool bAbove)
+{
+ if (mbValid)
+ mpImpl->SetFormShell(pParentShell,pFormShell,bAbove);
+}
+
+void ViewShellManager::ActivateSubShell (const ViewShell& rViewShell, ShellId nId)
+{
+ if (mbValid)
+ mpImpl->ActivateSubShell(rViewShell,nId);
+}
+
+void ViewShellManager::DeactivateSubShell (const ViewShell& rViewShell, ShellId nId)
+{
+ if (mbValid)
+ mpImpl->DeactivateSubShell(rViewShell,nId);
+}
+
+void ViewShellManager::InvalidateAllSubShells (ViewShell const * pViewShell)
+{
+ if (mbValid)
+ mpImpl->InvalidateAllSubShells(pViewShell);
+}
+
+void ViewShellManager::ActivateShell (SfxShell* pShell)
+{
+ if (mbValid && pShell!=nullptr)
+ mpImpl->ActivateShell(*pShell);
+}
+
+void ViewShellManager::DeactivateShell (const SfxShell* pShell)
+{
+ if (mbValid && pShell!=nullptr)
+ mpImpl->DeactivateShell(*pShell);
+}
+
+void ViewShellManager::MoveToTop (const ViewShell& rParentShell)
+{
+ if (mbValid)
+ mpImpl->MoveToTop(rParentShell);
+}
+
+SfxShell* ViewShellManager::GetShell (ShellId nId) const
+{
+ if (mbValid)
+ return mpImpl->GetShell(nId);
+ else
+ return nullptr;
+}
+
+SfxShell* ViewShellManager::GetTopShell() const
+{
+ if (mbValid)
+ return mpImpl->GetTopShell();
+ else
+ return nullptr;
+}
+
+SfxShell* ViewShellManager::GetTopViewShell() const
+{
+ if (mbValid)
+ return mpImpl->GetTopViewShell();
+ else
+ return nullptr;
+}
+
+void ViewShellManager::Shutdown()
+{
+ if (mbValid)
+ {
+ mpImpl->Shutdown();
+ mbValid = false;
+ }
+}
+
+void ViewShellManager::LockUpdate()
+{
+ mpImpl->LockUpdate();
+}
+
+void ViewShellManager::UnlockUpdate()
+{
+ mpImpl->UnlockUpdate();
+}
+
+//===== ViewShellManager::Implementation ======================================
+
+ViewShellManager::Implementation::Implementation (
+ ViewShellBase& rBase)
+ : mrBase(rBase),
+ mnUpdateLockCount(0),
+ mbShellStackIsUpToDate(true),
+ mpFormShell(nullptr),
+ mpFormShellParent(nullptr),
+ mbFormShellAboveParent(true),
+ mpTopShell(nullptr),
+ mpTopViewShell(nullptr)
+{}
+
+ViewShellManager::Implementation::~Implementation() COVERITY_NOEXCEPT_FALSE
+{
+ Shutdown();
+}
+
+void ViewShellManager::Implementation::AddShellFactory (
+ const SfxShell* pViewShell,
+ const SharedShellFactory& rpFactory)
+{
+ bool bAlreadyAdded (false);
+
+ // Check that the given factory has not already been added.
+ ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
+ maShellFactories.equal_range(pViewShell));
+ for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory)
+ if (iFactory->second == rpFactory)
+ {
+ bAlreadyAdded = true;
+ break;
+ }
+
+ // Add the factory if it is not already present.
+ if ( ! bAlreadyAdded)
+ maShellFactories.emplace(pViewShell, rpFactory);
+}
+
+void ViewShellManager::Implementation::RemoveShellFactory (
+ const SfxShell* pViewShell,
+ const SharedShellFactory& rpFactory)
+{
+ ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
+ maShellFactories.equal_range(pViewShell));
+ for (FactoryList::iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory)
+ if (iFactory->second == rpFactory)
+ {
+ maShellFactories.erase(iFactory);
+ break;
+ }
+}
+
+void ViewShellManager::Implementation::ActivateViewShell (ViewShell* pViewShell)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ ShellDescriptor aResult;
+ aResult.mpShell = pViewShell;
+
+ // Register as window listener so that the shells of the current
+ // window can be moved to the top of the shell stack.
+ if (aResult.mpShell != nullptr)
+ {
+ vcl::Window* pWindow = aResult.GetWindow();
+ if (pWindow != nullptr)
+ {
+ pWindow->AddEventListener(
+ LINK(this, ViewShellManager::Implementation, WindowEventHandler));
+ aResult.mbIsListenerAddedToWindow = true;
+ }
+ else
+ {
+ SAL_WARN("sd.view",
+ "ViewShellManager::ActivateViewShell: "
+ "new view shell has no active window");
+ }
+ }
+
+ ActivateShell(aResult);
+}
+
+void ViewShellManager::Implementation::DeactivateViewShell (const ViewShell& rShell)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ ActiveShellList::iterator iShell (::std::find_if (
+ maActiveViewShells.begin(),
+ maActiveViewShells.end(),
+ IsShell(&rShell)));
+ if (iShell == maActiveViewShells.end())
+ return;
+
+ UpdateLock aLocker (*this);
+
+ ShellDescriptor aDescriptor(*iShell);
+ mrBase.GetDocShell()->Disconnect(dynamic_cast<ViewShell*>(aDescriptor.mpShell));
+ maActiveViewShells.erase(iShell);
+ TakeShellsFromStack(aDescriptor.mpShell);
+
+ // Deactivate sub shells.
+ SubShellList::iterator iList (maActiveSubShells.find(&rShell));
+ if (iList != maActiveSubShells.end())
+ {
+ SubShellSubList& rList (iList->second);
+ while ( ! rList.empty())
+ DeactivateSubShell(rShell, rList.front().mnId);
+ }
+
+ DestroyViewShell(aDescriptor);
+}
+
+void ViewShellManager::Implementation::ActivateShell (SfxShell& rShell)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Create a new shell or recycle on in the cache.
+ ShellDescriptor aDescriptor;
+ aDescriptor.mpShell = &rShell;
+
+ ActivateShell(aDescriptor);
+}
+
+void ViewShellManager::Implementation::ActivateShell (const ShellDescriptor& rDescriptor)
+{
+ // Put shell on top of the active view shells.
+ if (rDescriptor.mpShell != nullptr)
+ {
+ maActiveViewShells.insert( maActiveViewShells.begin(), rDescriptor);
+ }
+}
+
+void ViewShellManager::Implementation::DeactivateShell (const SfxShell& rShell)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ ActiveShellList::iterator iShell (::std::find_if (
+ maActiveViewShells.begin(),
+ maActiveViewShells.end(),
+ IsShell(&rShell)));
+ if (iShell == maActiveViewShells.end())
+ return;
+
+ UpdateLock aLocker (*this);
+
+ ShellDescriptor aDescriptor(*iShell);
+ mrBase.GetDocShell()->Disconnect(dynamic_cast<ViewShell*>(aDescriptor.mpShell));
+ maActiveViewShells.erase(iShell);
+ TakeShellsFromStack(aDescriptor.mpShell);
+
+ // Deactivate sub shells.
+ SubShellList::iterator iList (maActiveSubShells.find(&rShell));
+ if (iList != maActiveSubShells.end())
+ {
+ SubShellSubList& rList (iList->second);
+ while ( ! rList.empty())
+ DeactivateSubShell(rShell, rList.front().mnId);
+ }
+
+ DestroyViewShell(aDescriptor);
+}
+
+void ViewShellManager::Implementation::ActivateSubShell (
+ const SfxShell& rParentShell,
+ ShellId nId)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Check that the given view shell is active.
+ if (std::none_of (maActiveViewShells.begin(), maActiveViewShells.end(), IsShell(&rParentShell)))
+ return;
+
+ // Create the sub shell list if it does not yet exist.
+ SubShellList::iterator iList (maActiveSubShells.find(&rParentShell));
+ if (iList == maActiveSubShells.end())
+ iList = maActiveSubShells.emplace(&rParentShell,SubShellSubList()).first;
+
+ // Do not activate an object bar that is already active. Requesting
+ // this is not exactly an error but may be an indication of one.
+ SubShellSubList& rList (iList->second);
+ if (std::any_of(rList.begin(),rList.end(), IsId(nId)))
+ return;
+
+ // Add just the id of the sub shell. The actual shell is created
+ // later in CreateShells().
+ UpdateLock aLock (*this);
+ rList.emplace_back(nId);
+}
+
+void ViewShellManager::Implementation::DeactivateSubShell (
+ const SfxShell& rParentShell,
+ ShellId nId)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Check that the given view shell is active.
+ SubShellList::iterator iList (maActiveSubShells.find(&rParentShell));
+ if (iList == maActiveSubShells.end())
+ return;
+
+ // Look up the sub shell.
+ SubShellSubList& rList (iList->second);
+ SubShellSubList::iterator iShell (
+ ::std::find_if(rList.begin(),rList.end(), IsId(nId)));
+ if (iShell == rList.end())
+ return;
+ SfxShell* pShell = iShell->mpShell;
+ if (pShell == nullptr)
+ return;
+
+ UpdateLock aLock (*this);
+
+ ShellDescriptor aDescriptor(*iShell);
+ // Remove the sub shell from both the internal structure as well as the
+ // SFX shell stack above and including the sub shell.
+ rList.erase(iShell);
+ TakeShellsFromStack(pShell);
+
+ DestroySubShell(aDescriptor);
+}
+
+void ViewShellManager::Implementation::MoveToTop (const SfxShell& rShell)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Check that we have access to a dispatcher. If not, then we are
+ // (probably) called while the view shell is still being created or
+ // initialized. Without dispatcher we can not rebuild the shell stack
+ // to move the requested shell to the top. So return right away instead
+ // of making a mess without being able to clean up afterwards.
+ if (mrBase.GetDispatcher() == nullptr)
+ return;
+
+ ActiveShellList::iterator iShell (::std::find_if (
+ maActiveViewShells.begin(),
+ maActiveViewShells.end(),
+ IsShell(&rShell)));
+ bool bMove = true;
+ if (iShell != maActiveViewShells.end())
+ {
+ // Is the shell already at the top of the stack? We have to keep
+ // the case in mind that mbKeepMainViewShellOnTop is true. Shells
+ // that are not the main view shell are placed on the second-to-top
+ // position in this case.
+ if (iShell == maActiveViewShells.begin())
+ {
+ // The shell is at the top position and is either a) the main
+ // view shell or b) another shell but the main view shell is not
+ // kept at the top position. We do not have to move the shell.
+ bMove = false;
+ }
+ }
+ else
+ {
+ // The shell is not on the stack. Therefore it can not be moved.
+ // We could insert it but we don't. Use ActivateViewShell() for
+ // that.
+ bMove = false;
+ }
+
+ // When the shell is not at the right position it is removed from the
+ // internal list of shells and inserted at the correct position.
+ if (bMove)
+ {
+ UpdateLock aLock (*this);
+
+ ShellDescriptor aDescriptor(*iShell);
+
+ TakeShellsFromStack(&rShell);
+ maActiveViewShells.erase(iShell);
+
+ maActiveViewShells.insert(maActiveViewShells.begin(), aDescriptor);
+ }
+}
+
+SfxShell* ViewShellManager::Implementation::GetShell (ShellId nId) const
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ SfxShell* pShell = nullptr;
+
+ // First search the active view shells.
+ ActiveShellList::const_iterator iShell (
+ ::std::find_if (
+ maActiveViewShells.begin(),
+ maActiveViewShells.end(),
+ IsId(nId)));
+ if (iShell != maActiveViewShells.end())
+ pShell = iShell->mpShell;
+ else
+ {
+ // Now search the active sub shells of every active view shell.
+ for (auto const& activeSubShell : maActiveSubShells)
+ {
+ const SubShellSubList& rList (activeSubShell.second);
+ SubShellSubList::const_iterator iSubShell(
+ ::std::find_if(rList.begin(),rList.end(), IsId(nId)));
+ if (iSubShell != rList.end())
+ {
+ pShell = iSubShell->mpShell;
+ break;
+ }
+ }
+ }
+
+ return pShell;
+}
+
+SfxShell* ViewShellManager::Implementation::GetTopShell() const
+{
+ OSL_ASSERT(mpTopShell == mrBase.GetSubShell(0));
+ return mpTopShell;
+}
+
+SfxShell* ViewShellManager::Implementation::GetTopViewShell() const
+{
+ return mpTopViewShell;
+}
+
+void ViewShellManager::Implementation::LockUpdate()
+{
+ mnUpdateLockCount++;
+}
+
+void ViewShellManager::Implementation::UnlockUpdate()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ mnUpdateLockCount--;
+ if (mnUpdateLockCount < 0)
+ {
+ // This should not happen.
+ OSL_ASSERT (mnUpdateLockCount>=0);
+ mnUpdateLockCount = 0;
+ }
+ if (mnUpdateLockCount == 0)
+ UpdateShellStack();
+}
+
+/** Update the SFX shell stack (the portion that is visible to us) so that
+ it matches the internal shell stack. This is done in six steps:
+ 1. Create the missing view shells and sub shells.
+ 2. Set up the internal shell stack.
+ 3. Get the SFX shell stack.
+ 4. Find the lowest shell in which the two stacks differ.
+ 5. Remove all shells above and including that shell from the SFX stack.
+ 6. Push all shells of the internal stack on the SFX shell stack that are
+ not already present on the later.
+*/
+void ViewShellManager::Implementation::UpdateShellStack()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Remember the undo manager from the top-most shell on the stack.
+ SfxShell* pTopMostShell = mrBase.GetSubShell(0);
+ SfxUndoManager* pUndoManager = (pTopMostShell!=nullptr)
+ ? pTopMostShell->GetUndoManager()
+ : nullptr;
+
+ // 1. Create the missing shells.
+ CreateShells();
+
+ // Update the pointer to the top-most active view shell.
+ mpTopViewShell = (maActiveViewShells.empty())
+ ? nullptr : maActiveViewShells.begin()->mpShell;
+
+
+ // 2. Create the internal target stack.
+ ShellStack aTargetStack;
+ CreateTargetStack(aTargetStack);
+
+ // 3. Get SFX shell stack.
+ ShellStack aSfxShellStack;
+ sal_uInt16 nIndex (0);
+ while (mrBase.GetSubShell(nIndex)!=nullptr)
+ ++nIndex;
+ aSfxShellStack.reserve(nIndex);
+ while (nIndex-- > 0)
+ aSfxShellStack.push_back(mrBase.GetSubShell(nIndex));
+
+#if OSL_DEBUG_LEVEL >= 2
+ SAL_INFO("sd.view", __func__ << ": Current SFX Stack");
+ DumpShellStack(aSfxShellStack);
+ SAL_INFO("sd.view", __func__ << ": Target Stack");
+ DumpShellStack(aTargetStack);
+#endif
+
+ // 4. Find the lowest shell in which the two stacks differ.
+ auto mismatchIters = std::mismatch(aSfxShellStack.begin(), aSfxShellStack.end(),
+ aTargetStack.begin(), aTargetStack.end());
+ ShellStack::iterator iSfxShell (mismatchIters.first);
+ ShellStack::iterator iTargetShell (mismatchIters.second);
+
+ // 5. Remove all shells above and including the differing shell from the
+ // SFX stack starting with the shell on top of the stack.
+ for (std::reverse_iterator<ShellStack::const_iterator> i(aSfxShellStack.end()), iLast(iSfxShell);
+ i != iLast; ++i)
+ {
+ SfxShell* const pShell = *i;
+ SAL_INFO("sd.view", __func__ << ": removing shell " << pShell << " from stack");
+ mrBase.RemoveSubShell(pShell);
+ }
+ aSfxShellStack.erase(iSfxShell, aSfxShellStack.end());
+
+ // 6. Push shells from the given stack onto the SFX stack.
+ mbShellStackIsUpToDate = false;
+ while (iTargetShell != aTargetStack.end())
+ {
+ SAL_INFO("sd.view", __func__ << ": pushing shell " << *iTargetShell << " on stack");
+ mrBase.AddSubShell(**iTargetShell);
+ ++iTargetShell;
+
+ // The pushing of the shell on to the shell stack may have lead to
+ // another invocation of this method. In this case we have to abort
+ // pushing shells on the stack and return immediately.
+ if (mbShellStackIsUpToDate)
+ break;
+ }
+ if (mrBase.GetDispatcher() != nullptr)
+ mrBase.GetDispatcher()->Flush();
+
+ // Update the pointer to the top-most shell and set its undo manager
+ // to the one of the previous top-most shell.
+ mpTopShell = mrBase.GetSubShell(0);
+ if (mpTopShell!=nullptr && pUndoManager!=nullptr && mpTopShell->GetUndoManager()==nullptr)
+ mpTopShell->SetUndoManager(pUndoManager);
+
+ // Finally tell an invocation of this method on a higher level that it can (has
+ // to) abort and return immediately.
+ mbShellStackIsUpToDate = true;
+
+#if OSL_DEBUG_LEVEL >= 2
+ SAL_INFO("sd.view", __func__ << ": New current stack");
+ DumpSfxShellStack();
+#endif
+}
+
+void ViewShellManager::Implementation::TakeShellsFromStack (const SfxShell* pShell)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Remember the undo manager from the top-most shell on the stack.
+ SfxShell* pTopMostShell = mrBase.GetSubShell(0);
+ SfxUndoManager* pUndoManager = (pTopMostShell!=nullptr)
+ ? pTopMostShell->GetUndoManager()
+ : nullptr;
+
+#if OSL_DEBUG_LEVEL >= 2
+ SAL_INFO("sd.view", __func__ << "TakeShellsFromStack( " << pShell << ")");
+ DumpSfxShellStack();
+#endif
+
+ // 0.Make sure that the given shell is on the stack. This is a
+ // preparation for the following assertion.
+ for (sal_uInt16 nIndex=0; true; nIndex++)
+ {
+ SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex);
+ if (pShellOnStack == nullptr)
+ {
+ // Set pShell to NULL to indicate the following code that the
+ // shell is not on the stack.
+ pShell = nullptr;
+ break;
+ }
+ else if (pShellOnStack == pShell)
+ break;
+ }
+
+ if (pShell == nullptr)
+ return;
+
+ // 1. Deactivate our shells on the stack before they are removed so
+ // that during the Deactivation() calls the stack is still intact.
+ for (sal_uInt16 nIndex=0; true; nIndex++)
+ {
+ SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex);
+ Deactivate(pShellOnStack);
+ if (pShellOnStack == pShell)
+ break;
+ }
+
+ // 2. Remove the shells from the stack.
+ while (true)
+ {
+ SfxShell* pShellOnStack = mrBase.GetSubShell(0);
+ SAL_INFO("sd.view", __func__ << "removing shell " << pShellOnStack << " from stack");
+ mrBase.RemoveSubShell(pShellOnStack);
+ if (pShellOnStack == pShell)
+ break;
+ }
+
+ // 3. Update the stack.
+ if (mrBase.GetDispatcher() != nullptr)
+ mrBase.GetDispatcher()->Flush();
+
+ // Update the pointer to the top-most shell and set its undo manager
+ // to the one of the previous top-most shell.
+ mpTopShell = mrBase.GetSubShell(0);
+ if (mpTopShell!=nullptr && pUndoManager!=nullptr && mpTopShell->GetUndoManager()==nullptr)
+ mpTopShell->SetUndoManager(pUndoManager);
+
+#if OSL_DEBUG_LEVEL >= 2
+ SAL_INFO("sd.view", __func__ << "Sfx shell stack is:");
+ DumpSfxShellStack();
+#endif
+}
+
+void ViewShellManager::Implementation::CreateShells()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Iterate over all view shells.
+ ActiveShellList::reverse_iterator iShell;
+ for (iShell=maActiveViewShells.rbegin(); iShell!=maActiveViewShells.rend(); ++iShell)
+ {
+ // Get the list of associated sub shells.
+ SubShellList::iterator iList (maActiveSubShells.find(iShell->mpShell));
+ if (iList != maActiveSubShells.end())
+ {
+ SubShellSubList& rList (iList->second);
+
+ // Iterate over all sub shells of the current view shell.
+ for (auto & subShell : rList)
+ {
+ if (subShell.mpShell == nullptr)
+ {
+ subShell = CreateSubShell(iShell->mpShell,subShell.mnId);
+ }
+ }
+ }
+ }
+}
+
+void ViewShellManager::Implementation::CreateTargetStack (ShellStack& rStack) const
+{
+ // Create a local stack of the shells that are to push on the shell
+ // stack. We can thus safely create the required shells while still
+ // having a valid shell stack.
+ for (ActiveShellList::const_reverse_iterator iViewShell (maActiveViewShells.rbegin());
+ iViewShell != maActiveViewShells.rend();
+ ++iViewShell)
+ {
+ // Possibly place the form shell below the current view shell.
+ if ( ! mbFormShellAboveParent
+ && mpFormShell!=nullptr
+ && iViewShell->mpShell==mpFormShellParent)
+ {
+ rStack.push_back(mpFormShell);
+ }
+
+ // Put the view shell itself on the local stack.
+ rStack.push_back (iViewShell->mpShell);
+
+ // Possibly place the form shell above the current view shell.
+ if (mbFormShellAboveParent
+ && mpFormShell!=nullptr
+ && iViewShell->mpShell==mpFormShellParent)
+ {
+ rStack.push_back(mpFormShell);
+ }
+
+ // Add all other sub shells.
+ SubShellList::const_iterator iList (maActiveSubShells.find(iViewShell->mpShell));
+ if (iList != maActiveSubShells.end())
+ {
+ const SubShellSubList& rList (iList->second);
+ SubShellSubList::const_reverse_iterator iSubShell;
+ for (iSubShell=rList.rbegin(); iSubShell!=rList.rend(); ++iSubShell)
+ if (iSubShell->mpShell != mpFormShell)
+ rStack.push_back(iSubShell->mpShell);
+ }
+ }
+}
+
+IMPL_LINK(ViewShellManager::Implementation, WindowEventHandler, VclWindowEvent&, rEvent, void)
+{
+ vcl::Window* pEventWindow = rEvent.GetWindow();
+
+ switch (rEvent.GetId())
+ {
+ case VclEventId::WindowGetFocus:
+ {
+ for (auto const& activeShell : maActiveViewShells)
+ {
+ if (pEventWindow == activeShell.GetWindow())
+ {
+ MoveToTop(*activeShell.mpShell);
+ break;
+ }
+ }
+ }
+ break;
+
+ case VclEventId::WindowLoseFocus:
+ break;
+
+ case VclEventId::ObjectDying:
+ // Remember that we do not have to remove the window
+ // listener for this window.
+ for (auto & activeViewShell : maActiveViewShells)
+ {
+ if (activeViewShell.GetWindow() == pEventWindow)
+ {
+ activeViewShell.mbIsListenerAddedToWindow = false;
+ break;
+ }
+ }
+ break;
+
+ default: break;
+ }
+}
+
+ShellDescriptor ViewShellManager::Implementation::CreateSubShell (
+ SfxShell const * pParentShell,
+ ShellId nShellId)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ ShellDescriptor aResult;
+
+ // Look up the factories for the parent shell.
+ ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
+ maShellFactories.equal_range(pParentShell));
+
+ // Try all factories to create the shell.
+ for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory)
+ {
+ SharedShellFactory pFactory = iFactory->second;
+ if (pFactory != nullptr)
+ aResult.mpShell = pFactory->CreateShell(nShellId);
+
+ // Exit the loop when the shell has been successfully created.
+ if (aResult.mpShell != nullptr)
+ {
+ aResult.mpFactory = pFactory;
+ aResult.mnId = nShellId;
+ break;
+ }
+ }
+
+ return aResult;
+}
+
+void ViewShellManager::Implementation::DestroyViewShell (
+ ShellDescriptor& rDescriptor)
+{
+ OSL_ASSERT(rDescriptor.mpShell != nullptr);
+
+ if (rDescriptor.mbIsListenerAddedToWindow)
+ {
+ rDescriptor.mbIsListenerAddedToWindow = false;
+ vcl::Window* pWindow = rDescriptor.GetWindow();
+ if (pWindow != nullptr)
+ {
+ pWindow->RemoveEventListener(
+ LINK(this, ViewShellManager::Implementation, WindowEventHandler));
+ }
+ }
+
+ // Destroy the sub shell factories.
+ ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
+ maShellFactories.equal_range(rDescriptor.mpShell));
+ if (aRange.first != maShellFactories.end())
+ maShellFactories.erase(aRange.first, aRange.second);
+
+ // Release the shell.
+ if (rDescriptor.mpFactory)
+ rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell);
+}
+
+void ViewShellManager::Implementation::DestroySubShell (
+ const ShellDescriptor& rDescriptor)
+{
+ OSL_ASSERT(rDescriptor.mpFactory);
+ rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell);
+}
+
+void ViewShellManager::Implementation::InvalidateAllSubShells (const SfxShell* pParentShell)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ SubShellList::iterator iList (maActiveSubShells.find(pParentShell));
+ if (iList != maActiveSubShells.end())
+ {
+ SubShellSubList& rList (iList->second);
+ for (auto const& shell : rList)
+ if (shell.mpShell != nullptr)
+ shell.mpShell->Invalidate();
+ }
+}
+
+void ViewShellManager::Implementation::Shutdown()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ // Take stacked shells from stack.
+ if ( ! maActiveViewShells.empty())
+ {
+ UpdateLock aLock (*this);
+
+ while ( ! maActiveViewShells.empty())
+ {
+ SfxShell* pShell = maActiveViewShells.front().mpShell;
+ if (pShell != nullptr)
+ {
+ ViewShell* pViewShell = dynamic_cast<ViewShell*>(pShell);
+ if (pViewShell != nullptr)
+ DeactivateViewShell(*pViewShell);
+ else
+ DeactivateShell(*pShell);
+ }
+ else
+ {
+ SAL_WARN("sd.view",
+ "ViewShellManager::Implementation::Shutdown(): empty active shell descriptor");
+ maActiveViewShells.pop_front();
+ }
+ }
+ }
+ mrBase.RemoveSubShell ();
+
+ maShellFactories.clear();
+}
+
+#if OSL_DEBUG_LEVEL >= 2
+void ViewShellManager::Implementation::DumpShellStack (const ShellStack& rStack)
+{
+ ShellStack::const_reverse_iterator iEntry;
+ for (iEntry=rStack.rbegin(); iEntry!=rStack.rend(); ++iEntry)
+ if (*iEntry != NULL)
+ SAL_INFO("sd.view", __func__ << ": " <<
+ *iEntry << " : " <<
+ (*iEntry)->GetName());
+ else
+ SAL_INFO("sd.view", __func__ << " null");
+}
+
+void ViewShellManager::Implementation::DumpSfxShellStack()
+{
+ ShellStack aSfxShellStack;
+ sal_uInt16 nIndex (0);
+ while (mrBase.GetSubShell(nIndex)!=NULL)
+ ++nIndex;
+ aSfxShellStack.reserve(nIndex);
+ while (nIndex-- > 0)
+ aSfxShellStack.push_back(mrBase.GetSubShell(nIndex));
+ DumpShellStack(aSfxShellStack);
+}
+#endif
+
+void ViewShellManager::Implementation::Deactivate (SfxShell* pShell)
+{
+ OSL_ASSERT(pShell!=nullptr);
+
+ // We have to end a text edit for view shells that are to be taken from
+ // the shell stack.
+ ViewShell* pViewShell = dynamic_cast<ViewShell*>(pShell);
+ if (pViewShell != nullptr)
+ {
+ sd::View* pView = pViewShell->GetView();
+ if (pView!=nullptr && pView->IsTextEdit())
+ {
+ pView->SdrEndTextEdit();
+ pView->UnmarkAll();
+ pViewShell->GetViewFrame()->GetDispatcher()->Execute(
+ SID_OBJECT_SELECT,
+ SfxCallMode::ASYNCHRON);
+ }
+ }
+
+ // Now we can deactivate the shell.
+ pShell->Deactivate(true);
+}
+
+void ViewShellManager::Implementation::SetFormShell (
+ const ViewShell* pFormShellParent,
+ FmFormShell* pFormShell,
+ bool bFormShellAboveParent)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ mpFormShellParent = pFormShellParent;
+ mpFormShell = pFormShell;
+ mbFormShellAboveParent = bFormShellAboveParent;
+}
+
+namespace {
+
+ShellDescriptor::ShellDescriptor()
+ : mpShell(nullptr),
+ mnId(ToolbarId::None),
+ mbIsListenerAddedToWindow(false)
+{
+}
+
+ShellDescriptor::ShellDescriptor (
+ ShellId nId)
+ : mpShell(nullptr),
+ mnId(nId),
+ mbIsListenerAddedToWindow(false)
+{
+}
+
+vcl::Window* ShellDescriptor::GetWindow() const
+{
+ ViewShell* pViewShell = dynamic_cast<ViewShell*>(mpShell);
+ if (pViewShell != nullptr)
+ return pViewShell->GetActiveWindow();
+ else
+ return nullptr;
+}
+
+} // end of anonymous namespace
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/ViewTabBar.cxx b/sd/source/ui/view/ViewTabBar.cxx
new file mode 100644
index 000000000..18a408e83
--- /dev/null
+++ b/sd/source/ui/view/ViewTabBar.cxx
@@ -0,0 +1,561 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ViewTabBar.hxx>
+
+#include <ViewShellBase.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <framework/Pane.hxx>
+#include <DrawController.hxx>
+
+#include <Client.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <com/sun/star/drawing/framework/ResourceId.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/drawing/framework/XView.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::framework::FrameworkHelper;
+
+namespace sd {
+
+namespace {
+bool IsEqual (const TabBarButton& rButton1, const TabBarButton& rButton2)
+{
+ return ((rButton1.ResourceId.is()
+ && rButton2.ResourceId.is()
+ && rButton1.ResourceId->compareTo(rButton2.ResourceId) == 0)
+ || rButton1.ButtonLabel == rButton2.ButtonLabel);
+}
+
+} // end of anonymous namespace
+
+ViewTabBar::ViewTabBar (
+ const Reference<XResourceId>& rxViewTabBarId,
+ const Reference<frame::XController>& rxController)
+ : mpTabControl(VclPtr<TabBarControl>::Create(GetAnchorWindow(rxViewTabBarId,rxController), this)),
+ mxController(rxController),
+ mxViewTabBarId(rxViewTabBarId),
+ mpViewShellBase(nullptr),
+ mnNoteBookWidthPadding(0)
+{
+ // Tunnel through the controller and use the ViewShellBase to obtain the
+ // view frame.
+ try
+ {
+ Reference<lang::XUnoTunnel> xTunnel (mxController, UNO_QUERY_THROW);
+ if (auto pController = comphelper::getFromUnoTunnel<DrawController>(xTunnel))
+ mpViewShellBase = pController->GetViewShellBase();
+ }
+ catch (const RuntimeException&)
+ {
+ }
+
+ // Register as listener at XConfigurationController.
+ Reference<XControllerManager> xControllerManager (mxController, UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationEvent,
+ Any());
+ }
+ }
+
+ mpTabControl->Show();
+
+ if (mpViewShellBase != nullptr
+ && rxViewTabBarId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
+ {
+ mpViewShellBase->SetViewTabBar(this);
+ }
+}
+
+ViewTabBar::~ViewTabBar()
+{
+}
+
+void ViewTabBar::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mpViewShellBase != nullptr
+ && mxViewTabBarId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
+ {
+ mpViewShellBase->SetViewTabBar(nullptr);
+ }
+
+ if (mxConfigurationController.is())
+ {
+ // Unregister listener from XConfigurationController.
+ try
+ {
+ mxConfigurationController->removeConfigurationChangeListener(this);
+ }
+ catch (const lang::DisposedException&)
+ {
+ // Receiving a disposed exception is the normal case. Is there
+ // a way to avoid it?
+ }
+ mxConfigurationController = nullptr;
+ }
+
+ {
+ const SolarMutexGuard aSolarGuard;
+ mpTabControl.disposeAndClear();
+ }
+
+ mxController = nullptr;
+}
+
+vcl::Window* ViewTabBar::GetAnchorWindow(
+ const Reference<XResourceId>& rxViewTabBarId,
+ const Reference<frame::XController>& rxController)
+{
+ vcl::Window* pWindow = nullptr;
+ ViewShellBase* pBase = nullptr;
+
+ // Tunnel through the controller and use the ViewShellBase to obtain the
+ // view frame.
+ try
+ {
+ Reference<lang::XUnoTunnel> xTunnel (rxController, UNO_QUERY_THROW);
+ if (auto pController = comphelper::getFromUnoTunnel<DrawController>(xTunnel))
+ pBase = pController->GetViewShellBase();
+ }
+ catch (const RuntimeException&)
+ {
+ }
+
+ // The ViewTabBar supports at the moment only the center pane.
+ if (rxViewTabBarId.is()
+ && rxViewTabBarId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
+ {
+ if (pBase != nullptr && pBase->GetViewFrame() != nullptr)
+ pWindow = &pBase->GetViewFrame()->GetWindow();
+ }
+
+ // The rest is (at the moment) just for the emergency case.
+ if (pWindow == nullptr)
+ {
+ Reference<XPane> xPane;
+ try
+ {
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY_THROW);
+ Reference<XConfigurationController> xCC (
+ xControllerManager->getConfigurationController());
+ if (xCC.is())
+ xPane.set(xCC->getResource(rxViewTabBarId->getAnchor()), UNO_QUERY);
+ }
+ catch (const RuntimeException&)
+ {
+ }
+
+ // Tunnel through the XWindow to the VCL side.
+ try
+ {
+ Reference<lang::XUnoTunnel> xTunnel (xPane, UNO_QUERY_THROW);
+ if (auto pPane = comphelper::getFromUnoTunnel<framework::Pane>(xTunnel))
+ pWindow = pPane->GetWindow()->GetParent();
+ }
+ catch (const RuntimeException&)
+ {
+ }
+ }
+
+ return pWindow;
+}
+
+//----- XConfigurationChangeListener ------------------------------------------
+
+void SAL_CALL ViewTabBar::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (rEvent.Type == FrameworkHelper::msResourceActivationEvent
+ && rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix)
+ && rEvent.ResourceId->isBoundTo(mxViewTabBarId->getAnchor(), AnchorBindingMode_DIRECT))
+ {
+ UpdateActiveButton();
+ }
+}
+
+//----- XEventListener --------------------------------------------------------
+
+void SAL_CALL ViewTabBar::disposing(
+ const lang::EventObject& rEvent)
+{
+ if (rEvent.Source == mxConfigurationController)
+ {
+ mxConfigurationController = nullptr;
+ mxController = nullptr;
+ }
+}
+
+//----- XTabBar ---------------------------------------------------------------
+
+void SAL_CALL ViewTabBar::addTabBarButtonAfter (
+ const TabBarButton& rButton,
+ const TabBarButton& rAnchor)
+{
+ const SolarMutexGuard aSolarGuard;
+ AddTabBarButton(rButton, rAnchor);
+}
+
+void SAL_CALL ViewTabBar::appendTabBarButton (const TabBarButton& rButton)
+{
+ const SolarMutexGuard aSolarGuard;
+ AddTabBarButton(rButton);
+}
+
+void SAL_CALL ViewTabBar::removeTabBarButton (const TabBarButton& rButton)
+{
+ const SolarMutexGuard aSolarGuard;
+ RemoveTabBarButton(rButton);
+}
+
+sal_Bool SAL_CALL ViewTabBar::hasTabBarButton (const TabBarButton& rButton)
+{
+ const SolarMutexGuard aSolarGuard;
+ return HasTabBarButton(rButton);
+}
+
+Sequence<TabBarButton> SAL_CALL ViewTabBar::getTabBarButtons()
+{
+ const SolarMutexGuard aSolarGuard;
+ return GetTabBarButtons();
+}
+
+//----- XResource -------------------------------------------------------------
+
+Reference<XResourceId> SAL_CALL ViewTabBar::getResourceId()
+{
+ return mxViewTabBarId;
+}
+
+sal_Bool SAL_CALL ViewTabBar::isAnchorOnly()
+{
+ return false;
+}
+
+//----- XUnoTunnel ------------------------------------------------------------
+
+const Sequence<sal_Int8>& ViewTabBar::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theViewTabBarUnoTunnelId;
+ return theViewTabBarUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL ViewTabBar::getSomething (const Sequence<sal_Int8>& rId)
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+bool ViewTabBar::ActivatePage(size_t nIndex)
+{
+ try
+ {
+ Reference<XControllerManager> xControllerManager (mxController,UNO_QUERY_THROW);
+ Reference<XConfigurationController> xConfigurationController (
+ xControllerManager->getConfigurationController());
+ if ( ! xConfigurationController.is())
+ throw RuntimeException();
+ Reference<XView> xView;
+ try
+ {
+ xView.set(xConfigurationController->getResource(
+ ResourceId::create(
+ ::comphelper::getProcessComponentContext(),
+ FrameworkHelper::msCenterPaneURL)),
+ UNO_QUERY);
+ }
+ catch (const DeploymentException&)
+ {
+ }
+
+ Client* pIPClient = nullptr;
+ if (mpViewShellBase != nullptr)
+ pIPClient = dynamic_cast<Client*>(mpViewShellBase->GetIPClient());
+ if (pIPClient==nullptr || ! pIPClient->IsObjectInPlaceActive())
+ {
+ if (nIndex < maTabBarButtons.size())
+ {
+ xConfigurationController->requestResourceActivation(
+ maTabBarButtons[nIndex].ResourceId,
+ ResourceActivationMode_REPLACE);
+ }
+
+ return true;
+ }
+ }
+ catch (const RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd.view");
+ }
+
+ return false;
+}
+
+int ViewTabBar::GetHeight() const
+{
+ int nHeight (0);
+
+ if (!maTabBarButtons.empty())
+ {
+ if (mpTabControl->IsReallyVisible())
+ {
+ weld::Notebook& rNotebook = mpTabControl->GetNotebook();
+ int nAllocatedWidth = mpTabControl->GetAllocatedWidth();
+ int nPageWidth = nAllocatedWidth - mnNoteBookWidthPadding;
+
+ // set each page width-request to the size it takes to fit the notebook allocation
+ for (int nIndex = 1, nPageCount = rNotebook.get_n_pages(); nIndex <= nPageCount; ++nIndex)
+ {
+ OString sIdent(OString::number(nIndex));
+ weld::Container* pContainer = rNotebook.get_page(sIdent);
+ pContainer->set_size_request(nPageWidth, -1);
+ }
+
+ // get the height-for-width for this allocation
+ nHeight = mpTabControl->get_preferred_size().Height();
+ }
+
+ if (nHeight <= 0)
+ {
+ // Using a default when the real height can not be determined.
+ // To get correct height this method should be called when the
+ // control is visible.
+ nHeight = 21;
+ }
+ }
+
+ return nHeight;
+}
+
+void ViewTabBar::AddTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton,
+ const css::drawing::framework::TabBarButton& rAnchor)
+{
+ TabBarButtonList::size_type nIndex;
+
+ if ( ! rAnchor.ResourceId.is()
+ || (rAnchor.ResourceId->getResourceURL().isEmpty()
+ && rAnchor.ButtonLabel.isEmpty()))
+ {
+ nIndex = 0;
+ }
+ else
+ {
+ for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
+ {
+ if (IsEqual(maTabBarButtons[nIndex], rAnchor))
+ {
+ ++nIndex;
+ break;
+ }
+ }
+ }
+
+ AddTabBarButton(rButton,nIndex);
+}
+
+void ViewTabBar::AddTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton)
+{
+ AddTabBarButton(rButton, maTabBarButtons.size());
+}
+
+void ViewTabBar::AddTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton,
+ sal_Int32 nPosition)
+{
+ if (nPosition >= 0 &&
+ nPosition <= mpTabControl->GetNotebook().get_n_pages())
+ {
+ // Insert the button into our local array.
+ maTabBarButtons.insert(maTabBarButtons.begin() + nPosition, rButton);
+ UpdateTabBarButtons();
+ UpdateActiveButton();
+ }
+}
+
+void ViewTabBar::RemoveTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton)
+{
+ for (TabBarButtonList::size_type nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
+ {
+ if (IsEqual(maTabBarButtons[nIndex], rButton))
+ {
+ maTabBarButtons.erase(maTabBarButtons.begin()+nIndex);
+ UpdateTabBarButtons();
+ UpdateActiveButton();
+ break;
+ }
+ }
+}
+
+bool ViewTabBar::HasTabBarButton (
+ const css::drawing::framework::TabBarButton& rButton)
+{
+ bool bResult (false);
+
+ for (const css::drawing::framework::TabBarButton & r : maTabBarButtons)
+ {
+ if (IsEqual(r, rButton))
+ {
+ bResult = true;
+ break;
+ }
+ }
+
+ return bResult;
+}
+
+css::uno::Sequence<css::drawing::framework::TabBarButton>
+ ViewTabBar::GetTabBarButtons()
+{
+ return comphelper::containerToSequence(maTabBarButtons);
+}
+
+void ViewTabBar::UpdateActiveButton()
+{
+ Reference<XView> xView;
+ if (mpViewShellBase != nullptr)
+ xView = FrameworkHelper::Instance(*mpViewShellBase)->GetView(
+ mxViewTabBarId->getAnchor());
+ if (!xView.is())
+ return;
+
+ Reference<XResourceId> xViewId (xView->getResourceId());
+ for (size_t nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
+ {
+ if (maTabBarButtons[nIndex].ResourceId->compareTo(xViewId) == 0)
+ {
+ mpTabControl->GetNotebook().set_current_page(nIndex);
+ break;
+ }
+ }
+}
+
+void ViewTabBar::UpdateTabBarButtons()
+{
+ int nMaxPageWidthReq(0);
+
+ weld::Notebook& rNotebook = mpTabControl->GetNotebook();
+ int nPageCount(rNotebook.get_n_pages());
+ int nIndex = 1;
+ for (const auto& rTab : maTabBarButtons)
+ {
+ OString sIdent(OString::number(nIndex));
+ // Create a new tab when there are not enough.
+ if (nPageCount < nIndex)
+ rNotebook.append_page(sIdent, rTab.ButtonLabel);
+ else
+ {
+ // Update the tab.
+ rNotebook.set_tab_label_text(sIdent, rTab.ButtonLabel);
+ }
+
+ // Set a fairly arbitrary initial width request for the pages so we can
+ // measure what extra width the notebook itself uses
+ weld::Container* pContainer = rNotebook.get_page(sIdent);
+ int nTextWidth = pContainer->get_pixel_size(rTab.ButtonLabel).Width();
+ pContainer->set_size_request(nTextWidth, -1);
+ nMaxPageWidthReq = std::max(nMaxPageWidthReq, nTextWidth);
+
+ ++nIndex;
+ }
+
+ // Delete tabs that are no longer used.
+ for (; nIndex<=nPageCount; ++nIndex)
+ rNotebook.remove_page(OString::number(nIndex));
+
+ int nWidthReq = rNotebook.get_preferred_size().Width();
+ // The excess width over the page request that the notebook uses we will
+ // use this later to help measure the best height-for-width given the
+ // eventual allocated width of the notebook
+ mnNoteBookWidthPadding = nWidthReq - nMaxPageWidthReq;
+}
+
+//===== TabBarControl =========================================================
+
+TabBarControl::TabBarControl (
+ vcl::Window* pParentWindow,
+ const ::rtl::Reference<ViewTabBar>& rpViewTabBar)
+ : InterimItemWindow(pParentWindow, "modules/simpress/ui/tabviewbar.ui", "TabViewBar")
+ , mxTabControl(m_xBuilder->weld_notebook("tabcontrol"))
+ , mpViewTabBar(rpViewTabBar)
+ , mnAllocatedWidth(0)
+{
+ // Because the actual window background is transparent--to avoid
+ // flickering due to multiple background paintings by this and by child
+ // windows--we have to paint the background for this control explicitly:
+ // the actual control is not painted over its whole bounding box.
+ SetPaintTransparent(false);
+ SetBackground(Application::GetSettings().GetStyleSettings().GetDialogColor());
+
+ InitControlBase(mxTabControl.get());
+
+ mxTabControl->connect_enter_page(LINK(this, TabBarControl, ActivatePageHdl));
+ mxTabControl->connect_size_allocate(LINK(this, TabBarControl, NotebookSizeAllocHdl));
+}
+
+void TabBarControl::dispose()
+{
+ mxTabControl.reset();
+ InterimItemWindow::dispose();
+}
+
+TabBarControl::~TabBarControl()
+{
+ disposeOnce();
+}
+
+IMPL_LINK(TabBarControl, NotebookSizeAllocHdl, const Size&, rSize, void)
+{
+ mnAllocatedWidth = rSize.Width();
+}
+
+IMPL_LINK(TabBarControl, ActivatePageHdl, const OString&, rPage, void)
+{
+ if (!mpViewTabBar->ActivatePage(mxTabControl->get_page_index(rPage)))
+ {
+ // When we run into this else branch then we have an active OLE
+ // object. We ignore the request to switch views. Additionally
+ // we put the active tab back to the one for the current view.
+ mpViewTabBar->UpdateActiveButton();
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/WindowUpdater.cxx b/sd/source/ui/view/WindowUpdater.cxx
new file mode 100644
index 000000000..c3f1bb53e
--- /dev/null
+++ b/sd/source/ui/view/WindowUpdater.cxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <WindowUpdater.hxx>
+#include <drawdoc.hxx>
+
+#include <vcl/outdev.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/window.hxx>
+
+#include <algorithm>
+
+namespace sd {
+
+WindowUpdater::WindowUpdater()
+ : mpDocument (nullptr)
+{
+ maCTLOptions.AddListener(this);
+}
+
+WindowUpdater::~WindowUpdater() noexcept
+{
+ maCTLOptions.RemoveListener(this);
+}
+
+void WindowUpdater::RegisterWindow (vcl::Window* pWindow)
+{
+ if (pWindow != nullptr)
+ {
+ tWindowList::iterator aWindowIterator (
+ ::std::find (
+ maWindowList.begin(), maWindowList.end(), pWindow));
+ if (aWindowIterator == maWindowList.end())
+ {
+ // Update the device once right now and add it to the list.
+ Update (pWindow->GetOutDev());
+ maWindowList.emplace_back(pWindow);
+ }
+ }
+}
+
+void WindowUpdater::UnregisterWindow (vcl::Window* pWindow)
+{
+ tWindowList::iterator aWindowIterator (
+ ::std::find (
+ maWindowList.begin(), maWindowList.end(), pWindow));
+ if (aWindowIterator != maWindowList.end())
+ {
+ maWindowList.erase (aWindowIterator);
+ }
+}
+
+void WindowUpdater::SetDocument (SdDrawDocument* pDocument)
+{
+ mpDocument = pDocument;
+}
+
+void WindowUpdater::Update (
+ OutputDevice* pDevice) const
+{
+ if (pDevice != nullptr)
+ {
+ UpdateWindow (pDevice);
+ }
+}
+
+void WindowUpdater::UpdateWindow (OutputDevice* pDevice) const
+{
+ if (pDevice == nullptr)
+ return;
+
+ SvtCTLOptions::TextNumerals aNumeralMode (maCTLOptions.GetCTLTextNumerals());
+
+ LanguageType aLanguage;
+ // Now this is a bit confusing. The numerals in arabic languages
+ // are Hindi numerals and what the western world generally uses are
+ // arabic numerals. The digits used in the Hindi language are not
+ // used at all.
+ switch (aNumeralMode)
+ {
+ case SvtCTLOptions::NUMERALS_HINDI:
+ aLanguage = LANGUAGE_ARABIC_SAUDI_ARABIA;
+ break;
+
+ case SvtCTLOptions::NUMERALS_SYSTEM:
+ aLanguage = LANGUAGE_SYSTEM;
+ break;
+
+ case SvtCTLOptions::NUMERALS_ARABIC:
+ default:
+ aLanguage = LANGUAGE_ENGLISH;
+ break;
+ }
+
+ pDevice->SetDigitLanguage (aLanguage);
+}
+
+void WindowUpdater::ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints )
+{
+ // Set the current state at all registered output devices.
+ for (auto& rxWindow : maWindowList)
+ Update (rxWindow->GetOutDev());
+
+ // Reformat the document for the modified state to take effect.
+ if (mpDocument != nullptr)
+ mpDocument->ReformatAllTextObjects();
+
+ // Invalidate the windows to make the modified state visible.
+ for (auto& rxWindow : maWindowList)
+ rxWindow->Invalidate();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/clview.cxx b/sd/source/ui/view/clview.cxx
new file mode 100644
index 000000000..9f11839da
--- /dev/null
+++ b/sd/source/ui/view/clview.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ClientView.hxx>
+#include <drawview.hxx>
+
+namespace sd
+{
+class DrawDocShell;
+class DrawViewShell;
+
+/**
+ * ClientView is used for DrawDocShell::Draw()
+ */
+
+ClientView::ClientView(DrawDocShell* pDocSh, OutputDevice* pOutDev)
+ : DrawView(pDocSh, pOutDev, nullptr)
+{
+}
+
+ClientView::~ClientView() {}
+
+/**
+ * If View should not Invalidate() the windows, this method has
+ * to be overridden and properly handled.
+ */
+
+void ClientView::InvalidateOneWin(OutputDevice& rWin)
+{
+ vcl::Region aRegion;
+ CompleteRedraw(&rWin, aRegion);
+}
+
+/**
+ * If View should not Invalidate() the windows, this method has
+ * to be overridden and properly handled.
+ */
+
+void ClientView::InvalidateOneWin(OutputDevice& rWin, const ::tools::Rectangle& rRect)
+{
+ CompleteRedraw(&rWin, vcl::Region(rRect));
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drawview.cxx b/sd/source/ui/view/drawview.cxx
new file mode 100644
index 000000000..e4cdf0107
--- /dev/null
+++ b/sd/source/ui/view/drawview.cxx
@@ -0,0 +1,634 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svl/style.hxx>
+#include <editeng/outliner.hxx>
+#include <svx/svdotext.hxx>
+#include <svl/poolitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <svl/whiter.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+
+#include <svx/svdundo.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+#include <strings.hrc>
+#include <View.hxx>
+#include <drawview.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <sdpage.hxx>
+#include <ViewShellBase.hxx>
+#include <DrawViewShell.hxx>
+#include <pres.hxx>
+#include <sdresid.hxx>
+#include <unchss.hxx>
+#include <slideshow.hxx>
+
+#include <undo/undomanager.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd {
+
+
+/**
+ * Shows the first page of document at position 0,0. In the case
+ * that there is no page a page is created.
+ */
+
+DrawView::DrawView(
+ DrawDocShell* pDocSh,
+ OutputDevice* pOutDev,
+ DrawViewShell* pShell)
+: ::sd::View(*pDocSh->GetDoc(), pOutDev, pShell)
+ ,mpDocShell(pDocSh)
+ ,mpDrawViewShell(pShell)
+ ,mnPOCHSmph(0)
+{
+ SetCurrentObj(SdrObjKind::Rectangle);
+}
+
+DrawView::~DrawView()
+{
+}
+
+/**
+ * Virtual method from SdrView, called at selection change.
+ */
+
+void DrawView::MarkListHasChanged()
+{
+ ::sd::View::MarkListHasChanged();
+
+ if (mpDrawViewShell)
+ mpDrawViewShell->SelectionHasChanged();
+}
+
+/**
+ * Virtual method from SdrView, called at model change.
+ */
+
+void DrawView::ModelHasChanged()
+{
+ ::sd::View::ModelHasChanged();
+
+ // force framer to rerender
+ SfxStyleSheetBasePool* pSSPool = mrDoc.GetStyleSheetPool();
+ pSSPool->Broadcast(SfxStyleSheetPoolHint());
+
+ if( mpDrawViewShell )
+ mpDrawViewShell->ModelHasChanged();
+
+}
+
+/**
+ * Redirect attributes onto title and outline text and background
+ * rectangle of a masterpage into templates, otherwise pass on baseclass.
+ */
+
+bool DrawView::SetAttributes(const SfxItemSet& rSet,
+ bool bReplaceAll, bool bSlide, bool bMaster)
+{
+ bool bOk = false;
+
+ if (mpDrawViewShell && bMaster)
+ {
+ SfxStyleSheetBasePool* pStShPool = mrDoc.GetStyleSheetPool();
+ SdPage& rPage = *mpDrawViewShell->getCurrentPage();
+ SdrPage& rMasterPage = rPage.TRG_GetMasterPage();
+ size_t nObjCount = rMasterPage.GetObjCount();
+ for (size_t nObj = 0; nObj < nObjCount; ++nObj)
+ {
+ SdrObject* pObject = rMasterPage.GetObj(nObj);
+ SetMasterAttributes(pObject, rPage, rSet, pStShPool, bOk, bMaster, bSlide);
+ }
+ return bOk;
+ }
+ if (mpDrawViewShell && bSlide)
+ {
+ SfxStyleSheetBasePool* pStShPool = mrDoc.GetStyleSheetPool();
+ SdPage& rPage = *mpDrawViewShell->getCurrentPage();
+ size_t nObjCount = rPage.GetObjCount();
+ for (size_t nObj = 0; nObj < nObjCount; ++nObj)
+ {
+ SdrObject* pObject = rPage.GetObj(nObj);
+ SetMasterAttributes(pObject, rPage, rSet, pStShPool, bOk, bMaster, bSlide);
+ }
+ return bOk;
+ }
+
+ // is there a masterpage edit?
+ if ( mpDrawViewShell && (mpDrawViewShell->GetEditMode() == EditMode::MasterPage) )
+ {
+ SfxStyleSheetBasePool* pStShPool = mrDoc.GetStyleSheetPool();
+ SdPage& rPage = *mpDrawViewShell->getCurrentPage();
+ SdrTextObj* pEditObject = GetTextEditObject();
+
+ if (pEditObject)
+ {
+ // Textedit
+
+ SdrInventor nInv = pEditObject->GetObjInventor();
+
+ if (nInv == SdrInventor::Default)
+ {
+ SdrObjKind eObjKind = pEditObject->GetObjIdentifier();
+ PresObjKind ePresObjKind = rPage.GetPresObjKind(pEditObject);
+
+ if ( ePresObjKind == PresObjKind::Title ||
+ ePresObjKind == PresObjKind::Notes )
+ {
+ // Presentation object (except outline)
+ SfxStyleSheet* pSheet = rPage.GetStyleSheetForPresObj( ePresObjKind );
+ DBG_ASSERT(pSheet, "StyleSheet not found");
+
+ SfxItemSet aTempSet( pSheet->GetItemSet() );
+ aTempSet.Put( rSet );
+ aTempSet.ClearInvalidItems();
+
+ // Undo-Action
+ mpDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<StyleSheetUndoAction>(&mrDoc, pSheet, &aTempSet));
+
+ pSheet->GetItemSet().Put(aTempSet);
+ pSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ bOk = true;
+ }
+ else if (eObjKind == SdrObjKind::OutlineText)
+ {
+ // Presentation object outline
+ OutlinerView* pOV = GetTextEditOutlinerView();
+ ::Outliner* pOutliner = pOV->GetOutliner();
+
+ pOutliner->SetUpdateLayout(false);
+ mpDocSh->SetWaitCursor( true );
+
+ // replace placeholder by template name
+ OUString aComment(SdResId(STR_UNDO_CHANGE_PRES_OBJECT));
+ aComment = aComment.replaceFirst("$", SdResId(STR_PSEUDOSHEET_OUTLINE));
+ mpDocSh->GetUndoManager()->EnterListAction( aComment, OUString(), 0, mpDrawViewShell->GetViewShellBase().GetViewShellId() );
+
+ std::vector<Paragraph*> aSelList;
+ pOV->CreateSelectionList(aSelList);
+
+ std::vector<Paragraph*>::reverse_iterator iter = aSelList.rbegin();
+ Paragraph* pPara = iter != aSelList.rend() ? *iter : nullptr;
+
+ while (pPara)
+ {
+ sal_Int32 nParaPos = pOutliner->GetAbsPos( pPara );
+ sal_Int16 nDepth = pOutliner->GetDepth( nParaPos );
+ OUString aName = rPage.GetLayoutName() + " " +
+ OUString::number((nDepth <= 0) ? 1 : nDepth + 1);
+ SfxStyleSheet* pSheet = static_cast<SfxStyleSheet*>(pStShPool->Find(aName, SfxStyleFamily::Page));
+ //We have no stylesheet if we access outline level 10
+ //in the master preview, there is no true style backing
+ //that entry
+ SAL_WARN_IF(!pSheet, "sd", "StyleSheet " << aName << " not found");
+ if (pSheet)
+ {
+ SfxItemSet aTempSet( pSheet->GetItemSet() );
+ aTempSet.Put( rSet );
+ aTempSet.ClearInvalidItems();
+
+ if( nDepth > 0 && aTempSet.GetItemState( EE_PARA_NUMBULLET ) == SfxItemState::SET )
+ {
+ // no SvxNumBulletItem in outline level 1 to 8!
+ aTempSet.ClearItem( EE_PARA_NUMBULLET );
+ }
+
+ // Undo-Action
+ mpDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<StyleSheetUndoAction>(&mrDoc, pSheet, &aTempSet));
+
+ pSheet->GetItemSet().Put(aTempSet);
+ pSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+
+ // now also broadcast any child sheets
+ sal_Int16 nChild;
+ for( nChild = nDepth + 1; nChild < 9; nChild++ )
+ {
+ OUString aSheetName = rPage.GetLayoutName() + " " +
+ OUString::number((nChild <= 0) ? 1 : nChild + 1);
+ SfxStyleSheet* pOutlSheet = static_cast< SfxStyleSheet* >(pStShPool->Find(aSheetName, SfxStyleFamily::Page));
+
+ if( pOutlSheet )
+ pOutlSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ }
+ }
+
+ ++iter;
+ pPara = iter != aSelList.rend() ? *iter : nullptr;
+
+ bool bJumpToLevel1 = false;
+ if( !pPara && nDepth > 0 && rSet.GetItemState( EE_PARA_NUMBULLET ) == SfxItemState::SET )
+ bJumpToLevel1 = true;
+
+ if (bJumpToLevel1)
+ {
+ iter = aSelList.rend();
+ --iter;
+
+ if (pOutliner->GetDepth(pOutliner->GetAbsPos(*iter)) > 0)
+ pPara = pOutliner->GetParagraph( 0 ); // Put NumBulletItem in outline level 1
+ }
+ }
+
+ mpDocSh->SetWaitCursor( false );
+ pOV->GetOutliner()->SetUpdateLayout(true);
+
+ mpDocSh->GetUndoManager()->LeaveListAction();
+
+ bOk = true;
+ }
+ else
+ {
+ bOk = ::sd::View::SetAttributes(rSet, bReplaceAll);
+ }
+ }
+ }
+ else
+ {
+ // Selection
+ const SdrMarkList& rList = GetMarkedObjectList();
+ const size_t nMarkCount = rList.GetMarkCount();
+ for (size_t nMark = 0; nMark < nMarkCount; ++nMark)
+ {
+ SdrObject* pObject = rList.GetMark(nMark)->GetMarkedSdrObj();
+ SetMasterAttributes(pObject, rPage, rSet, pStShPool, bOk, bMaster, bSlide);
+ }
+
+ if(!bOk)
+ bOk = ::sd::View::SetAttributes(rSet, bReplaceAll);
+ }
+ }
+ else // not at masterpage
+ {
+ bOk = ::sd::View::SetAttributes(rSet, bReplaceAll);
+ }
+
+ return bOk;
+}
+
+void DrawView::SetMasterAttributes( SdrObject* pObject, const SdPage& rPage, SfxItemSet rSet, SfxStyleSheetBasePool* pStShPool, bool& bOk, bool bMaster, bool bSlide )
+{
+ SdrInventor nInv = pObject->GetObjInventor();
+
+ if (nInv != SdrInventor::Default)
+ return;
+
+ SdrObjKind eObjKind = pObject->GetObjIdentifier();
+ PresObjKind ePresObjKind = rPage.GetPresObjKind(pObject);
+ if (bSlide && eObjKind == SdrObjKind::Text)
+ {
+ // Presentation object (except outline)
+ SfxStyleSheet* pSheet = rPage.GetTextStyleSheetForObject(pObject);
+ DBG_ASSERT(pSheet, "StyleSheet not found");
+
+ SfxItemSet aTempSet( pSheet->GetItemSet() );
+ aTempSet.Put( rSet );
+ aTempSet.ClearInvalidItems();
+
+ // Undo-Action
+ mpDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<StyleSheetUndoAction>(&mrDoc, pSheet, &aTempSet));
+
+ pSheet->GetItemSet().Put(aTempSet,false);
+ pSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ bOk = true;
+ }
+
+ if (!bSlide &&
+ (ePresObjKind == PresObjKind::Title ||
+ ePresObjKind == PresObjKind::Notes))
+ {
+ // Presentation object (except outline)
+ SfxStyleSheet* pSheet = rPage.GetStyleSheetForPresObj( ePresObjKind );
+ DBG_ASSERT(pSheet, "StyleSheet not found");
+
+ SfxItemSet aTempSet( pSheet->GetItemSet() );
+ aTempSet.Put( rSet );
+ aTempSet.ClearInvalidItems();
+
+ // Undo-Action
+ mpDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<StyleSheetUndoAction>(&mrDoc, pSheet, &aTempSet));
+
+ pSheet->GetItemSet().Put(aTempSet,false);
+ pSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ bOk = true;
+ }
+ else if (eObjKind == SdrObjKind::OutlineText)
+ {
+ // tdf#127900: do not forget to apply master style to placeholders
+ if (!rSet.HasItem(EE_PARA_NUMBULLET) || bMaster)
+ {
+ // Presentation object outline
+ for (sal_uInt16 nLevel = 9; nLevel > 0; nLevel--)
+ {
+ OUString aName = rPage.GetLayoutName() + " " +
+ OUString::number(nLevel);
+ SfxStyleSheet* pSheet = static_cast<SfxStyleSheet*>(pStShPool->
+ Find(aName, SfxStyleFamily::Page));
+ DBG_ASSERT(pSheet, "StyleSheet not found");
+
+ SfxItemSet aTempSet( pSheet->GetItemSet() );
+
+ if( nLevel > 1 )
+ {
+ // for all levels over 1, clear all items that will be
+ // hard set to level 1
+ SfxWhichIter aWhichIter(rSet);
+ sal_uInt16 nWhich(aWhichIter.FirstWhich());
+ while( nWhich )
+ {
+ if( SfxItemState::SET == aWhichIter.GetItemState() )
+ aTempSet.ClearItem( nWhich );
+ nWhich = aWhichIter.NextWhich();
+ }
+
+ }
+ else
+ {
+ // put the items hard into level one
+ aTempSet.Put( rSet );
+ }
+
+ aTempSet.ClearInvalidItems();
+
+ // Undo-Action
+ mpDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<StyleSheetUndoAction>(&mrDoc, pSheet, &aTempSet));
+
+ pSheet->GetItemSet().Set(aTempSet,false);
+ pSheet->Broadcast(SfxHint(SfxHintId::DataChanged));
+ }
+
+ // remove all hard set items from shape that are now set in style
+ SfxWhichIter aWhichIter(rSet);
+ sal_uInt16 nWhich(aWhichIter.FirstWhich());
+ while( nWhich )
+ {
+ if( SfxItemState::SET == aWhichIter.GetItemState() )
+ pObject->ClearMergedItem( nWhich );
+ nWhich = aWhichIter.NextWhich();
+ }
+ }
+ else
+ pObject->SetMergedItemSet(rSet);
+
+ bOk = true;
+ }
+}
+
+/**
+ * Notify for change of site arrangement
+ */
+
+void DrawView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ if ( mpDrawViewShell && rHint.GetId() == SfxHintId::ThisIsAnSdrHint )
+ {
+ SdrHintKind eHintKind = static_cast<const SdrHint&>(rHint).GetKind();
+
+ if ( mnPOCHSmph == 0 && eHintKind == SdrHintKind::PageOrderChange )
+ {
+ mpDrawViewShell->ResetActualPage();
+ }
+ else if ( eHintKind == SdrHintKind::LayerChange || eHintKind == SdrHintKind::LayerOrderChange )
+ {
+ mpDrawViewShell->ResetActualLayer();
+ }
+
+ // switch to that page when it's not a master page
+ if(SdrHintKind::SwitchToPage == eHintKind)
+ {
+ // We switch page only in the current view, which triggered this event
+ // and keep other views untouched.
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ if(pViewShell && pViewShell != &mpDrawViewShell->GetViewShellBase())
+ return;
+
+ const SdrPage* pPage = static_cast<const SdrHint&>(rHint).GetPage();
+ if(pPage && !pPage->IsMasterPage())
+ {
+ if(mpDrawViewShell->GetActualPage() != pPage)
+ {
+ sal_uInt16 nPageNum = (pPage->GetPageNum() - 1) / 2; // Sdr --> Sd
+ mpDrawViewShell->SwitchPage(nPageNum);
+ }
+ }
+ }
+ }
+
+ ::sd::View::Notify(rBC, rHint);
+}
+
+/**
+ * Lock/Unlock PageOrderChangedHint
+ */
+
+void DrawView::BlockPageOrderChangedHint(bool bBlock)
+{
+ if (bBlock)
+ mnPOCHSmph++;
+ else
+ {
+ DBG_ASSERT(mnPOCHSmph, "counter overflow");
+ mnPOCHSmph--;
+ }
+}
+
+/**
+ * If presentation objects are selected, intercept stylesheet-positioning at
+ * masterpage.
+ */
+
+bool DrawView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
+{
+ bool bResult = true;
+
+ // is there a masterpage edit?
+ if (mpDrawViewShell && mpDrawViewShell->GetEditMode() == EditMode::MasterPage)
+ {
+ if (IsPresObjSelected(false))
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(mpDrawViewShell->GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ bResult = false;
+ }
+ else
+ {
+ bResult = ::sd::View::SetStyleSheet(pStyleSheet, bDontRemoveHardAttr);
+ }
+ }
+ else
+ {
+ bResult = ::sd::View::SetStyleSheet(pStyleSheet, bDontRemoveHardAttr);
+ }
+ return bResult;
+}
+
+/**
+ * Paint-method: Redirect event to the view
+ */
+
+void DrawView::CompleteRedraw(OutputDevice* pOutDev, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector /*=0*/)
+{
+ bool bStandardPaint = true;
+
+ SdDrawDocument* pDoc = mpDocShell->GetDoc();
+ if( pDoc && pDoc->GetDocumentType() == DocumentType::Impress)
+ {
+ rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( pDoc ) );
+ if(xSlideshow.is() && xSlideshow->isRunning())
+ {
+ OutputDevice* pShowWindow = xSlideshow->getShowWindow();
+ if( (pShowWindow == pOutDev) || (xSlideshow->getAnimationMode() == ANIMATIONMODE_PREVIEW) )
+ {
+ if( pShowWindow == pOutDev && mpViewSh )
+ xSlideshow->paint();
+ bStandardPaint = false;
+ }
+ }
+ }
+
+ if(bStandardPaint)
+ {
+ ::sd::View::CompleteRedraw(pOutDev, rReg, pRedirector);
+ }
+}
+
+/**
+ * Make passed region visible (scrolling if necessary)
+ */
+
+void DrawView::MakeVisible(const ::tools::Rectangle& rRect, vcl::Window& rWin)
+{
+ if (!rRect.IsEmpty() && mpDrawViewShell)
+ {
+ mpDrawViewShell->MakeVisible(rRect, rWin);
+ }
+}
+
+/**
+ * Hide page.
+ */
+
+void DrawView::HideSdrPage()
+{
+ if (mpDrawViewShell)
+ {
+ mpDrawViewShell->HidePage();
+ }
+
+ ::sd::View::HideSdrPage();
+}
+
+void DrawView::DeleteMarked()
+{
+ sd::UndoManager* pUndoManager = mrDoc.GetUndoManager();
+ DBG_ASSERT( pUndoManager, "sd::DrawView::DeleteMarked(), ui action without undo manager!?" );
+
+ if( pUndoManager )
+ {
+ OUString aUndo(SvxResId(STR_EditDelete));
+ aUndo = aUndo.replaceFirst("%1", GetDescriptionOfMarkedObjects());
+ ViewShellId nViewShellId = mpDrawViewShell ? mpDrawViewShell->GetViewShellBase().GetViewShellId() : ViewShellId(-1);
+ pUndoManager->EnterListAction(aUndo, aUndo, 0, nViewShellId);
+ }
+
+ SdPage* pPage = nullptr;
+ bool bResetLayout = false;
+
+ const size_t nMarkCount = GetMarkedObjectList().GetMarkCount();
+ if( nMarkCount )
+ {
+ SdrMarkList aList( GetMarkedObjectList() );
+ for (size_t nMark = 0; nMark < nMarkCount; ++nMark)
+ {
+ SdrObject* pObj = aList.GetMark(nMark)->GetMarkedSdrObj();
+ if( pObj && !pObj->IsEmptyPresObj() && pObj->GetUserCall() )
+ {
+ pPage = static_cast< SdPage* >( pObj->getSdrPageFromSdrObject() );
+ if (pPage)
+ {
+ PresObjKind ePresObjKind(pPage->GetPresObjKind(pObj));
+ switch( ePresObjKind )
+ {
+ case PresObjKind::NONE:
+ continue; // ignore it
+ case PresObjKind::Graphic:
+ case PresObjKind::Object:
+ case PresObjKind::Chart:
+ case PresObjKind::OrgChart:
+ case PresObjKind::Table:
+ case PresObjKind::Calc:
+ case PresObjKind::Media:
+ ePresObjKind = PresObjKind::Outline;
+ break;
+ default:
+ break;
+ }
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObj );
+ bool bVertical = pTextObj && pTextObj->IsVerticalWriting();
+ ::tools::Rectangle aRect( pObj->GetLogicRect() );
+ SdrObject* pNewObj = pPage->InsertAutoLayoutShape( nullptr, ePresObjKind, bVertical, aRect, true );
+
+ // pUndoManager should not be NULL (see assert above)
+ // but since we have defensive code
+ // for it earlier and later in the function
+ // we might as well be consistent
+ if(pUndoManager)
+ {
+ // Move the new PresObj to the position before the
+ // object it will replace.
+ pUndoManager->AddUndoAction(
+ mrDoc.GetSdrUndoFactory().CreateUndoObjectOrdNum(
+ *pNewObj,
+ pNewObj->GetOrdNum(),
+ pObj->GetOrdNum()));
+ }
+ pPage->SetObjectOrdNum( pNewObj->GetOrdNum(), pObj->GetOrdNum() );
+
+ bResetLayout = true;
+ }
+ }
+ }
+ }
+
+ ::sd::View::DeleteMarked();
+
+ if( pPage && bResetLayout )
+ pPage->SetAutoLayout( pPage->GetAutoLayout() );
+
+ if( pUndoManager )
+ pUndoManager->LeaveListAction();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drbezob.cxx b/sd/source/ui/view/drbezob.cxx
new file mode 100644
index 000000000..c84489042
--- /dev/null
+++ b/sd/source/ui/view/drbezob.cxx
@@ -0,0 +1,320 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <BezierObjectBar.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objface.hxx>
+
+#include <svx/svxids.hrc>
+#include <svl/eitem.hxx>
+#include <sfx2/request.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdundo.hxx>
+#include <sfx2/dispatch.hxx>
+
+#include <sdresid.hxx>
+
+
+#include <strings.hrc>
+
+#include <DrawDocShell.hxx>
+#include <ViewShell.hxx>
+#include <drawdoc.hxx>
+#include <fusel.hxx>
+#include <fuconbez.hxx>
+
+using namespace sd;
+#define ShellClass_BezierObjectBar
+#include <sdslots.hxx>
+
+namespace sd {
+
+/**
+ * Declare default interface (Slotmap must not be empty)
+ */
+SFX_IMPL_INTERFACE(BezierObjectBar, ::SfxShell)
+
+void BezierObjectBar::InitInterface_Impl()
+{
+}
+
+
+BezierObjectBar::BezierObjectBar(
+ ViewShell* pSdViewShell,
+ ::sd::View* pSdView)
+ : SfxShell(pSdViewShell->GetViewShell()),
+ mpView(pSdView),
+ mpViewSh(pSdViewShell)
+{
+ DrawDocShell* pDocShell = mpViewSh->GetDocSh();
+ SetPool(&pDocShell->GetPool());
+ SetUndoManager(pDocShell->GetUndoManager());
+ SetRepeatTarget(mpView);
+}
+
+BezierObjectBar::~BezierObjectBar()
+{
+ SetRepeatTarget(nullptr);
+}
+
+/**
+ * Status of attribute items.
+ */
+
+void BezierObjectBar::GetAttrState(SfxItemSet& rSet)
+{
+ SfxItemSet aAttrSet( mpView->GetDoc().GetPool() );
+ mpView->GetAttributes( aAttrSet );
+ rSet.Put(aAttrSet, false); // <- sal_False, so DontCare-Status gets acquired
+
+ rtl::Reference<FuPoor> xFunc( mpViewSh->GetCurrentFunction() );
+
+ if(xFunc.is())
+ {
+ if( auto pFuSelection = dynamic_cast< const FuSelection *>( xFunc.get() ))
+ {
+ sal_uInt16 nEditMode = pFuSelection->GetEditMode();
+ rSet.Put(SfxBoolItem(nEditMode, true));
+ }
+ else if( auto pFuPolygon = dynamic_cast< const FuConstructBezierPolygon *>( xFunc.get() ))
+ {
+ sal_uInt16 nEditMode = pFuPolygon->GetEditMode();
+ rSet.Put(SfxBoolItem(nEditMode, true));
+ }
+ }
+
+ if(!mpView->IsMoveAllowed() || !mpView->IsResizeAllowed())
+ {
+ // #i77187# if object is move and/or size protected, do not allow point editing at all
+ rSet.DisableItem(SID_BEZIER_MOVE);
+ rSet.DisableItem(SID_BEZIER_INSERT);
+
+ rSet.DisableItem(SID_BEZIER_DELETE);
+ rSet.DisableItem(SID_BEZIER_CUTLINE);
+ rSet.DisableItem(SID_BEZIER_CONVERT);
+
+ rSet.DisableItem(SID_BEZIER_EDGE);
+ rSet.DisableItem(SID_BEZIER_SMOOTH);
+ rSet.DisableItem(SID_BEZIER_SYMMTR);
+
+ rSet.DisableItem(SID_BEZIER_CLOSE);
+
+ rSet.DisableItem(SID_BEZIER_ELIMINATE_POINTS);
+ }
+ else
+ {
+ IPolyPolygonEditorController* pIPPEC = nullptr;
+ if( mpView->GetMarkedObjectList().GetMarkCount() )
+ pIPPEC = mpView;
+ else
+ pIPPEC = dynamic_cast< IPolyPolygonEditorController* >( mpView->getSmartTags().getSelected().get() );
+
+ if ( !pIPPEC || !pIPPEC->IsRipUpAtMarkedPointsPossible())
+ {
+ rSet.DisableItem(SID_BEZIER_CUTLINE);
+ }
+ if (!pIPPEC || !pIPPEC->IsDeleteMarkedPointsPossible())
+ {
+ rSet.DisableItem(SID_BEZIER_DELETE);
+ }
+ if (!pIPPEC || !pIPPEC->IsSetMarkedSegmentsKindPossible())
+ {
+ rSet.DisableItem(SID_BEZIER_CONVERT);
+ }
+ else
+ {
+ SdrPathSegmentKind eSegm = pIPPEC->GetMarkedSegmentsKind();
+ switch (eSegm)
+ {
+ case SdrPathSegmentKind::DontCare: rSet.InvalidateItem(SID_BEZIER_CONVERT); break;
+ case SdrPathSegmentKind::Line : rSet.Put(SfxBoolItem(SID_BEZIER_CONVERT,false)); break; // Button down = curve
+ case SdrPathSegmentKind::Curve : rSet.Put(SfxBoolItem(SID_BEZIER_CONVERT,true)); break;
+ default: break;
+ }
+ }
+ if (!pIPPEC || !pIPPEC->IsSetMarkedPointsSmoothPossible())
+ {
+ rSet.DisableItem(SID_BEZIER_EDGE);
+ rSet.DisableItem(SID_BEZIER_SMOOTH);
+ rSet.DisableItem(SID_BEZIER_SYMMTR);
+ }
+ else
+ {
+ SdrPathSmoothKind eSmooth = pIPPEC->GetMarkedPointsSmooth();
+ switch (eSmooth)
+ {
+ case SdrPathSmoothKind::DontCare : break;
+ case SdrPathSmoothKind::Angular : rSet.Put(SfxBoolItem(SID_BEZIER_EDGE, true)); break;
+ case SdrPathSmoothKind::Asymmetric: rSet.Put(SfxBoolItem(SID_BEZIER_SMOOTH,true)); break;
+ case SdrPathSmoothKind::Symmetric : rSet.Put(SfxBoolItem(SID_BEZIER_SYMMTR,true)); break;
+ }
+ }
+ if (!pIPPEC || !pIPPEC->IsOpenCloseMarkedObjectsPossible())
+ {
+ rSet.DisableItem(SID_BEZIER_CLOSE);
+ }
+ else
+ {
+ SdrObjClosedKind eClose = pIPPEC->GetMarkedObjectsClosedState();
+ switch (eClose)
+ {
+ case SdrObjClosedKind::DontCare: rSet.InvalidateItem(SID_BEZIER_CLOSE); break;
+ case SdrObjClosedKind::Open : rSet.Put(SfxBoolItem(SID_BEZIER_CLOSE,false)); break;
+ case SdrObjClosedKind::Closed : rSet.Put(SfxBoolItem(SID_BEZIER_CLOSE,true)); break;
+ default: break;
+ }
+ }
+
+ if(pIPPEC == mpView)
+ rSet.Put(SfxBoolItem(SID_BEZIER_ELIMINATE_POINTS, mpView->IsEliminatePolyPoints()));
+ else
+ rSet.DisableItem( SID_BEZIER_ELIMINATE_POINTS ); // only works for views
+ }
+}
+
+/**
+ * Process SfxRequests
+ */
+
+void BezierObjectBar::Execute(SfxRequest& rReq)
+{
+ sal_uInt16 nSId = rReq.GetSlot();
+
+ switch (nSId)
+ {
+ case SID_BEZIER_CUTLINE:
+ case SID_BEZIER_CONVERT:
+ case SID_BEZIER_DELETE:
+ case SID_BEZIER_EDGE:
+ case SID_BEZIER_SMOOTH:
+ case SID_BEZIER_SYMMTR:
+ case SID_BEZIER_CLOSE:
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ IPolyPolygonEditorController* pIPPEC = nullptr;
+ if( rMarkList.GetMarkCount() )
+ pIPPEC = mpView;
+ else
+ pIPPEC = dynamic_cast< IPolyPolygonEditorController* >( mpView->getSmartTags().getSelected().get() );
+
+ if( pIPPEC && !mpView->IsAction())
+ {
+ switch (nSId)
+ {
+ case SID_BEZIER_DELETE:
+ pIPPEC->DeleteMarkedPoints();
+ break;
+
+ case SID_BEZIER_CUTLINE:
+ pIPPEC->RipUpAtMarkedPoints();
+ break;
+
+ case SID_BEZIER_CONVERT:
+ {
+ pIPPEC->SetMarkedSegmentsKind(SdrPathSegmentKind::Toggle);
+ break;
+ }
+
+ case SID_BEZIER_EDGE:
+ case SID_BEZIER_SMOOTH:
+ case SID_BEZIER_SYMMTR:
+ {
+ SdrPathSmoothKind eKind;
+
+ switch (nSId)
+ {
+ default:
+ case SID_BEZIER_EDGE: eKind = SdrPathSmoothKind::Angular; break;
+ case SID_BEZIER_SMOOTH: eKind = SdrPathSmoothKind::Asymmetric; break;
+ case SID_BEZIER_SYMMTR: eKind = SdrPathSmoothKind::Symmetric; break;
+ }
+
+ pIPPEC->SetMarkedPointsSmooth(eKind);
+ break;
+ }
+
+ case SID_BEZIER_CLOSE:
+ {
+ SdrPathObj* pPathObj = static_cast<SdrPathObj*>( rMarkList.GetMark(0)->GetMarkedSdrObj() );
+ const bool bUndo = mpView->IsUndoEnabled();
+ if( bUndo )
+ mpView->BegUndo(SdResId(STR_UNDO_BEZCLOSE));
+
+ mpView->UnmarkAllPoints();
+
+ if( bUndo )
+ mpView->AddUndo(mpView->GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPathObj));
+
+ pPathObj->ToggleClosed();
+
+ if( bUndo )
+ mpView->EndUndo();
+ break;
+ }
+ }
+ }
+
+ if( (pIPPEC == mpView) && !mpView->AreObjectsMarked() )
+ mpViewSh->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_BEZIER_ELIMINATE_POINTS:
+ {
+ mpView->SetEliminatePolyPoints(!mpView->IsEliminatePolyPoints());
+ Invalidate(SID_BEZIER_ELIMINATE_POINTS);
+ rReq.Done();
+ }
+ break;
+
+ case SID_BEZIER_MOVE:
+ case SID_BEZIER_INSERT:
+ {
+ rtl::Reference<FuPoor> xFunc( mpViewSh->GetCurrentFunction() );
+
+ if(xFunc.is())
+ {
+ if( auto pFuSelection = dynamic_cast<FuSelection *>( xFunc.get() ))
+ {
+ pFuSelection->SetEditMode(rReq.GetSlot());
+ }
+ else if( auto pFuPolygon = dynamic_cast<FuConstructBezierPolygon *>( xFunc.get() ))
+ {
+ pFuPolygon->SetEditMode(rReq.GetSlot());
+ }
+ }
+
+ rReq.Ignore ();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ Invalidate();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drtxtob.cxx b/sd/source/ui/view/drtxtob.cxx
new file mode 100644
index 000000000..b10af0828
--- /dev/null
+++ b/sd/source/ui/view/drtxtob.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 <TextObjectBar.hxx>
+
+#include <svx/svxids.hrc>
+
+#include <com/sun/star/linguistic2/XThesaurus.hpp>
+
+#include <editeng/eeitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/unolingu.hxx>
+#include <editeng/kernitem.hxx>
+#include <svl/whiter.hxx>
+#include <svl/itempool.hxx>
+#include <svl/stritem.hxx>
+#include <svl/style.hxx>
+#include <svl/languageoptions.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <sfx2/tplpitem.hxx>
+#include <editeng/escapementitem.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <editeng/writingmodeitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/fhgtitem.hxx>
+
+#include <sfx2/objface.hxx>
+
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <OutlineViewShell.hxx>
+#include <Window.hxx>
+#include <OutlineView.hxx>
+
+using namespace sd;
+using namespace ::com::sun::star;
+
+#define ShellClass_TextObjectBar
+#include <sdslots.hxx>
+
+namespace sd {
+
+/**
+ * Declare default interface (Slotmap must not be empty, therefore enter
+ * something that (hopefully) never occurs.
+ */
+SFX_IMPL_INTERFACE(TextObjectBar, SfxShell)
+
+void TextObjectBar::InitInterface_Impl()
+{
+}
+
+
+TextObjectBar::TextObjectBar (
+ ViewShell* pSdViewSh,
+ SfxItemPool& rItemPool,
+ ::sd::View* pSdView )
+ : SfxShell(pSdViewSh->GetViewShell()),
+ mpViewShell( pSdViewSh ),
+ mpView( pSdView )
+{
+ SetPool(&rItemPool);
+
+ if( mpView )
+ {
+ OutlineView* pOutlinerView = dynamic_cast< OutlineView* >( mpView );
+ if( pOutlinerView )
+ {
+ SetUndoManager(&pOutlinerView->GetOutliner().GetUndoManager());
+ }
+ else
+ {
+ DrawDocShell* pDocShell = mpView->GetDoc().GetDocSh();
+ if( pDocShell )
+ {
+ SetUndoManager(pDocShell->GetUndoManager());
+ DrawViewShell* pDrawViewShell = dynamic_cast< DrawViewShell* >( pSdViewSh );
+ if ( pDrawViewShell )
+ SetRepeatTarget(pSdView);
+ }
+ }
+ }
+
+ SetName( "TextObjectBar");
+
+ // SetHelpId( SD_IF_SDDRAWTEXTOBJECTBAR );
+}
+
+TextObjectBar::~TextObjectBar()
+{
+ SetRepeatTarget(nullptr);
+}
+
+void TextObjectBar::GetCharState( SfxItemSet& rSet )
+{
+ SfxItemSet aCharAttrSet( mpView->GetDoc().GetPool() );
+ mpView->GetAttributes( aCharAttrSet );
+
+ SfxItemSetFixed<EE_ITEMS_START,EE_ITEMS_END> aNewAttr( mpViewShell->GetPool() );
+
+ aNewAttr.Put(aCharAttrSet, false);
+ rSet.Put(aNewAttr, false);
+
+ SvxKerningItem aKern = aCharAttrSet.Get( EE_CHAR_KERNING );
+ //aKern.SetWhich(SID_ATTR_CHAR_KERNING);
+ rSet.Put(aKern);
+
+ SfxItemState eState = aCharAttrSet.GetItemState( EE_CHAR_KERNING );
+ if ( eState == SfxItemState::DONTCARE )
+ {
+ rSet.InvalidateItem(EE_CHAR_KERNING);
+ }
+}
+
+/**
+ * Status of attribute items.
+ */
+void TextObjectBar::GetAttrState( SfxItemSet& rSet )
+{
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ SfxItemSet aAttrSet( mpView->GetDoc().GetPool() );
+ bool bDisableParagraphTextDirection = !SvtCTLOptions().IsCTLFontEnabled();
+ bool bDisableVerticalText = !SvtCJKOptions::IsVerticalTextEnabled();
+
+ mpView->GetAttributes( aAttrSet );
+
+ while ( nWhich )
+ {
+ sal_uInt16 nSlotId = SfxItemPool::IsWhich(nWhich)
+ ? GetPool().GetSlotId(nWhich)
+ : nWhich;
+
+ switch ( nSlotId )
+ {
+ case SID_ATTR_CHAR_FONT:
+ case SID_ATTR_CHAR_FONTHEIGHT:
+ case SID_ATTR_CHAR_WEIGHT:
+ case SID_ATTR_CHAR_POSTURE:
+ case SID_ATTR_CHAR_SHADOWED:
+ case SID_ATTR_CHAR_STRIKEOUT:
+ case SID_ATTR_CHAR_CASEMAP:
+ {
+ sal_uInt16 stretchX = 100;
+ SvxScriptSetItem aSetItem( nSlotId, GetPool() );
+ aSetItem.GetItemSet().Put( aAttrSet, false );
+
+ SvtScriptType nScriptType = mpView->GetScriptType();
+
+ if( (nSlotId == SID_ATTR_CHAR_FONT) || (nSlotId == SID_ATTR_CHAR_FONTHEIGHT) )
+ {
+ // input language should be preferred over
+ // current cursor position to detect script type
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+ SdrOutliner *pOutliner = mpView->GetTextEditOutliner();
+
+ assert(mpViewShell);
+
+ if (OutlineView* pOView = dynamic_cast<OutlineView*>(mpView))
+ pOLV = pOView->GetViewByWindow(mpViewShell->GetActiveWindow());
+
+ sal_uInt16 stretchY = 100;
+ if( pOutliner )
+ pOutliner->GetGlobalCharStretching( stretchX, stretchY );
+
+ if(pOLV && !pOLV->GetSelection().HasRange())
+ {
+ if (mpViewShell->GetViewShell() && mpViewShell->GetViewShell()->GetWindow())
+ {
+ LanguageType nInputLang = mpViewShell->GetViewShell()->GetWindow()->GetInputLanguage();
+ if(nInputLang != LANGUAGE_DONTKNOW && nInputLang != LANGUAGE_SYSTEM)
+ nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( nInputLang );
+ }
+ }
+ }
+
+ const SfxPoolItem* pI = aSetItem.GetItemOfScript( nScriptType );
+ if( pI )
+ {
+ if( nSlotId == SID_ATTR_CHAR_FONTHEIGHT )
+ {
+ SvxFontHeightItem aFontItem = dynamic_cast<const SvxFontHeightItem&>(*pI);
+ aFontItem.SetHeight(aFontItem.GetHeight(), stretchX, aFontItem.GetPropUnit());
+ aFontItem.SetWhich(nWhich);
+ aAttrSet.Put( aFontItem );
+ }
+ else
+ {
+ aAttrSet.Put( pI->CloneSetWhich(nWhich) );
+ }
+ }
+ else
+ {
+ aAttrSet.InvalidateItem( nWhich );
+ }
+ }
+ break;
+
+ case SID_STYLE_APPLY:
+ case SID_STYLE_FAMILY2:
+ {
+ SfxStyleSheet* pStyleSheet = mpView->GetStyleSheetFromMarked();
+ if( pStyleSheet )
+ rSet.Put( SfxTemplateItem( nWhich, pStyleSheet->GetName() ) );
+ else
+ {
+ rSet.Put( SfxTemplateItem( nWhich, OUString() ) );
+ }
+ }
+ break;
+
+ case SID_OUTLINE_LEFT:
+ case SID_OUTLINE_RIGHT:
+ case SID_OUTLINE_UP:
+ case SID_OUTLINE_DOWN:
+ {
+ bool bDisableLeft = true;
+ bool bDisableRight = true;
+ bool bDisableUp = true;
+ bool bDisableDown = true;
+
+ //fdo#78151 it doesn't make sense to promote or demote outline levels in master view.
+ const DrawViewShell* pDrawViewShell = dynamic_cast< DrawViewShell* >(mpViewShell);
+ const bool bInMasterView = pDrawViewShell && pDrawViewShell->GetEditMode() == EditMode::MasterPage;
+
+ if (!bInMasterView)
+ {
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+
+ if (OutlineView* pOView = dynamic_cast<OutlineView*>(mpView))
+ pOLV = pOView->GetViewByWindow(mpViewShell->GetActiveWindow());
+
+ bool bOutlineViewSh = dynamic_cast< const OutlineViewShell *>( mpViewShell ) != nullptr;
+
+ if (pOLV)
+ {
+ // Outliner at outline-mode
+ ::Outliner* pOutl = pOLV->GetOutliner();
+
+ std::vector<Paragraph*> aSelList;
+ pOLV->CreateSelectionList(aSelList);
+ Paragraph* pPara = aSelList.empty() ? nullptr : *(aSelList.begin());
+
+ // find out if we are an OutlineView
+ bool bIsOutlineView(OutlinerMode::OutlineView == pOLV->GetOutliner()->GetOutlinerMode());
+
+ // This is ONLY for OutlineViews
+ if(bIsOutlineView)
+ {
+ // allow move up if position is 2 or greater OR it
+ // is a title object (and thus depth==1)
+ if(pOutl->GetAbsPos(pPara) > 1 || ( ::Outliner::HasParaFlag(pPara,ParaFlag::ISPAGE) && pOutl->GetAbsPos(pPara) > 0 ) )
+ {
+ // not at top
+ bDisableUp = false;
+ }
+ }
+ else
+ {
+ // old behaviour for OutlinerMode::OutlineObject
+ if(pOutl->GetAbsPos(pPara) > 0)
+ {
+ // not at top
+ bDisableUp = false;
+ }
+ }
+
+ for (const auto& rpItem : aSelList)
+ {
+ pPara = rpItem;
+
+ sal_Int16 nDepth = pOutl->GetDepth( pOutl->GetAbsPos( pPara ) );
+
+ if (nDepth > 0 || (bOutlineViewSh && (nDepth <= 0) && !::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE )) )
+ {
+ // not minimum depth
+ bDisableLeft = false;
+ }
+
+ if( (nDepth < pOLV->GetOutliner()->GetMaxDepth() && ( !bOutlineViewSh || pOutl->GetAbsPos(pPara) != 0 )) ||
+ (bOutlineViewSh && (nDepth <= 0) && ::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) && pOutl->GetAbsPos(pPara) != 0) )
+ {
+ // not maximum depth and not at top
+ bDisableRight = false;
+ }
+ }
+
+ if ( ( pOutl->GetAbsPos(pPara) < pOutl->GetParagraphCount() - 1 ) &&
+ ( pOutl->GetParagraphCount() > 1 || !bOutlineViewSh) )
+ {
+ // not last paragraph
+ bDisableDown = false;
+ }
+
+ // disable when first para and 2nd is not a title
+ pPara = aSelList.empty() ? nullptr : *(aSelList.begin());
+
+ if(!bDisableDown && bIsOutlineView
+ && pPara
+ && 0 == pOutl->GetAbsPos(pPara)
+ && pOutl->GetParagraphCount() > 1
+ && !::Outliner::HasParaFlag( pOutl->GetParagraph(1), ParaFlag::ISPAGE ) )
+ {
+ // Needs to be disabled
+ bDisableDown = true;
+ }
+ }
+ }
+
+ if (bDisableLeft)
+ rSet.DisableItem(SID_OUTLINE_LEFT);
+ if (bDisableRight)
+ rSet.DisableItem(SID_OUTLINE_RIGHT);
+ if (bDisableUp)
+ rSet.DisableItem(SID_OUTLINE_UP);
+ if (bDisableDown)
+ rSet.DisableItem(SID_OUTLINE_DOWN);
+ }
+ break;
+
+ case SID_TEXTDIRECTION_LEFT_TO_RIGHT:
+ case SID_TEXTDIRECTION_TOP_TO_BOTTOM:
+ {
+ if ( bDisableVerticalText )
+ {
+ rSet.DisableItem( SID_TEXTDIRECTION_LEFT_TO_RIGHT );
+ rSet.DisableItem( SID_TEXTDIRECTION_TOP_TO_BOTTOM );
+ }
+ else
+ {
+ bool bLeftToRight = true;
+
+ SdrOutliner* pOutl = mpView->GetTextEditOutliner();
+ if( pOutl )
+ {
+ if( pOutl->IsVertical() )
+ bLeftToRight = false;
+ }
+ else
+ bLeftToRight = aAttrSet.Get( SDRATTR_TEXTDIRECTION ).GetValue() == css::text::WritingMode_LR_TB;
+
+ rSet.Put( SfxBoolItem( SID_TEXTDIRECTION_LEFT_TO_RIGHT, bLeftToRight ) );
+ rSet.Put( SfxBoolItem( SID_TEXTDIRECTION_TOP_TO_BOTTOM, !bLeftToRight ) );
+
+ if( !bLeftToRight )
+ bDisableParagraphTextDirection = true;
+ }
+ }
+ break;
+
+ case SID_ULINE_VAL_NONE:
+ case SID_ULINE_VAL_SINGLE:
+ case SID_ULINE_VAL_DOUBLE:
+ case SID_ULINE_VAL_DOTTED:
+ {
+ if( aAttrSet.GetItemState( EE_CHAR_UNDERLINE ) >= SfxItemState::DEFAULT )
+ {
+ FontLineStyle eLineStyle = aAttrSet.Get(EE_CHAR_UNDERLINE).GetLineStyle();
+
+ switch (nSlotId)
+ {
+ case SID_ULINE_VAL_NONE:
+ rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_NONE));
+ break;
+ case SID_ULINE_VAL_SINGLE:
+ rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_SINGLE));
+ break;
+ case SID_ULINE_VAL_DOUBLE:
+ rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_DOUBLE));
+ break;
+ case SID_ULINE_VAL_DOTTED:
+ rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_DOTTED));
+ break;
+ }
+ }
+ }
+ break;
+
+ case SID_GROW_FONT_SIZE:
+ case SID_SHRINK_FONT_SIZE:
+ {
+ // todo
+ }
+ break;
+
+ case SID_THES:
+ {
+ if (mpView->GetTextEditOutlinerView())
+ {
+ EditView & rEditView = mpView->GetTextEditOutlinerView()->GetEditView();
+ OUString aStatusVal;
+ LanguageType nLang = LANGUAGE_NONE;
+ bool bIsLookUpWord = GetStatusValueForThesaurusFromContext( aStatusVal, nLang, rEditView );
+ rSet.Put( SfxStringItem( SID_THES, aStatusVal ) );
+
+ // disable "Thesaurus" context menu entry if there is nothing to look up
+ uno::Reference< linguistic2::XThesaurus > xThes( LinguMgr::GetThesaurus() );
+ if (!bIsLookUpWord ||
+ !xThes.is() || nLang == LANGUAGE_NONE || !xThes->hasLocale( LanguageTag( nLang). getLocale() ))
+ rSet.DisableItem( SID_THES );
+ }
+ else
+ {
+ rSet.DisableItem( SID_THES );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+
+ rSet.Put( aAttrSet, false ); // <- sal_False, so DontCare-Status gets acquired
+
+ // these are disabled in outline-mode
+ if (!mpViewShell || dynamic_cast< const DrawViewShell *>( mpViewShell ) == nullptr)
+ {
+ rSet.DisableItem( SID_ATTR_PARA_ADJUST_LEFT );
+ rSet.DisableItem( SID_ATTR_PARA_ADJUST_RIGHT );
+ rSet.DisableItem( SID_ATTR_PARA_ADJUST_CENTER );
+ rSet.DisableItem( SID_ATTR_PARA_ADJUST_BLOCK );
+ rSet.DisableItem( SID_ATTR_PARA_LINESPACE_10 );
+ rSet.DisableItem( SID_ATTR_PARA_LINESPACE_15 );
+ rSet.DisableItem( SID_ATTR_PARA_LINESPACE_20 );
+ rSet.DisableItem( SID_DEC_INDENT );
+ rSet.DisableItem( SID_INC_INDENT );
+ rSet.DisableItem( SID_PARASPACE_INCREASE );
+ rSet.DisableItem( SID_PARASPACE_DECREASE );
+ rSet.DisableItem( SID_TEXTDIRECTION_TOP_TO_BOTTOM );
+ rSet.DisableItem( SID_TEXTDIRECTION_LEFT_TO_RIGHT );
+ rSet.DisableItem( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ rSet.DisableItem( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ }
+ else
+ {
+ // paragraph spacing
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+ if( pOLV )
+ {
+ ESelection aSel = pOLV->GetSelection();
+ aSel.Adjust();
+ sal_Int32 nStartPara = aSel.nStartPara;
+ sal_Int32 nEndPara = aSel.nEndPara;
+ if( !aSel.HasRange() )
+ {
+ nStartPara = 0;
+ nEndPara = pOLV->GetOutliner()->GetParagraphCount() - 1;
+ }
+ ::tools::Long nUpper = 0;
+
+ for( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ )
+ {
+ const SfxItemSet& rItems = pOLV->GetOutliner()->GetParaAttribs( nPara );
+ const SvxULSpaceItem& rItem = rItems.Get( EE_PARA_ULSPACE );
+ nUpper = std::max( nUpper, static_cast<::tools::Long>(rItem.GetUpper()) );
+ }
+ if( nUpper == 0 )
+ rSet.DisableItem( SID_PARASPACE_DECREASE );
+ }
+ else
+ {
+ // never disabled at the moment!
+ //rSet.DisableItem( SID_PARASPACE_INCREASE );
+ //rSet.DisableItem( SID_PARASPACE_DECREASE );
+ }
+
+ // paragraph justification
+ const SvxLRSpaceItem& aLR = aAttrSet.Get( EE_PARA_LRSPACE );
+ rSet.Put(aLR);
+ SvxAdjust eAdj = aAttrSet.Get( EE_PARA_JUST ).GetAdjust();
+ switch( eAdj )
+ {
+ case SvxAdjust::Left:
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, true ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, false ) );
+ break;
+ case SvxAdjust::Center:
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, true ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, false ) );
+ break;
+ case SvxAdjust::Right:
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, true ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, false ) );
+ break;
+ case SvxAdjust::Block:
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, true ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, false ) );
+ break;
+ default:
+ break;
+ }
+
+ Invalidate(SID_ATTR_PARA_ADJUST_LEFT);
+ Invalidate(SID_ATTR_PARA_ADJUST_CENTER);
+ Invalidate(SID_ATTR_PARA_ADJUST_RIGHT);
+ Invalidate(SID_ATTR_PARA_ADJUST_BLOCK);
+ Invalidate(SID_ATTR_PARA_LINESPACE);
+ Invalidate(SID_ATTR_PARA_ULSPACE);
+
+ // paragraph text direction
+ if( bDisableParagraphTextDirection )
+ {
+ rSet.DisableItem( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ rSet.DisableItem( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ }
+ else
+ {
+ switch( aAttrSet.Get( EE_PARA_WRITINGDIR ).GetValue() )
+ {
+ case SvxFrameDirection::Vertical_LR_TB:
+ case SvxFrameDirection::Vertical_RL_TB:
+ {
+ rSet.DisableItem( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ rSet.DisableItem( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ }
+ break;
+
+ case SvxFrameDirection::Horizontal_LR_TB:
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LEFT_TO_RIGHT, true ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_RIGHT_TO_LEFT, false ) );
+ break;
+
+ case SvxFrameDirection::Horizontal_RL_TB:
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LEFT_TO_RIGHT, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_RIGHT_TO_LEFT, true ) );
+ break;
+
+ // The case for the superordinate object is missing.
+ case SvxFrameDirection::Environment:
+ {
+ SdDrawDocument& rDoc = mpView->GetDoc();
+ css::text::WritingMode eMode = rDoc.GetDefaultWritingMode();
+ bool bIsLeftToRight(false);
+
+ if(css::text::WritingMode_LR_TB == eMode
+ || css::text::WritingMode_TB_RL == eMode)
+ {
+ bIsLeftToRight = true;
+ }
+
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LEFT_TO_RIGHT, bIsLeftToRight ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_RIGHT_TO_LEFT, !bIsLeftToRight ) );
+ }
+ break;
+ default: break;
+ }
+ }
+
+ SvxLRSpaceItem aLRSpace = aAttrSet.Get( EE_PARA_LRSPACE );
+ aLRSpace.SetWhich(SID_ATTR_PARA_LRSPACE);
+ rSet.Put(aLRSpace);
+ Invalidate(SID_ATTR_PARA_LRSPACE);
+
+ //Added by xuxu
+ SfxItemState eState = aAttrSet.GetItemState( EE_PARA_LRSPACE );
+ if ( eState == SfxItemState::DONTCARE )
+ {
+ rSet.InvalidateItem(EE_PARA_LRSPACE);
+ rSet.InvalidateItem(SID_ATTR_PARA_LRSPACE);
+ }
+ sal_uInt16 nLineSpace = aAttrSet.Get( EE_PARA_SBL ).GetPropLineSpace();
+ switch( nLineSpace )
+ {
+ case 100:
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_10, true ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_15, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_20, false ) );
+ break;
+ case 150:
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_15, true ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_10, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_20, false ) );
+ break;
+ case 200:
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_20, true ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_10, false ) );
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_15, false ) );
+ break;
+ }
+ }
+
+ // justification (superscript, subscript) is also needed in outline-mode
+ SvxEscapement eEsc = static_cast<SvxEscapement>(aAttrSet.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue());
+ rSet.Put(SfxBoolItem(SID_SET_SUPER_SCRIPT, eEsc == SvxEscapement::Superscript));
+ rSet.Put(SfxBoolItem(SID_SET_SUB_SCRIPT, eEsc == SvxEscapement::Subscript));
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drtxtob1.cxx b/sd/source/ui/view/drtxtob1.cxx
new file mode 100644
index 000000000..86b7a698a
--- /dev/null
+++ b/sd/source/ui/view/drtxtob1.cxx
@@ -0,0 +1,865 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TextObjectBar.hxx>
+
+#include <svx/svxids.hrc>
+
+#include <editeng/eeitem.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/numitem.hxx>
+#include <svl/itempool.hxx>
+#include <svl/stritem.hxx>
+#include <svl/style.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/shdditem.hxx>
+#include <svx/svdpagv.hxx>
+#include <editeng/flstitem.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <editeng/writingmodeitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/cmapitem.hxx>
+
+#include <app.hrc>
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <prlayout.hxx>
+#include <ViewShell.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <stlpool.hxx>
+#include <stlsheet.hxx>
+#include <OutlineView.hxx>
+#include <Window.hxx>
+#include <futempl.hxx>
+#include <DrawDocShell.hxx>
+#include <futext.hxx>
+#include <editeng/colritem.hxx>
+
+#include <memory>
+
+namespace
+{
+ void lcl_convertStringArguments(sal_uInt16 nSlot, const std::unique_ptr<SfxItemSet>& pArgs)
+ {
+ Color aColor;
+ OUString sColor;
+ const SfxPoolItem* pColorStringItem = nullptr;
+
+ if (SfxItemState::SET != pArgs->GetItemState(SID_ATTR_COLOR_STR, false, &pColorStringItem))
+ return;
+
+ sColor = static_cast<const SfxStringItem*>(pColorStringItem)->GetValue();
+
+ if (sColor == "transparent")
+ aColor = COL_TRANSPARENT;
+ else
+ aColor = Color(ColorTransparency, sColor.toInt32(16));
+
+ switch (nSlot)
+ {
+ case SID_ATTR_CHAR_COLOR:
+ {
+ SvxColorItem aColorItem(aColor, EE_CHAR_COLOR);
+ pArgs->Put(aColorItem);
+ break;
+ }
+
+ case SID_ATTR_CHAR_BACK_COLOR:
+ {
+ SvxColorItem pBackgroundItem(aColor, EE_CHAR_BKGCOLOR);
+ pArgs->Put(pBackgroundItem);
+ break;
+ }
+ }
+ }
+}
+
+namespace sd {
+
+/**
+ * Process SfxRequests
+ */
+
+void TextObjectBar::Execute( SfxRequest &rReq )
+{
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+ OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
+
+ std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard;
+
+ assert(mpViewShell);
+
+ if (OutlineView* pOView = dynamic_cast<OutlineView*>(mpView))
+ {
+ pOLV = pOView->GetViewByWindow(mpViewShell->GetActiveWindow());
+ aGuard.reset( new OutlineViewModelChangeGuard( static_cast<OutlineView&>(*mpView) ) );
+ }
+
+ switch (nSlot)
+ {
+ case SID_STYLE_APPLY:
+ {
+ if( pArgs )
+ {
+ SdDrawDocument& rDoc = mpView->GetDoc();
+ assert(mpViewShell->GetViewShell());
+ rtl::Reference<FuPoor> xFunc( FuTemplate::Create( mpViewShell, static_cast< ::sd::Window*>( mpViewShell->GetViewShell()->GetWindow()), mpView, &rDoc, rReq ) );
+
+ if(xFunc.is())
+ {
+ xFunc->Activate();
+ xFunc->Deactivate();
+
+ if( rReq.GetSlot() == SID_STYLE_APPLY )
+ {
+ if (mpViewShell->GetViewFrame())
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_STYLE_APPLY );
+ }
+ }
+ }
+ else
+ {
+ if (mpViewShell->GetViewFrame())
+ mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_STYLE_DESIGNER, SfxCallMode::ASYNCHRON );
+ }
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_INC_INDENT:
+ case SID_DEC_INDENT:
+ {
+ if( pOLV )
+ {
+ ESelection aSel = pOLV->GetSelection();
+ aSel.Adjust();
+ sal_Int32 nStartPara = aSel.nStartPara;
+ sal_Int32 nEndPara = aSel.nEndPara;
+ if( !aSel.HasRange() )
+ {
+ nStartPara = 0;
+ nEndPara = pOLV->GetOutliner()->GetParagraphCount() - 1;
+ }
+
+ pOLV->GetOutliner()->UndoActionStart( OLUNDO_ATTR );
+ for( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ )
+ {
+ SfxStyleSheet* pStyleSheet = nullptr;
+ if (pOLV->GetOutliner() != nullptr)
+ pStyleSheet = pOLV->GetOutliner()->GetStyleSheet(nPara);
+ if (pStyleSheet != nullptr)
+ {
+ SfxItemSet aAttr( pStyleSheet->GetItemSet() );
+ SfxItemSet aTmpSet( pOLV->GetOutliner()->GetParaAttribs( nPara ) );
+ aAttr.Put( aTmpSet, false );
+ const SvxLRSpaceItem& rItem = aAttr.Get( EE_PARA_LRSPACE );
+ std::unique_ptr<SvxLRSpaceItem> pNewItem(rItem.Clone());
+
+ ::tools::Long nLeft = pNewItem->GetLeft();
+ if( nSlot == SID_INC_INDENT )
+ nLeft += 1000;
+ else
+ {
+ nLeft -= 1000;
+ nLeft = std::max<::tools::Long>( nLeft, 0 );
+ }
+ pNewItem->SetLeftValue( static_cast<sal_uInt16>(nLeft) );
+
+ SfxItemSet aNewAttrs( aAttr );
+ aNewAttrs.Put( std::move(pNewItem) );
+ pOLV->GetOutliner()->SetParaAttribs( nPara, aNewAttrs );
+ }
+ }
+ pOLV->GetOutliner()->UndoActionEnd();
+ mpViewShell->Invalidate( SID_UNDO );
+ }
+ rReq.Done();
+
+ Invalidate();
+ // to refresh preview (in outline mode), slot has to be invalidated:
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true );
+
+ }
+ break;
+
+ case SID_PARASPACE_INCREASE:
+ case SID_PARASPACE_DECREASE:
+ {
+ if( pOLV )
+ {
+ ESelection aSel = pOLV->GetSelection();
+ aSel.Adjust();
+ sal_Int32 nStartPara = aSel.nStartPara;
+ sal_Int32 nEndPara = aSel.nEndPara;
+ if( !aSel.HasRange() )
+ {
+ nStartPara = 0;
+ nEndPara = pOLV->GetOutliner()->GetParagraphCount() - 1;
+ }
+
+ pOLV->GetOutliner()->UndoActionStart( OLUNDO_ATTR );
+ for( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ )
+ {
+ SfxStyleSheet* pStyleSheet = nullptr;
+ if (pOLV->GetOutliner() != nullptr)
+ pStyleSheet = pOLV->GetOutliner()->GetStyleSheet(nPara);
+ if (pStyleSheet != nullptr)
+ {
+ SfxItemSet aAttr( pStyleSheet->GetItemSet() );
+ SfxItemSet aTmpSet( pOLV->GetOutliner()->GetParaAttribs( nPara ) );
+ aAttr.Put( aTmpSet, false ); // sal_False= InvalidItems is not default, handle it as "holes"
+ const SvxULSpaceItem& rItem = aAttr.Get( EE_PARA_ULSPACE );
+ std::unique_ptr<SvxULSpaceItem> pNewItem(rItem.Clone());
+
+ ::tools::Long nUpper = pNewItem->GetUpper();
+ if( nSlot == SID_PARASPACE_INCREASE )
+ nUpper += 100;
+ else
+ {
+ nUpper -= 100;
+ nUpper = std::max<::tools::Long>( nUpper, 0 );
+ }
+ pNewItem->SetUpper( static_cast<sal_uInt16>(nUpper) );
+
+ ::tools::Long nLower = pNewItem->GetLower();
+ if( nSlot == SID_PARASPACE_INCREASE )
+ nLower += 100;
+ else
+ {
+ nLower -= 100;
+ nLower = std::max<::tools::Long>( nLower, 0 );
+ }
+ pNewItem->SetLower( static_cast<sal_uInt16>(nLower) );
+
+ SfxItemSet aNewAttrs( aAttr );
+ aNewAttrs.Put( std::move(pNewItem) );
+ pOLV->GetOutliner()->SetParaAttribs( nPara, aNewAttrs );
+ }
+ }
+ pOLV->GetOutliner()->UndoActionEnd();
+ mpViewShell->Invalidate( SID_UNDO );
+ }
+ else
+ {
+ // the following code could be enabled, if I get a correct
+ // DontCare status from JOE.
+
+ // gets enabled, through it doesn't really work (see above)
+ SfxItemSet aEditAttr( mpView->GetDoc().GetPool() );
+ mpView->GetAttributes( aEditAttr );
+ if( aEditAttr.GetItemState( EE_PARA_ULSPACE ) >= SfxItemState::DEFAULT )
+ {
+ SfxItemSet aNewAttrs(*(aEditAttr.GetPool()), aEditAttr.GetRanges());
+ const SvxULSpaceItem& rItem = aEditAttr.Get( EE_PARA_ULSPACE );
+ std::unique_ptr<SvxULSpaceItem> pNewItem(rItem.Clone());
+ ::tools::Long nUpper = pNewItem->GetUpper();
+
+ if( nSlot == SID_PARASPACE_INCREASE )
+ nUpper += 100;
+ else
+ {
+ nUpper -= 100;
+ nUpper = std::max<::tools::Long>( nUpper, 0 );
+ }
+ pNewItem->SetUpper( static_cast<sal_uInt16>(nUpper) );
+
+ ::tools::Long nLower = pNewItem->GetLower();
+ if( nSlot == SID_PARASPACE_INCREASE )
+ nLower += 100;
+ else
+ {
+ nLower -= 100;
+ nLower = std::max<::tools::Long>( nLower, 0 );
+ }
+ pNewItem->SetLower( static_cast<sal_uInt16>(nLower) );
+
+ aNewAttrs.Put( std::move(pNewItem) );
+
+ mpView->SetAttributes( aNewAttrs );
+ }
+ }
+ rReq.Done();
+
+ Invalidate();
+ // to refresh preview (in outline mode), slot has to be invalidated:
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true );
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_PARA_ULSPACE, true );
+ }
+ break;
+
+ case SID_OUTLINE_LEFT:
+ {
+ if (pOLV)
+ {
+ pOLV->AdjustDepth( -1 );
+
+ // Ensure bold/italic etc. icon state updates
+ Invalidate();
+ // trigger preview refresh
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true );
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_OUTLINE_RIGHT:
+ {
+ if (pOLV)
+ {
+ pOLV->AdjustDepth( 1 );
+
+ // Ensure bold/italic etc. icon state updates
+ Invalidate();
+ // trigger preview refresh
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true );
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_ATTR_PARA_LRSPACE:
+ {
+ SvxLRSpaceItem aLRSpace = static_cast<const SvxLRSpaceItem&>(pArgs->Get(
+ SID_ATTR_PARA_LRSPACE));
+
+ SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aEditAttr( GetPool() );
+ aLRSpace.SetWhich( EE_PARA_LRSPACE );
+
+ aEditAttr.Put( aLRSpace );
+ mpView->SetAttributes( aEditAttr );
+
+ Invalidate(SID_ATTR_PARA_LRSPACE);
+ }
+ break;
+
+ case SID_HANGING_INDENT:
+ {
+ SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aLRSpaceSet( GetPool() );
+ mpView->GetAttributes( aLRSpaceSet );
+ SvxLRSpaceItem aParaMargin( aLRSpaceSet.Get( EE_PARA_LRSPACE ) );
+
+ SvxLRSpaceItem aNewMargin( EE_PARA_LRSPACE );
+ aNewMargin.SetTextLeft( aParaMargin.GetTextLeft() + aParaMargin.GetTextFirstLineOffset() );
+ aNewMargin.SetRight( aParaMargin.GetRight() );
+ aNewMargin.SetTextFirstLineOffset( ( aParaMargin.GetTextFirstLineOffset() ) * -1 );
+ aLRSpaceSet.Put( aNewMargin );
+ mpView->SetAttributes( aLRSpaceSet );
+
+ Invalidate(SID_ATTR_PARA_LRSPACE);
+ }
+ break;
+
+ case SID_OUTLINE_UP:
+ {
+ if (pOLV)
+ {
+ pOLV->AdjustHeight( -1 );
+
+ // trigger preview refresh
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true );
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_OUTLINE_DOWN:
+ {
+ if (pOLV)
+ {
+ pOLV->AdjustHeight( 1 );
+
+ // trigger preview refresh
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true );
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_TEXTDIRECTION_LEFT_TO_RIGHT:
+ case SID_TEXTDIRECTION_TOP_TO_BOTTOM:
+ {
+ mpView->SdrEndTextEdit();
+ // tdf#131571: SdrEndTextEdit invalidates pTextEditOutlinerView, the pointer retrieved for pOLV
+ // so reinitialize pOLV
+ pOLV=mpView->GetTextEditOutlinerView();
+ SfxItemSetFixed<SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION> aAttr( mpView->GetDoc().GetPool() );
+ aAttr.Put( SvxWritingModeItem(
+ nSlot == SID_TEXTDIRECTION_LEFT_TO_RIGHT ?
+ css::text::WritingMode_LR_TB : css::text::WritingMode_TB_RL,
+ SDRATTR_TEXTDIRECTION ) );
+ rReq.Done( aAttr );
+ mpView->SetAttributes( aAttr );
+ Invalidate();
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true );
+ }
+ break;
+
+ case FN_NUM_BULLET_ON:
+ {
+ if (pOLV)
+ {
+ bool bMasterPage = false;
+ SdrPageView* pPageView = mpView->GetSdrPageView();
+ if (pPageView)
+ {
+ SdPage* pPage = static_cast<SdPage*>(pPageView->GetPage());
+ bMasterPage = pPage && (pPage->GetPageKind() == PageKind::Standard) && pPage->IsMasterPage();
+ }
+
+ if (!bMasterPage)
+ pOLV->ToggleBullets();
+ else
+ {
+ //Resolves: fdo#78151 in master pages if we toggle bullets on
+ //and off then just disable/enable the bulleting, but do not
+ //change the *level* of the paragraph, because the paragraph is
+ //effectively a preview of the equivalent style level, and
+ //changing the level disconnects it from the style
+
+ ::Outliner* pOL = pOLV->GetOutliner();
+ if (pOL)
+ {
+ const SvxNumBulletItem *pItem = nullptr;
+ SfxStyleSheetBasePool* pSSPool = mpView->GetDocSh()->GetStyleSheetPool();
+ OUString sStyleName(SdResId(STR_PSEUDOSHEET_OUTLINE) + " 1");
+ SfxStyleSheetBase* pFirstStyleSheet = pSSPool->Find(sStyleName, SfxStyleFamily::Pseudo);
+ if( pFirstStyleSheet )
+ pItem = pFirstStyleSheet->GetItemSet().GetItemIfSet(EE_PARA_NUMBULLET, false);
+
+ if (pItem )
+ {
+ SvxNumRule aNewRule(pItem->GetNumRule());
+ ESelection aSel = pOLV->GetSelection();
+ aSel.Adjust();
+ sal_Int32 nStartPara = aSel.nStartPara;
+ sal_Int32 nEndPara = aSel.nEndPara;
+ for (sal_Int32 nPara = nStartPara; nPara <= nEndPara; ++nPara)
+ {
+ sal_uInt16 nLevel = pOL->GetDepth(nPara);
+ SvxNumberFormat aFmt(aNewRule.GetLevel(nLevel));
+
+ if (aFmt.GetNumberingType() == SVX_NUM_NUMBER_NONE)
+ {
+ aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
+ SdStyleSheetPool::setDefaultOutlineNumberFormatBulletAndIndent(nLevel, aFmt);
+ }
+ else
+ {
+ aFmt.SetNumberingType(SVX_NUM_NUMBER_NONE);
+ aFmt.SetAbsLSpace(0);
+ aFmt.SetFirstLineOffset(0);
+ }
+
+ aNewRule.SetLevel(nLevel, aFmt);
+ }
+
+ pFirstStyleSheet->GetItemSet().Put(SvxNumBulletItem(std::move(aNewRule), EE_PARA_NUMBULLET));
+
+ SdStyleSheet::BroadcastSdStyleSheetChange(pFirstStyleSheet, PresentationObjects::Outline_1, pSSPool);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case SID_GROW_FONT_SIZE:
+ case SID_SHRINK_FONT_SIZE:
+ {
+ const SvxFontListItem* pFonts = static_cast<const SvxFontListItem*>(mpViewShell->GetDocSh()->GetItem( SID_ATTR_CHAR_FONTLIST ));
+ const FontList* pFontList = pFonts ? pFonts->GetFontList(): nullptr;
+ if( pFontList )
+ {
+ FuText::ChangeFontSize( nSlot == SID_GROW_FONT_SIZE, pOLV, pFontList, mpView );
+ if( pOLV )
+ pOLV->SetAttribs( pOLV->GetEditView().GetEmptyItemSet() );
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_THES:
+ {
+ OUString aReplaceText;
+ const SfxStringItem* pItem2 = rReq.GetArg(FN_PARAM_THES_WORD_REPLACE);
+ if (pItem2)
+ aReplaceText = pItem2->GetValue();
+ if (!aReplaceText.isEmpty())
+ ReplaceTextWithSynonym( pOLV->GetEditView(), aReplaceText );
+ }
+ break;
+
+ default:
+ {
+ SfxItemSet aEditAttr( mpView->GetDoc().GetPool() );
+ mpView->GetAttributes( aEditAttr );
+ SfxItemSet aNewAttr(*(aEditAttr.GetPool()), aEditAttr.GetRanges());
+
+ if( !pArgs )
+ {
+ //aNewAttr.InvalidateAllItems(); <- produces problems (#35465#)
+
+ switch ( nSlot )
+ {
+ case SID_ATTR_CHAR_WEIGHT:
+ {
+ FontWeight eFW = aEditAttr.Get( EE_CHAR_WEIGHT ).GetWeight();
+ aNewAttr.Put( SvxWeightItem( eFW == WEIGHT_NORMAL ?
+ WEIGHT_BOLD : WEIGHT_NORMAL,
+ EE_CHAR_WEIGHT ) );
+ }
+ break;
+ case SID_ATTR_CHAR_POSTURE:
+ {
+ FontItalic eFI = aEditAttr.Get( EE_CHAR_ITALIC ).GetPosture();
+ aNewAttr.Put( SvxPostureItem( eFI == ITALIC_NORMAL ?
+ ITALIC_NONE : ITALIC_NORMAL,
+ EE_CHAR_ITALIC ) );
+ }
+ break;
+ case SID_ATTR_CHAR_UNDERLINE:
+ {
+ FontLineStyle eFU = aEditAttr.Get( EE_CHAR_UNDERLINE ).GetLineStyle();
+ aNewAttr.Put( SvxUnderlineItem( eFU == LINESTYLE_SINGLE ?
+ LINESTYLE_NONE : LINESTYLE_SINGLE,
+ EE_CHAR_UNDERLINE ) );
+ }
+ break;
+
+ case SID_ULINE_VAL_NONE:
+ {
+ aNewAttr.Put(SvxUnderlineItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE));
+ break;
+ }
+
+ case SID_ULINE_VAL_SINGLE:
+ case SID_ULINE_VAL_DOUBLE:
+ case SID_ULINE_VAL_DOTTED:
+ {
+ FontLineStyle eOld = aEditAttr.Get(EE_CHAR_UNDERLINE).GetLineStyle();
+ FontLineStyle eNew = eOld;
+
+ switch (nSlot)
+ {
+ case SID_ULINE_VAL_SINGLE:
+ eNew = ( eOld == LINESTYLE_SINGLE ) ? LINESTYLE_NONE : LINESTYLE_SINGLE;
+ break;
+ case SID_ULINE_VAL_DOUBLE:
+ eNew = ( eOld == LINESTYLE_DOUBLE ) ? LINESTYLE_NONE : LINESTYLE_DOUBLE;
+ break;
+ case SID_ULINE_VAL_DOTTED:
+ eNew = ( eOld == LINESTYLE_DOTTED ) ? LINESTYLE_NONE : LINESTYLE_DOTTED;
+ break;
+ }
+
+ SvxUnderlineItem aUnderline(eNew, EE_CHAR_UNDERLINE);
+ aNewAttr.Put(aUnderline);
+ }
+ break;
+
+ case SID_ATTR_CHAR_OVERLINE:
+ {
+ FontLineStyle eFO = aEditAttr.Get( EE_CHAR_OVERLINE ).GetLineStyle();
+ aNewAttr.Put( SvxOverlineItem( eFO == LINESTYLE_SINGLE ?
+ LINESTYLE_NONE : LINESTYLE_SINGLE,
+ EE_CHAR_OVERLINE ) );
+ }
+ break;
+ case SID_ATTR_CHAR_CONTOUR:
+ {
+ aNewAttr.Put( SvxContourItem( !aEditAttr.Get( EE_CHAR_OUTLINE ).GetValue(), EE_CHAR_OUTLINE ) );
+ }
+ break;
+ case SID_ATTR_CHAR_SHADOWED:
+ {
+ aNewAttr.Put( SvxShadowedItem( !aEditAttr.Get( EE_CHAR_SHADOW ).GetValue(), EE_CHAR_SHADOW ) );
+ }
+ break;
+ case SID_ATTR_CHAR_CASEMAP:
+ {
+ aNewAttr.Put( aEditAttr.Get( EE_CHAR_CASEMAP ) );
+ }
+ break;
+ case SID_ATTR_CHAR_STRIKEOUT:
+ {
+ FontStrikeout eFSO = aEditAttr.Get( EE_CHAR_STRIKEOUT ).GetStrikeout();
+ aNewAttr.Put( SvxCrossedOutItem( eFSO == STRIKEOUT_SINGLE ?
+ STRIKEOUT_NONE : STRIKEOUT_SINGLE, EE_CHAR_STRIKEOUT ) );
+ }
+ break;
+
+ case SID_ATTR_PARA_ADJUST_LEFT:
+ {
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
+ }
+ break;
+ case SID_ATTR_PARA_ADJUST_CENTER:
+ {
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
+ }
+ break;
+ case SID_ATTR_PARA_ADJUST_RIGHT:
+ {
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+ }
+ break;
+ case SID_ATTR_PARA_ADJUST_BLOCK:
+ {
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Block, EE_PARA_JUST ) );
+ }
+ break;
+ case SID_ATTR_PARA_LINESPACE_10:
+ {
+ SvxLineSpacingItem aItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL );
+ aItem.SetPropLineSpace( 100 );
+ aNewAttr.Put( aItem );
+ }
+ break;
+ case SID_ATTR_PARA_LINESPACE_15:
+ {
+ SvxLineSpacingItem aItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL );
+ aItem.SetPropLineSpace( 150 );
+ aNewAttr.Put( aItem );
+ }
+ break;
+ case SID_ATTR_PARA_LINESPACE_20:
+ {
+ SvxLineSpacingItem aItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL );
+ aItem.SetPropLineSpace( 200 );
+ aNewAttr.Put( aItem );
+ }
+ break;
+ case SID_SET_SUPER_SCRIPT:
+ {
+ SvxEscapementItem aItem( EE_CHAR_ESCAPEMENT );
+ SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue());
+
+ if( eEsc == SvxEscapement::Superscript )
+ aItem.SetEscapement( SvxEscapement::Off );
+ else
+ aItem.SetEscapement( SvxEscapement::Superscript );
+ aNewAttr.Put( aItem );
+ }
+ break;
+ case SID_SET_SUB_SCRIPT:
+ {
+ SvxEscapementItem aItem( EE_CHAR_ESCAPEMENT );
+ SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue());
+
+ if( eEsc == SvxEscapement::Subscript )
+ aItem.SetEscapement( SvxEscapement::Off );
+ else
+ aItem.SetEscapement( SvxEscapement::Subscript );
+ aNewAttr.Put( aItem );
+ }
+ break;
+
+ // attributes for TextObjectBar
+ case SID_ATTR_CHAR_FONT:
+ mpViewShell->GetViewFrame()->GetDispatcher()->
+ Execute( SID_CHAR_DLG, SfxCallMode::ASYNCHRON );
+ break;
+ case SID_ATTR_CHAR_FONTHEIGHT:
+ mpViewShell->GetViewFrame()->GetDispatcher()->
+ Execute( SID_CHAR_DLG, SfxCallMode::ASYNCHRON );
+ break;
+ case SID_ATTR_CHAR_COLOR:
+ break;
+// #i35937# removed need for FN_NUM_BULLET_ON handling
+ }
+
+ rReq.Done( aNewAttr );
+ pArgs = rReq.GetArgs();
+ }
+ else if ( nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT ||
+ nSlot == SID_ATTR_PARA_RIGHT_TO_LEFT )
+ {
+ bool bLeftToRight = nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT;
+
+ SvxAdjust nAdjust = SvxAdjust::Left;
+ if( const SvxAdjustItem* pAdjustItem = aEditAttr.GetItemIfSet(EE_PARA_JUST) )
+ nAdjust = pAdjustItem->GetAdjust();
+
+ if( bLeftToRight )
+ {
+ aNewAttr.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) );
+ if( nAdjust == SvxAdjust::Right )
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
+ }
+ else
+ {
+ aNewAttr.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
+ if( nAdjust == SvxAdjust::Left )
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+ }
+
+ rReq.Done( aNewAttr );
+ pArgs = rReq.GetArgs();
+
+ Invalidate( SID_RULER_TEXT_RIGHT_TO_LEFT );
+ }
+ else if ( nSlot == SID_ATTR_CHAR_FONT ||
+ nSlot == SID_ATTR_CHAR_FONTHEIGHT ||
+ nSlot == SID_ATTR_CHAR_POSTURE ||
+ nSlot == SID_ATTR_CHAR_WEIGHT )
+ {
+ // #i78017 establish the same behaviour as in Writer
+ SvtScriptType nScriptType = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
+ if (nSlot == SID_ATTR_CHAR_FONT)
+ nScriptType = mpView->GetScriptType();
+
+ SfxItemPool& rPool = mpView->GetDoc().GetPool();
+ SvxScriptSetItem aSvxScriptSetItem( nSlot, rPool );
+ aSvxScriptSetItem.PutItemForScriptType( nScriptType, pArgs->Get( rPool.GetWhich( nSlot ) ) );
+ aNewAttr.Put( aSvxScriptSetItem.GetItemSet() );
+ rReq.Done( aNewAttr );
+ pArgs = rReq.GetArgs();
+ }
+ else if (nSlot == SID_ATTR_PARA_ADJUST_LEFT ||
+ nSlot == SID_ATTR_PARA_ADJUST_CENTER ||
+ nSlot == SID_ATTR_PARA_ADJUST_RIGHT ||
+ nSlot == SID_ATTR_PARA_ADJUST_BLOCK)
+ {
+ switch( nSlot )
+ {
+ case SID_ATTR_PARA_ADJUST_LEFT:
+ {
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
+ }
+ break;
+ case SID_ATTR_PARA_ADJUST_CENTER:
+ {
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
+ }
+ break;
+ case SID_ATTR_PARA_ADJUST_RIGHT:
+ {
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+ }
+ break;
+ case SID_ATTR_PARA_ADJUST_BLOCK:
+ {
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Block, EE_PARA_JUST ) );
+ }
+ break;
+ }
+ rReq.Done( aNewAttr );
+ pArgs = rReq.GetArgs();
+ }
+ else if(nSlot == SID_ATTR_CHAR_KERNING)
+ {
+ aNewAttr.Put(pArgs->Get(pArgs->GetPool()->GetWhich(nSlot)));
+ rReq.Done( aNewAttr );
+ pArgs = rReq.GetArgs();
+ }
+ else if(nSlot == SID_SET_SUPER_SCRIPT )
+ {
+ SvxEscapementItem aItem(EE_CHAR_ESCAPEMENT);
+ SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue());
+
+ if( eEsc == SvxEscapement::Superscript )
+ aItem.SetEscapement( SvxEscapement::Off );
+ else
+ aItem.SetEscapement( SvxEscapement::Superscript );
+ aNewAttr.Put( aItem );
+ rReq.Done( aNewAttr );
+ pArgs = rReq.GetArgs();
+ }
+ else if( nSlot == SID_SET_SUB_SCRIPT )
+ {
+ SvxEscapementItem aItem(EE_CHAR_ESCAPEMENT);
+ SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue());
+
+ if( eEsc == SvxEscapement::Subscript )
+ aItem.SetEscapement( SvxEscapement::Off );
+ else
+ aItem.SetEscapement( SvxEscapement::Subscript );
+ aNewAttr.Put( aItem );
+ rReq.Done( aNewAttr );
+ pArgs = rReq.GetArgs();
+ }
+
+ std::unique_ptr<SfxItemSet> pNewArgs = pArgs->Clone();
+ lcl_convertStringArguments(nSlot, pNewArgs);
+
+ // Merge the color parameters to the color itself.
+ std::unique_ptr<SvxColorItem> pColorItem;
+ if (nSlot == SID_ATTR_CHAR_COLOR)
+ {
+ pColorItem = std::make_unique<SvxColorItem>(pNewArgs->Get(EE_CHAR_COLOR));
+ }
+ if (const SfxInt16Item* pIntItem = pArgs->GetItemIfSet(SID_ATTR_COLOR_THEME_INDEX, false))
+ {
+ pColorItem->GetThemeColor().SetThemeIndex(pIntItem->GetValue());
+ }
+ if (const SfxInt16Item* pIntItem = pArgs->GetItemIfSet(SID_ATTR_COLOR_LUM_MOD, false))
+ {
+ pColorItem->GetThemeColor().SetLumMod(pIntItem->GetValue());
+ }
+ if (const SfxInt16Item* pIntItem = pArgs->GetItemIfSet(SID_ATTR_COLOR_LUM_OFF, false))
+ {
+ pColorItem->GetThemeColor().SetLumOff(pIntItem->GetValue());
+ }
+ if (pColorItem)
+ {
+ pNewArgs->Put(std::move(pColorItem));
+ }
+
+ mpView->SetAttributes(*pNewArgs);
+
+ // invalidate entire shell because of performance and
+ // extension reasons
+ Invalidate();
+
+ // to refresh preview (in outline mode), slot has to be invalidated:
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true );
+ }
+ break;
+ }
+
+ if ( nSlot != SID_STYLE_APPLY && pOLV )
+ {
+ pOLV->ShowCursor();
+ pOLV->GetWindow()->GrabFocus();
+ }
+
+ Invalidate( SID_OUTLINE_LEFT );
+ Invalidate( SID_OUTLINE_RIGHT );
+ Invalidate( SID_OUTLINE_UP );
+ Invalidate( SID_OUTLINE_DOWN );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviews1.cxx b/sd/source/ui/view/drviews1.cxx
new file mode 100644
index 000000000..085bc93f2
--- /dev/null
+++ b/sd/source/ui/view/drviews1.cxx
@@ -0,0 +1,1360 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawViewShell.hxx>
+#include <ViewShellImplementation.hxx>
+
+#include <DrawController.hxx>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+#include <comphelper/scopeguard.hxx>
+#include <rtl/ref.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/svdpagv.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <svx/svdoole2.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <vcl/scrbar.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/fmshell.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/graphicfilter.hxx>
+
+#include <view/viewoverlaymanager.hxx>
+
+#include <app.hrc>
+
+#include <fupoor.hxx>
+#include <unokywds.hxx>
+#include <sdpage.hxx>
+#include <FrameView.hxx>
+#include <Window.hxx>
+#include <drawview.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <Ruler.hxx>
+#include <Client.hxx>
+#include <slideshow.hxx>
+#include <AnimationChildWindow.hxx>
+#include <ToolBarManager.hxx>
+#include <FormShellManager.hxx>
+#include <ViewShellBase.hxx>
+#include <LayerTabBar.hxx>
+#include <ViewShellManager.hxx>
+#include <ViewShellHint.hxx>
+#include <SlideSorter.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsPageSelector.hxx>
+
+#include <comphelper/lok.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+void DrawViewShell::Activate(bool bIsMDIActivate)
+{
+ ViewShell::Activate(bIsMDIActivate);
+
+ // When the mode is switched to normal the main view shell grabs focus.
+ // This is done for getting cut/copy/paste commands on slides in the left
+ // pane (slide sorter view shell) to work properly.
+ SfxShell* pTopViewShell = this->GetViewShellBase().GetViewShellManager()->GetTopViewShell();
+ if (pTopViewShell && pTopViewShell == this)
+ {
+ this->GetActiveWindow()->GrabFocus();
+ }
+}
+
+void DrawViewShell::UIActivating( SfxInPlaceClient* pCli )
+{
+ ViewShell::UIActivating(pCli);
+
+ // Disable own controls
+ maTabControl->Disable();
+ if (GetLayerTabControl() != nullptr)
+ GetLayerTabControl()->Disable();
+}
+
+void DrawViewShell::UIDeactivated( SfxInPlaceClient* pCli )
+{
+ // Enable own controls
+ maTabControl->Enable();
+ if (GetLayerTabControl() != nullptr)
+ GetLayerTabControl()->Enable();
+
+ ViewShell::UIDeactivated(pCli);
+}
+
+void DrawViewShell::Deactivate(bool bIsMDIActivate)
+{
+ // Temporarily disable context broadcasting while the Deactivate()
+ // call is forwarded to our base class.
+ const bool bIsContextBroadcasterEnabled (SfxShell::SetContextBroadcasterEnabled(false));
+
+ ViewShell::Deactivate(bIsMDIActivate);
+
+ SfxShell::SetContextBroadcasterEnabled(bIsContextBroadcasterEnabled);
+}
+
+namespace
+{
+ class LockUI
+ {
+ private:
+ void Lock(bool bLock);
+ SfxViewFrame *mpFrame;
+ public:
+ explicit LockUI(SfxViewFrame *pFrame) : mpFrame(pFrame) { Lock(true); }
+ ~LockUI() { Lock(false); }
+
+ };
+
+ void LockUI::Lock(bool bLock)
+ {
+ if (!mpFrame)
+ return;
+ mpFrame->Enable( !bLock );
+ }
+}
+
+/**
+ * Called, if state of selection of view is changed
+ */
+
+void DrawViewShell::SelectionHasChanged()
+{
+ Invalidate();
+
+ //Update3DWindow(); // 3D-Controller
+ SfxBoolItem aItem( SID_3D_STATE, true );
+ GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_3D_STATE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+
+ SdrOle2Obj* pOleObj = nullptr;
+
+ if ( mpDrawView->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+
+ if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::OLE2)
+ {
+ pOleObj = static_cast<SdrOle2Obj*>(pObj);
+ UpdateIMapDlg( pObj );
+ }
+ else if (nSdrObjKind == SdrObjKind::Graphic)
+ UpdateIMapDlg( pObj );
+ }
+ }
+
+ ViewShellBase& rBase = GetViewShellBase();
+ rBase.SetVerbs( uno::Sequence< embed::VerbDescriptor >() );
+
+ try
+ {
+ Client* pIPClient = static_cast<Client*>(rBase.GetIPClient());
+ if ( pIPClient && pIPClient->IsObjectInPlaceActive() )
+ {
+ // as appropriate take ole-objects into account and deactivate
+
+ // this means we recently deselected an inplace active ole object so
+ // we need to deselect it now
+ if (!pOleObj)
+ {
+ //#i47279# disable frame until after object has completed unload
+ LockUI aUILock(GetViewFrame());
+ pIPClient->DeactivateObject();
+ //HMHmpDrView->ShowMarkHdl();
+ }
+ else
+ {
+ const uno::Reference < embed::XEmbeddedObject >& xObj = pOleObj->GetObjRef();
+ if ( xObj.is() )
+ {
+ rBase.SetVerbs( xObj->getSupportedVerbs() );
+ }
+ else
+ {
+ rBase.SetVerbs( uno::Sequence < embed::VerbDescriptor >() );
+ }
+ }
+ }
+ else
+ {
+ if ( pOleObj )
+ {
+ const uno::Reference < embed::XEmbeddedObject >& xObj = pOleObj->GetObjRef();
+ if ( xObj.is() )
+ {
+ rBase.SetVerbs( xObj->getSupportedVerbs() );
+ }
+ else
+ {
+ rBase.SetVerbs( uno::Sequence < embed::VerbDescriptor >() );
+ }
+ }
+ else
+ {
+ rBase.SetVerbs( uno::Sequence < embed::VerbDescriptor >() );
+ }
+ }
+ }
+ catch( css::uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "sd::DrawViewShell::SelectionHasChanged()" );
+ }
+
+ if( HasCurrentFunction() )
+ {
+ GetCurrentFunction()->SelectionHasChanged();
+ }
+ else
+ {
+ GetViewShellBase().GetToolBarManager()->SelectionHasChanged(*this,*mpDrawView);
+ }
+
+ // Invalidate for every subshell
+ GetViewShellBase().GetViewShellManager()->InvalidateAllSubShells(this);
+
+ mpDrawView->UpdateSelectionClipboard();
+
+ GetViewShellBase().GetDrawController().FireSelectionChangeListener();
+}
+
+namespace {
+
+void collectUIInformation(const OUString& aZoom)
+{
+ EventDescription aDescription;
+ aDescription.aID = "impress_win";
+ aDescription.aParameters = {{"ZOOM", aZoom}};
+ aDescription.aAction = "SET";
+ aDescription.aKeyWord = "ImpressWindowUIObject";
+ aDescription.aParent = "MainWindow";
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+/**
+ * set zoom factor
+ */
+void DrawViewShell::SetZoom( ::tools::Long nZoom )
+{
+ // Make sure that the zoom factor will not be recalculated on
+ // following window resizings.
+ mbZoomOnPage = false;
+ ViewShell::SetZoom( nZoom );
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM );
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
+ mpViewOverlayManager->onZoomChanged();
+ collectUIInformation(OUString::number(nZoom));
+}
+
+/**
+ * Set zoom rectangle for active window
+ */
+
+void DrawViewShell::SetZoomRect( const ::tools::Rectangle& rZoomRect )
+{
+ ViewShell::SetZoomRect( rZoomRect );
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM );
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
+ mpViewOverlayManager->onZoomChanged();
+}
+
+/**
+ * PrepareClose, as appropriate end text input, so other viewshells
+ * discover a refreshed text object.
+ */
+
+bool DrawViewShell::PrepareClose( bool bUI )
+{
+ if ( !ViewShell::PrepareClose(bUI) )
+ return false;
+
+ if( HasCurrentFunction() )
+ {
+ sal_uInt16 nID = GetCurrentFunction()->GetSlotID();
+ if (nID == SID_TEXTEDIT || nID == SID_ATTR_CHAR)
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+ }
+
+ return true;
+}
+
+
+/**
+ * Set status (enabled/disabled) of menu SfxSlots
+ */
+
+void DrawViewShell::ChangeEditMode(EditMode eEMode, bool bIsLayerModeActive)
+{
+ if (meEditMode == eEMode && mbIsLayerModeActive == bIsLayerModeActive)
+ return;
+
+ ViewShellManager::UpdateLock aLock (GetViewShellBase().GetViewShellManager());
+
+ sal_uInt16 nActualPageId = maTabControl->GetPageId(0);
+
+ if (mePageKind == PageKind::Handout)
+ {
+ // at handouts only allow MasterPage
+ eEMode = EditMode::MasterPage;
+ }
+
+ GetViewShellBase().GetDrawController().FireChangeEditMode (eEMode == EditMode::MasterPage);
+ GetViewShellBase().GetDrawController().FireChangeLayerMode (bIsLayerModeActive);
+
+ if ( mpDrawView->IsTextEdit() )
+ {
+ // This exits the text edit mode when going in and out of window focus, which is not needed
+ // Let's keep this call as comment for now as it probably just needs a better conditional.
+ // mpDrawView->SdrEndTextEdit();
+ }
+
+ LayerTabBar* pLayerBar = GetLayerTabControl();
+ if (pLayerBar != nullptr)
+ pLayerBar->EndEditMode();
+ maTabControl->EndEditMode();
+
+ GetViewShellBase().GetDrawController().BroadcastContextChange();
+
+ meEditMode = eEMode;
+
+ if(pLayerBar)
+ {
+ // #i87182# only switch activation mode of LayerTabBar when there is one,
+ // else it will not get initialized with the current set of Layers as needed
+ mbIsLayerModeActive = bIsLayerModeActive;
+ }
+
+ // Determine whether to show the master view toolbar. The master
+ // page mode has to be active and the shell must not be a handout
+ // view.
+ bool bShowMasterViewToolbar (meEditMode == EditMode::MasterPage
+ && GetShellType() != ViewShell::ST_HANDOUT);
+ bool bShowPresentationToolbar (meEditMode != EditMode::MasterPage
+ && GetShellType() != ViewShell::ST_HANDOUT
+ && GetShellType() != ViewShell::ST_DRAW);
+
+ // If the master view toolbar is not shown we hide it before
+ // switching the edit mode.
+ if (::sd::ViewShell::mpImpl->mbIsInitialized
+ && IsMainViewShell())
+ {
+ if ( !bShowMasterViewToolbar )
+ GetViewShellBase().GetToolBarManager()->ResetToolBars(ToolBarManager::ToolBarGroup::MasterMode);
+ if ( !bShowPresentationToolbar )
+ GetViewShellBase().GetToolBarManager()->ResetToolBars(ToolBarManager::ToolBarGroup::CommonTask);
+ }
+
+ ConfigureAppBackgroundColor();
+
+ if (meEditMode == EditMode::Page)
+ {
+ /******************************************************************
+ * PAGEMODE
+ ******************************************************************/
+
+ maTabControl->Clear();
+
+ SdPage* pPage;
+ sal_uInt16 nPageCnt = GetDoc()->GetSdPageCount(mePageKind);
+
+ for (sal_uInt16 i = 0; i < nPageCnt; i++)
+ {
+ pPage = GetDoc()->GetSdPage(i, mePageKind);
+ OUString aPageName = pPage->GetName();
+ maTabControl->InsertPage(pPage->getPageId(), aPageName);
+
+ if ( pPage->IsSelected() )
+ {
+ nActualPageId = pPage->getPageId();
+ }
+ }
+
+ maTabControl->SetCurPageId(nActualPageId);
+
+ SwitchPage(maTabControl->GetPagePos(nActualPageId));
+
+ //tdf#102343 re-enable common undo on switch back from master mode
+ mpDrawView->GetModel()->SetDisableTextEditUsesCommonUndoManager(false);
+ }
+ else
+ {
+ /******************************************************************
+ * MASTERPAGE
+ ******************************************************************/
+ GetViewFrame()->SetChildWindow(
+ AnimationChildWindow::GetChildWindowId(), false );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED,
+ ".uno:SlideMasterPage=true");
+ if (!mpActualPage)
+ {
+ // as long as there is no mpActualPage, take first
+ mpActualPage = GetDoc()->GetSdPage(0, mePageKind);
+ }
+
+ maTabControl->Clear();
+ sal_uInt16 nActualMasterPageId = maTabControl->GetPageId(0);
+ sal_uInt16 nMasterPageCnt = GetDoc()->GetMasterSdPageCount(mePageKind);
+
+ for (sal_uInt16 i = 0; i < nMasterPageCnt; i++)
+ {
+ SdPage* pMaster = GetDoc()->GetMasterSdPage(i, mePageKind);
+ OUString aLayoutName = pMaster->GetLayoutName();
+ sal_Int32 nPos = aLayoutName.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ aLayoutName = aLayoutName.copy(0, nPos);
+
+ maTabControl->InsertPage(pMaster->getPageId(), aLayoutName);
+
+ if (&(mpActualPage->TRG_GetMasterPage()) == pMaster)
+ {
+ nActualMasterPageId = pMaster->getPageId();
+ }
+ }
+
+ maTabControl->SetCurPageId(nActualMasterPageId);
+ SwitchPage(maTabControl->GetPagePos(nActualMasterPageId));
+
+ //tdf#102343 changing attributes of textboxes in master typically
+ //changes the stylesheet they are linked to, so if the common
+ //undo manager is in use, those stylesheet changes are thrown
+ //away at present
+ mpDrawView->GetModel()->SetDisableTextEditUsesCommonUndoManager(true);
+ }
+
+ // If the master view toolbar is to be shown we turn it on after the
+ // edit mode has been changed.
+ if (::sd::ViewShell::mpImpl->mbIsInitialized
+ && IsMainViewShell())
+ {
+ if (bShowMasterViewToolbar)
+ GetViewShellBase().GetToolBarManager()->SetToolBar(
+ ToolBarManager::ToolBarGroup::MasterMode,
+ ToolBarManager::msMasterViewToolBar);
+ if (bShowPresentationToolbar)
+ GetViewShellBase().GetToolBarManager()->SetToolBar(
+ ToolBarManager::ToolBarGroup::CommonTask,
+ ToolBarManager::msCommonTaskToolBar);
+ }
+
+ if ( ! mbIsLayerModeActive)
+ {
+ maTabControl->Show();
+ // Set the tab control only for draw pages. For master page
+ // this has been done already above.
+ if (meEditMode == EditMode::Page)
+ maTabControl->SetCurPageId (nActualPageId);
+ }
+
+ ResetActualLayer();
+
+ Invalidate( SID_PAGEMODE );
+ Invalidate( SID_LAYERMODE );
+ Invalidate( SID_MASTERPAGE );
+ Invalidate( SID_DELETE_MASTER_PAGE );
+ Invalidate( SID_DELETE_PAGE );
+ Invalidate( SID_SLIDE_MASTER_MODE );
+ Invalidate( SID_NOTES_MASTER_MODE );
+ Invalidate( SID_HANDOUT_MASTER_MODE );
+ InvalidateWindows();
+
+ SetContextName(GetSidebarContextName());
+
+}
+
+/**
+ * Generate horizontal ruler
+ */
+
+VclPtr<SvxRuler> DrawViewShell::CreateHRuler (::sd::Window* pWin)
+{
+ VclPtr<Ruler> pRuler;
+ WinBits aWBits;
+ SvxRulerSupportFlags nFlags = SvxRulerSupportFlags::OBJECT;
+
+ aWBits = WB_HSCROLL | WB_3DLOOK | WB_BORDER | WB_EXTRAFIELD;
+ nFlags |= SvxRulerSupportFlags::SET_NULLOFFSET |
+ SvxRulerSupportFlags::TABS |
+ SvxRulerSupportFlags::PARAGRAPH_MARGINS; // new
+
+ pRuler = VclPtr<Ruler>::Create(*this, GetParentWindow(), pWin, nFlags,
+ GetViewFrame()->GetBindings(), aWBits);
+
+ // Metric ...
+ sal_uInt16 nMetric = static_cast<sal_uInt16>(GetDoc()->GetUIUnit());
+
+ if( nMetric == 0xffff )
+ nMetric = static_cast<sal_uInt16>(GetViewShellBase().GetViewFrame()->GetDispatcher()->GetModule()->GetFieldUnit());
+
+ pRuler->SetUnit( FieldUnit( nMetric ) );
+
+ // ... and also set DefTab at the ruler
+ pRuler->SetDefTabDist( GetDoc()->GetDefaultTabulator() ); // new
+
+ Fraction aUIScale(pWin->GetMapMode().GetScaleX());
+ aUIScale *= GetDoc()->GetUIScale();
+ pRuler->SetZoom(aUIScale);
+
+ return pRuler;
+}
+
+/**
+ * Generate vertical ruler
+ */
+
+VclPtr<SvxRuler> DrawViewShell::CreateVRuler(::sd::Window* pWin)
+{
+ VclPtr<SvxRuler> pRuler;
+ WinBits aWBits = WB_VSCROLL | WB_3DLOOK | WB_BORDER;
+ SvxRulerSupportFlags nFlags = SvxRulerSupportFlags::OBJECT;
+
+ pRuler = VclPtr<Ruler>::Create(*this, GetParentWindow(), pWin, nFlags,
+ GetViewFrame()->GetBindings(), aWBits);
+
+ // Metric same as HRuler, use document setting
+ sal_uInt16 nMetric = static_cast<sal_uInt16>(GetDoc()->GetUIUnit());
+
+ if( nMetric == 0xffff )
+ nMetric = static_cast<sal_uInt16>(GetViewShellBase().GetViewFrame()->GetDispatcher()->GetModule()->GetFieldUnit());
+
+ pRuler->SetUnit( FieldUnit( nMetric ) );
+
+ Fraction aUIScale(pWin->GetMapMode().GetScaleY());
+ aUIScale *= GetDoc()->GetUIScale();
+ pRuler->SetZoom(aUIScale);
+
+ return pRuler;
+}
+
+/**
+ * Refresh horizontal ruler
+ */
+
+void DrawViewShell::UpdateHRuler()
+{
+ Invalidate( SID_ATTR_LONG_LRSPACE );
+ Invalidate( SID_RULER_PAGE_POS );
+ Invalidate( SID_RULER_OBJECT );
+ Invalidate( SID_RULER_TEXT_RIGHT_TO_LEFT );
+
+ if (mpHorizontalRuler)
+ mpHorizontalRuler->ForceUpdate();
+}
+
+/**
+ * Refresh vertical ruler
+ */
+
+void DrawViewShell::UpdateVRuler()
+{
+ Invalidate( SID_ATTR_LONG_LRSPACE );
+ Invalidate( SID_RULER_PAGE_POS );
+ Invalidate( SID_RULER_OBJECT );
+
+ if (mpVerticalRuler)
+ mpVerticalRuler->ForceUpdate();
+}
+
+/**
+ * Refresh TabControl on splitter change
+ */
+
+IMPL_LINK( DrawViewShell, TabSplitHdl, TabBar *, pTab, void )
+{
+ const ::tools::Long nMax = maViewSize.Width() - maScrBarWH.Width()
+ - maTabControl->GetPosPixel().X() ;
+
+ Size aTabSize = maTabControl->GetSizePixel();
+ aTabSize.setWidth( std::min(pTab->GetSplitSize(), static_cast<::tools::Long>(nMax-1)) );
+
+ maTabControl->SetSizePixel(aTabSize);
+
+ if(GetLayerTabControl()) // #i87182#
+ {
+ GetLayerTabControl()->SetSizePixel(aTabSize);
+ }
+
+ Point aPos = maTabControl->GetPosPixel();
+ aPos.AdjustX(aTabSize.Width() );
+
+ Size aScrSize(nMax - aTabSize.Width(), maScrBarWH.Height());
+ mpHorizontalScrollBar->SetPosSizePixel(aPos, aScrSize);
+}
+
+/// inherited from sd::ViewShell
+SdPage* DrawViewShell::getCurrentPage() const
+{
+ const sal_uInt16 nPageCount = (meEditMode == EditMode::Page)?
+ GetDoc()->GetSdPageCount(mePageKind):
+ GetDoc()->GetMasterSdPageCount(mePageKind);
+
+ sal_uInt16 nCurrentPage = maTabControl->GetCurPagePos();
+ DBG_ASSERT((nCurrentPage<nPageCount), "sd::DrawViewShell::getCurrentPage(), illegal page index!");
+ if (nCurrentPage >= nPageCount)
+ nCurrentPage = 0; // play safe here
+
+ if (meEditMode == EditMode::Page)
+ {
+ return GetDoc()->GetSdPage(nCurrentPage, mePageKind);
+ }
+ else // EditMode::MasterPage
+ {
+ return GetDoc()->GetMasterSdPage(nCurrentPage, mePageKind);
+ }
+}
+
+/**
+ * Select new refreshed page, in case of a page order change (eg. by undo)
+ */
+
+void DrawViewShell::ResetActualPage()
+{
+ if (!GetDoc())
+ return;
+
+ sal_uInt16 nCurrentPageId = maTabControl->GetCurPageId();
+ sal_uInt16 nNewPageId = nCurrentPageId;
+ sal_uInt16 nCurrentPageNum = maTabControl->GetPagePos(nCurrentPageId);
+ sal_uInt16 nPageCount = (meEditMode == EditMode::Page)?GetDoc()->GetSdPageCount(mePageKind):GetDoc()->GetMasterSdPageCount(mePageKind);
+
+ if (meEditMode == EditMode::Page)
+ {
+
+ // Update for TabControl
+ maTabControl->Clear();
+
+ SdPage* pPage = nullptr;
+
+ for (sal_uInt16 i = 0; i < nPageCount; i++)
+ {
+ pPage = GetDoc()->GetSdPage(i, mePageKind);
+ OUString aPageName = pPage->GetName();
+ maTabControl->InsertPage(pPage->getPageId(), aPageName);
+
+ if (nCurrentPageId == pPage->getPageId())
+ {
+ nCurrentPageNum = i;
+ GetDoc()->SetSelected(pPage, true);
+ }
+ else
+ GetDoc()->SetSelected(pPage, false);
+ }
+
+ nNewPageId = maTabControl->GetPageId(nCurrentPageNum);
+ maTabControl->SetCurPageId(nNewPageId);
+ }
+ else // EditMode::MasterPage
+ {
+ maTabControl->Clear();
+
+ sal_uInt16 nMasterPageCnt = GetDoc()->GetMasterSdPageCount(mePageKind);
+ for (sal_uInt16 i = 0; i < nMasterPageCnt; i++)
+ {
+ SdPage* pMaster = GetDoc()->GetMasterSdPage(i, mePageKind);
+ OUString aLayoutName = pMaster->GetLayoutName();
+ sal_Int32 nPos = aLayoutName.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ aLayoutName = aLayoutName.copy(0, nPos);
+ maTabControl->InsertPage(pMaster->getPageId(), aLayoutName);
+
+ if (pMaster->getPageId() == nCurrentPageId)
+ nCurrentPageNum = i;
+ }
+
+ nNewPageId = maTabControl->GetPageId(nCurrentPageNum);
+ maTabControl->SetCurPageId(nNewPageId);
+ SwitchPage(nCurrentPageNum);
+ }
+
+ bool bAllowChangeFocus = nNewPageId != nCurrentPageId;
+ SfxBoolItem aI(SID_SWITCHPAGE, bAllowChangeFocus);
+ GetViewFrame()->GetDispatcher()->ExecuteList(SID_SWITCHPAGE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aI });
+}
+
+/**
+ * Apply "Verb" on OLE-object.
+ */
+ErrCode DrawViewShell::DoVerb(sal_Int32 nVerb)
+{
+ if ( mpDrawView->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+
+ if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::OLE2)
+ {
+ ActivateObject( static_cast<SdrOle2Obj*>(pObj), nVerb);
+ }
+ }
+ }
+
+ return ERRCODE_NONE;
+}
+
+/**
+ * Activate OLE-object
+ */
+bool DrawViewShell::ActivateObject(SdrOle2Obj* pObj, sal_Int32 nVerb)
+{
+ bool bActivated = false;
+
+ if ( !GetDocSh()->IsUIActive() )
+ {
+ ToolBarManager::UpdateLock aLock (GetViewShellBase().GetToolBarManager());
+
+ bActivated = ViewShell::ActivateObject(pObj, nVerb);
+ }
+
+ return bActivated;
+}
+
+/**
+ * Mark the desired page as selected (1), deselected (0), toggle (2).
+ * nPage refers to the page in question.
+ */
+bool DrawViewShell::SelectPage(sal_uInt16 nPage, sal_uInt16 nSelect)
+{
+ SdPage* pPage = GetDoc()->GetSdPage(nPage, PageKind::Standard);
+
+ //page selector marks pages to selected in view
+ auto &pageSelector = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase())->GetSlideSorter().GetController().GetPageSelector();
+
+ if (pPage)
+ {
+ if (nSelect == 0)
+ {
+ GetDoc()->SetSelected(pPage, false); // Deselect.
+ pageSelector.DeselectPage(nPage);
+ }
+ else if (nSelect == 1)
+ {
+ GetDoc()->SetSelected(pPage, true); // Select.
+ pageSelector.SelectPage(nPage);
+ }
+ else
+ {
+ // Toggle.
+ if (pPage->IsSelected())
+ {
+ GetDoc()->SetSelected(pPage, false);
+ pageSelector.DeselectPage(nPage);
+ }
+ else
+ {
+ GetDoc()->SetSelected(pPage, true);
+ pageSelector.SelectPage(nPage);
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool DrawViewShell::IsSelected(sal_uInt16 nPage)
+{
+ slidesorter::SlideSorterViewShell* pVShell
+ = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase());
+ if (pVShell != nullptr)
+ return pVShell->GetSlideSorter().GetController().GetPageSelector().IsPageSelected(nPage);
+
+ return false;
+}
+
+bool DrawViewShell::IsVisible(sal_uInt16 nPage)
+{
+ slidesorter::SlideSorterViewShell* pVShell
+ = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase());
+ if (pVShell != nullptr)
+ return pVShell->GetSlideSorter().GetController().GetPageSelector().IsPageVisible(nPage);
+
+ return false;
+}
+
+/**
+ * Switch to desired page.
+ * nSelectPage refers to the current EditMode
+ * bAllowChangeFocus set to false when slide is inserted before current page
+ * and we need to only update the current page number,
+ * do not disturb editing in that case
+ */
+bool DrawViewShell::SwitchPage(sal_uInt16 nSelectedPage, bool bAllowChangeFocus)
+{
+ /** Under some circumstances there are nested calls to SwitchPage() and
+ may crash the application (activation of form controls when the
+ shell of the edit view is not on top of the shell stack, see issue
+ 83888 for details.) Therefore the nested calls are ignored (they
+ would jump to the wrong page anyway.)
+ */
+
+ if (mbIsInSwitchPage)
+ return false;
+ mbIsInSwitchPage = true;
+ comphelper::ScopeGuard aGuard(
+ [this] () { this->mbIsInSwitchPage = false; } );
+
+ if (GetActiveWindow()->IsInPaint())
+ {
+ // Switching the current page while a Paint is being executed is
+ // dangerous. So, post it for later execution and return.
+ maAsynchronousSwitchPageCall.Post(
+ [this, nSelectedPage] () { this->SwitchPage(nSelectedPage); } );
+ return false;
+ }
+
+ bool bOK = false;
+
+ // With the current implementation of FuSlideShow there is a problem
+ // when it displays the show in a window: when the show is stopped it
+ // returns at one point in time SDRPAGE_NOTFOUND as current page index.
+ // Because FuSlideShow is currently being rewritten this bug is fixed
+ // here.
+ // This is not as bad a hack as it may look because making SwitchPage()
+ // more robust with respect to invalid page numbers is a good thing
+ // anyway.
+ if (nSelectedPage == SDRPAGE_NOTFOUND)
+ {
+ nSelectedPage = 0;
+ }
+ else
+ {
+ // Make sure that the given page index points to an existing page. Move
+ // the index into the valid range if necessary.
+ sal_uInt16 nPageCount = (meEditMode == EditMode::Page)
+ ? GetDoc()->GetSdPageCount(mePageKind)
+ : GetDoc()->GetMasterSdPageCount(mePageKind);
+ if (nSelectedPage >= nPageCount)
+ nSelectedPage = nPageCount-1;
+ }
+
+ if (IsSwitchPageAllowed())
+ {
+ ModifyGuard aGuard2( GetDoc() );
+
+ bOK = true;
+
+ if (mpActualPage)
+ {
+ SdPage* pNewPage = nullptr;
+
+ if (meEditMode == EditMode::MasterPage)
+ {
+ if( GetDoc()->GetMasterSdPageCount(mePageKind) > nSelectedPage )
+ pNewPage = GetDoc()->GetMasterSdPage(nSelectedPage, mePageKind);
+
+ if( pNewPage )
+ {
+ SdrPageView* pPV = mpDrawView->GetSdrPageView();
+ OUString sPageText(pNewPage->GetLayoutName());
+ sal_Int32 nPos = sPageText.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ sPageText = sPageText.copy(0, nPos);
+ if (pPV
+ && pNewPage == dynamic_cast< SdPage* >( pPV->GetPage() )
+ && sPageText == maTabControl->GetPageText(maTabControl->GetPageId(nSelectedPage)))
+ {
+ // this slide is already visible
+ return true;
+ }
+ }
+ }
+ else
+ {
+ OSL_ASSERT(mpFrameView!=nullptr);
+ mpFrameView->SetSelectedPage(nSelectedPage);
+
+ if (GetDoc()->GetSdPageCount(mePageKind) > nSelectedPage)
+ pNewPage = GetDoc()->GetSdPage(nSelectedPage, mePageKind);
+
+ if (mpActualPage == pNewPage)
+ {
+ SdrPageView* pPV = mpDrawView->GetSdrPageView();
+
+ SdPage* pCurrentPage = pPV ? dynamic_cast<SdPage*>(pPV->GetPage()) : nullptr;
+ if (pCurrentPage
+ && pNewPage == pCurrentPage
+ && maTabControl->GetPageText(maTabControl->GetPageId(nSelectedPage)) == pNewPage->GetName())
+ {
+ // this slide is already visible
+ return true;
+ }
+ }
+ }
+ }
+
+ if (bAllowChangeFocus)
+ mpDrawView->SdrEndTextEdit();
+
+ mpActualPage = nullptr;
+
+ if (meEditMode == EditMode::Page)
+ {
+ mpActualPage = GetDoc()->GetSdPage(nSelectedPage, mePageKind);
+ }
+ else
+ {
+ SdPage* pMaster = GetDoc()->GetMasterSdPage(nSelectedPage, mePageKind);
+
+ // does the selected page fit to the masterpage?
+ sal_uInt16 nPageCount = GetDoc()->GetSdPageCount(mePageKind);
+ for (sal_uInt16 i = 0; i < nPageCount; i++)
+ {
+ SdPage* pPage = GetDoc()->GetSdPage(i, mePageKind);
+ if(pPage && pPage->IsSelected() && pMaster == &(pPage->TRG_GetMasterPage()))
+ {
+ mpActualPage = pPage;
+ break;
+ }
+ }
+
+ if (!mpActualPage)
+ {
+ // take the first page, that fits to the masterpage
+ for (sal_uInt16 i = 0; i < nPageCount; i++)
+ {
+ SdPage* pPage = GetDoc()->GetSdPage(i, mePageKind);
+ if(pPage && pMaster == &(pPage->TRG_GetMasterPage()))
+ {
+ mpActualPage = pPage;
+ break;
+ }
+ }
+ }
+ }
+
+ for (sal_uInt16 i = 0; i < GetDoc()->GetSdPageCount(mePageKind); i++)
+ {
+ // deselect all pages
+ GetDoc()->SetSelected( GetDoc()->GetSdPage(i, mePageKind), false);
+ }
+
+ if (!mpActualPage)
+ {
+ // as far as there is no mpActualPage, take the first
+ mpActualPage = GetDoc()->GetSdPage(0, mePageKind);
+ }
+
+ // also select this page (mpActualPage always points at a drawing page,
+ // never at a masterpage)
+ GetDoc()->SetSelected(mpActualPage, true);
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // notify LibreOfficeKit about changed page
+ OString aPayload = OString::number(nSelectedPage);
+ if (SfxViewShell* pViewShell = GetViewShell())
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload.getStr());
+ }
+
+ rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetDoc() ) );
+ if( !xSlideshow.is() || !xSlideshow->isRunning() || ( xSlideshow->getAnimationMode() != ANIMATIONMODE_SHOW ) )
+ {
+ // tighten VisArea, to possibly deactivate objects
+ // !!! only if we are not in presentation mode (#96279) !!!
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ GetViewShell()->DisconnectAllClients();
+ VisAreaChanged(::tools::Rectangle(Point(), Size(1, 1)));
+ }
+
+ // Try to prefetch all graphics for the active page. This will be done
+ // in threads to be more efficient than loading them on-demand one by one.
+ std::vector<Graphic*> graphics;
+ mpActualPage->getGraphicsForPrefetch(graphics);
+ if(graphics.size() > 1) // threading does not help with loading just one
+ GraphicFilter::GetGraphicFilter().MakeGraphicsAvailableThreaded(graphics);
+
+ if (meEditMode == EditMode::Page)
+ {
+ /**********************************************************************
+ * PAGEMODE
+ **********************************************************************/
+ GetDoc()->SetSelected(mpActualPage, true);
+
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+
+ if (pPageView)
+ {
+ mpFrameView->SetVisibleLayers( pPageView->GetVisibleLayers() );
+ mpFrameView->SetPrintableLayers( pPageView->GetPrintableLayers() );
+ mpFrameView->SetLockedLayers( pPageView->GetLockedLayers() );
+
+ if (mePageKind == PageKind::Notes)
+ {
+ mpFrameView->SetNotesHelpLines( pPageView->GetHelpLines() );
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ mpFrameView->SetHandoutHelpLines( pPageView->GetHelpLines() );
+ }
+ else
+ {
+ mpFrameView->SetStandardHelpLines( pPageView->GetHelpLines() );
+ }
+ }
+
+ mpDrawView->HideSdrPage();
+ maTabControl->SetCurPageId(maTabControl->GetPageId(nSelectedPage));
+ mpDrawView->ShowSdrPage(mpActualPage);
+ GetViewShellBase().GetDrawController().FireSwitchCurrentPage(mpActualPage);
+
+ SdrPageView* pNewPageView = mpDrawView->GetSdrPageView();
+
+ if (pNewPageView)
+ {
+ pNewPageView->SetVisibleLayers( mpFrameView->GetVisibleLayers() );
+ pNewPageView->SetPrintableLayers( mpFrameView->GetPrintableLayers() );
+ pNewPageView->SetLockedLayers( mpFrameView->GetLockedLayers() );
+
+ if (mePageKind == PageKind::Notes)
+ {
+ pNewPageView->SetHelpLines( mpFrameView->GetNotesHelpLines() );
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ pNewPageView->SetHelpLines( mpFrameView->GetHandoutHelpLines() );
+ }
+ else
+ {
+ pNewPageView->SetHelpLines( mpFrameView->GetStandardHelpLines() );
+ }
+ }
+
+ OUString aPageName = mpActualPage->GetName();
+
+ if (maTabControl->GetPageText(maTabControl->GetPageId(nSelectedPage)) != aPageName)
+ {
+ maTabControl->SetPageText(maTabControl->GetPageId(nSelectedPage), aPageName);
+ }
+ }
+ else
+ {
+ /**********************************************************************
+ * MASTERPAGE
+ **********************************************************************/
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+
+ if (pPageView)
+ {
+ mpFrameView->SetVisibleLayers( pPageView->GetVisibleLayers() );
+ mpFrameView->SetPrintableLayers( pPageView->GetPrintableLayers() );
+ mpFrameView->SetLockedLayers( pPageView->GetLockedLayers() );
+
+ if (mePageKind == PageKind::Notes)
+ {
+ mpFrameView->SetNotesHelpLines( pPageView->GetHelpLines() );
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ mpFrameView->SetHandoutHelpLines( pPageView->GetHelpLines() );
+ }
+ else
+ {
+ mpFrameView->SetStandardHelpLines( pPageView->GetHelpLines() );
+ }
+ }
+
+ mpDrawView->HideSdrPage();
+ maTabControl->SetCurPageId(maTabControl->GetPageId(nSelectedPage));
+
+ SdPage* pMaster = GetDoc()->GetMasterSdPage(nSelectedPage, mePageKind);
+
+ if( !pMaster ) // if this page should not exist
+ pMaster = GetDoc()->GetMasterSdPage(0, mePageKind);
+
+ sal_uInt16 nNum = pMaster->GetPageNum();
+ mpDrawView->ShowSdrPage(mpDrawView->GetModel()->GetMasterPage(nNum));
+
+ GetViewShellBase().GetDrawController().FireSwitchCurrentPage(pMaster);
+
+ SdrPageView* pNewPageView = mpDrawView->GetSdrPageView();
+
+ if (pNewPageView)
+ {
+ pNewPageView->SetVisibleLayers( mpFrameView->GetVisibleLayers() );
+ pNewPageView->SetPrintableLayers( mpFrameView->GetPrintableLayers() );
+ pNewPageView->SetLockedLayers( mpFrameView->GetLockedLayers() );
+
+ if (mePageKind == PageKind::Notes)
+ {
+ pNewPageView->SetHelpLines( mpFrameView->GetNotesHelpLines() );
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ pNewPageView->SetHelpLines( mpFrameView->GetHandoutHelpLines() );
+ }
+ else
+ {
+ pNewPageView->SetHelpLines( mpFrameView->GetStandardHelpLines() );
+ }
+ }
+
+ OUString aLayoutName(pMaster->GetLayoutName());
+ sal_Int32 nPos = aLayoutName.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ aLayoutName = aLayoutName.copy(0, nPos);
+
+ if (maTabControl->GetPageText(maTabControl->GetPageId(nSelectedPage)) != aLayoutName)
+ {
+ maTabControl->SetPageText(maTabControl->GetPageId(nSelectedPage), aLayoutName);
+ }
+
+ if( mePageKind == PageKind::Handout )
+ {
+ // set pages for all available handout presentation objects
+ sd::ShapeList& rShapeList = pMaster->GetPresentationShapeList();
+ SdrObject* pObj = nullptr;
+ rShapeList.seekShape(0);
+
+ while( (pObj = rShapeList.getNextShape()) )
+ {
+ if( pMaster->GetPresObjKind(pObj) == PresObjKind::Handout )
+ {
+ // #i105146# We want no content to be displayed for PageKind::Handout,
+ // so just never set a page as content
+ static_cast<SdrPageObj*>(pObj)->SetReferencedPage(nullptr);
+ }
+ }
+ }
+ }
+
+ Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ VisAreaChanged(aVisAreaWin);
+ mpDrawView->VisAreaChanged(GetActiveWindow()->GetOutDev());
+
+ // so navigator (and effect window) notice that
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_NAVIGATOR_STATE, true);
+ rBindings.Invalidate(SID_NAVIGATOR_PAGENAME, true);
+ rBindings.Invalidate(SID_STATUS_PAGE, true);
+ rBindings.Invalidate(SID_DELETE_MASTER_PAGE, true);
+ rBindings.Invalidate(SID_DELETE_PAGE, true);
+ rBindings.Invalidate(SID_ASSIGN_LAYOUT, true);
+ rBindings.Invalidate(SID_INSERTPAGE, true);
+ UpdatePreview( mpActualPage );
+
+ mpDrawView->AdjustMarkHdl();
+ }
+
+ return bOK;
+}
+
+/**
+ * Check if page change is allowed
+ */
+
+bool DrawViewShell::IsSwitchPageAllowed() const
+{
+ bool bOK = true;
+
+ FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell();
+ if (pFormShell != nullptr && !pFormShell->PrepareClose(false))
+ bOK = false;
+
+ return bOK;
+}
+
+/**
+ * Select new refreshed page, in case of a page order change (eg. by undo)
+ */
+
+void DrawViewShell::ResetActualLayer()
+{
+ LayerTabBar* pLayerBar = GetLayerTabControl();
+ if (pLayerBar == nullptr)
+ return;
+
+ // remember old tab count and current tab id
+ // this is needed when one layer is renamed to
+ // restore current tab
+ sal_uInt16 nOldLayerCnt = pLayerBar->GetPageCount(); // actually it is tab count
+ sal_uInt16 nOldLayerPos = pLayerBar->GetCurPageId(); // actually it is a tab nId
+
+ /**
+ * Update for LayerTab
+ */
+ pLayerBar->Clear();
+
+ OUString aName; // a real layer name
+ OUString aActiveLayer = mpDrawView->GetActiveLayer();
+ sal_uInt16 nActiveLayerPos = SDRLAYERPOS_NOTFOUND;
+ SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin();
+ sal_uInt16 nLayerCnt = rLayerAdmin.GetLayerCount();
+
+ for ( sal_uInt16 nLayerPos = 0; nLayerPos < nLayerCnt; nLayerPos++ )
+ {
+ aName = rLayerAdmin.GetLayer(nLayerPos)->GetName();
+
+ if ( aName == aActiveLayer )
+ {
+ nActiveLayerPos = nLayerPos;
+ }
+
+ if ( aName != sUNO_LayerName_background ) // layer "background" has never a tab
+ {
+ if (meEditMode == EditMode::MasterPage)
+ {
+ // don't show page layer onto the masterpage
+ if (aName != sUNO_LayerName_layout &&
+ aName != sUNO_LayerName_controls &&
+ aName != sUNO_LayerName_measurelines)
+ {
+ TabBarPageBits nBits = TabBarPageBits::NONE;
+ SdrPageView* pPV = mpDrawView->GetSdrPageView();
+ if (pPV)
+ {
+ if (!pPV->IsLayerVisible(aName))
+ {
+ nBits |= TabBarPageBits::Blue;
+ }
+ if (pPV->IsLayerLocked(aName))
+ {
+ nBits |= TabBarPageBits::Italic;
+ }
+ if (!pPV->IsLayerPrintable(aName))
+ {
+ nBits |= TabBarPageBits::Underline;
+ }
+ }
+
+ pLayerBar->InsertPage(nLayerPos+1, aName, nBits); // why +1? It is a nId, not a position. Position is APPEND.
+ }
+ }
+ else
+ {
+ // don't show masterpage layer onto the page
+ if (aName != sUNO_LayerName_background_objects)
+ {
+ TabBarPageBits nBits = TabBarPageBits::NONE;
+ if (!mpDrawView->GetSdrPageView()->IsLayerVisible(aName))
+ {
+ nBits = TabBarPageBits::Blue;
+ }
+ if (mpDrawView->GetSdrPageView()->IsLayerLocked(aName))
+ {
+ nBits |= TabBarPageBits::Italic;
+ }
+ if (!mpDrawView->GetSdrPageView()->IsLayerPrintable(aName))
+ {
+ nBits |= TabBarPageBits::Underline;
+ }
+
+ pLayerBar->InsertPage(nLayerPos+1, aName, nBits);// why +1?
+ }
+ }
+ }
+ }
+
+ if ( nActiveLayerPos == SDRLAYERPOS_NOTFOUND )
+ {
+ if( nOldLayerCnt == pLayerBar->GetPageCount() )
+ {
+ nActiveLayerPos = nOldLayerPos - 1;
+ }
+ else
+ {
+ nActiveLayerPos = ( meEditMode == EditMode::MasterPage ) ? 2 : 0;
+ }
+
+ mpDrawView->SetActiveLayer( pLayerBar->GetLayerName(nActiveLayerPos + 1) );// why +1?
+ }
+
+ pLayerBar->SetCurPageId(nActiveLayerPos + 1);
+ GetViewFrame()->GetBindings().Invalidate( SID_MODIFYLAYER );
+ GetViewFrame()->GetBindings().Invalidate( SID_DELETE_LAYER );
+}
+
+/**
+ * AcceptDrop
+ */
+
+sal_Int8 DrawViewShell::AcceptDrop (
+ const AcceptDropEvent& rEvt,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* /*pTargetWindow*/,
+ sal_uInt16 /*nPage*/,
+ SdrLayerID nLayer )
+{
+ if( SlideShow::IsRunning( GetViewShellBase() ) )
+ return DND_ACTION_NONE;
+
+ return mpDrawView->AcceptDrop( rEvt, rTargetHelper, nLayer );
+}
+
+/**
+ * ExecuteDrop
+ */
+
+sal_Int8 DrawViewShell::ExecuteDrop (
+ const ExecuteDropEvent& rEvt,
+ DropTargetHelper& /*rTargetHelper*/,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer)
+{
+ if( nPage != SDRPAGE_NOTFOUND )
+ nPage = GetDoc()->GetSdPage( nPage, mePageKind )->GetPageNum();
+
+ if( SlideShow::IsRunning( GetViewShellBase() ) )
+ return DND_ACTION_NONE;
+
+ Broadcast(ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START));
+ sal_Int8 nResult (mpDrawView->ExecuteDrop( rEvt, pTargetWindow, nPage, nLayer ));
+ Broadcast(ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END));
+
+ return nResult;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviews2.cxx b/sd/source/ui/view/drviews2.cxx
new file mode 100644
index 000000000..8be942743
--- /dev/null
+++ b/sd/source/ui/view/drviews2.cxx
@@ -0,0 +1,4004 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <avmedia/mediaplayer.hxx>
+
+#include <basic/sberrors.hxx>
+#include <basic/sbstar.hxx>
+
+#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPages.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/ui/dialogs/XSLTFilterDialog.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/scanner/XScannerManager2.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <comphelper/lok.hxx>
+
+#include <editeng/contouritem.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/section.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/CustomPropertyField.hxx>
+#include <editeng/urlfieldhelper.hxx>
+
+#include <sal/log.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/msgpool.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/zoomitem.hxx>
+
+#include <svx/compressgraphicdialog.hxx>
+#include <svx/ClassificationDialog.hxx>
+#include <svx/ClassificationCommon.hxx>
+#include <svx/bmpmask.hxx>
+#include <svx/extedit.hxx>
+#include <svx/extrusionbar.hxx>
+#include <svx/f3dchild.hxx>
+#include <svx/fontwork.hxx>
+#include <svx/fontworkbar.hxx>
+#include <svx/graphichelper.hxx>
+#include <svx/hlnkitem.hxx>
+#include <svx/imapdlg.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/svxids.hrc>
+#include <svx/sdtfsitm.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/chrtitem.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xflgrit.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <tools/UnitConversion.hxx>
+
+#include <unotools/useroptions.hxx>
+
+#include <vcl/abstdlg.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/unohelp2.hxx>
+#include <vcl/weld.hxx>
+
+#include <editeng/cmapitem.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/numitem.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/SvxColorChildWindow.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/flstitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/colritem.hxx>
+
+#include <svl/poolitem.hxx>
+#include <svl/style.hxx>
+#include <svl/whiter.hxx>
+
+#include <app.hrc>
+#include <strings.hrc>
+
+#include <AnimationChildWindow.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <LayerTabBar.hxx>
+#include <Outliner.hxx>
+#include <ViewShellHint.hxx>
+#include <ViewShellImplementation.hxx>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <drawview.hxx>
+#include <fuarea.hxx>
+#include <fubullet.hxx>
+#include <fuchar.hxx>
+#include <fucushow.hxx>
+#include <fuconnct.hxx>
+#include <fucopy.hxx>
+#include <fudspord.hxx>
+#include <fuexecuteinteraction.hxx>
+#include <fuexpand.hxx>
+#include <fuinsert.hxx>
+#include <fuinsfil.hxx>
+#include <fuline.hxx>
+#include <fulinend.hxx>
+#include <fulink.hxx>
+#include <fumeasur.hxx>
+#include <fumorph.hxx>
+#include <fuoaprms.hxx>
+#include <fuolbull.hxx>
+#include <fupage.hxx>
+#include <fuparagr.hxx>
+#include <fuprlout.hxx>
+#include <fuscale.hxx>
+#include <fusel.hxx>
+#include <fusldlg.hxx>
+#include <fusnapln.hxx>
+#include <fusumry.hxx>
+#include <futempl.hxx>
+#include <futhes.hxx>
+#include <futransf.hxx>
+#include <futxtatt.hxx>
+#include <fuvect.hxx>
+#include <futext.hxx>
+#include <helpids.h>
+#include <sdabstdlg.hxx>
+#include <sdattr.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <unokywds.hxx>
+#include <slideshow.hxx>
+#include <stlsheet.hxx>
+#include <undolayer.hxx>
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <sfx2/classificationhelper.hxx>
+#include <sdmod.hxx>
+#include <model/SlsPageDescriptor.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <SlideSorter.hxx>
+#include <view/SlideSorterView.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <tools/GraphicSizeCheck.hxx>
+
+#include <ViewShellBase.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+#define MIN_ACTIONS_FOR_DIALOG 5000 ///< if there are more meta objects, we show a dialog during the break up
+
+namespace sd {
+
+namespace {
+
+const SvxFieldItem* findField(editeng::Section const & rSection)
+{
+ for (SfxPoolItem const * pPool: rSection.maAttributes)
+ {
+ if (pPool->Which() == EE_FEATURE_FIELD)
+ return static_cast<const SvxFieldItem*>(pPool);
+ }
+ return nullptr;
+}
+
+bool hasCustomPropertyField(std::vector<editeng::Section> const & aSections, std::u16string_view rName)
+{
+ for (editeng::Section const & rSection : aSections)
+ {
+ const SvxFieldItem* pFieldItem = findField(rSection);
+ if (pFieldItem)
+ {
+ const editeng::CustomPropertyField* pCustomPropertyField = dynamic_cast<const editeng::CustomPropertyField*>(pFieldItem->GetField());
+ if (pCustomPropertyField && pCustomPropertyField->GetName() == rName)
+ return true;
+ }
+ }
+ return false;
+}
+
+OUString getWeightString(SfxItemSet const & rItemSet)
+{
+ OUString sWeightString = "NORMAL";
+
+ if (const SfxPoolItem* pItem = rItemSet.GetItem(EE_CHAR_WEIGHT, false))
+ {
+ const SvxWeightItem* pWeightItem = dynamic_cast<const SvxWeightItem*>(pItem);
+ if (pWeightItem && pWeightItem->GetWeight() == WEIGHT_BOLD)
+ sWeightString = "BOLD";
+ }
+ return sWeightString;
+}
+
+class ClassificationCommon
+{
+protected:
+ sd::DrawViewShell& m_rDrawViewShell;
+ uno::Reference<document::XDocumentProperties> m_xDocumentProperties;
+ uno::Reference<beans::XPropertyContainer> m_xPropertyContainer;
+ sfx::ClassificationKeyCreator m_aKeyCreator;
+public:
+ ClassificationCommon(sd::DrawViewShell& rDrawViewShell, const css::uno::Reference<css::document::XDocumentProperties>& rDocProps)
+ : m_rDrawViewShell(rDrawViewShell)
+ , m_xDocumentProperties(rDocProps)
+ , m_xPropertyContainer(m_xDocumentProperties->getUserDefinedProperties())
+ , m_aKeyCreator(SfxClassificationHelper::getPolicyType())
+ {}
+};
+
+class ClassificationCollector : public ClassificationCommon
+{
+private:
+ std::vector<svx::ClassificationResult> m_aResults;
+
+ void iterateSectionsAndCollect(std::vector<editeng::Section> const & rSections, EditTextObject const & rEditText)
+ {
+ sal_Int32 nCurrentParagraph = -1;
+ OUString sBlank;
+
+ for (editeng::Section const & rSection : rSections)
+ {
+ // Insert new paragraph if needed
+ while (nCurrentParagraph < rSection.mnParagraph)
+ {
+ nCurrentParagraph++;
+ // Get Weight of current paragraph
+ OUString sWeightProperty = getWeightString(rEditText.GetParaAttribs(nCurrentParagraph));
+ // Insert new paragraph into collection
+ m_aResults.push_back({ svx::ClassificationType::PARAGRAPH, sWeightProperty, sBlank, sBlank });
+ }
+
+ const SvxFieldItem* pFieldItem = findField(rSection);
+ const editeng::CustomPropertyField* pCustomPropertyField = pFieldItem ?
+ dynamic_cast<const editeng::CustomPropertyField*>(pFieldItem->GetField()) :
+ nullptr;
+ if (pCustomPropertyField)
+ {
+ const OUString& aKey = pCustomPropertyField->GetName();
+ if (m_aKeyCreator.isMarkingTextKey(aKey))
+ {
+ OUString aValue = svx::classification::getProperty(m_xPropertyContainer, aKey);
+ m_aResults.push_back({ svx::ClassificationType::TEXT, aValue, sBlank, sBlank });
+ }
+ else if (m_aKeyCreator.isCategoryNameKey(aKey) || m_aKeyCreator.isCategoryIdentifierKey(aKey))
+ {
+ OUString aValue = svx::classification::getProperty(m_xPropertyContainer, aKey);
+ m_aResults.push_back({ svx::ClassificationType::CATEGORY, aValue, sBlank, sBlank });
+ }
+ else if (m_aKeyCreator.isMarkingKey(aKey))
+ {
+ OUString aValue = svx::classification::getProperty(m_xPropertyContainer, aKey);
+ m_aResults.push_back({ svx::ClassificationType::MARKING, aValue, sBlank, sBlank });
+ }
+ else if (m_aKeyCreator.isIntellectualPropertyPartKey(aKey))
+ {
+ OUString aValue = svx::classification::getProperty(m_xPropertyContainer, aKey);
+ m_aResults.push_back({ svx::ClassificationType::INTELLECTUAL_PROPERTY_PART, aValue, sBlank, sBlank });
+ }
+ }
+ }
+ }
+
+public:
+ ClassificationCollector(sd::DrawViewShell & rDrawViewShell, const css::uno::Reference<css::document::XDocumentProperties>& rDocProps)
+ : ClassificationCommon(rDrawViewShell, rDocProps)
+ {}
+
+ std::vector<svx::ClassificationResult> const & getResults() const
+ {
+ return m_aResults;
+ }
+
+ void collect()
+ {
+ // Set to MASTER mode
+ EditMode eOldMode = m_rDrawViewShell.GetEditMode();
+ if (eOldMode != EditMode::MasterPage)
+ m_rDrawViewShell.ChangeEditMode(EditMode::MasterPage, false);
+
+ // Scoped guard to revert to the previous mode
+ comphelper::ScopeGuard const aGuard([this, eOldMode] () {
+ m_rDrawViewShell.ChangeEditMode(eOldMode, false);
+ });
+
+ const sal_uInt16 nCount = m_rDrawViewShell.GetDoc()->GetMasterSdPageCount(PageKind::Standard);
+
+ for (sal_uInt16 nPageIndex = 0; nPageIndex < nCount; ++nPageIndex)
+ {
+ SdPage* pMasterPage = m_rDrawViewShell.GetDoc()->GetMasterSdPage(nPageIndex, PageKind::Standard);
+ for (size_t nObject = 0; nObject < pMasterPage->GetObjCount(); ++nObject)
+ {
+ SdrObject* pObject = pMasterPage->GetObj(nObject);
+ SdrRectObj* pRectObject = dynamic_cast<SdrRectObj*>(pObject);
+ if (pRectObject && pRectObject->GetTextKind() == SdrObjKind::Text)
+ {
+ OutlinerParaObject* pOutlinerParagraphObject = pRectObject->GetOutlinerParaObject();
+ if (pOutlinerParagraphObject)
+ {
+ const EditTextObject& rEditText = pOutlinerParagraphObject->GetTextObject();
+ std::vector<editeng::Section> aSections;
+ rEditText.GetAllSections(aSections);
+
+ // Search for a custom property field that has the classification category identifier key
+ if (hasCustomPropertyField(aSections, m_aKeyCreator.makeCategoryNameKey()))
+ {
+ iterateSectionsAndCollect(aSections, rEditText);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+};
+
+class ClassificationInserter : public ClassificationCommon
+{
+private:
+ /// Delete the previous existing classification object(s) - if they exist
+ void deleteExistingObjects()
+ {
+ OUString sKey = m_aKeyCreator.makeCategoryNameKey();
+
+ const sal_uInt16 nCount = m_rDrawViewShell.GetDoc()->GetMasterSdPageCount(PageKind::Standard);
+
+ for (sal_uInt16 nPageIndex = 0; nPageIndex < nCount; ++nPageIndex)
+ {
+ SdPage* pMasterPage = m_rDrawViewShell.GetDoc()->GetMasterSdPage(nPageIndex, PageKind::Standard);
+ for (size_t nObject = 0; nObject < pMasterPage->GetObjCount(); ++nObject)
+ {
+ SdrObject* pObject = pMasterPage->GetObj(nObject);
+ SdrRectObj* pRectObject = dynamic_cast<SdrRectObj*>(pObject);
+ if (pRectObject && pRectObject->GetTextKind() == SdrObjKind::Text)
+ {
+ OutlinerParaObject* pOutlinerParagraphObject = pRectObject->GetOutlinerParaObject();
+ if (pOutlinerParagraphObject)
+ {
+ const EditTextObject& rEditText = pOutlinerParagraphObject->GetTextObject();
+ std::vector<editeng::Section> aSections;
+ rEditText.GetAllSections(aSections);
+
+ if (hasCustomPropertyField(aSections, sKey))
+ {
+ pMasterPage->RemoveObject(pRectObject->GetOrdNum());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void fillTheOutliner(Outliner* pOutliner, std::vector<svx::ClassificationResult> const & rResults)
+ {
+ sal_Int32 nParagraph = -1;
+ for (svx::ClassificationResult const & rResult : rResults)
+ {
+
+ ESelection aPosition(nParagraph, EE_TEXTPOS_MAX_COUNT, nParagraph, EE_TEXTPOS_MAX_COUNT);
+
+ switch (rResult.meType)
+ {
+ case svx::ClassificationType::TEXT:
+ {
+ OUString sKey = m_aKeyCreator.makeNumberedTextKey();
+ svx::classification::addOrInsertDocumentProperty(m_xPropertyContainer, sKey, rResult.msName);
+ pOutliner->QuickInsertField(SvxFieldItem(editeng::CustomPropertyField(sKey, rResult.msName), EE_FEATURE_FIELD), aPosition);
+ }
+ break;
+
+ case svx::ClassificationType::CATEGORY:
+ {
+ OUString sKey = m_aKeyCreator.makeCategoryNameKey();
+ pOutliner->QuickInsertField(SvxFieldItem(editeng::CustomPropertyField(sKey, rResult.msName), EE_FEATURE_FIELD), aPosition);
+ }
+ break;
+
+ case svx::ClassificationType::MARKING:
+ {
+ OUString sKey = m_aKeyCreator.makeNumberedMarkingKey();
+ svx::classification::addOrInsertDocumentProperty(m_xPropertyContainer, sKey, rResult.msName);
+ pOutliner->QuickInsertField(SvxFieldItem(editeng::CustomPropertyField(sKey, rResult.msName), EE_FEATURE_FIELD), aPosition);
+ }
+ break;
+
+ case svx::ClassificationType::INTELLECTUAL_PROPERTY_PART:
+ {
+ OUString sKey = m_aKeyCreator.makeNumberedIntellectualPropertyPartKey();
+ svx::classification::addOrInsertDocumentProperty(m_xPropertyContainer, sKey, rResult.msName);
+ pOutliner->QuickInsertField(SvxFieldItem(editeng::CustomPropertyField(sKey, rResult.msName), EE_FEATURE_FIELD), aPosition);
+ }
+ break;
+
+ case svx::ClassificationType::PARAGRAPH:
+ {
+ nParagraph++;
+ pOutliner->Insert("");
+
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aItemSet(m_rDrawViewShell.GetDoc()->GetPool());
+
+ if (rResult.msName == "BOLD")
+ aItemSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT));
+ else
+ aItemSet.Put(SvxWeightItem(WEIGHT_NORMAL, EE_CHAR_WEIGHT));
+
+ SvxNumRule aDefaultNumRule(SvxNumRuleFlags::NONE, 0, false);
+ aItemSet.Put(SvxNumBulletItem(std::move(aDefaultNumRule), EE_PARA_NUMBULLET));
+
+ pOutliner->SetParaAttribs(nParagraph, aItemSet);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+public:
+ ClassificationInserter(sd::DrawViewShell & rDrawViewShell, const css::uno::Reference<css::document::XDocumentProperties>& rDocProps)
+ : ClassificationCommon(rDrawViewShell, rDocProps)
+ {
+ }
+
+ void insert(std::vector<svx::ClassificationResult> const & rResults)
+ {
+ // Set to MASTER mode
+ EditMode eOldMode = m_rDrawViewShell.GetEditMode();
+ if (eOldMode != EditMode::MasterPage)
+ m_rDrawViewShell.ChangeEditMode(EditMode::MasterPage, false);
+
+ // Scoped guard to revert the mode
+ comphelper::ScopeGuard const aGuard([this, eOldMode] () {
+ m_rDrawViewShell.ChangeEditMode(eOldMode, false);
+ });
+
+ // Delete the previous existing object - if exists
+ deleteExistingObjects();
+
+ // Clear properties
+ svx::classification::removeAllProperties(m_xPropertyContainer);
+
+ SfxClassificationHelper aHelper(m_xDocumentProperties);
+
+ // Apply properties from the BA policy
+ for (svx::ClassificationResult const & rResult : rResults)
+ {
+ if (rResult.meType == svx::ClassificationType::CATEGORY)
+ aHelper.SetBACName(rResult.msName, SfxClassificationHelper::getPolicyType());
+ }
+
+ // Insert full text as document property
+ svx::classification::insertFullTextualRepresentationAsDocumentProperty(m_xPropertyContainer, m_aKeyCreator, rResults);
+
+ // Create the outliner from the
+ Outliner* pOutliner = m_rDrawViewShell.GetDoc()->GetInternalOutliner();
+ OutlinerMode eOutlinerMode = pOutliner->GetOutlinerMode();
+
+ comphelper::ScopeGuard const aOutlinerGuard([pOutliner, eOutlinerMode] () {
+ pOutliner->Init(eOutlinerMode);
+ });
+
+ pOutliner->Init(OutlinerMode::TextObject);
+
+ // Fill the outliner with the text from classification result
+ fillTheOutliner(pOutliner, rResults);
+
+ // Calculate to outliner text size
+ pOutliner->UpdateFields();
+ pOutliner->SetUpdateLayout(true);
+ Size aTextSize(pOutliner->CalcTextSize());
+ pOutliner->SetUpdateLayout(false);
+
+ // Create objects, apply the outliner and add them (objects) to all master pages
+ const sal_uInt16 nCount = m_rDrawViewShell.GetDoc()->GetMasterSdPageCount(PageKind::Standard);
+
+ for (sal_uInt16 nPageIndex = 0; nPageIndex < nCount; ++nPageIndex)
+ {
+ SdPage* pMasterPage = m_rDrawViewShell.GetDoc()->GetMasterSdPage(nPageIndex, PageKind::Standard);
+ if (!pMasterPage)
+ continue;
+
+ SdrRectObj* pObject = new SdrRectObj(
+ *m_rDrawViewShell.GetDoc(), // TTTT should be reference
+ SdrObjKind::Text);
+ pObject->SetMergedItem(makeSdrTextAutoGrowWidthItem(true));
+ pObject->SetOutlinerParaObject(pOutliner->CreateParaObject());
+ pMasterPage->InsertObject(pObject);
+
+ // Calculate position
+ ::tools::Rectangle aRectangle(Point(), pMasterPage->GetSize());
+ Point aPosition(aRectangle.Center().X(), aRectangle.Bottom());
+
+ aPosition.AdjustX( -(aTextSize.Width() / 2) );
+ aPosition.AdjustY( -(aTextSize.Height()) );
+
+ pObject->SetLogicRect(::tools::Rectangle(aPosition, aTextSize));
+ }
+ }
+};
+
+ void lcl_convertStringArguments(sal_uInt16 nSlot, const std::unique_ptr<SfxItemSet>& pArgs)
+ {
+ Color aColor;
+ const SfxPoolItem* pItem = nullptr;
+
+ if (SfxItemState::SET == pArgs->GetItemState(SID_ATTR_LINE_WIDTH_ARG, false, &pItem))
+ {
+ double fValue = static_cast<const SvxDoubleItem*>(pItem)->GetValue();
+ // FIXME: different units...
+ int nPow = 100;
+ int nValue = fValue * nPow;
+
+ XLineWidthItem aItem(nValue);
+ pArgs->Put(aItem);
+ }
+ if (SfxItemState::SET == pArgs->GetItemState(SID_ATTR_COLOR_STR, false, &pItem))
+ {
+ OUString sColor = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ if (sColor == "transparent")
+ aColor = COL_TRANSPARENT;
+ else
+ aColor = Color(ColorTransparency, sColor.toInt32(16));
+
+ switch (nSlot)
+ {
+ case SID_ATTR_LINE_COLOR:
+ {
+ XLineColorItem aLineColorItem(OUString(), aColor);
+ pArgs->Put(aLineColorItem);
+ break;
+ }
+
+ case SID_ATTR_FILL_COLOR:
+ {
+ XFillColorItem aFillColorItem(OUString(), aColor);
+ pArgs->Put(aFillColorItem);
+ break;
+ }
+ }
+ }
+ if (SfxItemState::SET == pArgs->GetItemState(SID_FILL_GRADIENT_JSON, false, &pItem))
+ {
+ const SfxStringItem* pJSON = static_cast<const SfxStringItem*>(pItem);
+ if (pJSON)
+ {
+ XGradient aGradient = XGradient::fromJSON(pJSON->GetValue());
+ XFillGradientItem aItem(aGradient);
+ pArgs->Put(aItem);
+ }
+ }
+
+ if (nSlot == SID_ATTR_FILL_COLOR)
+ {
+ // Merge the color parameters to the color itself.
+ const XFillColorItem* pColorItem = static_cast<const XFillColorItem*>(pArgs->GetItem(SID_ATTR_FILL_COLOR));
+ if (pColorItem)
+ {
+ XFillColorItem aColorItem(*pColorItem);
+ if (pArgs->GetItemState(SID_ATTR_COLOR_THEME_INDEX, false, &pItem) == SfxItemState::SET)
+ {
+ auto pIntItem = static_cast<const SfxInt16Item*>(pItem);
+ aColorItem.GetThemeColor().SetThemeIndex(pIntItem->GetValue());
+ }
+ if (pArgs->GetItemState(SID_ATTR_COLOR_LUM_MOD, false, &pItem) == SfxItemState::SET)
+ {
+ auto pIntItem = static_cast<const SfxInt16Item*>(pItem);
+ aColorItem.GetThemeColor().SetLumMod(pIntItem->GetValue());
+ }
+ if (pArgs->GetItemState(SID_ATTR_COLOR_LUM_OFF, false, &pItem) == SfxItemState::SET)
+ {
+ auto pIntItem = static_cast<const SfxInt16Item*>(pItem);
+ aColorItem.GetThemeColor().SetLumOff(pIntItem->GetValue());
+ }
+ pArgs->Put(aColorItem);
+ }
+ }
+ }
+}
+
+/**
+ * SfxRequests for temporary actions
+ */
+
+void DrawViewShell::FuTemporary(SfxRequest& rReq)
+{
+ // during a native slide show nothing gets executed!
+ if(SlideShow::IsRunning( GetViewShellBase() ) && (rReq.GetSlot() != SID_NAVIGATOR))
+ return;
+
+ DBG_ASSERT( mpDrawView, "sd::DrawViewShell::FuTemporary(), no draw view!" );
+ if( !mpDrawView )
+ return;
+
+ CheckLineTo (rReq);
+
+ DeactivateCurrentFunction();
+
+ sal_uInt16 nSId = rReq.GetSlot();
+
+ switch ( nSId )
+ {
+ case SID_OUTLINE_TEXT_AUTOFIT:
+ {
+ SfxUndoManager* pUndoManager = GetDocSh()->GetUndoManager();
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ pUndoManager->EnterListAction("", "", 0, GetViewShellBase().GetViewShellId());
+ mpDrawView->BegUndo();
+
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ bool bSet = pObj->GetMergedItemSet().GetItem<SdrTextFitToSizeTypeItem>(SDRATTR_TEXT_FITTOSIZE)->GetValue() != drawing::TextFitToSizeType_NONE;
+
+ mpDrawView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
+
+ if (!bSet)
+ {
+ //If we are turning on AutoFit we have to turn these off if already on
+ if (pObj->GetMergedItemSet().GetItem<SdrOnOffItem>(SDRATTR_TEXT_AUTOGROWHEIGHT)->GetValue())
+ pObj->SetMergedItem(makeSdrTextAutoGrowHeightItem(false));
+ if (pObj->GetMergedItemSet().GetItem<SdrOnOffItem>(SDRATTR_TEXT_AUTOGROWWIDTH)->GetValue())
+ pObj->SetMergedItem(makeSdrTextAutoGrowWidthItem(false));
+ }
+
+ pObj->SetMergedItem(SdrTextFitToSizeTypeItem(bSet ? drawing::TextFitToSizeType_NONE : drawing::TextFitToSizeType_AUTOFIT));
+
+ mpDrawView->EndUndo();
+ pUndoManager->LeaveListAction();
+ }
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ // area and line attributes: shall have
+ // an own Execute method (like StateMethode)
+ case SID_ATTR_FILL_STYLE:
+ case SID_ATTR_FILL_COLOR:
+ case SID_ATTR_FILL_GRADIENT:
+ case SID_ATTR_FILL_HATCH:
+ case SID_ATTR_FILL_BITMAP:
+ case SID_ATTR_FILL_SHADOW:
+ case SID_ATTR_SHADOW_COLOR:
+ case SID_ATTR_SHADOW_TRANSPARENCE:
+ case SID_ATTR_SHADOW_BLUR:
+ case SID_ATTR_SHADOW_XDISTANCE:
+ case SID_ATTR_SHADOW_YDISTANCE:
+ case SID_ATTR_FILL_USE_SLIDE_BACKGROUND:
+ case SID_ATTR_FILL_TRANSPARENCE:
+ case SID_ATTR_FILL_FLOATTRANSPARENCE:
+
+ case SID_ATTR_LINE_STYLE:
+ case SID_ATTR_LINE_DASH:
+ case SID_ATTR_LINE_WIDTH:
+ case SID_ATTR_LINE_COLOR:
+ case SID_ATTR_LINEEND_STYLE:
+ case SID_ATTR_LINE_START:
+ case SID_ATTR_LINE_END:
+ case SID_ATTR_LINE_TRANSPARENCE:
+ case SID_ATTR_LINE_JOINT:
+ case SID_ATTR_LINE_CAP:
+
+ case SID_ATTR_TEXT_FITTOSIZE:
+ {
+ if( rReq.GetArgs() )
+ {
+ std::unique_ptr<SfxItemSet> pNewArgs = rReq.GetArgs()->Clone();
+ lcl_convertStringArguments(rReq.GetSlot(), pNewArgs);
+ mpDrawView->SetAttributes(*pNewArgs);
+ rReq.Done();
+ }
+ else
+ {
+ switch( rReq.GetSlot() )
+ {
+ case SID_ATTR_FILL_SHADOW:
+ case SID_ATTR_SHADOW_COLOR:
+ case SID_ATTR_SHADOW_TRANSPARENCE:
+ case SID_ATTR_SHADOW_BLUR:
+ case SID_ATTR_SHADOW_XDISTANCE:
+ case SID_ATTR_SHADOW_YDISTANCE:
+ case SID_ATTR_FILL_STYLE:
+ case SID_ATTR_FILL_COLOR:
+ case SID_ATTR_FILL_GRADIENT:
+ case SID_ATTR_FILL_HATCH:
+ case SID_ATTR_FILL_BITMAP:
+ case SID_ATTR_FILL_USE_SLIDE_BACKGROUND:
+ case SID_ATTR_FILL_TRANSPARENCE:
+ case SID_ATTR_FILL_FLOATTRANSPARENCE:
+ GetViewFrame()->GetDispatcher()->Execute( SID_ATTRIBUTES_AREA, SfxCallMode::ASYNCHRON );
+ break;
+ case SID_ATTR_LINE_STYLE:
+ case SID_ATTR_LINE_DASH:
+ case SID_ATTR_LINE_WIDTH:
+ case SID_ATTR_LINE_COLOR:
+ case SID_ATTR_LINE_TRANSPARENCE:
+ case SID_ATTR_LINE_JOINT:
+ case SID_ATTR_LINE_CAP:
+ GetViewFrame()->GetDispatcher()->Execute( SID_ATTRIBUTES_LINE, SfxCallMode::ASYNCHRON );
+ break;
+ case SID_ATTR_TEXT_FITTOSIZE:
+ GetViewFrame()->GetDispatcher()->Execute( SID_TEXTATTR_DLG, SfxCallMode::ASYNCHRON );
+ break;
+ }
+ }
+ Cancel();
+ }
+ break;
+
+ case SID_HYPHENATION:
+ {
+ const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(SID_HYPHENATION);
+
+ if( pItem )
+ {
+ SfxItemSetFixed<EE_PARA_HYPHENATE, EE_PARA_HYPHENATE> aSet( GetPool() );
+ bool bValue = pItem->GetValue();
+ aSet.Put( SfxBoolItem( EE_PARA_HYPHENATE, bValue ) );
+ mpDrawView->SetAttributes( aSet );
+ }
+ else // only for testing purpose
+ {
+ OSL_FAIL(" no value for hyphenation!");
+ SfxItemSetFixed<EE_PARA_HYPHENATE, EE_PARA_HYPHENATE> aSet( GetPool() );
+ aSet.Put( SfxBoolItem( EE_PARA_HYPHENATE, true ) );
+ mpDrawView->SetAttributes( aSet );
+ }
+ rReq.Done();
+ Cancel();
+ }
+ break;
+
+ case SID_INSERTPAGE:
+ case SID_INSERTPAGE_QUICK:
+ {
+ SdPage* pNewPage = CreateOrDuplicatePage (rReq, mePageKind, GetActualPage());
+ Cancel();
+ if(HasCurrentFunction(SID_BEZIER_EDIT) )
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ if (pNewPage != nullptr)
+ SwitchPage((pNewPage->GetPageNum()-1)/2);
+ rReq.Done ();
+ }
+ break;
+
+ case SID_DUPLICATE_PAGE:
+ {
+ auto slideSorter = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase());
+ SdPage* pNewPage = nullptr;
+ if(slideSorter)
+ DuplicateSelectedSlides(rReq);
+ else
+ pNewPage = CreateOrDuplicatePage (rReq, mePageKind, GetActualPage());
+ Cancel();
+ if(HasCurrentFunction(SID_BEZIER_EDIT) )
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ if(!slideSorter && pNewPage != nullptr)
+ SwitchPage((pNewPage->GetPageNum()-1)/2);
+ rReq.Done();
+ }
+ break;
+
+ case SID_INSERT_MASTER_PAGE:
+ {
+ // Use the API to create a new page.
+ Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier (
+ GetDoc()->getUnoModel(), UNO_QUERY);
+ if (xMasterPagesSupplier.is())
+ {
+ Reference<drawing::XDrawPages> xMasterPages (
+ xMasterPagesSupplier->getMasterPages());
+ if (xMasterPages.is())
+ {
+ sal_uInt16 nIndex = GetCurPagePos() + 1;
+ xMasterPages->insertNewByIndex (nIndex);
+
+ // Create shapes for the default layout.
+ SdPage* pMasterPage = GetDoc()->GetMasterSdPage(
+ nIndex, PageKind::Standard);
+ pMasterPage->CreateTitleAndLayout (true,true);
+ }
+ }
+
+ Cancel();
+ if(HasCurrentFunction(SID_BEZIER_EDIT))
+ GetViewFrame()->GetDispatcher()->Execute(
+ SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ rReq.Done ();
+ }
+ break;
+
+ case SID_MODIFYPAGE:
+ {
+ if (mePageKind==PageKind::Standard || mePageKind==PageKind::Notes ||
+ (mePageKind==PageKind::Handout && meEditMode==EditMode::MasterPage) )
+ {
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+ sal_uInt16 nPage = maTabControl->GetCurPagePos();
+ mpActualPage = GetDoc()->GetSdPage(nPage, mePageKind);
+ ::sd::ViewShell::mpImpl->ProcessModifyPageSlot (
+ rReq,
+ mpActualPage,
+ mePageKind);
+ }
+
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_ASSIGN_LAYOUT:
+ {
+ if (mePageKind==PageKind::Standard || mePageKind==PageKind::Notes || (mePageKind==PageKind::Handout && meEditMode==EditMode::MasterPage))
+ {
+ if ( mpDrawView->IsTextEdit() )
+ mpDrawView->SdrEndTextEdit();
+
+ ::sd::ViewShell::mpImpl->AssignLayout(rReq, mePageKind);
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_RENAMEPAGE:
+ case SID_RENAME_MASTER_PAGE:
+ {
+ if (mePageKind==PageKind::Standard || mePageKind==PageKind::Notes )
+ {
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ sal_uInt16 nPage = maTabControl->GetCurPagePos();
+ SdPage* pCurrentPage = ( GetEditMode() == EditMode::Page )
+ ? GetDoc()->GetSdPage( nPage, GetPageKind() )
+ : GetDoc()->GetMasterSdPage( nPage, GetPageKind() );
+
+ OUString aTitle = SdResId(STR_TITLE_RENAMESLIDE);
+ OUString aDescr = SdResId(STR_DESC_RENAMESLIDE);
+ const OUString& aPageName = pCurrentPage->GetName();
+
+ if(rReq.GetArgs())
+ {
+ OUString aName = rReq.GetArgs()->GetItem<const SfxStringItem>(SID_RENAMEPAGE)->GetValue();
+
+ bool bResult = RenameSlide( maTabControl->GetPageId(nPage), aName );
+ DBG_ASSERT( bResult, "Couldn't rename slide" );
+ }
+ else
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxNameDialog> aNameDlg(pFact->CreateSvxNameDialog(GetFrameWeld(), aPageName, aDescr));
+ aNameDlg->SetText( aTitle );
+ aNameDlg->SetCheckNameHdl( LINK( this, DrawViewShell, RenameSlideHdl ), true );
+ aNameDlg->SetEditHelpId( HID_SD_NAMEDIALOG_PAGE );
+
+ if( aNameDlg->Execute() == RET_OK )
+ {
+ OUString aNewName;
+ aNameDlg->GetName( aNewName );
+ if (aNewName != aPageName)
+ {
+ bool bResult = RenameSlide( maTabControl->GetPageId(nPage), aNewName );
+ DBG_ASSERT( bResult, "Couldn't rename slide" );
+ }
+ }
+ }
+ }
+ Cancel();
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_RENAMEPAGE_QUICK:
+ {
+ if (mePageKind==PageKind::Standard || mePageKind==PageKind::Notes )
+ {
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ maTabControl->StartEditMode( maTabControl->GetCurPageId() );
+ }
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_PAGESIZE : // either this (no menu entries or something else!)
+ {
+ const SfxItemSet *pArgs = rReq.GetArgs ();
+
+ if (pArgs && pArgs->Count () == 3)
+ {
+ const SfxUInt32Item* pWidth = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGEWIDTH);
+ const SfxUInt32Item* pHeight = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGEHEIGHT);
+ const SfxBoolItem* pScaleAll = rReq.GetArg<SfxBoolItem>(ID_VAL_SCALEOBJECTS);
+
+ Size aSize (pWidth->GetValue (), pHeight->GetValue ());
+
+ SetupPage (aSize, 0, 0, 0, 0, true, false, pScaleAll->GetValue ());
+ rReq.Ignore ();
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ rReq.Ignore ();
+ break;
+ }
+
+ case SID_PAGEMARGIN : // or this (no menu entries or something else!)
+ {
+ const SfxItemSet *pArgs = rReq.GetArgs ();
+
+ if (pArgs && pArgs->Count () == 5)
+ {
+ const SfxUInt32Item* pLeft = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGELEFT);
+ const SfxUInt32Item* pRight = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGERIGHT);
+ const SfxUInt32Item* pUpper = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGETOP);
+ const SfxUInt32Item* pLower = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGEBOTTOM);
+ const SfxBoolItem* pScaleAll = rReq.GetArg<SfxBoolItem>(ID_VAL_SCALEOBJECTS);
+
+ Size aEmptySize (0, 0);
+
+ SetupPage (aEmptySize, pLeft->GetValue (), pRight->GetValue (),
+ pUpper->GetValue (), pLower->GetValue (),
+ false, true, pScaleAll->GetValue ());
+ rReq.Ignore ();
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ rReq.Ignore ();
+ break;
+ }
+
+ case SID_ATTR_ZOOMSLIDER:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ const SfxUInt16Item* pScale = (pArgs && pArgs->Count () == 1) ?
+ rReq.GetArg(SID_ATTR_ZOOMSLIDER) : nullptr;
+ if (pScale && CHECK_RANGE (5, pScale->GetValue (), 3000))
+ {
+ SetZoom (pScale->GetValue ());
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_ATTR_ZOOM );
+ rBindings.Invalidate( SID_ZOOM_IN );
+ rBindings.Invalidate( SID_ZOOM_OUT );
+ rBindings.Invalidate( SID_ATTR_ZOOMSLIDER );
+
+ }
+
+ Cancel();
+ rReq.Done ();
+ break;
+ }
+
+ case SID_ATTR_ZOOM:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ mbZoomOnPage = false;
+
+ if ( pArgs )
+ {
+ SvxZoomType eZT = pArgs->Get( SID_ATTR_ZOOM ).GetType();
+ switch( eZT )
+ {
+ case SvxZoomType::PERCENT:
+ SetZoom( static_cast<::tools::Long>( pArgs->Get( SID_ATTR_ZOOM ).GetValue()) );
+ break;
+
+ case SvxZoomType::OPTIMAL:
+ GetViewFrame()->GetDispatcher()->Execute( SID_SIZE_ALL,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ break;
+
+ case SvxZoomType::PAGEWIDTH:
+ GetViewFrame()->GetDispatcher()->Execute( SID_SIZE_PAGE_WIDTH,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ break;
+
+ case SvxZoomType::WHOLEPAGE:
+ GetViewFrame()->GetDispatcher()->Execute( SID_SIZE_PAGE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ break;
+ case SvxZoomType::PAGEWIDTH_NOBORDER:
+ OSL_FAIL("sd::DrawViewShell::FuTemporary(), SvxZoomType::PAGEWIDTH_NOBORDER not handled!" );
+ break;
+ }
+ rReq.Ignore ();
+ }
+ else
+ {
+ // open zoom dialog
+ SetCurrentFunction( FuScale::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ }
+ Cancel();
+ }
+ break;
+
+ case SID_CHANGEBEZIER:
+ case SID_CHANGEPOLYGON:
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ }
+
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ if( rReq.GetSlot() == SID_CHANGEBEZIER )
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->ConvertMarkedToPathObj(false);
+ }
+ else
+ {
+ if( mpDrawView->IsVectorizeAllowed() )
+ {
+ SetCurrentFunction( FuVectorize::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ }
+ else
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->ConvertMarkedToPolyObj();
+ }
+ }
+
+ Invalidate(SID_CHANGEBEZIER);
+ Invalidate(SID_CHANGEPOLYGON);
+ }
+ Cancel();
+
+ if( HasCurrentFunction(SID_BEZIER_EDIT) )
+ { // where applicable, activate right edit action
+ GetViewFrame()->GetDispatcher()->Execute(SID_SWITCH_POINTEDIT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+ rReq.Ignore ();
+ break;
+
+ case SID_CONVERT_TO_CONTOUR:
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ }
+
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->ConvertMarkedToPathObj(true);
+
+ Invalidate(SID_CONVERT_TO_CONTOUR);
+ }
+ Cancel();
+
+ rReq.Ignore ();
+ break;
+
+ case SID_CONVERT_TO_METAFILE:
+ case SID_CONVERT_TO_BITMAP:
+ {
+ // End text edit mode when it is active because the metafile or
+ // bitmap that will be created does not support it.
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ }
+
+ if ( mpDrawView->IsPresObjSelected(true,true,true) )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+
+ // create SdrGrafObj from metafile/bitmap
+ Graphic aGraphic;
+ switch (nSId)
+ {
+ case SID_CONVERT_TO_METAFILE:
+ {
+ // switch on undo for the next operations
+ mpDrawView->BegUndo(SdResId(STR_UNDO_CONVERT_TO_METAFILE));
+ GDIMetaFile aMetaFile(mpDrawView->GetMarkedObjMetaFile());
+ aGraphic = Graphic(aMetaFile);
+ }
+ break;
+ case SID_CONVERT_TO_BITMAP:
+ {
+ // Disable spelling during conversion
+ bool bOnlineSpell = GetDoc()->GetOnlineSpell();
+ GetDoc()->SetOnlineSpell(false);
+
+ // switch on undo for the next operations
+ mpDrawView->BegUndo(SdResId(STR_UNDO_CONVERT_TO_BITMAP));
+ bool bDone(false);
+
+ // I have to get the image here directly since GetMarkedObjBitmapEx works
+ // based on Bitmaps, but not on BitmapEx, thus throwing away the alpha
+ // channel. Argh! GetMarkedObjBitmapEx itself is too widely used to safely
+ // change that, e.g. in the exchange formats. For now I can only add this
+ // exception to get good results for Svgs. This is how the code gets more
+ // and more crowded, at last I made a remark for myself to change this
+ // as one of the next tasks.
+ if(1 == mpDrawView->GetMarkedObjectCount())
+ {
+ const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(mpDrawView->GetMarkedObjectByIndex(0));
+
+ if(pSdrGrafObj && pSdrGrafObj->isEmbeddedVectorGraphicData())
+ {
+ aGraphic = Graphic(pSdrGrafObj->GetGraphic().getVectorGraphicData()->getReplacement());
+ bDone = true;
+ }
+ }
+
+ if(!bDone)
+ {
+ aGraphic = Graphic(mpDrawView->GetMarkedObjBitmapEx());
+ }
+ // Restore online spelling
+ GetDoc()->SetOnlineSpell(bOnlineSpell);
+ }
+ break;
+ }
+
+ // create new object
+ SdrGrafObj* pGraphicObj = new SdrGrafObj(
+ *GetDoc(),
+ aGraphic);
+
+ // get some necessary info and ensure it
+ const SdrMarkList& rMarkList(mpDrawView->GetMarkedObjectList());
+ const size_t nMarkCount(rMarkList.GetMarkCount());
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+ OSL_ENSURE(nMarkCount, "DrawViewShell::FuTemporary: SID_CONVERT_TO_BITMAP with empty selection (!)");
+ OSL_ENSURE(pPageView, "DrawViewShell::FuTemporary: SID_CONVERT_TO_BITMAP without SdrPageView (!)");
+
+ // fit rectangle of new graphic object to selection's mark rect
+ ::tools::Rectangle aAllMarkedRect;
+ rMarkList.TakeBoundRect(pPageView, aAllMarkedRect);
+ pGraphicObj->SetLogicRect(aAllMarkedRect);
+
+ // #i71540# to keep the order, it is necessary to replace the lowest object
+ // of the selection with the new object. This also means that with multi
+ // selection, all other objects need to be deleted first
+ SdrMark* pFirstMark = rMarkList.GetMark(0);
+ SdrObject* pReplacementCandidate = pFirstMark->GetMarkedSdrObj();
+
+ if(nMarkCount > 1)
+ {
+ // take first object out of selection
+ mpDrawView->MarkObj(pReplacementCandidate, pPageView, true, true);
+
+ // clear remaining selection
+ mpDrawView->DeleteMarkedObj();
+ }
+
+ // #i124816# copy layer from lowest object which gets replaced
+ pGraphicObj->SetLayer(pReplacementCandidate->GetLayer());
+
+ // now replace lowest object with new one
+ mpDrawView->ReplaceObjectAtView(pReplacementCandidate, *pPageView, pGraphicObj);
+
+ // switch off undo
+ mpDrawView->EndUndo();
+ }
+ }
+
+ Cancel();
+
+ rReq.Done ();
+ break;
+
+ case SID_REMOVE_HYPERLINK:
+ {
+ if (mpDrawView->IsTextEdit())
+ {
+ // First make sure the field is selected
+ OutlinerView* pOutView = mpDrawView->GetTextEditOutlinerView();
+ if (pOutView)
+ {
+ pOutView->SelectFieldAtCursor();
+ URLFieldHelper::RemoveURLField(pOutView->GetEditView());
+ }
+ }
+ }
+ Cancel();
+ rReq.Done ();
+ break;
+
+ case SID_SET_DEFAULT:
+ {
+ std::optional<SfxItemSet> pSet;
+
+ if (mpDrawView->IsTextEdit())
+ {
+ pSet.emplace( GetPool(), svl::Items<EE_ITEMS_START, EE_ITEMS_END> );
+ mpDrawView->SetAttributes( *pSet, true );
+ }
+ else
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ // For every presentation object a SfxItemSet of hard attributes
+ // and the UserCall is stored in this list. This is because
+ // at the following mpDrawView->SetAttributes( *pSet, sal_True )
+ // they get lost and have to be restored.
+ std::vector<std::pair<std::unique_ptr<SfxItemSet>,SdrObjUserCall*> > aAttrList;
+ SdPage* pPresPage = static_cast<SdPage*>( mpDrawView->GetSdrPageView()->GetPage() );
+
+ for ( size_t i = 0; i < nCount; ++i )
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+
+ if( pPresPage->IsPresObj( pObj ) )
+ {
+ auto pNewSet = std::make_unique<SfxItemSetFixed<SDRATTR_TEXT_MINFRAMEHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT>>( GetDoc()->GetPool() );
+ pNewSet->Put(pObj->GetMergedItemSet());
+ aAttrList.emplace_back(std::move(pNewSet), pObj->GetUserCall());
+ }
+ }
+
+ pSet.emplace( GetPool() );
+ mpDrawView->SetAttributes( *pSet, true );
+
+ sal_uLong j = 0;
+
+ for ( size_t i = 0; i < nCount; ++i )
+ {
+ SfxStyleSheet* pSheet = nullptr;
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+
+ if (pObj->GetObjIdentifier() == SdrObjKind::TitleText)
+ {
+ pSheet = mpActualPage->GetStyleSheetForPresObj(PresObjKind::Title);
+ if (pSheet)
+ pObj->SetStyleSheet(pSheet, false);
+ }
+ else if(pObj->GetObjIdentifier() == SdrObjKind::OutlineText)
+ {
+ for (sal_uInt16 nLevel = 1; nLevel < 10; nLevel++)
+ {
+ pSheet = mpActualPage->GetStyleSheetForPresObj( PresObjKind::Outline );
+ DBG_ASSERT(pSheet, "Template for outline object not found");
+ if (pSheet)
+ {
+ pObj->StartListening(*pSheet);
+
+ if( nLevel == 1 )
+ // text frame listens on StyleSheet of level1
+ pObj->NbcSetStyleSheet(pSheet, false);
+ }
+ }
+ }
+
+ if( pPresPage->IsPresObj( pObj ) )
+ {
+ std::pair<std::unique_ptr<SfxItemSet>,SdrObjUserCall*> &rAttr = aAttrList[j++];
+
+ std::unique_ptr<SfxItemSet> & pNewSet(rAttr.first);
+ SdrObjUserCall* pUserCall = rAttr.second;
+
+ if ( pNewSet && pNewSet->GetItemState( SDRATTR_TEXT_MINFRAMEHEIGHT ) == SfxItemState::SET )
+ {
+ pObj->SetMergedItem(pNewSet->Get(SDRATTR_TEXT_MINFRAMEHEIGHT));
+ }
+
+ if ( pNewSet && pNewSet->GetItemState( SDRATTR_TEXT_AUTOGROWHEIGHT ) == SfxItemState::SET )
+ {
+ pObj->SetMergedItem(pNewSet->Get(SDRATTR_TEXT_AUTOGROWHEIGHT));
+ }
+
+ if( pUserCall )
+ pObj->SetUserCall( pUserCall );
+ }
+ }
+ }
+
+ pSet.reset();
+ Cancel();
+ }
+ break;
+
+ case SID_DELETE_SNAPITEM:
+ {
+ SdrPageView* pPV;
+ Point aMPos = GetActiveWindow()->PixelToLogic( maMousePos );
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(GetActiveWindow()->PixelToLogic( Size(
+ FuPoor::HITPIX, 0 ) ).Width());
+ sal_uInt16 nHelpLine;
+
+ if( mpDrawView->PickHelpLine( aMPos, nHitLog, *GetActiveWindow()->GetOutDev(), nHelpLine, pPV) )
+ {
+ pPV->DeleteHelpLine( nHelpLine );
+ }
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_DELETE_PAGE:
+ case SID_DELETE_MASTER_PAGE:
+ DeleteActualPage();
+ Cancel();
+ rReq.Ignore ();
+ break;
+
+ case SID_DELETE_LAYER:
+ DeleteActualLayer();
+ Cancel();
+ rReq.Ignore ();
+ break;
+
+ case SID_ORIGINAL_SIZE:
+ mpDrawView->SetMarkedOriginalSize();
+ Cancel();
+ rReq.Done();
+ break;
+
+ case SID_DRAW_FONTWORK:
+ case SID_DRAW_FONTWORK_VERTICAL:
+ {
+ svx::FontworkBar::execute(*mpView, rReq, GetViewFrame()->GetBindings()); // SJ: can be removed (I think)
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_SAVE_GRAPHIC:
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ const SdrGrafObj* pObj = dynamic_cast<const SdrGrafObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj());
+ if (pObj && pObj->GetGraphicType() == GraphicType::Bitmap)
+ {
+ weld::Window* pFrame = GetFrameWeld();
+ GraphicAttr aGraphicAttr = pObj->GetGraphicAttr();
+ short nState = RET_CANCEL;
+ if (aGraphicAttr != GraphicAttr()) // the image has been modified
+ {
+ if (pFrame)
+ {
+ nState = GraphicHelper::HasToSaveTransformedImage(pFrame);
+ }
+ }
+ else
+ {
+ nState = RET_NO;
+ }
+
+ if (nState == RET_YES)
+ {
+ GraphicHelper::ExportGraphic(pFrame, pObj->GetTransformedGraphic(), "");
+ }
+ else if (nState == RET_NO)
+ {
+ const GraphicObject& aGraphicObject(pObj->GetGraphicObject());
+ GraphicHelper::ExportGraphic(pFrame, aGraphicObject.GetGraphic(), "");
+ }
+ }
+ }
+ Cancel();
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_EXTERNAL_EDIT:
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ if( auto pGraphicObj = dynamic_cast<SdrGrafObj*>( pObj ) )
+ if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap )
+ {
+ GraphicObject aGraphicObject( pGraphicObj->GetGraphicObject() );
+ m_ExternalEdits.push_back(
+ std::make_unique<SdrExternalToolEdit>(
+ mpDrawView.get(), pObj));
+ m_ExternalEdits.back()->Edit( &aGraphicObject );
+ }
+ }
+ Cancel();
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_COMPRESS_GRAPHIC:
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGraphicObj = dynamic_cast<SdrGrafObj*>( pObj ) )
+ if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap )
+ {
+ CompressGraphicsDialog dialog(GetFrameWeld(), pGraphicObj, GetViewFrame()->GetBindings() );
+ if (dialog.run() == RET_OK)
+ {
+ SdrGrafObj* pNewObject = dialog.GetCompressedSdrGrafObj();
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+ OUString aUndoString = mpDrawView->GetDescriptionOfMarkedObjects() + " Compress";
+ mpDrawView->BegUndo( aUndoString );
+ mpDrawView->ReplaceObjectAtView( pObj, *pPageView, pNewObject );
+ mpDrawView->EndUndo();
+ }
+ }
+ }
+ Cancel();
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_GRAPHIC_SIZE_CHECK:
+ {
+ sd::GraphicSizeCheckGUIResult aResult(GetDoc());
+ svx::GenericCheckDialog aDialog(GetFrameWeld(), aResult);
+ aDialog.run();
+
+ Cancel();
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_ATTRIBUTES_LINE: // BASIC
+ {
+ SetCurrentFunction( FuLine::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ if (rReq.GetArgs())
+ Cancel();
+ }
+ break;
+
+ case SID_ATTRIBUTES_AREA: // BASIC
+ {
+ SetCurrentFunction( FuArea::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ if (rReq.GetArgs())
+ Cancel();
+ }
+ break;
+
+ case SID_ATTR_TRANSFORM:
+ {
+ SetCurrentFunction( FuTransform::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ // tdf#138963 conditions tested for here must be the same as those
+ // of the early returns from FuTransform::DoExecute
+ if (rReq.GetArgs() || !mpDrawView->AreObjectsMarked())
+ {
+ Invalidate(SID_RULER_OBJECT);
+ Cancel();
+ }
+ }
+ break;
+ case SID_MOVE_SHAPE_HANDLE:
+ {
+ const SfxItemSet *pArgs = rReq.GetArgs ();
+ if (pArgs && pArgs->Count () >= 3)
+ {
+ const SfxUInt32Item* handleNumItem = rReq.GetArg<SfxUInt32Item>(FN_PARAM_1);
+ const SfxUInt32Item* newPosXTwips = rReq.GetArg<SfxUInt32Item>(FN_PARAM_2);
+ const SfxUInt32Item* newPosYTwips = rReq.GetArg<SfxUInt32Item>(FN_PARAM_3);
+ const SfxInt32Item* OrdNum = rReq.GetArg<SfxInt32Item>(FN_PARAM_4);
+
+ const sal_uLong handleNum = handleNumItem->GetValue();
+ const sal_uLong newPosX = convertTwipToMm100(newPosXTwips->GetValue());
+ const sal_uLong newPosY = convertTwipToMm100(newPosYTwips->GetValue());
+
+ mpDrawView->MoveShapeHandle(handleNum, Point(newPosX, newPosY), OrdNum ? OrdNum->GetValue() : -1);
+ Cancel();
+ }
+ break;
+ }
+ case SID_CHAR_DLG_EFFECT:
+ case SID_CHAR_DLG: // BASIC
+ {
+ SetCurrentFunction( FuChar::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_PARA_DLG:
+ {
+ SetCurrentFunction( FuParagraph::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case FN_NUM_BULLET_ON:
+ {
+ // The value (sal_uInt16)0xFFFF means set bullet on/off.
+ SfxUInt16Item aItem(FN_SVX_SET_BULLET, sal_uInt16(0xFFFF));
+ GetViewFrame()->GetDispatcher()->ExecuteList(FN_SVX_SET_BULLET,
+ SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+
+ case FN_NUM_NUMBERING_ON:
+ {
+ // The value (sal_uInt16)0xFFFF means set bullet on/off.
+ SfxUInt16Item aItem(FN_SVX_SET_NUMBER, sal_uInt16(0xFFFF));
+ GetViewFrame()->GetDispatcher()->ExecuteList(FN_SVX_SET_NUMBER,
+ SfxCallMode::RECORD, { &aItem });
+ }
+ break;
+
+ case SID_OUTLINE_BULLET:
+ case FN_SVX_SET_BULLET:
+ case FN_SVX_SET_NUMBER:
+ {
+ SetCurrentFunction( FuBulletAndPosition::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case FN_INSERT_SOFT_HYPHEN:
+ case FN_INSERT_HARDHYPHEN:
+ case FN_INSERT_HARD_SPACE:
+ case FN_INSERT_NNBSP:
+ case SID_INSERT_RLM :
+ case SID_INSERT_LRM :
+ case SID_INSERT_WJ :
+ case SID_INSERT_ZWSP:
+ case SID_CHARMAP:
+ {
+ SetCurrentFunction( FuBullet::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_PRESENTATION_LAYOUT:
+ {
+ SetCurrentFunction( FuPresentationLayout::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) );
+ Cancel();
+ }
+ break;
+
+ case SID_PASTE_SPECIAL:
+ {
+ SetCurrentFunction( FuInsertClipboard::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_CHANGE_PICTURE:
+ case SID_INSERT_GRAPHIC:
+ {
+ SetCurrentFunction( FuInsertGraphic::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq,
+ nSId == SID_CHANGE_PICTURE ) );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_INSERT_AVMEDIA:
+ {
+ SetCurrentFunction( FuInsertAVMedia::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_INSERT_OBJECT:
+ case SID_INSERT_FLOATINGFRAME:
+ case SID_INSERT_MATH:
+ case SID_INSERT_DIAGRAM:
+ case SID_ATTR_TABLE:
+ {
+ SetCurrentFunction( FuInsertOLE::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ // Set the selection tool as the old one. This in particular important for the
+ // zoom function, in which clicking without dragging zooms as well, and that
+ // makes exiting the object editing mode impossible.
+ if (dynamic_cast<FuSelection*>( GetOldFunction().get() ) == nullptr)
+ SetOldFunction( FuSelection::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+ case SID_CLASSIFICATION_APPLY:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ const SfxPoolItem* pItem = nullptr;
+ if (pArgs && pArgs->GetItemState(nSId, false, &pItem) == SfxItemState::SET)
+ {
+ const OUString& rName = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ auto eType = SfxClassificationPolicyType::IntellectualProperty;
+ if (pArgs->GetItemState(SID_TYPE_NAME, false, &pItem) == SfxItemState::SET)
+ {
+ const OUString& rType = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ eType = SfxClassificationHelper::stringToPolicyType(rType);
+ }
+ if (SfxViewFrame* pViewFrame = GetViewFrame())
+ {
+ if (SfxObjectShell* pObjectShell = pViewFrame->GetObjectShell())
+ {
+ SfxClassificationHelper aHelper(pObjectShell->getDocProperties());
+ aHelper.SetBACName(rName, eType);
+ }
+ }
+ }
+ else
+ SAL_WARN("sd.ui", "missing parameter for SID_CLASSIFICATION_APPLY");
+
+ Cancel();
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_CLASSIFICATION_DIALOG:
+ {
+ if (SfxObjectShell* pObjShell = SfxObjectShell::Current())
+ {
+ css::uno::Reference<css::document::XDocumentProperties> xDocProps(pObjShell->getDocProperties());
+ auto xDialog = std::make_shared<svx::ClassificationDialog>(GetFrameWeld(), xDocProps, false, [](){} );
+ ClassificationCollector aCollector(*this, xDocProps);
+ aCollector.collect();
+
+ xDialog->setupValues(std::vector(aCollector.getResults()));
+
+ if (RET_OK == xDialog->run())
+ {
+ ClassificationInserter aInserter(*this, xDocProps);
+ aInserter.insert(xDialog->getResult());
+ }
+ xDialog.reset();
+ }
+
+ Cancel();
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_COPYOBJECTS:
+ {
+ if ( mpDrawView->IsPresObjSelected(false) )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ SetCurrentFunction( FuCopy::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ }
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_INSERTFILE: // BASIC
+ {
+ Broadcast (ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START));
+ SetCurrentFunction( FuInsertFile::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Broadcast (ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END));
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_SELECT_BACKGROUND:
+ case SID_SAVE_BACKGROUND:
+ case SID_ATTR_PAGE_SIZE:
+ case SID_ATTR_PAGE:
+ case SID_PAGESETUP: // BASIC ??
+ {
+ SetCurrentFunction( FuPage::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ rReq.Ignore (); // we generate independent macros !!
+ }
+ break;
+
+ case SID_BEFORE_OBJ:
+ case SID_BEHIND_OBJ:
+ {
+ SetCurrentFunction( FuDisplayOrder::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) );
+ rReq.Done();
+ // finishes itself, no Cancel() needed!
+ }
+ break;
+
+ case SID_REVERSE_ORDER: // BASIC
+ {
+ mpDrawView->ReverseOrderOfMarked();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_ANIMATION_EFFECTS:
+ {
+ SetCurrentFunction( FuObjectAnimationParameters::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) );
+ Cancel();
+ }
+ break;
+
+ case SID_EXECUTE_ANIMATION_EFFECT:
+ {
+ SetCurrentFunction(FuExecuteInteraction::Create(this, GetActiveWindow(),
+ mpDrawView.get(), GetDoc(), rReq));
+ Cancel();
+ }
+ break;
+
+ case SID_LINEEND_POLYGON:
+ {
+ SetCurrentFunction( FuLineEnd::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_CAPTUREPOINT:
+ // negative value to signal call from menu
+ maMousePos = Point(-1,-1);
+ [[fallthrough]];
+ case SID_SET_SNAPITEM:
+ {
+ SetCurrentFunction( FuSnapLine::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) );
+ Cancel();
+ }
+ break;
+
+ case SID_MANAGE_LINKS:
+ {
+ SetCurrentFunction( FuLink::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_THESAURUS:
+ {
+ SetCurrentFunction( FuThesaurus::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_TEXTATTR_DLG:
+ {
+ if (mpDrawView->IsTextEdit())
+ mpDrawView->SdrEndTextEdit();
+ SetCurrentFunction( FuTextAttrDlg::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_MEASURE_DLG:
+ {
+ SetCurrentFunction( FuMeasureDlg::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_CONNECTION_DLG:
+ {
+ SetCurrentFunction( FuConnectionDlg::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_CONNECTION_NEW_ROUTING:
+ {
+ SfxItemSetFixed<SDRATTR_EDGELINE1DELTA, SDRATTR_EDGELINE3DELTA> aDefAttr( GetPool() );
+ GetView()->SetAttributes( aDefAttr, true ); // (ReplaceAll)
+
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_TWAIN_SELECT:
+ {
+ if( mxScannerManager.is() )
+ {
+ try
+ {
+ const css::uno::Sequence< css::scanner::ScannerContext >
+ aContexts( mxScannerManager->getAvailableScanners() );
+
+ if( aContexts.hasElements() )
+ {
+ css::scanner::ScannerContext aContext( aContexts.getConstArray()[ 0 ] );
+
+ Reference<lang::XInitialization> xInit(mxScannerManager, UNO_QUERY);
+ if (xInit.is())
+ {
+ // initialize dialog
+ weld::Window* pWindow = rReq.GetFrameWeld();
+ uno::Sequence<uno::Any> aSeq(comphelper::InitAnyPropertySequence(
+ {
+ {"ParentWindow", pWindow ? uno::Any(pWindow->GetXWindow()) : uno::Any(Reference<awt::XWindow>())}
+ }));
+ xInit->initialize( aSeq );
+ }
+
+ mxScannerManager->configureScannerAndScan( aContext, mxScannerListener );
+ }
+ }
+ catch(...)
+ {
+ }
+ }
+
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_TWAIN_TRANSFER:
+ {
+ bool bDone = false;
+
+ if( mxScannerManager.is() )
+ {
+ try
+ {
+ const css::uno::Sequence< css::scanner::ScannerContext > aContexts( mxScannerManager->getAvailableScanners() );
+
+ if( aContexts.hasElements() )
+ {
+ mxScannerManager->startScan( aContexts.getConstArray()[ 0 ], mxScannerListener );
+ bDone = true;
+ }
+ }
+ catch( ... )
+ {
+ }
+ }
+
+ if( !bDone )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+#ifndef UNX
+ SdResId(STR_TWAIN_NO_SOURCE)
+#else
+ SdResId(STR_TWAIN_NO_SOURCE_UNX)
+#endif
+ ));
+ xInfoBox->run();
+
+ }
+ else
+ {
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_TWAIN_SELECT );
+ rBindings.Invalidate( SID_TWAIN_TRANSFER );
+ }
+
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_POLYGON_MORPHING:
+ {
+ SetCurrentFunction( FuMorph::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_INSERTLAYER:
+ {
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin();
+ sal_uInt16 nLayerCnt = rLayerAdmin.GetLayerCount();
+ sal_uInt16 nLayer = nLayerCnt - 2 + 1;
+ OUString aLayerName = SdResId(STR_LAYER) + OUString::number(nLayer);
+ OUString aLayerTitle, aLayerDesc;
+ bool bIsVisible = false;
+ bool bIsLocked = false;
+ bool bIsPrintable = false;
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if (! pArgs)
+ {
+ SfxItemSetFixed<ATTR_LAYER_START, ATTR_LAYER_END> aNewAttr( GetDoc()->GetPool() );
+
+ aNewAttr.Put( makeSdAttrLayerName( aLayerName ) );
+ aNewAttr.Put( makeSdAttrLayerTitle() );
+ aNewAttr.Put( makeSdAttrLayerDesc() );
+ aNewAttr.Put( makeSdAttrLayerVisible() );
+ aNewAttr.Put( makeSdAttrLayerPrintable() );
+ aNewAttr.Put( makeSdAttrLayerLocked() );
+ aNewAttr.Put( makeSdAttrLayerThisPage() );
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = GetActiveWindow();
+ ScopedVclPtr<AbstractSdInsertLayerDlg> pDlg( pFact->CreateSdInsertLayerDlg(pWin ? pWin->GetFrameWeld() : nullptr, aNewAttr, true, SdResId(STR_INSERTLAYER)) );
+ pDlg->SetHelpId( SD_MOD()->GetSlotPool()->GetSlot( SID_INSERTLAYER )->GetCommand() );
+
+ // test for already existing names
+ bool bLoop = true;
+ while( bLoop && pDlg->Execute() == RET_OK )
+ {
+ pDlg->GetAttr( aNewAttr );
+ aLayerName = static_cast<const SfxStringItem &>( aNewAttr.Get (ATTR_LAYER_NAME)).GetValue ();
+
+ if( rLayerAdmin.GetLayer( aLayerName )
+ || aLayerName.isEmpty()
+ || LayerTabBar::IsLocalizedNameOfStandardLayer( aLayerName) )
+ {
+ // name already exists
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SdResId(STR_WARN_NAME_DUPLICATE)));
+ xWarn->run();
+ }
+ else
+ bLoop = false;
+ }
+ if( bLoop ) // was canceled
+ {
+ pDlg.disposeAndClear();
+ Cancel();
+ rReq.Ignore ();
+ break;
+ }
+ else
+ {
+ aLayerTitle = static_cast<const SfxStringItem &>( aNewAttr.Get (ATTR_LAYER_TITLE)).GetValue ();
+ aLayerDesc = static_cast<const SfxStringItem &>( aNewAttr.Get (ATTR_LAYER_DESC)).GetValue ();
+ bIsVisible = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_VISIBLE)).GetValue ();
+ bIsLocked = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_LOCKED)).GetValue () ;
+ bIsPrintable = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_PRINTABLE)).GetValue () ;
+ }
+ }
+ else if (pArgs->Count () != 4)
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ Cancel();
+ rReq.Ignore ();
+ break;
+ }
+ else
+ {
+ const SfxStringItem* pLayerName = rReq.GetArg<SfxStringItem>(ID_VAL_LAYERNAME);
+ const SfxBoolItem* pIsVisible = rReq.GetArg<SfxBoolItem>(ID_VAL_ISVISIBLE);
+ const SfxBoolItem* pIsLocked = rReq.GetArg<SfxBoolItem>(ID_VAL_ISLOCKED);
+ const SfxBoolItem* pIsPrintable = rReq.GetArg<SfxBoolItem>(ID_VAL_ISPRINTABLE);
+
+ aLayerName = pLayerName->GetValue ();
+ bIsVisible = pIsVisible->GetValue ();
+ bIsLocked = pIsLocked->GetValue ();
+ bIsPrintable = pIsPrintable->GetValue ();
+ }
+
+ OUString aPrevLayer = mpDrawView->GetActiveLayer();
+ SdrLayer* pLayer;
+ sal_uInt16 nPrevLayer = 0;
+ nLayerCnt = rLayerAdmin.GetLayerCount();
+
+ for ( nLayer = 0; nLayer < nLayerCnt; nLayer++ )
+ {
+ pLayer = rLayerAdmin.GetLayer(nLayer);
+ OUString aName = pLayer->GetName();
+
+ if ( aPrevLayer == aName )
+ {
+ nPrevLayer = std::max(nLayer, sal_uInt16(4));
+ }
+ }
+
+ mpDrawView->InsertNewLayer(aLayerName, nPrevLayer + 1);
+ pLayer = rLayerAdmin.GetLayer(aLayerName);
+ if( pLayer )
+ {
+ pLayer->SetTitle( aLayerTitle );
+ pLayer->SetDescription( aLayerDesc );
+ }
+
+ mpDrawView->SetLayerVisible( aLayerName, bIsVisible );
+ mpDrawView->SetLayerLocked( aLayerName, bIsLocked);
+ mpDrawView->SetLayerPrintable(aLayerName, bIsPrintable);
+
+ mpDrawView->SetActiveLayer(aLayerName);
+
+ ResetActualLayer();
+
+ GetDoc()->SetChanged();
+
+ GetViewFrame()->GetDispatcher()->Execute(SID_SWITCHLAYER,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_MODIFYLAYER:
+ {
+ if(!GetLayerTabControl()) // #i87182#
+ {
+ OSL_ENSURE(false, "No LayerTabBar (!)");
+ Cancel();
+ rReq.Ignore();
+ break;
+ }
+
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin();
+ sal_uInt16 nCurPage = GetLayerTabControl()->GetCurPageId();
+ OUString aLayerName = GetLayerTabControl()->GetLayerName(nCurPage);
+ SdrLayer* pLayer = rLayerAdmin.GetLayer(aLayerName);
+
+ OUString aLayerTitle = pLayer->GetTitle();
+ OUString aLayerDesc = pLayer->GetDescription();
+
+ OUString aOldLayerName(aLayerName);
+ OUString aOldLayerTitle(aLayerTitle);
+ OUString aOldLayerDesc(aLayerDesc);
+
+ bool bIsVisible, bIsLocked, bIsPrintable;
+ bool bOldIsVisible = bIsVisible = mpDrawView->IsLayerVisible(aLayerName);
+ bool bOldIsLocked = bIsLocked = mpDrawView->IsLayerLocked(aLayerName);
+ bool bOldIsPrintable = bIsPrintable = mpDrawView->IsLayerPrintable(aLayerName);
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ // is it allowed to delete the layer?
+ bool bDelete = !( LayerTabBar::IsRealNameOfStandardLayer(aLayerName) );
+
+ if (! pArgs)
+ {
+ SfxItemSetFixed<ATTR_LAYER_START, ATTR_LAYER_END> aNewAttr( GetDoc()->GetPool() );
+
+ aNewAttr.Put( makeSdAttrLayerName( aLayerName ) );
+ aNewAttr.Put( makeSdAttrLayerTitle( aLayerTitle ) );
+ aNewAttr.Put( makeSdAttrLayerDesc( aLayerDesc ) );
+ aNewAttr.Put( makeSdAttrLayerVisible( bIsVisible ) );
+ aNewAttr.Put( makeSdAttrLayerLocked( bIsLocked ) );
+ aNewAttr.Put( makeSdAttrLayerPrintable( bIsPrintable ) );
+ aNewAttr.Put( makeSdAttrLayerThisPage() );
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = GetActiveWindow();
+ ScopedVclPtr<AbstractSdInsertLayerDlg> pDlg( pFact->CreateSdInsertLayerDlg(pWin ? pWin->GetFrameWeld() : nullptr, aNewAttr, bDelete, SdResId(STR_MODIFYLAYER)) );
+ pDlg->SetHelpId( SD_MOD()->GetSlotPool()->GetSlot( SID_MODIFYLAYER )->GetCommand() );
+
+ // test for already existing names
+ bool bLoop = true;
+ sal_uInt16 nRet = 0;
+ while( bLoop )
+ {
+ nRet = pDlg->Execute();
+ if (nRet != RET_OK)
+ break;
+ pDlg->GetAttr( aNewAttr );
+ aLayerName = static_cast<const SfxStringItem &>( aNewAttr.Get (ATTR_LAYER_NAME)).GetValue ();
+ if (bDelete)
+ {
+ if( (rLayerAdmin.GetLayer( aLayerName ) && aLayerName != aOldLayerName)
+ || LayerTabBar::IsRealNameOfStandardLayer(aLayerName)
+ || LayerTabBar::IsLocalizedNameOfStandardLayer(aLayerName)
+ || aLayerName.isEmpty() )
+ {
+ // name already exists
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SdResId(STR_WARN_NAME_DUPLICATE)));
+ xWarn->run();
+ }
+ else
+ bLoop = false;
+ }
+ else
+ bLoop = false; // altering name is already disabled in the dialog itself
+ }
+ switch (nRet)
+ {
+ case RET_OK :
+ aLayerTitle = static_cast<const SfxStringItem &>( aNewAttr.Get (ATTR_LAYER_TITLE)).GetValue ();
+ aLayerDesc = static_cast<const SfxStringItem &>( aNewAttr.Get (ATTR_LAYER_DESC)).GetValue ();
+ bIsVisible = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_VISIBLE)).GetValue ();
+ bIsLocked = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_LOCKED)).GetValue ();
+ bIsPrintable = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_PRINTABLE)).GetValue ();
+ break;
+
+ default :
+ pDlg.disposeAndClear();
+ rReq.Ignore ();
+ Cancel ();
+ return;
+ }
+ }
+ else if (pArgs->Count () == 4)
+ {
+ const SfxStringItem* pLayerName = rReq.GetArg<SfxStringItem>(ID_VAL_LAYERNAME);
+ const SfxBoolItem* pIsVisible = rReq.GetArg<SfxBoolItem>(ID_VAL_ISVISIBLE);
+ const SfxBoolItem* pIsLocked = rReq.GetArg<SfxBoolItem>(ID_VAL_ISLOCKED);
+ const SfxBoolItem* pIsPrintable = rReq.GetArg<SfxBoolItem>(ID_VAL_ISPRINTABLE);
+
+ aLayerName = pLayerName->GetValue ();
+ bIsVisible = pIsVisible->GetValue ();
+ bIsLocked = pIsLocked->GetValue ();
+ bIsPrintable = pIsPrintable->GetValue ();
+ }
+ else
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ Cancel ();
+ rReq.Ignore ();
+ break;
+ }
+
+ SfxUndoManager* pManager = GetDoc()->GetDocSh()->GetUndoManager();
+ std::unique_ptr<SdLayerModifyUndoAction> pAction( new SdLayerModifyUndoAction(
+ GetDoc(),
+ pLayer,
+ // old values
+ aOldLayerName,
+ aOldLayerTitle,
+ aOldLayerDesc,
+ bOldIsVisible,
+ bOldIsLocked,
+ bOldIsPrintable,
+ // new values
+ aLayerName,
+ aLayerTitle,
+ aLayerDesc,
+ bIsVisible,
+ bIsLocked,
+ bIsPrintable
+ ) );
+ pManager->AddUndoAction( std::move(pAction) );
+
+ ModifyLayer( pLayer, aLayerName, aLayerTitle, aLayerDesc, bIsVisible, bIsLocked, bIsPrintable );
+
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_RENAMELAYER:
+ {
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ if(GetLayerTabControl()) // #i87182#
+ {
+ GetLayerTabControl()->StartEditMode(GetLayerTabControl()->GetCurPageId());
+ }
+ else
+ {
+ OSL_ENSURE(false, "No LayerTabBar (!)");
+ }
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_EDIT_HYPERLINK :
+ {
+ // Ensure the field is selected first
+ OutlinerView* pOutView = mpDrawView->GetTextEditOutlinerView();
+ if (pOutView)
+ pOutView->SelectFieldAtCursor();
+
+ GetViewFrame()->GetDispatcher()->Execute( SID_HYPERLINK_DIALOG );
+
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_OPEN_HYPERLINK:
+ {
+ OutlinerView* pOutView = mpDrawView->GetTextEditOutlinerView();
+ if ( pOutView )
+ {
+ const SvxFieldData* pField = pOutView->GetFieldAtCursor();
+ if( auto pURLField = dynamic_cast< const SvxURLField *>( pField ) )
+ {
+ SfxStringItem aUrl( SID_FILE_NAME, pURLField->GetURL() );
+ SfxStringItem aTarget( SID_TARGETNAME, pURLField->GetTargetFrame() );
+
+ OUString aReferName;
+ SfxViewFrame* pFrame = GetViewFrame();
+ SfxMedium* pMed = pFrame->GetObjectShell()->GetMedium();
+ if (pMed)
+ aReferName = pMed->GetName();
+
+ SfxFrameItem aFrm( SID_DOCFRAME, pFrame );
+ SfxStringItem aReferer( SID_REFERER, aReferName );
+
+ SfxBoolItem aNewView( SID_OPEN_NEW_VIEW, false );
+ SfxBoolItem aBrowsing( SID_BROWSE, true );
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ {
+ pViewFrm->GetDispatcher()->ExecuteList(SID_OPENDOC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aUrl, &aTarget, &aFrm, &aReferer,
+ &aNewView, &aBrowsing });
+ }
+ }
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_COPY_HYPERLINK_LOCATION:
+ {
+ OutlinerView* pOutView = mpDrawView->GetTextEditOutlinerView();
+ if ( pOutView )
+ {
+ const SvxFieldData* pField = pOutView->GetFieldAtCursor();
+ if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
+ {
+ uno::Reference<datatransfer::clipboard::XClipboard> xClipboard
+ = pOutView->GetWindow()->GetClipboard();
+
+ vcl::unohelper::TextDataObject::CopyStringTo(pURLField->GetURL(), xClipboard, SfxViewShell::Current());
+ }
+ }
+
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_HYPERLINK_SETLINK:
+ {
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ if (pReqArgs)
+ {
+ const SvxHyperlinkItem* pHLItem =
+ &pReqArgs->Get(SID_HYPERLINK_SETLINK);
+
+ if (pHLItem->GetInsertMode() == HLINK_FIELD)
+ {
+ InsertURLField(pHLItem->GetURL(), pHLItem->GetName(),
+ pHLItem->GetTargetFrame());
+ }
+ else if (pHLItem->GetInsertMode() == HLINK_BUTTON)
+ {
+ InsertURLButton(pHLItem->GetURL(), pHLItem->GetName(),
+ pHLItem->GetTargetFrame(), nullptr);
+ }
+ else if (pHLItem->GetInsertMode() == HLINK_DEFAULT)
+ {
+ OutlinerView* pOlView = mpDrawView->GetTextEditOutlinerView();
+
+ if (pOlView || comphelper::LibreOfficeKit::isActive())
+ {
+ InsertURLField(pHLItem->GetURL(), pHLItem->GetName(),
+ pHLItem->GetTargetFrame());
+ }
+ else
+ {
+ InsertURLButton(pHLItem->GetURL(), pHLItem->GetName(),
+ pHLItem->GetTargetFrame(), nullptr);
+ }
+ }
+ }
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_HIDE_LAST_LEVEL:
+ {
+ ESelection aSel;
+ // fdo#78151 editing a PresObjKind::Outline in a master page ?
+ ::Outliner* pOL = GetOutlinerForMasterPageOutlineTextObj(aSel);
+ if (pOL)
+ {
+ //we are on the last paragraph
+ aSel.Adjust();
+ if (aSel.nEndPara == pOL->GetParagraphCount() - 1)
+ {
+ sal_uInt16 nDepth = pOL->GetDepth(aSel.nEndPara);
+ //there exists a previous numbering level
+ if (nDepth != sal_uInt16(-1) && nDepth > 0)
+ {
+ Paragraph* pPara = pOL->GetParagraph(aSel.nEndPara);
+ pOL->Remove(pPara, 1);
+ }
+ }
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_SHOW_NEXT_LEVEL:
+ {
+ const TranslateId STR_PRESOBJ_MPOUTLINE_ARY[]
+ {
+ STR_PRESOBJ_MPOUTLINE,
+ STR_PRESOBJ_MPOUTLLAYER2,
+ STR_PRESOBJ_MPOUTLLAYER3,
+ STR_PRESOBJ_MPOUTLLAYER4,
+ STR_PRESOBJ_MPOUTLLAYER5,
+ STR_PRESOBJ_MPOUTLLAYER6,
+ STR_PRESOBJ_MPOUTLLAYER7,
+ STR_PRESOBJ_MPNOTESTITLE,
+ STR_PRESOBJ_MPNOTESTEXT,
+ STR_PRESOBJ_NOTESTEXT
+ };
+
+ ESelection aSel;
+ // fdo#78151 editing a PresObjKind::Outline in a master page ?
+ ::Outliner* pOL = GetOutlinerForMasterPageOutlineTextObj(aSel);
+ if (pOL)
+ {
+ //we are on the last paragraph
+ aSel.Adjust();
+ if (aSel.nEndPara == pOL->GetParagraphCount() - 1)
+ {
+ sal_uInt16 nDepth = pOL->GetDepth(aSel.nEndPara);
+ //there exists a previous numbering level
+ if (nDepth < 8)
+ {
+ sal_uInt16 nNewDepth = nDepth+1;
+ pOL->Insert(SdResId(STR_PRESOBJ_MPOUTLINE_ARY[nNewDepth]), EE_PARA_APPEND, nNewDepth);
+ }
+ }
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_INSERT_FLD_DATE_FIX:
+ case SID_INSERT_FLD_DATE_VAR:
+ case SID_INSERT_FLD_TIME_FIX:
+ case SID_INSERT_FLD_TIME_VAR:
+ case SID_INSERT_FLD_AUTHOR:
+ case SID_INSERT_FLD_PAGE:
+ case SID_INSERT_FLD_PAGE_TITLE:
+ case SID_INSERT_FLD_PAGES:
+ case SID_INSERT_FLD_FILE:
+ {
+ sal_uInt16 nMul = 1;
+ std::unique_ptr<SvxFieldItem> pFieldItem;
+
+ switch( nSId )
+ {
+ case SID_INSERT_FLD_DATE_FIX:
+ pFieldItem.reset(new SvxFieldItem(
+ SvxDateField( Date( Date::SYSTEM ), SvxDateType::Fix ), EE_FEATURE_FIELD ));
+ break;
+
+ case SID_INSERT_FLD_DATE_VAR:
+ pFieldItem.reset(new SvxFieldItem( SvxDateField(), EE_FEATURE_FIELD ));
+ break;
+
+ case SID_INSERT_FLD_TIME_FIX:
+ pFieldItem.reset(new SvxFieldItem(
+ SvxExtTimeField( ::tools::Time( ::tools::Time::SYSTEM ), SvxTimeType::Fix ), EE_FEATURE_FIELD ));
+ break;
+
+ case SID_INSERT_FLD_TIME_VAR:
+ pFieldItem.reset(new SvxFieldItem( SvxExtTimeField(), EE_FEATURE_FIELD ));
+ break;
+
+ case SID_INSERT_FLD_AUTHOR:
+ {
+ SvtUserOptions aUserOptions;
+ pFieldItem.reset(new SvxFieldItem(
+ SvxAuthorField(
+ aUserOptions.GetFirstName(), aUserOptions.GetLastName(), aUserOptions.GetID() ), EE_FEATURE_FIELD ));
+ }
+ break;
+
+ case SID_INSERT_FLD_PAGE:
+ {
+ pFieldItem.reset(new SvxFieldItem( SvxPageField(), EE_FEATURE_FIELD ));
+ nMul = 3;
+ }
+ break;
+
+ case SID_INSERT_FLD_PAGE_TITLE:
+ {
+ pFieldItem.reset(new SvxFieldItem( SvxPageTitleField(), EE_FEATURE_FIELD));
+ nMul = 3;
+ }
+ break;
+
+ case SID_INSERT_FLD_PAGES:
+ {
+ pFieldItem.reset(new SvxFieldItem( SvxPagesField(), EE_FEATURE_FIELD ));
+ nMul = 3;
+ }
+ break;
+
+ case SID_INSERT_FLD_FILE:
+ {
+ OUString aName;
+ if( GetDocSh()->HasName() )
+ aName = GetDocSh()->GetMedium()->GetName();
+ pFieldItem.reset(new SvxFieldItem( SvxExtFileField( aName ), EE_FEATURE_FIELD ));
+ }
+ break;
+ }
+
+ OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView();
+
+ if( pOLV )
+ {
+ const SvxFieldItem* pOldFldItem = pOLV->GetFieldAtSelection();
+
+ if( pOldFldItem && ( nullptr != dynamic_cast< const SvxURLField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxDateField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxTimeField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtTimeField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtFileField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxAuthorField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxPageField *>( pOldFldItem->GetField() ) ) )
+ {
+ // select field, then it will be deleted when inserting
+ ESelection aSel = pOLV->GetSelection();
+ if( aSel.nStartPos == aSel.nEndPos )
+ aSel.nEndPos++;
+ pOLV->SetSelection( aSel );
+ }
+
+ if( pFieldItem )
+ pOLV->InsertField( *pFieldItem );
+ }
+ else
+ {
+ Outliner* pOutl = GetDoc()->GetInternalOutliner();
+ pOutl->Init( OutlinerMode::TextObject );
+ OutlinerMode nOutlMode = pOutl->GetOutlinerMode();
+ pOutl->SetStyleSheet( 0, nullptr );
+ pOutl->QuickInsertField( *pFieldItem, ESelection() );
+ std::optional<OutlinerParaObject> pOutlParaObject = pOutl->CreateParaObject();
+
+ SdrRectObj* pRectObj = new SdrRectObj(
+ *GetDoc(),
+ SdrObjKind::Text);
+ pRectObj->SetMergedItem(makeSdrTextAutoGrowWidthItem(true));
+
+ pOutl->UpdateFields();
+ pOutl->SetUpdateLayout( true );
+ Size aSize( pOutl->CalcTextSize() );
+ aSize.setWidth( aSize.Width() * nMul );
+ pOutl->SetUpdateLayout( false );
+
+ Point aPos;
+ ::tools::Rectangle aRect( aPos, GetActiveWindow()->GetOutputSizePixel() );
+ aPos = aRect.Center();
+ aPos = GetActiveWindow()->PixelToLogic(aPos);
+ aPos.AdjustX( -(aSize.Width() / 2) );
+ aPos.AdjustY( -(aSize.Height() / 2) );
+
+ ::tools::Rectangle aLogicRect(aPos, aSize);
+ pRectObj->SetLogicRect(aLogicRect);
+ pRectObj->SetOutlinerParaObject( std::move(pOutlParaObject) );
+ mpDrawView->InsertObjectAtView(pRectObj, *mpDrawView->GetSdrPageView());
+ pOutl->Init( nOutlMode );
+ }
+
+ pFieldItem.reset();
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_MODIFY_FIELD:
+ {
+ OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView();
+
+ if( pOLV )
+ {
+ const SvxFieldItem* pFldItem = pOLV->GetFieldAtSelection();
+
+ if( pFldItem && (nullptr != dynamic_cast< const SvxDateField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxAuthorField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtFileField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtTimeField *>( pFldItem->GetField() ) ) )
+ {
+ // Dialog...
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = GetActiveWindow();
+ ScopedVclPtr<AbstractSdModifyFieldDlg> pDlg( pFact->CreateSdModifyFieldDlg(pWin ? pWin->GetFrameWeld() : nullptr, pFldItem->GetField(), pOLV->GetAttribs() ) );
+ if( pDlg->Execute() == RET_OK )
+ {
+ // To make a correct SetAttribs() call at the utlinerView
+ // it is necessary to split the actions here
+ std::unique_ptr<SvxFieldData> pField(pDlg->GetField());
+ ESelection aSel = pOLV->GetSelection();
+ bool bSelectionWasModified(false);
+
+ if( pField )
+ {
+ SvxFieldItem aFieldItem( *pField, EE_FEATURE_FIELD );
+
+ if( aSel.nStartPos == aSel.nEndPos )
+ {
+ bSelectionWasModified = true;
+ aSel.nEndPos++;
+ pOLV->SetSelection( aSel );
+ }
+
+ pOLV->InsertField( aFieldItem );
+
+ // select again for eventual SetAttribs call
+ pOLV->SetSelection( aSel );
+ }
+
+ SfxItemSet aSet( pDlg->GetItemSet() );
+
+ if( aSet.Count() )
+ {
+ pOLV->SetAttribs( aSet );
+
+ ::Outliner* pOutliner = pOLV->GetOutliner();
+ if( pOutliner )
+ pOutliner->UpdateFields();
+ }
+
+ if(pField)
+ {
+ // restore selection to original
+ if(bSelectionWasModified)
+ {
+ aSel.nEndPos--;
+ pOLV->SetSelection( aSel );
+ }
+ }
+ }
+ }
+ }
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_OPEN_XML_FILTERSETTINGS:
+ {
+ try
+ {
+ css::uno::Reference < css::ui::dialogs::XExecutableDialog > xDialog = css::ui::dialogs::XSLTFilterDialog::create( ::comphelper::getProcessComponentContext() );
+ xDialog->execute();
+ }
+ catch( css::uno::RuntimeException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sd.view");
+ }
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_GROUP: // BASIC
+ {
+ if ( mpDrawView->IsPresObjSelected( true, true, true ) )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ mpDrawView->GroupMarked();
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_UNGROUP: // BASIC
+ {
+ mpDrawView->UnGroupMarked();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_NAME_GROUP:
+ {
+ // only allow for single object selection since the name of an object needs
+ // to be unique
+ if(1 == mpDrawView->GetMarkedObjectCount())
+ {
+ // #i68101#
+ SdrObject* pSelected = mpDrawView->GetMarkedObjectByIndex(0);
+ OSL_ENSURE(pSelected, "DrawViewShell::FuTemp03: nMarkCount, but no object (!)");
+ OUString aName(pSelected->GetName());
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxObjectNameDialog> pDlg(pFact->CreateSvxObjectNameDialog(GetFrameWeld(), aName));
+
+ pDlg->SetCheckNameHdl(LINK(this, DrawViewShell, NameObjectHdl));
+
+ if(RET_OK == pDlg->Execute())
+ {
+ pDlg->GetName(aName);
+ pSelected->SetName(aName);
+
+ SdPage* pPage = GetActualPage();
+ if (pPage)
+ pPage->notifyObjectRenamed(pSelected);
+ }
+ }
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_NAVIGATOR_STATE, true );
+ rBindings.Invalidate( SID_CONTEXT );
+
+ Cancel();
+ rReq.Ignore();
+ break;
+ }
+
+ // #i68101#
+ case SID_OBJECT_TITLE_DESCRIPTION:
+ {
+ if(1 == mpDrawView->GetMarkedObjectCount())
+ {
+ SdrObject* pSelected = mpDrawView->GetMarkedObjectByIndex(0);
+ OSL_ENSURE(pSelected, "DrawViewShell::FuTemp03: nMarkCount, but no object (!)");
+ OUString aTitle(pSelected->GetTitle());
+ OUString aDescription(pSelected->GetDescription());
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxObjectTitleDescDialog> pDlg(pFact->CreateSvxObjectTitleDescDialog(
+ GetFrameWeld(), aTitle, aDescription));
+
+ if(RET_OK == pDlg->Execute())
+ {
+ pDlg->GetTitle(aTitle);
+ pDlg->GetDescription(aDescription);
+ pSelected->SetTitle(aTitle);
+ pSelected->SetDescription(aDescription);
+ }
+ }
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_NAVIGATOR_STATE, true );
+ rBindings.Invalidate( SID_CONTEXT );
+
+ Cancel();
+ rReq.Ignore();
+ break;
+ }
+
+ case SID_ENTER_GROUP: // BASIC
+ {
+ mpDrawView->EnterMarkedGroup();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_LEAVE_GROUP: // BASIC
+ {
+ mpDrawView->LeaveOneGroup();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_LEAVE_ALL_GROUPS: // BASIC
+ {
+ mpDrawView->LeaveAllGroup();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_TEXT_COMBINE: // BASIC
+ {
+ // End text edit to avoid conflicts
+ if(mpDrawView->IsTextEdit())
+ mpDrawView->SdrEndTextEdit();
+
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->CombineMarkedTextObjects();
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_COMBINE: // BASIC
+ {
+ // End text edit to avoid conflicts
+ if(mpDrawView->IsTextEdit())
+ mpDrawView->SdrEndTextEdit();
+
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->CombineMarkedObjects(false);
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_DISTRIBUTE_HLEFT:
+ case SID_DISTRIBUTE_HCENTER:
+ case SID_DISTRIBUTE_HDISTANCE:
+ case SID_DISTRIBUTE_HRIGHT:
+ case SID_DISTRIBUTE_VTOP:
+ case SID_DISTRIBUTE_VCENTER:
+ case SID_DISTRIBUTE_VDISTANCE:
+ case SID_DISTRIBUTE_VBOTTOM:
+ {
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ mpDrawView->DistributeMarkedObjects(nSId);
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+ case SID_POLY_MERGE:
+ {
+ // End text edit to avoid conflicts
+ if(mpDrawView->IsTextEdit())
+ mpDrawView->SdrEndTextEdit();
+
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->MergeMarkedObjects(SdrMergeMode::Merge);
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_POLY_SUBSTRACT:
+ {
+ // End text edit to avoid conflicts
+ if(mpDrawView->IsTextEdit())
+ mpDrawView->SdrEndTextEdit();
+
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->MergeMarkedObjects(SdrMergeMode::Subtract);
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_POLY_INTERSECT:
+ {
+ // End text edit to avoid conflicts
+ if(mpDrawView->IsTextEdit())
+ mpDrawView->SdrEndTextEdit();
+
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->MergeMarkedObjects(SdrMergeMode::Intersect);
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_EQUALIZEWIDTH:
+ case SID_EQUALIZEHEIGHT:
+ {
+ // End text edit to avoid conflicts
+ if(mpDrawView->IsTextEdit())
+ mpDrawView->SdrEndTextEdit();
+
+ mpDrawView->EqualizeMarkedObjects(nSId == SID_EQUALIZEWIDTH);
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_DISMANTLE: // BASIC
+ {
+ if ( mpDrawView->IsDismantlePossible() )
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->DismantleMarkedObjects();
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_CONNECT: // BASIC
+ {
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->CombineMarkedObjects();
+ }
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_BREAK: // BASIC
+ {
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ if ( mpDrawView->IsBreak3DObjPossible() )
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->Break3DObj();
+ }
+ else if ( mpDrawView->IsDismantlePossible(true) )
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->DismantleMarkedObjects(true);
+ }
+ else if ( mpDrawView->IsImportMtfPossible() )
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ const size_t nCnt=rMarkList.GetMarkCount();
+
+ // determine the sum of meta objects of all selected meta files
+ sal_uLong nCount = 0;
+ for(size_t nm=0; nm<nCnt; ++nm)
+ {
+ SdrMark* pM=rMarkList.GetMark(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrGrafObj* pGraf= dynamic_cast< SdrGrafObj *>( pObj );
+ SdrOle2Obj* pOle2= dynamic_cast< SdrOle2Obj *>( pObj );
+
+ if (pGraf != nullptr)
+ {
+ if (pGraf->HasGDIMetaFile())
+ {
+ nCount += pGraf->GetGraphic().GetGDIMetaFile().GetActionSize();
+ }
+ else if (pGraf->isEmbeddedVectorGraphicData())
+ {
+ nCount += pGraf->getMetafileFromEmbeddedVectorGraphicData().GetActionSize();
+ }
+ }
+
+ if(pOle2 && pOle2->GetGraphic())
+ {
+ nCount += pOle2->GetGraphic()->GetGDIMetaFile().GetActionSize();
+ }
+ }
+
+ // decide with the sum of all meta objects if we should show a dialog
+ if(nCount < MIN_ACTIONS_FOR_DIALOG)
+ {
+ // nope, no dialog
+ mpDrawView->DoImportMarkedMtf();
+ }
+ else
+ {
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateBreakDlg(GetFrameWeld(), mpDrawView.get(), GetDocSh(), nCount, static_cast<sal_uLong>(nCnt) ));
+ pDlg->Execute();
+ }
+ }
+
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_CONVERT_TO_3D:
+ {
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ if (mpDrawView->IsConvertTo3DObjPossible())
+ {
+ if (mpDrawView->IsTextEdit())
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->ConvertMarkedObjTo3D();
+ }
+ }
+
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_FRAME_TO_TOP: // BASIC
+ {
+ mpDrawView->PutMarkedToTop();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_MOREFRONT: // BASIC
+ case SID_FRAME_UP: // BASIC
+ {
+ mpDrawView->MovMarkedToTop();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_MOREBACK: // BASIC
+ case SID_FRAME_DOWN: // BASIC
+ {
+ mpDrawView->MovMarkedToBtm();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_FRAME_TO_BOTTOM: // BASIC
+ {
+ mpDrawView->PutMarkedToBtm();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_HORIZONTAL: // BASIC
+ case SID_FLIP_HORIZONTAL:
+ {
+ mpDrawView->MirrorAllMarkedHorizontal();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_VERTICAL: // BASIC
+ case SID_FLIP_VERTICAL:
+ {
+ mpDrawView->MirrorAllMarkedVertical();
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_OBJECT_ALIGN_LEFT: // BASIC
+ {
+ mpDrawView->AlignMarkedObjects(SdrHorAlign::Left, SdrVertAlign::NONE);
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_OBJECT_ALIGN_CENTER: // BASIC
+ {
+ mpDrawView->AlignMarkedObjects(SdrHorAlign::Center, SdrVertAlign::NONE);
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_OBJECT_ALIGN_RIGHT: // BASIC
+ {
+ mpDrawView->AlignMarkedObjects(SdrHorAlign::Right, SdrVertAlign::NONE);
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_OBJECT_ALIGN_UP: // BASIC
+ {
+ mpDrawView->AlignMarkedObjects(SdrHorAlign::NONE, SdrVertAlign::Top);
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_OBJECT_ALIGN_MIDDLE: // BASIC
+ {
+ mpDrawView->AlignMarkedObjects(SdrHorAlign::NONE, SdrVertAlign::Center);
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_OBJECT_ALIGN_DOWN: // BASIC
+ {
+ mpDrawView->AlignMarkedObjects(SdrHorAlign::NONE, SdrVertAlign::Bottom);
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_SELECTALL: // BASIC
+ {
+ if( (dynamic_cast<FuSelection*>( GetOldFunction().get() ) != nullptr) &&
+ !GetView()->IsFrameDragSingles() && GetView()->HasMarkablePoints())
+ {
+ if ( !mpDrawView->IsAction() )
+ mpDrawView->MarkAllPoints();
+ }
+ else
+ mpDrawView->SelectAll();
+
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_STYLE_NEW: // BASIC ???
+ case SID_STYLE_APPLY:
+ case SID_STYLE_EDIT:
+ case SID_STYLE_DELETE:
+ case SID_STYLE_HIDE:
+ case SID_STYLE_SHOW:
+ case SID_STYLE_FAMILY:
+ case SID_STYLE_WATERCAN:
+ case SID_STYLE_UPDATE_BY_EXAMPLE:
+ case SID_STYLE_NEW_BY_EXAMPLE:
+ {
+ if( rReq.GetSlot() == SID_STYLE_EDIT && !rReq.GetArgs() )
+ {
+ SfxStyleSheet* pStyleSheet = mpDrawView->GetStyleSheet();
+ if( pStyleSheet && pStyleSheet->GetFamily() == SfxStyleFamily::Page)
+ pStyleSheet = static_cast<SdStyleSheet*>(pStyleSheet)->GetPseudoStyleSheet();
+
+ if( (pStyleSheet == nullptr) && GetView()->IsTextEdit() )
+ {
+ GetView()->SdrEndTextEdit();
+
+ pStyleSheet = mpDrawView->GetStyleSheet();
+ if(pStyleSheet && pStyleSheet->GetFamily() == SfxStyleFamily::Page)
+ pStyleSheet = static_cast<SdStyleSheet*>(pStyleSheet)->GetPseudoStyleSheet();
+ }
+
+ if( pStyleSheet == nullptr )
+ {
+ rReq.Ignore();
+ break;
+ }
+
+ SfxAllItemSet aSet(GetDoc()->GetPool());
+
+ SfxStringItem aStyleNameItem( SID_STYLE_EDIT, pStyleSheet->GetName() );
+ aSet.Put(aStyleNameItem);
+
+ SfxUInt16Item aStyleFamilyItem( SID_STYLE_FAMILY, static_cast<sal_uInt16>(pStyleSheet->GetFamily()) );
+ aSet.Put(aStyleFamilyItem);
+
+ rReq.SetArgs(aSet);
+ }
+
+ if( rReq.GetArgs() )
+ {
+ SetCurrentFunction( FuTemplate::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ if( rReq.GetSlot() == SID_STYLE_APPLY )
+ GetViewFrame()->GetBindings().Invalidate( SID_STYLE_APPLY );
+ Cancel();
+ }
+ else if( rReq.GetSlot() == SID_STYLE_APPLY )
+ GetViewFrame()->GetDispatcher()->Execute( SID_STYLE_DESIGNER, SfxCallMode::ASYNCHRON );
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_IMAP:
+ {
+ sal_uInt16 nId = SvxIMapDlgChildWindow::GetChildWindowId();
+
+ GetViewFrame()->ToggleChildWindow( nId );
+ GetViewFrame()->GetBindings().Invalidate( SID_IMAP );
+
+ if ( GetViewFrame()->HasChildWindow( nId )
+ && ( ( ViewShell::Implementation::GetImageMapDialog() ) != nullptr ) )
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+
+ if ( rMarkList.GetMarkCount() == 1 )
+ UpdateIMapDlg( rMarkList.GetMark( 0 )->GetMarkedSdrObj() );
+ }
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_GRID_FRONT:
+ {
+ mpDrawView->SetGridFront( !mpDrawView->IsGridFront() );
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_HELPLINES_FRONT:
+ {
+ mpDrawView->SetHlplFront( !mpDrawView->IsHlplFront() );
+ Cancel();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_FONTWORK:
+ {
+ if ( rReq.GetArgs() )
+ {
+ GetViewFrame()->SetChildWindow(SvxFontWorkChildWindow::GetChildWindowId(),
+ static_cast<const SfxBoolItem&>(rReq.GetArgs()->
+ Get(SID_FONTWORK)).GetValue());
+ }
+ else
+ {
+ GetViewFrame()->ToggleChildWindow( SvxFontWorkChildWindow::GetChildWindowId() );
+ }
+
+ GetViewFrame()->GetBindings().Invalidate(SID_FONTWORK);
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_COLOR_CONTROL:
+ {
+ if ( rReq.GetArgs() )
+ GetViewFrame()->SetChildWindow(SvxColorChildWindow::GetChildWindowId(),
+ static_cast<const SfxBoolItem&>(rReq.GetArgs()->
+ Get(SID_COLOR_CONTROL)).GetValue());
+ else
+ GetViewFrame()->ToggleChildWindow(SvxColorChildWindow::GetChildWindowId() );
+
+ GetViewFrame()->GetBindings().Invalidate(SID_COLOR_CONTROL);
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_EXTRUSION_TOGGLE:
+ case SID_EXTRUSION_TILT_DOWN:
+ case SID_EXTRUSION_TILT_UP:
+ case SID_EXTRUSION_TILT_LEFT:
+ case SID_EXTRUSION_TILT_RIGHT:
+ case SID_EXTRUSION_3D_COLOR:
+ case SID_EXTRUSION_DEPTH:
+ case SID_EXTRUSION_DIRECTION:
+ case SID_EXTRUSION_PROJECTION:
+ case SID_EXTRUSION_LIGHTING_DIRECTION:
+ case SID_EXTRUSION_LIGHTING_INTENSITY:
+ case SID_EXTRUSION_SURFACE:
+ case SID_EXTRUSION_DEPTH_FLOATER:
+ case SID_EXTRUSION_DIRECTION_FLOATER:
+ case SID_EXTRUSION_LIGHTING_FLOATER:
+ case SID_EXTRUSION_SURFACE_FLOATER:
+ case SID_EXTRUSION_DEPTH_DIALOG:
+ svx::ExtrusionBar::execute( mpDrawView.get(), rReq, GetViewFrame()->GetBindings() );
+ Cancel();
+ rReq.Ignore ();
+ break;
+
+ case SID_FONTWORK_SHAPE:
+ case SID_FONTWORK_SHAPE_TYPE:
+ case SID_FONTWORK_ALIGNMENT:
+ case SID_FONTWORK_SAME_LETTER_HEIGHTS:
+ case SID_FONTWORK_CHARACTER_SPACING:
+ case SID_FONTWORK_KERN_CHARACTER_PAIRS:
+ case SID_FONTWORK_GALLERY_FLOATER:
+ case SID_FONTWORK_CHARACTER_SPACING_FLOATER:
+ case SID_FONTWORK_ALIGNMENT_FLOATER:
+ case SID_FONTWORK_CHARACTER_SPACING_DIALOG:
+ svx::FontworkBar::execute(*mpDrawView, rReq, GetViewFrame()->GetBindings());
+ Cancel();
+ rReq.Ignore ();
+ break;
+
+ case SID_BMPMASK:
+ {
+ GetViewFrame()->ToggleChildWindow( SvxBmpMaskChildWindow::GetChildWindowId() );
+ GetViewFrame()->GetBindings().Invalidate( SID_BMPMASK );
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_NAVIGATOR:
+ {
+ if ( rReq.GetArgs() )
+ GetViewFrame()->SetChildWindow(SID_NAVIGATOR,
+ static_cast<const SfxBoolItem&>(rReq.GetArgs()->
+ Get(SID_NAVIGATOR)).GetValue());
+ else
+ GetViewFrame()->ToggleChildWindow( SID_NAVIGATOR );
+
+ GetViewFrame()->GetBindings().Invalidate(SID_NAVIGATOR);
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_SLIDE_TRANSITIONS_PANEL:
+ case SID_MASTER_SLIDES_PANEL:
+ case SID_CUSTOM_ANIMATION_PANEL:
+ case SID_GALLERY:
+ {
+ // First make sure that the sidebar is visible
+ GetViewFrame()->ShowChildWindow(SID_SIDEBAR);
+
+ OUString panelId;
+ if (nSId == SID_CUSTOM_ANIMATION_PANEL)
+ panelId = "SdCustomAnimationPanel";
+ else if (nSId == SID_GALLERY)
+ panelId = "GalleryPanel";
+ else if (nSId == SID_SLIDE_TRANSITIONS_PANEL)
+ panelId = "SdSlideTransitionPanel";
+ else if (nSId == SID_MASTER_SLIDES_PANEL)
+ panelId = "SdAllMasterPagesPanel";
+
+ ::sfx2::sidebar::Sidebar::TogglePanel(
+ panelId,
+ GetViewFrame()->GetFrame().GetFrameInterface());
+
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_ANIMATION_OBJECTS:
+ {
+ if ( rReq.GetArgs() )
+ GetViewFrame()->SetChildWindow(
+ AnimationChildWindow::GetChildWindowId(),
+ static_cast<const SfxBoolItem&>(rReq.GetArgs()->
+ Get(SID_ANIMATION_OBJECTS)).GetValue());
+ else
+ GetViewFrame()->ToggleChildWindow(
+ AnimationChildWindow::GetChildWindowId() );
+
+ GetViewFrame()->GetBindings().Invalidate(SID_ANIMATION_OBJECTS);
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_3D_WIN:
+ {
+ if ( rReq.GetArgs() )
+ GetViewFrame()->SetChildWindow( Svx3DChildWindow::GetChildWindowId(),
+ static_cast<const SfxBoolItem&>(rReq.GetArgs()->
+ Get( SID_3D_WIN )).GetValue());
+ else
+ GetViewFrame()->ToggleChildWindow( Svx3DChildWindow::GetChildWindowId() );
+
+ GetViewFrame()->GetBindings().Invalidate( SID_3D_WIN );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_CONVERT_TO_3D_LATHE_FAST:
+ {
+ /* The call is enough. The initialization via Start3DCreation and
+ CreateMirrorPolygons is no longer needed if the parameter
+ sal_True is provided. Then a tilted rotary body with an axis left
+ besides the bounding rectangle of the selected objects is drawn
+ immediately and without user interaction. */
+ mpDrawView->SdrEndTextEdit();
+ if(GetActiveWindow())
+ GetActiveWindow()->EnterWait();
+ mpDrawView->End3DCreation(true);
+ Cancel();
+ rReq.Ignore();
+ if(GetActiveWindow())
+ GetActiveWindow()->LeaveWait();
+ }
+ break;
+
+ case SID_PRESENTATION_DLG:
+ {
+ SetCurrentFunction( FuSlideShowDlg::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_REMOTE_DLG:
+ {
+#ifdef ENABLE_SDREMOTE
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateRemoteDialog(GetFrameWeld()));
+ pDlg->Execute();
+#endif
+ }
+ break;
+
+ case SID_CUSTOMSHOW_DLG:
+ {
+ SetCurrentFunction( FuCustomShowDlg::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_EXPAND_PAGE:
+ {
+ SetCurrentFunction( FuExpandPage::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_SUMMARY_PAGE:
+ {
+ mpDrawView->SdrEndTextEdit();
+ SetCurrentFunction( FuSummaryPage::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+#if HAVE_FEATURE_AVMEDIA
+ case SID_AVMEDIA_PLAYER:
+ {
+ GetViewFrame()->ToggleChildWindow( ::avmedia::MediaPlayer::GetChildWindowId() );
+ GetViewFrame()->GetBindings().Invalidate( SID_AVMEDIA_PLAYER );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+#endif
+
+ case SID_PRESENTATION_MINIMIZER:
+ {
+ Reference<XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ Reference<util::XURLTransformer> xParser(util::URLTransformer::create(xContext));
+ Reference<frame::XDispatchProvider> xProvider(GetViewShellBase().GetController()->getFrame(), UNO_QUERY);
+ if (xProvider.is())
+ {
+ util::URL aURL;
+ aURL.Complete = "vnd.com.sun.star.comp.PresentationMinimizer:execute";
+ xParser->parseStrict(aURL);
+ uno::Reference<frame::XDispatch> xDispatch(xProvider->queryDispatch(aURL, OUString(), 0));
+ if (xDispatch.is())
+ {
+ xDispatch->dispatch(aURL, uno::Sequence< beans::PropertyValue >());
+ }
+ }
+ Cancel();
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_DISPLAY_MASTER_BACKGROUND:
+ case SID_DISPLAY_MASTER_OBJECTS:
+ {
+ // Determine current page and toggle visibility of layers
+ // associated with master page background or master page shapes.
+ // FIXME: This solution is wrong, because shapes of master pages need
+ // not be on layer "background" or "backgroundobjects".
+ // See tdf#118613
+ SdPage* pPage = GetActualPage();
+ if (pPage != nullptr
+ && GetDoc() != nullptr)
+ {
+ SdrLayerIDSet aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers();
+ SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin();
+ SdrLayerID aLayerId;
+ if (nSId == SID_DISPLAY_MASTER_BACKGROUND)
+ aLayerId = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ else
+ aLayerId = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ aVisibleLayers.Set(aLayerId, !aVisibleLayers.IsSet(aLayerId));
+ pPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+ }
+ Cancel();
+ rReq.Done(); // Mark task as done to auto-update the state of each buttons tdf#132816
+ }
+ break;
+
+ case SID_PHOTOALBUM:
+ {
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = GetActiveWindow();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateSdPhotoAlbumDialog(
+ pWin ? pWin->GetFrameWeld() : nullptr,
+ GetDoc()));
+
+ pDlg->Execute();
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_INSERT_QRCODE:
+ case SID_EDIT_QRCODE:
+ {
+ VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
+ const uno::Reference<frame::XModel> xModel = GetViewShellBase().GetController()->getModel();
+ ScopedVclPtr<AbstractQrCodeGenDialog> pDlg(pFact->CreateQrCodeGenDialog(
+ GetFrameWeld(), xModel, rReq.GetSlot() == SID_EDIT_QRCODE));
+ pDlg->Execute();
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_ADDITIONS_DIALOG:
+ {
+ OUString sAdditionsTag = "";
+
+ const SfxStringItem* pStringArg = rReq.GetArg<SfxStringItem>(FN_PARAM_ADDITIONS_TAG);
+ if (pStringArg)
+ sAdditionsTag = pStringArg->GetValue();
+
+ VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractAdditionsDialog> pDlg(
+ pFact->CreateAdditionsDialog(GetFrameWeld(), sAdditionsTag));
+ pDlg->Execute();
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_ATTR_GLOW_COLOR:
+ case SID_ATTR_GLOW_RADIUS:
+ case SID_ATTR_GLOW_TRANSPARENCY:
+ case SID_ATTR_SOFTEDGE_RADIUS:
+ case SID_ATTR_TEXTCOLUMNS_NUMBER:
+ case SID_ATTR_TEXTCOLUMNS_SPACING:
+ if (const SfxItemSet* pNewArgs = rReq.GetArgs())
+ mpDrawView->SetAttributes(*pNewArgs);
+ rReq.Done();
+ Cancel();
+ break;
+
+ default:
+ {
+ SAL_WARN( "sd.ui", "Slot without function" );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+ }
+
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->Activate();
+ }
+}
+
+void DrawViewShell::ExecChar( SfxRequest &rReq )
+{
+ SdDrawDocument* pDoc = GetDoc();
+ if (!pDoc || !mpDrawView)
+ return;
+
+ SfxItemSet aEditAttr( pDoc->GetPool() );
+ mpDrawView->GetAttributes( aEditAttr );
+
+ //modified by wj for sym2_1580, if put old itemset into new set,
+ //when mpDrawView->SetAttributes(aNewAttr) it will invalidate all the item
+ // and use old attr to update all the attributes
+// SfxItemSet aNewAttr( GetPool(),
+// EE_ITEMS_START, EE_ITEMS_END );
+// aNewAttr.Put( aEditAttr, sal_False );
+ SfxItemSet aNewAttr( pDoc->GetPool() );
+ //modified end
+
+ sal_uInt16 nSId = rReq.GetSlot();
+
+ switch ( nSId )
+ {
+ case SID_ATTR_CHAR_FONT:
+ if( rReq.GetArgs() )
+ {
+ const SvxFontItem* pItem = rReq.GetArg<SvxFontItem>(SID_ATTR_CHAR_FONT);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+ case SID_ATTR_CHAR_FONTHEIGHT:
+ if( rReq.GetArgs() )
+ {
+ const SvxFontHeightItem* pItem = rReq.GetArg<SvxFontHeightItem>(SID_ATTR_CHAR_FONTHEIGHT);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+ case SID_ATTR_CHAR_WEIGHT:
+ if( rReq.GetArgs() )
+ {
+ const SvxWeightItem* pItem = rReq.GetArg<SvxWeightItem>(SID_ATTR_CHAR_WEIGHT);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+ case SID_ATTR_CHAR_POSTURE:
+ if( rReq.GetArgs() )
+ {
+ const SvxPostureItem* pItem = rReq.GetArg<SvxPostureItem>(SID_ATTR_CHAR_POSTURE);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+ case SID_ATTR_CHAR_UNDERLINE:
+ if( rReq.GetArgs() )
+ {
+ const SvxUnderlineItem* pItem = rReq.GetArg<SvxUnderlineItem>(SID_ATTR_CHAR_UNDERLINE);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ else
+ {
+ FontLineStyle eFU = aEditAttr.Get( EE_CHAR_UNDERLINE ).GetLineStyle();
+ aNewAttr.Put( SvxUnderlineItem( eFU != LINESTYLE_NONE ?LINESTYLE_NONE : LINESTYLE_SINGLE, EE_CHAR_UNDERLINE ) );
+ }
+ }
+ break;
+ case SID_ATTR_CHAR_OVERLINE:
+ if( rReq.GetArgs() )
+ {
+ const SvxOverlineItem* pItem = rReq.GetArg<SvxOverlineItem>(SID_ATTR_CHAR_OVERLINE);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ else
+ {
+ FontLineStyle eFU = aEditAttr.Get( EE_CHAR_OVERLINE ).GetLineStyle();
+ aNewAttr.Put( SvxOverlineItem( eFU != LINESTYLE_NONE ?LINESTYLE_NONE : LINESTYLE_SINGLE, EE_CHAR_OVERLINE ) );
+ }
+ }
+ break;
+
+ case SID_ULINE_VAL_NONE:
+ {
+ aNewAttr.Put(SvxUnderlineItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE));
+ break;
+ }
+
+ case SID_ULINE_VAL_SINGLE:
+ case SID_ULINE_VAL_DOUBLE:
+ case SID_ULINE_VAL_DOTTED:
+ {
+ FontLineStyle eOld = aEditAttr.Get(EE_CHAR_UNDERLINE).GetLineStyle();
+ FontLineStyle eNew = eOld;
+
+ switch (nSId)
+ {
+ case SID_ULINE_VAL_SINGLE:
+ eNew = ( eOld == LINESTYLE_SINGLE ) ? LINESTYLE_NONE : LINESTYLE_SINGLE;
+ break;
+ case SID_ULINE_VAL_DOUBLE:
+ eNew = ( eOld == LINESTYLE_DOUBLE ) ? LINESTYLE_NONE : LINESTYLE_DOUBLE;
+ break;
+ case SID_ULINE_VAL_DOTTED:
+ eNew = ( eOld == LINESTYLE_DOTTED ) ? LINESTYLE_NONE : LINESTYLE_DOTTED;
+ break;
+ }
+
+ SvxUnderlineItem aUnderline(eNew, EE_CHAR_UNDERLINE);
+ aNewAttr.Put(aUnderline);
+ }
+ break;
+
+ case SID_ATTR_CHAR_SHADOWED:
+ if( rReq.GetArgs() )
+ {
+ const SvxShadowedItem* pItem = rReq.GetArg<SvxShadowedItem>(SID_ATTR_CHAR_SHADOWED);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+ case SID_ATTR_CHAR_CONTOUR:
+ if( rReq.GetArgs() )
+ {
+ const SvxContourItem* pItem = rReq.GetArg<SvxContourItem>(SID_ATTR_CHAR_CONTOUR);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+
+ case SID_ATTR_CHAR_STRIKEOUT:
+ if( rReq.GetArgs() )
+ {
+ const SvxCrossedOutItem* pItem = rReq.GetArg<SvxCrossedOutItem>(SID_ATTR_CHAR_STRIKEOUT);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+ case SID_ATTR_CHAR_COLOR:
+ if( rReq.GetArgs() )
+ {
+ const SvxColorItem* pItem = rReq.GetArg<SvxColorItem>(SID_ATTR_CHAR_COLOR);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+ case SID_ATTR_CHAR_KERNING:
+ if( rReq.GetArgs() )
+ {
+ const SvxKerningItem* pItem = rReq.GetArg<SvxKerningItem>(SID_ATTR_CHAR_KERNING);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+ case SID_ATTR_CHAR_CASEMAP:
+ if( rReq.GetArgs() )
+ {
+ const SvxCaseMapItem* pItem = rReq.GetArg<SvxCaseMapItem>(SID_ATTR_CHAR_CASEMAP);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+ case SID_SET_SUB_SCRIPT:
+ {
+ SvxEscapementItem aItem( EE_CHAR_ESCAPEMENT );
+ SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue());
+ if( eEsc == SvxEscapement::Subscript )
+ aItem.SetEscapement( SvxEscapement::Off );
+ else
+ aItem.SetEscapement( SvxEscapement::Subscript );
+ aNewAttr.Put( aItem );
+ }
+ break;
+ case SID_SET_SUPER_SCRIPT:
+ {
+ SvxEscapementItem aItem( EE_CHAR_ESCAPEMENT );
+ SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue());
+ if( eEsc == SvxEscapement::Superscript )
+ aItem.SetEscapement( SvxEscapement::Off );
+ else
+ aItem.SetEscapement( SvxEscapement::Superscript );
+ aNewAttr.Put( aItem );
+ }
+ break;
+ case SID_SHRINK_FONT_SIZE:
+ case SID_GROW_FONT_SIZE:
+ {
+ const SvxFontListItem* pFonts = dynamic_cast<const SvxFontListItem*>(GetDocSh()->GetItem( SID_ATTR_CHAR_FONTLIST ) );
+ const FontList* pFontList = pFonts ? pFonts->GetFontList() : nullptr;
+ if( pFontList )
+ {
+ FuText::ChangeFontSize( nSId == SID_GROW_FONT_SIZE, nullptr, pFontList, mpView );
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ }
+ break;
+ }
+ case SID_ATTR_CHAR_BACK_COLOR:
+ if( rReq.GetArgs() )
+ {
+ const SvxColorItem* pItem = rReq.GetArg<SvxColorItem>(SID_ATTR_CHAR_BACK_COLOR);
+ if (pItem)
+ {
+ aNewAttr.Put(*pItem);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ mpDrawView->SetAttributes(aNewAttr);
+ rReq.Done();
+ Cancel();
+}
+
+/** This method consists basically of three parts:
+ 1. Process the arguments of the SFX request.
+ 2. Use the model to create a new page or duplicate an existing one.
+ 3. Update the tab control and switch to the new page.
+*/
+SdPage* DrawViewShell::CreateOrDuplicatePage (
+ SfxRequest& rRequest,
+ PageKind ePageKind,
+ SdPage* pPage,
+ const sal_Int32 nInsertPosition)
+{
+ SdPage* pNewPage = nullptr;
+ if (ePageKind == PageKind::Standard && meEditMode != EditMode::MasterPage)
+ {
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+ pNewPage = ViewShell::CreateOrDuplicatePage (rRequest, ePageKind, pPage, nInsertPosition);
+ }
+ return pNewPage;
+}
+
+void DrawViewShell::DuplicateSelectedSlides (SfxRequest& rRequest)
+{
+ // Create a list of the pages that are to be duplicated. The process of
+ // duplication alters the selection.
+ sal_Int32 nInsertPosition (0);
+ ::std::vector<SdPage*> aPagesToDuplicate;
+ sd::slidesorter::SlideSorter &mrSlideSorter = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase())->GetSlideSorter();
+ sd::slidesorter::model::PageEnumeration aSelectedPages (
+ sd::slidesorter::model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel()));
+ while (aSelectedPages.HasMoreElements())
+ {
+ sd::slidesorter::model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ if (pDescriptor && pDescriptor->GetPage())
+ {
+ aPagesToDuplicate.push_back(pDescriptor->GetPage());
+ nInsertPosition = pDescriptor->GetPage()->GetPageNum()+2;
+ }
+ }
+
+ // Duplicate the pages in aPagesToDuplicate and collect the newly
+ // created pages in aPagesToSelect.
+ const bool bUndo (aPagesToDuplicate.size()>1 && mrSlideSorter.GetView().IsUndoEnabled());
+ if (bUndo)
+ mrSlideSorter.GetView().BegUndo(SdResId(STR_INSERTPAGE));
+
+ ::std::vector<SdPage*> aPagesToSelect;
+ for(::std::vector<SdPage*>::const_iterator
+ iPage(aPagesToDuplicate.begin()),
+ iEnd(aPagesToDuplicate.end());
+ iPage!=iEnd;
+ ++iPage, nInsertPosition+=2)
+ {
+ aPagesToSelect.push_back(
+ mrSlideSorter.GetViewShell()->CreateOrDuplicatePage(
+ rRequest, PageKind::Standard, *iPage, nInsertPosition));
+ }
+ aPagesToDuplicate.clear();
+
+ if (bUndo)
+ mrSlideSorter.GetView().EndUndo();
+
+ // Set the selection to the pages in aPagesToSelect.
+ sd::slidesorter::controller::PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector());
+ rSelector.DeselectAllPages();
+ for (auto const& it: aPagesToSelect)
+ {
+ rSelector.SelectPage(it);
+ }
+}
+
+void DrawViewShell::ExecutePropPanelAttr (SfxRequest const & rReq)
+{
+ if(SlideShow::IsRunning( GetViewShellBase() ))
+ return;
+
+ SdDrawDocument* pDoc = GetDoc();
+ if (!pDoc || !mpDrawView)
+ return;
+
+ sal_uInt16 nSId = rReq.GetSlot();
+ SfxItemSet aAttrs( pDoc->GetPool() );
+
+ switch ( nSId )
+ {
+ case SID_TABLE_VERT_NONE:
+ case SID_TABLE_VERT_CENTER:
+ case SID_TABLE_VERT_BOTTOM:
+ SdrTextVertAdjust eTVA = SDRTEXTVERTADJUST_TOP;
+ if (nSId == SID_TABLE_VERT_CENTER)
+ eTVA = SDRTEXTVERTADJUST_CENTER;
+ else if (nSId == SID_TABLE_VERT_BOTTOM)
+ eTVA = SDRTEXTVERTADJUST_BOTTOM;
+
+ aAttrs.Put( SdrTextVertAdjustItem(eTVA) );
+ mpDrawView->SetAttributes(aAttrs);
+
+ break;
+ }
+}
+
+void DrawViewShell::GetStatePropPanelAttr(SfxItemSet& rSet)
+{
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ SdDrawDocument* pDoc = GetDoc();
+ if (!pDoc || !mpDrawView)
+ return;
+
+ SfxItemSet aAttrs( pDoc->GetPool() );
+ mpDrawView->GetAttributes( aAttrs );
+
+ while ( nWhich )
+ {
+ sal_uInt16 nSlotId = SfxItemPool::IsWhich(nWhich)
+ ? GetPool().GetSlotId(nWhich)
+ : nWhich;
+ switch ( nSlotId )
+ {
+ case SID_TABLE_VERT_NONE:
+ case SID_TABLE_VERT_CENTER:
+ case SID_TABLE_VERT_BOTTOM:
+ bool bContour = false;
+ SfxItemState eConState = aAttrs.GetItemState( SDRATTR_TEXT_CONTOURFRAME );
+ if( eConState != SfxItemState::DONTCARE )
+ {
+ bContour = aAttrs.Get( SDRATTR_TEXT_CONTOURFRAME ).GetValue();
+ }
+ if (bContour) break;
+
+ SfxItemState eVState = aAttrs.GetItemState( SDRATTR_TEXT_VERTADJUST );
+ //SfxItemState eHState = aAttrs.GetItemState( SDRATTR_TEXT_HORZADJUST );
+
+ //if(SfxItemState::DONTCARE != eVState && SfxItemState::DONTCARE != eHState)
+ if(SfxItemState::DONTCARE != eVState)
+ {
+ SdrTextVertAdjust eTVA = aAttrs.Get(SDRATTR_TEXT_VERTADJUST).GetValue();
+ bool bSet = (nSlotId == SID_TABLE_VERT_NONE && eTVA == SDRTEXTVERTADJUST_TOP) ||
+ (nSlotId == SID_TABLE_VERT_CENTER && eTVA == SDRTEXTVERTADJUST_CENTER) ||
+ (nSlotId == SID_TABLE_VERT_BOTTOM && eTVA == SDRTEXTVERTADJUST_BOTTOM);
+ rSet.Put(SfxBoolItem(nSlotId, bSet));
+ }
+ else
+ {
+ rSet.Put(SfxBoolItem(nSlotId, false));
+ }
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviews3.cxx b/sd/source/ui/view/drviews3.cxx
new file mode 100644
index 000000000..3f16136ff
--- /dev/null
+++ b/sd/source/ui/view/drviews3.cxx
@@ -0,0 +1,1106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <DrawViewShell.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/tstpitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/protitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <svx/svdotable.hxx>
+#include <editeng/numitem.hxx>
+#include <svx/rulritem.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svdpagv.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/dispatch.hxx>
+#include <tools/urlobj.hxx>
+#include <svl/eitem.hxx>
+#include <svl/rectitem.hxx>
+#include <svl/stritem.hxx>
+#include <svx/svdoole2.hxx>
+#include <svl/itempool.hxx>
+#include <svl/ptitem.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/sberrors.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/f3dchild.hxx>
+#include <svx/float3d.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/diagram/IDiagramHelper.hxx>
+
+#include <app.hrc>
+#include <strings.hrc>
+
+#include <sdundogr.hxx>
+#include <undopage.hxx>
+#include <fupoor.hxx>
+#include <slideshow.hxx>
+#include <sdpage.hxx>
+#include <Window.hxx>
+#include <sdresid.hxx>
+#include <unokywds.hxx>
+#include <drawview.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <sdabstdlg.hxx>
+#include <sfx2/ipclient.hxx>
+#include <tools/diagnose_ex.h>
+#include <ViewShellBase.hxx>
+#include <FormShellManager.hxx>
+#include <LayerTabBar.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <com/sun/star/drawing/framework/XConfiguration.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <editeng/lspcitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <memory>
+#include <comphelper/processfactory.hxx>
+#include <oox/drawingml/diagram/diagram.hxx>
+#include <oox/export/drawingml.hxx>
+#include <oox/shape/ShapeFilterBase.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::com::sun::star::frame::XFrame;
+using ::com::sun::star::frame::XController;
+
+namespace sd {
+
+/**
+ * handle SfxRequests for controller
+ */
+void DrawViewShell::ExecCtrl(SfxRequest& rReq)
+{
+ // except a page switch and jumps to bookmarks, nothing is executed during
+ // a slide show
+ if( HasCurrentFunction(SID_PRESENTATION) &&
+ rReq.GetSlot() != SID_SWITCHPAGE &&
+ rReq.GetSlot() != SID_JUMPTOMARK)
+ return;
+
+ CheckLineTo (rReq);
+
+ // End text edit mode for some requests.
+ sal_uInt16 nSlot = rReq.GetSlot();
+ bool bAllowFocusChange = true;
+ switch (nSlot)
+ {
+ case SID_OUTPUT_QUALITY_COLOR:
+ case SID_OUTPUT_QUALITY_GRAYSCALE:
+ case SID_OUTPUT_QUALITY_BLACKWHITE:
+ case SID_OUTPUT_QUALITY_CONTRAST:
+ // Do nothing.
+ break;
+ case SID_SWITCHPAGE:
+ if (rReq.GetArgs() && rReq.GetArgs()->Count () == 1)
+ {
+ const SfxBoolItem* pAllowFocusChange = rReq.GetArg<SfxBoolItem>(SID_SWITCHPAGE);
+ bAllowFocusChange = pAllowFocusChange->GetValue();
+ if (!bAllowFocusChange)
+ break;
+ }
+ [[fallthrough]];
+ default:
+ if ( mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+ }
+
+ // sal_uInt16 nSlot = rReq.GetSlot();
+ switch (nSlot)
+ {
+ case SID_SWITCHPAGE: // BASIC
+ {
+ // switch page in running slide show
+ if(SlideShow::IsRunning(GetViewShellBase()) && rReq.GetArgs())
+ {
+ if (const SfxUInt32Item* pWhatPage = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATPAGE))
+ SlideShow::GetSlideShow(GetViewShellBase())->jumpToPageNumber(static_cast<sal_Int32>((pWhatPage->GetValue()-1)>>1));
+ }
+ else
+ {
+ const SfxItemSet *pArgs = rReq.GetArgs ();
+ sal_uInt16 nSelectedPage = 0;
+
+ if (! pArgs || pArgs->Count () == 1)
+ {
+ nSelectedPage = maTabControl->GetCurPagePos();
+ }
+ else if (pArgs->Count () == 2)
+ {
+ const SfxUInt32Item* pWhatPage = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATPAGE);
+ const SfxUInt32Item* pWhatKind = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATKIND);
+
+ sal_Int32 nWhatPage = static_cast<sal_Int32>(pWhatPage->GetValue ());
+ PageKind nWhatKind = static_cast<PageKind>(pWhatKind->GetValue ());
+ if (nWhatKind < PageKind::Standard || nWhatKind > PageKind::Handout)
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE);
+#endif
+ rReq.Ignore ();
+ break;
+ }
+ else if (meEditMode != EditMode::MasterPage)
+ {
+ if (! CHECK_RANGE (0, nWhatPage, GetDoc()->GetSdPageCount(nWhatKind)))
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE);
+#endif
+ rReq.Ignore ();
+ break;
+ }
+
+ nSelectedPage = static_cast<short>(nWhatPage);
+ mePageKind = nWhatKind;
+ }
+ }
+ else
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ rReq.Ignore ();
+ break;
+ }
+
+ if( GetDocSh() && (GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED))
+ GetDocSh()->SetModified();
+
+ SwitchPage(nSelectedPage, bAllowFocusChange);
+
+ if(HasCurrentFunction(SID_BEZIER_EDIT))
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+
+ Invalidate();
+ InvalidateWindows();
+ rReq.Done ();
+ }
+ break;
+ }
+
+ case SID_SWITCHLAYER: // BASIC
+ {
+ const SfxItemSet *pArgs = rReq.GetArgs ();
+
+ // #i87182#
+ bool bCurPageValid(false);
+ sal_uInt16 nCurPage(0);
+
+ if(GetLayerTabControl())
+ {
+ nCurPage = GetLayerTabControl()->GetCurPageId();
+ bCurPageValid = true;
+ }
+
+ if(pArgs && 1 == pArgs->Count())
+ {
+ const SfxUInt32Item* pWhatLayer = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYER);
+
+ if(pWhatLayer)
+ {
+ nCurPage = static_cast<short>(pWhatLayer->GetValue());
+ bCurPageValid = true;
+ }
+ }
+
+ if(bCurPageValid)
+ {
+ OUString aLayerName( GetLayerTabControl()->GetLayerName(nCurPage));
+ if (!aLayerName.isEmpty())
+ {
+ mpDrawView->SetActiveLayer(aLayerName);
+ }
+ Invalidate();
+ }
+
+ rReq.Done ();
+
+ break;
+ }
+
+ case SID_PAGEMODE: // BASIC
+ {
+
+ const SfxItemSet *pArgs = rReq.GetArgs();
+
+ if (pArgs && pArgs->Count () == 2)
+ {
+ const SfxBoolItem* pIsActive = rReq.GetArg<SfxBoolItem>(ID_VAL_ISACTIVE);
+ const SfxUInt32Item* pWhatKind = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATKIND);
+
+ PageKind nWhatKind = static_cast<PageKind>(pWhatKind->GetValue());
+ if ( nWhatKind >= PageKind::Standard && nWhatKind <= PageKind::Handout)
+ {
+ mbIsLayerModeActive = pIsActive->GetValue();
+ mePageKind = nWhatKind;
+ }
+ }
+
+ // turn on default layer of page
+ mpDrawView->SetActiveLayer(sUNO_LayerName_layout);
+
+ ChangeEditMode(EditMode::Page, mbIsLayerModeActive);
+
+ Invalidate();
+ rReq.Done ();
+
+ break;
+ }
+
+ case SID_LAYERMODE: // BASIC
+ {
+ const SfxItemSet *pArgs = rReq.GetArgs();
+
+ if (pArgs && pArgs->Count() == 2)
+ {
+ const SfxUInt32Item* pWhatLayer = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYER);
+ EditMode nWhatLayer = static_cast<EditMode>(pWhatLayer->GetValue());
+ if (nWhatLayer == EditMode::Page || nWhatLayer == EditMode::MasterPage)
+ {
+ mbIsLayerModeActive = rReq.GetArg<SfxBoolItem>(ID_VAL_ISACTIVE)->GetValue();
+ meEditMode = nWhatLayer;
+ }
+ }
+
+ ChangeEditMode(meEditMode, !mbIsLayerModeActive);
+
+ Invalidate();
+ rReq.Done();
+
+ break;
+ }
+
+ case SID_HEADER_AND_FOOTER:
+ case SID_INSERT_PAGE_NUMBER:
+ case SID_INSERT_DATE_TIME:
+ {
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = GetActiveWindow();
+ VclPtr<AbstractHeaderFooterDialog> pDlg(pFact->CreateHeaderFooterDialog(this, pWin ? pWin->GetFrameWeld() : nullptr, GetDoc(), mpActualPage));
+ auto xRequest = std::make_shared<SfxRequest>(rReq);
+ rReq.Ignore(); // the 'old' request is not relevant any more
+ pDlg->StartExecuteAsync([this, pDlg, xRequest](sal_Int32 /*nResult*/){
+ GetActiveWindow()->Invalidate();
+ UpdatePreview( mpActualPage );
+
+ Invalidate();
+ xRequest->Done();
+
+ pDlg->disposeOnce();
+ });
+ break;
+ }
+
+ case SID_MASTER_LAYOUTS:
+ {
+ SdPage* pPage = GetActualPage();
+ if (meEditMode == EditMode::MasterPage)
+ // Use the master page of the current page.
+ pPage = static_cast<SdPage*>(&pPage->TRG_GetMasterPage());
+
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = GetActiveWindow();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateMasterLayoutDialog(pWin ? pWin->GetFrameWeld() : nullptr, GetDoc(), pPage));
+ pDlg->Execute();
+ Invalidate();
+ rReq.Done ();
+ break;
+ }
+ case SID_OBJECTRESIZE:
+ {
+ // The server likes to change the client size
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ SfxInPlaceClient* pIPClient = GetViewShell()->GetIPClient();
+
+ if ( pIPClient && pIPClient->IsObjectInPlaceActive() )
+ {
+ const SfxRectangleItem& rRect =
+ rReq.GetArgs()->Get(SID_OBJECTRESIZE);
+ ::tools::Rectangle aRect( GetActiveWindow()->PixelToLogic( rRect.GetValue() ) );
+
+ if ( mpDrawView->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ SdrOle2Obj* pOle2Obj = dynamic_cast< SdrOle2Obj* >( pObj );
+ if(pOle2Obj)
+ {
+ if( pOle2Obj->GetObjRef().is() )
+ {
+ pOle2Obj->SetLogicRect(aRect);
+ }
+ }
+ }
+ }
+ }
+ rReq.Ignore ();
+ break;
+ }
+
+ case SID_RELOAD:
+ {
+ sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId();
+ SfxViewFrame* pFrame = GetViewFrame();
+
+ try
+ {
+ Reference< XFrame > xFrame( pFrame->GetFrame().GetFrameInterface(), UNO_SET_THROW );
+
+ // Save the current configuration of panes and views.
+ Reference<XControllerManager> xControllerManager (
+ GetViewShellBase().GetController(), UNO_QUERY_THROW);
+ Reference<XConfigurationController> xConfigurationController (
+ xControllerManager->getConfigurationController(), UNO_SET_THROW );
+ Reference<XConfiguration> xConfiguration (
+ xConfigurationController->getRequestedConfiguration(), UNO_SET_THROW );
+
+ SfxChildWindow* pWindow = pFrame->GetChildWindow(nId);
+ if(pWindow)
+ {
+ Svx3DWin* p3DWin = static_cast<Svx3DWin*>(pWindow->GetWindow());
+ if(p3DWin)
+ p3DWin->DocumentReload();
+ }
+
+ // normal forwarding to ViewFrame for execution
+ GetViewFrame()->ExecuteSlot(rReq);
+
+ // From here on we must cope with this object and the frame already being
+ // deleted. Do not call any methods or use data members.
+ Reference<XController> xController( xFrame->getController(), UNO_SET_THROW );
+
+ // Restore the configuration.
+ xControllerManager.set( xController, UNO_QUERY_THROW );
+ xConfigurationController.set( xControllerManager->getConfigurationController() );
+ if ( ! xConfigurationController.is())
+ throw RuntimeException();
+ xConfigurationController->restoreConfiguration(xConfiguration);
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd.view");
+ }
+
+ // We have to return immediately to avoid accessing this object.
+ return;
+ }
+
+ case SID_JUMPTOMARK:
+ {
+ if( rReq.GetArgs() )
+ {
+ const SfxStringItem* pBookmark = rReq.GetArg<SfxStringItem>(SID_JUMPTOMARK);
+
+ if (pBookmark)
+ {
+ OUString sBookmark(INetURLObject::decode(pBookmark->GetValue(), INetURLObject::DecodeMechanism::WithCharset));
+
+ rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if(xSlideshow.is() && xSlideshow->isRunning())
+ {
+ xSlideshow->jumpToBookmark(sBookmark);
+ }
+ else
+ {
+ GotoBookmark(sBookmark);
+ }
+ }
+ }
+ rReq.Done();
+ break;
+ }
+
+ case SID_OUTPUT_QUALITY_COLOR:
+ case SID_OUTPUT_QUALITY_GRAYSCALE:
+ case SID_OUTPUT_QUALITY_BLACKWHITE:
+ case SID_OUTPUT_QUALITY_CONTRAST:
+ {
+ ExecReq( rReq );
+ break;
+ }
+
+ case SID_MAIL_SCROLLBODY_PAGEDOWN:
+ {
+ ExecReq( rReq );
+ break;
+ }
+
+ case SID_ATTR_YEAR2000:
+ {
+ FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell();
+ if (pFormShell != nullptr)
+ {
+ const SfxPoolItem* pItem;
+ if (rReq.GetArgs()->GetItemState(
+ SID_ATTR_YEAR2000, true, &pItem) == SfxItemState::SET)
+ pFormShell->SetY2KState (
+ static_cast<const SfxUInt16Item*>(pItem)->GetValue());
+ }
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_OPT_LOCALE_CHANGED:
+ {
+ GetActiveWindow()->Invalidate();
+ UpdatePreview( mpActualPage );
+ rReq.Done();
+ }
+ break;
+
+ case SID_REGENERATE_DIAGRAM:
+ case SID_EDIT_DIAGRAM:
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+
+ if (1 == rMarkList.GetMarkCount())
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ // Support advanced DiagramHelper
+ if(nullptr != pObj && pObj->isDiagram())
+ {
+ if(SID_REGENERATE_DIAGRAM == nSlot)
+ {
+ mpDrawView->UnmarkAll();
+ pObj->getDiagramHelper()->reLayout(*static_cast<SdrObjGroup*>(pObj));
+ mpDrawView->MarkObj(pObj, mpDrawView->GetSdrPageView());
+ }
+ else // SID_EDIT_DIAGRAM
+ {
+ VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg = pFact->CreateDiagramDialog(
+ GetFrameWeld(),
+ *static_cast<SdrObjGroup*>(pObj));
+ pDlg->Execute();
+ }
+ }
+ }
+
+ rReq.Done();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void DrawViewShell::ExecRuler(SfxRequest& rReq)
+{
+ // nothing is executed during a slide show!
+ if(HasCurrentFunction(SID_PRESENTATION))
+ return;
+
+ CheckLineTo (rReq);
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ const Point aPagePos( GetActiveWindow()->GetViewOrigin() );
+ Size aPageSize = mpActualPage->GetSize();
+ Size aViewSize = GetActiveWindow()->GetViewSize();
+
+ switch ( rReq.GetSlot() )
+ {
+ case SID_ATTR_LONG_LRSPACE:
+ if (pArgs)
+ {
+ std::unique_ptr<SdUndoGroup> pUndoGroup(new SdUndoGroup(GetDoc()));
+ pUndoGroup->SetComment(SdResId(STR_UNDO_CHANGE_PAGEBORDER));
+
+ const SvxLongLRSpaceItem& rLRSpace =
+ pArgs->Get(SID_ATTR_LONG_LRSPACE);
+
+ if( mpDrawView->IsTextEdit() )
+ {
+ ::tools::Rectangle aRect = maMarkRect;
+ aRect.SetPos(aRect.TopLeft() + aPagePos);
+ aRect.SetLeft( rLRSpace.GetLeft() );
+ aRect.SetRight( aViewSize.Width() - rLRSpace.GetRight() );
+ aRect.SetPos(aRect.TopLeft() - aPagePos);
+ if ( aRect != maMarkRect)
+ {
+ mpDrawView->SetAllMarkedRect(aRect);
+ maMarkRect = mpDrawView->GetAllMarkedRect();
+ Invalidate( SID_RULER_OBJECT );
+ }
+ }
+ else
+ {
+ ::tools::Long nLeft = std::max(::tools::Long(0), rLRSpace.GetLeft() - aPagePos.X());
+ ::tools::Long nRight = std::max(::tools::Long(0), rLRSpace.GetRight() + aPagePos.X() +
+ aPageSize.Width() - aViewSize.Width());
+
+ sal_uInt16 nPageCnt = GetDoc()->GetSdPageCount(mePageKind);
+ sal_uInt16 i;
+ for ( i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = GetDoc()->GetSdPage(i, mePageKind);
+ SdUndoAction* pUndo = new SdPageLRUndoAction(GetDoc(),
+ pPage,
+ pPage->GetLeftBorder(),
+ pPage->GetRightBorder(),
+ nLeft, nRight);
+ pUndoGroup->AddAction(pUndo);
+ pPage->SetLeftBorder(nLeft);
+ pPage->SetRightBorder(nRight);
+ }
+ nPageCnt = GetDoc()->GetMasterSdPageCount(mePageKind);
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = GetDoc()->GetMasterSdPage(i, mePageKind);
+ SdUndoAction* pUndo = new SdPageLRUndoAction(GetDoc(),
+ pPage,
+ pPage->GetLeftBorder(),
+ pPage->GetRightBorder(),
+ nLeft, nRight);
+ pUndoGroup->AddAction(pUndo);
+ pPage->SetLeftBorder(nLeft);
+ pPage->SetRightBorder(nRight);
+ }
+ InvalidateWindows();
+ }
+
+ // give the undo group to the undo manager
+ GetViewFrame()->GetObjectShell()->GetUndoManager()->
+ AddUndoAction(std::move(pUndoGroup));
+ }
+ break;
+ case SID_ATTR_LONG_ULSPACE:
+ if (pArgs)
+ {
+ std::unique_ptr<SdUndoGroup> pUndoGroup(new SdUndoGroup(GetDoc()));
+ pUndoGroup->SetComment(SdResId(STR_UNDO_CHANGE_PAGEBORDER));
+
+ const SvxLongULSpaceItem& rULSpace =
+ pArgs->Get(SID_ATTR_LONG_ULSPACE);
+
+ if( mpDrawView->IsTextEdit() )
+ {
+ ::tools::Rectangle aRect = maMarkRect;
+ aRect.SetPos(aRect.TopLeft() + aPagePos);
+ aRect.SetTop( rULSpace.GetUpper() );
+ aRect.SetBottom( aViewSize.Height() - rULSpace.GetLower() );
+ aRect.SetPos(aRect.TopLeft() - aPagePos);
+
+ if ( aRect != maMarkRect)
+ {
+ mpDrawView->SetAllMarkedRect(aRect);
+ maMarkRect = mpDrawView->GetAllMarkedRect();
+ Invalidate( SID_RULER_OBJECT );
+ }
+ }
+ else
+ {
+ ::tools::Long nUpper = std::max(::tools::Long(0), rULSpace.GetUpper() - aPagePos.Y());
+ ::tools::Long nLower = std::max(::tools::Long(0), rULSpace.GetLower() + aPagePos.Y() +
+ aPageSize.Height() - aViewSize.Height());
+
+ sal_uInt16 nPageCnt = GetDoc()->GetSdPageCount(mePageKind);
+ sal_uInt16 i;
+ for ( i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = GetDoc()->GetSdPage(i, mePageKind);
+ SdUndoAction* pUndo = new SdPageULUndoAction(GetDoc(),
+ pPage,
+ pPage->GetUpperBorder(),
+ pPage->GetLowerBorder(),
+ nUpper, nLower);
+ pUndoGroup->AddAction(pUndo);
+ pPage->SetUpperBorder(nUpper);
+ pPage->SetLowerBorder(nLower);
+ }
+ nPageCnt = GetDoc()->GetMasterSdPageCount(mePageKind);
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ SdPage* pPage = GetDoc()->GetMasterSdPage(i, mePageKind);
+ SdUndoAction* pUndo = new SdPageULUndoAction(GetDoc(),
+ pPage,
+ pPage->GetUpperBorder(),
+ pPage->GetLowerBorder(),
+ nUpper, nLower);
+ pUndoGroup->AddAction(pUndo);
+ pPage->SetUpperBorder(nUpper);
+ pPage->SetLowerBorder(nLower);
+ }
+ InvalidateWindows();
+ }
+
+ // give the undo group to the undo manager
+ GetViewFrame()->GetObjectShell()->GetUndoManager()->
+ AddUndoAction(std::move(pUndoGroup));
+ }
+ break;
+ case SID_RULER_OBJECT:
+ if (pArgs)
+ {
+ ::tools::Rectangle aRect = maMarkRect;
+ aRect.SetPos(aRect.TopLeft() + aPagePos);
+
+ const SvxObjectItem& rOI = pArgs->Get(SID_RULER_OBJECT);
+
+ if ( rOI.GetStartX() != rOI.GetEndX() )
+ {
+ aRect.SetLeft( rOI.GetStartX() );
+ aRect.SetRight( rOI.GetEndX() );
+ }
+ if ( rOI.GetStartY() != rOI.GetEndY() )
+ {
+ aRect.SetTop( rOI.GetStartY() );
+ aRect.SetBottom( rOI.GetEndY() );
+ }
+ aRect.SetPos(aRect.TopLeft() - aPagePos);
+ if ( aRect != maMarkRect)
+ {
+ mpDrawView->SetAllMarkedRect(aRect);
+ maMarkRect = mpDrawView->GetAllMarkedRect();
+ Invalidate( SID_RULER_OBJECT );
+ }
+ }
+ break;
+ case SID_ATTR_TABSTOP:
+ if (pArgs && mpDrawView->IsTextEdit())
+ {
+ const SvxTabStopItem& rItem = pArgs->Get( EE_PARA_TABS );
+
+ SfxItemSetFixed<EE_PARA_TABS, EE_PARA_TABS> aEditAttr( GetPool() );
+
+ aEditAttr.Put( rItem );
+ mpDrawView->SetAttributes( aEditAttr );
+
+ Invalidate(SID_ATTR_TABSTOP);
+ }
+ break;
+ case SID_ATTR_PARA_LINESPACE:
+ if (pArgs)
+ {
+ SvxLineSpacingItem aParaLineSP = pArgs->Get(
+ GetPool().GetWhich(SID_ATTR_PARA_LINESPACE));
+
+ SfxItemSetFixed<EE_PARA_SBL, EE_PARA_SBL> aEditAttr( GetPool() );
+ aParaLineSP.SetWhich( EE_PARA_SBL );
+
+ aEditAttr.Put( aParaLineSP );
+ mpDrawView->SetAttributes( aEditAttr );
+
+ Invalidate(SID_ATTR_PARA_LINESPACE);
+ }
+ break;
+ case SID_ATTR_PARA_ADJUST_LEFT:
+ {
+ SvxAdjustItem aItem( SvxAdjust::Left, EE_PARA_JUST );
+ SfxItemSetFixed<EE_PARA_JUST, EE_PARA_JUST> aEditAttr( GetPool() );
+
+ aEditAttr.Put( aItem );
+ mpDrawView->SetAttributes( aEditAttr );
+
+ Invalidate(SID_ATTR_PARA_ADJUST_LEFT);
+ break;
+ }
+ case SID_ATTR_PARA_ADJUST_CENTER:
+ {
+ SvxAdjustItem aItem( SvxAdjust::Center, EE_PARA_JUST );
+ SfxItemSetFixed<EE_PARA_JUST, EE_PARA_JUST> aEditAttr( GetPool() );
+
+ aEditAttr.Put( aItem );
+ mpDrawView->SetAttributes( aEditAttr );
+
+ Invalidate(SID_ATTR_PARA_ADJUST_CENTER);
+ break;
+ }
+ case SID_ATTR_PARA_ADJUST_RIGHT:
+ {
+ SvxAdjustItem aItem( SvxAdjust::Right, EE_PARA_JUST );
+ SfxItemSetFixed<EE_PARA_JUST, EE_PARA_JUST> aEditAttr( GetPool() );
+
+ aEditAttr.Put( aItem );
+ mpDrawView->SetAttributes( aEditAttr );
+
+ Invalidate(SID_ATTR_PARA_ADJUST_RIGHT);
+ break;
+ }
+ case SID_ATTR_PARA_ADJUST_BLOCK:
+ {
+ SvxAdjustItem aItem( SvxAdjust::Block, EE_PARA_JUST );
+ SfxItemSetFixed<EE_PARA_JUST, EE_PARA_JUST> aEditAttr( GetPool() );
+
+ aEditAttr.Put( aItem );
+ mpDrawView->SetAttributes( aEditAttr );
+
+ Invalidate(SID_ATTR_PARA_ADJUST_BLOCK);
+ break;
+ }
+ case SID_ATTR_PARA_ULSPACE:
+ if (pArgs)
+ {
+ SvxULSpaceItem aULSP = static_cast<const SvxULSpaceItem&>(pArgs->Get(
+ SID_ATTR_PARA_ULSPACE));
+ SfxItemSetFixed<EE_PARA_ULSPACE, EE_PARA_ULSPACE> aEditAttr( GetPool() );
+ aULSP.SetWhich( EE_PARA_ULSPACE );
+
+ aEditAttr.Put( aULSP );
+ mpDrawView->SetAttributes( aEditAttr );
+
+ Invalidate(SID_ATTR_PARA_ULSPACE);
+ }
+ break;
+ case SID_ATTR_PARA_LRSPACE:
+ if (pArgs)
+ {
+ SvxLRSpaceItem aLRSpace = static_cast<const SvxLRSpaceItem&>(pArgs->Get(
+ SID_ATTR_PARA_LRSPACE));
+
+ SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aEditAttr( GetPool() );
+ aLRSpace.SetWhich( EE_PARA_LRSPACE );
+
+ aEditAttr.Put( aLRSpace );
+ mpDrawView->SetAttributes( aEditAttr );
+
+ Invalidate(SID_ATTR_PARA_LRSPACE);
+ }
+ break;
+ case SID_ATTR_LRSPACE:
+ if (pArgs && mpDrawView->IsTextEdit())
+ {
+ sal_uInt16 nId = SID_ATTR_PARA_LRSPACE;
+ const SvxLRSpaceItem& rItem = static_cast<const SvxLRSpaceItem&>(
+ pArgs->Get( nId ));
+
+ SfxItemSetFixed<
+ EE_PARA_NUMBULLET, EE_PARA_NUMBULLET,
+ EE_PARA_OUTLLEVEL, EE_PARA_OUTLLEVEL,
+ EE_PARA_LRSPACE, EE_PARA_LRSPACE> aEditAttr( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aEditAttr );
+
+ nId = EE_PARA_LRSPACE;
+ SvxLRSpaceItem aLRSpaceItem( rItem.GetLeft(),
+ rItem.GetRight(), rItem.GetTextLeft(),
+ rItem.GetTextFirstLineOffset(), nId );
+
+ const sal_Int16 nOutlineLevel = aEditAttr.Get( EE_PARA_OUTLLEVEL ).GetValue();
+ const SvxLRSpaceItem& rOrigLRSpaceItem = aEditAttr.Get( EE_PARA_LRSPACE );
+ const SvxNumBulletItem& rNumBulletItem = aEditAttr.Get( EE_PARA_NUMBULLET );
+ if( nOutlineLevel != -1 &&
+ rNumBulletItem.GetNumRule().GetLevelCount() > nOutlineLevel )
+ {
+ const SvxNumberFormat& rFormat = rNumBulletItem.GetNumRule().GetLevel(nOutlineLevel);
+ SvxNumberFormat aFormat(rFormat);
+
+ // left margin gets distributed onto LRSpace item
+ // and number format AbsLSpace - this fixes
+ // n#707779 (previously, LRSpace left indent could
+ // become negative - EditEngine really does not
+ // like that.
+ const auto nAbsLSpace=aFormat.GetAbsLSpace();
+ const ::tools::Long nTxtLeft=rItem.GetTextLeft();
+ const ::tools::Long nLeftIndent=std::max(::tools::Long(0),nTxtLeft - nAbsLSpace);
+ aLRSpaceItem.SetTextLeft(nLeftIndent);
+ // control for clipped left indent - remainder
+ // reduces number format first line indent
+ aFormat.SetAbsLSpace(nTxtLeft - nLeftIndent);
+
+ // negative first line indent goes to the number
+ // format, positive to the lrSpace item
+ if( rItem.GetTextFirstLineOffset() < 0 )
+ {
+ aFormat.SetFirstLineOffset(
+ rItem.GetTextFirstLineOffset()
+ - rOrigLRSpaceItem.GetTextFirstLineOffset()
+ + aFormat.GetCharTextDistance());
+ aLRSpaceItem.SetTextFirstLineOffset(0);
+ }
+ else
+ {
+ aFormat.SetFirstLineOffset(0);
+ aLRSpaceItem.SetTextFirstLineOffset(
+ rItem.GetTextFirstLineOffset()
+ - aFormat.GetFirstLineOffset() //TODO: overflow
+ + aFormat.GetCharTextDistance());
+ }
+
+ if( rFormat != aFormat )
+ {
+ // put all items
+ const_cast<SvxNumRule&>(rNumBulletItem.GetNumRule()).SetLevel(nOutlineLevel,aFormat);
+ aEditAttr.Put( rNumBulletItem );
+ aEditAttr.Put( aLRSpaceItem );
+ mpDrawView->SetAttributes( aEditAttr );
+
+ Invalidate(SID_ATTR_PARA_LRSPACE);
+ break;
+ }
+ }
+
+ // only put lrSpace item
+ SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aEditAttrReduced( GetDoc()->GetPool() );
+ aEditAttrReduced.Put( aLRSpaceItem );
+ mpDrawView->SetAttributes( aEditAttrReduced );
+
+ Invalidate(SID_ATTR_PARA_LRSPACE);
+ }
+ break;
+ }
+}
+
+void DrawViewShell::GetRulerState(SfxItemSet& rSet)
+{
+ Point aOrigin;
+
+ if (mpDrawView->GetSdrPageView())
+ {
+ aOrigin = mpDrawView->GetSdrPageView()->GetPageOrigin();
+ }
+
+ Size aViewSize = GetActiveWindow()->GetViewSize();
+
+ const Point aPagePos( GetActiveWindow()->GetViewOrigin() );
+ Size aPageSize = mpActualPage->GetSize();
+
+ ::tools::Rectangle aRect(aPagePos, Point( aViewSize.Width() - (aPagePos.X() + aPageSize.Width()),
+ aViewSize.Height() - (aPagePos.Y() + aPageSize.Height())));
+
+ if( mpDrawView->IsTextEdit() )
+ {
+ Point aPnt1 = GetActiveWindow()->GetWinViewPos();
+ ::tools::Rectangle aMinMaxRect( aPnt1, Size(-1, -1) );
+ rSet.Put( SfxRectangleItem(SID_RULER_LR_MIN_MAX, aMinMaxRect) );
+ }
+ else
+ {
+ rSet.Put( SfxRectangleItem(SID_RULER_LR_MIN_MAX, aRect) );
+ }
+
+ SvxLongLRSpaceItem aLRSpace(aPagePos.X() + mpActualPage->GetLeftBorder(),
+ aRect.Right() + mpActualPage->GetRightBorder(),
+ SID_ATTR_LONG_LRSPACE);
+ SvxLongULSpaceItem aULSpace(aPagePos.Y() + mpActualPage->GetUpperBorder(),
+ aRect.Bottom() + mpActualPage->GetLowerBorder(),
+ SID_ATTR_LONG_ULSPACE);
+ rSet.Put(SvxPagePosSizeItem(Point(0,0) - aPagePos, aViewSize.Width(),
+ aViewSize.Height()));
+ SfxPointItem aPointItem( SID_RULER_NULL_OFFSET, aPagePos + aOrigin );
+
+ SvxProtectItem aProtect( SID_RULER_PROTECT );
+
+ maMarkRect = mpDrawView->GetAllMarkedRect();
+
+ const bool bRTL = GetDoc() && GetDoc()->GetDefaultWritingMode() == css::text::WritingMode_RL_TB;
+ rSet.Put(SfxBoolItem(SID_RULER_TEXT_RIGHT_TO_LEFT, bRTL));
+
+ if( mpDrawView->AreObjectsMarked() )
+ {
+ if( mpDrawView->IsTextEdit() )
+ {
+ SdrObject* pObj = mpDrawView->GetMarkedObjectList().GetMark( 0 )->GetMarkedSdrObj();
+ if( pObj->GetObjInventor() == SdrInventor::Default)
+ {
+ SfxItemSet aEditAttr( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aEditAttr );
+ if( aEditAttr.GetItemState( EE_PARA_TABS ) >= SfxItemState::DEFAULT )
+ {
+ const SvxTabStopItem& rItem = aEditAttr.Get( EE_PARA_TABS );
+ rSet.Put( rItem );
+
+ const SvxLRSpaceItem& rLRSpaceItem = aEditAttr.Get( EE_PARA_LRSPACE );
+ SvxLRSpaceItem aLRSpaceItem( rLRSpaceItem.GetLeft(),
+ rLRSpaceItem.GetRight(), rLRSpaceItem.GetTextLeft(),
+ rLRSpaceItem.GetTextFirstLineOffset(), SID_ATTR_PARA_LRSPACE );
+
+ const sal_Int16 nOutlineLevel = aEditAttr.Get( EE_PARA_OUTLLEVEL ).GetValue();
+ const SvxNumBulletItem& rNumBulletItem = aEditAttr.Get( EE_PARA_NUMBULLET );
+ if( nOutlineLevel != -1 &&
+ rNumBulletItem.GetNumRule().GetLevelCount() > nOutlineLevel )
+ {
+ const SvxNumberFormat& rFormat = rNumBulletItem.GetNumRule().GetLevel(nOutlineLevel);
+ aLRSpaceItem.SetTextLeft(rFormat.GetAbsLSpace() + rLRSpaceItem.GetTextLeft());
+ aLRSpaceItem.SetTextFirstLineOffset(
+ rLRSpaceItem.GetTextFirstLineOffset() + rFormat.GetFirstLineOffset()
+ //TODO: overflow
+ - rFormat.GetCharTextDistance());
+ }
+
+ rSet.Put( aLRSpaceItem );
+
+ Point aPos( aPagePos + maMarkRect.TopLeft() );
+
+ if ( aEditAttr.GetItemState( SDRATTR_TEXT_LEFTDIST ) == SfxItemState::SET )
+ {
+ const SdrMetricItem& rTLDItem = aEditAttr.Get( SDRATTR_TEXT_LEFTDIST );
+ ::tools::Long nLD = rTLDItem.GetValue();
+ aPos.AdjustX(nLD );
+ }
+
+ aPointItem.SetValue( aPos );
+
+ ::tools::Rectangle aParaRect(maMarkRect);
+ if (pObj->GetObjIdentifier() == SdrObjKind::Table)
+ {
+ sdr::table::SdrTableObj* pTable = static_cast<sdr::table::SdrTableObj*>(pObj);
+ sdr::table::CellPos cellpos;
+ pTable->getActiveCellPos(cellpos);
+ pTable->getCellBounds(cellpos, aParaRect);
+ }
+
+ aLRSpace.SetLeft(aPagePos.X() + aParaRect.Left());
+
+ if ( aEditAttr.GetItemState( SDRATTR_TEXT_LEFTDIST ) == SfxItemState::SET )
+ {
+ const SdrMetricItem& rTLDItem = aEditAttr.Get( SDRATTR_TEXT_LEFTDIST );
+ ::tools::Long nLD = rTLDItem.GetValue();
+ aLRSpace.SetLeft( aLRSpace.GetLeft() + nLD );
+ }
+
+ aLRSpace.SetRight(aRect.Right() + aPageSize.Width() - aParaRect.Right());
+
+ if ( aEditAttr.GetItemState( SDRATTR_TEXT_RIGHTDIST ) == SfxItemState::SET )
+ {
+ const SdrMetricItem& rTRDItem = aEditAttr.Get( SDRATTR_TEXT_RIGHTDIST );
+ ::tools::Long nRD = rTRDItem.GetValue();
+ aLRSpace.SetRight( aLRSpace.GetRight() + nRD );
+ }
+
+ aULSpace.SetUpper( aPagePos.Y() + maMarkRect.Top() );
+ aULSpace.SetLower( aRect.Bottom() + aPageSize.Height() - maMarkRect.Bottom() );
+
+ rSet.DisableItem( SID_RULER_OBJECT );
+
+ // lock page margins
+ aProtect.SetSizeProtect( true );
+ aProtect.SetPosProtect( true );
+ }
+
+ if( aEditAttr.GetItemState( EE_PARA_WRITINGDIR ) >= SfxItemState::DEFAULT )
+ {
+ const SvxFrameDirectionItem& rItem = aEditAttr.Get( EE_PARA_WRITINGDIR );
+ rSet.Put(SfxBoolItem(SID_RULER_TEXT_RIGHT_TO_LEFT, rItem.GetValue() == SvxFrameDirection::Horizontal_RL_TB));
+ }
+ }
+ }
+ else
+ {
+ rSet.DisableItem( EE_PARA_TABS );
+ rSet.DisableItem( SID_RULER_TEXT_RIGHT_TO_LEFT );
+
+ if( mpDrawView->IsResizeAllowed(true) )
+ {
+ ::tools::Rectangle aResizeRect( maMarkRect );
+
+ aResizeRect.SetPos(aResizeRect.TopLeft() + aPagePos);
+ SvxObjectItem aObjItem(aResizeRect.Left(), aResizeRect.Right(),
+ aResizeRect.Top(), aResizeRect.Bottom());
+ rSet.Put(aObjItem);
+ rSet.DisableItem( EE_PARA_TABS );
+ }
+ else
+ {
+ rSet.DisableItem( SID_RULER_OBJECT );
+ }
+ }
+ }
+ else
+ {
+ rSet.DisableItem( SID_RULER_OBJECT );
+ rSet.DisableItem( EE_PARA_TABS );
+ }
+
+ rSet.Put( aLRSpace );
+ rSet.Put( aULSpace );
+
+ rSet.Put( aPointItem );
+ rSet.Put( aProtect );
+}
+
+void DrawViewShell::ExecStatusBar(SfxRequest& rReq)
+{
+ // nothing is executed during a slide show!
+ if(HasCurrentFunction(SID_PRESENTATION))
+ return;
+
+ CheckLineTo (rReq);
+
+ switch ( rReq.GetSlot() )
+ {
+ case SID_ATTR_SIZE:
+ {
+ GetViewFrame()->GetDispatcher()->Execute( SID_ATTR_TRANSFORM, SfxCallMode::ASYNCHRON );
+ }
+ break;
+
+ case SID_STATUS_LAYOUT:
+ {
+ GetViewFrame()->GetDispatcher()->Execute( SID_PRESENTATION_LAYOUT, SfxCallMode::ASYNCHRON );
+ }
+ break;
+ }
+}
+
+/**
+ * set state of snap object entries in popup
+ */
+void DrawViewShell::GetSnapItemState( SfxItemSet &rSet )
+{
+ SdrPageView* pPV;
+ Point aMPos = GetActiveWindow()->PixelToLogic(maMousePos);
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(GetActiveWindow()->PixelToLogic(
+ Size(FuPoor::HITPIX,0)).Width());
+ sal_uInt16 nHelpLine;
+
+ if ( !mpDrawView->PickHelpLine(aMPos, nHitLog, *GetActiveWindow()->GetOutDev(), nHelpLine, pPV) )
+ return;
+
+ const SdrHelpLine& rHelpLine = (pPV->GetHelpLines())[nHelpLine];
+
+ if ( rHelpLine.GetKind() == SdrHelpLineKind::Point )
+ {
+ rSet.Put( SfxStringItem( SID_SET_SNAPITEM,
+ SdResId( STR_POPUP_EDIT_SNAPPOINT)) );
+ rSet.Put( SfxStringItem( SID_DELETE_SNAPITEM,
+ SdResId( STR_POPUP_DELETE_SNAPPOINT)) );
+ }
+ else
+ {
+ rSet.Put( SfxStringItem( SID_SET_SNAPITEM,
+ SdResId( STR_POPUP_EDIT_SNAPLINE)) );
+ rSet.Put( SfxStringItem( SID_DELETE_SNAPITEM,
+ SdResId( STR_POPUP_DELETE_SNAPLINE)) );
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviews4.cxx b/sd/source/ui/view/drviews4.cxx
new file mode 100644
index 000000000..df251880d
--- /dev/null
+++ b/sd/source/ui/view/drviews4.cxx
@@ -0,0 +1,982 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+
+#include <DrawViewShell.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/urlbmk.hxx>
+#include <svx/svdpagv.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/svxids.hrc>
+#include <svx/ruler.hxx>
+#include <svx/svdobjkind.hxx>
+#include <editeng/outliner.hxx>
+#include <sfx2/ipclient.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svdopath.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <editeng/editview.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/cursor.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/dialoghelper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
+
+#include <app.hrc>
+#include <strings.hrc>
+
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <Window.hxx>
+#include <fupoor.hxx>
+#include <sdmod.hxx>
+#include <Ruler.hxx>
+#include <sdresid.hxx>
+#include <sdpage.hxx>
+#include <slideshow.hxx>
+#include <sdpopup.hxx>
+#include <drawview.hxx>
+#include <svx/bmpmask.hxx>
+#include <LayerTabBar.hxx>
+#include <ViewShellBase.hxx>
+
+#include <SlideSorterViewShell.hxx>
+#include <svx/svditer.hxx>
+
+#include <navigatr.hxx>
+#include <memory>
+
+namespace {
+ void EndTextEditOnPage(sal_uInt16 nPageId)
+ {
+ SfxViewShell* pShell = SfxViewShell::GetFirst();
+ while (pShell)
+ {
+ ::sd::ViewShellBase* pBase = dynamic_cast<::sd::ViewShellBase*>(pShell);
+ if (pBase)
+ {
+ ::sd::ViewShell* pViewSh = pBase->GetMainViewShell().get();
+ ::sd::DrawViewShell* pDrawSh = dynamic_cast<::sd::DrawViewShell*>(pViewSh);
+ if (pDrawSh && pDrawSh->GetDrawView() && pDrawSh->getCurrentPage()->getPageId() == nPageId)
+ pDrawSh->GetDrawView()->SdrEndTextEdit();
+ }
+
+ pShell = SfxViewShell::GetNext(*pShell);
+ }
+ }
+}
+
+namespace sd {
+
+#define PIPETTE_RANGE 0
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+
+void DrawViewShell::DeleteActualPage()
+{
+ mpDrawView->SdrEndTextEdit();
+
+ try
+ {
+ Reference<XDrawPagesSupplier> xDrawPagesSupplier( GetDoc()->getUnoModel(), UNO_QUERY_THROW );
+ Reference<XDrawPages> xPages( xDrawPagesSupplier->getDrawPages(), UNO_SET_THROW );
+ sal_uInt16 nPageCount = GetDoc()->GetSdPageCount(mePageKind);
+ SdPage* pPage = nullptr;
+ std::vector<Reference<XDrawPage>> pagesToDelete;
+
+ GetView()->BegUndo(SdResId(STR_UNDO_DELETEPAGES));
+
+ for (sal_uInt16 i = 0; i < nPageCount; i++)
+ {
+ pPage = GetDoc()->GetSdPage(i, mePageKind);
+ sal_uInt16 nPageIndex = maTabControl->GetPagePos(pPage->getPageId());
+
+ slidesorter::SlideSorterViewShell* pVShell
+ = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase());
+ bool bUseSlideSorter = pVShell != nullptr;
+
+ if((bUseSlideSorter && IsSelected(nPageIndex)) || (!bUseSlideSorter && pPage->IsSelected()))
+ {
+ EndTextEditOnPage(pPage->getPageId());
+ Reference< XDrawPage > xPage( xPages->getByIndex( nPageIndex ), UNO_QUERY_THROW );
+ pagesToDelete.push_back(xPage);
+ }
+ }
+ for (const auto &xPage: pagesToDelete)
+ {
+ xPages->remove(xPage);
+ }
+
+ GetView()->EndUndo();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "SelectionManager::DeleteSelectedMasterPages()");
+ }
+}
+
+void DrawViewShell::DeleteActualLayer()
+{
+ if(!GetLayerTabControl()) // #i87182#
+ {
+ OSL_ENSURE(false, "No LayerTabBar (!)");
+ return;
+ }
+
+ SdrLayerAdmin& rAdmin = GetDoc()->GetLayerAdmin();
+ sal_uInt16 nId = GetLayerTabControl()->GetCurPageId();
+ const OUString& rName = GetLayerTabControl()->GetLayerName(nId);
+ if(LayerTabBar::IsRealNameOfStandardLayer(rName))
+ {
+ assert(false && "Standard layer may not be deleted.");
+ return;
+ }
+ const OUString& rDisplayName(GetLayerTabControl()->GetPageText(nId));
+ OUString aString(SdResId(STR_ASK_DELETE_LAYER));
+
+ // replace placeholder
+ aString = aString.replaceFirst("$", rDisplayName);
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ aString));
+ if (xQueryBox->run() == RET_YES)
+ {
+ const SdrLayer* pLayer = rAdmin.GetLayer(rName);
+ mpDrawView->DeleteLayer( pLayer->GetName() );
+
+ /* in order to redraw TabBar and Window; should be initiated later on by
+ a hint from Joe (as by a change if the layer order). */
+ // ( View::Notify() --> ViewShell::ResetActualLayer() )
+
+ mbIsLayerModeActive = false; // so that ChangeEditMode() does something
+ ChangeEditMode(GetEditMode(), true);
+ }
+}
+
+bool DrawViewShell::KeyInput (const KeyEvent& rKEvt, ::sd::Window* pWin)
+{
+ bool bRet = false;
+
+ if (!IsInputLocked() || (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE))
+ {
+ if(KEY_RETURN == rKEvt.GetKeyCode().GetCode()
+ && rKEvt.GetKeyCode().IsMod1()
+ && GetView()->IsTextEdit())
+ {
+ // this should be used for cursor travelling.
+ SdPage* pActualPage = GetActualPage();
+ const SdrMarkList& rMarkList = GetView()->GetMarkedObjectList();
+ SdrTextObj* pCandidate = nullptr;
+
+ if(pActualPage && 1 == rMarkList.GetMarkCount())
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+
+ // remember which object was the text in edit mode
+ SdrObject* pOldObj = pMark->GetMarkedSdrObj();
+
+ // end text edit now
+ GetView()->SdrEndTextEdit();
+
+ // look for a new candidate, a successor of pOldObj
+ SdrObjListIter aIter(pActualPage, SdrIterMode::DeepNoGroups);
+ bool bDidVisitOldObject(false);
+
+ while(aIter.IsMore() && !pCandidate)
+ {
+ SdrObject* pObj = aIter.Next();
+
+ if(auto pSdrTextObj = dynamic_cast<SdrTextObj *>( pObj ))
+ {
+ SdrInventor nInv(pObj->GetObjInventor());
+ SdrObjKind nKnd(pObj->GetObjIdentifier());
+
+ if(SdrInventor::Default == nInv &&
+ (SdrObjKind::TitleText == nKnd || SdrObjKind::OutlineText == nKnd || SdrObjKind::Text == nKnd)
+ && bDidVisitOldObject)
+ {
+ pCandidate = pSdrTextObj;
+ }
+
+ if(pObj == pOldObj)
+ {
+ bDidVisitOldObject = true;
+ }
+ }
+ }
+ }
+
+ if(pCandidate)
+ {
+ // set the new candidate to text edit mode
+ GetView()->UnMarkAll();
+ GetView()->MarkObj(pCandidate, GetView()->GetSdrPageView());
+
+ GetViewFrame()->GetDispatcher()->Execute(
+ SID_ATTR_CHAR, SfxCallMode::ASYNCHRON);
+ }
+ else
+ {
+ // insert a new page with the same page layout
+ GetViewFrame()->GetDispatcher()->Execute(
+ SID_INSERTPAGE_QUICK, SfxCallMode::ASYNCHRON);
+ }
+ }
+ else
+ {
+ bRet = ViewShell::KeyInput(rKEvt, pWin);
+ //If object is marked , the corresponding entry is set true , else
+ //the corresponding entry is set false .
+ if(KEY_TAB == rKEvt.GetKeyCode().GetCode())
+ {
+ FreshNavigatrTree();
+ }
+ }
+ if (!bRet && !mbReadOnly) // tdf#139804
+ {
+ bRet = GetView()->KeyInput(rKEvt, pWin);
+ }
+ }
+
+ return bRet;
+}
+
+/**
+ * Start with Drag from ruler (helper lines, origin)
+ */
+void DrawViewShell::StartRulerDrag (
+ const Ruler& rRuler,
+ const MouseEvent& rMEvt)
+{
+ GetActiveWindow()->CaptureMouse();
+
+ Point aWPos = GetActiveWindow()->PixelToLogic(GetActiveWindow()->GetPointerPosPixel());
+
+ if ( rRuler.GetExtraRect().Contains(rMEvt.GetPosPixel()) )
+ {
+ mpDrawView->BegSetPageOrg(aWPos);
+ mbIsRulerDrag = true;
+ }
+ else
+ {
+ // #i34536# if no guide-lines are visible yet, that show them
+ if( ! mpDrawView->IsHlplVisible())
+ mpDrawView->SetHlplVisible();
+
+ SdrHelpLineKind eKind;
+
+ if ( rMEvt.IsMod1() )
+ eKind = SdrHelpLineKind::Point;
+ else if ( rRuler.IsHorizontal() )
+ eKind = SdrHelpLineKind::Horizontal;
+ else
+ eKind = SdrHelpLineKind::Vertical;
+
+ mpDrawView->BegDragHelpLine(aWPos, eKind);
+ mbIsRulerDrag = true;
+ }
+}
+
+void DrawViewShell::FreshNavigatrTree()
+{
+ SfxChildWindow* pWindow = GetViewFrame()->GetChildWindow( SID_NAVIGATOR );
+ if( pWindow )
+ {
+ SdNavigatorFloat* pNavWin = static_cast<SdNavigatorFloat*>( pWindow->GetWindow() );
+ if( pNavWin )
+ pNavWin->FreshTree( GetDoc() );
+ }
+}
+
+void DrawViewShell::MouseButtonDown(const MouseEvent& rMEvt,
+ ::sd::Window* pWin)
+{
+ mbMouseButtonDown = true;
+ mbMouseSelecting = false;
+
+ // We have to check if a context menu is shown and we have an UI
+ // active inplace client. In that case we have to ignore the mouse
+ // button down event. Otherwise we would crash (context menu has been
+ // opened by inplace client and we would deactivate the inplace client,
+ // the context menu is closed by VCL asynchronously which in the end
+ // would work on deleted objects or the context menu has no parent anymore)
+ SfxInPlaceClient* pIPClient = GetViewShell()->GetIPClient();
+ bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() );
+
+ if (bIsOleActive && vcl::IsInPopupMenuExecute())
+ return;
+
+ if ( IsInputLocked() )
+ return;
+
+ ViewShell::MouseButtonDown(rMEvt, pWin);
+
+ //If object is marked , the corresponding entry is set true ,
+ //else the corresponding entry is set false .
+ FreshNavigatrTree();
+ if (mbPipette)
+ {
+ SfxChildWindow* pWnd = GetViewFrame()->GetChildWindow(SvxBmpMaskChildWindow::GetChildWindowId());
+ SvxBmpMask* pBmpMask = pWnd ? static_cast<SvxBmpMask*>(pWnd->GetWindow()) : nullptr;
+ if (pBmpMask)
+ pBmpMask->PipetteClicked();
+ }
+}
+
+void DrawViewShell::MouseMove(const MouseEvent& rMEvt, ::sd::Window* pWin)
+{
+ if ( IsMouseButtonDown() )
+ mbMouseSelecting = true;
+
+ if ( IsInputLocked() )
+ return;
+
+ if ( mpDrawView->IsAction() )
+ {
+ ::tools::Rectangle aOutputArea(Point(0,0), GetActiveWindow()->GetOutputSizePixel());
+
+ if ( !aOutputArea.Contains(rMEvt.GetPosPixel()) )
+ {
+ bool bInsideOtherWindow = false;
+
+ if (mpContentWindow)
+ {
+ aOutputArea = ::tools::Rectangle(Point(0,0),
+ mpContentWindow->GetOutputSizePixel());
+
+ Point aPos = mpContentWindow->GetPointerPosPixel();
+ if ( aOutputArea.Contains(aPos) )
+ bInsideOtherWindow = true;
+ }
+
+ if (! GetActiveWindow()->HasFocus ())
+ {
+ GetActiveWindow()->ReleaseMouse ();
+ mpDrawView->BrkAction ();
+ return;
+ }
+ else if ( bInsideOtherWindow )
+ {
+ GetActiveWindow()->ReleaseMouse();
+ pWin->CaptureMouse ();
+ }
+ }
+ else if ( pWin != GetActiveWindow() )
+ pWin->CaptureMouse();
+ }
+
+ // Since the next MouseMove may execute a IsSolidDraggingNow() in
+ // SdrCreateView::MovCreateObj and there the ApplicationBackgroundColor
+ // is needed it is necessary to set it here.
+ if (GetDoc())
+ {
+ ConfigureAppBackgroundColor();
+ mpDrawView->SetApplicationBackgroundColor( mnAppBackgroundColor );
+ }
+
+ ViewShell::MouseMove(rMEvt, pWin);
+
+ maMousePos = rMEvt.GetPosPixel();
+
+ ::tools::Rectangle aRect;
+
+ if ( mbIsRulerDrag )
+ {
+ Point aLogPos = GetActiveWindow()->PixelToLogic(maMousePos);
+ mpDrawView->MovAction(aLogPos);
+ }
+
+ if ( mpDrawView->IsAction() )
+ {
+ mpDrawView->TakeActionRect(aRect);
+ aRect = GetActiveWindow()->LogicToPixel(aRect);
+ }
+ else
+ {
+ aRect = ::tools::Rectangle(maMousePos, maMousePos);
+ }
+
+ ShowMousePosInfo(aRect, pWin);
+
+ SvxBmpMask* pBmpMask = nullptr;
+ if (mbPipette && GetViewFrame()->HasChildWindow(SvxBmpMaskChildWindow::GetChildWindowId()))
+ {
+ SfxChildWindow* pWnd = GetViewFrame()->GetChildWindow(SvxBmpMaskChildWindow::GetChildWindowId());
+ pBmpMask = pWnd ? static_cast<SvxBmpMask*>(pWnd->GetWindow()) : nullptr;
+ }
+
+ if (!pBmpMask)
+ return;
+
+ const ::tools::Long nStartX = maMousePos.X() - PIPETTE_RANGE;
+ const ::tools::Long nEndX = maMousePos.X() + PIPETTE_RANGE;
+ const ::tools::Long nStartY = maMousePos.Y() - PIPETTE_RANGE;
+ const ::tools::Long nEndY = maMousePos.Y() + PIPETTE_RANGE;
+ ::tools::Long nRed = 0;
+ ::tools::Long nGreen = 0;
+ ::tools::Long nBlue = 0;
+ const double fDiv = ( ( PIPETTE_RANGE << 1 ) + 1 ) * ( ( PIPETTE_RANGE << 1 ) + 1 );
+
+ for ( ::tools::Long nY = nStartY; nY <= nEndY; nY++ )
+ {
+ for( ::tools::Long nX = nStartX; nX <= nEndX; nX++ )
+ {
+ const Color aCol( pWin->GetOutDev()->GetPixel( pWin->PixelToLogic( Point( nX, nY ) ) ) );
+
+ nRed += aCol.GetRed();
+ nGreen += aCol.GetGreen();
+ nBlue += aCol.GetBlue();
+ }
+ }
+
+ pBmpMask->SetColor( Color( static_cast<sal_uInt8>( nRed / fDiv + .5 ),
+ static_cast<sal_uInt8>( nGreen / fDiv + .5 ),
+ static_cast<sal_uInt8>( nBlue / fDiv + .5 ) ) );
+}
+
+void DrawViewShell::MouseButtonUp(const MouseEvent& rMEvt, ::sd::Window* pWin)
+{
+ mbMouseButtonDown = false;
+
+ if ( !IsInputLocked() )
+ {
+ bool bIsSetPageOrg = mpDrawView->IsSetPageOrg();
+
+ if (mbIsRulerDrag)
+ {
+ ::tools::Rectangle aOutputArea(Point(0,0), GetActiveWindow()->GetOutputSizePixel());
+
+ if (aOutputArea.Contains(rMEvt.GetPosPixel()))
+ {
+ mpDrawView->EndAction();
+
+ if (bIsSetPageOrg)
+ GetViewFrame()->GetBindings().Invalidate(SID_RULER_NULL_OFFSET);
+ }
+ else if (rMEvt.IsLeft() && bIsSetPageOrg)
+ {
+ mpDrawView->BrkAction();
+ SdPage* pPage = static_cast<SdPage*>( mpDrawView->GetSdrPageView()->GetPage() );
+ Point aOrg(pPage->GetLeftBorder(), pPage->GetUpperBorder());
+ mpDrawView->GetSdrPageView()->SetPageOrigin(aOrg);
+ GetViewFrame()->GetBindings().Invalidate(SID_RULER_NULL_OFFSET);
+ }
+ else
+ {
+ mpDrawView->BrkAction();
+ }
+
+ GetActiveWindow()->ReleaseMouse();
+ mbIsRulerDrag = false;
+ }
+ else
+ ViewShell::MouseButtonUp(rMEvt, pWin);
+ //If object is marked , the corresponding entry is set true ,
+ //else the corresponding entry is set false .
+ FreshNavigatrTree();
+ }
+ mbMouseSelecting = false;
+}
+
+void DrawViewShell::Command(const CommandEvent& rCEvt, ::sd::Window* pWin)
+{
+ // The command event is send to the window after a possible context
+ // menu from an inplace client is closed. Now we have the chance to
+ // deactivate the inplace client without any problem regarding parent
+ // windows and code on the stack.
+ SfxInPlaceClient* pIPClient = GetViewShell()->GetIPClient();
+ bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() );
+ if ( bIsOleActive && ( rCEvt.GetCommand() == CommandEventId::ContextMenu ))
+ {
+ // Deactivate OLE object
+ mpDrawView->UnmarkAll();
+ SelectionHasChanged();
+ return;
+ }
+
+ if ( IsInputLocked() )
+ return;
+
+ if( GetView() &&GetView()->getSmartTags().Command(rCEvt) )
+ return;
+
+ const bool bNativeShow (SlideShow::IsRunning(GetViewShellBase()));
+
+ if( rCEvt.GetCommand() == CommandEventId::PasteSelection && !bNativeShow )
+ {
+ TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromPrimarySelection());
+
+ if( aDataHelper.GetTransferable().is() )
+ {
+ Point aPos;
+ sal_Int8 nDnDAction = DND_ACTION_COPY;
+
+ if( GetActiveWindow() )
+ aPos = GetActiveWindow()->PixelToLogic( rCEvt.GetMousePosPixel() );
+
+ if( !mpDrawView->InsertData( aDataHelper, aPos, nDnDAction, false ) )
+ {
+ INetBookmark aINetBookmark( "", "" );
+
+ if( ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) ) ||
+ ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::FILEGRPDESCRIPTOR, aINetBookmark ) ) ||
+ ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::UNIFORMRESOURCELOCATOR, aINetBookmark ) ) )
+ {
+ InsertURLField( aINetBookmark.GetURL(), aINetBookmark.GetDescription(), "" );
+ }
+ }
+ }
+ }
+ else if( rCEvt.GetCommand() == CommandEventId::ContextMenu && !bNativeShow &&
+ pWin != nullptr && !mpDrawView->IsAction() && !SD_MOD()->GetWaterCan() )
+ {
+ OUString aPopupId; // Resource name for popup menu
+
+ // is there a snap object under the cursor?
+ SdrPageView* pPV;
+ Point aMPos = pWin->PixelToLogic( maMousePos );
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(GetActiveWindow()->PixelToLogic(
+ Size(FuPoor::HITPIX, 0 ) ).Width());
+ sal_uInt16 nHelpLine;
+ // for gluepoints
+ SdrObject* pObj = nullptr;
+ sal_uInt16 nPickId = 0;
+ // for field command
+ OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView();
+ const SvxFieldItem* pFldItem = nullptr;
+ if( pOLV )
+ pFldItem = pOLV->GetFieldAtSelection();
+
+ // helper line
+ if ( mpDrawView->PickHelpLine( aMPos, nHitLog, *GetActiveWindow()->GetOutDev(), nHelpLine, pPV) )
+ {
+ ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(10, 10));
+ weld::Window* pParent = weld::GetPopupParent(*pWin, aRect);
+ ShowSnapLineContextMenu(pParent, aRect, *pPV, nHelpLine);
+ return;
+ }
+ // is gluepoint under cursor marked?
+ else if( mpDrawView->PickGluePoint( aMPos, pObj, nPickId, pPV ) &&
+ mpDrawView->IsGluePointMarked( pObj, nPickId ) )
+ {
+ aPopupId = "gluepoint";
+ }
+ // field command?
+ else if( pFldItem && (nullptr != dynamic_cast< const SvxDateField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtTimeField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtFileField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxAuthorField *>( pFldItem->GetField() ) ) )
+ {
+ LanguageType eLanguage( LANGUAGE_SYSTEM );
+
+ // Format popup with outliner language, if possible
+ if( pOLV->GetOutliner() )
+ {
+ ESelection aSelection( pOLV->GetSelection() );
+ eLanguage = pOLV->GetOutliner()->GetLanguage( aSelection.nStartPara, aSelection.nStartPos );
+ }
+
+ //fdo#44998 if the outliner has captured the mouse events release the lock
+ //so the SdFieldPopup can get them
+ pOLV->ReleaseMouse();
+ SdFieldPopup aFieldPopup(pFldItem->GetField(), eLanguage);
+
+ if ( rCEvt.IsMouseEvent() )
+ aMPos = rCEvt.GetMousePosPixel();
+ else
+ aMPos = Point( 20, 20 );
+ ::tools::Rectangle aRect(aMPos, Size(1, 1));
+ weld::Window* pParent = weld::GetPopupParent(*pWin, aRect);
+
+ aFieldPopup.Execute(pParent, aRect);
+
+ std::unique_ptr<SvxFieldData> pField(aFieldPopup.GetField());
+ if (pField)
+ {
+ SvxFieldItem aFieldItem( *pField, EE_FEATURE_FIELD );
+ // select field, so that it will be deleted on insert
+ ESelection aSel = pOLV->GetSelection();
+ bool bSel = true;
+ if( aSel.nStartPos == aSel.nEndPos )
+ {
+ bSel = false;
+ aSel.nEndPos++;
+ }
+ pOLV->SetSelection( aSel );
+
+ pOLV->InsertField( aFieldItem );
+
+ // reset selection back to original state
+ if( !bSel )
+ aSel.nEndPos--;
+ pOLV->SetSelection( aSel );
+ }
+ }
+ else
+ {
+ // is something selected?
+ if (mpDrawView->AreObjectsMarked() &&
+ mpDrawView->GetMarkedObjectList().GetMarkCount() == 1 )
+ {
+ pObj = mpDrawView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
+ if( HasCurrentFunction(SID_BEZIER_EDIT) && (dynamic_cast< SdrPathObj * >( pObj ) != nullptr ) )
+ {
+ aPopupId = "bezier";
+ }
+ else
+ {
+ if( mpDrawView->GetTextEditObject() )
+ {
+ OutlinerView* pOutlinerView = mpDrawView->GetTextEditOutlinerView();
+ Point aPos(rCEvt.GetMousePosPixel());
+
+ if ( pOutlinerView )
+ {
+ if( ( rCEvt.IsMouseEvent() && pOutlinerView->IsWrongSpelledWordAtPos(aPos) ) ||
+ ( !rCEvt.IsMouseEvent() && pOutlinerView->IsCursorAtWrongSpelledWord() ) )
+ {
+ // Popup for Online-Spelling now handled by DrawDocShell
+ Link<SpellCallbackInfo&,void> aLink = LINK(GetDocSh(), DrawDocShell, OnlineSpellCallback);
+
+ if( !rCEvt.IsMouseEvent() )
+ {
+ aPos = GetActiveWindow()->LogicToPixel( pOutlinerView->GetEditView().GetCursor()->GetPos() );
+ }
+ // While showing the spell context menu
+ // we lock the input so that another
+ // context menu can not be opened during
+ // that time (crash #i43235#). In order
+ // to not lock the UI completely we
+ // first release the mouse.
+ GetActiveWindow()->ReleaseMouse();
+ LockInput();
+ pOutlinerView->ExecuteSpellPopup(aPos, aLink);
+ pOutlinerView->GetEditView().Invalidate();
+ UnlockInput();
+ }
+ else
+ {
+ if( (pObj->GetObjInventor() == SdrInventor::Default) && (pObj->GetObjIdentifier() == SdrObjKind::Table) )
+ {
+ aPopupId = "table";
+ }
+ else
+ {
+ aPopupId = "drawtext";
+ }
+ }
+ }
+ }
+ else
+ {
+ SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nId = pObj->GetObjIdentifier();
+
+ if (nInv == SdrInventor::Default)
+ {
+ switch ( nId )
+ {
+ case SdrObjKind::OutlineText:
+ case SdrObjKind::Caption:
+ case SdrObjKind::TitleText:
+ case SdrObjKind::Text:
+ aPopupId = "textbox";
+ break;
+
+ case SdrObjKind::PathLine:
+ case SdrObjKind::PolyLine:
+ aPopupId = "curve";
+ break;
+
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::Edge:
+ aPopupId = "connector";
+ break;
+
+ case SdrObjKind::Line:
+ aPopupId = "line";
+ break;
+
+ case SdrObjKind::Measure:
+ aPopupId = "measure";
+ break;
+
+ case SdrObjKind::Rectangle:
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathFill:
+ case SdrObjKind::Polygon:
+ case SdrObjKind::CircleSection:
+ case SdrObjKind::CircleArc:
+ case SdrObjKind::CircleCut:
+ case SdrObjKind::CustomShape:
+ aPopupId = "draw";
+ break;
+
+ case SdrObjKind::Group:
+ aPopupId = "group";
+ break;
+
+ case SdrObjKind::Graphic:
+ aPopupId = "graphic";
+ break;
+
+ case SdrObjKind::OLE2:
+ aPopupId = "oleobject";
+ break;
+ case SdrObjKind::Media:
+ aPopupId = "media";
+ break;
+ case SdrObjKind::Table:
+ aPopupId = "table";
+ break;
+ default: ;
+ }
+ }
+ else if( nInv == SdrInventor::E3d )
+ {
+ if( nId == SdrObjKind::E3D_Scene )
+ {
+ if( !mpDrawView->IsGroupEntered() )
+ aPopupId = "3dscene";
+ else
+ aPopupId = "3dscene2";
+ }
+ else
+ aPopupId = "3dobject";
+ }
+ else if( nInv == SdrInventor::FmForm )
+ {
+ aPopupId = "form";
+ }
+ }
+ }
+ }
+
+ // multiple selection
+ else if (mpDrawView->AreObjectsMarked() &&
+ mpDrawView->GetMarkedObjectList().GetMarkCount() > 1 )
+ {
+ aPopupId = "multiselect";
+ }
+
+ // nothing selected
+ else
+ {
+ aPopupId = "page";
+ }
+ }
+ // show Popup-Menu
+ if (!aPopupId.isEmpty())
+ {
+ GetActiveWindow()->ReleaseMouse();
+
+ // tdf#137445 at this context menu popup time get what the
+ // DisableEditHyperlink would be for this position
+ bool bShouldDisableEditHyperlink = ShouldDisableEditHyperlink();
+
+ if(rCEvt.IsMouseEvent())
+ GetViewFrame()->GetDispatcher()->ExecutePopup( aPopupId );
+ else
+ {
+ //don't open contextmenu at mouse position if not opened via mouse
+
+ //middle of the window if nothing is marked
+ Point aMenuPos(GetActiveWindow()->GetSizePixel().Width()/2
+ ,GetActiveWindow()->GetSizePixel().Height()/2);
+
+ //middle of the bounding rect if something is marked
+ if( mpDrawView->AreObjectsMarked() && mpDrawView->GetMarkedObjectList().GetMarkCount() >= 1 )
+ {
+ ::tools::Rectangle aMarkRect;
+ mpDrawView->GetMarkedObjectList().TakeBoundRect(nullptr,aMarkRect);
+ aMenuPos = GetActiveWindow()->LogicToPixel( aMarkRect.Center() );
+
+ //move the point into the visible window area
+ if( aMenuPos.X() < 0 )
+ aMenuPos.setX( 0 );
+ if( aMenuPos.Y() < 0 )
+ aMenuPos.setY( 0 );
+ if( aMenuPos.X() > GetActiveWindow()->GetSizePixel().Width() )
+ aMenuPos.setX( GetActiveWindow()->GetSizePixel().Width() );
+ if( aMenuPos.Y() > GetActiveWindow()->GetSizePixel().Height() )
+ aMenuPos.setY( GetActiveWindow()->GetSizePixel().Height() );
+ }
+
+ //open context menu at that point
+ GetViewFrame()->GetDispatcher()->ExecutePopup( aPopupId, GetActiveWindow(), &aMenuPos );
+ }
+
+ if (!bShouldDisableEditHyperlink)
+ {
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ // tdf#137445 set what the menu popup state for this was
+ EnableEditHyperlink();
+ // ensure moAtContextMenu_DisableEditHyperlink will be cleared
+ // in the case that EditHyperlink is not dispatched by the menu
+ rBindings.Invalidate(SID_EDIT_HYPERLINK);
+ }
+ }
+ }
+ else
+ {
+ ViewShell::Command(rCEvt, pWin);
+ }
+}
+
+void DrawViewShell::EnableEditHyperlink()
+{
+ moAtContextMenu_DisableEditHyperlink = false;
+}
+
+void DrawViewShell::ShowMousePosInfo(const ::tools::Rectangle& rRect,
+ ::sd::Window const * pWin)
+{
+ if (mbHasRulers && pWin )
+ {
+ RulerLine pHLines[2];
+ RulerLine pVLines[2];
+ ::tools::Long nHOffs = 0;
+ ::tools::Long nVOffs = 0;
+ sal_uInt16 nCnt;
+
+ if (mpHorizontalRuler)
+ mpHorizontalRuler->SetLines();
+
+ if (mpVerticalRuler)
+ mpVerticalRuler->SetLines();
+
+ if (mpHorizontalRuler)
+ {
+ nHOffs = mpHorizontalRuler->GetNullOffset() +
+ mpHorizontalRuler->GetPageOffset();
+ }
+
+ if (mpVerticalRuler)
+ {
+ nVOffs = mpVerticalRuler->GetNullOffset() +
+ mpVerticalRuler->GetPageOffset();
+ }
+
+ nCnt = 1;
+ pHLines[0].nPos = rRect.Left() - nHOffs;
+ pVLines[0].nPos = rRect.Top() - nVOffs;
+
+ if ( rRect.Right() != rRect.Left() || rRect.Bottom() != rRect.Top() )
+ {
+ pHLines[1].nPos = rRect.Right() - nHOffs;
+ pVLines[1].nPos = rRect.Bottom() - nVOffs;
+ nCnt++;
+ }
+
+ if (mpHorizontalRuler)
+ mpHorizontalRuler->SetLines(nCnt, pHLines);
+ if (mpVerticalRuler)
+ mpVerticalRuler->SetLines(nCnt, pVLines);
+ }
+
+ // display with coordinates in StatusBar
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ if ( GetViewShell()->GetUIActiveClient() )
+ return;
+
+ SfxItemSetFixed<
+ SID_CONTEXT, SID_CONTEXT,
+ SID_ATTR_POSITION, SID_ATTR_SIZE> aSet(GetPool());
+
+ GetStatusBarState(aSet);
+
+ aSet.Put( SfxStringItem( SID_CONTEXT, mpDrawView->GetStatusText() ) );
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.SetState(aSet);
+ rBindings.Invalidate(SID_CONTEXT);
+ rBindings.Invalidate(SID_ATTR_POSITION);
+ rBindings.Invalidate(SID_ATTR_SIZE);
+}
+
+void DrawViewShell::LockInput()
+{
+ mnLockCount++;
+}
+
+void DrawViewShell::UnlockInput()
+{
+ DBG_ASSERT( mnLockCount, "Input for this shell is not locked!" );
+ if ( mnLockCount )
+ mnLockCount--;
+}
+
+void DrawViewShell::ShowSnapLineContextMenu(weld::Window* pParent, const ::tools::Rectangle& rRect,
+ SdrPageView& rPageView, const sal_uInt16 nSnapLineIndex)
+{
+ const SdrHelpLine& rHelpLine (rPageView.GetHelpLines()[nSnapLineIndex]);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/simpress/ui/snapmenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+
+ if (rHelpLine.GetKind() == SdrHelpLineKind::Point)
+ {
+ xMenu->append(OUString::number(SID_SET_SNAPITEM), SdResId(STR_POPUP_EDIT_SNAPPOINT));
+ xMenu->append_separator("separator");
+ xMenu->append(OUString::number(SID_DELETE_SNAPITEM), SdResId(STR_POPUP_DELETE_SNAPPOINT));
+ }
+ else
+ {
+ xMenu->append(OUString::number(SID_SET_SNAPITEM), SdResId(STR_POPUP_EDIT_SNAPLINE));
+ xMenu->append_separator("separator");
+ xMenu->append(OUString::number(SID_DELETE_SNAPITEM), SdResId(STR_POPUP_DELETE_SNAPLINE));
+ }
+
+ const int nResult = xMenu->popup_at_rect(pParent, rRect).toInt32();
+ switch (nResult)
+ {
+ case SID_SET_SNAPITEM:
+ {
+ SfxUInt32Item aHelpLineItem (ID_VAL_INDEX, nSnapLineIndex);
+ const SfxPoolItem* aArguments[] = {&aHelpLineItem, nullptr};
+ GetViewFrame()->GetDispatcher()->Execute(
+ SID_SET_SNAPITEM,
+ SfxCallMode::SLOT,
+ aArguments);
+ }
+ break;
+
+ case SID_DELETE_SNAPITEM:
+ {
+ rPageView.DeleteHelpLine(nSnapLineIndex);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviews5.cxx b/sd/source/ui/view/drviews5.cxx
new file mode 100644
index 000000000..3eb9f39c3
--- /dev/null
+++ b/sd/source/ui/view/drviews5.cxx
@@ -0,0 +1,650 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawViewShell.hxx>
+#include <editeng/outliner.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/request.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdoutl.hxx>
+
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <sdcommands.h>
+#include <sal/log.hxx>
+
+#include <svx/fmshell.hxx>
+#include <editeng/eeitem.hxx>
+#include <AccessibleDrawDocumentView.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <LayerTabBar.hxx>
+
+#include <app.hrc>
+#include <helpids.h>
+#include <optsitem.hxx>
+#include <sdmod.hxx>
+#include <FrameView.hxx>
+#include <Window.hxx>
+#include <drawview.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <Client.hxx>
+#include <slideshow.hxx>
+#include <unokywds.hxx>
+#include <sdpage.hxx>
+#include <SdUnoDrawView.hxx>
+#include <ViewShellBase.hxx>
+#include <FormShellManager.hxx>
+#include <DrawController.hxx>
+#include <memory>
+#include <comphelper/lok.hxx>
+
+namespace sd {
+
+void DrawViewShell::ModelHasChanged()
+{
+ Invalidate();
+ // that the navigator also gets an up to date state
+ GetViewFrame()->GetBindings().Invalidate( SID_NAVIGATOR_STATE, true );
+
+ SfxBoolItem aItem( SID_3D_STATE, true );
+ GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_3D_STATE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+
+ // now initialize the TextEditOutliner which was newly created by the draw engine
+ ::Outliner* pOutliner = mpDrawView->GetTextEditOutliner();
+ if (pOutliner)
+ {
+ SfxStyleSheetPool* pSPool = static_cast<SfxStyleSheetPool*>( GetDocSh()->GetStyleSheetPool() );
+ pOutliner->SetStyleSheetPool(pSPool);
+ }
+}
+
+void DrawViewShell::Resize()
+{
+ ViewShell::Resize();
+
+ // tdf#151621 Do not set if the embedded object is opening in a new window.
+ if (GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED
+ && GetDocSh()->IsInPlaceActive())
+ {
+ SetZoomRect(GetDocSh()->GetVisArea(ASPECT_CONTENT));
+ }
+
+ rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if( xSlideshow.is() && xSlideshow->isRunning() && !xSlideshow->isFullScreen() )
+ {
+ xSlideshow->resize(maViewSize);
+ }
+}
+
+void DrawViewShell::ArrangeGUIElements()
+{
+ // Retrieve the current size (thickness) of the scroll bars. That is
+ // the width of the vertical and the height of the horizontal scroll
+ // bar.
+ int nScrollBarSize = GetParentWindow()->GetSettings().GetStyleSettings().GetScrollBarSize();
+ maScrBarWH = Size (nScrollBarSize, nScrollBarSize);
+
+ ViewShell::ArrangeGUIElements ();
+
+ maTabControl->Hide();
+
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ Client* pIPClient = static_cast<Client*>(GetViewShell()->GetIPClient());
+ bool bClientActive = false;
+ if ( pIPClient && pIPClient->IsObjectInPlaceActive() )
+ bClientActive = true;
+
+ bool bInPlaceActive = GetViewFrame()->GetFrame().IsInPlace();
+
+ if ( mbZoomOnPage && !bInPlaceActive && !bClientActive )
+ {
+ // with split, always resize first window
+ //af pWindow = mpContentWindow.get();
+ SfxRequest aReq(SID_SIZE_PAGE, SfxCallMode::SLOT, GetDoc()->GetItemPool());
+ ExecuteSlot( aReq );
+ }
+}
+
+/**
+ * Apply data of the FrameView on the current view
+ */
+void DrawViewShell::ReadFrameViewData(FrameView* pView)
+{
+ ModifyGuard aGuard( GetDoc() );
+
+ // this option has to be adjust at the model
+ GetDoc()->SetPickThroughTransparentTextFrames(
+ SD_MOD()->GetSdOptions(GetDoc()->GetDocumentType())->IsPickThrough());
+
+ // initialization of the Character-(Screen-) attribute
+ if (HasRuler() != pView->HasRuler())
+ SetRuler( pView->HasRuler() );
+
+ if (mpDrawView->GetGridCoarse() != pView->GetGridCoarse())
+ mpDrawView->SetGridCoarse( pView->GetGridCoarse() );
+
+ if (mpDrawView->GetGridFine() != pView->GetGridFine())
+ mpDrawView->SetGridFine( pView->GetGridFine() );
+
+ if (mpDrawView->GetSnapGridWidthX() != pView->GetSnapGridWidthX() || mpDrawView->GetSnapGridWidthY() != pView->GetSnapGridWidthY())
+ mpDrawView->SetSnapGridWidth(pView->GetSnapGridWidthX(), pView->GetSnapGridWidthY());
+
+ if (mpDrawView->IsGridVisible() != pView->IsGridVisible())
+ mpDrawView->SetGridVisible( pView->IsGridVisible() );
+
+ if (mpDrawView->IsGridFront() != pView->IsGridFront())
+ mpDrawView->SetGridFront( pView->IsGridFront() );
+
+ if (mpDrawView->GetSnapAngle() != pView->GetSnapAngle())
+ mpDrawView->SetSnapAngle( pView->GetSnapAngle() );
+
+ if (mpDrawView->IsGridSnap() != pView->IsGridSnap() )
+ mpDrawView->SetGridSnap( pView->IsGridSnap() );
+
+ if (mpDrawView->IsBordSnap() != pView->IsBordSnap() )
+ mpDrawView->SetBordSnap( pView->IsBordSnap() );
+
+ if (mpDrawView->IsHlplSnap() != pView->IsHlplSnap() )
+ mpDrawView->SetHlplSnap( pView->IsHlplSnap() );
+
+ if (mpDrawView->IsOFrmSnap() != pView->IsOFrmSnap() )
+ mpDrawView->SetOFrmSnap( pView->IsOFrmSnap() );
+
+ if (mpDrawView->IsOPntSnap() != pView->IsOPntSnap() )
+ mpDrawView->SetOPntSnap( pView->IsOPntSnap() );
+
+ if (mpDrawView->IsOConSnap() != pView->IsOConSnap() )
+ mpDrawView->SetOConSnap( pView->IsOConSnap() );
+
+ if (mpDrawView->IsHlplVisible() != pView->IsHlplVisible() )
+ mpDrawView->SetHlplVisible( pView->IsHlplVisible() );
+
+ if (mpDrawView->IsDragStripes() != pView->IsDragStripes() )
+ mpDrawView->SetDragStripes( pView->IsDragStripes() );
+
+ if (mpDrawView->IsPlusHandlesAlwaysVisible() != pView->IsPlusHandlesAlwaysVisible() )
+ mpDrawView->SetPlusHandlesAlwaysVisible( pView->IsPlusHandlesAlwaysVisible() );
+
+ if (mpDrawView->GetSnapMagneticPixel() != pView->GetSnapMagneticPixel() )
+ mpDrawView->SetSnapMagneticPixel( pView->GetSnapMagneticPixel() );
+
+ if (mpDrawView->IsMarkedHitMovesAlways() != pView->IsMarkedHitMovesAlways() )
+ mpDrawView->SetMarkedHitMovesAlways( pView->IsMarkedHitMovesAlways() );
+
+ if (mpDrawView->IsMoveOnlyDragging() != pView->IsMoveOnlyDragging() )
+ mpDrawView->SetMoveOnlyDragging( pView->IsMoveOnlyDragging() );
+
+ if (mpDrawView->IsNoDragXorPolys() != pView->IsNoDragXorPolys() )
+ mpDrawView->SetNoDragXorPolys( pView->IsNoDragXorPolys() );
+
+ if (mpDrawView->IsCrookNoContortion() != pView->IsCrookNoContortion() )
+ mpDrawView->SetCrookNoContortion( pView->IsCrookNoContortion() );
+
+ if (mpDrawView->IsAngleSnapEnabled() != pView->IsAngleSnapEnabled() )
+ mpDrawView->SetAngleSnapEnabled( pView->IsAngleSnapEnabled() );
+
+ if (mpDrawView->IsBigOrtho() != pView->IsBigOrtho() )
+ mpDrawView->SetBigOrtho( pView->IsBigOrtho() );
+
+ if (mpDrawView->IsOrtho() != pView->IsOrtho() )
+ mpDrawView->SetOrtho( pView->IsOrtho() );
+
+ if (mpDrawView->GetEliminatePolyPointLimitAngle() != pView->GetEliminatePolyPointLimitAngle() )
+ mpDrawView->SetEliminatePolyPointLimitAngle( pView->GetEliminatePolyPointLimitAngle() );
+
+ if (mpDrawView->IsEliminatePolyPoints() != pView->IsEliminatePolyPoints() )
+ mpDrawView->SetEliminatePolyPoints( pView->IsEliminatePolyPoints() );
+
+ if (mpDrawView->IsSolidDragging() != pView->IsSolidDragging() )
+ mpDrawView->SetSolidDragging( pView->IsSolidDragging() );
+
+ if (mpDrawView->IsQuickTextEditMode() != pView->IsQuickEdit())
+ mpDrawView->SetQuickTextEditMode( pView->IsQuickEdit() );
+
+ // #i26631#
+ if (mpDrawView->IsMasterPagePaintCaching() != pView->IsMasterPagePaintCaching())
+ mpDrawView->SetMasterPagePaintCaching( pView->IsMasterPagePaintCaching() );
+
+ // handle size: 9 pixels
+ sal_uInt16 nTmp = mpDrawView->GetMarkHdlSizePixel();
+ if( nTmp != 9 )
+ mpDrawView->SetMarkHdlSizePixel( 9 );
+
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+ if (pPageView)
+ {
+ if ( pPageView->GetVisibleLayers() != pView->GetVisibleLayers() )
+ pPageView->SetVisibleLayers( pView->GetVisibleLayers() );
+
+ if ( pPageView->GetPrintableLayers() != pView->GetPrintableLayers() )
+ pPageView->SetPrintableLayers( pView->GetPrintableLayers() );
+
+ if ( pPageView->GetLockedLayers() != pView->GetLockedLayers() )
+ pPageView->SetLockedLayers( pView->GetLockedLayers() );
+
+ if (mePageKind == PageKind::Notes)
+ {
+ if (pPageView->GetHelpLines() != pView->GetNotesHelpLines())
+ pPageView->SetHelpLines( pView->GetNotesHelpLines() );
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ if (pPageView->GetHelpLines() != pView->GetHandoutHelpLines())
+ pPageView->SetHelpLines( pView->GetHandoutHelpLines() );
+ }
+ else
+ {
+ if (pPageView->GetHelpLines() != pView->GetStandardHelpLines())
+ pPageView->SetHelpLines( pView->GetStandardHelpLines() );
+ }
+ }
+
+ if ( mpDrawView->GetActiveLayer() != pView->GetActiveLayer() )
+ mpDrawView->SetActiveLayer( pView->GetActiveLayer() );
+
+ sal_uInt16 nSelectedPage = 0;
+
+ if (mePageKind != PageKind::Handout)
+ {
+ nSelectedPage = pView->GetSelectedPage();
+ }
+
+ EditMode eNewEditMode = pView->GetViewShEditMode(/*mePageKind*/);
+ bool bNewLayerMode = pView->IsLayerMode();
+
+ if(IsLayerModeActive() && bNewLayerMode)
+ {
+ // #i57936# Force mbIsLayerModeActive to false so that ChangeEditMode
+ // below does something regarding LayerTabBar content refresh. That refresh
+ // is only done when IsLayerModeActive changes. It needs to be done
+ // since e.g. Layer visibility was changed above and this may need
+ // a refresh to show the correct graphical representation
+ mbIsLayerModeActive = false;
+ }
+
+ ChangeEditMode(eNewEditMode, bNewLayerMode);
+ SwitchPage(nSelectedPage);
+
+ // restore DrawMode for 'normal' window
+ if(GetActiveWindow()->GetOutDev()->GetDrawMode() != pView->GetDrawMode())
+ GetActiveWindow()->GetOutDev()->SetDrawMode(pView->GetDrawMode());
+
+ if ( mpDrawView->IsDesignMode() != pView->IsDesignMode() )
+ {
+ SfxBoolItem aDesignModeItem( SID_FM_DESIGN_MODE, pView->IsDesignMode() );
+ GetViewFrame()->GetDispatcher()->ExecuteList(SID_FM_DESIGN_MODE,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aDesignModeItem });
+ }
+
+ // has to be called in the end, because it executes a WriteFrameViewData()
+ if (mpDrawView->IsFrameDragSingles() != pView->IsFrameDragSingles() )
+ mpDrawView->SetFrameDragSingles( pView->IsFrameDragSingles() );
+}
+
+/**
+ * Apply data of the current view on the FrameView
+ */
+void DrawViewShell::WriteFrameViewData()
+{
+ // store character-(screen-) attribute of FrameView
+ mpFrameView->SetRuler( HasRuler() );
+ mpFrameView->SetGridCoarse( mpDrawView->GetGridCoarse() );
+ mpFrameView->SetGridFine( mpDrawView->GetGridFine() );
+ mpFrameView->SetSnapGridWidth(mpDrawView->GetSnapGridWidthX(), mpDrawView->GetSnapGridWidthY());
+ mpFrameView->SetGridVisible( mpDrawView->IsGridVisible() );
+ mpFrameView->SetGridFront( mpDrawView->IsGridFront() );
+ mpFrameView->SetSnapAngle( mpDrawView->GetSnapAngle() );
+ mpFrameView->SetGridSnap( mpDrawView->IsGridSnap() );
+ mpFrameView->SetBordSnap( mpDrawView->IsBordSnap() );
+ mpFrameView->SetHlplSnap( mpDrawView->IsHlplSnap() );
+ mpFrameView->SetOFrmSnap( mpDrawView->IsOFrmSnap() );
+ mpFrameView->SetOPntSnap( mpDrawView->IsOPntSnap() );
+ mpFrameView->SetOConSnap( mpDrawView->IsOConSnap() );
+ mpFrameView->SetHlplVisible( mpDrawView->IsHlplVisible() );
+ mpFrameView->SetDragStripes( mpDrawView->IsDragStripes() );
+ mpFrameView->SetPlusHandlesAlwaysVisible( mpDrawView->IsPlusHandlesAlwaysVisible() );
+ mpFrameView->SetFrameDragSingles( mpDrawView->IsFrameDragSingles() );
+ mpFrameView->SetMarkedHitMovesAlways( mpDrawView->IsMarkedHitMovesAlways() );
+ mpFrameView->SetMoveOnlyDragging( mpDrawView->IsMoveOnlyDragging() );
+ mpFrameView->SetNoDragXorPolys( mpDrawView->IsNoDragXorPolys() );
+ mpFrameView->SetCrookNoContortion( mpDrawView->IsCrookNoContortion() );
+ mpFrameView->SetBigOrtho( mpDrawView->IsBigOrtho() );
+ mpFrameView->SetEliminatePolyPointLimitAngle( mpDrawView->GetEliminatePolyPointLimitAngle() );
+ mpFrameView->SetEliminatePolyPoints( mpDrawView->IsEliminatePolyPoints() );
+
+ mpFrameView->SetSolidDragging( mpDrawView->IsSolidDragging() );
+ mpFrameView->SetQuickEdit( mpDrawView->IsQuickTextEditMode() );
+
+ mpFrameView->SetDesignMode( mpDrawView->IsDesignMode() );
+
+ Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel();
+ ::tools::Rectangle aVisArea = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // aVisArea is nonsensical in the LOK case, use the slide size
+ aVisArea = ::tools::Rectangle(Point(), getCurrentPage()->GetSize());
+ }
+
+ mpFrameView->SetVisArea(aVisArea);
+
+ if( mePageKind == PageKind::Handout )
+ mpFrameView->SetSelectedPage(0);
+ else
+ {
+ mpFrameView->SetSelectedPage( maTabControl->GetCurPagePos() );
+ }
+
+ mpFrameView->SetViewShEditMode(meEditMode);
+ mpFrameView->SetLayerMode(IsLayerModeActive());
+
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+
+ if (pPageView)
+ {
+ if ( mpFrameView->GetVisibleLayers() != pPageView->GetVisibleLayers() )
+ mpFrameView->SetVisibleLayers( pPageView->GetVisibleLayers() );
+
+ if ( mpFrameView->GetPrintableLayers() != pPageView->GetPrintableLayers() )
+ mpFrameView->SetPrintableLayers( pPageView->GetPrintableLayers() );
+
+ if ( mpFrameView->GetLockedLayers() != pPageView->GetLockedLayers() )
+ mpFrameView->SetLockedLayers( pPageView->GetLockedLayers() );
+
+ if (mePageKind == PageKind::Notes)
+ {
+ mpFrameView->SetNotesHelpLines( pPageView->GetHelpLines() );
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ mpFrameView->SetHandoutHelpLines( pPageView->GetHelpLines() );
+ }
+ else
+ {
+ mpFrameView->SetStandardHelpLines( pPageView->GetHelpLines() );
+ }
+ }
+
+ if ( mpFrameView->GetActiveLayer() != mpDrawView->GetActiveLayer() )
+ mpFrameView->SetActiveLayer( mpDrawView->GetActiveLayer() );
+
+ // store DrawMode for 'normal' window
+ if(mpFrameView->GetDrawMode() != GetActiveWindow()->GetOutDev()->GetDrawMode())
+ mpFrameView->SetDrawMode(GetActiveWindow()->GetOutDev()->GetDrawMode());
+}
+
+void DrawViewShell::PrePaint()
+{
+ mpDrawView->PrePaint();
+}
+
+/**
+ * The event is forwarded to the Viewshell and the current function by the
+ * window pWin.
+ *
+ * Remark: pWin==NULL, if Paint() is called from ShowWindow!
+ */
+void DrawViewShell::Paint(const ::tools::Rectangle& rRect, ::sd::Window* pWin)
+{
+ /* This is done before each text edit, so why not do it before every paint.
+ The default language is only used if the outliner only contains one
+ character in a symbol font */
+ GetDoc()->GetDrawOutliner().SetDefaultLanguage( GetDoc()->GetLanguage( EE_CHAR_LANGUAGE ) );
+
+ // Set Application Background color for usage in SdrPaintView(s)
+ mpDrawView->SetApplicationBackgroundColor( mnAppBackgroundColor );
+
+ /* This is done before each text edit, so why not do it before every paint.
+ The default language is only used if the outliner only contains one
+ character in a symbol font */
+ GetDoc()->GetDrawOutliner().SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
+
+ mpDrawView->CompleteRedraw( pWin->GetOutDev(), vcl::Region( rRect ) );
+}
+
+/**
+ * adjust zoom factor for InPlace
+ */
+void DrawViewShell::SetZoomFactor(const Fraction& rZoomX, const Fraction& rZoomY)
+{
+ ViewShell::SetZoomFactor(rZoomX, rZoomY);
+ mbZoomOnPage = false;
+ Point aOrigin = GetActiveWindow()->GetViewOrigin();
+ GetActiveWindow()->SetWinViewPos(aOrigin);
+}
+
+void DrawViewShell::HidePage()
+{
+ FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell();
+ if (pFormShell != nullptr)
+ pFormShell->PrepareClose(false);
+}
+
+void DrawViewShell::WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& rSequence )
+{
+ WriteFrameViewData();
+
+ ViewShell::WriteUserDataSequence( rSequence );
+
+ const sal_Int32 nIndex = rSequence.getLength();
+ rSequence.realloc( nIndex + 1 );
+ auto pSequence = rSequence.getArray();
+ pSequence[nIndex].Name = sUNO_View_ZoomOnPage ;
+ pSequence[nIndex].Value <<= mbZoomOnPage;
+
+ // Common SdrModel processing
+ GetDocSh()->GetDoc()->WriteUserDataSequence(rSequence);
+}
+
+void DrawViewShell::ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& rSequence )
+{
+ WriteFrameViewData();
+
+ ViewShell::ReadUserDataSequence( rSequence );
+
+ for (const css::beans::PropertyValue& rValue : rSequence)
+ {
+ if ( rValue.Name == sUNO_View_ZoomOnPage )
+ {
+ bool bZoomPage = false;
+ if( rValue.Value >>= bZoomPage )
+ {
+ mbZoomOnPage = bZoomPage;
+ }
+ }
+ // Fallback to common SdrModel processing
+ else GetDocSh()->GetDoc()->ReadUserDataSequenceValue(&rValue);
+ }
+
+ // The parameter rSequence contains the config-items from
+ // <config:config-item-set config:name="ooo:view-settings">. Determine, whether
+ // they contain "VisibleLayers", "PrintableLayers" and "LockedLayers". If not, it
+ // is a foreign document or a new document after transition period and the corresponding
+ // information were read from <draw:layer-set>. In that case we need to bring
+ // the information from model to view.
+ bool bHasVisiPrnLockSettings(false);
+ for ( auto & rPropertyValue : rSequence )
+ {
+ if ( rPropertyValue.Name == sUNO_View_VisibleLayers
+ || rPropertyValue.Name == sUNO_View_PrintableLayers
+ || rPropertyValue.Name == sUNO_View_LockedLayers )
+ {
+ bHasVisiPrnLockSettings = true;
+ break;
+ }
+ }
+ if ( !bHasVisiPrnLockSettings )
+ {
+ const SdrLayerAdmin& rLayerAdmin = GetDocSh()->GetDoc()->GetLayerAdmin();
+ SdrLayerIDSet aSdrLayerIDSet;
+ rLayerAdmin.getVisibleLayersODF( aSdrLayerIDSet );
+ mpFrameView -> SetVisibleLayers( aSdrLayerIDSet );
+ rLayerAdmin.getPrintableLayersODF( aSdrLayerIDSet );
+ mpFrameView -> SetPrintableLayers( aSdrLayerIDSet );
+ rLayerAdmin.getLockedLayersODF( aSdrLayerIDSet );
+ mpFrameView -> SetLockedLayers( aSdrLayerIDSet );
+ }
+ else
+ {
+ // tdf#129898 repair layer "DrawnInSlideshow", which was wrongly written
+ // in LO 6.2 to 6.4. The ODF defaults were corrected when reading draw:layer-set, but
+ // not in reading config settings, because there the name is not known.
+ const SdrLayerAdmin& rLayerAdmin = GetDocSh()->GetDoc()->GetLayerAdmin();
+ if (rLayerAdmin.GetLayer("DrawnInSlideshow"))
+ {
+ SdrLayerIDSet aSdrLayerIDSet;
+ rLayerAdmin.getVisibleLayersODF( aSdrLayerIDSet );
+ mpFrameView -> SetVisibleLayers( aSdrLayerIDSet );
+ rLayerAdmin.getPrintableLayersODF( aSdrLayerIDSet );
+ mpFrameView -> SetPrintableLayers( aSdrLayerIDSet );
+ rLayerAdmin.getLockedLayersODF( aSdrLayerIDSet );
+ mpFrameView -> SetLockedLayers( aSdrLayerIDSet );
+ }
+ }
+
+
+ if( mpFrameView->GetPageKind() != mePageKind )
+ {
+ mePageKind = mpFrameView->GetPageKind();
+
+ if (mePageKind == PageKind::Notes)
+ {
+ GetActiveWindow()->SetHelpId( CMD_SID_NOTES_MODE );
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ GetActiveWindow()->SetHelpId( CMD_SID_HANDOUT_MASTER_MODE );
+ }
+ else
+ {
+ GetActiveWindow()->SetHelpId( HID_SDDRAWVIEWSHELL );
+ }
+ }
+
+ ReadFrameViewData( mpFrameView );
+
+ if( !mbZoomOnPage )
+ {
+ const ::tools::Rectangle aVisArea( mpFrameView->GetVisArea() );
+
+ // tdf#151621 Do not set if the embedded object is opening in a new window.
+ if (GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED
+ && GetDocSh()->IsInPlaceActive())
+ {
+ GetDocSh()->SetVisArea(aVisArea);
+ }
+
+ VisAreaChanged(aVisArea);
+
+ ::sd::View* pView = GetView();
+
+ if (pView)
+ {
+ pView->VisAreaChanged(GetActiveWindow()->GetOutDev());
+ }
+
+ SetZoomRect(aVisArea);
+ }
+ ChangeEditMode (meEditMode, ! IsLayerModeActive());
+ ResetActualLayer();
+}
+
+void DrawViewShell::VisAreaChanged(const ::tools::Rectangle& rRect)
+{
+ ViewShell::VisAreaChanged( rRect );
+
+ DrawController& rController = GetViewShellBase().GetDrawController();
+ rController.FireVisAreaChanged (rRect);
+}
+
+/** If there is a valid controller then create a new instance of
+ <type>AccessibleDrawDocumentView</type>. Otherwise return an empty
+ reference.
+*/
+css::uno::Reference<css::accessibility::XAccessible>
+ DrawViewShell::CreateAccessibleDocumentView (::sd::Window* pWindow)
+{
+ if (GetViewShellBase().GetController() != nullptr)
+ {
+ rtl::Reference<accessibility::AccessibleDrawDocumentView> pDocumentView =
+ new accessibility::AccessibleDrawDocumentView (
+ pWindow,
+ this,
+ GetViewShellBase().GetController(),
+ pWindow->GetAccessibleParentWindow()->GetAccessible());
+ pDocumentView->Init();
+ return pDocumentView;
+ }
+
+ SAL_WARN("sd", "DrawViewShell::CreateAccessibleDocumentView: no controller");
+ return css::uno::Reference< css::accessibility::XAccessible>();
+}
+
+int DrawViewShell::GetActiveTabLayerIndex() const
+{
+ const LayerTabBar* pBar
+ = const_cast<DrawViewShell*>(this)->GetLayerTabControl ();
+ if (pBar != nullptr)
+ return pBar->GetPagePos (pBar->GetCurPageId());
+ else
+ return -1;
+}
+
+void DrawViewShell::SetActiveTabLayerIndex (int nIndex)
+{
+ LayerTabBar* pBar = GetLayerTabControl ();
+ if (pBar == nullptr)
+ return;
+
+ // Ignore invalid indices silently.
+ if (nIndex>=0 && nIndex<pBar->GetPageCount())
+ {
+ // Tell the draw view and the tab control of the new active layer.
+ mpDrawView->SetActiveLayer (pBar->GetLayerName (pBar->GetPageId (static_cast<sal_uInt16>(nIndex))));
+ pBar->SetCurPageId (pBar->GetPageId (static_cast<sal_uInt16>(nIndex)));
+ rtl::Reference<SdUnoDrawView> pUnoDrawView(new SdUnoDrawView (
+ *this,
+ *GetView()));
+ css::uno::Reference< css::drawing::XLayer> rLayer = pUnoDrawView->getActiveLayer();
+ GetViewShellBase().GetDrawController().fireChangeLayer( &rLayer );
+ }
+}
+
+LayerTabBar* DrawViewShell::GetLayerTabControl()
+{
+ return mpLayerTabBar.get();
+}
+
+int DrawViewShell::GetTabLayerCount() const
+{
+ const LayerTabBar* pBar
+ = const_cast<DrawViewShell*>(this)->GetLayerTabControl ();
+ if (pBar != nullptr)
+ return pBar->GetPageCount();
+ else
+ return 0;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviews6.cxx b/sd/source/ui/view/drviews6.cxx
new file mode 100644
index 000000000..7d85151f7
--- /dev/null
+++ b/sd/source/ui/view/drviews6.cxx
@@ -0,0 +1,339 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <DrawViewShell.hxx>
+#include <sfx2/request.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svxids.hrc>
+#include <svx/fontwork.hxx>
+#include <svx/bmpmask.hxx>
+#include <svx/imapdlg.hxx>
+#include <svx/SvxColorChildWindow.hxx>
+#include <svx/f3dchild.hxx>
+#include <avmedia/mediaplayer.hxx>
+#include <svl/intitem.hxx>
+
+#include <app.hrc>
+#include <strings.hrc>
+
+#include <animobjs.hxx>
+#include <AnimationChildWindow.hxx>
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <drawview.hxx>
+#include <svx/svdoashp.hxx>
+
+namespace sd {
+
+/**
+ * handle SfxRequests for FontWork
+ */
+void DrawViewShell::ExecFormText(SfxRequest& rReq)
+{
+ // nothing is executed during a slide show!
+ if(HasCurrentFunction(SID_PRESENTATION))
+ return;
+
+ CheckLineTo (rReq);
+
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+
+ if ( rMarkList.GetMarkCount() == 1 && rReq.GetArgs() &&
+ !mpDrawView->IsPresObjSelected() )
+ {
+ const SfxItemSet& rSet = *rReq.GetArgs();
+
+ if ( mpDrawView->IsTextEdit() )
+ mpDrawView->SdrEndTextEdit();
+
+ mpDrawView->SetAttributes(rSet);
+ }
+}
+
+/**
+ * Return state values for FontWork
+ */
+void DrawViewShell::GetFormTextState(SfxItemSet& rSet)
+{
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ const SdrObject* pObj = nullptr;
+
+ if ( rMarkList.GetMarkCount() == 1 )
+ pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ const SdrTextObj* pTextObj = dynamic_cast< const SdrTextObj* >(pObj);
+ const bool bDeactivate(
+ !pObj ||
+ !pTextObj ||
+ !pTextObj->HasText() ||
+ dynamic_cast< const SdrObjCustomShape* >(pObj)); // #121538# no FontWork for CustomShapes
+
+ if(bDeactivate)
+ {
+// automatic open/close the FontWork-Dialog; first deactivate it
+
+ rSet.DisableItem(XATTR_FORMTXTSTYLE);
+ rSet.DisableItem(XATTR_FORMTXTADJUST);
+ rSet.DisableItem(XATTR_FORMTXTDISTANCE);
+ rSet.DisableItem(XATTR_FORMTXTSTART);
+ rSet.DisableItem(XATTR_FORMTXTMIRROR);
+ rSet.DisableItem(XATTR_FORMTXTHIDEFORM);
+ rSet.DisableItem(XATTR_FORMTXTOUTLINE);
+ rSet.DisableItem(XATTR_FORMTXTSHADOW);
+ rSet.DisableItem(XATTR_FORMTXTSHDWCOLOR);
+ rSet.DisableItem(XATTR_FORMTXTSHDWXVAL);
+ rSet.DisableItem(XATTR_FORMTXTSHDWYVAL);
+ }
+ else
+ {
+ SfxItemSet aSet( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aSet );
+ rSet.Set( aSet );
+ }
+}
+
+void DrawViewShell::ExecAnimationWin( SfxRequest& rReq )
+{
+ // nothing is executed during a slide show!
+ if (HasCurrentFunction(SID_PRESENTATION))
+ return;
+
+ CheckLineTo (rReq);
+
+ sal_uInt16 nSId = rReq.GetSlot();
+
+ switch( nSId )
+ {
+ case SID_ANIMATOR_INIT:
+ case SID_ANIMATOR_ADD:
+ case SID_ANIMATOR_CREATE:
+ {
+ AnimationWindow* pAnimWin;
+ sal_uInt16 nId = AnimationChildWindow::GetChildWindowId();
+
+ SfxChildWindow* pWnd = GetViewFrame()->GetChildWindow(nId);
+
+ pAnimWin = pWnd ? static_cast<AnimationWindow*>(pWnd->GetWindow()) : nullptr;
+
+ if ( pAnimWin )
+ {
+ if( nSId == SID_ANIMATOR_ADD )
+ pAnimWin->AddObj( *mpDrawView );
+ else if( nSId == SID_ANIMATOR_CREATE )
+ pAnimWin->CreateAnimObj( *mpDrawView );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * Return status values for animator
+ *
+ * nValue == 0 -> No button
+ * nValue == 1 -> Button 'accept'
+ * nValue == 2 -> Button 'accept individually'
+ * nValue == 3 -> Buttons 'accept' and 'accept individually'
+ */
+void DrawViewShell::GetAnimationWinState( SfxItemSet& rSet )
+{
+ // here we could disable buttons etc.
+ sal_uInt16 nValue;
+
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+
+ if( nMarkCount == 0 )
+ nValue = 0;
+ else if( nMarkCount > 1 )
+ nValue = 3;
+ else // 1 Object
+ {
+ const SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nId = pObj->GetObjIdentifier();
+ // 1 selected group object
+ if( nInv == SdrInventor::Default && nId == SdrObjKind::Group )
+ nValue = 3;
+ else if( nInv == SdrInventor::Default && nId == SdrObjKind::Graphic ) // Animated GIF ?
+ {
+ sal_uInt16 nCount = 0;
+
+ if( static_cast<const SdrGrafObj*>(pObj)->IsAnimated() )
+ nCount = static_cast<const SdrGrafObj*>(pObj)->GetGraphic().GetAnimation().Count();
+ if( nCount > 0 )
+ nValue = 2;
+ else
+ nValue = 1;
+ }
+ else
+ nValue = 1;
+ }
+ rSet.Put( SfxUInt16Item( SID_ANIMATOR_STATE, nValue ) );
+}
+
+void DrawViewShell::SetChildWindowState( SfxItemSet& rSet )
+{
+ // State of SfxChild-Windows (Animator, Fontwork etc.)
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_FONTWORK ) )
+ {
+ sal_uInt16 nId = SvxFontWorkChildWindow::GetChildWindowId();
+ rSet.Put(SfxBoolItem(SID_FONTWORK, GetViewFrame()->HasChildWindow(nId)));
+ }
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_COLOR_CONTROL ) )
+ {
+ sal_uInt16 nId = SvxColorChildWindow::GetChildWindowId();
+ rSet.Put(SfxBoolItem(SID_COLOR_CONTROL, GetViewFrame()->HasChildWindow(nId)));
+ }
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ANIMATION_OBJECTS ) )
+ {
+ sal_uInt16 nId = AnimationChildWindow::GetChildWindowId();
+ rSet.Put( SfxBoolItem( SID_ANIMATION_OBJECTS, GetViewFrame()->HasChildWindow( nId ) ) );
+ }
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_NAVIGATOR ) )
+ {
+ rSet.Put( SfxBoolItem( SID_NAVIGATOR, GetViewFrame()->HasChildWindow( SID_NAVIGATOR ) ) );
+ }
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_BMPMASK ) )
+ {
+ sal_uInt16 nId = SvxBmpMaskChildWindow::GetChildWindowId();
+ rSet.Put( SfxBoolItem( SID_BMPMASK, GetViewFrame()->HasChildWindow( nId ) ) );
+ }
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_IMAP ) )
+ {
+ sal_uInt16 nId = SvxIMapDlgChildWindow::GetChildWindowId();
+ rSet.Put( SfxBoolItem( SID_IMAP, GetViewFrame()->HasChildWindow( nId ) ) );
+ }
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_3D_WIN ) )
+ {
+ sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId();
+ rSet.Put( SfxBoolItem( SID_3D_WIN, GetViewFrame()->HasChildWindow( nId ) ) );
+ }
+#if HAVE_FEATURE_AVMEDIA
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_AVMEDIA_PLAYER ) )
+ {
+ sal_uInt16 nId = ::avmedia::MediaPlayer::GetChildWindowId();
+ rSet.Put( SfxBoolItem( SID_AVMEDIA_PLAYER, GetViewFrame()->HasChildWindow( nId ) ) );
+ }
+#endif
+}
+
+/**
+ * Handle SfxRequests for pipette
+ */
+void DrawViewShell::ExecBmpMask( SfxRequest const & rReq )
+{
+ // nothing is executed during a slide show!
+ if (HasCurrentFunction(SID_PRESENTATION))
+ return;
+
+ switch ( rReq.GetSlot() )
+ {
+ case SID_BMPMASK_PIPETTE :
+ {
+ mbPipette = static_cast<const SfxBoolItem&>( rReq.GetArgs()->
+ Get( SID_BMPMASK_PIPETTE ) ).GetValue();
+ }
+ break;
+
+ case SID_BMPMASK_EXEC :
+ {
+ SdrGrafObj* pObj = nullptr;
+ if( mpDrawView && mpDrawView->GetMarkedObjectList().GetMarkCount() )
+ pObj = dynamic_cast< SdrGrafObj* >( mpDrawView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj() );
+
+ if ( pObj && !mpDrawView->IsTextEdit() )
+ {
+ typedef std::unique_ptr< SdrGrafObj, SdrObjectFreeOp > SdrGrafObjPtr;
+ SdrGrafObjPtr xNewObj(pObj->CloneSdrObject(pObj->getSdrModelFromSdrObject()));
+ bool bCont = true;
+
+ if (xNewObj->IsLinkedGraphic())
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "modules/sdraw/ui/queryunlinkimagedialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQueryBox(xBuilder->weld_message_dialog("QueryUnlinkImageDialog"));
+
+ if (RET_YES == xQueryBox->run())
+ xNewObj->ReleaseGraphicLink();
+ else
+ bCont = false;
+ }
+
+ SfxChildWindow* pWnd = GetViewFrame()->GetChildWindow(
+ SvxBmpMaskChildWindow::GetChildWindowId());
+ SvxBmpMask* pBmpMask = pWnd ? static_cast<SvxBmpMask*>(pWnd->GetWindow()) : nullptr;
+ assert(pBmpMask);
+ if (bCont && pBmpMask)
+ {
+ const Graphic& rOldGraphic = xNewObj->GetGraphic();
+ const Graphic aNewGraphic(pBmpMask->Mask(rOldGraphic));
+
+ if( aNewGraphic != rOldGraphic )
+ {
+ SdrPageView* pPV = mpDrawView->GetSdrPageView();
+
+ xNewObj->SetEmptyPresObj(false);
+ xNewObj->SetGraphic(pBmpMask->Mask(xNewObj->GetGraphic()));
+
+ OUString aStr = mpDrawView->GetDescriptionOfMarkedObjects() +
+ " " + SdResId(STR_EYEDROPPER);
+
+ mpDrawView->BegUndo( aStr );
+ mpDrawView->ReplaceObjectAtView(pObj, *pPV, xNewObj.release());
+ mpDrawView->EndUndo();
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void DrawViewShell::GetBmpMaskState( SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ const SdrObject* pObj = nullptr;
+ bool bEnable = false;
+
+ if ( rMarkList.GetMarkCount() == 1 )
+ pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ // valid graphic object?
+ if( auto pGrafObj = dynamic_cast< const SdrGrafObj *>( pObj ) )
+ if (!pGrafObj->IsEPS() && !mpDrawView->IsTextEdit() )
+ bEnable = true;
+
+ // put value
+ rSet.Put( SfxBoolItem( SID_BMPMASK_EXEC, bEnable ) );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviews7.cxx b/sd/source/ui/view/drviews7.cxx
new file mode 100644
index 000000000..4f375dc6a
--- /dev/null
+++ b/sd/source/ui/view/drviews7.cxx
@@ -0,0 +1,1991 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <utility>
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/linguistic2/XThesaurus.hpp>
+#include <svx/pageitem.hxx>
+#include <svx/rulritem.hxx>
+#include <svx/svdouno.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/urlfieldhelper.hxx>
+#include <officecfg/Office/Impress.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svdpagv.hxx>
+#include <svx/clipfmtitem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <svl/visitem.hxx>
+#include <svl/whiter.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <editeng/unolingu.hxx>
+#include <svx/extrusionbar.hxx>
+#include <svx/fontworkbar.hxx>
+
+// #UndoRedo#
+#include <svtools/insdlg.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <svl/cjkoptions.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/request.hxx>
+
+#include <svtools/cliplistener.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <app.hrc>
+
+#include <PresentationViewShell.hxx>
+
+#include <drawdoc.hxx>
+#include <DrawViewShell.hxx>
+#include <sdmod.hxx>
+#include <unokywds.hxx>
+#include <sdpage.hxx>
+#include <DrawDocShell.hxx>
+#include <zoomlist.hxx>
+#include <slideshow.hxx>
+#include <drawview.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <LayerTabBar.hxx>
+#include <fupoor.hxx>
+#include <Window.hxx>
+#include <fuediglu.hxx>
+#include <fubullet.hxx>
+#include <fuconcs.hxx>
+#include <fuformatpaintbrush.hxx>
+#include <stlsheet.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::linguistic2;
+
+/** Create a list of clipboard formats that are supported both from the
+ current clipboard content and the DrawViewShell.
+ The list is stored in a new instance of SvxClipboardFormatItem.
+*/
+static ::std::unique_ptr<SvxClipboardFormatItem> GetSupportedClipboardFormats (
+ TransferableDataHelper& rDataHelper)
+{
+ ::std::unique_ptr<SvxClipboardFormatItem> pResult (
+ new SvxClipboardFormatItem(SID_CLIPBOARD_FORMAT_ITEMS));
+
+ sal_uInt32 nFormatCount (rDataHelper.GetFormatCount());
+ for (sal_uInt32 i=0; i<nFormatCount; i++)
+ {
+ const SotClipboardFormatId nTestFormat = rDataHelper.GetFormat(i);
+
+ // Check if the current format is the same as one that has already
+ // been handled.
+ bool bDuplicate (false);
+ for (sal_uInt32 j=0; j<i; j++)
+ {
+ if (nTestFormat == rDataHelper.GetFormat(j))
+ {
+ bDuplicate = true;
+ break;
+ }
+ }
+
+ // Look up the format among those that are supported by the
+ // DrawViewShell.
+ if ( ! bDuplicate)
+ {
+ switch (nTestFormat)
+ {
+ case SotClipboardFormatId::EMBED_SOURCE:
+ {
+ OUString sName;
+
+ TransferableObjectDescriptor aDescriptor;
+ if (rDataHelper.GetTransferableObjectDescriptor(
+ SotClipboardFormatId::OBJECTDESCRIPTOR, aDescriptor))
+ {
+ sName = aDescriptor.maTypeName;
+ }
+ if (!sName.isEmpty())
+ pResult->AddClipbrdFormat(nTestFormat, sName);
+ else
+ pResult->AddClipbrdFormat(nTestFormat);
+
+ break;
+ }
+
+
+ case SotClipboardFormatId::LINK_SOURCE:
+ case SotClipboardFormatId::DRAWING:
+ case SotClipboardFormatId::SVXB:
+ case SotClipboardFormatId::GDIMETAFILE:
+ case SotClipboardFormatId::BITMAP:
+ case SotClipboardFormatId::NETSCAPE_BOOKMARK:
+ case SotClipboardFormatId::STRING:
+ case SotClipboardFormatId::HTML:
+ case SotClipboardFormatId::RTF:
+ case SotClipboardFormatId::RICHTEXT:
+ case SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT:
+ pResult->AddClipbrdFormat(nTestFormat);
+ break;
+ default: break;
+ }
+ }
+ }
+
+ // Check some OLE formats whose names are handled differently.
+ SotClipboardFormatId nFormat (SotClipboardFormatId::EMBED_SOURCE_OLE);
+ bool bHasFormat (rDataHelper.HasFormat(nFormat));
+ if ( ! bHasFormat)
+ {
+ bHasFormat = rDataHelper.HasFormat(nFormat);
+ }
+ if (bHasFormat)
+ {
+ OUString sName;
+ OUString sSource;
+ if (SvPasteObjectHelper::GetEmbeddedName (rDataHelper, sName, sSource, nFormat))
+ pResult->AddClipbrdFormat (nFormat, sName);
+ }
+
+ return pResult;
+}
+
+namespace sd {
+
+IMPL_LINK( DrawViewShell, ClipboardChanged, TransferableDataHelper*, pDataHelper, void )
+{
+ mbPastePossible = ( pDataHelper->GetFormatCount() != 0 );
+
+ // Update the list of supported clipboard formats according to the
+ // new clipboard content.
+ // There are some stack traces that indicate the possibility of the
+ // DrawViewShell destructor called during the call to
+ // GetSupportedClipboardFormats(). If that really has happened then
+ // exit immediately.
+ TransferableDataHelper aDataHelper (
+ TransferableDataHelper::CreateFromSystemClipboard(GetActiveWindow()));
+ ::std::unique_ptr<SvxClipboardFormatItem> pFormats (GetSupportedClipboardFormats(aDataHelper));
+ if (mpDrawView == nullptr)
+ return;
+ mpCurrentClipboardFormats = std::move(pFormats);
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_PASTE );
+ rBindings.Invalidate( SID_PASTE_SPECIAL );
+ rBindings.Invalidate( SID_PASTE_UNFORMATTED );
+ rBindings.Invalidate( SID_CLIPBOARD_FORMAT_ITEMS );
+}
+
+void DrawViewShell::GetDrawAttrState(SfxItemSet& rSet)
+{
+ SfxItemSet aSet( mpDrawView->GetGeoAttrFromMarked() );
+ rSet.Put(aSet,false);
+}
+
+::Outliner* DrawViewShell::GetOutlinerForMasterPageOutlineTextObj(ESelection &rSel)
+{
+ if( !mpDrawView )
+ return nullptr;
+
+ //when there is one object selected
+ if (!mpDrawView->AreObjectsMarked() || (mpDrawView->GetMarkedObjectList().GetMarkCount() != 1))
+ return nullptr;
+
+ //and we are editing the outline object
+ if (!mpDrawView->IsTextEdit())
+ return nullptr;
+
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+ if (!pPageView)
+ return nullptr;
+
+ SdPage* pPage = static_cast<SdPage*>(pPageView->GetPage());
+ //only show these in a normal master page
+ if (!pPage || (pPage->GetPageKind() != PageKind::Standard) || !pPage->IsMasterPage())
+ return nullptr;
+
+ OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView();
+ ::Outliner* pOL = pOLV ? pOLV->GetOutliner() : nullptr;
+ if (!pOL)
+ return nullptr;
+ rSel = pOLV->GetSelection();
+
+ return pOL;
+}
+
+void DrawViewShell::GetMarginProperties( SfxItemSet &rSet )
+{
+ SdPage *pPage = getCurrentPage();
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ switch ( nWhich )
+ {
+ case SID_ATTR_PAGE_LRSPACE:
+ {
+ // const SvxLRSpaceItem aTmpPageLRSpace ( rDesc.GetMaster().GetLRSpace() );
+ const SvxLongLRSpaceItem aLongLR(
+ static_cast<::tools::Long>(pPage->GetLeftBorder()),
+ static_cast<::tools::Long>(pPage->GetRightBorder()),
+ SID_ATTR_PAGE_LRSPACE );
+ rSet.Put( aLongLR );
+ }
+ break;
+
+ case SID_ATTR_PAGE_ULSPACE:
+ {
+ // const SvxULSpaceItem aUL( rDesc.GetMaster().GetULSpace() );
+ SvxLongULSpaceItem aLongUL(
+ static_cast<::tools::Long>(pPage->GetUpperBorder()),
+ static_cast<::tools::Long>(pPage->GetLowerBorder()),
+ SID_ATTR_PAGE_ULSPACE );
+ rSet.Put( aLongUL );
+ }
+ break;
+
+ default:
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+bool DrawViewShell::ShouldDisableEditHyperlink() const
+{
+ if (!mpDrawView)
+ return true;
+ if (!mpDrawView->AreObjectsMarked())
+ return true;
+ if (mpDrawView->GetMarkedObjectList().GetMarkCount() != 1)
+ return true;
+
+ bool bDisableEditHyperlink = true;
+ if( mpDrawView->IsTextEdit() )
+ {
+ if (URLFieldHelper::IsCursorAtURLField(mpDrawView->GetTextEditOutlinerView()))
+ bDisableEditHyperlink = false;
+ }
+ else
+ {
+ SdrUnoObj* pUnoCtrl = dynamic_cast<SdrUnoObj*>( mpDrawView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj() );
+
+ if ( pUnoCtrl && SdrInventor::FmForm == pUnoCtrl->GetObjInventor() )
+ {
+ const uno::Reference< awt::XControlModel >& xControlModel( pUnoCtrl->GetUnoControlModel() );
+ if( xControlModel.is() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
+ if( xPropSet.is() )
+ {
+ uno::Reference< beans::XPropertySetInfo > xPropInfo( xPropSet->getPropertySetInfo() );
+ if( xPropInfo.is() && xPropInfo->hasPropertyByName( "TargetURL") )
+ {
+ bDisableEditHyperlink = false;
+ }
+ }
+ }
+ }
+ }
+ return bDisableEditHyperlink;
+}
+
+void DrawViewShell::GetMenuState( SfxItemSet &rSet )
+{
+ if (mpDrawView == nullptr)
+ {
+ // This assertion and return are here to prevent crashes.
+ DBG_ASSERT(mpDrawView!=nullptr, "Please report this assertion to the Impress team.");
+ return;
+ }
+
+ ViewShell::GetMenuState(rSet);
+ bool bDisableVerticalText = !SvtCJKOptions::IsVerticalTextEnabled();
+
+ if ( bDisableVerticalText )
+ {
+ rSet.DisableItem( SID_DRAW_FONTWORK_VERTICAL );
+ rSet.DisableItem( SID_DRAW_CAPTION_VERTICAL );
+ rSet.DisableItem( SID_TEXT_FITTOSIZE_VERTICAL );
+ rSet.DisableItem( SID_DRAW_TEXT_VERTICAL );
+ }
+
+ bool bConvertToPathPossible = mpDrawView->IsConvertToPathObjPossible();
+
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+
+ if( nMarkCount == 1 )
+ {
+ bool bDisable = true;
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if( auto pGrafObj = dynamic_cast<const SdrGrafObj*>( pObj) )
+ if( pGrafObj->getQrCode() )
+ bDisable = false;
+ if(bDisable)
+ {
+ rSet.DisableItem(SID_EDIT_QRCODE);
+ }
+ }
+
+ //format paintbrush
+ FuFormatPaintBrush::GetMenuState( *this, rSet );
+
+ // State of SfxChild-Windows (Animator, Fontwork etc.)
+ SetChildWindowState( rSet );
+
+ if(HasCurrentFunction())
+ {
+ sal_uInt16 nSId = GetCurrentFunction()->GetSlotID();
+ rSet.Put( SfxBoolItem( nSId, true ) );
+ }
+
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+
+ GetMenuStateSel(rSet);
+
+ if (SfxItemState::DEFAULT == rSet.GetItemState(SID_ASSIGN_LAYOUT))
+ {
+ bool bDisable = true;
+ if( pPageView )
+ {
+ SdPage* pPage = dynamic_cast< SdPage* >( pPageView->GetPage() );
+
+ if( pPage && !pPage->IsMasterPage() )
+ {
+ rSet.Put( SfxUInt32Item( SID_ASSIGN_LAYOUT, static_cast< sal_uInt32 >(pPage->GetAutoLayout()) ) );
+ bDisable = false;
+ }
+ }
+
+ if(bDisable)
+ {
+ rSet.DisableItem(SID_ASSIGN_LAYOUT);
+ }
+ }
+
+ if (SfxItemState::DEFAULT == rSet.GetItemState(SID_EXPAND_PAGE))
+ {
+ bool bDisable = true;
+ if( pPageView )
+ {
+ SdPage* pPage = dynamic_cast< SdPage* >( pPageView->GetPage() );
+
+ if( pPage && (pPage->GetPageKind() == PageKind::Standard) && !pPage->IsMasterPage() )
+ {
+ SdrObject* pObj = pPage->GetPresObj(PresObjKind::Outline);
+
+ if (pObj!=nullptr )
+ {
+ if( !pObj->IsEmptyPresObj() )
+ {
+ bDisable = false;
+ }
+ else
+ {
+ // check if the object is in edit, then if it's temporarily not empty
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObj );
+ if( pTextObj )
+ {
+ if( pTextObj->CanCreateEditOutlinerParaObject() )
+ {
+ bDisable = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(bDisable)
+ {
+ rSet.DisableItem(SID_EXPAND_PAGE);
+ }
+ }
+
+ if (SfxItemState::DEFAULT == rSet.GetItemState(SID_SUMMARY_PAGE))
+ {
+ bool bDisable = true;
+ if( pPageView )
+ {
+ SdPage* pPage = dynamic_cast< SdPage* >( pPageView->GetPage() );
+
+ if( pPage && (pPage->GetPageKind() == PageKind::Standard) && !pPage->IsMasterPage() )
+ {
+ SdrObject* pObj = pPage->GetPresObj(PresObjKind::Title);
+
+ if(pObj && !pObj->IsEmptyPresObj())
+ {
+ bDisable = false;
+ }
+ }
+ }
+
+ if(bDisable)
+ {
+ rSet.DisableItem(SID_SUMMARY_PAGE);
+ }
+ }
+
+ if (SfxItemState::DEFAULT == rSet.GetItemState(SID_ASSIGN_LAYOUT))
+ {
+ bool bDisable = true;
+ if( pPageView )
+ {
+ SdPage* pPage = dynamic_cast< SdPage* >( pPageView->GetPage() );
+
+ if( pPage && !pPage->IsMasterPage() )
+ {
+ rSet.Put( SfxUInt32Item(SID_ASSIGN_LAYOUT, pPage->GetAutoLayout()) );
+ bDisable = false;
+ }
+ }
+
+ if(bDisable)
+ {
+ rSet.DisableItem(SID_ASSIGN_LAYOUT);
+ }
+ }
+
+ // is it possible to start the presentation?
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_PRESENTATION ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_REHEARSE_TIMINGS ) )
+ {
+ bool bDisable = true;
+ sal_uInt16 nCount = GetDoc()->GetSdPageCount( PageKind::Standard );
+
+ for( sal_uInt16 i = 0; i < nCount && bDisable; i++ )
+ {
+ SdPage* pPage = GetDoc()->GetSdPage(i, PageKind::Standard);
+
+ if( !pPage->IsExcluded() )
+ bDisable = false;
+ }
+
+ if( bDisable || GetDocSh()->IsPreview())
+ {
+ rSet.DisableItem( SID_PRESENTATION );
+ rSet.DisableItem( SID_REHEARSE_TIMINGS );
+ }
+ }
+
+ // gluepoints
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_EDITMODE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_INSERT_POINT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_PERCENT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_ESCDIR ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_ESCDIR_LEFT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_ESCDIR_RIGHT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_ESCDIR_TOP ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_ESCDIR_BOTTOM ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_HORZALIGN_CENTER ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_HORZALIGN_LEFT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_HORZALIGN_RIGHT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_VERTALIGN_CENTER ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_VERTALIGN_TOP ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_VERTALIGN_BOTTOM ) )
+ {
+ // percent
+ TriState eState = mpDrawView->IsMarkedGluePointsPercent();
+ if( eState == TRISTATE_INDET )
+ rSet.InvalidateItem( SID_GLUE_PERCENT );
+ else
+ rSet.Put( SfxBoolItem( SID_GLUE_PERCENT, eState == TRISTATE_TRUE ) );
+
+ // alignment has no effect by percent
+ if( eState == TRISTATE_TRUE )
+ {
+ rSet.DisableItem( SID_GLUE_HORZALIGN_CENTER );
+ rSet.DisableItem( SID_GLUE_HORZALIGN_LEFT );
+ rSet.DisableItem( SID_GLUE_HORZALIGN_RIGHT );
+ rSet.DisableItem( SID_GLUE_VERTALIGN_CENTER );
+ rSet.DisableItem( SID_GLUE_VERTALIGN_TOP );
+ rSet.DisableItem( SID_GLUE_VERTALIGN_BOTTOM );
+ }
+ else
+ {
+ // horizontal alignment
+ SdrAlign nHorz = mpDrawView->GetMarkedGluePointsAlign( false );
+ rSet.Put( SfxBoolItem( SID_GLUE_HORZALIGN_CENTER, nHorz == SdrAlign::HORZ_CENTER ) );
+ rSet.Put( SfxBoolItem( SID_GLUE_HORZALIGN_LEFT, nHorz == SdrAlign::HORZ_LEFT ) );
+ rSet.Put( SfxBoolItem( SID_GLUE_HORZALIGN_RIGHT, nHorz == SdrAlign::HORZ_RIGHT ) );
+ // vertical alignment
+ SdrAlign nVert = mpDrawView->GetMarkedGluePointsAlign( true );
+ rSet.Put( SfxBoolItem( SID_GLUE_VERTALIGN_CENTER, nVert == SdrAlign::VERT_CENTER ) );
+ rSet.Put( SfxBoolItem( SID_GLUE_VERTALIGN_TOP, nVert == SdrAlign::VERT_TOP ) );
+ rSet.Put( SfxBoolItem( SID_GLUE_VERTALIGN_BOTTOM, nVert == SdrAlign::VERT_BOTTOM ) );
+ }
+
+ // insert point
+ rSet.Put( SfxBoolItem( SID_GLUE_INSERT_POINT, mpDrawView->IsInsGluePointMode() ) );
+
+ // Escape direction
+ // left
+ eState = mpDrawView->IsMarkedGluePointsEscDir( SdrEscapeDirection::LEFT );
+ if( eState == TRISTATE_INDET )
+ rSet.InvalidateItem( SID_GLUE_ESCDIR_LEFT );
+ else
+ rSet.Put( SfxBoolItem( SID_GLUE_ESCDIR_LEFT, eState == TRISTATE_TRUE ) );
+ // right
+ eState = mpDrawView->IsMarkedGluePointsEscDir( SdrEscapeDirection::RIGHT );
+ if( eState == TRISTATE_INDET )
+ rSet.InvalidateItem( SID_GLUE_ESCDIR_RIGHT );
+ else
+ rSet.Put( SfxBoolItem( SID_GLUE_ESCDIR_RIGHT, eState == TRISTATE_TRUE ) );
+ // top
+ eState = mpDrawView->IsMarkedGluePointsEscDir( SdrEscapeDirection::TOP );
+ if( eState == TRISTATE_INDET )
+ rSet.InvalidateItem( SID_GLUE_ESCDIR_TOP );
+ else
+ rSet.Put( SfxBoolItem( SID_GLUE_ESCDIR_TOP, eState == TRISTATE_TRUE ) );
+ // bottom
+ eState = mpDrawView->IsMarkedGluePointsEscDir( SdrEscapeDirection::BOTTOM );
+ if( eState == TRISTATE_INDET )
+ rSet.InvalidateItem( SID_GLUE_ESCDIR_BOTTOM );
+ else
+ rSet.Put( SfxBoolItem( SID_GLUE_ESCDIR_BOTTOM, eState == TRISTATE_TRUE ) );
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_GRID_FRONT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_HELPLINES_FRONT ) )
+ {
+ rSet.Put( SfxBoolItem( SID_GRID_FRONT, mpDrawView->IsGridFront() ) );
+ rSet.Put( SfxBoolItem( SID_HELPLINES_FRONT, mpDrawView->IsHlplFront() ) );
+ }
+
+ if (!mpDrawView->IsFrameDragSingles())
+ rSet.Put(SfxBoolItem(SID_BEZIER_EDIT, true));
+ else
+ rSet.Put(SfxBoolItem(SID_BEZIER_EDIT, false));
+
+ if(dynamic_cast<FuEditGluePoints*>( GetCurrentFunction().get()))
+ rSet.Put(SfxBoolItem(SID_GLUE_EDITMODE, true));
+ else
+ rSet.Put(SfxBoolItem(SID_GLUE_EDITMODE, false));
+
+ if( !mpDrawView->IsMirrorAllowed( true, true ) )
+ {
+ rSet.DisableItem( SID_HORIZONTAL );
+ rSet.DisableItem( SID_VERTICAL );
+ rSet.DisableItem( SID_FLIP_HORIZONTAL );
+ rSet.DisableItem( SID_FLIP_VERTICAL );
+ }
+
+ if( !mpDrawView->IsMirrorAllowed() )
+ {
+ rSet.DisableItem( SID_OBJECT_MIRROR );
+// rSet.DisableItem( SID_CONVERT_TO_3D_LATHE );
+// rSet.DisableItem( SID_CONVERT_TO_3D_LATHE_FAST );
+ }
+
+ // interactive transparence control
+ if(!mpDrawView->IsTransparenceAllowed())
+ {
+ rSet.DisableItem( SID_OBJECT_TRANSPARENCE );
+ }
+
+ // interactive gradient control
+ if(!mpDrawView->IsGradientAllowed())
+ {
+ rSet.DisableItem( SID_OBJECT_GRADIENT );
+ }
+
+ // disable morphing if necessary
+ if ( !mpDrawView->IsMorphingAllowed() )
+ rSet.DisableItem( SID_POLYGON_MORPHING );
+
+ if( !mpDrawView->IsReverseOrderPossible() )
+ {
+ rSet.DisableItem( SID_REVERSE_ORDER );
+ }
+
+ if ( !bConvertToPathPossible &&
+ !mpDrawView->IsCrookAllowed( mpDrawView->IsCrookNoContortion() ) )
+ {
+ // implicit transformation into curve not possible
+ rSet.DisableItem(SID_OBJECT_CROOK_ROTATE);
+ rSet.DisableItem(SID_OBJECT_CROOK_SLANT);
+ rSet.DisableItem(SID_OBJECT_CROOK_STRETCH);
+ }
+
+ if ( !mpDrawView->IsGroupEntered() )
+ {
+ rSet.DisableItem( SID_LEAVE_GROUP );
+ rSet.Put( SfxBoolItem( SID_LEAVE_ALL_GROUPS, false ) );
+ rSet.ClearItem( SID_LEAVE_ALL_GROUPS );
+ rSet.DisableItem( SID_LEAVE_ALL_GROUPS );
+ }
+ else
+ rSet.Put( SfxBoolItem( SID_LEAVE_ALL_GROUPS, true ) );
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_THESAURUS ) )
+ {
+ if ( !mpDrawView->IsTextEdit() )
+ {
+ rSet.DisableItem( SID_THESAURUS );
+ }
+ else
+ {
+ LanguageType eLang = GetDoc()->GetLanguage( EE_CHAR_LANGUAGE );
+ Reference< XThesaurus > xThesaurus( LinguMgr::GetThesaurus() );
+
+ if (!xThesaurus.is() || eLang == LANGUAGE_NONE || !xThesaurus->hasLocale( LanguageTag::convertToLocale( eLang)) )
+ rSet.DisableItem( SID_THESAURUS );
+ }
+ }
+
+ if ( !mpDrawView->IsTextEdit() )
+ {
+ rSet.DisableItem( SID_THESAURUS );
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_SELECTALL ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_SIZE_ALL ) )
+ {
+ if( pPageView && pPageView->GetObjList()->GetObjCount() == 0 )
+ {
+ // should be disabled if there is no object on the draw area:
+ rSet.DisableItem( SID_SELECTALL );
+ rSet.DisableItem( SID_SIZE_ALL );
+ }
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_CONTEXT ) )
+ rSet.Put( SfxStringItem( SID_CONTEXT, mpDrawView->GetStatusText() ) );
+
+ // clipboard (paste)
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_PASTE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_PASTE_SPECIAL ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_PASTE_UNFORMATTED ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_CLIPBOARD_FORMAT_ITEMS ) )
+ {
+ if ( !mxClipEvtLstnr.is() )
+ {
+ // avoid clipboard initialization for
+ // read-only presentation views (workaround for NT4.0
+ // clipboard prob...)
+ if( dynamic_cast< const PresentationViewShell *>( this ) == nullptr )
+ {
+ // create listener
+ mxClipEvtLstnr = new TransferableClipboardListener( LINK( this, DrawViewShell, ClipboardChanged ) );
+ mxClipEvtLstnr->AddListener( GetActiveWindow() );
+
+ // get initial state
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( GetActiveWindow() ) );
+ mbPastePossible = ( aDataHelper.GetFormatCount() != 0 );
+ mpCurrentClipboardFormats = GetSupportedClipboardFormats( aDataHelper );
+ }
+ else
+ mbPastePossible = false;
+ }
+
+ if( !mbPastePossible )
+ {
+ rSet.DisableItem( SID_PASTE );
+ rSet.DisableItem( SID_PASTE_SPECIAL );
+ rSet.DisableItem( SID_PASTE_UNFORMATTED );
+ rSet.DisableItem( SID_CLIPBOARD_FORMAT_ITEMS );
+ }
+ else if( SfxItemState::DEFAULT == rSet.GetItemState( SID_CLIPBOARD_FORMAT_ITEMS ) )
+ {
+ if (mpCurrentClipboardFormats != nullptr)
+ rSet.Put(*mpCurrentClipboardFormats);
+ }
+ }
+
+ if ( !bConvertToPathPossible )
+ {
+ rSet.DisableItem(SID_CHANGEBEZIER);
+ }
+
+ if (mpDrawView == nullptr)
+ {
+ // The mpDrawView was not NULL but is now.
+ // The reason for this may be that the DrawViewShell has been
+ // destroyed in the meantime.
+ // We can only return immediately and hope that the deleted
+ // DrawViewShell is not called again.
+ DBG_ASSERT(mpDrawView!=nullptr, "Please report this assertion to the Impress team.");
+ return;
+ }
+
+ if( !( mpDrawView->IsConvertToPolyObjPossible() || mpDrawView->IsVectorizeAllowed() ) )
+ rSet.DisableItem(SID_CHANGEPOLYGON);
+
+ if( !( mpDrawView->IsConvertToPolyObjPossible() || mpDrawView->IsConvertToContourPossible() ) )
+ rSet.DisableItem(SID_CONVERT_TO_CONTOUR);
+
+ if ( !mpDrawView->IsConvertTo3DObjPossible() )
+ {
+ rSet.DisableItem(SID_CONVERT_TO_3D);
+ rSet.DisableItem(SID_CONVERT_TO_3D_LATHE);
+ rSet.DisableItem(SID_CONVERT_TO_3D_LATHE_FAST);
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_MANAGE_LINKS ) )
+ {
+ if ( GetDoc()->GetLinkCount() == 0 )
+ {
+ rSet.DisableItem(SID_MANAGE_LINKS);
+ }
+ }
+
+ if (mePageKind == PageKind::Handout)
+ {
+ rSet.DisableItem(SID_PRESENTATION_LAYOUT);
+ rSet.DisableItem(SID_SELECT_BACKGROUND);
+ rSet.DisableItem(SID_SAVE_BACKGROUND);
+ }
+
+ if (mePageKind == PageKind::Notes)
+ {
+ rSet.DisableItem(SID_INSERTPAGE);
+ rSet.DisableItem(SID_RENAMEPAGE);
+ rSet.DisableItem(SID_RENAMEPAGE_QUICK);
+ rSet.DisableItem(SID_DUPLICATE_PAGE);
+ rSet.ClearItem(SID_ANIMATION_OBJECTS);
+ rSet.DisableItem(SID_ANIMATION_OBJECTS);
+ rSet.DisableItem(SID_ANIMATION_EFFECTS);
+ rSet.DisableItem(SID_EXECUTE_ANIMATION_EFFECT);
+
+ if (meEditMode == EditMode::MasterPage)
+ rSet.DisableItem(SID_MODIFYPAGE);
+
+ rSet.DisableItem(SID_SELECT_BACKGROUND);
+ rSet.DisableItem(SID_SAVE_BACKGROUND);
+ rSet.DisableItem(SID_INSERTLAYER);
+ rSet.DisableItem(SID_LAYERMODE);
+ rSet.DisableItem(SID_INSERTFILE);
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ rSet.DisableItem(SID_INSERTPAGE);
+ rSet.DisableItem(SID_DUPLICATE_PAGE);
+ rSet.ClearItem(SID_ANIMATION_OBJECTS);
+ rSet.DisableItem(SID_ANIMATION_OBJECTS);
+ rSet.DisableItem(SID_ANIMATION_EFFECTS);
+ rSet.DisableItem(SID_EXECUTE_ANIMATION_EFFECT);
+ rSet.DisableItem(SID_RENAMEPAGE);
+ rSet.DisableItem(SID_RENAMEPAGE_QUICK);
+ rSet.DisableItem(SID_INSERTLAYER);
+ rSet.DisableItem(SID_MODIFYLAYER);
+ rSet.DisableItem(SID_RENAMELAYER);
+ rSet.DisableItem(SID_LAYERMODE);
+ rSet.DisableItem(SID_INSERTFILE);
+ rSet.DisableItem(SID_PAGEMODE);
+ rSet.DisableItem(SID_SELECT_BACKGROUND);
+ rSet.DisableItem(SID_SAVE_BACKGROUND);
+ }
+ else
+ {
+ if (meEditMode == EditMode::MasterPage)
+ {
+ rSet.DisableItem(SID_INSERTPAGE);
+ rSet.DisableItem(SID_DUPLICATE_PAGE);
+ rSet.DisableItem(SID_MODIFYPAGE);
+ rSet.ClearItem(SID_ANIMATION_OBJECTS);
+ rSet.DisableItem(SID_ANIMATION_OBJECTS);
+ }
+
+ rSet.Put (SfxBoolItem (SID_LAYERMODE, IsLayerModeActive()));
+ }
+
+ if ( ! IsLayerModeActive())
+ {
+ rSet.DisableItem( SID_INSERTLAYER );
+ rSet.DisableItem( SID_MODIFYLAYER );
+ rSet.DisableItem( SID_DELETE_LAYER );
+ rSet.DisableItem( SID_RENAMELAYER );
+ }
+
+ if (meEditMode == EditMode::Page)
+ {
+ /**********************************************************************
+ * page mode
+ **********************************************************************/
+ rSet.Put(SfxBoolItem(SID_PAGEMODE, true));
+ rSet.Put(SfxBoolItem(SID_MASTERPAGE, false));
+ rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false));
+
+ rSet.DisableItem (SID_INSERT_MASTER_PAGE);
+ rSet.DisableItem (SID_DELETE_MASTER_PAGE);
+ rSet.DisableItem (SID_RENAME_MASTER_PAGE);
+ rSet.DisableItem (SID_CLOSE_MASTER_VIEW);
+ }
+ else
+ {
+ rSet.Put(SfxBoolItem(SID_PAGEMODE, false));
+ rSet.Put(SfxBoolItem(SID_MASTERPAGE, true));
+
+ /**********************************************************************
+ * Background page mode
+ **********************************************************************/
+ if (mePageKind == PageKind::Standard)
+ {
+ rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, true));
+ rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false));
+
+ }
+ else if (mePageKind == PageKind::Notes)
+ {
+ rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, true));
+ rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false));
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, true));
+ }
+ }
+
+ // set state of the ruler
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_RULER ) )
+ rSet.Put( SfxBoolItem( SID_RULER, HasRuler() ) );
+
+ // do not delete the last page or a master page
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_DELETE_PAGE )
+ || SfxItemState::DEFAULT == rSet.GetItemState( SID_DELETE_MASTER_PAGE ) )
+ {
+ if (maTabControl->GetPageCount() == 1 ||
+ meEditMode == EditMode::MasterPage ||
+ mePageKind == PageKind::Notes ||
+ mePageKind == PageKind::Handout ||
+ (GetShellType()!=ST_DRAW&&IsLayerModeActive()))
+ {
+ if (rSet.GetItemState(SID_DELETE_PAGE) == SfxItemState::DEFAULT)
+ rSet.DisableItem(SID_DELETE_PAGE);
+ if (rSet.GetItemState(SID_DELETE_MASTER_PAGE)==SfxItemState::DEFAULT)
+ rSet.DisableItem(SID_DELETE_MASTER_PAGE);
+ }
+ }
+
+ // is it allowed to delete the current layer?
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_DELETE_LAYER )
+ || SfxItemState::DEFAULT == rSet.GetItemState( SID_RENAMELAYER ) )
+ {
+ if(GetLayerTabControl()) // #i87182#
+ {
+ sal_uInt16 nCurrentLayer = GetLayerTabControl()->GetCurPageId();
+ const OUString& rName = GetLayerTabControl()->GetLayerName(nCurrentLayer);
+
+ if (!IsLayerModeActive() || LayerTabBar::IsRealNameOfStandardLayer(rName))
+ {
+ rSet.DisableItem(SID_DELETE_LAYER);
+ rSet.DisableItem(SID_RENAMELAYER);
+ }
+ }
+ else
+ {
+ OSL_ENSURE(false, "No LayerTabBar (!)");
+ }
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_CUT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_COPY ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTLINE_BULLET ))
+ {
+ OutlinerView* pOlView = mpDrawView->GetTextEditOutlinerView();
+
+ // special treatment of for SID_OUTLINE_BULLET if objects with different
+ // kinds of NumBullets are marked
+ bool bHasOutliner = false;
+ bool bHasOther = false;
+ for(size_t nNum = 0; nNum < nMarkCount; ++nNum)
+ {
+ SdrObject* pObj = rMarkList.GetMark(nNum)->GetMarkedSdrObj();
+ if( pObj->GetObjInventor() == SdrInventor::Default )
+ {
+ if( pObj->GetObjIdentifier() == SdrObjKind::OutlineText )
+ {
+ bHasOutliner = true;
+ if(bHasOther)
+ break;
+ }
+ else
+ {
+ bHasOther = true;
+ if(bHasOutliner)
+ break;
+ }
+ }
+ }
+
+ if( bHasOther && bHasOutliner )
+ rSet.DisableItem( SID_OUTLINE_BULLET );
+
+ if (pOlView)
+ {
+ if (pOlView->GetSelected().isEmpty() || GetObjectShell()->isContentExtractionLocked())
+ {
+ rSet.DisableItem( SID_CUT );
+ rSet.DisableItem( SID_COPY );
+ }
+ }
+
+ }
+
+ FuBullet::GetSlotState( rSet, this, GetViewFrame() );
+
+ if ( GetDocSh()->IsUIActive() )
+ {
+ rSet.DisableItem( SID_INSERT_OBJECT );
+ rSet.DisableItem( SID_INSERT_FLOATINGFRAME );
+ rSet.DisableItem( SID_INSERT_MATH );
+ rSet.DisableItem( SID_INSERT_DIAGRAM );
+ rSet.DisableItem( SID_ATTR_TABLE );
+ rSet.DisableItem( SID_SIZE_REAL );
+ rSet.DisableItem( SID_SIZE_OPTIMAL );
+ rSet.DisableItem( SID_SIZE_ALL );
+ rSet.DisableItem( SID_SIZE_PAGE_WIDTH );
+ rSet.DisableItem( SID_SIZE_PAGE );
+ rSet.DisableItem( SID_DUPLICATE_PAGE );
+ rSet.DisableItem( SID_ZOOM_TOOLBOX );
+ }
+
+ // Zoom-State
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ZOOM_IN ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_ZOOM_OUT )||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_ZOOM_PANNING ) )
+ {
+ if( GetActiveWindow()->GetZoom() <= GetActiveWindow()->GetMinZoom() || GetDocSh()->IsUIActive() )
+ {
+ rSet.DisableItem( SID_ZOOM_OUT );
+ rSet.DisableItem( SID_ZOOM_PANNING );
+ }
+ if( GetActiveWindow()->GetZoom() >= GetActiveWindow()->GetMaxZoom() || GetDocSh()->IsUIActive() )
+ rSet.DisableItem( SID_ZOOM_IN );
+ }
+
+ if (!mpZoomList->IsNextPossible())
+ {
+ rSet.DisableItem(SID_ZOOM_NEXT);
+ }
+ if (!mpZoomList->IsPreviousPossible())
+ {
+ rSet.DisableItem(SID_ZOOM_PREV);
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_REMOTE_DLG ) )
+ {
+
+ bool bDisableSdremoteForGood = false;
+#ifndef ENABLE_SDREMOTE
+ bDisableSdremoteForGood = true;
+#endif
+ bDisableSdremoteForGood |= ! ( /*officecfg::Office::Common::Misc::ExperimentalMode::get() &&*/
+ officecfg::Office::Impress::Misc::Start::EnableSdremote::get() );
+
+ // This dialog is only useful for TCP/IP remote control
+ // which is unusual, under-tested and a security issue.
+ if ( bDisableSdremoteForGood )
+ {
+ rSet.Put(SfxVisibilityItem(SID_REMOTE_DLG, false));
+ }
+ }
+
+ // EditText active
+ if (GetViewShellBase().GetViewShellManager()->GetShell(ToolbarId::Draw_Text_Toolbox_Sd) != nullptr)
+ {
+ sal_uInt16 nCurrentSId = SID_ATTR_CHAR;
+
+ if(HasCurrentFunction())
+ {
+ nCurrentSId = GetCurrentFunction()->GetSlotID();
+ }
+ if( nCurrentSId != SID_TEXT_FITTOSIZE &&
+ nCurrentSId != SID_TEXT_FITTOSIZE_VERTICAL &&
+ nCurrentSId != SID_ATTR_CHAR_VERTICAL )
+ nCurrentSId = SID_ATTR_CHAR;
+
+ rSet.Put( SfxBoolItem( nCurrentSId, true ) );
+ }
+
+ if ( GetDocSh()->IsReadOnly() )
+ {
+ rSet.DisableItem( SID_AUTOSPELL_CHECK );
+ }
+ else
+ {
+ if (GetDoc()->GetOnlineSpell())
+ {
+ rSet.Put(SfxBoolItem(SID_AUTOSPELL_CHECK, true));
+ }
+ else
+ {
+ rSet.Put(SfxBoolItem(SID_AUTOSPELL_CHECK, false));
+ }
+ }
+
+ SdrPageView* pPV = mpDrawView->GetSdrPageView();
+ OUString aActiveLayer = mpDrawView->GetActiveLayer();
+
+ if ( ( !aActiveLayer.isEmpty() && pPV && ( pPV->IsLayerLocked(aActiveLayer) ||
+ !pPV->IsLayerVisible(aActiveLayer) ) ) ||
+ SD_MOD()->GetWaterCan() )
+ {
+ rSet.DisableItem( SID_PASTE );
+ rSet.DisableItem( SID_PASTE_SPECIAL );
+ rSet.DisableItem( SID_PASTE_UNFORMATTED );
+ rSet.DisableItem( SID_CLIPBOARD_FORMAT_ITEMS );
+
+ rSet.DisableItem( SID_INSERT_FLD_DATE_FIX );
+ rSet.DisableItem( SID_INSERT_FLD_DATE_VAR );
+ rSet.DisableItem( SID_INSERT_FLD_TIME_FIX );
+ rSet.DisableItem( SID_INSERT_FLD_TIME_VAR );
+ rSet.DisableItem( SID_INSERT_FLD_AUTHOR );
+ rSet.DisableItem( SID_INSERT_FLD_PAGE );
+ rSet.DisableItem( SID_INSERT_FLD_PAGE_TITLE );
+ rSet.DisableItem( SID_INSERT_FLD_PAGES );
+ rSet.DisableItem( SID_INSERT_FLD_FILE );
+
+ rSet.DisableItem( SID_INSERT_GRAPHIC );
+ rSet.DisableItem( SID_INSERT_AVMEDIA );
+ rSet.DisableItem( SID_INSERT_DIAGRAM );
+ rSet.DisableItem( SID_INSERT_OBJECT );
+ rSet.DisableItem( SID_INSERT_FLOATINGFRAME );
+
+ rSet.DisableItem( SID_INSERT_MATH );
+ rSet.DisableItem( SID_INSERT_FRAME );
+ rSet.DisableItem( SID_INSERTFILE );
+ rSet.DisableItem( SID_ATTR_TABLE );
+ rSet.DisableItem( SID_COPYOBJECTS );
+
+ rSet.DisableItem( SID_SCAN );
+ rSet.DisableItem( SID_TWAIN_SELECT );
+ rSet.DisableItem( SID_TWAIN_TRANSFER );
+
+// rSet.DisableItem( SID_BEZIER_EDIT );
+ rSet.DisableItem( SID_GLUE_EDITMODE );
+ rSet.DisableItem( SID_OBJECT_ROTATE );
+ rSet.DisableItem( SID_OBJECT_SHEAR );
+ rSet.DisableItem( SID_OBJECT_MIRROR );
+ rSet.DisableItem( SID_OBJECT_CROP );
+ rSet.DisableItem( SID_ATTR_GRAF_CROP );
+ rSet.DisableItem( SID_OBJECT_TRANSPARENCE );
+ rSet.DisableItem( SID_OBJECT_GRADIENT );
+ rSet.DisableItem( SID_OBJECT_CROOK_ROTATE );
+ rSet.DisableItem( SID_OBJECT_CROOK_SLANT );
+ rSet.DisableItem( SID_OBJECT_CROOK_STRETCH );
+
+ // Disable all object-creating tools
+ rSet.ClearItem( SID_ATTR_CHAR );
+ rSet.DisableItem( SID_ATTR_CHAR );
+ rSet.ClearItem( SID_ATTR_CHAR_VERTICAL );
+ rSet.DisableItem( SID_ATTR_CHAR_VERTICAL );
+ rSet.ClearItem(SID_DRAW_LINE);
+ rSet.DisableItem(SID_DRAW_LINE);
+ rSet.ClearItem(SID_DRAW_MEASURELINE);
+ rSet.DisableItem(SID_DRAW_MEASURELINE);
+ rSet.ClearItem(SID_DRAW_XLINE);
+ rSet.DisableItem(SID_DRAW_XLINE);
+ rSet.ClearItem( SID_LINE_ARROW_START );
+ rSet.DisableItem( SID_LINE_ARROW_START );
+ rSet.ClearItem( SID_LINE_ARROW_END );
+ rSet.DisableItem( SID_LINE_ARROW_END );
+ rSet.ClearItem( SID_LINE_ARROWS );
+ rSet.DisableItem( SID_LINE_ARROWS );
+ rSet.ClearItem( SID_LINE_ARROW_CIRCLE );
+ rSet.DisableItem( SID_LINE_ARROW_CIRCLE );
+ rSet.ClearItem( SID_LINE_CIRCLE_ARROW );
+ rSet.DisableItem( SID_LINE_CIRCLE_ARROW );
+ rSet.ClearItem( SID_LINE_ARROW_SQUARE );
+ rSet.DisableItem( SID_LINE_ARROW_SQUARE );
+ rSet.ClearItem( SID_LINE_SQUARE_ARROW );
+ rSet.DisableItem( SID_LINE_SQUARE_ARROW );
+
+ rSet.ClearItem(SID_DRAW_RECT);
+ rSet.DisableItem(SID_DRAW_RECT);
+ rSet.ClearItem(SID_DRAW_RECT_NOFILL);
+ rSet.DisableItem(SID_DRAW_RECT_NOFILL);
+ rSet.ClearItem(SID_DRAW_RECT_ROUND);
+ rSet.DisableItem(SID_DRAW_RECT_ROUND);
+ rSet.ClearItem(SID_DRAW_RECT_ROUND_NOFILL);
+ rSet.DisableItem(SID_DRAW_RECT_ROUND_NOFILL);
+ rSet.ClearItem(SID_DRAW_SQUARE);
+ rSet.DisableItem(SID_DRAW_SQUARE);
+ rSet.ClearItem(SID_DRAW_SQUARE_NOFILL);
+ rSet.DisableItem(SID_DRAW_SQUARE_NOFILL);
+ rSet.ClearItem(SID_DRAW_SQUARE_ROUND);
+ rSet.DisableItem(SID_DRAW_SQUARE_ROUND);
+ rSet.ClearItem(SID_DRAW_SQUARE_ROUND_NOFILL);
+ rSet.DisableItem(SID_DRAW_SQUARE_ROUND_NOFILL);
+ rSet.ClearItem(SID_DRAW_ELLIPSE);
+ rSet.DisableItem(SID_DRAW_ELLIPSE);
+ rSet.ClearItem(SID_DRAW_ELLIPSE_NOFILL);
+ rSet.DisableItem(SID_DRAW_ELLIPSE_NOFILL);
+ rSet.ClearItem(SID_DRAW_CIRCLE);
+ rSet.DisableItem(SID_DRAW_CIRCLE);
+ rSet.ClearItem(SID_DRAW_CIRCLE_NOFILL);
+ rSet.DisableItem(SID_DRAW_CIRCLE_NOFILL);
+ rSet.ClearItem(SID_DRAW_CAPTION);
+ rSet.DisableItem(SID_DRAW_CAPTION);
+ rSet.ClearItem(SID_DRAW_FONTWORK);
+ rSet.DisableItem(SID_DRAW_FONTWORK);
+ rSet.ClearItem(SID_DRAW_FONTWORK_VERTICAL);
+ rSet.DisableItem(SID_DRAW_FONTWORK_VERTICAL);
+ rSet.ClearItem(SID_DRAW_CAPTION_VERTICAL);
+ rSet.DisableItem(SID_DRAW_CAPTION_VERTICAL);
+ rSet.ClearItem(SID_TEXT_FITTOSIZE);
+ rSet.DisableItem(SID_TEXT_FITTOSIZE);
+ rSet.ClearItem(SID_TEXT_FITTOSIZE_VERTICAL);
+ rSet.DisableItem(SID_TEXT_FITTOSIZE_VERTICAL);
+ rSet.ClearItem(SID_TOOL_CONNECTOR);
+ rSet.DisableItem(SID_TOOL_CONNECTOR);
+ rSet.ClearItem(SID_CONNECTOR_ARROW_START);
+ rSet.DisableItem(SID_CONNECTOR_ARROW_START);
+ rSet.ClearItem(SID_CONNECTOR_ARROW_END);
+ rSet.DisableItem(SID_CONNECTOR_ARROW_END);
+ rSet.ClearItem(SID_CONNECTOR_ARROWS);
+ rSet.DisableItem(SID_CONNECTOR_ARROWS);
+ rSet.ClearItem(SID_CONNECTOR_CIRCLE_START);
+ rSet.DisableItem(SID_CONNECTOR_CIRCLE_START);
+ rSet.ClearItem(SID_CONNECTOR_CIRCLE_END);
+ rSet.DisableItem(SID_CONNECTOR_CIRCLE_END);
+ rSet.ClearItem(SID_CONNECTOR_CIRCLES);
+ rSet.DisableItem(SID_CONNECTOR_CIRCLES);
+ rSet.ClearItem(SID_CONNECTOR_LINE);
+ rSet.DisableItem(SID_CONNECTOR_LINE);
+ rSet.ClearItem(SID_CONNECTOR_LINE_ARROW_START);
+ rSet.DisableItem(SID_CONNECTOR_LINE_ARROW_START);
+ rSet.ClearItem(SID_CONNECTOR_LINE_ARROW_END);
+ rSet.DisableItem(SID_CONNECTOR_LINE_ARROW_END);
+ rSet.ClearItem(SID_CONNECTOR_LINE_ARROWS);
+ rSet.DisableItem(SID_CONNECTOR_LINE_ARROWS);
+ rSet.ClearItem(SID_CONNECTOR_LINE_CIRCLE_START);
+ rSet.DisableItem(SID_CONNECTOR_LINE_CIRCLE_START);
+ rSet.ClearItem(SID_CONNECTOR_LINE_CIRCLE_END);
+ rSet.DisableItem(SID_CONNECTOR_LINE_CIRCLE_END);
+ rSet.ClearItem(SID_CONNECTOR_LINE_CIRCLES);
+ rSet.DisableItem(SID_CONNECTOR_LINE_CIRCLES);
+ rSet.ClearItem(SID_CONNECTOR_CURVE);
+ rSet.DisableItem(SID_CONNECTOR_CURVE);
+ rSet.ClearItem(SID_CONNECTOR_CURVE_ARROW_START);
+ rSet.DisableItem(SID_CONNECTOR_CURVE_ARROW_START);
+ rSet.ClearItem(SID_CONNECTOR_CURVE_ARROW_END);
+ rSet.DisableItem(SID_CONNECTOR_CURVE_ARROW_END);
+ rSet.ClearItem(SID_CONNECTOR_CURVE_ARROWS);
+ rSet.DisableItem(SID_CONNECTOR_CURVE_ARROWS);
+ rSet.ClearItem(SID_CONNECTOR_CURVE_CIRCLE_START);
+ rSet.DisableItem(SID_CONNECTOR_CURVE_CIRCLE_START);
+ rSet.ClearItem(SID_CONNECTOR_CURVE_CIRCLE_END);
+ rSet.DisableItem(SID_CONNECTOR_CURVE_CIRCLE_END);
+ rSet.ClearItem(SID_CONNECTOR_CURVE_CIRCLES);
+ rSet.DisableItem(SID_CONNECTOR_CURVE_CIRCLES);
+ rSet.ClearItem(SID_CONNECTOR_LINES);
+ rSet.DisableItem(SID_CONNECTOR_LINES);
+ rSet.ClearItem(SID_CONNECTOR_LINES_ARROW_START);
+ rSet.DisableItem(SID_CONNECTOR_LINES_ARROW_START);
+ rSet.ClearItem(SID_CONNECTOR_LINES_ARROW_END);
+ rSet.DisableItem(SID_CONNECTOR_LINES_ARROW_END);
+ rSet.ClearItem(SID_CONNECTOR_LINES_ARROWS);
+ rSet.DisableItem(SID_CONNECTOR_LINES_ARROWS);
+ rSet.ClearItem(SID_CONNECTOR_LINES_CIRCLE_START);
+ rSet.DisableItem(SID_CONNECTOR_LINES_CIRCLE_START);
+ rSet.ClearItem(SID_CONNECTOR_LINES_CIRCLE_END);
+ rSet.DisableItem(SID_CONNECTOR_LINES_CIRCLE_END);
+ rSet.ClearItem(SID_CONNECTOR_LINES_CIRCLES);
+ rSet.DisableItem(SID_CONNECTOR_LINES_CIRCLES);
+ rSet.ClearItem(SID_DRAW_ARC);
+ rSet.DisableItem(SID_DRAW_ARC);
+ rSet.ClearItem(SID_DRAW_CIRCLEARC);
+ rSet.DisableItem(SID_DRAW_CIRCLEARC);
+ rSet.ClearItem(SID_DRAW_PIE);
+ rSet.DisableItem(SID_DRAW_PIE);
+ rSet.ClearItem(SID_DRAW_PIE_NOFILL);
+ rSet.DisableItem(SID_DRAW_PIE_NOFILL);
+ rSet.ClearItem(SID_DRAW_CIRCLEPIE);
+ rSet.DisableItem(SID_DRAW_CIRCLEPIE);
+ rSet.ClearItem(SID_DRAW_CIRCLEPIE_NOFILL);
+ rSet.DisableItem(SID_DRAW_CIRCLEPIE_NOFILL);
+ rSet.ClearItem(SID_DRAW_ELLIPSECUT);
+ rSet.DisableItem(SID_DRAW_ELLIPSECUT);
+ rSet.ClearItem(SID_DRAW_ELLIPSECUT_NOFILL);
+ rSet.DisableItem(SID_DRAW_ELLIPSECUT_NOFILL);
+ rSet.ClearItem(SID_DRAW_CIRCLECUT);
+ rSet.DisableItem(SID_DRAW_CIRCLECUT);
+ rSet.ClearItem(SID_DRAW_CIRCLECUT_NOFILL);
+ rSet.DisableItem(SID_DRAW_CIRCLECUT_NOFILL);
+ rSet.ClearItem(SID_DRAW_POLYGON);
+ rSet.DisableItem(SID_DRAW_POLYGON);
+ rSet.ClearItem(SID_DRAW_POLYGON_NOFILL);
+ rSet.DisableItem(SID_DRAW_POLYGON_NOFILL);
+ rSet.ClearItem(SID_DRAW_FREELINE);
+ rSet.DisableItem(SID_DRAW_FREELINE);
+ rSet.ClearItem(SID_DRAW_FREELINE_NOFILL);
+ rSet.DisableItem(SID_DRAW_FREELINE_NOFILL);
+ rSet.ClearItem(SID_DRAW_XPOLYGON);
+ rSet.DisableItem(SID_DRAW_XPOLYGON);
+ rSet.ClearItem(SID_DRAW_XPOLYGON_NOFILL);
+ rSet.DisableItem(SID_DRAW_XPOLYGON_NOFILL);
+ rSet.ClearItem(SID_DRAW_BEZIER_FILL);
+ rSet.DisableItem(SID_DRAW_BEZIER_FILL);
+ rSet.ClearItem(SID_DRAW_BEZIER_NOFILL);
+ rSet.DisableItem(SID_DRAW_BEZIER_NOFILL);
+ rSet.ClearItem(SID_3D_CUBE);
+ rSet.DisableItem(SID_3D_CUBE);
+ rSet.ClearItem(SID_3D_SHELL);
+ rSet.DisableItem(SID_3D_SHELL);
+ rSet.ClearItem(SID_3D_SPHERE);
+ rSet.DisableItem(SID_3D_SPHERE);
+ rSet.ClearItem(SID_3D_HALF_SPHERE);
+ rSet.DisableItem(SID_3D_HALF_SPHERE);
+ rSet.ClearItem(SID_3D_CYLINDER);
+ rSet.DisableItem(SID_3D_CYLINDER);
+ rSet.ClearItem(SID_3D_CONE);
+ rSet.DisableItem(SID_3D_CONE);
+ rSet.ClearItem(SID_3D_TORUS);
+ rSet.DisableItem(SID_3D_TORUS);
+ rSet.ClearItem(SID_3D_PYRAMID);
+ rSet.DisableItem(SID_3D_PYRAMID);
+ }
+
+ // are the modules available?
+
+ if (!SvtModuleOptions().IsCalc())
+ {
+ // remove menu entry if module is not available
+ rSet.Put( SfxVisibilityItem( SID_ATTR_TABLE, false ) );
+ }
+ if (!SvtModuleOptions().IsChart())
+ {
+ rSet.DisableItem( SID_INSERT_DIAGRAM );
+ }
+ if (!SvtModuleOptions().IsMath())
+ {
+ rSet.DisableItem( SID_INSERT_MATH );
+ }
+
+ rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if( (xSlideshow.is() && xSlideshow->isRunning() && (xSlideshow->getAnimationMode() != ANIMATIONMODE_PREVIEW) ) || GetDocSh()->IsPreview() )
+ {
+ // Own Slots
+ rSet.DisableItem( SID_PRESENTATION );
+ rSet.DisableItem( SID_ZOOM_IN );
+ rSet.DisableItem( SID_ZOOM_OUT );
+ rSet.DisableItem( SID_ZOOM_PANNING );
+ rSet.DisableItem( SID_ZOOM_MODE );
+ rSet.DisableItem( SID_ZOOM_NEXT );
+ rSet.DisableItem( SID_ZOOM_PREV );
+ rSet.DisableItem( SID_SIZE_REAL );
+ rSet.DisableItem( SID_SIZE_OPTIMAL );
+ rSet.DisableItem( SID_SIZE_ALL );
+ rSet.DisableItem( SID_SIZE_PAGE_WIDTH );
+ rSet.DisableItem( SID_SIZE_PAGE );
+ rSet.DisableItem( SID_INSERTPAGE );
+ rSet.DisableItem( SID_DUPLICATE_PAGE );
+ rSet.DisableItem( SID_MODIFYPAGE );
+ rSet.DisableItem( SID_RENAMEPAGE );
+ rSet.DisableItem( SID_RENAMEPAGE_QUICK );
+ rSet.DisableItem( SID_DELETE_PAGE );
+ rSet.DisableItem( SID_PAGESETUP );
+
+ if( xSlideshow.is() && xSlideshow->isRunning() )
+ {
+ rSet.ClearItem(SID_INSERTFILE);
+ rSet.ClearItem(SID_OBJECT_ROTATE);
+ rSet.ClearItem(SID_FM_CONFIG);
+ rSet.ClearItem(SID_ANIMATION_EFFECTS);
+ rSet.ClearItem(SID_EXECUTE_ANIMATION_EFFECT);
+ rSet.ClearItem(SID_ANIMATION_OBJECTS);
+ rSet.ClearItem(SID_3D_WIN);
+
+ rSet.DisableItem(SID_OBJECT_ALIGN);
+ rSet.DisableItem(SID_ZOOM_TOOLBOX);
+ rSet.DisableItem(SID_OBJECT_CHOOSE_MODE);
+ rSet.DisableItem(SID_DRAWTBX_TEXT);
+ rSet.DisableItem(SID_DRAWTBX_RECTANGLES);
+ rSet.DisableItem(SID_DRAWTBX_ELLIPSES);
+ rSet.DisableItem(SID_DRAWTBX_LINES);
+ rSet.DisableItem(SID_DRAWTBX_ARROWS);
+ rSet.DisableItem(SID_DRAWTBX_3D_OBJECTS);
+ rSet.DisableItem(SID_DRAWTBX_CONNECTORS);
+ rSet.DisableItem(SID_OBJECT_CHOOSE_MODE );
+ rSet.DisableItem(SID_DRAWTBX_INSERT);
+ rSet.DisableItem(SID_INSERTFILE);
+ rSet.DisableItem(SID_OBJECT_ROTATE);
+ rSet.DisableItem(SID_POSITION);
+ rSet.DisableItem(SID_FM_CONFIG);
+ rSet.DisableItem(SID_ANIMATION_EFFECTS);
+ rSet.DisableItem(SID_EXECUTE_ANIMATION_EFFECT);
+ rSet.DisableItem(SID_ANIMATION_OBJECTS);
+ rSet.DisableItem(SID_3D_WIN);
+ }
+ }
+
+ // Menuoption: Change->Convert->To Bitmap, Change->Convert->To Metafile
+ // disable, if there only Bitmap or Metafiles marked
+ // Menuoption: Format->Area, Format->Line
+ // disabled, if the marked objects not able to handle
+ // these attributes
+
+ bool bSingleGraphicSelected = false;
+
+ if (!mpDrawView->AreObjectsMarked())
+ {
+ rSet.DisableItem (SID_CONVERT_TO_METAFILE);
+ rSet.DisableItem (SID_CONVERT_TO_BITMAP);
+ }
+ else
+ {
+ // get marklist
+ SdrMarkList aMarkList = mpDrawView->GetMarkedObjectList();
+
+ bool bFoundBitmap = false;
+ bool bFoundMetafile = false;
+ bool bFoundObjNoArea = false;
+ bool bFoundNoGraphicObj = false;
+ bool bFoundAny = false;
+ bool bFoundTable = false;
+
+// const size_t nMarkCount = aMarkList.GetMarkCount();
+ for (size_t i=0; i < nMarkCount && !bFoundAny; ++i)
+ {
+ SdrObject* pObj = aMarkList.GetMark(i)->GetMarkedSdrObj();
+ SdrObjKind nId = pObj->GetObjIdentifier();
+ SdrInventor nInv = pObj->GetObjInventor();
+
+ if(nInv == SdrInventor::Default)
+ {
+ // 2D objects
+ switch( nId )
+ {
+ case SdrObjKind::PathLine :
+ case SdrObjKind::PolyLine :
+ case SdrObjKind::Line:
+ case SdrObjKind::FreehandLine :
+ case SdrObjKind::Edge:
+ case SdrObjKind::CircleArc :
+ bFoundObjNoArea = true;
+ bFoundNoGraphicObj = true;
+ break;
+ case SdrObjKind::OLE2 :
+ // #i118485# #i118525# Allow Line, Area and Graphic (Metafile, Bitmap)
+ bSingleGraphicSelected = nMarkCount == 1;
+ bFoundBitmap = true;
+ bFoundMetafile = true;
+ break;
+ case SdrObjKind::Graphic :
+ {
+ bSingleGraphicSelected = nMarkCount == 1;
+ const SdrGrafObj* pSdrGrafObj = static_cast< const SdrGrafObj* >(pObj);
+
+ // Current size of the OBJ_GRAF
+ const ::tools::Rectangle aRect = pObj->GetLogicRect();
+ const Size aCurrentSizeofObj = aRect.GetSize();
+
+ // Original size of the OBJ_GRAF
+ const Size aOriginalSizeofObj = pSdrGrafObj->getOriginalSize();
+
+ if(aCurrentSizeofObj == aOriginalSizeofObj )
+ rSet.DisableItem(SID_ORIGINAL_SIZE);
+
+ switch(pSdrGrafObj->GetGraphicType())
+ {
+ case GraphicType::Bitmap :
+ bFoundBitmap = true;
+ if(pSdrGrafObj->isEmbeddedVectorGraphicData())
+ {
+ bFoundMetafile = true;
+ }
+ break;
+ case GraphicType::GdiMetafile :
+ bFoundMetafile = true;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case SdrObjKind::Table:
+ bFoundTable = true;
+ break;
+ default :
+ bFoundAny = true;
+ }
+ }
+ else if(nInv == SdrInventor::E3d)
+ {
+ // 3D objects
+ bFoundAny = true;
+ }
+ }
+
+ if( bFoundTable )
+ rSet.DisableItem( SID_ATTRIBUTES_LINE );
+
+ if (!bFoundAny)
+ {
+ // Disable menuitem for area-dialog
+ if( bFoundObjNoArea ) // #i25616#
+ rSet.DisableItem( SID_ATTRIBUTES_AREA );
+
+ if( bFoundBitmap && !bFoundMetafile && !bFoundNoGraphicObj ) // only Bitmaps marked
+ rSet.DisableItem( SID_CONVERT_TO_BITMAP );
+ else if( !bFoundBitmap && bFoundMetafile && !bFoundNoGraphicObj ) // only Metafiles marked
+ rSet.DisableItem( SID_CONVERT_TO_METAFILE );
+ else if( !bFoundBitmap && !bFoundMetafile && !bFoundNoGraphicObj ) // nothing to do
+ {
+ rSet.DisableItem( SID_CONVERT_TO_BITMAP );
+ rSet.DisableItem( SID_CONVERT_TO_METAFILE );
+ }
+ }
+ }
+
+ if( !bSingleGraphicSelected )
+ {
+ rSet.DisableItem (SID_OBJECT_CROP);
+ rSet.DisableItem (SID_ATTR_GRAF_CROP);
+ }
+
+ // Menuoption: Edit->Hyperlink
+ // Disable, if there is no hyperlink
+ bool bDisableEditHyperlink;
+ if (!moAtContextMenu_DisableEditHyperlink)
+ bDisableEditHyperlink = ShouldDisableEditHyperlink();
+ else
+ {
+ // tdf#137445 if a popup menu was active, use the state as of when the popup was launched and then drop
+ // moAtContextMenu_DisableEditHyperlink
+ bDisableEditHyperlink = *moAtContextMenu_DisableEditHyperlink;
+ moAtContextMenu_DisableEditHyperlink.reset();
+ }
+
+ //highlight selected custom shape
+ {
+ if(HasCurrentFunction())
+ {
+ rtl::Reference< FuPoor > xFunc( GetCurrentFunction() );
+ FuConstructCustomShape* pShapeFunc = dynamic_cast< FuConstructCustomShape* >( xFunc.get() );
+
+ static const sal_uInt16 nCSTbArray[] = { SID_DRAWTBX_CS_BASIC, SID_DRAWTBX_CS_SYMBOL,
+ SID_DRAWTBX_CS_ARROW, SID_DRAWTBX_CS_FLOWCHART,
+ SID_DRAWTBX_CS_CALLOUT, SID_DRAWTBX_CS_STAR };
+
+ const sal_uInt16 nCurrentSId = GetCurrentFunction()->GetSlotID();
+ for (sal_uInt16 i : nCSTbArray)
+ {
+ rSet.ClearItem( i ); // Why is this necessary?
+ rSet.Put( SfxStringItem( i, nCurrentSId == i && pShapeFunc
+ ? pShapeFunc->GetShapeType() : OUString() ) );
+ }
+ }
+ }
+
+ if ( bDisableEditHyperlink || GetDocSh()->IsReadOnly() )
+ rSet.DisableItem( SID_EDIT_HYPERLINK );
+
+ if ( bDisableEditHyperlink )
+ {
+ rSet.DisableItem( SID_OPEN_HYPERLINK );
+ rSet.DisableItem( SID_COPY_HYPERLINK_LOCATION );
+ }
+
+ //fdo#78151 enable show next level/hide last level if editing a master page
+ //PresObjKind::Outline object and the current selection allow that to happen
+ {
+ bool bDisableShowNextLevel = true;
+ bool bDisableHideLastLevel = true;
+
+ ESelection aSel;
+ ::Outliner* pOL = GetOutlinerForMasterPageOutlineTextObj(aSel);
+ if (pOL)
+ {
+ //and are on the last paragraph
+ aSel.Adjust();
+ if (aSel.nEndPara == pOL->GetParagraphCount() - 1)
+ {
+ sal_uInt16 nDepth = pOL->GetDepth(aSel.nEndPara);
+ if (nDepth != sal_uInt16(-1))
+ {
+ //there exists another numbering level that
+ //is currently hidden
+ if (nDepth < 8)
+ bDisableShowNextLevel = false;
+ //there exists a previous numbering level
+ if (nDepth > 0)
+ bDisableHideLastLevel = false;
+ }
+ }
+ }
+
+ if (bDisableShowNextLevel)
+ rSet.DisableItem(SID_SHOW_NEXT_LEVEL);
+
+ if (bDisableHideLastLevel)
+ rSet.DisableItem(SID_HIDE_LAST_LEVEL);
+ }
+
+#if defined(_WIN32) || defined UNX
+ if( !mxScannerManager.is() )
+ {
+ rSet.DisableItem( SID_TWAIN_SELECT );
+ rSet.DisableItem( SID_TWAIN_TRANSFER );
+ }
+#endif
+
+ // Set the state of two entries in the 'Slide' context sub-menu
+ // concerning the visibility of master page background and master page
+ // shapes.
+ if (rSet.GetItemState(SID_DISPLAY_MASTER_BACKGROUND) == SfxItemState::DEFAULT
+ || rSet.GetItemState(SID_DISPLAY_MASTER_OBJECTS) == SfxItemState::DEFAULT)
+ {
+ SdPage* pPage = GetActualPage();
+ if (pPage != nullptr && GetDoc() != nullptr)
+ {
+ SdrLayerIDSet aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers();
+ SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin();
+ SdrLayerID aBackgroundId = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID aObjectId = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ rSet.Put(SfxBoolItem(SID_DISPLAY_MASTER_BACKGROUND,
+ aVisibleLayers.IsSet(aBackgroundId)));
+ rSet.Put(SfxBoolItem(SID_DISPLAY_MASTER_OBJECTS,
+ aVisibleLayers.IsSet(aObjectId)));
+ }
+ }
+
+ if (rSet.GetItemState(SID_SAVE_BACKGROUND) == SfxItemState::DEFAULT)
+ {
+ bool bDisableSaveBackground = true;
+ SdPage* pPage = GetActualPage();
+ if (pPage != nullptr && GetDoc() != nullptr)
+ {
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aMergedAttr(GetDoc()->GetPool());
+ SdStyleSheet* pStyleSheet = pPage->getPresentationStyle(HID_PSEUDOSHEET_BACKGROUND);
+ MergePageBackgroundFilling(pPage, pStyleSheet, meEditMode == EditMode::MasterPage, aMergedAttr);
+ if (drawing::FillStyle_BITMAP == aMergedAttr.Get(XATTR_FILLSTYLE).GetValue())
+ {
+ bDisableSaveBackground = false;
+ }
+ }
+ if (bDisableSaveBackground)
+ rSet.DisableItem(SID_SAVE_BACKGROUND);
+ }
+
+ if (GetObjectShell()->isExportLocked())
+ rSet.DisableItem(SID_PRESENTATION_MINIMIZER);
+
+ if (rSet.GetItemState(SID_INSERT_SIGNATURELINE) == SfxItemState::DEFAULT)
+ {
+ if (!GetObjectShell()->IsSignPDF())
+ {
+ // Currently SID_INSERT_SIGNATURELINE assumes a PDF that was opened for signing, disable
+ // it otherwise.
+ rSet.DisableItem(SID_INSERT_SIGNATURELINE);
+ }
+ }
+
+ GetModeSwitchingMenuState (rSet);
+}
+
+void DrawViewShell::GetModeSwitchingMenuState (SfxItemSet &rSet)
+{
+ //DrawView
+ rSet.Put(SfxBoolItem(SID_SLIDE_SORTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_OUTLINE_MODE, false));
+ rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, false));
+ if (mePageKind == PageKind::Notes)
+ {
+ rSet.Put(SfxBoolItem(SID_DRAWINGMODE, false));
+ rSet.Put(SfxBoolItem(SID_NOTES_MODE, true));
+ rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false));
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ rSet.Put(SfxBoolItem(SID_DRAWINGMODE, false));
+ rSet.Put(SfxBoolItem(SID_NOTES_MODE, false));
+ rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, true));
+ }
+ else
+ {
+ rSet.Put(SfxBoolItem(SID_DRAWINGMODE, true));
+ rSet.Put(SfxBoolItem(SID_NOTES_MODE, false));
+ rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false));
+ }
+
+ // Removed [GetDocSh()->GetCurrentFunction() ||] from the following
+ // clause because the current function of the docshell can only be
+ // search and replace or spell checking and in that case switching the
+ // view mode is allowed.
+ const bool bIsRunning = SlideShow::IsRunning(GetViewShellBase());
+
+ if (GetViewFrame()->GetFrame().IsInPlace() || bIsRunning)
+ {
+ if ( !GetViewFrame()->GetFrame().IsInPlace() )
+ {
+ rSet.ClearItem( SID_DRAWINGMODE );
+ rSet.DisableItem( SID_DRAWINGMODE );
+ }
+
+ rSet.ClearItem( SID_NOTES_MODE );
+ rSet.DisableItem( SID_NOTES_MODE );
+
+ rSet.ClearItem( SID_HANDOUT_MASTER_MODE );
+ rSet.DisableItem( SID_HANDOUT_MASTER_MODE );
+
+ rSet.ClearItem( SID_OUTLINE_MODE );
+ rSet.DisableItem( SID_OUTLINE_MODE );
+
+ rSet.ClearItem( SID_SLIDE_MASTER_MODE );
+ rSet.DisableItem( SID_SLIDE_MASTER_MODE );
+
+ rSet.ClearItem( SID_NOTES_MASTER_MODE );
+ rSet.DisableItem( SID_NOTES_MASTER_MODE );
+
+ rSet.ClearItem( SID_SLIDE_SORTER_MODE );
+ rSet.DisableItem( SID_SLIDE_SORTER_MODE );
+ }
+
+ if (GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED)
+ {
+ // Outplace-Edit: do not allow switch
+ rSet.ClearItem( SID_OUTLINE_MODE );
+ rSet.DisableItem( SID_OUTLINE_MODE );
+
+ rSet.ClearItem( SID_SLIDE_SORTER_MODE );
+ rSet.DisableItem( SID_SLIDE_SORTER_MODE );
+
+ rSet.ClearItem( SID_NOTES_MODE );
+ rSet.DisableItem( SID_NOTES_MODE );
+
+ rSet.ClearItem( SID_HANDOUT_MASTER_MODE );
+ rSet.DisableItem( SID_HANDOUT_MASTER_MODE );
+
+ rSet.ClearItem( SID_SLIDE_MASTER_MODE );
+ rSet.DisableItem( SID_SLIDE_MASTER_MODE );
+
+ rSet.ClearItem( SID_NOTES_MASTER_MODE );
+ rSet.DisableItem( SID_NOTES_MASTER_MODE );
+ }
+
+ svx::ExtrusionBar::getState( mpDrawView.get(), rSet );
+ svx::FontworkBar::getState( mpDrawView.get(), rSet );
+}
+
+void DrawViewShell::GetPageProperties( SfxItemSet &rSet )
+{
+ SdPage *pPage = getCurrentPage();
+
+ if (pPage == nullptr || GetDoc() == nullptr)
+ return;
+
+ SvxPageItem aPageItem(SID_ATTR_PAGE);
+ aPageItem.SetLandscape( pPage->GetOrientation() == Orientation::Landscape );
+
+ rSet.Put(SvxSizeItem( SID_ATTR_PAGE_SIZE, pPage->GetSize() ));
+ rSet.Put(aPageItem);
+
+ const SfxItemSet &rPageAttr = pPage->getSdrPageProperties().GetItemSet();
+ const XFillStyleItem* pFillStyle = rPageAttr.GetItem(XATTR_FILLSTYLE);
+ if (!pFillStyle)
+ return;
+
+ drawing::FillStyle eXFS = pFillStyle->GetValue();
+ XFillStyleItem aFillStyleItem( eXFS );
+ aFillStyleItem.SetWhich( SID_ATTR_PAGE_FILLSTYLE );
+ rSet.Put(aFillStyleItem);
+
+ switch (eXFS)
+ {
+ case drawing::FillStyle_SOLID:
+ if (const XFillColorItem* pColorItem = rPageAttr.GetItem(XATTR_FILLCOLOR))
+ {
+ Color aColor = pColorItem->GetColorValue();
+ XFillColorItem aFillColorItem( OUString(), aColor );
+ aFillColorItem.SetWhich( SID_ATTR_PAGE_COLOR );
+ rSet.Put( aFillColorItem );
+ }
+ break;
+
+ case drawing::FillStyle_GRADIENT:
+ {
+ const XFillGradientItem *pGradient = rPageAttr.GetItem( XATTR_FILLGRADIENT );
+ XFillGradientItem aFillGradientItem( pGradient->GetName(), pGradient->GetGradientValue(), SID_ATTR_PAGE_GRADIENT );
+ rSet.Put( aFillGradientItem );
+ }
+ break;
+
+ case drawing::FillStyle_HATCH:
+ {
+ const XFillHatchItem *pFillHatchItem( rPageAttr.GetItem( XATTR_FILLHATCH ) );
+ XFillHatchItem aFillHatchItem( pFillHatchItem->GetName(), pFillHatchItem->GetHatchValue());
+ aFillHatchItem.SetWhich( SID_ATTR_PAGE_HATCH );
+ rSet.Put( aFillHatchItem );
+ }
+ break;
+
+ case drawing::FillStyle_BITMAP:
+ {
+ const XFillBitmapItem *pFillBitmapItem = rPageAttr.GetItem( XATTR_FILLBITMAP );
+ XFillBitmapItem aFillBitmapItem( pFillBitmapItem->GetName(), pFillBitmapItem->GetGraphicObject() );
+ aFillBitmapItem.SetWhich( SID_ATTR_PAGE_BITMAP );
+ rSet.Put( aFillBitmapItem );
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void DrawViewShell::SetPageProperties (SfxRequest& rReq)
+{
+ SdPage *pPage = getCurrentPage();
+ if (!pPage)
+ return;
+ sal_uInt16 nSlotId = rReq.GetSlot();
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ if (!pArgs)
+ return;
+
+ if ( ( nSlotId >= SID_ATTR_PAGE_COLOR ) && ( nSlotId <= SID_ATTR_PAGE_FILLSTYLE ) )
+ {
+ SdrPageProperties& rPageProperties = pPage->getSdrPageProperties();
+ const SfxItemSet &aPageItemSet = rPageProperties.GetItemSet();
+ SfxItemSet aTempSet = aPageItemSet.CloneAsValue(false, &mpDrawView->GetModel()->GetItemPool());
+ const SfxPoolItem* pItem = nullptr;
+
+ rPageProperties.ClearItem(XATTR_FILLSTYLE);
+ rPageProperties.ClearItem(XATTR_FILLGRADIENT);
+ rPageProperties.ClearItem(XATTR_FILLHATCH);
+ rPageProperties.ClearItem(XATTR_FILLBITMAP);
+
+ switch (nSlotId)
+ {
+ case SID_ATTR_PAGE_FILLSTYLE:
+ {
+ XFillStyleItem aFSItem( pArgs->Get( XATTR_FILLSTYLE ) );
+ drawing::FillStyle eXFS = aFSItem.GetValue();
+
+ if ( eXFS == drawing::FillStyle_NONE )
+ rPageProperties.PutItem( XFillStyleItem( eXFS ) );
+ }
+ break;
+
+ case SID_ATTR_PAGE_COLOR:
+ {
+ if (SfxItemState::SET == pArgs->GetItemState(SID_ATTR_COLOR_STR, false, &pItem))
+ {
+ Color aColor;
+ OUString sColor;
+
+ sColor = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ if (sColor == "transparent")
+ aColor = COL_TRANSPARENT;
+ else
+ aColor = Color(ColorTransparency, sColor.toInt32(16));
+
+ XFillColorItem aColorItem(OUString(), aColor);
+ rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ rPageProperties.PutItem( aColorItem );
+ }
+ else
+ {
+ XFillColorItem aColorItem( pArgs->Get( XATTR_FILLCOLOR ) );
+ rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ rPageProperties.PutItem( aColorItem );
+ }
+ }
+ break;
+
+ case SID_ATTR_PAGE_GRADIENT:
+ {
+ if (SfxItemState::SET == pArgs->GetItemState(SID_FILL_GRADIENT_JSON, false, &pItem))
+ {
+ const SfxStringItem* pJSON = static_cast<const SfxStringItem*>(pItem);
+ XFillGradientItem aGradientItem( XGradient::fromJSON(pJSON->GetValue()) );
+
+ // MigrateItemSet guarantees unique gradient names
+ SfxItemSetFixed<XATTR_FILLGRADIENT, XATTR_FILLGRADIENT> aMigrateSet( mpDrawView->GetModel()->GetItemPool() );
+ aMigrateSet.Put( aGradientItem );
+ SdrModel::MigrateItemSet( &aMigrateSet, &aTempSet, mpDrawView->GetModel() );
+
+ rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_GRADIENT ) );
+ rPageProperties.PutItemSet( aTempSet );
+ }
+ else
+ {
+ XFillGradientItem aGradientItem( pArgs->Get( XATTR_FILLGRADIENT ) );
+
+ // MigrateItemSet guarantees unique gradient names
+ SfxItemSetFixed<XATTR_FILLGRADIENT, XATTR_FILLGRADIENT> aMigrateSet( mpDrawView->GetModel()->GetItemPool() );
+ aMigrateSet.Put( aGradientItem );
+ SdrModel::MigrateItemSet( &aMigrateSet, &aTempSet, mpDrawView->GetModel() );
+
+ rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_GRADIENT ) );
+ rPageProperties.PutItemSet( aTempSet );
+ }
+ }
+ break;
+
+ case SID_ATTR_PAGE_HATCH:
+ {
+ XFillHatchItem aHatchItem( pArgs->Get( XATTR_FILLHATCH ) );
+ rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_HATCH ) );
+ rPageProperties.PutItem( aHatchItem );
+ }
+ break;
+
+ case SID_ATTR_PAGE_BITMAP:
+ {
+ XFillBitmapItem aBitmapItem( pArgs->Get( XATTR_FILLBITMAP ) );
+ rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_BITMAP ) );
+ rPageProperties.PutItem( aBitmapItem );
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ rReq.Done();
+ }
+ else
+ {
+ PageKind ePageKind = GetPageKind();
+ const SfxPoolItem* pPoolItem = nullptr;
+ Size aNewSize(pPage->GetSize());
+ sal_Int32 nLeft = -1, nRight = -1, nUpper = -1, nLower = -1;
+ bool bScaleAll = true;
+ Orientation eOrientation = pPage->GetOrientation();
+ SdPage* pMasterPage = pPage->IsMasterPage() ? pPage : &static_cast<SdPage&>(pPage->TRG_GetMasterPage());
+ bool bFullSize = pMasterPage->IsBackgroundFullSize();
+ sal_uInt16 nPaperBin = pPage->GetPaperBin();
+
+ switch (nSlotId)
+ {
+ case SID_ATTR_PAGE_LRSPACE:
+ if( pArgs->GetItemState(SID_ATTR_PAGE_LRSPACE,
+ true,&pPoolItem) == SfxItemState::SET )
+ {
+ nLeft = static_cast<const SvxLongLRSpaceItem*>(pPoolItem)->GetLeft();
+ nRight = static_cast<const SvxLongLRSpaceItem*>(pPoolItem)->GetRight();
+ if (nLeft != -1)
+ {
+ nUpper = pPage->GetUpperBorder();
+ nLower = pPage->GetLowerBorder();
+ }
+ SetPageSizeAndBorder(ePageKind, aNewSize, nLeft, nRight, nUpper, nLower, bScaleAll, eOrientation, nPaperBin, bFullSize );
+ }
+ break;
+
+ case SID_ATTR_PAGE_ULSPACE:
+ if( pArgs->GetItemState(SID_ATTR_PAGE_ULSPACE,
+ true,&pPoolItem) == SfxItemState::SET )
+ {
+ nUpper = static_cast<const SvxLongULSpaceItem*>(pPoolItem)->GetUpper();
+ nLower = static_cast<const SvxLongULSpaceItem*>(pPoolItem)->GetLower();
+ if (nUpper != -1)
+ {
+ nLeft = pPage->GetLeftBorder();
+ nRight = pPage->GetRightBorder();
+ }
+ SetPageSizeAndBorder(ePageKind, aNewSize, nLeft, nRight, nUpper, nLower, bScaleAll, eOrientation, nPaperBin, bFullSize );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void DrawViewShell::GetState (SfxItemSet& rSet)
+{
+ // Iterate over all requested items in the set.
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ switch (nWhich)
+ {
+ case SID_SEARCH_ITEM:
+ case SID_SEARCH_OPTIONS:
+ // Forward this request to the common (old) code of the
+ // document shell.
+ GetDocSh()->GetState (rSet);
+ break;
+ default:
+ SAL_WARN("sd", "DrawViewShell::GetState(): can not handle which id " << nWhich);
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void DrawViewShell::Execute (SfxRequest& rReq)
+{
+ if(SlideShow::IsRunning(GetViewShellBase()))
+ {
+ // Do not execute anything during a native slide show.
+ return;
+ }
+
+ switch (rReq.GetSlot())
+ {
+ case SID_SEARCH_ITEM:
+ // Forward this request to the common (old) code of the
+ // document shell.
+ GetDocSh()->Execute (rReq);
+ break;
+
+ case SID_SPELL_DIALOG:
+ {
+ SfxViewFrame* pViewFrame = GetViewFrame();
+ if (rReq.GetArgs() != nullptr)
+ pViewFrame->SetChildWindow (SID_SPELL_DIALOG,
+ static_cast<const SfxBoolItem&>(rReq.GetArgs()->
+ Get(SID_SPELL_DIALOG)).GetValue());
+ else
+ pViewFrame->ToggleChildWindow(SID_SPELL_DIALOG);
+
+ pViewFrame->GetBindings().Invalidate(SID_SPELL_DIALOG);
+ rReq.Ignore ();
+ }
+ break;
+
+ default:
+ SAL_WARN("sd", "DrawViewShell::Execute(): can not handle slot " << rReq.GetSlot());
+ break;
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviews8.cxx b/sd/source/ui/view/drviews8.cxx
new file mode 100644
index 000000000..e5ae5cd97
--- /dev/null
+++ b/sd/source/ui/view/drviews8.cxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawViewShell.hxx>
+
+#include <com/sun/star/scanner/XScannerManager2.hpp>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdpagv.hxx>
+
+#include <Window.hxx>
+#include <drawview.hxx>
+#include <tools/helpers.hxx>
+#include <vcl/svapp.hxx>
+
+namespace sd {
+
+void DrawViewShell::ScannerEvent()
+{
+ if( mxScannerManager.is() )
+ {
+ const css::scanner::ScannerContext aContext( mxScannerManager->getAvailableScanners().getConstArray()[ 0 ] );
+ const css::scanner::ScanError eError = mxScannerManager->getError( aContext );
+
+ if( css::scanner::ScanError_ScanErrorNone == eError )
+ {
+ const css::uno::Reference< css::awt::XBitmap > xBitmap( mxScannerManager->getBitmap( aContext ) );
+
+ if( xBitmap.is() )
+ {
+ const BitmapEx aScanBmp( VCLUnoHelper::GetBitmap( xBitmap ) );
+
+ if( !aScanBmp.IsEmpty() )
+ {
+ const SolarMutexGuard aGuard;
+ SdrPage* pPage = mpDrawView->GetSdrPageView()->GetPage();
+ Size aBmpSize( aScanBmp.GetPrefSize() ), aPageSize( pPage->GetSize() );
+ const MapMode aMap100( MapUnit::Map100thMM );
+
+ if( !aBmpSize.Width() || !aBmpSize.Height() )
+ aBmpSize = aScanBmp.GetSizePixel();
+
+ if( aScanBmp.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
+ aBmpSize = GetActiveWindow()->PixelToLogic( aBmpSize, aMap100 );
+ else
+ aBmpSize = OutputDevice::LogicToLogic( aBmpSize, aScanBmp.GetPrefMapMode(), aMap100 );
+
+ aPageSize.AdjustWidth( -(pPage->GetLeftBorder() + pPage->GetRightBorder()) );
+ aPageSize.AdjustHeight( -(pPage->GetUpperBorder() + pPage->GetLowerBorder()) );
+
+ if( ( ( aBmpSize.Height() > aPageSize.Height() ) || ( aBmpSize.Width() > aPageSize.Width() ) ) && aBmpSize.Height() && aPageSize.Height() )
+ {
+ double fGrfWH = static_cast<double>(aBmpSize.Width()) / aBmpSize.Height();
+ double fWinWH = static_cast<double>(aPageSize.Width()) / aPageSize.Height();
+
+ if( fGrfWH < fWinWH )
+ {
+ aBmpSize.setWidth( FRound( aPageSize.Height() * fGrfWH ) );
+ aBmpSize.setHeight( aPageSize.Height() );
+ }
+ else if( fGrfWH > 0.F )
+ {
+ aBmpSize.setWidth( aPageSize.Width() );
+ aBmpSize.setHeight( FRound( aPageSize.Width() / fGrfWH ) );
+ }
+ }
+
+ Point aPnt ( ( aPageSize.Width() - aBmpSize.Width() ) >> 1, ( aPageSize.Height() - aBmpSize.Height() ) >> 1 );
+ aPnt += Point( pPage->GetLeftBorder(), pPage->GetUpperBorder() );
+ ::tools::Rectangle aRect( aPnt, aBmpSize );
+ bool bInsertNewObject = true;
+
+ if( GetView()->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ if( auto pGrafObj = dynamic_cast< SdrGrafObj *>( pObj ) )
+ {
+ if( pGrafObj->IsEmptyPresObj() )
+ {
+ bInsertNewObject = false;
+ pGrafObj->SetEmptyPresObj(false);
+ pGrafObj->SetOutlinerParaObject(std::nullopt);
+ pGrafObj->SetGraphic( Graphic( aScanBmp ) );
+ }
+ }
+ }
+ }
+
+ if( bInsertNewObject )
+ {
+ auto pGrafObj = new SdrGrafObj(
+ GetView()->getSdrModelFromSdrView(),
+ Graphic(aScanBmp),
+ aRect);
+ SdrPageView* pPV = GetView()->GetSdrPageView();
+ GetView()->InsertObjectAtView( pGrafObj, *pPV, SdrInsertFlags::SETDEFLAYER );
+ }
+ }
+ }
+ }
+ }
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_TWAIN_SELECT );
+ rBindings.Invalidate( SID_TWAIN_TRANSFER );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviews9.cxx b/sd/source/ui/view/drviews9.cxx
new file mode 100644
index 000000000..f80419587
--- /dev/null
+++ b/sd/source/ui/view/drviews9.cxx
@@ -0,0 +1,886 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <DrawViewShell.hxx>
+#include <svx/xgrad.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xflclit.hxx>
+#include <sfx2/bindings.hxx>
+
+#include <sfx2/dispatch.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/request.hxx>
+#include <svl/stritem.hxx>
+#include <svx/svxids.hrc>
+#include <svx/xtable.hxx>
+#include <vcl/graph.hxx>
+#include <svx/svdograf.hxx>
+#include <svl/whiter.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/sberrors.hxx>
+
+#include <sfx2/viewfrm.hxx>
+
+#include <app.hrc>
+#include <strings.hrc>
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <drawview.hxx>
+#include <DrawDocShell.hxx>
+#include <sdresid.hxx>
+
+#include <svx/galleryitem.hxx>
+#include <com/sun/star/gallery/GalleryItemType.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <memory>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+void DrawViewShell::ExecGallery(SfxRequest const & rReq)
+{
+ // nothing is executed during a slide show!
+ if(HasCurrentFunction(SID_PRESENTATION))
+ return;
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ const SvxGalleryItem* pGalleryItem = SfxItemSet::GetItem<SvxGalleryItem>(pArgs, SID_GALLERY_FORMATS, false);
+ if ( !pGalleryItem )
+ return;
+
+ GetDocSh()->SetWaitCursor( true );
+
+ sal_Int8 nType( pGalleryItem->GetType() );
+ // insert graphic
+ if (nType == css::gallery::GalleryItemType::GRAPHIC)
+ {
+ Graphic aGraphic( pGalleryItem->GetGraphic() );
+
+ // reduce size if necessary
+ ScopedVclPtrInstance< Window > aWindow(GetActiveWindow());
+ aWindow->SetMapMode(aGraphic.GetPrefMapMode());
+ Size aSizePix = aWindow->LogicToPixel(aGraphic.GetPrefSize());
+ aWindow->SetMapMode( MapMode(MapUnit::Map100thMM) );
+ Size aSize = aWindow->PixelToLogic(aSizePix);
+
+ // constrain size to page size if necessary
+ SdrPage* pPage = mpDrawView->GetSdrPageView()->GetPage();
+ Size aPageSize = pPage->GetSize();
+ aPageSize.AdjustWidth( -(pPage->GetLeftBorder() + pPage->GetRightBorder()) );
+ aPageSize.AdjustHeight( -(pPage->GetUpperBorder() + pPage->GetLowerBorder()) );
+
+ // If the image is too large we make it fit into the page
+ if ( ( ( aSize.Height() > aPageSize.Height() ) || ( aSize.Width() > aPageSize.Width() ) ) &&
+ aSize.Height() && aPageSize.Height() )
+ {
+ float fGrfWH = static_cast<float>(aSize.Width()) /
+ static_cast<float>(aSize.Height());
+ float fWinWH = static_cast<float>(aPageSize.Width()) /
+ static_cast<float>(aPageSize.Height());
+
+ // constrain size to page size if necessary
+ if ((fGrfWH != 0.F) && (fGrfWH < fWinWH))
+ {
+ aSize.setWidth( static_cast<::tools::Long>(aPageSize.Height() * fGrfWH) );
+ aSize.setHeight( aPageSize.Height() );
+ }
+ else
+ {
+ aSize.setWidth( aPageSize.Width() );
+ aSize.setHeight( static_cast<::tools::Long>(aPageSize.Width() / fGrfWH) );
+ }
+ }
+
+ // set output rectangle for graphic
+ Point aPnt ((aPageSize.Width() - aSize.Width()) / 2,
+ (aPageSize.Height() - aSize.Height()) / 2);
+ aPnt += Point(pPage->GetLeftBorder(), pPage->GetUpperBorder());
+ ::tools::Rectangle aRect (aPnt, aSize);
+
+ SdrGrafObj* pGrafObj = nullptr;
+
+ bool bInsertNewObject = true;
+
+ if ( mpDrawView->AreObjectsMarked() )
+ {
+ // is there an empty graphic object?
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ if (pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::Graphic)
+ {
+ pGrafObj = static_cast<SdrGrafObj*>(pObj);
+
+ if( pGrafObj->IsEmptyPresObj() )
+ {
+ // the empty graphic object gets a new graphic
+ bInsertNewObject = false;
+
+ SdrGrafObj* pNewGrafObj(pGrafObj->CloneSdrObject(pGrafObj->getSdrModelFromSdrObject()));
+ pNewGrafObj->SetEmptyPresObj(false);
+ pNewGrafObj->SetOutlinerParaObject(std::nullopt);
+ pNewGrafObj->SetGraphic(aGraphic);
+
+ OUString aStr = mpDrawView->GetDescriptionOfMarkedObjects() +
+ " " + SdResId(STR_UNDO_REPLACE);
+ mpDrawView->BegUndo(aStr);
+ SdrPageView* pPV = mpDrawView->GetSdrPageView();
+ mpDrawView->ReplaceObjectAtView(pGrafObj, *pPV, pNewGrafObj);
+ mpDrawView->EndUndo();
+ }
+ }
+ }
+ }
+
+ if( bInsertNewObject )
+ {
+ pGrafObj = new SdrGrafObj(
+ GetView()->getSdrModelFromSdrView(),
+ aGraphic,
+ aRect);
+ SdrPageView* pPV = mpDrawView->GetSdrPageView();
+ mpDrawView->InsertObjectAtView(pGrafObj, *pPV, SdrInsertFlags::SETDEFLAYER);
+ }
+ }
+ // insert sound
+ else if( nType == css::gallery::GalleryItemType::MEDIA )
+ {
+ const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, pGalleryItem->GetURL() );
+ GetViewFrame()->GetDispatcher()->ExecuteList(SID_INSERT_AVMEDIA,
+ SfxCallMode::SYNCHRON, { &aMediaURLItem });
+ }
+
+ GetDocSh()->SetWaitCursor( false );
+}
+
+/**
+ * Edit macros for attribute configuration
+ */
+
+/* the work flow to adjust the attributes is nearly everywhere the same
+ 1. read existing attributes
+ 2. read parameter from the basic-set
+ 3. delete selected item from the attribute-set
+ 4. create new attribute-item
+ 5. insert item into set */
+void DrawViewShell::AttrExec (SfxRequest &rReq)
+{
+ // nothing is executed during a slide show!
+ if(HasCurrentFunction(SID_PRESENTATION))
+ return;
+
+ CheckLineTo (rReq);
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ SfxItemSet aAttr( GetDoc()->GetPool() );
+
+ GetView()->GetAttributes( aAttr );
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ switch (rReq.GetSlot ())
+ {
+ // set new fill-style
+ case SID_SETFILLSTYLE :
+ if (pArgs && pArgs->Count () == 1)
+ {
+ const SfxUInt32Item* pFillStyle = rReq.GetArg<SfxUInt32Item>(ID_VAL_STYLE);
+ if (CHECK_RANGE (drawing::FillStyle_NONE, static_cast<drawing::FillStyle>(pFillStyle->GetValue ()), drawing::FillStyle_BITMAP))
+ {
+ aAttr.ClearItem (XATTR_FILLSTYLE);
+ XFillStyleItem aStyleItem(static_cast<drawing::FillStyle>(pFillStyle->GetValue ()));
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put (aStyleItem);
+ rBindings.Invalidate (SID_ATTR_FILL_STYLE);
+ rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE);
+ }
+#if HAVE_FEATURE_SCRIPTING
+ else StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE);
+#endif
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ // determine new line style
+ case SID_SETLINESTYLE :
+ if (pArgs && pArgs->Count () == 1)
+ {
+ const SfxUInt32Item* pLineStyle = rReq.GetArg<SfxUInt32Item>(ID_VAL_STYLE);
+ if (CHECK_RANGE (sal_Int32(drawing::LineStyle_NONE), static_cast<sal_Int32>(pLineStyle->GetValue()), sal_Int32(drawing::LineStyle_DASH)))
+ {
+ aAttr.ClearItem (XATTR_LINESTYLE);
+ XLineStyleItem aStyleItem(static_cast<drawing::LineStyle>(pLineStyle->GetValue()));
+ aStyleItem.SetWhich(XATTR_LINESTYLE);
+ aAttr.Put(aStyleItem);
+ rBindings.Invalidate (SID_ATTR_LINE_STYLE);
+ }
+#if HAVE_FEATURE_SCRIPTING
+ else StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE);
+#endif
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ // set line width
+ case SID_SETLINEWIDTH :
+ if (pArgs && pArgs->Count () == 1)
+ {
+ const SfxUInt32Item* pLineWidth = rReq.GetArg<SfxUInt32Item>(ID_VAL_WIDTH);
+ aAttr.ClearItem (XATTR_LINEWIDTH);
+ XLineWidthItem aWidthItem(pLineWidth->GetValue());
+ aWidthItem.SetWhich(XATTR_LINEWIDTH);
+ aAttr.Put(aWidthItem);
+ rBindings.Invalidate (SID_ATTR_LINE_WIDTH);
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ case SID_SETFILLCOLOR :
+ if (pArgs && pArgs->Count () == 3)
+ {
+ const SfxUInt32Item* pRed = rReq.GetArg<SfxUInt32Item>(ID_VAL_RED);
+ const SfxUInt32Item* pGreen = rReq.GetArg<SfxUInt32Item>(ID_VAL_GREEN);
+ const SfxUInt32Item* pBlue = rReq.GetArg<SfxUInt32Item>(ID_VAL_BLUE);
+
+ aAttr.ClearItem (XATTR_FILLCOLOR);
+ aAttr.ClearItem (XATTR_FILLSTYLE);
+ XFillColorItem aColorItem(-1, Color (static_cast<sal_uInt8>(pRed->GetValue ()),
+ static_cast<sal_uInt8>(pGreen->GetValue ()),
+ static_cast<sal_uInt8>(pBlue->GetValue ())));
+ aColorItem.SetWhich(XATTR_FILLCOLOR);
+ aAttr.Put(aColorItem);
+ rBindings.Invalidate (SID_ATTR_FILL_COLOR);
+ rBindings.Invalidate (SID_ATTR_PAGE_COLOR);
+ rBindings.Invalidate (SID_ATTR_FILL_STYLE);
+ rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE);
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ case SID_SETLINECOLOR :
+ if (pArgs && pArgs->Count () == 3)
+ {
+ const SfxUInt32Item* pRed = rReq.GetArg<SfxUInt32Item>(ID_VAL_RED);
+ const SfxUInt32Item* pGreen = rReq.GetArg<SfxUInt32Item>(ID_VAL_GREEN);
+ const SfxUInt32Item* pBlue = rReq.GetArg<SfxUInt32Item>(ID_VAL_BLUE);
+
+ aAttr.ClearItem (XATTR_LINECOLOR);
+ XLineColorItem aColorItem(-1, Color(static_cast<sal_uInt8>(pRed->GetValue()),
+ static_cast<sal_uInt8>(pGreen->GetValue()),
+ static_cast<sal_uInt8>(pBlue->GetValue())));
+ aColorItem.SetWhich(XATTR_LINECOLOR);
+ aAttr.Put(aColorItem);
+ rBindings.Invalidate (SID_ATTR_LINE_COLOR);
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ case SID_SETGRADSTARTCOLOR :
+ case SID_SETGRADENDCOLOR :
+ if (pArgs && pArgs->Count () == 4)
+ {
+ const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX);
+ const SfxUInt32Item* pRed = rReq.GetArg<SfxUInt32Item>(ID_VAL_RED);
+ const SfxUInt32Item* pGreen = rReq.GetArg<SfxUInt32Item>(ID_VAL_GREEN);
+ const SfxUInt32Item* pBlue = rReq.GetArg<SfxUInt32Item>(ID_VAL_BLUE);
+
+ XGradientListRef pGradientList = GetDoc()->GetGradientList ();
+ ::tools::Long nCounts = pGradientList->Count ();
+ Color aColor (static_cast<sal_uInt8>(pRed->GetValue ()),
+ static_cast<sal_uInt8>(pGreen->GetValue ()),
+ static_cast<sal_uInt8>(pBlue->GetValue ()));
+ ::tools::Long i;
+
+ aAttr.ClearItem (XATTR_FILLGRADIENT);
+ aAttr.ClearItem (XATTR_FILLSTYLE);
+
+ for ( i = 0; i < nCounts; i ++)
+ {
+ const XGradientEntry* pEntry = pGradientList->GetGradient(i);
+
+ if (pEntry->GetName () == pName->GetValue ())
+ {
+ XGradient aGradient(pEntry->GetGradient());
+
+ if (rReq.GetSlot () == SID_SETGRADSTARTCOLOR) aGradient.SetStartColor (aColor);
+ else aGradient.SetEndColor (aColor);
+
+ XFillStyleItem aStyleItem(drawing::FillStyle_GRADIENT);
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put(aStyleItem);
+ XFillGradientItem aGradientItem(pName->GetValue (), aGradient);
+ aGradientItem.SetWhich(XATTR_FILLGRADIENT);
+ aAttr.Put(aGradientItem);
+ break;
+ }
+ }
+
+ if (i >= nCounts)
+ {
+ Color aBlack (0, 0, 0);
+ XGradient aGradient ((rReq.GetSlot () == SID_SETGRADSTARTCOLOR)
+ ? aColor
+ : aBlack,
+ (rReq.GetSlot () == SID_SETGRADENDCOLOR)
+ ? aColor
+ : aBlack);
+
+ GetDoc()->GetGradientList()->Insert(std::make_unique<XGradientEntry>(aGradient, pName->GetValue()));
+
+ XFillStyleItem aStyleItem(drawing::FillStyle_GRADIENT);
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put(aStyleItem);
+ XFillGradientItem aGradientItem(pName->GetValue(), aGradient);
+ aGradientItem.SetWhich(XATTR_FILLGRADIENT);
+ aAttr.Put(aGradientItem);
+ }
+
+ rBindings.Invalidate (SID_ATTR_FILL_STYLE);
+ rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE);
+ rBindings.Invalidate (SID_ATTR_FILL_GRADIENT);
+ rBindings.Invalidate (SID_ATTR_PAGE_GRADIENT);
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ case SID_SETHATCHCOLOR :
+ if (pArgs && pArgs->Count () == 4)
+ {
+ const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX);
+ const SfxUInt32Item* pRed = rReq.GetArg<SfxUInt32Item>(ID_VAL_RED);
+ const SfxUInt32Item* pGreen = rReq.GetArg<SfxUInt32Item>(ID_VAL_GREEN);
+ const SfxUInt32Item* pBlue = rReq.GetArg<SfxUInt32Item>(ID_VAL_BLUE);
+
+ XHatchListRef pHatchList = GetDoc()->GetHatchList ();
+ ::tools::Long nCounts = pHatchList->Count ();
+ Color aColor (static_cast<sal_uInt8>(pRed->GetValue ()),
+ static_cast<sal_uInt8>(pGreen->GetValue ()),
+ static_cast<sal_uInt8>(pBlue->GetValue ()));
+ ::tools::Long i;
+
+ aAttr.ClearItem (XATTR_FILLHATCH);
+ aAttr.ClearItem (XATTR_FILLSTYLE);
+
+ for ( i = 0; i < nCounts; i ++)
+ {
+ const XHatchEntry* pEntry = pHatchList->GetHatch(i);
+
+ if (pEntry->GetName () == pName->GetValue ())
+ {
+ XHatch aHatch(pEntry->GetHatch());
+
+ aHatch.SetColor (aColor);
+
+ XFillStyleItem aStyleItem(drawing::FillStyle_HATCH);
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put(aStyleItem);
+ XFillHatchItem aHatchItem(pName->GetValue(), aHatch);
+ aHatchItem.SetWhich(XATTR_FILLHATCH);
+ aAttr.Put(aHatchItem);
+ break;
+ }
+ }
+
+ if (i >= nCounts)
+ {
+ XHatch aHatch (aColor);
+
+ GetDoc()->GetHatchList()->Insert(std::make_unique<XHatchEntry>(aHatch, pName->GetValue()));
+
+ XFillStyleItem aStyleItem(drawing::FillStyle_HATCH);
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put(aStyleItem);
+ XFillHatchItem aHatchItem(pName->GetValue (), aHatch);
+ aHatchItem.SetWhich(XATTR_FILLHATCH);
+ aAttr.Put(aHatchItem);
+ }
+
+ rBindings.Invalidate (SID_ATTR_FILL_HATCH);
+ rBindings.Invalidate (SID_ATTR_PAGE_HATCH);
+ rBindings.Invalidate (SID_ATTR_FILL_STYLE);
+ rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE);
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ // configuration for line-dash
+ case SID_DASH :
+ if (pArgs && pArgs->Count () == 7)
+ {
+ const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX);
+ const SfxUInt32Item* pStyle = rReq.GetArg<SfxUInt32Item>(ID_VAL_STYLE);
+ const SfxUInt32Item* pDots = rReq.GetArg<SfxUInt32Item>(ID_VAL_DOTS);
+ const SfxUInt32Item* pDotLen = rReq.GetArg<SfxUInt32Item>(ID_VAL_DOTLEN);
+ const SfxUInt32Item* pDashes = rReq.GetArg<SfxUInt32Item>(ID_VAL_DASHES);
+ const SfxUInt32Item* pDashLen = rReq.GetArg<SfxUInt32Item>(ID_VAL_DASHLEN);
+ const SfxUInt32Item* pDistance = rReq.GetArg<SfxUInt32Item>(ID_VAL_DISTANCE);
+
+ if (CHECK_RANGE (sal_Int32(css::drawing::DashStyle_RECT), static_cast<sal_Int32>(pStyle->GetValue()), sal_Int32(css::drawing::DashStyle_ROUNDRELATIVE)))
+ {
+ XDash aNewDash (static_cast<css::drawing::DashStyle>(pStyle->GetValue ()), static_cast<short>(pDots->GetValue ()), pDotLen->GetValue (),
+ static_cast<short>(pDashes->GetValue ()), pDashLen->GetValue (), pDistance->GetValue ());
+
+ aAttr.ClearItem (XATTR_LINEDASH);
+ aAttr.ClearItem (XATTR_LINESTYLE);
+
+ XDashListRef pDashList = GetDoc()->GetDashList();
+ ::tools::Long nCounts = pDashList->Count ();
+ std::unique_ptr<XDashEntry> pEntry = std::make_unique<XDashEntry>(aNewDash, pName->GetValue());
+ ::tools::Long i;
+
+ for ( i = 0; i < nCounts; i++ )
+ if (pDashList->GetDash (i)->GetName () == pName->GetValue ())
+ break;
+
+ if (i < nCounts)
+ pDashList->Replace(std::move(pEntry), i);
+ else
+ pDashList->Insert(std::move(pEntry));
+
+ XLineDashItem aDashItem(pName->GetValue(), aNewDash);
+ aDashItem.SetWhich(XATTR_LINEDASH);
+ aAttr.Put(aDashItem);
+ XLineStyleItem aStyleItem(drawing::LineStyle_DASH);
+ aStyleItem.SetWhich(XATTR_LINESTYLE);
+ aAttr.Put(aStyleItem);
+ rBindings.Invalidate (SID_ATTR_LINE_DASH);
+ rBindings.Invalidate (SID_ATTR_FILL_STYLE);
+ }
+#if HAVE_FEATURE_SCRIPTING
+ else StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE);
+#endif
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ // configuration for gradients
+ case SID_GRADIENT :
+ if (pArgs && pArgs->Count () == 8)
+ {
+ const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX);
+ const SfxUInt32Item* pStyle = rReq.GetArg<SfxUInt32Item>(ID_VAL_STYLE);
+ const SfxUInt32Item* pAngle = rReq.GetArg<SfxUInt32Item>(ID_VAL_ANGLE);
+ const SfxUInt32Item* pBorder = rReq.GetArg<SfxUInt32Item>(ID_VAL_BORDER);
+ const SfxUInt32Item* pCenterX = rReq.GetArg<SfxUInt32Item>(ID_VAL_CENTER_X);
+ const SfxUInt32Item* pCenterY = rReq.GetArg<SfxUInt32Item>(ID_VAL_CENTER_Y);
+ const SfxUInt32Item* pStart = rReq.GetArg<SfxUInt32Item>(ID_VAL_STARTINTENS);
+ const SfxUInt32Item* pEnd = rReq.GetArg<SfxUInt32Item>(ID_VAL_ENDINTENS);
+
+ if (CHECK_RANGE (sal_Int32(css::awt::GradientStyle_LINEAR), static_cast<sal_Int32>(pStyle->GetValue()), sal_Int32(css::awt::GradientStyle_RECT)) &&
+ CHECK_RANGE (0, static_cast<sal_Int32>(pAngle->GetValue ()), 360) &&
+ CHECK_RANGE (0, static_cast<sal_Int32>(pBorder->GetValue ()), 100) &&
+ CHECK_RANGE (0, static_cast<sal_Int32>(pCenterX->GetValue ()), 100) &&
+ CHECK_RANGE (0, static_cast<sal_Int32>(pCenterY->GetValue ()), 100) &&
+ CHECK_RANGE (0, static_cast<sal_Int32>(pStart->GetValue ()), 100) &&
+ CHECK_RANGE (0, static_cast<sal_Int32>(pEnd->GetValue ()), 100))
+ {
+ aAttr.ClearItem (XATTR_FILLGRADIENT);
+ aAttr.ClearItem (XATTR_FILLSTYLE);
+
+ XGradientListRef pGradientList = GetDoc()->GetGradientList ();
+ ::tools::Long nCounts = pGradientList->Count ();
+ ::tools::Long i;
+
+ for ( i = 0; i < nCounts; i++ )
+ {
+ const XGradientEntry* pEntry = pGradientList->GetGradient(i);
+
+ if (pEntry->GetName () == pName->GetValue ())
+ {
+ XGradient aGradient(pEntry->GetGradient());
+
+ aGradient.SetGradientStyle (static_cast<css::awt::GradientStyle>(pStyle->GetValue ()));
+ aGradient.SetAngle (Degree10(pAngle->GetValue () * 10));
+ aGradient.SetBorder (static_cast<short>(pBorder->GetValue ()));
+ aGradient.SetXOffset (static_cast<short>(pCenterX->GetValue ()));
+ aGradient.SetYOffset (static_cast<short>(pCenterY->GetValue ()));
+ aGradient.SetStartIntens (static_cast<short>(pStart->GetValue ()));
+ aGradient.SetEndIntens (static_cast<short>(pEnd->GetValue ()));
+
+ XFillStyleItem aStyleItem(drawing::FillStyle_GRADIENT);
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put(aStyleItem);
+ XFillGradientItem aGradientItem(pName->GetValue (), aGradient);
+ aGradientItem.SetWhich(XATTR_FILLGRADIENT);
+ aAttr.Put(aGradientItem);
+ break;
+ }
+ }
+
+ if (i >= nCounts)
+ {
+ Color aBlack (0, 0, 0);
+ XGradient aGradient (aBlack, aBlack, static_cast<css::awt::GradientStyle>(pStyle->GetValue ()),
+ Degree10(pAngle->GetValue () * 10), static_cast<short>(pCenterX->GetValue ()),
+ static_cast<short>(pCenterY->GetValue ()), static_cast<short>(pBorder->GetValue ()),
+ static_cast<short>(pStart->GetValue ()), static_cast<short>(pEnd->GetValue ()));
+
+ pGradientList->Insert(std::make_unique<XGradientEntry>(aGradient, pName->GetValue()));
+ XFillStyleItem aStyleItem(drawing::FillStyle_GRADIENT);
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put(aStyleItem);
+ XFillGradientItem aGradientItem(pName->GetValue (), aGradient);
+ aGradientItem.SetWhich(XATTR_FILLGRADIENT);
+ aAttr.Put(aGradientItem);
+ }
+
+ rBindings.Invalidate (SID_ATTR_FILL_GRADIENT);
+ rBindings.Invalidate (SID_ATTR_PAGE_GRADIENT);
+ rBindings.Invalidate (SID_ATTR_FILL_STYLE);
+ rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE);
+ }
+#if HAVE_FEATURE_SCRIPTING
+ else StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE);
+#endif
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ // configuration for hatch
+ case SID_HATCH :
+ if (pArgs && pArgs->Count () == 4)
+ {
+ const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX);
+ const SfxUInt32Item* pStyle = rReq.GetArg<SfxUInt32Item>(ID_VAL_STYLE);
+ const SfxUInt32Item* pDistance = rReq.GetArg<SfxUInt32Item>(ID_VAL_DISTANCE);
+ const SfxUInt32Item* pAngle = rReq.GetArg<SfxUInt32Item>(ID_VAL_ANGLE);
+
+ if (CHECK_RANGE (sal_Int32(css::drawing::HatchStyle_SINGLE), static_cast<sal_Int32>(pStyle->GetValue()), sal_Int32(css::drawing::HatchStyle_TRIPLE)) &&
+ CHECK_RANGE (0, static_cast<sal_Int32>(pAngle->GetValue ()), 360))
+ {
+ aAttr.ClearItem (XATTR_FILLHATCH);
+ aAttr.ClearItem (XATTR_FILLSTYLE);
+
+ XHatchListRef pHatchList = GetDoc()->GetHatchList ();
+ ::tools::Long nCounts = pHatchList->Count ();
+ ::tools::Long i;
+
+ for ( i = 0; i < nCounts; i++ )
+ {
+ const XHatchEntry* pEntry = pHatchList->GetHatch(i);
+
+ if (pEntry->GetName () == pName->GetValue ())
+ {
+ XHatch aHatch(pEntry->GetHatch());
+
+ aHatch.SetHatchStyle (static_cast<css::drawing::HatchStyle>(pStyle->GetValue ()));
+ aHatch.SetDistance (pDistance->GetValue ());
+ aHatch.SetAngle (Degree10(pAngle->GetValue () * 10));
+
+ XFillStyleItem aStyleItem(drawing::FillStyle_HATCH);
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put(aStyleItem);
+ XFillHatchItem aHatchItem(pName->GetValue (), aHatch);
+ aHatchItem.SetWhich(XATTR_FILLHATCH);
+ aAttr.Put(aHatchItem);
+ break;
+ }
+ }
+
+ if (i >= nCounts)
+ {
+ XHatch aHatch (Color(0), static_cast<css::drawing::HatchStyle>(pStyle->GetValue ()), pDistance->GetValue (),
+ Degree10(pAngle->GetValue () * 10));
+
+ pHatchList->Insert(std::make_unique<XHatchEntry>(aHatch, pName->GetValue()));
+ XFillStyleItem aStyleItem(drawing::FillStyle_HATCH);
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put(aStyleItem);
+ XFillHatchItem aHatchItem(pName->GetValue (), aHatch);
+ aHatchItem.SetWhich(XATTR_FILLHATCH);
+ aAttr.Put(aHatchItem);
+ }
+
+ rBindings.Invalidate (SID_ATTR_FILL_HATCH);
+ rBindings.Invalidate (SID_ATTR_FILL_STYLE);
+ }
+#if HAVE_FEATURE_SCRIPTING
+ else StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE);
+#endif
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ case SID_SELECTGRADIENT :
+ if (pArgs && (pArgs->Count () == 1))
+ {
+ const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX);
+
+ XGradientListRef pGradientList = GetDoc()->GetGradientList ();
+ ::tools::Long nCounts = pGradientList->Count ();
+
+ for (::tools::Long i = 0; i < nCounts; i ++)
+ {
+ const XGradientEntry* pEntry = pGradientList->GetGradient(i);
+
+ if (pEntry->GetName () == pName->GetValue ())
+ {
+ aAttr.ClearItem (XATTR_FILLGRADIENT);
+ aAttr.ClearItem (XATTR_FILLSTYLE);
+ XFillStyleItem aStyleItem(drawing::FillStyle_GRADIENT);
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put(aStyleItem);
+ XFillGradientItem aGradientItem(pName->GetValue (), pEntry->GetGradient ());
+ aGradientItem.SetWhich(XATTR_FILLGRADIENT);
+ aAttr.Put(aGradientItem);
+ rBindings.Invalidate (SID_ATTR_FILL_GRADIENT);
+ rBindings.Invalidate (SID_ATTR_PAGE_GRADIENT);
+ rBindings.Invalidate (SID_ATTR_FILL_STYLE);
+ rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE);
+ break;
+ }
+ }
+
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ case SID_SELECTHATCH :
+ if (pArgs && pArgs->Count () == 1)
+ {
+ const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX);
+
+ XHatchListRef pHatchList = GetDoc()->GetHatchList ();
+ ::tools::Long nCounts = pHatchList->Count ();
+
+ for (::tools::Long i = 0; i < nCounts; i ++)
+ {
+ const XHatchEntry* pEntry = pHatchList->GetHatch(i);
+
+ if (pEntry->GetName () == pName->GetValue ())
+ {
+ aAttr.ClearItem (XATTR_FILLHATCH);
+ aAttr.ClearItem (XATTR_FILLSTYLE);
+ XFillStyleItem aStyleItem(drawing::FillStyle_HATCH);
+ aStyleItem.SetWhich(XATTR_FILLSTYLE);
+ aAttr.Put(aStyleItem);
+ XFillHatchItem aHatchItem(pName->GetValue (), pEntry->GetHatch ());
+ aHatchItem.SetWhich(XATTR_FILLHATCH);
+ aAttr.Put(aHatchItem);
+
+ rBindings.Invalidate (SID_ATTR_FILL_HATCH);
+ rBindings.Invalidate (SID_ATTR_PAGE_HATCH);
+ rBindings.Invalidate (SID_ATTR_FILL_STYLE);
+ rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE);
+ break;
+ }
+ }
+
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+ case SID_UNSELECT :
+ mpDrawView->UnmarkAll ();
+ break;
+
+ case SID_GETRED :
+ if (pArgs && pArgs->Count () == 1)
+ {
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ break;
+
+/* case SID_SETFONTFAMILYNAME :
+ case SID_SETFONTSTYLENAME :
+ case SID_SETFONTFAMILY :
+ case SID_SETFONTPITCH :
+ case SID_SETFONTCHARSET :
+ case SID_SETFONTPOSTURE :
+ case SID_SETFONTWEIGHT :
+ case SID_SETFONTUNDERLINE :
+ case SID_SETFONTCROSSEDOUT :
+ case SID_SETFONTSHADOWED :
+ case SID_SETFONTCONTOUR :
+ case SID_SETFONTCOLOR :
+ case SID_SETFONTLANGUAGE :
+ case SID_SETFONTWORDLINE :
+ case SID_SETFONTCASEMAP :
+ case SID_SETFONTESCAPE :
+ case SID_SETFONTKERNING :
+ break;*/
+
+ default :
+ ;
+ }
+
+ mpDrawView->SetAttributes (const_cast<const SfxItemSet &>(aAttr));
+ rReq.Ignore ();
+}
+
+/**
+ * Edit macros for attribute configuration
+ */
+void DrawViewShell::AttrState (SfxItemSet& rSet)
+{
+ SfxWhichIter aIter (rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich ();
+ SfxItemSet aAttr( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aAttr );
+
+ while (nWhich)
+ {
+ switch (nWhich)
+ {
+ case SID_GETFILLSTYLE :
+ {
+ const XFillStyleItem &rFillStyleItem = aAttr.Get (XATTR_FILLSTYLE);
+
+ rSet.Put (SfxUInt32Item (nWhich, static_cast<::tools::Long>(rFillStyleItem.GetValue ())));
+ break;
+ }
+
+ case SID_GETLINESTYLE :
+ {
+ const XLineStyleItem &rLineStyleItem = aAttr.Get (XATTR_LINESTYLE);
+
+ rSet.Put (SfxUInt32Item (nWhich, static_cast<::tools::Long>(rLineStyleItem.GetValue ())));
+ break;
+ }
+
+ case SID_GETLINEWIDTH :
+ {
+ const XLineWidthItem &rLineWidthItem = aAttr.Get (XATTR_LINEWIDTH);
+
+ rSet.Put (SfxUInt32Item (nWhich, static_cast<::tools::Long>(rLineWidthItem.GetValue ())));
+ break;
+ }
+
+ case SID_GETGREEN :
+ case SID_GETRED :
+ case SID_GETBLUE :
+ {
+ const SfxUInt32Item &rWhatKind = static_cast<const SfxUInt32Item &>( rSet.Get (ID_VAL_WHATKIND) );
+ Color aColor;
+
+ switch (rWhatKind.GetValue ())
+ {
+ case 1 :
+ {
+ const XLineColorItem &rLineColorItem = aAttr.Get (XATTR_LINECOLOR);
+
+ aColor = rLineColorItem.GetColorValue ();
+ break;
+ }
+
+ case 2 :
+ {
+ const XFillColorItem &rFillColorItem = aAttr.Get (XATTR_FILLCOLOR);
+
+ aColor = rFillColorItem.GetColorValue ();
+ break;
+ }
+
+ case 3 :
+ case 4 :
+ {
+ const XFillGradientItem &rFillGradientItem = aAttr.Get (XATTR_FILLGRADIENT);
+ const XGradient &rGradient = rFillGradientItem.GetGradientValue ();
+
+ aColor = (rWhatKind.GetValue () == 3)
+ ? rGradient.GetStartColor ()
+ : rGradient.GetEndColor ();
+ break;
+ }
+
+ case 5:
+ {
+ const XFillHatchItem &rFillHatchItem = aAttr.Get (XATTR_FILLHATCH);
+ const XHatch &rHatch = rFillHatchItem.GetHatchValue ();
+
+ aColor = rHatch.GetColor ();
+ break;
+ }
+
+ default :
+ ;
+ }
+
+ rSet.Put (SfxUInt32Item (nWhich, static_cast<::tools::Long>((nWhich == SID_GETRED)
+ ? aColor.GetRed ()
+ : (nWhich == SID_GETGREEN)
+ ? aColor.GetGreen ()
+ : aColor.GetBlue ())));
+ break;
+ }
+
+ default :
+ ;
+ }
+
+ nWhich = aIter.NextWhich ();
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewsa.cxx b/sd/source/ui/view/drviewsa.cxx
new file mode 100644
index 000000000..a61d64599
--- /dev/null
+++ b/sd/source/ui/view/drviewsa.cxx
@@ -0,0 +1,848 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawViewShell.hxx>
+#include <com/sun/star/scanner/ScannerManager.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/processfactory.hxx>
+#include <editeng/sizeitem.hxx>
+#include <svx/svdlayer.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <svx/svdpagv.hxx>
+#include <svl/ptitem.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <svl/eitem.hxx>
+
+#include <sdcommands.h>
+#include <svx/f3dchild.hxx>
+#include <svx/clipfmtitem.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <svtools/cliplistener.hxx>
+#include <svx/float3d.hxx>
+#include <svx/extedit.hxx>
+#include <svx/sidebar/SelectionAnalyzer.hxx>
+#include <svx/sidebar/SelectionChangeHandler.hxx>
+#include <helpids.h>
+
+#include <view/viewoverlaymanager.hxx>
+#include <app.hrc>
+#include <strings.hrc>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+#include <FrameView.hxx>
+#include <drawdoc.hxx>
+#include <sdresid.hxx>
+#include <DrawDocShell.hxx>
+#include <Window.hxx>
+#include <fupoor.hxx>
+#include <fusel.hxx>
+#include <funavig.hxx>
+#include <drawview.hxx>
+#include <SdUnoDrawView.hxx>
+#include <ViewShellBase.hxx>
+#include <slideshow.hxx>
+#include <annotationmanager.hxx>
+#include <DrawController.hxx>
+#include <tools/diagnose_ex.h>
+#include <LayerTabBar.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using vcl::EnumContext;
+
+namespace sd {
+
+bool DrawViewShell::mbPipette = false;
+
+namespace {
+
+class ScannerEventListener : public ::cppu::WeakImplHelper< lang::XEventListener >
+{
+private:
+
+ DrawViewShell* mpParent;
+
+public:
+
+ explicit ScannerEventListener( DrawViewShell* pParent ) : mpParent( pParent ) {}
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const lang::EventObject& rEventObject ) override;
+
+ void ParentDestroyed() { mpParent = nullptr; }
+};
+
+}
+
+void SAL_CALL ScannerEventListener::disposing( const lang::EventObject& /*rEventObject*/ )
+{
+ if( mpParent )
+ mpParent->ScannerEvent();
+}
+
+DrawViewShell::DrawViewShell( ViewShellBase& rViewShellBase, vcl::Window* pParentWindow, PageKind ePageKind, FrameView* pFrameViewArgument )
+ : ViewShell (pParentWindow, rViewShellBase)
+ , maTabControl(VclPtr<sd::TabControl>::Create(this, pParentWindow))
+ , mbIsLayerModeActive(false)
+ , mbIsInSwitchPage(false)
+ , mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler(
+ [this] () { return this->GetSidebarContextName(); },
+ uno::Reference<frame::XController>(&rViewShellBase.GetDrawController()),
+ vcl::EnumContext::Context::Default))
+ , mbMouseButtonDown(false)
+ , mbMouseSelecting(false)
+{
+ if (pFrameViewArgument != nullptr)
+ mpFrameView = pFrameViewArgument;
+ else
+ mpFrameView = new FrameView(GetDoc());
+ Construct(GetDocSh(), ePageKind);
+
+ mpSelectionChangeHandler->Connect();
+
+ SetContextName(GetSidebarContextName());
+
+ doShow();
+
+ ConfigureAppBackgroundColor();
+ SD_MOD()->GetColorConfig().AddListener(this);
+}
+
+DrawViewShell::~DrawViewShell()
+{
+ SD_MOD()->GetColorConfig().RemoveListener(this);
+
+ mpSelectionChangeHandler->Disconnect();
+
+ mpAnnotationManager.reset();
+ mpViewOverlayManager.reset();
+
+ OSL_ASSERT (GetViewShell()!=nullptr);
+
+ if( mxScannerListener.is() )
+ static_cast< ScannerEventListener* >( mxScannerListener.get() )->ParentDestroyed();
+
+ // Remove references to items within Svx3DWin
+ // (maybe do a listening sometime in Svx3DWin)
+ sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId();
+ SfxChildWindow* pWindow = GetViewFrame() ? GetViewFrame()->GetChildWindow(nId) : nullptr;
+ if(pWindow)
+ {
+ Svx3DWin* p3DWin = static_cast< Svx3DWin* > (pWindow->GetWindow());
+ if(p3DWin)
+ p3DWin->DocumentReload();
+ }
+
+ EndListening (*GetDoc());
+ EndListening (*GetDocSh());
+
+ if( SlideShow::IsRunning(*this) )
+ StopSlideShow();
+
+ DisposeFunctions();
+
+ sal_uInt16 aPageCnt = GetDoc()->GetSdPageCount(mePageKind);
+
+ for (sal_uInt16 i = 0; i < aPageCnt; i++)
+ {
+ SdPage* pPage = GetDoc()->GetSdPage(i, mePageKind);
+
+ if (pPage == mpActualPage)
+ {
+ GetDoc()->SetSelected(pPage, true);
+ }
+ else
+ {
+ GetDoc()->SetSelected(pPage, false);
+ }
+ }
+
+ if ( mxClipEvtLstnr.is() )
+ {
+ mxClipEvtLstnr->RemoveListener( GetActiveWindow() );
+ mxClipEvtLstnr->ClearCallbackLink(); // prevent callback if another thread is waiting
+ mxClipEvtLstnr.clear();
+ }
+
+ mpDrawView.reset();
+ // Set mpView to NULL so that the destructor of the ViewShell base class
+ // does not access it.
+ mpView = nullptr;
+
+ mpFrameView->Disconnect();
+ maTabControl.disposeAndClear();
+}
+
+/**
+ * common part of both constructors
+ */
+void DrawViewShell::Construct(DrawDocShell* pDocSh, PageKind eInitialPageKind)
+{
+ mpActualPage = nullptr;
+ mbReadOnly = GetDocSh()->IsReadOnly();
+ mxClipEvtLstnr.clear();
+ mbPastePossible = false;
+ mbIsLayerModeActive = false;
+
+ mpFrameView->Connect();
+
+ OSL_ASSERT (GetViewShell()!=nullptr);
+
+ SetPool( &GetDoc()->GetPool() );
+
+ GetDoc()->CreateFirstPages();
+
+ mpDrawView.reset( new DrawView(pDocSh, GetActiveWindow()->GetOutDev(), this) );
+ mpView = mpDrawView.get(); // Pointer of base class ViewShell
+ mpDrawView->SetSwapAsynchron(); // Asynchronous load of graphics
+
+ // We do not read the page kind from the frame view anymore so we have
+ // to set it in order to resync frame view and this view.
+ mpFrameView->SetPageKind(eInitialPageKind);
+ mePageKind = eInitialPageKind;
+ meEditMode = EditMode::Page;
+ DocumentType eDocType = GetDoc()->GetDocumentType(); // RTTI does not work here
+ switch (mePageKind)
+ {
+ case PageKind::Standard:
+ meShellType = ST_IMPRESS;
+ break;
+
+ case PageKind::Notes:
+ meShellType = ST_NOTES;
+ break;
+
+ case PageKind::Handout:
+ meShellType = ST_HANDOUT;
+ break;
+ }
+
+ Size aPageSize( GetDoc()->GetSdPage(0, mePageKind)->GetSize() );
+ Point aPageOrg( aPageSize.Width(), aPageSize.Height() / 2);
+ Size aSize(aPageSize.Width() * 3, aPageSize.Height() * 2);
+ InitWindows(aPageOrg, aSize, Point(-1, -1));
+
+ Point aVisAreaPos;
+
+ if ( pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
+ {
+ aVisAreaPos = pDocSh->GetVisArea(ASPECT_CONTENT).TopLeft();
+ }
+
+ mpDrawView->SetWorkArea(::tools::Rectangle(Point() - aVisAreaPos - aPageOrg, aSize));
+
+ // objects can not grow bigger than ViewSize
+ GetDoc()->SetMaxObjSize(aSize);
+
+ // Split-Handler for TabControls
+ maTabControl->SetSplitHdl( LINK( this, DrawViewShell, TabSplitHdl ) );
+
+ /* In order to set the correct EditMode of the FrameView, we select another
+ one (small trick). */
+ if (mpFrameView->GetViewShEditMode(/*mePageKind*/) == EditMode::Page)
+ {
+ meEditMode = EditMode::MasterPage;
+ }
+ else
+ {
+ meEditMode = EditMode::Page;
+ }
+
+ // Use configuration of FrameView
+ ReadFrameViewData(mpFrameView);
+
+ if( eDocType == DocumentType::Draw )
+ {
+ GetActiveWindow()->SetHelpId( HID_SDGRAPHICVIEWSHELL );
+ }
+ else
+ {
+ if (mePageKind == PageKind::Notes)
+ {
+ GetActiveWindow()->SetHelpId( CMD_SID_NOTES_MODE );
+
+ // AutoLayouts have to be created
+ GetDoc()->StopWorkStartupDelay();
+ }
+ else if (mePageKind == PageKind::Handout)
+ {
+ GetActiveWindow()->SetHelpId( CMD_SID_HANDOUT_MASTER_MODE );
+
+ // AutoLayouts have to be created
+ GetDoc()->StopWorkStartupDelay();
+ }
+ else
+ {
+ GetActiveWindow()->SetHelpId( HID_SDDRAWVIEWSHELL );
+ }
+ }
+
+ // start selection function
+ SfxRequest aReq(SID_OBJECT_SELECT, SfxCallMode::SLOT, GetDoc()->GetItemPool());
+ FuPermanent(aReq);
+ mpDrawView->SetFrameDragSingles();
+
+ if (pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED)
+ {
+ mbZoomOnPage = false;
+ }
+ else
+ {
+ mbZoomOnPage = true;
+ }
+
+ mbIsRulerDrag = false;
+
+ SetName ("DrawViewShell");
+
+ mnLockCount = 0;
+
+ uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+
+ try
+ {
+ mxScannerManager = scanner::ScannerManager::create( xContext );
+
+ mxScannerListener = new ScannerEventListener( this );
+ }
+ catch (Exception const &)
+ {
+ // Eat the exception and log it
+ // We can still continue if scanner manager is not available.
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+
+ mpAnnotationManager.reset( new AnnotationManager( GetViewShellBase() ) );
+ mpViewOverlayManager.reset( new ViewOverlayManager( GetViewShellBase() ) );
+}
+
+void DrawViewShell::Init (bool bIsMainViewShell)
+{
+ ViewShell::Init(bIsMainViewShell);
+
+ if (!IsListening(*GetDocSh()))
+ StartListening (*GetDocSh());
+}
+
+void DrawViewShell::Shutdown()
+{
+ ViewShell::Shutdown();
+
+ if(SlideShow::IsRunning( GetViewShellBase() ) )
+ {
+ // Turn off effects.
+ GetDrawView()->SetAnimationMode(SdrAnimationMode::Disable);
+ }
+}
+
+css::uno::Reference<css::drawing::XDrawSubController> DrawViewShell::CreateSubController()
+{
+ css::uno::Reference<css::drawing::XDrawSubController> xSubController;
+
+ if (IsMainViewShell())
+ {
+ // Create uno sub controller for the main view shell.
+ xSubController.set( new SdUnoDrawView( *this, *GetView()));
+ }
+
+ return xSubController;
+}
+
+bool DrawViewShell::RelocateToParentWindow (vcl::Window* pParentWindow)
+{
+ // DrawViewShells can not be relocated to a new parent window at the
+ // moment, so return <FALSE/> except when the given parent window is the
+ // parent window that is already in use.
+ return pParentWindow==GetParentWindow();
+}
+
+/**
+ * check if we have to draw a polyline
+ */
+
+/*
+ Polylines are represented by macros as a sequence of:
+ MoveTo (x, y)
+ LineTo (x, y) [or BezierTo (x, y)]
+ LineTo (x, y)
+ :
+ There is no end command for polylines. Therefore, we have to test all
+ commands in the requests for LineTo (BezierTo) and we have to gather
+ the point-parameter. The first not-LineTo leads to the creation of the
+ polyline from the gathered points.
+*/
+
+void DrawViewShell::CheckLineTo(SfxRequest& rReq)
+{
+#ifdef DBG_UTIL
+ if(rReq.IsAPI())
+ {
+ if(SID_LINETO == rReq.GetSlot() || SID_BEZIERTO == rReq.GetSlot() || SID_MOVETO == rReq.GetSlot() )
+ {
+ OSL_FAIL("DrawViewShell::CheckLineTo: slots SID_LINETO, SID_BEZIERTO, SID_MOVETO no longer supported.");
+ }
+ }
+#endif
+
+ rReq.Ignore ();
+}
+
+/**
+ * Change page parameter if SID_PAGESIZE or SID_PAGEMARGIN
+ */
+void DrawViewShell::SetupPage (Size const &rSize,
+ ::tools::Long nLeft,
+ ::tools::Long nRight,
+ ::tools::Long nUpper,
+ ::tools::Long nLower,
+ bool bSize,
+ bool bMargin,
+ bool bScaleAll)
+{
+ sal_uInt16 nPageCnt = GetDoc()->GetMasterSdPageCount(mePageKind);
+ sal_uInt16 i;
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ // first, handle all master pages
+ SdPage *pPage = GetDoc()->GetMasterSdPage(i, mePageKind);
+
+ if( pPage )
+ {
+ if( bSize )
+ {
+ ::tools::Rectangle aBorderRect(nLeft, nUpper, nRight, nLower);
+ pPage->ScaleObjects(rSize, aBorderRect, bScaleAll);
+ pPage->SetSize(rSize);
+
+ }
+ if( bMargin )
+ {
+ pPage->SetLeftBorder(nLeft);
+ pPage->SetRightBorder(nRight);
+ pPage->SetUpperBorder(nUpper);
+ pPage->SetLowerBorder(nLower);
+ }
+
+ if ( mePageKind == PageKind::Standard )
+ {
+ GetDoc()->GetMasterSdPage(i, PageKind::Notes)->CreateTitleAndLayout();
+ }
+
+ pPage->CreateTitleAndLayout();
+ }
+ }
+
+ nPageCnt = GetDoc()->GetSdPageCount(mePageKind);
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ // then, handle all pages
+ SdPage *pPage = GetDoc()->GetSdPage(i, mePageKind);
+
+ if( pPage )
+ {
+ if( bSize )
+ {
+ ::tools::Rectangle aBorderRect(nLeft, nUpper, nRight, nLower);
+ pPage->ScaleObjects(rSize, aBorderRect, bScaleAll);
+ pPage->SetSize(rSize);
+ }
+ if( bMargin )
+ {
+ pPage->SetLeftBorder(nLeft);
+ pPage->SetRightBorder(nRight);
+ pPage->SetUpperBorder(nUpper);
+ pPage->SetLowerBorder(nLower);
+ }
+
+ if ( mePageKind == PageKind::Standard )
+ {
+ SdPage* pNotesPage = GetDoc()->GetSdPage(i, PageKind::Notes);
+ pNotesPage->SetAutoLayout( pNotesPage->GetAutoLayout() );
+ }
+
+ pPage->SetAutoLayout( pPage->GetAutoLayout() );
+ }
+ }
+
+ if ( mePageKind == PageKind::Standard )
+ {
+ SdPage* pHandoutPage = GetDoc()->GetSdPage(0, PageKind::Handout);
+ pHandoutPage->CreateTitleAndLayout(true);
+ }
+
+ ::tools::Long nWidth = mpActualPage->GetSize().Width();
+ ::tools::Long nHeight = mpActualPage->GetSize().Height();
+
+ Point aPageOrg(nWidth, nHeight / 2);
+ Size aSize( nWidth * 3, nHeight * 2);
+
+ InitWindows(aPageOrg, aSize, Point(-1, -1), true);
+
+ Point aVisAreaPos;
+
+ if ( GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
+ {
+ aVisAreaPos = GetDocSh()->GetVisArea(ASPECT_CONTENT).TopLeft();
+ }
+
+ GetView()->SetWorkArea(::tools::Rectangle(Point() - aVisAreaPos - aPageOrg, aSize));
+
+ UpdateScrollBars();
+
+ Point aNewOrigin(mpActualPage->GetLeftBorder(), mpActualPage->GetUpperBorder());
+ GetView()->GetSdrPageView()->SetPageOrigin(aNewOrigin);
+
+ GetViewFrame()->GetBindings().Invalidate(SID_RULER_NULL_OFFSET);
+
+ // zoom onto (new) page size
+ GetViewFrame()->GetDispatcher()->Execute(SID_SIZE_PAGE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+}
+
+void DrawViewShell::GetStatusBarState(SfxItemSet& rSet)
+{
+ /* Zoom-Item
+ Here we should propagate the corresponding value (Optimal ?, page width
+ or page) with the help of the ZoomItems !!! */
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_ZOOM ) )
+ {
+ if (GetDocSh()->IsUIActive() || SlideShow::IsRunning(GetViewShellBase())
+ || !GetActiveWindow())
+ {
+ rSet.DisableItem( SID_ATTR_ZOOM );
+ }
+ else
+ {
+ std::unique_ptr<SvxZoomItem> pZoomItem;
+ sal_uInt16 nZoom = static_cast<sal_uInt16>(GetActiveWindow()->GetZoom());
+
+ if( mbZoomOnPage )
+ pZoomItem.reset(new SvxZoomItem( SvxZoomType::WHOLEPAGE, nZoom ));
+ else
+ pZoomItem.reset(new SvxZoomItem( SvxZoomType::PERCENT, nZoom ));
+
+ // constrain area
+ SvxZoomEnableFlags nZoomValues = SvxZoomEnableFlags::ALL;
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+
+ if( pPageView && pPageView->GetObjList()->GetObjCount() == 0 )
+ {
+ nZoomValues &= ~SvxZoomEnableFlags::OPTIMAL;
+ }
+
+ pZoomItem->SetValueSet( nZoomValues );
+ rSet.Put( std::move(pZoomItem) );
+ }
+ }
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_ZOOMSLIDER ) )
+ {
+ rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetDoc() ) );
+ if (GetDocSh()->IsUIActive() || (xSlideshow.is() && xSlideshow->isRunning()) || !GetActiveWindow() )
+ {
+ rSet.DisableItem( SID_ATTR_ZOOMSLIDER );
+ }
+ else
+ {
+ sd::Window * pActiveWindow = GetActiveWindow();
+ SvxZoomSliderItem aZoomItem( static_cast<sal_uInt16>(pActiveWindow->GetZoom()), static_cast<sal_uInt16>(pActiveWindow->GetMinZoom()), static_cast<sal_uInt16>(pActiveWindow->GetMaxZoom()) ) ;
+
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+ if( pPageView )
+ {
+ Point aPagePos(0, 0);
+ Size aPageSize = pPageView->GetPage()->GetSize();
+
+ aPagePos.AdjustX(aPageSize.Width() / 2 );
+ aPageSize.setWidth( static_cast<::tools::Long>(aPageSize.Width() * 1.03) );
+
+ aPagePos.AdjustY(aPageSize.Height() / 2 );
+ aPageSize.setHeight( static_cast<::tools::Long>(aPageSize.Height() * 1.03) );
+ aPagePos.AdjustY( -(aPageSize.Height() / 2) );
+
+ aPagePos.AdjustX( -(aPageSize.Width() / 2) );
+
+ ::tools::Rectangle aFullPageZoomRect( aPagePos, aPageSize );
+ aZoomItem.AddSnappingPoint( pActiveWindow->GetZoomForRect( aFullPageZoomRect ) );
+ }
+ aZoomItem.AddSnappingPoint(100);
+ rSet.Put( aZoomItem );
+ }
+ }
+
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+ if (pPageView)
+ {
+ Point aPos = GetActiveWindow()->PixelToLogic(maMousePos);
+ pPageView->LogicToPagePos(aPos);
+ Fraction aUIScale(GetDoc()->GetUIScale());
+ aPos.setX( ::tools::Long(aPos.X() / aUIScale) );
+ aPos.setY( ::tools::Long(aPos.Y() / aUIScale) );
+
+ // position- and size items
+ if ( mpDrawView->IsAction() )
+ {
+ ::tools::Rectangle aRect;
+ mpDrawView->TakeActionRect( aRect );
+
+ if ( aRect.IsEmpty() )
+ rSet.Put( SfxPointItem(SID_ATTR_POSITION, aPos) );
+ else
+ {
+ pPageView->LogicToPagePos(aRect);
+ aPos = aRect.TopLeft();
+ aPos.setX( ::tools::Long(aPos.X() / aUIScale) );
+ aPos.setY( ::tools::Long(aPos.Y() / aUIScale) );
+ rSet.Put( SfxPointItem( SID_ATTR_POSITION, aPos) );
+ Size aSize( aRect.Right() - aRect.Left(), aRect.Bottom() - aRect.Top() );
+ aSize.setHeight( ::tools::Long(aSize.Height() / aUIScale) );
+ aSize.setWidth( ::tools::Long(aSize.Width() / aUIScale) );
+ rSet.Put( SvxSizeItem( SID_ATTR_SIZE, aSize) );
+ }
+ }
+ else
+ {
+ if ( mpDrawView->AreObjectsMarked() )
+ {
+ ::tools::Rectangle aRect = mpDrawView->GetAllMarkedRect();
+ pPageView->LogicToPagePos(aRect);
+
+ // Show the position of the selected shape(s)
+ Point aShapePosition (aRect.TopLeft());
+ aShapePosition.setX( ::tools::Long(aShapePosition.X() / aUIScale) );
+ aShapePosition.setY( ::tools::Long(aShapePosition.Y() / aUIScale) );
+ rSet.Put (SfxPointItem(SID_ATTR_POSITION, aShapePosition));
+
+ Size aSize( aRect.Right() - aRect.Left(), aRect.Bottom() - aRect.Top() );
+ aSize.setHeight( ::tools::Long(aSize.Height() / aUIScale) );
+ aSize.setWidth( ::tools::Long(aSize.Width() / aUIScale) );
+ rSet.Put( SvxSizeItem( SID_ATTR_SIZE, aSize) );
+ }
+ else
+ {
+ rSet.Put( SfxPointItem(SID_ATTR_POSITION, aPos) );
+ rSet.Put( SvxSizeItem( SID_ATTR_SIZE, Size( 0, 0 ) ) );
+ }
+ }
+ }
+
+ // Display of current page and layer.
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_STATUS_PAGE ) )
+ {
+ sal_Int32 nPageCount = sal_Int32(GetDoc()->GetSdPageCount(mePageKind));
+ sal_Int32 nActivePageCount = sal_Int32(GetDoc()->GetActiveSdPageCount());
+ // Always show the slide/page number.
+ OUString aOUString = (nPageCount == nActivePageCount) ? SdResId(STR_SD_PAGE_COUNT) : SdResId(STR_SD_PAGE_COUNT_CUSTOM);
+
+ aOUString = aOUString.replaceFirst("%1", OUString::number(maTabControl->GetCurPagePos() + 1));
+ aOUString = aOUString.replaceFirst("%2", OUString::number(nPageCount));
+ if(nPageCount != nActivePageCount)
+ aOUString = aOUString.replaceFirst("%3", OUString::number(nActivePageCount));
+
+ // If in layer mode additionally show the layer that contains all
+ // selected shapes of the page. If the shapes are distributed on
+ // more than one layer, no layer name is shown.
+ if (IsLayerModeActive())
+ {
+ SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin();
+ SdrLayerID nLayer(0), nOldLayer(0);
+ SdrObject* pObj = nullptr;
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+ bool bOneLayer = true;
+
+ // Use the first ten selected shapes as a (hopefully
+ // representative) sample of all shapes of the current page.
+ // Detect whether they belong to the same layer.
+ for( size_t j = 0; j < nMarkCount && bOneLayer && j < 10; ++j )
+ {
+ pObj = rMarkList.GetMark( j )->GetMarkedSdrObj();
+ if( pObj )
+ {
+ nLayer = pObj->GetLayer();
+
+ if( j != 0 && nLayer != nOldLayer )
+ bOneLayer = false;
+
+ nOldLayer = nLayer;
+ }
+ }
+
+ // Append the layer name to the current page number.
+ if( bOneLayer && nMarkCount )
+ {
+ SdrLayer* pLayer = rLayerAdmin.GetLayerPerID( nLayer );
+ if( pLayer )
+ {
+ aOUString += " (" + LayerTabBar::convertToLocalizedName(pLayer->GetName()) + ")";
+ }
+ }
+ }
+
+ rSet.Put (SfxStringItem (SID_STATUS_PAGE, aOUString));
+ }
+ // Layout
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_STATUS_LAYOUT ) )
+ {
+ OUString aString = mpActualPage->GetLayoutName();
+ sal_Int32 nPos = aString.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ aString = aString.copy(0, nPos);
+ rSet.Put( SfxStringItem( SID_STATUS_LAYOUT, aString ) );
+ }
+ // Scale
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_SCALE ) )
+ {
+ const Fraction& aUIScale = GetDoc()->GetUIScale();
+ OUString aString = OUString::number(aUIScale.GetNumerator()) +
+ ":" + OUString::number(aUIScale.GetDenominator());
+ rSet.Put( SfxStringItem( SID_SCALE, aString ) );
+ }
+}
+
+void DrawViewShell::Notify (SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId()!=SfxHintId::ModeChanged)
+ return;
+
+ // Change to selection when turning on read-only mode.
+ if(GetDocSh()->IsReadOnly() && dynamic_cast< FuSelection* >( GetCurrentFunction().get() ) )
+ {
+ SfxRequest aReq(SID_OBJECT_SELECT, SfxCallMode::SLOT, GetDoc()->GetItemPool());
+ FuPermanent(aReq);
+ }
+
+ // Turn on design mode when document is not read-only.
+ if (GetDocSh()->IsReadOnly() != mbReadOnly )
+ {
+ mbReadOnly = GetDocSh()->IsReadOnly();
+
+ SfxBoolItem aItem( SID_FM_DESIGN_MODE, !mbReadOnly );
+ GetViewFrame()->GetDispatcher()->ExecuteList(SID_FM_DESIGN_MODE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+ }
+
+}
+
+void DrawViewShell::ExecuteAnnotation (SfxRequest const & rRequest)
+{
+ if (mpAnnotationManager)
+ mpAnnotationManager->ExecuteAnnotation( rRequest );
+}
+
+void DrawViewShell::GetAnnotationState (SfxItemSet& rItemSet )
+{
+ if (mpAnnotationManager)
+ mpAnnotationManager->GetAnnotationState( rItemSet );
+}
+
+OUString const & DrawViewShell::GetSidebarContextName() const
+{
+ svx::sidebar::SelectionAnalyzer::ViewType eViewType (svx::sidebar::SelectionAnalyzer::ViewType::Standard);
+ switch (mePageKind)
+ {
+ case PageKind::Handout:
+ eViewType = svx::sidebar::SelectionAnalyzer::ViewType::Handout;
+ break;
+ case PageKind::Notes:
+ eViewType = svx::sidebar::SelectionAnalyzer::ViewType::Notes;
+ break;
+ case PageKind::Standard:
+ if (meEditMode == EditMode::MasterPage)
+ eViewType = svx::sidebar::SelectionAnalyzer::ViewType::Master;
+ else
+ eViewType = svx::sidebar::SelectionAnalyzer::ViewType::Standard;
+ break;
+ }
+ return EnumContext::GetContextName(
+ svx::sidebar::SelectionAnalyzer::GetContextForSelection_SD(
+ mpDrawView->GetMarkedObjectList(),
+ eViewType));
+}
+
+void DrawViewShell::ExecGoToNextPage (SfxRequest& rReq)
+{
+ SetCurrentFunction( FuNavigation::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) );
+ Cancel();
+}
+
+void DrawViewShell::GetStateGoToNextPage (SfxItemSet& rSet)
+{
+ SdPage* pPage = GetActualPage();
+ sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2;
+ sal_uInt16 totalPages = GetDoc()->GetSdPageCount(pPage->GetPageKind());
+ if (nSdPage + 1 >= totalPages)
+ rSet.DisableItem( SID_GO_TO_NEXT_PAGE );
+}
+
+void DrawViewShell::ExecGoToPreviousPage (SfxRequest& rReq)
+{
+ SetCurrentFunction( FuNavigation::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) );
+ Cancel();
+}
+
+void DrawViewShell::GetStateGoToPreviousPage (SfxItemSet& rSet)
+{
+ SdPage* pPage = GetActualPage();
+ sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2;
+ if (nSdPage == 0)
+ rSet.DisableItem( SID_GO_TO_PREVIOUS_PAGE );
+}
+
+
+void DrawViewShell::ExecGoToFirstPage (SfxRequest& rReq)
+{
+ SetCurrentFunction( FuNavigation::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) );
+ Cancel();
+}
+
+void DrawViewShell::GetStateGoToFirstPage (SfxItemSet& rSet)
+{
+ SdPage* pPage = GetActualPage();
+ sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2;
+ if (nSdPage == 0)
+ rSet.DisableItem( SID_GO_TO_FIRST_PAGE );
+}
+
+void DrawViewShell::ExecGoToLastPage (SfxRequest& rReq)
+{
+ SetCurrentFunction( FuNavigation::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) );
+ Cancel();
+}
+
+void DrawViewShell::GetStateGoToLastPage (SfxItemSet& rSet)
+{
+ SdPage* pPage = GetActualPage();
+ sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2;
+ sal_uInt16 totalPages = GetDoc()->GetSdPageCount(pPage->GetPageKind());
+ if (nSdPage + 1 >= totalPages)
+ rSet.DisableItem( SID_GO_TO_LAST_PAGE );
+}
+
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewsb.cxx b/sd/source/ui/view/drviewsb.cxx
new file mode 100644
index 000000000..6f6bba855
--- /dev/null
+++ b/sd/source/ui/view/drviewsb.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 <svx/svdlayer.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/svxdlg.hxx>
+#include <osl/diagnose.h>
+
+#include <app.hrc>
+
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <unokywds.hxx>
+#include <sdpage.hxx>
+#include <DrawViewShell.hxx>
+#include <drawview.hxx>
+#include <unmodpg.hxx>
+#include <ViewShellBase.hxx>
+#include <FormShellManager.hxx>
+#include <LayerTabBar.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <SlideSorter.hxx>
+#include <controller/SlideSorterController.hxx>
+
+namespace sd {
+
+bool DrawViewShell::RenameSlide( sal_uInt16 nPageId, const OUString & rName )
+{
+ bool bOutDummy;
+ if( GetDoc()->GetPageByName( rName, bOutDummy ) != SDRPAGE_NOTFOUND )
+ return false;
+
+ SdPage* pPageToRename = nullptr;
+ PageKind ePageKind = GetPageKind();
+
+ if( GetEditMode() == EditMode::Page )
+ {
+ pPageToRename = GetDoc()->GetSdPage( maTabControl->GetPagePos(nPageId), ePageKind );
+
+ // Undo
+ SdPage* pUndoPage = pPageToRename;
+ SdrLayerAdmin & rLayerAdmin = GetDoc()->GetLayerAdmin();
+ SdrLayerID nBackground = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID nBgObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ SdrLayerIDSet aVisibleLayers = mpActualPage->TRG_GetMasterPageVisibleLayers();
+
+ SfxUndoManager* pManager = GetDoc()->GetDocSh()->GetUndoManager();
+ pManager->AddUndoAction(
+ std::make_unique<ModifyPageUndoAction>(
+ GetDoc(), pUndoPage, rName, pUndoPage->GetAutoLayout(),
+ aVisibleLayers.IsSet( nBackground ),
+ aVisibleLayers.IsSet( nBgObj )));
+
+ // rename
+ pPageToRename->SetName( rName );
+
+ if( ePageKind == PageKind::Standard )
+ {
+ // also rename notes-page
+ SdPage* pNotesPage = GetDoc()->GetSdPage( maTabControl->GetPagePos(nPageId), PageKind::Notes );
+ pNotesPage->SetName( rName );
+ }
+ }
+ else
+ {
+ // rename MasterPage -> rename LayoutTemplate
+ pPageToRename = GetDoc()->GetMasterSdPage( maTabControl->GetPagePos(nPageId), ePageKind );
+ GetDoc()->RenameLayoutTemplate( pPageToRename->GetLayoutName(), rName );
+ }
+
+ bool bSuccess = (rName == pPageToRename->GetName());
+
+ if( bSuccess )
+ {
+ // user edited page names may be changed by the page so update control
+ maTabControl->SetPageText( nPageId, rName );
+
+ // set document to modified state
+ GetDoc()->SetChanged();
+
+ // inform navigator about change
+ if (GetViewFrame())
+ {
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_NAVIGATOR_STATE, true);
+ }
+
+ // Tell the slide sorter about the name change (necessary for
+ // accessibility.)
+ slidesorter::SlideSorterViewShell* pSlideSorterViewShell
+ = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase());
+ if (pSlideSorterViewShell != nullptr)
+ {
+ pSlideSorterViewShell->GetSlideSorter().GetController().PageNameHasChanged(
+ maTabControl->GetPagePos(nPageId), rName);
+ }
+ }
+
+ return bSuccess;
+}
+
+IMPL_LINK( DrawViewShell, RenameSlideHdl, AbstractSvxNameDialog&, rDialog, bool )
+{
+ OUString aNewName;
+ rDialog.GetName( aNewName );
+
+ SdPage* pCurrentPage = GetDoc()->GetSdPage( maTabControl->GetCurPagePos(), GetPageKind() );
+
+ return pCurrentPage && ( aNewName == pCurrentPage->GetName() || GetDocSh()->IsNewPageNameValid( aNewName ) );
+}
+
+void DrawViewShell::ModifyLayer (
+ SdrLayer* pLayer,
+ const OUString& rLayerName,
+ const OUString& rLayerTitle,
+ const OUString& rLayerDesc,
+ bool bIsVisible,
+ bool bIsLocked,
+ bool bIsPrintable)
+{
+ if(!GetLayerTabControl()) // #i87182#
+ {
+ OSL_ENSURE(false, "No LayerTabBar (!)");
+ return;
+ }
+
+ if( !pLayer )
+ return;
+
+ const sal_uInt16 nPageCount = GetLayerTabControl()->GetPageCount();
+ sal_uInt16 nCurPage = 0;
+ sal_uInt16 nPos;
+ for( nPos = 0; nPos < nPageCount; nPos++ )
+ {
+ sal_uInt16 nId = GetLayerTabControl()->GetPageId( nPos );
+ if (GetLayerTabControl()->GetLayerName(nId) == pLayer->GetName())
+ {
+ nCurPage = nId;
+ break;
+ }
+ }
+
+ pLayer->SetName( rLayerName );
+ pLayer->SetTitle( rLayerTitle );
+ pLayer->SetDescription( rLayerDesc );
+ mpDrawView->SetLayerVisible( rLayerName, bIsVisible );
+ mpDrawView->SetLayerLocked( rLayerName, bIsLocked);
+ mpDrawView->SetLayerPrintable(rLayerName, bIsPrintable);
+
+ GetDoc()->SetChanged();
+
+ GetLayerTabControl()->SetPageText(nCurPage, rLayerName);
+
+ // Set page bits for modified tab name display
+
+ TabBarPageBits nBits = TabBarPageBits::NONE;
+
+ if (!bIsVisible)
+ {
+ nBits = TabBarPageBits::Blue;
+ }
+ if (bIsLocked)
+ {
+ nBits |= TabBarPageBits::Italic;
+ }
+ if (!bIsPrintable)
+ {
+ nBits |= TabBarPageBits::Underline;
+ }
+
+ // Save the bits
+
+ GetLayerTabControl()->SetPageBits(nCurPage, nBits);
+
+ GetViewFrame()->GetDispatcher()->Execute(
+ SID_SWITCHLAYER,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+
+ // Call Invalidate at the form shell.
+ FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell();
+ if (pFormShell != nullptr)
+ pFormShell->Invalidate();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewsc.cxx b/sd/source/ui/view/drviewsc.cxx
new file mode 100644
index 000000000..6be86e63c
--- /dev/null
+++ b/sd/source/ui/view/drviewsc.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawViewShell.hxx>
+
+#include <svx/imapdlg.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/ImageMapInfo.hxx>
+
+#include <sfx2/viewfrm.hxx>
+
+#include <drawdoc.hxx>
+#include <drawview.hxx>
+#include <memory>
+
+namespace sd {
+
+void DrawViewShell::UpdateIMapDlg( SdrObject* pObj )
+{
+ if( ( dynamic_cast< SdrGrafObj *>( pObj ) == nullptr && dynamic_cast< SdrOle2Obj *>( pObj ) == nullptr )
+ || mpDrawView->IsTextEdit()
+ || !GetViewFrame()->HasChildWindow( SvxIMapDlgChildWindow::GetChildWindowId() ) )
+ return;
+
+ Graphic aGraphic;
+ ImageMap* pIMap = nullptr;
+ std::unique_ptr<TargetList> pTargetList;
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo( pObj );
+
+ // get graphic from shape
+ SdrGrafObj* pGrafObj = dynamic_cast< SdrGrafObj* >( pObj );
+ if( pGrafObj )
+ aGraphic = pGrafObj->GetGraphic();
+
+ if ( pIMapInfo )
+ {
+ pIMap = const_cast<ImageMap*>(&pIMapInfo->GetImageMap());
+ pTargetList.reset(new TargetList);
+ SfxViewFrame::GetTargetList( *pTargetList );
+ }
+
+ SvxIMapDlgChildWindow::UpdateIMapDlg( aGraphic, pIMap, pTargetList.get(), pObj );
+}
+
+IMPL_LINK( DrawViewShell, NameObjectHdl, AbstractSvxObjectNameDialog&, rDialog, bool )
+{
+ OUString aName;
+ rDialog.GetName( aName );
+ return aName.isEmpty() || ( GetDoc() && !GetDoc()->GetObj( aName ) );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewsd.cxx b/sd/source/ui/view/drviewsd.cxx
new file mode 100644
index 000000000..31fe06dde
--- /dev/null
+++ b/sd/source/ui/view/drviewsd.cxx
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawViewShell.hxx>
+
+#include <svx/svxids.hrc>
+#include <svl/stritem.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/docfile.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
+
+#include <sfx2/viewfrm.hxx>
+
+#include <app.hrc>
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <pgjump.hxx>
+#include <navigatr.hxx>
+#include <drawview.hxx>
+
+namespace sd {
+
+/**
+ * handle SfxRequests for navigator
+ */
+void DrawViewShell::ExecNavigatorWin( SfxRequest& rReq )
+{
+ CheckLineTo (rReq);
+
+ sal_uInt16 nSId = rReq.GetSlot();
+
+ switch( nSId )
+ {
+ case SID_NAVIGATOR_INIT:
+ {
+ SfxChildWindow* pWindow = GetViewFrame()->GetChildWindow( SID_NAVIGATOR );
+ if( pWindow )
+ {
+ SdNavigatorFloat* pNavWin = static_cast<SdNavigatorFloat*>(pWindow->GetWindow());
+ if( pNavWin )
+ pNavWin->InitTreeLB( GetDoc() );
+ }
+ }
+ break;
+
+ case SID_NAVIGATOR_PAGE:
+ case SID_NAVIGATOR_OBJECT:
+ {
+ if (nSId == SID_NAVIGATOR_PAGE)
+ {
+ if ( mpDrawView->IsTextEdit() )
+ mpDrawView->SdrEndTextEdit();
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ PageJump eJump = static_cast<PageJump>(static_cast<const SfxUInt16Item&>( pArgs->
+ Get(SID_NAVIGATOR_PAGE)).GetValue());
+
+ switch (eJump)
+ {
+ case PAGE_FIRST:
+ {
+ // jump to first page
+ SwitchPage(0);
+ }
+ break;
+
+ case PAGE_LAST:
+ {
+ // jump to last page
+ SwitchPage(GetDoc()->GetSdPageCount(mpActualPage->GetPageKind()) - 1);
+ }
+ break;
+
+ case PAGE_NEXT:
+ {
+ // jump to next page
+ sal_uInt16 nSdPage = (mpActualPage->GetPageNum() - 1) / 2;
+
+ if (nSdPage < GetDoc()->GetSdPageCount(mpActualPage->GetPageKind()) - 1)
+ {
+ SwitchPage(nSdPage + 1);
+ }
+ }
+ break;
+
+ case PAGE_PREVIOUS:
+ {
+ // jump to previous page
+ sal_uInt16 nSdPage = (mpActualPage->GetPageNum() - 1) / 2;
+
+ if (nSdPage > 0)
+ {
+ SwitchPage(nSdPage - 1);
+ }
+ }
+ break;
+
+ case PAGE_NONE:
+ break;
+ }
+ }
+ else if (nSId == SID_NAVIGATOR_OBJECT)
+ {
+ OUString aBookmarkStr("#");
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ OUString aTarget = static_cast<const SfxStringItem&>( pArgs->
+ Get(SID_NAVIGATOR_OBJECT)).GetValue();
+ aBookmarkStr += aTarget;
+ SfxStringItem aStrItem(SID_FILE_NAME, aBookmarkStr);
+ SfxStringItem aReferer(SID_REFERER, GetDocSh()->GetMedium()->GetName());
+ SfxViewFrame* pFrame = GetViewFrame();
+ SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
+ SfxBoolItem aBrowseItem(SID_BROWSE, true);
+ pFrame->GetDispatcher()->
+ ExecuteList(SID_OPENDOC, SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
+ }
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_NAVIGATOR_STATE );
+ rBindings.Invalidate( SID_NAVIGATOR_PAGENAME );
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void DrawViewShell::GetNavigatorWinState( SfxItemSet& rSet )
+{
+ NavState nState = NavState::NONE;
+ sal_uInt16 nCurrentPage = 0;
+ sal_uInt16 nLastPage;
+ OUString aPageName;
+
+ nState |= NavState::TableUpdate;
+
+ if (mpActualPage != nullptr)
+ {
+ nCurrentPage = ( mpActualPage->GetPageNum() - 1 ) / 2;
+ aPageName = mpActualPage->GetName();
+ }
+ nLastPage = GetDoc()->GetSdPageCount( mePageKind ) - 1;
+
+
+ // first page / previous page
+ if( nCurrentPage == 0 )
+ {
+ nState |= NavState::BtnFirstDisabled | NavState::BtnPrevDisabled;
+ }
+ else
+ {
+ nState |= NavState::BtnFirstEnabled | NavState::BtnPrevEnabled;
+ }
+
+ // last page / next page
+ if( nCurrentPage == nLastPage )
+ {
+ nState |= NavState::BtnLastDisabled | NavState::BtnNextDisabled;
+ }
+ else
+ {
+ nState |= NavState::BtnLastEnabled | NavState::BtnNextEnabled;
+ }
+
+ rSet.Put( SfxUInt32Item( SID_NAVIGATOR_STATE, static_cast<sal_uInt32>(nState) ) );
+ rSet.Put( SfxStringItem( SID_NAVIGATOR_PAGENAME, aPageName ) );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewse.cxx b/sd/source/ui/view/drviewse.cxx
new file mode 100644
index 000000000..309eb2b85
--- /dev/null
+++ b/sd/source/ui/view/drviewse.cxx
@@ -0,0 +1,1701 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <com/sun/star/presentation/XPresentation2.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <i18nutil/unicode.hxx>
+#include <i18nutil/transliteration.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/Any.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/outlobj.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svl/urlbmk.hxx>
+#include <svx/clipfmtitem.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdorect.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/poolitem.hxx>
+#include <svl/stritem.hxx>
+#include <editeng/eeitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/request.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/flditem.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/svdobjkind.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <tools/urlobj.hxx>
+#include <sfx2/ipclient.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <svl/urihelper.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/notebookbar/SfxNotebookBar.hxx>
+#include <osl/diagnose.h>
+
+#include <DrawViewShell.hxx>
+#include <slideshow.hxx>
+#include <ViewShellHint.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <app.hrc>
+#include <strings.hrc>
+
+#include <drawdoc.hxx>
+#include <fusel.hxx>
+#include <futext.hxx>
+#include <fuconrec.hxx>
+#include <fuconcs.hxx>
+#include <fuconuno.hxx>
+#include <fuconbez.hxx>
+#include <fuediglu.hxx>
+#include <fuconarc.hxx>
+#include <fucon3d.hxx>
+#include <sdresid.hxx>
+#include <unokywds.hxx>
+#include <Outliner.hxx>
+#include <sdpage.hxx>
+#include <FrameView.hxx>
+#include <zoomlist.hxx>
+#include <drawview.hxx>
+#include <DrawDocShell.hxx>
+#include <ViewShellBase.hxx>
+#include <ToolBarManager.hxx>
+#include <anminfo.hxx>
+#include <optsitem.hxx>
+#include <Window.hxx>
+#include <fuformatpaintbrush.hxx>
+#include <fuzoom.hxx>
+#include <sdmod.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::beans;
+
+namespace sd {
+
+// Permanent Functions
+
+static void ImpAddPrintableCharactersToTextEdit(SfxRequest const & rReq, ::sd::View* pView)
+{
+ // evtl. feed characters to activated textedit
+ const SfxItemSet* pSet = rReq.GetArgs();
+
+ if(!pSet)
+ return;
+
+ OUString aInputString;
+
+ if(SfxItemState::SET == pSet->GetItemState(SID_ATTR_CHAR))
+ aInputString = static_cast<const SfxStringItem&>(pSet->Get(SID_ATTR_CHAR)).GetValue();
+
+ if(aInputString.isEmpty())
+ return;
+
+ OutlinerView* pOLV = pView->GetTextEditOutlinerView();
+
+ if(pOLV)
+ {
+ for(sal_Int32 a(0); a < aInputString.getLength(); a++)
+ {
+ vcl::KeyCode aKeyCode;
+ // tdf#38669 - create the key event using a Unicode character
+ KeyEvent aKeyEvent(aInputString[a], aKeyCode);
+
+ // add actual character
+ pOLV->PostKeyEvent(aKeyEvent);
+ }
+ }
+}
+
+void DrawViewShell::FuPermanent(SfxRequest& rReq)
+{
+ // We do not execute a thing during a native slide show
+
+ if (SlideShow::IsRunning(GetViewShellBase()))
+ return;
+
+ sal_uInt16 nSId = rReq.GetSlot();
+
+ if( HasCurrentFunction() &&
+ ( nSId == SID_TEXTEDIT || nSId == SID_ATTR_CHAR || nSId == SID_TEXT_FITTOSIZE ||
+ nSId == SID_ATTR_CHAR_VERTICAL || nSId == SID_TEXT_FITTOSIZE_VERTICAL ) )
+ {
+ rtl::Reference<FuPoor> xFunc( GetCurrentFunction() );
+
+ FuText* pFuText = dynamic_cast< FuText* >( xFunc.get() );
+
+ if( pFuText )
+ {
+ pFuText->SetPermanent(true);
+ xFunc->ReceiveRequest( rReq );
+
+ Invalidate();
+
+ // evtl. feed characters to activated textedit
+ if(SID_ATTR_CHAR == nSId && GetView() && GetView()->IsTextEdit())
+ ImpAddPrintableCharactersToTextEdit(rReq, GetView());
+
+ rReq.Done();
+ return;
+ }
+ }
+
+ CheckLineTo (rReq);
+ sal_uInt16 nOldSId = 0;
+ bool bPermanent = false;
+
+ if( !mpDrawView )
+ return;
+
+ if(HasCurrentFunction())
+ {
+ if( (nSId == SID_FORMATPAINTBRUSH) && (GetCurrentFunction()->GetSlotID() == SID_TEXTEDIT) )
+ {
+ // save text edit mode for format paintbrush!
+ SetOldFunction( GetCurrentFunction() );
+ }
+ else
+ {
+ if(GetOldFunction() == GetCurrentFunction())
+ {
+ SetOldFunction(nullptr);
+ }
+ }
+
+ if ( nSId != SID_TEXTEDIT && nSId != SID_ATTR_CHAR && nSId != SID_TEXT_FITTOSIZE &&
+ nSId != SID_ATTR_CHAR_VERTICAL && nSId != SID_TEXT_FITTOSIZE_VERTICAL &&
+ nSId != SID_FORMATPAINTBRUSH &&
+ mpDrawView->IsTextEdit() )
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ if( HasCurrentFunction() )
+ {
+ nOldSId = GetCurrentFunction()->GetSlotID();
+
+ if (nOldSId == nSId ||
+ ((nOldSId == SID_TEXTEDIT || nOldSId == SID_ATTR_CHAR || nOldSId == SID_TEXT_FITTOSIZE ||
+ nOldSId == SID_ATTR_CHAR_VERTICAL || nOldSId == SID_TEXT_FITTOSIZE_VERTICAL) &&
+ (nSId == SID_TEXTEDIT || nSId == SID_ATTR_CHAR || nSId == SID_TEXT_FITTOSIZE ||
+ nSId == SID_ATTR_CHAR_VERTICAL || nSId == SID_TEXT_FITTOSIZE_VERTICAL )))
+ {
+ bPermanent = true;
+ }
+
+ GetCurrentFunction()->Deactivate();
+ }
+
+ SetCurrentFunction(nullptr);
+
+ SfxBindings& rBind = GetViewFrame()->GetBindings();
+ rBind.Invalidate(nOldSId);
+ rBind.Update(nOldSId);
+ }
+
+ // for LibreOfficeKit - choosing a shape should construct it directly
+ bool bCreateDirectly = false;
+
+ switch ( nSId )
+ {
+ case SID_TEXTEDIT: // BASIC ???
+ case SID_ATTR_CHAR:
+ case SID_ATTR_CHAR_VERTICAL:
+ case SID_TEXT_FITTOSIZE:
+ case SID_TEXT_FITTOSIZE_VERTICAL:
+ {
+ SetCurrentFunction( FuText::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) );
+ GetCurrentFunction()->DoExecute(rReq);
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_ATTR_CHAR );
+ rBindings.Invalidate( SID_ATTR_CHAR_VERTICAL );
+ rBindings.Invalidate( SID_TEXT_FITTOSIZE );
+ rBindings.Invalidate( SID_TEXT_FITTOSIZE_VERTICAL );
+
+ // evtl. feed characters to activated textedit
+ if(SID_ATTR_CHAR == nSId && GetView() && GetView()->IsTextEdit())
+ ImpAddPrintableCharactersToTextEdit(rReq, GetView());
+
+ rReq.Done();
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if (pArgs && pArgs->HasItem(FN_PARAM_1))
+ bCreateDirectly = static_cast<const SfxBoolItem&>(pArgs->Get(FN_PARAM_1)).GetValue();
+ }
+ break;
+
+ case SID_FM_CREATE_CONTROL:
+ {
+ SetCurrentFunction( FuConstructUnoControl::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent ) );
+ rReq.Done();
+ }
+ break;
+
+ case SID_FM_CREATE_FIELDCONTROL:
+ {
+ const SfxUnoAnyItem* pDescriptorItem = rReq.GetArg<SfxUnoAnyItem>(SID_FM_DATACCESS_DESCRIPTOR);
+ DBG_ASSERT( pDescriptorItem, "DrawViewShell::FuPermanent(SID_FM_CREATE_FIELDCONTROL): invalid request args!" );
+
+ if(pDescriptorItem)
+ {
+ // get the form view
+ FmFormView* pFormView = mpDrawView.get();
+ SdrPageView* pPageView = pFormView ? pFormView->GetSdrPageView() : nullptr;
+
+ if(pPageView)
+ {
+ svx::ODataAccessDescriptor aDescriptor(pDescriptorItem->GetValue());
+ SdrObjectUniquePtr pNewDBField = pFormView->CreateFieldControl(aDescriptor);
+
+ if(pNewDBField)
+ {
+ ::tools::Rectangle aVisArea = GetActiveWindow()->PixelToLogic(::tools::Rectangle(Point(0,0), GetActiveWindow()->GetOutputSizePixel()));
+ Point aObjPos(aVisArea.Center());
+ Size aObjSize(pNewDBField->GetLogicRect().GetSize());
+ aObjPos.AdjustX( -(aObjSize.Width() / 2) );
+ aObjPos.AdjustY( -(aObjSize.Height() / 2) );
+ ::tools::Rectangle aNewObjectRectangle(aObjPos, aObjSize);
+
+ pNewDBField->SetLogicRect(aNewObjectRectangle);
+
+ GetView()->InsertObjectAtView(pNewDBField.release(), *pPageView);
+ }
+ }
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_OBJECT_SELECT:
+ case SID_OBJECT_ROTATE:
+ case SID_OBJECT_MIRROR:
+ case SID_OBJECT_CROP:
+ case SID_OBJECT_TRANSPARENCE:
+ case SID_OBJECT_GRADIENT:
+ case SID_OBJECT_SHEAR:
+ case SID_OBJECT_CROOK_ROTATE:
+ case SID_OBJECT_CROOK_SLANT:
+ case SID_OBJECT_CROOK_STRETCH:
+ case SID_CONVERT_TO_3D_LATHE:
+ {
+ sal_uInt16 nSlotId = rReq.GetSlot();
+
+ // toggle function
+ if( nOldSId == nSlotId )
+ {
+ nSlotId = SID_OBJECT_SELECT;
+ rReq.SetSlot( nSlotId );
+ }
+
+ if (nSlotId == SID_OBJECT_CROOK_ROTATE ||
+ nSlotId == SID_OBJECT_CROOK_SLANT ||
+ nSlotId == SID_OBJECT_CROOK_STRETCH)
+ {
+ if ( mpDrawView->GetMarkedObjectList().GetMarkCount() > 0 &&
+ !mpDrawView->IsCrookAllowed( mpDrawView->IsCrookNoContortion() ) )
+ {
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ SdResId(STR_ASK_FOR_CONVERT_TO_BEZIER)));
+ if (xQueryBox->run() == RET_YES )
+ {
+ // implicit transformation into bezier
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->ConvertMarkedToPathObj(false);
+ }
+ }
+ }
+ }
+ else if (nSlotId == SID_OBJECT_SHEAR)
+ {
+ size_t i = 0;
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ const size_t nMarkCnt = rMarkList.GetMarkCount();
+ bool b3DObjMarked = false;
+
+ while (i < nMarkCnt && !b3DObjMarked)
+ {
+ if (nullptr != dynamic_cast< E3dObject *>( rMarkList.GetMark(i)->GetMarkedSdrObj() ))
+ {
+ b3DObjMarked = true;
+ }
+ else
+ {
+ i++;
+ }
+ }
+
+ if ( nMarkCnt > 0 && !b3DObjMarked &&
+ (!mpDrawView->IsShearAllowed() || !mpDrawView->IsDistortAllowed()) )
+ {
+ if ( mpDrawView->IsPresObjSelected() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ SdResId(STR_ASK_FOR_CONVERT_TO_BEZIER)));
+ if (xQueryBox->run() == RET_YES)
+ {
+ // implicit transformation into bezier
+ weld::WaitObject aWait(GetFrameWeld());
+ mpDrawView->ConvertMarkedToPathObj(false);
+ }
+ }
+ }
+ }
+
+ SetCurrentFunction( FuSelection::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) );
+ rReq.Done();
+ Invalidate( SID_OBJECT_SELECT );
+ }
+ break;
+
+ case SID_DRAW_LINE:
+ case SID_DRAW_XLINE:
+ case SID_DRAW_MEASURELINE:
+ case SID_LINE_ARROW_START:
+ case SID_LINE_ARROW_END:
+ case SID_LINE_ARROWS:
+ case SID_LINE_ARROW_CIRCLE:
+ case SID_LINE_CIRCLE_ARROW:
+ case SID_LINE_ARROW_SQUARE:
+ case SID_LINE_SQUARE_ARROW:
+
+ case SID_DRAW_RECT:
+ case SID_DRAW_RECT_NOFILL:
+ case SID_DRAW_RECT_ROUND:
+ case SID_DRAW_RECT_ROUND_NOFILL:
+ case SID_DRAW_SQUARE:
+ case SID_DRAW_SQUARE_NOFILL:
+ case SID_DRAW_SQUARE_ROUND:
+ case SID_DRAW_SQUARE_ROUND_NOFILL:
+ case SID_DRAW_ELLIPSE:
+ case SID_DRAW_ELLIPSE_NOFILL:
+ case SID_DRAW_CIRCLE:
+ case SID_DRAW_CIRCLE_NOFILL:
+ case SID_DRAW_CAPTION:
+ case SID_DRAW_CAPTION_VERTICAL:
+ case SID_TOOL_CONNECTOR:
+ case SID_CONNECTOR_ARROW_START:
+ case SID_CONNECTOR_ARROW_END:
+ case SID_CONNECTOR_ARROWS:
+ case SID_CONNECTOR_CIRCLE_START:
+ case SID_CONNECTOR_CIRCLE_END:
+ case SID_CONNECTOR_CIRCLES:
+ case SID_CONNECTOR_LINE:
+ case SID_CONNECTOR_LINE_ARROW_START:
+ case SID_CONNECTOR_LINE_ARROW_END:
+ case SID_CONNECTOR_LINE_ARROWS:
+ case SID_CONNECTOR_LINE_CIRCLE_START:
+ case SID_CONNECTOR_LINE_CIRCLE_END:
+ case SID_CONNECTOR_LINE_CIRCLES:
+ case SID_CONNECTOR_CURVE:
+ case SID_CONNECTOR_CURVE_ARROW_START:
+ case SID_CONNECTOR_CURVE_ARROW_END:
+ case SID_CONNECTOR_CURVE_ARROWS:
+ case SID_CONNECTOR_CURVE_CIRCLE_START:
+ case SID_CONNECTOR_CURVE_CIRCLE_END:
+ case SID_CONNECTOR_CURVE_CIRCLES:
+ case SID_CONNECTOR_LINES:
+ case SID_CONNECTOR_LINES_ARROW_START:
+ case SID_CONNECTOR_LINES_ARROW_END:
+ case SID_CONNECTOR_LINES_ARROWS:
+ case SID_CONNECTOR_LINES_CIRCLE_START:
+ case SID_CONNECTOR_LINES_CIRCLE_END:
+ case SID_CONNECTOR_LINES_CIRCLES:
+ case SID_INSERT_SIGNATURELINE:
+ {
+ bCreateDirectly = comphelper::LibreOfficeKit::isActive();
+ SetCurrentFunction( FuConstructRectangle::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent ) );
+ rReq.Done();
+ }
+ break;
+ case SID_DRAW_POLYGON:
+ case SID_DRAW_POLYGON_NOFILL:
+ case SID_DRAW_XPOLYGON:
+ case SID_DRAW_XPOLYGON_NOFILL:
+ case SID_DRAW_FREELINE:
+ case SID_DRAW_FREELINE_NOFILL:
+ case SID_DRAW_BEZIER_FILL: // BASIC
+ case SID_DRAW_BEZIER_NOFILL: // BASIC
+ {
+ SetCurrentFunction( FuConstructBezierPolygon::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent) );
+ rReq.Done();
+ }
+ break;
+
+ case SID_GLUE_EDITMODE:
+ {
+ if (nOldSId != SID_GLUE_EDITMODE)
+ {
+ SetCurrentFunction( FuEditGluePoints::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent ) );
+ }
+ else
+ {
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ }
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_DRAW_ARC:
+ case SID_DRAW_CIRCLEARC:
+ case SID_DRAW_PIE:
+ case SID_DRAW_PIE_NOFILL:
+ case SID_DRAW_CIRCLEPIE:
+ case SID_DRAW_CIRCLEPIE_NOFILL:
+ case SID_DRAW_ELLIPSECUT:
+ case SID_DRAW_ELLIPSECUT_NOFILL:
+ case SID_DRAW_CIRCLECUT:
+ case SID_DRAW_CIRCLECUT_NOFILL:
+ {
+ SetCurrentFunction( FuConstructArc::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent) );
+ rReq.Done();
+ }
+ break;
+
+ case SID_3D_CUBE:
+ case SID_3D_SHELL:
+ case SID_3D_SPHERE:
+ case SID_3D_TORUS:
+ case SID_3D_HALF_SPHERE:
+ case SID_3D_CYLINDER:
+ case SID_3D_CONE:
+ case SID_3D_PYRAMID:
+ {
+ SetCurrentFunction( FuConstruct3dObject::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent ) );
+ rReq.Done();
+ }
+ break;
+
+ case SID_DRAWTBX_CS_BASIC :
+ case SID_DRAWTBX_CS_SYMBOL :
+ case SID_DRAWTBX_CS_ARROW :
+ case SID_DRAWTBX_CS_FLOWCHART :
+ case SID_DRAWTBX_CS_CALLOUT :
+ case SID_DRAWTBX_CS_STAR :
+ case SID_DRAW_CS_ID :
+ {
+ SetCurrentFunction( FuConstructCustomShape::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent ) );
+ rReq.Done();
+
+ bCreateDirectly = comphelper::LibreOfficeKit::isActive();
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if (pArgs && pArgs->HasItem(FN_PARAM_1))
+ {
+ bCreateDirectly = static_cast<const SfxBoolItem&>(pArgs->Get(FN_PARAM_1)).GetValue();
+ }
+
+ if ( nSId != SID_DRAW_CS_ID )
+ {
+ SfxBindings& rBind = GetViewFrame()->GetBindings();
+ rBind.Invalidate( nSId );
+ rBind.Update( nSId );
+ }
+ }
+ break;
+
+ case SID_FORMATPAINTBRUSH:
+ {
+ SetCurrentFunction( FuFormatPaintBrush::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ rReq.Done();
+ SfxBindings& rBind = GetViewFrame()->GetBindings();
+ rBind.Invalidate( nSId );
+ rBind.Update( nSId );
+ break;
+ }
+
+ case SID_ZOOM_MODE:
+ case SID_ZOOM_PANNING:
+ {
+ if (nOldSId != nSId)
+ {
+ mbZoomOnPage = false;
+ SetCurrentFunction( FuZoom::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) );
+ }
+ else
+ {
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+ }
+ rReq.Done();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if(HasOldFunction())
+ {
+ sal_uInt16 nSlotId = GetOldFunction()->GetSlotID();
+
+ GetOldFunction()->Deactivate();
+ SetOldFunction(nullptr);
+
+ SfxBindings& rBind = GetViewFrame()->GetBindings();
+ rBind.Invalidate( nSlotId );
+ rBind.Update( nSlotId );
+ }
+
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->Activate();
+ SetOldFunction( GetCurrentFunction() );
+ }
+
+ // invalidate shell, is faster than every individually (says MI)
+ // now explicit the last slot incl. Update()
+ Invalidate();
+
+ // CTRL-SID_OBJECT_SELECT -> select first draw object if none is selected yet
+ if(SID_OBJECT_SELECT == nSId && HasCurrentFunction() && (rReq.GetModifier() & KEY_MOD1))
+ {
+ if(!GetView()->AreObjectsMarked())
+ {
+ // select first object
+ GetView()->UnmarkAllObj();
+ GetView()->MarkNextObj(true);
+
+ // ...and make it visible
+ if(GetView()->AreObjectsMarked())
+ GetView()->MakeVisible(GetView()->GetAllMarkedRect(), *GetActiveWindow());
+ }
+ }
+
+ // with qualifier construct directly
+ if(!(HasCurrentFunction() && ((rReq.GetModifier() & KEY_MOD1) || bCreateDirectly)))
+ return;
+
+ // disable interactive drawing for LOK
+ if (bCreateDirectly)
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+
+ // get SdOptions
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDoc()->GetDocumentType());
+ sal_uInt32 nDefaultObjectSizeWidth(pOptions->GetDefaultObjectSizeWidth());
+ sal_uInt32 nDefaultObjectSizeHeight(pOptions->GetDefaultObjectSizeHeight());
+
+ // calc position and size
+ ::tools::Rectangle aVisArea = GetActiveWindow()->PixelToLogic(::tools::Rectangle(Point(0,0), GetActiveWindow()->GetOutputSizePixel()));
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // aVisArea is nonsensical in the LOK case, use the slide size
+ aVisArea = ::tools::Rectangle(Point(), getCurrentPage()->GetSize());
+ }
+
+ Point aPagePos = aVisArea.Center();
+ aPagePos.AdjustX( -sal_Int32(nDefaultObjectSizeWidth / 2) );
+ aPagePos.AdjustY( -sal_Int32(nDefaultObjectSizeHeight / 2) );
+ ::tools::Rectangle aNewObjectRectangle(aPagePos, Size(nDefaultObjectSizeWidth, nDefaultObjectSizeHeight));
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ // create the default object
+ SdrObjectUniquePtr pObj = GetCurrentFunction()->CreateDefaultObject(nSId, aNewObjectRectangle);
+
+ if(!pObj)
+ return;
+
+ auto pObjTmp = pObj.get();
+ // insert into page
+ GetView()->InsertObjectAtView(pObj.release(), *pPageView);
+
+ // Now that pFuActual has done what it was created for we
+ // can switch on the edit mode for callout objects.
+ switch (nSId)
+ {
+ case SID_DRAW_CAPTION:
+ case SID_DRAW_CAPTION_VERTICAL:
+ {
+ // Make FuText the current function.
+ SfxUInt16Item aItem (SID_TEXTEDIT, 1);
+ GetViewFrame()->GetDispatcher()->
+ ExecuteList(SID_TEXTEDIT, SfxCallMode::SYNCHRON |
+ SfxCallMode::RECORD, { &aItem });
+ // Put text object into edit mode.
+ GetView()->SdrBeginTextEdit(static_cast<SdrTextObj*>(pObjTmp), pPageView);
+ break;
+ }
+ }
+}
+
+void DrawViewShell::FuDeleteSelectedObjects()
+{
+ if( !mpDrawView )
+ return;
+
+ bool bConsumed = false;
+
+ //if any placeholders are selected
+ if (mpDrawView->IsPresObjSelected(false))
+ {
+ //If there are placeholders in the list which can be toggled
+ //off in edit->master->master elements then do that here,
+ std::vector<SdrObject*> aPresMarksToRemove;
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ for (size_t i=0; i < rMarkList.GetMarkCount(); ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ SdPage* pPage = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject());
+ PresObjKind eKind = pPage->GetPresObjKind(pObj);
+ if (eKind == PresObjKind::Footer || eKind == PresObjKind::Header ||
+ eKind == PresObjKind::DateTime || eKind == PresObjKind::SlideNumber)
+ {
+ aPresMarksToRemove.push_back(pObj);
+ }
+ }
+
+ for (SdrObject* pObj : aPresMarksToRemove)
+ {
+ //Unmark object
+ mpDrawView->MarkObj(pObj, mpDrawView->GetSdrPageView(), true);
+ SdPage* pPage = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject());
+ //remove placeholder from master page
+ pPage->DestroyDefaultPresObj(pPage->GetPresObjKind(pObj));
+ }
+
+ bConsumed = true;
+ }
+
+ // placeholders which cannot be deleted selected
+ if (mpDrawView->IsPresObjSelected(false, true, false, true))
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ bConsumed = true;
+ }
+
+ if (bConsumed)
+ return;
+
+ vcl::KeyCode aKCode(KEY_DELETE);
+ KeyEvent aKEvt( 0, aKCode);
+
+ bConsumed = mpDrawView->getSmartTags().KeyInput( aKEvt );
+
+ if (!bConsumed && HasCurrentFunction())
+ bConsumed = GetCurrentFunction()->KeyInput(aKEvt);
+
+ if (!bConsumed)
+ mpDrawView->DeleteMarked();
+}
+
+void DrawViewShell::FuSupport(SfxRequest& rReq)
+{
+ if( rReq.GetSlot() == SID_STYLE_FAMILY && rReq.GetArgs())
+ GetDocSh()->SetStyleFamily(static_cast<SfxStyleFamily>(rReq.GetArgs()->Get( SID_STYLE_FAMILY ).GetValue()));
+
+ // We do not execute a thing during a native slide show
+ if(SlideShow::IsRunning(GetViewShellBase()) &&
+ (rReq.GetSlot() != SID_PRESENTATION_END &&
+ rReq.GetSlot() != SID_SIZE_PAGE))
+ return;
+
+ CheckLineTo (rReq);
+
+ if( !mpDrawView )
+ return;
+
+ sal_uInt16 nSId = rReq.GetSlot();
+
+ switch ( nSId )
+ {
+ case SID_CLEAR_UNDO_STACK:
+ {
+ GetDocSh()->ClearUndoBuffer();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_PRESENTATION:
+ case SID_PRESENTATION_CURRENT_SLIDE:
+ case SID_REHEARSE_TIMINGS:
+ {
+ slideshowhelp::ShowSlideShow(rReq, *GetDoc());
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_PRESENTATION_END:
+ {
+ StopSlideShow();
+
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_BEZIER_EDIT:
+ {
+ mpDrawView->SetFrameDragSingles(!mpDrawView->IsFrameDragSingles());
+
+ /******************************************************************
+ * turn ObjectBar on
+ ******************************************************************/
+ if( dynamic_cast< FuSelection* >( GetCurrentFunction().get() ) || dynamic_cast< FuConstructBezierPolygon* >( GetCurrentFunction().get() ) )
+ {
+ // Tell the tool bar manager about the context change.
+ GetViewShellBase().GetToolBarManager()->SelectionHasChanged(*this,*mpDrawView);
+ }
+
+ Invalidate(SID_BEZIER_EDIT);
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_OBJECT_CLOSE:
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ if ( rMarkList.GetMark(0) && !mpDrawView->IsAction() )
+ {
+ SdrPathObj* pPathObj = static_cast<SdrPathObj*>( rMarkList.GetMark(0)->GetMarkedSdrObj());
+ const bool bUndo = mpDrawView->IsUndoEnabled();
+ if( bUndo )
+ mpDrawView->BegUndo(SdResId(STR_UNDO_BEZCLOSE));
+
+ mpDrawView->UnmarkAllPoints();
+
+ if( bUndo )
+ mpDrawView->AddUndo(std::make_unique<SdrUndoGeoObj>(*pPathObj));
+
+ pPathObj->ToggleClosed();
+
+ if( bUndo )
+ mpDrawView->EndUndo();
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_CUT:
+ {
+ if ( mpDrawView->IsPresObjSelected(false, true, false, true) )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ //tdf#126197: EndTextEdit in all views if current one is not in TextEdit
+ if ( !mpDrawView->IsTextEdit() )
+ mpDrawView->EndTextEditAllViews();
+
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->DoCut();
+ }
+ else if(mpDrawView)
+ {
+ mpDrawView->DoCut();
+ }
+ }
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_COPY:
+ {
+ if ( mpDrawView->IsPresObjSelected(false, true, false, true) )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ else
+ {
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->DoCopy();
+ }
+ else if( mpDrawView )
+ {
+ mpDrawView->DoCopy();
+ }
+ }
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_PASTE:
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->DoPaste();
+ }
+ else if(mpDrawView)
+ {
+ mpDrawView->DoPaste();
+ }
+
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_UNICODE_NOTATION_TOGGLE:
+ {
+ if( mpDrawView->IsTextEdit() )
+ {
+ OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView();
+ if( pOLV )
+ {
+ OUString sInput = pOLV->GetSurroundingText();
+ ESelection aSel( pOLV->GetSelection() );
+ if( aSel.nStartPos > aSel.nEndPos )
+ aSel.nEndPos = aSel.nStartPos;
+
+ //calculate a valid end-position by reading logical characters
+ sal_Int32 nUtf16Pos=0;
+ while( (nUtf16Pos < sInput.getLength()) && (nUtf16Pos < aSel.nEndPos) )
+ {
+ sInput.iterateCodePoints(&nUtf16Pos);
+ //The mouse can set the cursor in the middle of a multi-unit character,
+ // so reset to the proper end of the logical characters
+ if( nUtf16Pos > aSel.nEndPos )
+ aSel.nEndPos = nUtf16Pos;
+ }
+
+ ToggleUnicodeCodepoint aToggle;
+ while( nUtf16Pos && aToggle.AllowMoreInput( sInput[nUtf16Pos-1]) )
+ --nUtf16Pos;
+ OUString sReplacement = aToggle.ReplacementString();
+ if( !sReplacement.isEmpty() )
+ {
+ OUString sStringToReplace = aToggle.StringToReplace();
+ mpDrawView->BegUndo(sStringToReplace +"->"+ sReplacement);
+ aSel.nStartPos = aSel.nEndPos - sStringToReplace.getLength();
+ pOLV->SetSelection( aSel );
+ pOLV->InsertText(sReplacement, true);
+ mpDrawView->EndUndo();
+ }
+ }
+ }
+ }
+ break;
+
+ case SID_PASTE_UNFORMATTED:
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->DoPasteUnformatted();
+ }
+ else if(mpDrawView)
+ {
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( GetActiveWindow() ) );
+ if (aDataHelper.GetTransferable().is())
+ {
+ sal_Int8 nAction = DND_ACTION_COPY;
+ mpDrawView->InsertData( aDataHelper,
+ GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(), GetActiveWindow()->GetOutputSizePixel() ).Center() ),
+ nAction, false, SotClipboardFormatId::STRING);
+ }
+ }
+
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_CLIPBOARD_FORMAT_ITEMS:
+ {
+ weld::WaitObject aWait(GetFrameWeld());
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( GetActiveWindow() ) );
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
+
+ if( pReqArgs )
+ {
+ const SfxUInt32Item* pIsActive = rReq.GetArg<SfxUInt32Item>(SID_CLIPBOARD_FORMAT_ITEMS);
+ nFormat = static_cast<SotClipboardFormatId>(pIsActive->GetValue());
+ }
+
+ if( nFormat != SotClipboardFormatId::NONE && aDataHelper.GetTransferable().is() )
+ {
+ sal_Int8 nAction = DND_ACTION_COPY;
+
+ if( !mpDrawView->InsertData( aDataHelper,
+ GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(), GetActiveWindow()->GetOutputSizePixel() ).Center() ),
+ nAction, false, nFormat ) )
+ {
+ INetBookmark aINetBookmark( "", "" );
+
+ if( ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) ) ||
+ ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::FILEGRPDESCRIPTOR, aINetBookmark ) ) ||
+ ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::UNIFORMRESOURCELOCATOR, aINetBookmark ) ) )
+ {
+ InsertURLField( aINetBookmark.GetURL(), aINetBookmark.GetDescription(), "" );
+ }
+ }
+ }
+ }
+ break;
+
+ case SID_DELETE:
+ {
+ if ( mpDrawView->IsTextEdit() )
+ {
+ OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView();
+
+ if (pOLV)
+ {
+ vcl::KeyCode aKCode(KEY_DELETE);
+ KeyEvent aKEvt( 0, aKCode);
+ // We use SdrObjEditView to handle DEL for underflow handling
+ (void)mpDrawView->KeyInput(aKEvt, nullptr);
+ }
+ }
+ else
+ {
+ mpDrawView->EndTextEditAllViews();
+ FuDeleteSelectedObjects();
+ }
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_NOTES_MODE:
+ case SID_SLIDE_MASTER_MODE:
+ case SID_NOTES_MASTER_MODE:
+ case SID_HANDOUT_MASTER_MODE:
+
+ // AutoLayouts have to be ready.
+ GetDoc()->StopWorkStartupDelay();
+ [[fallthrough]];
+
+ case SID_DRAWINGMODE:
+ case SID_SLIDE_SORTER_MODE:
+ case SID_OUTLINE_MODE:
+ // Let the sub-shell manager handle the slot handling.
+ framework::FrameworkHelper::Instance(GetViewShellBase())->HandleModeChangeSlot(
+ nSId,
+ rReq);
+ rReq.Ignore ();
+ break;
+
+ case SID_MASTERPAGE: // BASIC
+ {
+ if (comphelper::LibreOfficeKit::isActive())
+ GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED,
+ ".uno:SlideMasterPage=true");
+
+ // AutoLayouts needs to be finished
+ GetDoc()->StopWorkStartupDelay();
+
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ if ( pReqArgs )
+ {
+ const SfxBoolItem* pIsActive = rReq.GetArg<SfxBoolItem>(SID_MASTERPAGE);
+ mbIsLayerModeActive = pIsActive->GetValue ();
+ }
+
+ Broadcast (
+ ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_START));
+
+ // turn on default layer of MasterPage
+ mpDrawView->SetActiveLayer(sUNO_LayerName_background_objects);
+
+ ChangeEditMode(EditMode::MasterPage, mbIsLayerModeActive);
+
+ if(HasCurrentFunction(SID_BEZIER_EDIT))
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+
+ Broadcast (
+ ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_END));
+
+ InvalidateWindows();
+ Invalidate();
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_CLOSE_MASTER_VIEW:
+ {
+ // Notify of disabling master view, which is enabled in DrawViewShell::ChangeEditMode.
+ if (comphelper::LibreOfficeKit::isActive())
+ GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED,
+ ".uno:SlideMasterPage=false");
+
+ Broadcast (
+ ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_START));
+
+ // Switch page back to the first one. Not doing so leads to a
+ // crash. This seems to be some bug in the edit mode switching
+ // and page switching methods.
+ SwitchPage (0);
+ ChangeEditMode(EditMode::Page, IsLayerModeActive());
+ Broadcast (
+ ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_END));
+
+ if(HasCurrentFunction(SID_BEZIER_EDIT))
+ {
+ GetViewFrame()->GetDispatcher()->Execute(
+ SID_OBJECT_SELECT,
+ SfxCallMode::ASYNCHRON);
+ }
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_RULER:
+ {
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ // Remember old ruler state
+ bool bOldHasRuler(HasRuler());
+
+ if ( pReqArgs )
+ {
+ const SfxBoolItem* pIsActive = rReq.GetArg<SfxBoolItem>(SID_RULER);
+ SetRuler (pIsActive->GetValue ());
+ }
+ else SetRuler (!HasRuler());
+
+ // Did ruler state change? Tell that to SdOptions, too.
+ bool bHasRuler(HasRuler());
+
+ if(bOldHasRuler != bHasRuler)
+ {
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDoc()->GetDocumentType());
+
+ if(pOptions && pOptions->IsRulerVisible() != bHasRuler)
+ {
+ pOptions->SetRulerVisible(bHasRuler);
+ }
+ }
+
+ Invalidate (SID_RULER);
+ Resize();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_SIZE_PAGE:
+ case SID_SIZE_PAGE_WIDTH: // BASIC
+ {
+ mbZoomOnPage = ( rReq.GetSlot() == SID_SIZE_PAGE );
+
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+
+ if ( pPageView )
+ {
+ Point aPagePos(0, 0); // = pPageView->GetOffset();
+ Size aPageSize = pPageView->GetPage()->GetSize();
+
+ aPagePos.AdjustX(aPageSize.Width() / 2 );
+ aPageSize.setWidth( static_cast<::tools::Long>(aPageSize.Width() * 1.03) );
+
+ if( rReq.GetSlot() == SID_SIZE_PAGE )
+ {
+ aPagePos.AdjustY(aPageSize.Height() / 2 );
+ aPageSize.setHeight( static_cast<::tools::Long>(aPageSize.Height() * 1.03) );
+ aPagePos.AdjustY( -(aPageSize.Height() / 2) );
+ }
+ else
+ {
+ Point aPt = GetActiveWindow()->PixelToLogic( Point( 0, GetActiveWindow()->GetSizePixel().Height() / 2 ) );
+ aPagePos.AdjustY(aPt.Y() );
+ aPageSize.setHeight( 2 );
+ }
+
+ aPagePos.AdjustX( -(aPageSize.Width() / 2) );
+
+ SetZoomRect( ::tools::Rectangle( aPagePos, aPageSize ) );
+
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0),
+ GetActiveWindow()->GetOutputSizePixel()) );
+ mpZoomList->InsertZoomRect(aVisAreaWin);
+ }
+ Invalidate( SID_ZOOM_IN );
+ Invalidate( SID_ZOOM_OUT );
+ Invalidate( SID_ZOOM_PANNING );
+ rReq.Done ();
+ }
+ break;
+
+ case SID_SIZE_REAL: // BASIC
+ {
+ mbZoomOnPage = false;
+ SetZoom( 100 );
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0),
+ GetActiveWindow()->GetOutputSizePixel()) );
+ mpZoomList->InsertZoomRect(aVisAreaWin);
+ Invalidate( SID_ZOOM_IN );
+ Invalidate( SID_ZOOM_OUT );
+ Invalidate( SID_ZOOM_PANNING );
+ rReq.Done ();
+ }
+ break;
+
+ case SID_ZOOM_OUT: // BASIC
+ {
+ mbZoomOnPage = false;
+ SetZoom( std::max<::tools::Long>( GetActiveWindow()->GetZoom() / 2, GetActiveWindow()->GetMinZoom() ) );
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0),
+ GetActiveWindow()->GetOutputSizePixel()) );
+ mpZoomList->InsertZoomRect(aVisAreaWin);
+ Invalidate( SID_ZOOM_IN );
+ Invalidate( SID_ZOOM_OUT );
+ Invalidate( SID_ZOOM_PANNING );
+ rReq.Done ();
+ }
+ break;
+
+ case SID_ZOOM_IN:
+ {
+ mbZoomOnPage = false;
+ SetZoom( std::min<::tools::Long>( GetActiveWindow()->GetZoom() * 2, GetActiveWindow()->GetMaxZoom() ) );
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0),
+ GetActiveWindow()->GetOutputSizePixel()) );
+ mpZoomList->InsertZoomRect(aVisAreaWin);
+ Invalidate( SID_ZOOM_IN );
+ Invalidate(SID_ZOOM_OUT);
+ Invalidate( SID_ZOOM_PANNING );
+ rReq.Done ();
+ }
+ break;
+
+ case SID_SIZE_VISAREA:
+ {
+ ::tools::Rectangle aVisArea = mpFrameView->GetVisArea();
+ Size aVisAreaSize = aVisArea.GetSize();
+
+ if (!aVisAreaSize.IsEmpty())
+ {
+ mbZoomOnPage = false;
+ SetZoomRect(aVisArea);
+ Invalidate( SID_ZOOM_IN );
+ Invalidate( SID_ZOOM_OUT );
+ Invalidate( SID_ZOOM_PANNING );
+ }
+ rReq.Done ();
+ }
+ break;
+
+ // name confusion: SID_SIZE_OPTIMAL -> Zoom onto selected objects
+ // --> Is offered as object zoom in program
+ case SID_SIZE_OPTIMAL: // BASIC
+ {
+ mbZoomOnPage = false;
+ if ( mpDrawView->AreObjectsMarked() )
+ {
+ maMarkRect = mpDrawView->GetAllMarkedRect();
+ ::tools::Long nW = static_cast<::tools::Long>(maMarkRect.GetWidth() * 1.03);
+ ::tools::Long nH = static_cast<::tools::Long>(maMarkRect.GetHeight() * 1.03);
+ Point aPos = maMarkRect.Center();
+ aPos.AdjustX( -(nW / 2) );
+ aPos.AdjustY( -(nH / 2) );
+ if ( nW && nH )
+ {
+ SetZoomRect(::tools::Rectangle(aPos, Size(nW, nH)));
+
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0),
+ GetActiveWindow()->GetOutputSizePixel()) );
+ mpZoomList->InsertZoomRect(aVisAreaWin);
+ }
+ }
+ Invalidate( SID_ZOOM_IN );
+ Invalidate( SID_ZOOM_OUT );
+ Invalidate( SID_ZOOM_PANNING );
+ rReq.Done ();
+ }
+ break;
+
+ // name confusion: SID_SIZE_ALL -> Zoom onto all objects
+ // --> Is offered as optimal in program
+ case SID_SIZE_ALL: // BASIC
+ {
+ mbZoomOnPage = false;
+ SdrPageView* pPageView = mpDrawView->GetSdrPageView();
+
+ if( pPageView )
+ {
+ ::tools::Rectangle aBoundRect( pPageView->GetObjList()->GetAllObjBoundRect() );
+
+ ::tools::Long nW = static_cast<::tools::Long>(aBoundRect.GetWidth() * 1.03);
+ ::tools::Long nH = static_cast<::tools::Long>(aBoundRect.GetHeight() * 1.03);
+ Point aPos = aBoundRect.Center();
+ aPos.AdjustX( -(nW / 2) );
+ aPos.AdjustY( -(nH / 2) );
+ if ( nW && nH )
+ {
+ SetZoomRect( ::tools::Rectangle( aPos, Size( nW, nH ) ) );
+
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0),
+ GetActiveWindow()->GetOutputSizePixel()) );
+ mpZoomList->InsertZoomRect(aVisAreaWin);
+ }
+
+ Invalidate( SID_ZOOM_IN );
+ Invalidate( SID_ZOOM_OUT );
+ Invalidate( SID_ZOOM_PANNING );
+ }
+ rReq.Done ();
+ }
+ break;
+
+ case SID_ZOOM_PREV:
+ {
+ if (mpDrawView->IsTextEdit())
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ if (mpZoomList->IsPreviousPossible())
+ {
+ // set previous ZoomRect
+ SetZoomRect(mpZoomList->GetPreviousZoomRect());
+ }
+ rReq.Done ();
+ }
+ break;
+
+ case SID_ZOOM_NEXT:
+ {
+ if (mpDrawView->IsTextEdit())
+ {
+ mpDrawView->SdrEndTextEdit();
+ }
+
+ if (mpZoomList->IsNextPossible())
+ {
+ // set next ZoomRect
+ SetZoomRect(mpZoomList->GetNextZoomRect());
+ }
+ rReq.Done ();
+ }
+ break;
+
+ case SID_GLUE_INSERT_POINT:
+ case SID_GLUE_PERCENT:
+ case SID_GLUE_ESCDIR:
+ case SID_GLUE_ESCDIR_LEFT:
+ case SID_GLUE_ESCDIR_RIGHT:
+ case SID_GLUE_ESCDIR_TOP:
+ case SID_GLUE_ESCDIR_BOTTOM:
+ case SID_GLUE_HORZALIGN_CENTER:
+ case SID_GLUE_HORZALIGN_LEFT:
+ case SID_GLUE_HORZALIGN_RIGHT:
+ case SID_GLUE_VERTALIGN_CENTER:
+ case SID_GLUE_VERTALIGN_TOP:
+ case SID_GLUE_VERTALIGN_BOTTOM:
+ {
+ rtl::Reference<FuPoor> xFunc( GetCurrentFunction() );
+ FuEditGluePoints* pFunc = dynamic_cast< FuEditGluePoints* >( xFunc.get() );
+
+ if(pFunc)
+ pFunc->ReceiveRequest(rReq);
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_AUTOSPELL_CHECK:
+ {
+ bool bOnlineSpell;
+ const SfxPoolItem* pItem;
+
+ if (rReq.GetArgs()->HasItem(FN_PARAM_1, &pItem))
+ bOnlineSpell = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ else // Toggle
+ bOnlineSpell = !GetDoc()->GetOnlineSpell();
+
+ GetDoc()->SetOnlineSpell(bOnlineSpell);
+
+ ::Outliner* pOL = mpDrawView->GetTextEditOutliner();
+
+ if (pOL)
+ {
+ EEControlBits nCntrl = pOL->GetControlWord();
+
+ if (bOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+
+ pOL->SetControlWord(nCntrl);
+ }
+
+ GetActiveWindow()->Invalidate();
+ rReq.Done ();
+ }
+ break;
+
+ case SID_TRANSLITERATE_SENTENCE_CASE:
+ case SID_TRANSLITERATE_TITLE_CASE:
+ case SID_TRANSLITERATE_TOGGLE_CASE:
+ case SID_TRANSLITERATE_UPPER:
+ case SID_TRANSLITERATE_LOWER:
+ case SID_TRANSLITERATE_HALFWIDTH:
+ case SID_TRANSLITERATE_FULLWIDTH:
+ case SID_TRANSLITERATE_HIRAGANA:
+ case SID_TRANSLITERATE_KATAKANA:
+ {
+ OutlinerView* pOLV = GetView()->GetTextEditOutlinerView();
+ if( pOLV )
+ {
+ TransliterationFlags nType = TransliterationFlags::NONE;
+
+ switch( nSId )
+ {
+ case SID_TRANSLITERATE_SENTENCE_CASE:
+ nType = TransliterationFlags::SENTENCE_CASE;
+ break;
+ case SID_TRANSLITERATE_TITLE_CASE:
+ nType = TransliterationFlags::TITLE_CASE;
+ break;
+ case SID_TRANSLITERATE_TOGGLE_CASE:
+ nType = TransliterationFlags::TOGGLE_CASE;
+ break;
+ case SID_TRANSLITERATE_UPPER:
+ nType = TransliterationFlags::LOWERCASE_UPPERCASE;
+ break;
+ case SID_TRANSLITERATE_LOWER:
+ nType = TransliterationFlags::UPPERCASE_LOWERCASE;
+ break;
+ case SID_TRANSLITERATE_HALFWIDTH:
+ nType = TransliterationFlags::FULLWIDTH_HALFWIDTH;
+ break;
+ case SID_TRANSLITERATE_FULLWIDTH:
+ nType = TransliterationFlags::HALFWIDTH_FULLWIDTH;
+ break;
+ case SID_TRANSLITERATE_HIRAGANA:
+ nType = TransliterationFlags::KATAKANA_HIRAGANA;
+ break;
+ case SID_TRANSLITERATE_KATAKANA:
+ nType = TransliterationFlags::HIRAGANA_KATAKANA;
+ break;
+ }
+
+ pOLV->TransliterateText( nType );
+ }
+
+ rReq.Done();
+ }
+ break;
+
+ // #UndoRedo#
+ case SID_UNDO :
+ {
+ // moved implementation to BaseClass
+ ImpSidUndo(rReq);
+ }
+ break;
+ case SID_REDO :
+ {
+ // moved implementation to BaseClass
+ ImpSidRedo(rReq);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void DrawViewShell::FuSupportRotate(SfxRequest const &rReq)
+{
+ if( rReq.GetSlot() != SID_TRANSLITERATE_ROTATE_CASE )
+ return;
+
+ ::sd::View* pView = GetView();
+
+ if (!pView)
+ return;
+
+ OutlinerView* pOLV = pView->GetTextEditOutlinerView();
+
+ if (!pOLV)
+ return;
+
+ pOLV->TransliterateText( m_aRotateCase.getNextMode() );
+}
+
+void DrawViewShell::InsertURLField(const OUString& rURL, const OUString& rText,
+ const OUString& rTarget)
+{
+ OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView();
+
+ if (pOLV)
+ {
+ ESelection aSel( pOLV->GetSelection() );
+ SvxFieldItem aURLItem( SvxURLField( rURL, rText, SvxURLFormat::Repr ), EE_FEATURE_FIELD );
+ pOLV->InsertField( aURLItem );
+ if ( aSel.nStartPos <= aSel.nEndPos )
+ aSel.nEndPos = aSel.nStartPos + 1;
+ else
+ aSel.nStartPos = aSel.nEndPos + 1;
+ pOLV->SetSelection( aSel );
+ }
+ else
+ {
+ Outliner* pOutl = GetDoc()->GetInternalOutliner();
+ pOutl->Init( OutlinerMode::TextObject );
+ OutlinerMode nOutlMode = pOutl->GetOutlinerMode();
+
+ SvxURLField aURLField(rURL, rText, SvxURLFormat::Repr);
+ aURLField.SetTargetFrame(rTarget);
+ SvxFieldItem aURLItem(aURLField, EE_FEATURE_FIELD);
+ pOutl->QuickInsertField( aURLItem, ESelection() );
+ std::optional<OutlinerParaObject> pOutlParaObject = pOutl->CreateParaObject();
+
+ SdrRectObj* pRectObj = new SdrRectObj(
+ GetView()->getSdrModelFromSdrView(),
+ SdrObjKind::Text);
+
+ pOutl->UpdateFields();
+ pOutl->SetUpdateLayout( true );
+ Size aSize(pOutl->CalcTextSize());
+ pOutl->SetUpdateLayout( false );
+
+ Point aPos;
+ ::tools::Rectangle aRect(aPos, GetActiveWindow()->GetOutputSizePixel() );
+ aPos = aRect.Center();
+ aPos = GetActiveWindow()->PixelToLogic(aPos);
+
+ if (aPos.getX() - (aSize.Width() / 2) >= 0)
+ aPos.AdjustX( -(aSize.Width() / 2) );
+ if (aPos.getY() - (aSize.Height() / 2) >= 0)
+ aPos.AdjustY( -(aSize.Height() / 2) );
+
+ ::tools::Rectangle aLogicRect(aPos, aSize);
+ pRectObj->SetLogicRect(aLogicRect);
+ pRectObj->SetOutlinerParaObject( std::move(pOutlParaObject) );
+ mpDrawView->InsertObjectAtView(pRectObj, *mpDrawView->GetSdrPageView());
+ pOutl->Init( nOutlMode );
+ }
+}
+
+void DrawViewShell::InsertURLButton(const OUString& rURL, const OUString& rText,
+ const OUString& rTarget, const Point* pPos)
+{
+ bool bNewObj = true;
+
+ const OUString sTargetURL( ::URIHelper::SmartRel2Abs( INetURLObject( GetDocSh()->GetMedium()->GetBaseURL() ), rURL, URIHelper::GetMaybeFileHdl(), true, false,
+ INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::Unambiguous ) );
+ if (mpDrawView->GetMarkedObjectList().GetMarkCount() > 0)
+ {
+ SdrObject* pMarkedObj = mpDrawView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
+ if( pMarkedObj ) try
+ {
+ // change first marked object
+ if( SdrInventor::FmForm == pMarkedObj->GetObjInventor() && pMarkedObj->GetObjIdentifier() == SdrObjKind::FormButton )
+ {
+ bNewObj = false;
+
+ SdrUnoObj* pUnoCtrl = static_cast< SdrUnoObj* >( pMarkedObj );
+
+ Reference< awt::XControlModel > xControlModel( pUnoCtrl->GetUnoControlModel(), UNO_SET_THROW );
+ Reference< beans::XPropertySet > xPropSet( xControlModel, UNO_QUERY_THROW );
+
+ xPropSet->setPropertyValue("Label" , Any( rText ) );
+ xPropSet->setPropertyValue("TargetURL" , Any( sTargetURL ) );
+
+ if( !rTarget.isEmpty() )
+ xPropSet->setPropertyValue("TargetFrame" , Any( rTarget ) );
+
+ xPropSet->setPropertyValue( "ButtonType" , Any( form::FormButtonType_URL ) );
+#if HAVE_FEATURE_AVMEDIA
+ if ( ::avmedia::MediaWindow::isMediaURL( rURL, ""/*TODO?*/ ) )
+ {
+ xPropSet->setPropertyValue( "DispatchURLInternal" , Any( true ) );
+ }
+#endif
+ }
+ else
+ {
+ // add url as interaction for first selected shape
+ bNewObj = false;
+
+ SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pMarkedObj, true);
+ pInfo->meClickAction = presentation::ClickAction_DOCUMENT;
+ pInfo->SetBookmark( sTargetURL );
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+
+ if (!bNewObj)
+ return;
+
+ try
+ {
+ SdrUnoObj* pUnoCtrl = static_cast< SdrUnoObj* >(
+ SdrObjFactory::MakeNewObject(
+ GetView()->getSdrModelFromSdrView(),
+ SdrInventor::FmForm,
+ SdrObjKind::FormButton)); //,
+ //mpDrawView->GetSdrPageView()->GetPage()));
+
+ Reference< awt::XControlModel > xControlModel( pUnoCtrl->GetUnoControlModel(), uno::UNO_SET_THROW );
+ Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY_THROW );
+
+ xPropSet->setPropertyValue( "Label" , Any( rText ) );
+ xPropSet->setPropertyValue( "TargetURL" , Any( sTargetURL ) );
+
+ if( !rTarget.isEmpty() )
+ xPropSet->setPropertyValue( "TargetFrame" , Any( rTarget ) );
+
+ xPropSet->setPropertyValue( "ButtonType" , Any( form::FormButtonType_URL ) );
+#if HAVE_FEATURE_AVMEDIA
+ if ( ::avmedia::MediaWindow::isMediaURL( rURL, ""/*TODO?*/ ) )
+ xPropSet->setPropertyValue( "DispatchURLInternal" , Any( true ) );
+#endif
+
+ Point aPos;
+
+ if (pPos)
+ {
+ aPos = *pPos;
+ }
+ else
+ {
+ aPos = ::tools::Rectangle(aPos, GetActiveWindow()->GetOutputSizePixel()).Center();
+ aPos = GetActiveWindow()->PixelToLogic(aPos);
+ }
+
+ Size aSize(4000, 1000);
+ aPos.AdjustX( -(aSize.Width() / 2) );
+ aPos.AdjustY( -(aSize.Height() / 2) );
+ pUnoCtrl->SetLogicRect(::tools::Rectangle(aPos, aSize));
+
+ SdrInsertFlags nOptions = SdrInsertFlags::SETDEFLAYER;
+
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ SfxInPlaceClient* pIpClient = GetViewShell()->GetIPClient();
+ if (pIpClient!=nullptr && pIpClient->IsObjectInPlaceActive())
+ {
+ nOptions |= SdrInsertFlags::DONTMARK;
+ }
+
+ mpDrawView->InsertObjectAtView(pUnoCtrl, *mpDrawView->GetSdrPageView(), nOptions);
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void DrawViewShell::ShowUIControls (bool bVisible)
+{
+ ViewShell::ShowUIControls (bVisible);
+ maTabControl->Show (bVisible);
+}
+
+namespace slideshowhelp
+{
+ void ShowSlideShow(SfxRequest const & rReq, SdDrawDocument &rDoc)
+ {
+ Reference< XPresentation2 > xPresentation( rDoc.getPresentation() );
+ if( !xPresentation.is() )
+ return;
+
+ sfx2::SfxNotebookBar::LockNotebookBar();
+ if (SID_REHEARSE_TIMINGS == rReq.GetSlot())
+ xPresentation->rehearseTimings();
+ else if (rDoc.getPresentationSettings().mbCustomShow)
+ {
+ //fdo#69975 if a custom show has been set, then
+ //use it whether or not we've been asked to
+ //start from the current or first slide
+ xPresentation->start();
+
+ // if the custom show not set by default, only show it.
+ if (rDoc.getPresentationSettings().mbStartCustomShow)
+ rDoc.getPresentationSettings().mbCustomShow = false;
+ }
+ else if (SID_PRESENTATION_CURRENT_SLIDE == rReq.GetSlot())
+ {
+ //If there is no custom show set, start will automatically
+ //start at the current page
+ xPresentation->start();
+ }
+ else
+ {
+ //Start at page 0, this would blow away any custom
+ //show settings if any were set
+ Sequence< PropertyValue > aArguments{ comphelper::makePropertyValue("FirstPage",
+ OUString("0")) };
+ xPresentation->startWithArguments( aArguments );
+ }
+ sfx2::SfxNotebookBar::UnlockNotebookBar();
+ }
+}
+
+void DrawViewShell::StopSlideShow()
+{
+ Reference< XPresentation2 > xPresentation( GetDoc()->getPresentation() );
+ if(xPresentation.is() && xPresentation->isRunning())
+ {
+ if( mpDrawView->IsTextEdit() )
+ mpDrawView->SdrEndTextEdit();
+
+ xPresentation->end();
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewsf.cxx b/sd/source/ui/view/drviewsf.cxx
new file mode 100644
index 000000000..8aab2c576
--- /dev/null
+++ b/sd/source/ui/view/drviewsf.cxx
@@ -0,0 +1,826 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawViewShell.hxx>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/string.hxx>
+#include <svx/svxids.hrc>
+#include <svx/sdmetitm.hxx>
+#include <svx/hlnkitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/whiter.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+#include <sfx2/tplpitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <svx/xdef.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/fmshell.hxx>
+#include <svl/cjkoptions.hxx>
+
+#include <app.hrc>
+
+#include <sdmod.hxx>
+#include <stlsheet.hxx>
+#include <drawview.hxx>
+#include <drawdoc.hxx>
+#include <Window.hxx>
+#include <ViewShellBase.hxx>
+#include <FormShellManager.hxx>
+#include <anminfo.hxx>
+
+#include <editeng/lspcitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/numitem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/urlfieldhelper.hxx>
+#include <svx/nbdtmgfact.hxx>
+#include <svx/nbdtmg.hxx>
+#include <memory>
+
+using namespace com::sun::star::drawing;
+using namespace svx::sidebar;
+using namespace ::com::sun::star;
+
+namespace sd {
+
+/**
+ * Set state of controller SfxSlots
+ */
+void DrawViewShell::GetCtrlState(SfxItemSet &rSet)
+{
+ if (rSet.GetItemState(SID_RELOAD) != SfxItemState::UNKNOWN)
+ {
+ // let "last version" of SFx en/disable
+ GetViewFrame()->GetSlotState (SID_RELOAD, nullptr, &rSet);
+ }
+
+ if (SfxItemState::DEFAULT == rSet.GetItemState(SID_HYPERLINK_GETLINK))
+ {
+ SvxHyperlinkItem aHLinkItem;
+
+ OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView();
+
+ if (pOLV)
+ {
+ const SvxFieldData* pField = pOLV->GetFieldAtCursor();
+ if( auto pUrlField = dynamic_cast< const SvxURLField *>( pField ) )
+ {
+ aHLinkItem.SetName(pUrlField->GetRepresentation());
+ aHLinkItem.SetURL(pUrlField->GetURL());
+ aHLinkItem.SetTargetFrame(pUrlField->GetTargetFrame());
+ }
+ else
+ {
+ // use selected text as name for urls
+ OUString sReturn = pOLV->GetSelected();
+ if (sReturn.getLength() > 255)
+ sReturn = sReturn.copy(0, 255);
+ aHLinkItem.SetName(comphelper::string::stripEnd(sReturn, ' '));
+ }
+ }
+ else
+ {
+ if (mpDrawView->GetMarkedObjectList().GetMarkCount() > 0)
+ {
+ bool bFound = false;
+
+ SdrObject* pMarkedObj = mpDrawView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
+ if( pMarkedObj && (SdrInventor::FmForm == pMarkedObj->GetObjInventor()) )
+ {
+ SdrUnoObj* pUnoCtrl = dynamic_cast< SdrUnoObj* >( pMarkedObj );
+
+ if(pUnoCtrl) try
+ {
+ uno::Reference< awt::XControlModel > xControlModel( pUnoCtrl->GetUnoControlModel(), uno::UNO_SET_THROW );
+ uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySetInfo > xPropInfo( xPropSet->getPropertySetInfo(), uno::UNO_SET_THROW );
+
+ form::FormButtonType eButtonType = form::FormButtonType_URL;
+ static const OUStringLiteral sButtonType( u"ButtonType" );
+ if(xPropInfo->hasPropertyByName( sButtonType ) && (xPropSet->getPropertyValue( sButtonType ) >>= eButtonType ) )
+ {
+ OUString aString;
+
+ // Label
+ static const OUStringLiteral sLabel( u"Label" );
+ if(xPropInfo->hasPropertyByName(sLabel))
+ {
+ if( xPropSet->getPropertyValue(sLabel) >>= aString )
+ aHLinkItem.SetName(aString);
+ }
+
+ // URL
+ static const OUStringLiteral sTargetURL( u"TargetURL" );
+ if(xPropInfo->hasPropertyByName(sTargetURL))
+ {
+ if( xPropSet->getPropertyValue(sTargetURL) >>= aString )
+ aHLinkItem.SetURL(aString);
+ }
+
+ // Target
+ static const OUStringLiteral sTargetFrame( u"TargetFrame" );
+ if(xPropInfo->hasPropertyByName(sTargetFrame) )
+ {
+ if( xPropSet->getPropertyValue(sTargetFrame) >>= aString )
+ aHLinkItem.SetTargetFrame(aString);
+ }
+
+ aHLinkItem.SetInsertMode(HLINK_BUTTON);
+ bFound = true;
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+
+ // try interaction link
+ if( !bFound && pMarkedObj )
+ {
+ SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pMarkedObj);
+ if( pInfo && (pInfo->meClickAction == presentation::ClickAction_DOCUMENT) )
+ aHLinkItem.SetURL( pInfo->GetBookmark());
+ aHLinkItem.SetInsertMode(HLINK_BUTTON);
+ }
+ }
+ }
+
+ rSet.Put(aHLinkItem);
+ }
+ rSet.Put( SfxBoolItem( SID_READONLY_MODE, mbReadOnly ) );
+
+ // output quality
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTPUT_QUALITY_COLOR ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTPUT_QUALITY_GRAYSCALE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTPUT_QUALITY_BLACKWHITE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTPUT_QUALITY_CONTRAST ) )
+ {
+ const sal_uLong nMode = static_cast<sal_Int32>(GetActiveWindow()->GetOutDev()->GetDrawMode());
+ rSet.Put( SfxBoolItem( SID_OUTPUT_QUALITY_COLOR, sal_uLong(OUTPUT_DRAWMODE_COLOR) == nMode ) );
+ rSet.Put( SfxBoolItem( SID_OUTPUT_QUALITY_GRAYSCALE, static_cast<sal_uLong>(OUTPUT_DRAWMODE_GRAYSCALE) == nMode ) );
+ rSet.Put( SfxBoolItem( SID_OUTPUT_QUALITY_BLACKWHITE, static_cast<sal_uLong>(OUTPUT_DRAWMODE_BLACKWHITE) == nMode ) );
+ rSet.Put( SfxBoolItem( SID_OUTPUT_QUALITY_CONTRAST, static_cast<sal_uLong>(OUTPUT_DRAWMODE_CONTRAST) == nMode ) );
+ }
+
+ if ( SfxItemState::DEFAULT == rSet.GetItemState(SID_MAIL_SCROLLBODY_PAGEDOWN) )
+ {
+ rSet.Put( SfxBoolItem( SID_MAIL_SCROLLBODY_PAGEDOWN, true ) );
+ }
+
+ if ( SfxItemState::DEFAULT == rSet.GetItemState(SID_ATTR_YEAR2000) )
+ {
+ FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell();
+ if (pFormShell != nullptr)
+ {
+ sal_uInt16 nState = 0;
+ if (pFormShell->GetY2KState(nState))
+ rSet.Put( SfxUInt16Item( SID_ATTR_YEAR2000, nState ) );
+ else
+ rSet.DisableItem( SID_ATTR_YEAR2000 );
+ }
+ }
+
+ if ( !GetView()->GetTextEditOutliner() )
+ {
+ if( !SvtCJKOptions::IsChangeCaseMapEnabled() )
+ {
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, false );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, false );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, false );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, false );
+ }
+ else
+ {
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, true );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, true );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, true );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, true );
+ }
+
+ rSet.DisableItem( SID_TRANSLITERATE_SENTENCE_CASE );
+ rSet.DisableItem( SID_TRANSLITERATE_TITLE_CASE );
+ rSet.DisableItem( SID_TRANSLITERATE_TOGGLE_CASE );
+ rSet.DisableItem( SID_TRANSLITERATE_UPPER );
+ rSet.DisableItem( SID_TRANSLITERATE_LOWER );
+ rSet.DisableItem( SID_TRANSLITERATE_HALFWIDTH );
+ rSet.DisableItem( SID_TRANSLITERATE_FULLWIDTH );
+ rSet.DisableItem( SID_TRANSLITERATE_HIRAGANA );
+ rSet.DisableItem( SID_TRANSLITERATE_KATAKANA );
+ }
+ else
+ {
+ if( !SvtCJKOptions::IsChangeCaseMapEnabled() )
+ {
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, false );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, false );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, false );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, false );
+ rSet.DisableItem( SID_TRANSLITERATE_HALFWIDTH );
+ rSet.DisableItem( SID_TRANSLITERATE_FULLWIDTH );
+ rSet.DisableItem( SID_TRANSLITERATE_HIRAGANA );
+ rSet.DisableItem( SID_TRANSLITERATE_KATAKANA );
+ }
+ else
+ {
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, true );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, true );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, true );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, true );
+ }
+ }
+}
+
+void DrawViewShell::GetAttrState( SfxItemSet& rSet )
+{
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ bool bAttr = false;
+ SfxAllItemSet aAllSet( *rSet.GetPool() );
+
+ while ( nWhich )
+ {
+ sal_uInt16 nSlotId = SfxItemPool::IsWhich(nWhich)
+ ? GetPool().GetSlotId(nWhich)
+ : nWhich;
+ switch ( nSlotId )
+ {
+ case SID_ATTR_PARA_ADJUST_LEFT:
+ {
+ SfxItemSet aAttrs( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aAttrs );
+
+ SvxAdjust eAdj = aAttrs.Get( EE_PARA_JUST ).GetAdjust();
+ if ( eAdj == SvxAdjust::Left)
+ {
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, true ) );
+ }
+
+ bAttr = true;
+
+ Invalidate(nSlotId);
+ }
+ break;
+ case SID_ATTR_PARA_ADJUST_CENTER:
+ {
+ SfxItemSet aAttrs( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aAttrs );
+
+ SvxAdjust eAdj = aAttrs.Get( EE_PARA_JUST ).GetAdjust();
+ if ( eAdj == SvxAdjust::Center)
+ {
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, true ) );
+ }
+
+ bAttr = true;
+
+ Invalidate(nSlotId);
+ }
+ break;
+ case SID_ATTR_PARA_ADJUST_RIGHT:
+ {
+ SfxItemSet aAttrs( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aAttrs );
+
+ SvxAdjust eAdj = aAttrs.Get( EE_PARA_JUST ).GetAdjust();
+ if ( eAdj == SvxAdjust::Right)
+ {
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, true ) );
+ }
+
+ bAttr = true;
+
+ Invalidate(nSlotId);
+ }
+ break;
+ case SID_ATTR_PARA_ADJUST_BLOCK:
+ {
+ SfxItemSet aAttrs( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aAttrs );
+
+ SvxAdjust eAdj = aAttrs.Get( EE_PARA_JUST ).GetAdjust();
+ if ( eAdj == SvxAdjust::Block)
+ {
+ rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, true ) );
+ }
+
+ bAttr = true;
+
+ Invalidate(nSlotId);
+ }
+ break;
+ case SID_ATTR_PARA_LRSPACE:
+ {
+ SfxItemSet aAttrs( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aAttrs );
+ SvxLRSpaceItem aLRSpace = aAttrs.Get( EE_PARA_LRSPACE );
+ aLRSpace.SetWhich(SID_ATTR_PARA_LRSPACE);
+ rSet.Put(aLRSpace);
+ bAttr = true;
+ Invalidate(SID_ATTR_PARA_LRSPACE);
+ }
+ break;
+ case SID_ATTR_PARA_LINESPACE:
+ {
+ SfxItemSet aAttrs( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aAttrs );
+ SvxLineSpacingItem aLineLR = aAttrs.Get( EE_PARA_SBL );
+ rSet.Put(aLineLR);
+ bAttr = true;
+ Invalidate(SID_ATTR_PARA_LINESPACE);
+ }
+ break;
+ case SID_ATTR_PARA_ULSPACE:
+ {
+ SfxItemSet aAttrs( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aAttrs );
+ SvxULSpaceItem aULSP = aAttrs.Get( EE_PARA_ULSPACE );
+ aULSP.SetWhich(SID_ATTR_PARA_ULSPACE);
+ rSet.Put(aULSP);
+ bAttr = true;
+ Invalidate(SID_ATTR_PARA_ULSPACE);
+ }
+ break;
+ case SID_ULINE_VAL_NONE:
+ case SID_ULINE_VAL_SINGLE:
+ case SID_ULINE_VAL_DOUBLE:
+ case SID_ULINE_VAL_DOTTED:
+ {
+ SfxItemSet aAttrs( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aAttrs );
+ if( aAttrs.GetItemState( EE_CHAR_UNDERLINE ) >= SfxItemState::DEFAULT )
+ {
+ FontLineStyle eLineStyle = aAttrs.Get(EE_CHAR_UNDERLINE).GetLineStyle();
+
+ switch (nSlotId)
+ {
+ case SID_ULINE_VAL_NONE:
+ rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_NONE));
+ break;
+ case SID_ULINE_VAL_SINGLE:
+ rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_SINGLE));
+ break;
+ case SID_ULINE_VAL_DOUBLE:
+ rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_DOUBLE));
+ break;
+ case SID_ULINE_VAL_DOTTED:
+ rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_DOTTED));
+ break;
+ }
+ }
+
+ bAttr = true;
+
+ Invalidate(nSlotId);
+ }
+ break;
+ case SID_ATTR_FILL_STYLE:
+ case SID_ATTR_FILL_COLOR:
+ case SID_ATTR_FILL_GRADIENT:
+ case SID_ATTR_FILL_HATCH:
+ case SID_ATTR_FILL_BITMAP:
+ case SID_ATTR_FILL_SHADOW:
+ case SID_ATTR_SHADOW_COLOR:
+ case SID_ATTR_SHADOW_TRANSPARENCE:
+ case SID_ATTR_SHADOW_BLUR:
+ case SID_ATTR_SHADOW_XDISTANCE:
+ case SID_ATTR_SHADOW_YDISTANCE:
+ case SID_ATTR_FILL_USE_SLIDE_BACKGROUND:
+ case SID_ATTR_FILL_TRANSPARENCE:
+ case SID_ATTR_FILL_FLOATTRANSPARENCE:
+ case SID_ATTR_LINE_STYLE:
+ case SID_ATTR_LINE_DASH:
+ case SID_ATTR_LINE_WIDTH:
+ case SID_ATTR_LINE_COLOR:
+ case SID_ATTR_LINE_TRANSPARENCE:
+ case SID_ATTR_LINE_JOINT:
+ case SID_ATTR_LINE_CAP:
+ case SID_ATTR_TEXT_FITTOSIZE:
+ case SID_ATTR_CHAR_FONT:
+ case SID_ATTR_CHAR_FONTHEIGHT:
+ case SID_ATTR_CHAR_SHADOWED:
+ case SID_ATTR_CHAR_POSTURE:
+ case SID_ATTR_CHAR_OVERLINE:
+ case SID_ATTR_CHAR_UNDERLINE:
+ case SID_ATTR_CHAR_STRIKEOUT:
+ case SID_ATTR_CHAR_CONTOUR:
+ case SID_ATTR_CHAR_WEIGHT:
+ case SID_ATTR_CHAR_COLOR:
+ case SID_ATTR_CHAR_KERNING:
+ case SID_ATTR_CHAR_CASEMAP:
+ case SID_ATTR_GLOW_COLOR:
+ case SID_ATTR_GLOW_RADIUS:
+ case SID_ATTR_GLOW_TRANSPARENCY:
+ case SID_ATTR_SOFTEDGE_RADIUS:
+ case SID_SET_SUB_SCRIPT:
+ case SID_SET_SUPER_SCRIPT:
+ {
+ bAttr = true;
+ }
+ break;
+
+ case SID_ATTR_TEXTCOLUMNS_NUMBER:
+ case SID_ATTR_TEXTCOLUMNS_SPACING:
+ {
+ SfxItemSet aAttrs(GetDoc()->GetPool());
+ mpDrawView->GetAttributes(aAttrs);
+ const sal_uInt16 nActWhich = nSlotId == SID_ATTR_TEXTCOLUMNS_NUMBER
+ ? SDRATTR_TEXTCOLUMNS_NUMBER
+ : SDRATTR_TEXTCOLUMNS_SPACING;
+ rSet.Put(aAttrs.Get(nActWhich).CloneSetWhich(nSlotId));
+ }
+ break;
+
+ case SID_HYPHENATION:
+ {
+ SfxItemSet aAttrs( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aAttrs );
+ if( aAttrs.GetItemState( EE_PARA_HYPHENATE ) >= SfxItemState::DEFAULT )
+ {
+ bool bValue = aAttrs.Get( EE_PARA_HYPHENATE ).GetValue();
+ rSet.Put( SfxBoolItem( SID_HYPHENATION, bValue ) );
+ }
+ }
+ break;
+
+ case SID_STYLE_FAMILY2:
+ case SID_STYLE_FAMILY3:
+ case SID_STYLE_FAMILY5:
+ case SID_STYLE_APPLY: // StyleControl
+ {
+ SfxStyleSheet* pStyleSheet = mpDrawView->GetStyleSheet();
+ if( pStyleSheet )
+ {
+ if( nSlotId != SID_STYLE_APPLY && !mpDrawView->AreObjectsMarked() )
+ {
+ SfxTemplateItem aTmpItem( nWhich, OUString() );
+ aAllSet.Put( aTmpItem, aTmpItem.Which() );
+ }
+ else
+ {
+ if (pStyleSheet->GetFamily() == SfxStyleFamily::Page)
+ pStyleSheet = static_cast<SdStyleSheet*>(pStyleSheet)->GetPseudoStyleSheet();
+
+ if( pStyleSheet )
+ {
+ SfxStyleFamily eFamily = pStyleSheet->GetFamily();
+
+ if ((eFamily == SfxStyleFamily::Para && nSlotId == SID_STYLE_FAMILY2) ||
+ (eFamily == SfxStyleFamily::Frame && nSlotId == SID_STYLE_FAMILY3) ||
+ (eFamily == SfxStyleFamily::Pseudo && nSlotId == SID_STYLE_FAMILY5))
+ {
+ SfxTemplateItem aTmpItem ( nWhich, pStyleSheet->GetName() );
+ aAllSet.Put( aTmpItem, aTmpItem.Which() );
+ }
+ else
+ {
+ SfxTemplateItem aTmpItem(nWhich, OUString());
+ aAllSet.Put(aTmpItem,aTmpItem.Which() );
+ }
+ }
+ }
+ }
+ else
+ { SfxTemplateItem aItem( nWhich, OUString() );
+ aAllSet.Put( aItem, aItem.Which() );
+ }
+ }
+ break;
+
+ case SID_SET_DEFAULT:
+ {
+ if( !mpDrawView->GetMarkedObjectList().GetMarkCount() ||
+ ( !mpDrawView->IsTextEdit() && !mpDrawView->GetStyleSheet() )
+ )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_REMOVE_HYPERLINK:
+ {
+ if (!URLFieldHelper::IsCursorAtURLField(mpDrawView->GetTextEditOutlinerView()))
+ rSet.DisableItem(nWhich);
+ }
+ break;
+
+ case SID_STYLE_WATERCAN:
+ {
+ std::unique_ptr<SfxUInt16Item> pFamilyItem;
+ GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem);
+ if (pFamilyItem && static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Pseudo)
+ rSet.Put(SfxBoolItem(nWhich,false));
+ else
+ {
+ SfxBoolItem aItem(nWhich, SD_MOD()->GetWaterCan());
+ aAllSet.Put( aItem, aItem.Which());
+ }
+ }
+ break;
+
+ case SID_STYLE_NEW:
+ {
+ std::unique_ptr<SfxUInt16Item> pFamilyItem;
+ GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem);
+ if (pFamilyItem && static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Pseudo)
+ {
+ rSet.DisableItem(nWhich);
+ }
+ }
+ break;
+
+ case SID_STYLE_DRAGHIERARCHIE:
+ {
+ std::unique_ptr<SfxUInt16Item> pFamilyItem;
+ GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem);
+ if (pFamilyItem && static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Pseudo)
+ rSet.DisableItem(nWhich);
+ }
+ break;
+
+ case SID_STYLE_NEW_BY_EXAMPLE:
+ {
+ // It is not possible to create PseudoStyleSheets 'by Example';
+ // normal style sheets need a selected object for that
+
+ std::unique_ptr<SfxUInt16Item> pFamilyItem;
+ GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem);
+ if (pFamilyItem)
+ {
+ if (static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Pseudo)
+ {
+ rSet.DisableItem(nWhich);
+ }
+ else if (static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Para)
+ {
+ if (!mpDrawView->AreObjectsMarked())
+ {
+ rSet.DisableItem(nWhich);
+ }
+ }
+ }
+ // if there is no (yet) a style designer, we have to go back into the
+ // view state; an actual set family can not be considered
+ else
+ {
+ if (!mpDrawView->AreObjectsMarked())
+ {
+ rSet.DisableItem(nWhich);
+ }
+ }
+ }
+ break;
+
+ case SID_STYLE_UPDATE_BY_EXAMPLE:
+ {
+ if (!mpDrawView->AreObjectsMarked())
+ {
+ rSet.DisableItem(nWhich);
+ }
+ }
+ break;
+ case FN_BUL_NUM_RULE_INDEX:
+ case FN_NUM_NUM_RULE_INDEX:
+ {
+ SfxItemSet aEditAttr( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( aEditAttr );
+
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aNewAttr( GetPool() );
+ aNewAttr.Put( aEditAttr, false );
+
+ std::unique_ptr<SvxNumRule> pNumRule;
+ const SfxPoolItem* pTmpItem=nullptr;
+ TypedWhichId<SvxNumBulletItem> nNumItemId = SID_ATTR_NUMBERING_RULE;
+ sal_uInt16 nActNumLvl = mpDrawView->GetSelectionLevel();
+ pTmpItem=GetNumBulletItem(aNewAttr, nNumItemId);
+
+ if (pTmpItem)
+ pNumRule.reset(new SvxNumRule(static_cast<const SvxNumBulletItem*>(pTmpItem)->GetNumRule()));
+
+ if ( pNumRule )
+ {
+ sal_uInt16 nMask = 1;
+ sal_uInt16 nCount = 0;
+ sal_uInt16 nCurLevel = sal_uInt16(0xFFFF);
+ for(sal_uInt16 i = 0; i < pNumRule->GetLevelCount(); i++)
+ {
+ if(nActNumLvl & nMask)
+ {
+ nCount++;
+ nCurLevel = i;
+ }
+ nMask <<= 1;
+ }
+ if ( nCount == 1 )
+ {
+ const SvxNumberFormat* pNumFmt = pNumRule->Get(nCurLevel);
+ if ( pNumFmt )
+ {
+ bool bBullets = false;
+ switch(pNumFmt->GetNumberingType())
+ {
+ case SVX_NUM_CHAR_SPECIAL:
+ case SVX_NUM_BITMAP:
+ bBullets = true;
+ break;
+
+ default:
+ bBullets = false;
+ }
+
+ rSet.Put(SfxUInt16Item(FN_BUL_NUM_RULE_INDEX,sal_uInt16(0xFFFF)));
+ rSet.Put(SfxUInt16Item(FN_NUM_NUM_RULE_INDEX,sal_uInt16(0xFFFF)));
+ if ( bBullets )
+ {
+ NBOTypeMgrBase* pBullets = NBOutlineTypeMgrFact::CreateInstance(NBOType::Bullets);
+ if ( pBullets )
+ {
+ sal_uInt16 nBulIndex = pBullets->GetNBOIndexForNumRule(*pNumRule,nActNumLvl);
+ rSet.Put(SfxUInt16Item(FN_BUL_NUM_RULE_INDEX,nBulIndex));
+ }
+ }else
+ {
+ NBOTypeMgrBase* pNumbering = NBOutlineTypeMgrFact::CreateInstance(NBOType::Numbering);
+ if ( pNumbering )
+ {
+ sal_uInt16 nBulIndex = pNumbering->GetNBOIndexForNumRule(*pNumRule,nActNumLvl);
+ rSet.Put(SfxUInt16Item(FN_NUM_NUM_RULE_INDEX,nBulIndex));
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case FN_NUM_BULLET_ON:
+ case FN_NUM_NUMBERING_ON:
+ {
+ bool bEnable = false;
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+ for (size_t nIndex = 0; nIndex < nMarkCount; ++nIndex)
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >(rMarkList.GetMark(nIndex)->GetMarkedSdrObj());
+ if (pTextObj && pTextObj->GetObjInventor() == SdrInventor::Default)
+ {
+ if (pTextObj->GetObjIdentifier() != SdrObjKind::OLE2)
+ {
+ bEnable = true;
+ break;
+ }
+ }
+ }
+ if (bEnable)
+ {
+ rSet.Put(SfxBoolItem(FN_NUM_BULLET_ON, false));
+ rSet.Put(SfxBoolItem(FN_NUM_NUMBERING_ON, false));
+ }
+ else
+ {
+ rSet.DisableItem(FN_NUM_BULLET_ON);
+ rSet.DisableItem(FN_NUM_NUMBERING_ON);
+ }
+ }
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+
+ std::optional<SfxItemSet> pSet;
+
+ if( bAttr )
+ {
+ pSet.emplace( GetDoc()->GetPool() );
+ mpDrawView->GetAttributes( *pSet );
+ rSet.Put( *pSet, false );
+ }
+
+ rSet.Put( aAllSet, false );
+
+ // there were changes at area and/or line attributes
+ if( !(bAttr && pSet) )
+ return;
+
+ // if the view owns selected objects, corresponding items have to be
+ // changed from SfxItemState::DEFAULT (_ON) to SfxItemState::DISABLED
+ if( mpDrawView->AreObjectsMarked() )
+ {
+ SfxWhichIter aNewIter( *pSet );
+ nWhich = aNewIter.FirstWhich();
+ while( nWhich )
+ {
+ if (nWhich >= XATTR_LINE_FIRST && nWhich <= XATTR_LINE_LAST
+ && SfxItemState::DEFAULT == aNewIter.GetItemState() )
+ {
+ rSet.ClearItem( nWhich );
+ rSet.DisableItem( nWhich );
+ }
+ nWhich = aNewIter.NextWhich();
+ }
+ }
+
+ SfxItemState eState = pSet->GetItemState( EE_PARA_LRSPACE );
+ if ( eState == SfxItemState::DONTCARE )
+ {
+ rSet.InvalidateItem(EE_PARA_LRSPACE);
+ rSet.InvalidateItem(SID_ATTR_PARA_LRSPACE);
+ }
+ eState = pSet->GetItemState( EE_PARA_SBL );
+ if ( eState == SfxItemState::DONTCARE )
+ {
+ rSet.InvalidateItem(EE_PARA_SBL);
+ rSet.InvalidateItem(SID_ATTR_PARA_LINESPACE);
+ }
+ eState = pSet->GetItemState( EE_PARA_ULSPACE );
+ if ( eState == SfxItemState::DONTCARE )
+ {
+ rSet.InvalidateItem(EE_PARA_ULSPACE);
+ rSet.InvalidateItem(SID_ATTR_PARA_ULSPACE);
+ }
+
+ SvxEscapement eEsc = static_cast<SvxEscapement>(pSet->Get( EE_CHAR_ESCAPEMENT ).GetEnumValue());
+ rSet.Put(SfxBoolItem(SID_SET_SUPER_SCRIPT, eEsc == SvxEscapement::Superscript));
+ rSet.Put(SfxBoolItem(SID_SET_SUB_SCRIPT, eEsc == SvxEscapement::Subscript));
+
+ eState = pSet->GetItemState( EE_CHAR_KERNING );
+ if ( eState == SfxItemState::DONTCARE )
+ {
+ rSet.InvalidateItem(EE_CHAR_KERNING);
+ rSet.InvalidateItem(SID_ATTR_CHAR_KERNING);
+ }
+}
+
+OUString DrawViewShell::GetSelectionText(bool bCompleteWords)
+{
+ OUString aStrSelection;
+ ::Outliner* pOl = mpDrawView->GetTextEditOutliner();
+ OutlinerView* pOlView = mpDrawView->GetTextEditOutlinerView();
+
+ if (pOl && pOlView)
+ {
+ if (bCompleteWords)
+ {
+ ESelection aSel = pOlView->GetSelection();
+ OUString aStrCurrentDelimiters = pOl->GetWordDelimiters();
+
+ pOl->SetWordDelimiters(" .,;\"'");
+ aStrSelection = pOl->GetWord( aSel.nEndPara, aSel.nEndPos );
+ pOl->SetWordDelimiters( aStrCurrentDelimiters );
+ }
+ else
+ {
+ aStrSelection = pOlView->GetSelected();
+ }
+ }
+
+ return aStrSelection;
+}
+
+bool DrawViewShell::HasSelection(bool bText) const
+{
+ bool bReturn = false;
+
+ if (bText)
+ {
+ OutlinerView* pOlView = mpDrawView->GetTextEditOutlinerView();
+
+ if (pOlView && !pOlView->GetSelected().isEmpty())
+ {
+ bReturn = true;
+ }
+ }
+ else if (mpDrawView->GetMarkedObjectList().GetMarkCount() != 0)
+ {
+ bReturn = true;
+ }
+
+ return bReturn;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewsg.cxx b/sd/source/ui/view/drviewsg.cxx
new file mode 100644
index 000000000..e3930fa7e
--- /dev/null
+++ b/sd/source/ui/view/drviewsg.cxx
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawViewShell.hxx>
+#include <ViewShellImplementation.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/imapdlg.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/ImageMapInfo.hxx>
+
+#include <app.hrc>
+
+#include <drawdoc.hxx>
+#include <sdmod.hxx>
+#include <optsitem.hxx>
+#include <FrameView.hxx>
+#include <drawview.hxx>
+
+namespace sd {
+
+void DrawViewShell::ExecIMap( SfxRequest const & rReq )
+{
+ // during a slide show, nothing is executed!
+ if(HasCurrentFunction(SID_PRESENTATION) )
+ return;
+
+ if ( rReq.GetSlot() != SID_IMAP_EXEC )
+ return;
+
+ SdrMark* pMark = mpDrawView->GetMarkedObjectList().GetMark(0);
+
+ if ( !pMark )
+ return;
+
+ SdrObject* pSdrObj = pMark->GetMarkedSdrObj();
+ SvxIMapDlg* pDlg = ViewShell::Implementation::GetImageMapDialog();
+
+ if ( pDlg->GetEditingObject() == static_cast<void*>(pSdrObj) )
+ {
+ const ImageMap& rImageMap = pDlg->GetImageMap();
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo( pSdrObj );
+
+ if ( !pIMapInfo )
+ pSdrObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SvxIMapInfo( rImageMap )) );
+ else
+ pIMapInfo->SetImageMap( rImageMap );
+
+ GetDoc()->SetChanged();
+ }
+}
+
+void DrawViewShell::GetIMapState( SfxItemSet& rSet )
+{
+ bool bDisable = true;
+
+ if( GetViewFrame()->HasChildWindow( SvxIMapDlgChildWindow::GetChildWindowId() ) )
+ {
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+
+ if ( rMarkList.GetMarkCount() == 1 )
+ {
+ const SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ SvxIMapDlg* pImageMapDialog = ViewShell::Implementation::GetImageMapDialog();
+ if ( ( dynamic_cast< const SdrGrafObj *>( pObj ) != nullptr /*|| pObj->ISA( SdrOle2Obj )*/ )
+ && pImageMapDialog!=nullptr
+ && ( pImageMapDialog->GetEditingObject() == static_cast<void const *>(pObj) ) )
+ {
+ bDisable = false;
+ }
+ }
+ }
+
+ rSet.Put( SfxBoolItem( SID_IMAP_EXEC, bDisable ) );
+}
+
+void DrawViewShell::ExecOptionsBar( SfxRequest& rReq )
+{
+ // during a slide show, nothing is executed!
+ if(HasCurrentFunction(SID_PRESENTATION))
+ return;
+
+ bool bDefault = false;
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDoc()->GetDocumentType());
+
+ switch( nSlot )
+ {
+ case SID_SOLID_CREATE:
+ pOptions->SetSolidDragging( !mpDrawView->IsSolidDragging() );
+ break;
+
+ // Grid- / Help lines option
+ case SID_GRID_VISIBLE: // not here yet!
+ {
+ pOptions->SetGridVisible( !mpDrawView->IsGridVisible() );
+ }
+ break;
+
+ case SID_GRID_USE:
+ {
+ pOptions->SetUseGridSnap( !mpDrawView->IsGridSnap() );
+ }
+ break;
+
+ case SID_HELPLINES_VISIBLE: // not here yet!
+ {
+ pOptions->SetHelplines( !mpDrawView->IsHlplVisible() );
+ }
+ break;
+
+ case SID_HELPLINES_USE:
+ {
+ pOptions->SetSnapHelplines( !mpDrawView->IsHlplSnap() );
+ }
+ break;
+
+ case SID_HELPLINES_MOVE:
+ {
+ pOptions->SetDragStripes( !mpDrawView->IsDragStripes() );
+ }
+ break;
+
+ case SID_SNAP_BORDER:
+ {
+ pOptions->SetSnapBorder( !mpDrawView->IsBordSnap() );
+ }
+ break;
+
+ case SID_SNAP_FRAME:
+ {
+ pOptions->SetSnapFrame( !mpDrawView->IsOFrmSnap() );
+ }
+ break;
+
+ case SID_SNAP_POINTS:
+ {
+ pOptions->SetSnapPoints( !mpDrawView->IsOPntSnap() );
+ }
+ break;
+
+ case SID_QUICKEDIT:
+ {
+ pOptions->SetQuickEdit( !mpDrawView->IsQuickTextEditMode() );
+ }
+ break;
+
+ case SID_PICK_THROUGH:
+ {
+ pOptions->SetPickThrough(
+ !mpDrawView->GetModel()->IsPickThroughTransparentTextFrames() );
+ }
+ break;
+
+ case SID_DOUBLECLICK_TEXTEDIT:
+ {
+ pOptions->SetDoubleClickTextEdit( !mpFrameView->IsDoubleClickTextEdit() );
+ }
+ break;
+
+ case SID_CLICK_CHANGE_ROTATION:
+ {
+ pOptions->SetClickChangeRotation( !mpFrameView->IsClickChangeRotation() );
+ }
+ break;
+
+ default:
+ bDefault = true;
+ break;
+ }
+
+ if( bDefault )
+ return;
+
+ pOptions->StoreConfig();
+
+ // Saves the configuration IMMEDIATELY
+ // SfxGetpApp()->SaveConfiguration();
+ WriteFrameViewData();
+
+ mpFrameView->Update( pOptions );
+ ReadFrameViewData( mpFrameView );
+
+ Invalidate( nSlot );
+ rReq.Done();
+
+}
+
+void DrawViewShell::GetOptionsBarState( SfxItemSet& rSet )
+{
+ rSet.Put( SfxBoolItem( SID_SOLID_CREATE, mpDrawView->IsSolidDragging() ) );
+ rSet.Put( SfxBoolItem( SID_GRID_VISIBLE, mpDrawView->IsGridVisible() ) );
+ rSet.Put( SfxBoolItem( SID_GRID_USE, mpDrawView->IsGridSnap() ) );
+ rSet.Put( SfxBoolItem( SID_HELPLINES_VISIBLE, mpDrawView->IsHlplVisible() ) );
+ rSet.Put( SfxBoolItem( SID_HELPLINES_USE, mpDrawView->IsHlplSnap() ) );
+ rSet.Put( SfxBoolItem( SID_HELPLINES_MOVE, mpDrawView->IsDragStripes() ) );
+
+ rSet.Put( SfxBoolItem( SID_SNAP_BORDER, mpDrawView->IsBordSnap() ) );
+ rSet.Put( SfxBoolItem( SID_SNAP_FRAME, mpDrawView->IsOFrmSnap() ) );
+ rSet.Put( SfxBoolItem( SID_SNAP_POINTS, mpDrawView->IsOPntSnap() ) );
+
+ rSet.Put( SfxBoolItem( SID_QUICKEDIT, mpDrawView->IsQuickTextEditMode() ) );
+ rSet.Put( SfxBoolItem( SID_PICK_THROUGH,
+ mpDrawView->GetModel()->IsPickThroughTransparentTextFrames() ) );
+
+ rSet.Put( SfxBoolItem( SID_DOUBLECLICK_TEXTEDIT, mpFrameView->IsDoubleClickTextEdit() ) );
+ rSet.Put( SfxBoolItem( SID_CLICK_CHANGE_ROTATION, mpFrameView->IsClickChangeRotation() ) );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewsh.cxx b/sd/source/ui/view/drviewsh.cxx
new file mode 100644
index 000000000..c0e09a478
--- /dev/null
+++ b/sd/source/ui/view/drviewsh.cxx
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DrawViewShell.hxx>
+
+#include <sal/log.hxx>
+#include <rtl/math.hxx>
+#include <comphelper/lok.hxx>
+
+#include <DrawDocShell.hxx>
+
+#include <slideshow.hxx>
+
+namespace sd {
+
+void DrawViewShell::GotoBookmark(std::u16string_view rBookmark)
+{
+ ::sd::DrawDocShell* pDocSh = GetDocSh();
+ if( pDocSh )
+ {
+ if( !pDocSh->GetViewShell() ) //#i26016# this case occurs if the jump-target-document was opened already with file open dialog before triggering the jump via hyperlink
+ pDocSh->Connect(this);
+ pDocSh->GotoBookmark(rBookmark);
+ }
+}
+
+/**
+ * Make area visible (scroll part of picture)
+|*
+\************************************************************************/
+
+void DrawViewShell::MakeVisible(const ::tools::Rectangle& rRect, vcl::Window& rWin)
+{
+ if ( (IsMouseButtonDown() && !IsMouseSelecting()) || SlideShow::IsRunning( GetViewShellBase() ) )
+ return;
+
+ // tdf#98646 check if Rectangle which contains the bounds of the region to
+ // be shown eventually contains values that cause overflows when processing
+ // e.g. when calling GetWidth()
+ const bool bOverflowInX(!rtl::math::approxEqual(static_cast<double>(rRect.getWidth()), static_cast<double>(rRect.Right()) - static_cast<double>(rRect.Left())));
+ const bool bOverflowInY(!rtl::math::approxEqual(static_cast<double>(rRect.getHeight()), static_cast<double>(rRect.Bottom()) - static_cast<double>(rRect.Top())));
+
+ if(bOverflowInX || bOverflowInY)
+ {
+ SAL_WARN("sd", "The given Rectangle contains values that lead to numerical overflows (!)");
+ return;
+ }
+
+ // In older versions, if in X or Y the size of the object was
+ // smaller than the visible area, the user-defined zoom was
+ // changed. This was decided to be a bug for
+ // StarOffice 6.x (Apr 2002), thus I developed a
+ // version which instead handles X/Y bigger/smaller and visibility
+ // questions separately
+ const Size aLogicSize(rRect.GetSize());
+
+ // visible area
+ Size aVisSizePixel(rWin.GetOutputSizePixel());
+ bool bTiledRendering = comphelper::LibreOfficeKit::isActive() && !rWin.IsMapModeEnabled();
+ if (bTiledRendering)
+ {
+ rWin.GetOutDev()->Push(vcl::PushFlags::MAPMODE);
+ rWin.EnableMapMode();
+ }
+ ::tools::Rectangle aVisArea(rWin.PixelToLogic(::tools::Rectangle(Point(0,0), aVisSizePixel)));
+ if (bTiledRendering)
+ rWin.GetOutDev()->Pop();
+ Size aVisAreaSize(aVisArea.GetSize());
+
+ if ( aVisArea.Contains(rRect) )
+ return;
+
+ // object is not entirely in visible area
+ sal_Int32 nFreeSpaceX(aVisAreaSize.Width() - aLogicSize.Width());
+ sal_Int32 nFreeSpaceY(aVisAreaSize.Height() - aLogicSize.Height());
+
+ // allow a mode for move-only visibility without zooming.
+ const sal_Int32 nPercentBorder(30);
+ const ::tools::Rectangle aInnerRectangle(
+ aVisArea.Left() + ((aVisAreaSize.Width() * nPercentBorder) / 200),
+ aVisArea.Top() + ((aVisAreaSize.Height() * nPercentBorder) / 200),
+ aVisArea.Right() - ((aVisAreaSize.Width() * nPercentBorder) / 200),
+ aVisArea.Bottom() - ((aVisAreaSize.Height() * nPercentBorder) / 200)
+ );
+ Point aNewPos(aVisArea.TopLeft());
+
+ if(nFreeSpaceX < 0)
+ {
+ if(aInnerRectangle.Left() > rRect.Right())
+ {
+ // object moves out to the left
+ aNewPos.AdjustX( -(aVisAreaSize.Width() / 2) );
+ }
+
+ if(aInnerRectangle.Right() < rRect.Left())
+ {
+ // object moves out to the right
+ aNewPos.AdjustX(aVisAreaSize.Width() / 2 );
+ }
+ }
+ else
+ {
+ if(nFreeSpaceX > rRect.GetWidth())
+ {
+ nFreeSpaceX = rRect.GetWidth();
+ }
+
+ if(nFreeSpaceX <= 0)
+ {
+ SAL_WARN("sd", "The given Rectangle contains values that lead to numerical overflows (!)");
+ }
+ else
+ {
+ const ::tools::Long distRight(rRect.Right() - aNewPos.X() - aVisAreaSize.Width());
+
+ if(distRight > 0)
+ {
+ ::tools::Long mult = (distRight / nFreeSpaceX) + 1;
+ aNewPos.AdjustX(mult * nFreeSpaceX );
+ }
+
+ const ::tools::Long distLeft(aNewPos.X() - rRect.Left());
+
+ if(distLeft > 0)
+ {
+ ::tools::Long mult = (distLeft / nFreeSpaceX) + 1;
+ aNewPos.AdjustX( -(mult * nFreeSpaceX) );
+ }
+ }
+ }
+
+ if(nFreeSpaceY < 0)
+ {
+ if(aInnerRectangle.Top() > rRect.Bottom())
+ {
+ // object moves out to the top
+ aNewPos.AdjustY( -(aVisAreaSize.Height() / 2) );
+ }
+
+ if(aInnerRectangle.Bottom() < rRect.Top())
+ {
+ // object moves out to the right
+ aNewPos.AdjustY(aVisAreaSize.Height() / 2 );
+ }
+ }
+ else
+ {
+ if(nFreeSpaceY > rRect.GetHeight())
+ {
+ nFreeSpaceY = rRect.GetHeight();
+ }
+
+ if(nFreeSpaceY <= 0)
+ {
+ SAL_WARN("sd", "The given Rectangle contains values that lead to numerical overflows (!)");
+ }
+ else
+ {
+ const ::tools::Long distBottom(rRect.Bottom() - aNewPos.Y() - aVisAreaSize.Height());
+
+ if(distBottom > 0)
+ {
+ ::tools::Long mult = (distBottom / nFreeSpaceY) + 1;
+ aNewPos.AdjustY(mult * nFreeSpaceY );
+ }
+
+ const ::tools::Long distTop(aNewPos.Y() - rRect.Top());
+
+ if(distTop > 0)
+ {
+ ::tools::Long mult = (distTop / nFreeSpaceY) + 1;
+ aNewPos.AdjustY( -(mult * nFreeSpaceY) );
+ }
+ }
+ }
+
+ // did position change? Does it need to be set?
+ if(aNewPos != aVisArea.TopLeft())
+ {
+ aVisArea.SetPos(aNewPos);
+ SetZoomRect(aVisArea);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewsi.cxx b/sd/source/ui/view/drviewsi.cxx
new file mode 100644
index 000000000..039840824
--- /dev/null
+++ b/sd/source/ui/view/drviewsi.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 <DrawViewShell.hxx>
+#include <svx/xfillit0.hxx>
+#include <editeng/eeitem.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/dispatch.hxx>
+#include <svx/float3d.hxx>
+#include <svx/f3dchild.hxx>
+#include <vcl/weld.hxx>
+
+#include <strings.hrc>
+
+#include <drawdoc.hxx>
+#include <Window.hxx>
+#include <sdresid.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd {
+
+/**
+ * Handle SfxRequests for EffekteWindow
+ */
+void DrawViewShell::ExecEffectWin( SfxRequest& rReq )
+{
+ CheckLineTo (rReq);
+
+ sal_uInt16 nSId = rReq.GetSlot();
+
+ switch( nSId )
+ {
+ case SID_3D_INIT:
+ {
+ sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId();
+ SfxChildWindow* pWindow = GetViewFrame()->GetChildWindow( nId );
+ if( pWindow )
+ {
+ Svx3DWin* p3DWin = static_cast<Svx3DWin*>( pWindow->GetWindow() );
+ if( p3DWin )
+ p3DWin->InitColorLB();
+ }
+ }
+ break;
+
+ case SID_3D_STATE:
+ {
+ Update3DWindow();
+ }
+ break;
+
+ case SID_3D_ASSIGN:
+ {
+ AssignFrom3DWindow();
+ }
+ break;
+
+ }
+}
+
+void DrawViewShell::Update3DWindow()
+{
+ sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId();
+ SfxChildWindow* pWindow = GetViewFrame()->GetChildWindow( nId );
+ if( pWindow )
+ {
+ Svx3DWin* p3DWin = static_cast<Svx3DWin*>( pWindow->GetWindow() );
+ if( p3DWin && p3DWin->IsUpdateMode() )
+ {
+ SfxItemSet aTmpItemSet = GetView()->Get3DAttributes();
+ p3DWin->Update( aTmpItemSet );
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+void DrawViewShell::AssignFrom3DWindow()
+{
+ sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId();
+ SfxChildWindow* pWin = GetViewFrame()->GetChildWindow( nId );
+ if( !pWin )
+ return;
+
+ Svx3DWin* p3DWin = static_cast<Svx3DWin*>( pWin->GetWindow() );
+ if( !(p3DWin && GetView()) )
+ return;
+
+ if(!GetView()->IsPresObjSelected())
+ {
+ SfxItemSetFixed<SDRATTR_START, SDRATTR_END> aSet( GetDoc()->GetPool() );
+ p3DWin->GetAttr( aSet );
+
+ // own UNDO-compounding also around transformation in 3D
+ GetView()->BegUndo(SdResId(STR_UNDO_APPLY_3D_FAVOURITE));
+
+ if(GetView()->IsConvertTo3DObjPossible())
+ {
+ // assign only text-attribute
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aTextSet( GetDoc()->GetPool() );
+ aTextSet.Put( aSet, false );
+ GetView()->SetAttributes( aTextSet );
+
+ // transform text into 3D
+ sal_uInt16 nSId = SID_CONVERT_TO_3D;
+ SfxBoolItem aItem( nSId, true );
+ GetViewFrame()->GetDispatcher()->ExecuteList(
+ nSId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aItem });
+
+ // Determine if a FILL attribute is set.
+ // If not, hard set a fill attribute
+ drawing::FillStyle eFillStyle = aSet.Get(XATTR_FILLSTYLE).GetValue();
+ if(eFillStyle == drawing::FillStyle_NONE)
+ aSet.Put(XFillStyleItem (drawing::FillStyle_SOLID));
+
+ // remove some 3DSCENE attributes since these were
+ // created by convert to 3D and may not be changed
+ // to the defaults again.
+ aSet.ClearItem(SDRATTR_3DSCENE_DISTANCE);
+ aSet.ClearItem(SDRATTR_3DSCENE_FOCAL_LENGTH);
+ aSet.ClearItem(SDRATTR_3DOBJ_DEPTH);
+ }
+
+ // assign attribute
+ GetView()->Set3DAttributes( aSet );
+
+ // end UNDO
+ GetView()->EndUndo();
+ }
+ else
+ {
+ vcl::Window* pWindow = GetActiveWindow();
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWindow ? pWindow->GetFrameWeld() : nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+
+ // get focus back
+ GetActiveWindow()->GrabFocus();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewsj.cxx b/sd/source/ui/view/drviewsj.cxx
new file mode 100644
index 000000000..a1a7d899f
--- /dev/null
+++ b/sd/source/ui/view/drviewsj.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 <DrawViewShell.hxx>
+#include <com/sun/star/embed/EmbedMisc.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/presentation/ClickAction.hpp>
+#include <sfx2/objsh.hxx>
+#include <svx/svxids.hrc>
+#include <svx/sdmetitm.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+
+#include <app.hrc>
+
+#include <anminfo.hxx>
+#include <drawdoc.hxx>
+#include <drawview.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+/**
+ * Set state (Enabled/Disabled) of Menu-SfxSlots
+ */
+void DrawViewShell::GetMenuStateSel( SfxItemSet &rSet )
+{
+ // Status of menu entries (Buttons,...)
+
+ // Single selection
+ const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+
+ if ( nMarkCount == 1 )
+ {
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_BEZIER_EDIT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_UNGROUP ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_ENTER_GROUP ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_NAME_GROUP ) ||
+
+ // #i68101#
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_TITLE_DESCRIPTION ) ||
+
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_FILL_STYLE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_FILL_USE_SLIDE_BACKGROUND ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_FILL_TRANSPARENCE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_FILL_FLOATTRANSPARENCE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_CHANGEBEZIER ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_CHANGEPOLYGON ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_LINEEND_POLYGON ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_MEASURE_DLG ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_CONNECTION_DLG ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_CONNECTION_NEW_ROUTING ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_SHEAR ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_LEFT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_CENTER ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_RIGHT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_UP ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_MIDDLE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_DOWN ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_FRAME_TO_TOP ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_MOREFRONT ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_FRAME_UP ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_MOREBACK ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_FRAME_DOWN ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_FRAME_TO_BOTTOM ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_BEFORE_OBJ ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_BEHIND_OBJ ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_REVERSE_ORDER ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_ORIGINAL_SIZE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_SAVE_GRAPHIC ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_COMPRESS_GRAPHIC ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_TEXTATTR_DLG ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_EXECUTE_ANIMATION_EFFECT ))
+ {
+ const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(pObj);
+ const SdrOle2Obj* pSdrOle2Obj = dynamic_cast< const SdrOle2Obj* >(pObj);
+ const SdAnimationInfo* pAnimationInfo
+ = SdDrawDocument::GetAnimationInfo(rMarkList.GetMark(0)->GetMarkedSdrObj());
+ SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nId = pObj->GetObjIdentifier();
+ SdrObjTransformInfoRec aInfoRec;
+ pObj->TakeObjInfo( aInfoRec );
+
+ // don't show original size entry if not possible
+ if(pSdrOle2Obj)
+ {
+ if (pSdrOle2Obj->GetObjRef().is() &&
+ (pSdrOle2Obj->GetObjRef()->getStatus( pSdrOle2Obj->GetAspect() ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE) )
+ rSet.DisableItem(SID_ORIGINAL_SIZE);
+ }
+
+ if(!pSdrGrafObj)
+ {
+ rSet.DisableItem(SID_SAVE_GRAPHIC);
+ rSet.DisableItem(SID_COMPRESS_GRAPHIC);
+ }
+
+ if (!pAnimationInfo
+ || pAnimationInfo->meClickAction == presentation::ClickAction::ClickAction_NONE
+ // Sound does not work in edit mode
+ || pAnimationInfo->meClickAction == presentation::ClickAction::ClickAction_SOUND
+ // No point in exiting the presentation in edit mode
+ || pAnimationInfo->meClickAction
+ == presentation::ClickAction::ClickAction_STOPPRESENTATION)
+ {
+ rSet.DisableItem(SID_EXECUTE_ANIMATION_EFFECT);
+ }
+
+ /* If it is not a group object or 3D object, we disable "enter
+ group". */
+ const auto* pSdrObjGroup = dynamic_cast<const SdrObjGroup*>(pObj);
+
+ if( !( ( pSdrObjGroup != nullptr && nInv == SdrInventor::Default ) ||
+ ( dynamic_cast< const E3dScene* >(pObj) != nullptr ) ) )
+ {
+ rSet.DisableItem( SID_ENTER_GROUP );
+ }
+
+ // Don't allow enter Diagrams
+ if(nullptr != pSdrObjGroup && pSdrObjGroup->isDiagram())
+ {
+ rSet.DisableItem( SID_ENTER_GROUP );
+ }
+
+ // If it is not a group object, we disable "ungroup"
+ if(pSdrObjGroup == nullptr || nInv != SdrInventor::Default)
+ {
+ rSet.DisableItem(SID_UNGROUP);
+ }
+
+ // Support advanced DiagramHelper
+ if(!pSdrObjGroup || !pSdrObjGroup->isDiagram())
+ {
+ rSet.DisableItem( SID_REGENERATE_DIAGRAM );
+ rSet.DisableItem( SID_EDIT_DIAGRAM );
+ }
+
+ if( nInv == SdrInventor::Default &&
+ (nId == SdrObjKind::Line ||
+ nId == SdrObjKind::PolyLine ||
+ nId == SdrObjKind::PathLine ||
+ nId == SdrObjKind::FreehandLine ))
+ {
+ //rSet.DisableItem( SID_ATTRIBUTES_AREA ); // remove again!
+ rSet.DisableItem( SID_ATTR_FILL_STYLE );
+ rSet.DisableItem( SID_ATTR_FILL_USE_SLIDE_BACKGROUND );
+ rSet.DisableItem( SID_ATTR_FILL_TRANSPARENCE );
+ rSet.DisableItem( SID_ATTR_FILL_FLOATTRANSPARENCE );
+ }
+ if( (dynamic_cast< const SdrPathObj *>( pObj ) == nullptr&& !aInfoRec.bCanConvToPath) || dynamic_cast< const SdrObjGroup *>( pObj ) != nullptr ) // As long as JOE handles it incorrectly!
+ { // JOE: a group object may can be converted into a PathObj
+ rSet.DisableItem( SID_LINEEND_POLYGON );
+ }
+ if(nInv == SdrInventor::Default &&
+ (nId == SdrObjKind::PathFill || nId == SdrObjKind::PathLine || !aInfoRec.bCanConvToPath))
+ rSet.DisableItem( SID_CHANGEBEZIER );
+
+ if( nInv == SdrInventor::Default &&
+ ( nId == SdrObjKind::Polygon || nId == SdrObjKind::PolyLine || !aInfoRec.bCanConvToPoly ) &&
+ !GetView()->IsVectorizeAllowed() )
+ {
+ rSet.DisableItem( SID_CHANGEPOLYGON );
+ }
+
+ if(nInv == SdrInventor::Default && nId == SdrObjKind::Table )
+ {
+ rSet.DisableItem( SID_TEXTATTR_DLG );
+ }
+
+ if( nInv != SdrInventor::Default || nId != SdrObjKind::Measure )
+ rSet.DisableItem( SID_MEASURE_DLG );
+
+ if( nInv != SdrInventor::Default || nId != SdrObjKind::Edge )
+ rSet.DisableItem( SID_CONNECTION_DLG );
+ else
+ {
+ bool bDisable = true;
+ SfxItemSet aAttrSet( GetDoc()->GetPool() );
+ GetView()->GetAttributes( aAttrSet );
+
+ if( aAttrSet.GetItemState( SDRATTR_EDGELINE1DELTA ) >= SfxItemState::DEFAULT &&
+ aAttrSet.GetItemState( SDRATTR_EDGELINE2DELTA ) >= SfxItemState::DEFAULT &&
+ aAttrSet.GetItemState( SDRATTR_EDGELINE3DELTA ) >= SfxItemState::DEFAULT )
+ {
+ ::tools::Long nVal1 = aAttrSet.Get( SDRATTR_EDGELINE1DELTA ).GetValue();
+ ::tools::Long nVal2 = aAttrSet.Get( SDRATTR_EDGELINE2DELTA ).GetValue();
+ ::tools::Long nVal3 = aAttrSet.Get( SDRATTR_EDGELINE3DELTA ).GetValue();
+ {
+ if( nVal1 != 0 || nVal2 != 0 || nVal3 != 0 )
+ bDisable = false;
+ }
+ }
+ if( bDisable )
+ rSet.DisableItem( SID_CONNECTION_NEW_ROUTING );
+ }
+
+ if ( nInv == SdrInventor::E3d ||
+ (!mpDrawView->IsConvertToPathObjPossible() &&
+ !mpDrawView->IsShearAllowed() &&
+ !mpDrawView->IsDistortAllowed()) )
+ {
+ rSet.DisableItem( SID_OBJECT_SHEAR );
+ }
+
+ if(dynamic_cast< const E3dCompoundObject *>( pObj ) != nullptr)
+ {
+ rSet.DisableItem( SID_OBJECT_ALIGN );
+ rSet.DisableItem( SID_OBJECT_ALIGN_LEFT );
+ rSet.DisableItem( SID_OBJECT_ALIGN_CENTER );
+ rSet.DisableItem( SID_OBJECT_ALIGN_RIGHT );
+ rSet.DisableItem( SID_OBJECT_ALIGN_UP );
+ rSet.DisableItem( SID_OBJECT_ALIGN_MIDDLE );
+ rSet.DisableItem( SID_OBJECT_ALIGN_DOWN );
+ rSet.DisableItem( SID_FRAME_TO_TOP );
+ rSet.DisableItem( SID_MOREFRONT );
+ rSet.DisableItem( SID_FRAME_UP );
+ rSet.DisableItem( SID_MOREBACK );
+ rSet.DisableItem( SID_FRAME_DOWN );
+ rSet.DisableItem( SID_FRAME_TO_BOTTOM );
+ rSet.DisableItem( SID_BEFORE_OBJ );
+ rSet.DisableItem( SID_BEHIND_OBJ );
+ rSet.DisableItem( SID_REVERSE_ORDER );
+ rSet.DisableItem( SID_POSITION );
+ }
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_DISMANTLE ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_BREAK ) )
+ {
+ if ( !mpDrawView->IsDismantlePossible() )
+ {
+ rSet.DisableItem( SID_DISMANTLE );
+ }
+
+ if ( !mpDrawView->IsDismantlePossible(true) &&
+ !mpDrawView->IsImportMtfPossible() &&
+ !mpDrawView->IsBreak3DObjPossible() )
+ {
+ rSet.DisableItem( SID_BREAK );
+ }
+ }
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_MODIFY_FIELD ) )
+ {
+ OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView();
+
+ if( pOLV )
+ {
+ const SvxFieldItem* pFldItem = pOLV->GetFieldAtSelection();
+
+ if( !( pFldItem && (nullptr != dynamic_cast< const SvxDateField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxAuthorField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtFileField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtTimeField *>( pFldItem->GetField() ) ) ) )
+ {
+ rSet.DisableItem( SID_MODIFY_FIELD );
+ }
+ }
+ else
+ rSet.DisableItem( SID_MODIFY_FIELD );
+ }
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTLINE_TEXT_AUTOFIT ) )
+ {
+ const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ const SdrTextFitToSizeTypeItem* pItem = pObj->GetMergedItemSet().GetItem<SdrTextFitToSizeTypeItem>(SDRATTR_TEXT_FITTOSIZE);
+ const bool bSet = pItem && pItem->GetValue() != drawing::TextFitToSizeType_NONE;
+ rSet.Put(SfxBoolItem(SID_OUTLINE_TEXT_AUTOFIT, bSet));
+ }
+
+ rSet.DisableItem(SID_GROUP);
+ rSet.DisableItem(SID_TEXT_COMBINE);
+ rSet.DisableItem(SID_COMBINE);
+ rSet.DisableItem(SID_DISTRIBUTE_HLEFT);
+ rSet.DisableItem(SID_DISTRIBUTE_HCENTER);
+ rSet.DisableItem(SID_DISTRIBUTE_HDISTANCE);
+ rSet.DisableItem(SID_DISTRIBUTE_HRIGHT);
+ rSet.DisableItem(SID_DISTRIBUTE_VTOP);
+ rSet.DisableItem(SID_DISTRIBUTE_VCENTER);
+ rSet.DisableItem(SID_DISTRIBUTE_VDISTANCE);
+ rSet.DisableItem(SID_DISTRIBUTE_VBOTTOM);
+ rSet.DisableItem(SID_POLY_MERGE);
+ rSet.DisableItem(SID_POLY_SUBSTRACT);
+ rSet.DisableItem(SID_POLY_INTERSECT);
+ rSet.DisableItem(SID_EQUALIZEWIDTH);
+ rSet.DisableItem(SID_EQUALIZEHEIGHT);
+ rSet.DisableItem(SID_CONNECT);
+ }
+ // multi-selection
+ else if( nMarkCount > 1 )
+ {
+ // distribute dialog for 3+n objects
+ if(nMarkCount <= 2)
+ {
+ rSet.DisableItem(SID_DISTRIBUTE_HLEFT);
+ rSet.DisableItem(SID_DISTRIBUTE_HCENTER);
+ rSet.DisableItem(SID_DISTRIBUTE_HDISTANCE);
+ rSet.DisableItem(SID_DISTRIBUTE_HRIGHT);
+ rSet.DisableItem(SID_DISTRIBUTE_VTOP);
+ rSet.DisableItem(SID_DISTRIBUTE_VCENTER);
+ rSet.DisableItem(SID_DISTRIBUTE_VDISTANCE);
+ rSet.DisableItem(SID_DISTRIBUTE_VBOTTOM);
+ }
+
+ rSet.DisableItem( SID_LINEEND_POLYGON );
+ rSet.DisableItem( SID_ENTER_GROUP );
+ // Now names for objects have to be unique
+ rSet.DisableItem( SID_NAME_GROUP );
+ // #i68101#
+ rSet.DisableItem( SID_OBJECT_TITLE_DESCRIPTION );
+ rSet.DisableItem( SID_MODIFY_FIELD );
+
+ {
+ bool bText = false;
+ bool bLine = false;
+ bool bGroup = false;
+ bool bDrawObj = false;
+ bool b3dObj = false;
+ bool bTable = false;
+ bool bMeasureObj = false;
+ bool bEdgeObj = false; // Connector
+ bool bE3dCompoundObject = false;
+
+ for( size_t i = 0; i < nMarkCount && !bText && i < 50; ++i )
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nId = pObj->GetObjIdentifier();
+
+ if (nInv == SdrInventor::Default)
+ {
+ switch (nId)
+ {
+ case SdrObjKind::Text: bText = true; break;
+
+ case SdrObjKind::Line: bLine = true; break;
+
+ case SdrObjKind::Edge: bEdgeObj = true; break;
+
+ case SdrObjKind::Measure: bMeasureObj = true; break;
+
+ case SdrObjKind::Rectangle:
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathFill:
+ case SdrObjKind::PathLine:
+ case SdrObjKind::CircleSection:
+ case SdrObjKind::CircleArc:
+ case SdrObjKind::CircleCut: bDrawObj = true; break;
+
+ case SdrObjKind::Group: bGroup = true; break;
+
+ case SdrObjKind::Graphic: break;
+
+ case SdrObjKind::Table: bTable = true; break;
+ default: ;
+ }
+ }
+ else if (nInv == SdrInventor::E3d)
+ {
+ if(dynamic_cast< const E3dScene *>( pObj ) != nullptr)
+ b3dObj = true;
+ else if(dynamic_cast< const E3dCompoundObject* >(pObj) != nullptr)
+ bE3dCompoundObject = true;
+ }
+ }
+ if( bLine && !bText && !bDrawObj &&!b3dObj)
+ {
+ rSet.DisableItem( SID_ATTR_FILL_STYLE );
+ rSet.DisableItem( SID_ATTR_FILL_USE_SLIDE_BACKGROUND );
+ rSet.DisableItem( SID_ATTR_FILL_TRANSPARENCE );
+ rSet.DisableItem( SID_ATTR_FILL_FLOATTRANSPARENCE );
+ }
+ if( !bEdgeObj )
+ rSet.DisableItem( SID_CONNECTION_DLG );
+
+ if (b3dObj)
+ {
+ rSet.DisableItem( SID_COMBINE );
+ rSet.DisableItem(SID_POLY_MERGE);
+ rSet.DisableItem(SID_POLY_SUBSTRACT);
+ rSet.DisableItem(SID_POLY_INTERSECT);
+ rSet.DisableItem(SID_EQUALIZEWIDTH);
+ rSet.DisableItem(SID_EQUALIZEHEIGHT);
+ }
+
+ if (b3dObj ||
+ (!mpDrawView->IsConvertToPathObjPossible() &&
+ !mpDrawView->IsShearAllowed() &&
+ !mpDrawView->IsDistortAllowed()) )
+ {
+ rSet.DisableItem( SID_OBJECT_SHEAR );
+ }
+
+ if( !bGroup )
+ {
+ rSet.DisableItem( SID_UNGROUP );
+ }
+ if( bTable )
+ rSet.DisableItem( SID_TEXTATTR_DLG );
+
+ if( !bMeasureObj )
+ rSet.DisableItem( SID_MEASURE_DLG );
+
+ if(bE3dCompoundObject)
+ {
+ rSet.DisableItem( SID_OBJECT_ALIGN );
+ rSet.DisableItem( SID_OBJECT_ALIGN_LEFT );
+ rSet.DisableItem( SID_OBJECT_ALIGN_CENTER );
+ rSet.DisableItem( SID_OBJECT_ALIGN_RIGHT );
+ rSet.DisableItem( SID_OBJECT_ALIGN_UP );
+ rSet.DisableItem( SID_OBJECT_ALIGN_MIDDLE );
+ rSet.DisableItem( SID_OBJECT_ALIGN_DOWN );
+ rSet.DisableItem( SID_FRAME_TO_TOP );
+ rSet.DisableItem( SID_MOREFRONT );
+ rSet.DisableItem( SID_FRAME_UP );
+ rSet.DisableItem( SID_MOREBACK );
+ rSet.DisableItem( SID_FRAME_DOWN );
+ rSet.DisableItem( SID_FRAME_TO_BOTTOM );
+ rSet.DisableItem( SID_BEFORE_OBJ );
+ rSet.DisableItem( SID_BEHIND_OBJ );
+ rSet.DisableItem( SID_REVERSE_ORDER );
+ rSet.DisableItem( SID_POSITION );
+ }
+ }
+
+ if ( !mpDrawView->IsDismantlePossible() )
+ {
+ rSet.DisableItem( SID_DISMANTLE );
+ }
+ if ( !mpDrawView->IsDismantlePossible(true) &&
+ !mpDrawView->IsImportMtfPossible() &&
+ !mpDrawView->IsBreak3DObjPossible() )
+ {
+ rSet.DisableItem( SID_BREAK );
+ }
+ if ( !mpDrawView->IsCombinePossible() )
+ {
+ rSet.DisableItem(SID_COMBINE);
+ rSet.DisableItem(SID_POLY_MERGE);
+ rSet.DisableItem(SID_POLY_SUBSTRACT);
+ rSet.DisableItem(SID_POLY_INTERSECT);
+ rSet.DisableItem(SID_EQUALIZEWIDTH);
+ rSet.DisableItem(SID_EQUALIZEHEIGHT);
+ }
+ if ( !mpDrawView->IsCombinePossible(true) )
+ {
+ rSet.DisableItem( SID_CONNECT );
+ }
+ if ( !mpDrawView->IsGroupPossible() )
+ {
+ rSet.DisableItem( SID_GROUP );
+ }
+ if ( !mpDrawView->IsUnGroupPossible() )
+ {
+ rSet.DisableItem( SID_UNGROUP );
+ }
+ }
+ // select no object
+ else
+ {
+ rSet.DisableItem( SID_ENTER_GROUP );
+ rSet.DisableItem( SID_CUT );
+ rSet.DisableItem( SID_COPY );
+ rSet.DisableItem( SID_DELETE );
+ rSet.DisableItem( SID_ATTR_TRANSFORM );
+
+ rSet.DisableItem( SID_OBJECT_ALIGN );
+ rSet.DisableItem( SID_OBJECT_ALIGN_LEFT );
+ rSet.DisableItem( SID_OBJECT_ALIGN_CENTER );
+ rSet.DisableItem( SID_OBJECT_ALIGN_RIGHT );
+ rSet.DisableItem( SID_OBJECT_ALIGN_UP );
+ rSet.DisableItem( SID_OBJECT_ALIGN_MIDDLE );
+ rSet.DisableItem( SID_OBJECT_ALIGN_DOWN );
+
+ rSet.DisableItem( SID_FRAME_TO_TOP );
+ rSet.DisableItem( SID_MOREFRONT );
+ rSet.DisableItem( SID_FRAME_UP );
+ rSet.DisableItem( SID_MOREBACK );
+ rSet.DisableItem( SID_FRAME_DOWN );
+ rSet.DisableItem( SID_FRAME_TO_BOTTOM );
+ rSet.DisableItem( SID_BEFORE_OBJ );
+ rSet.DisableItem( SID_BEHIND_OBJ );
+ rSet.DisableItem( SID_POSITION );
+
+ rSet.DisableItem( SID_SIZE_OPTIMAL );
+ rSet.DisableItem( SID_LINEEND_POLYGON );
+ rSet.DisableItem( SID_COPYOBJECTS );
+ rSet.DisableItem( SID_HORIZONTAL );
+ rSet.DisableItem( SID_VERTICAL );
+ rSet.DisableItem( SID_FLIP_HORIZONTAL );
+ rSet.DisableItem( SID_FLIP_VERTICAL );
+ rSet.DisableItem( SID_GROUP );
+ rSet.DisableItem( SID_UNGROUP );
+ rSet.DisableItem( SID_NAME_GROUP );
+
+ // #i68101#
+ rSet.DisableItem( SID_OBJECT_TITLE_DESCRIPTION );
+
+ rSet.DisableItem( SID_DISMANTLE );
+ rSet.DisableItem( SID_BREAK );
+ rSet.DisableItem( SID_TEXT_COMBINE );
+ rSet.DisableItem( SID_COMBINE );
+ rSet.DisableItem(SID_DISTRIBUTE_DLG);
+ rSet.DisableItem(SID_DISTRIBUTE_HLEFT);
+ rSet.DisableItem(SID_DISTRIBUTE_HCENTER);
+ rSet.DisableItem(SID_DISTRIBUTE_HDISTANCE);
+ rSet.DisableItem(SID_DISTRIBUTE_HRIGHT);
+ rSet.DisableItem(SID_DISTRIBUTE_VTOP);
+ rSet.DisableItem(SID_DISTRIBUTE_VCENTER);
+ rSet.DisableItem(SID_DISTRIBUTE_VDISTANCE);
+ rSet.DisableItem(SID_DISTRIBUTE_VBOTTOM);
+ rSet.DisableItem(SID_POLY_MERGE);
+ rSet.DisableItem(SID_POLY_SUBSTRACT);
+ rSet.DisableItem(SID_POLY_INTERSECT);
+ rSet.DisableItem(SID_EQUALIZEWIDTH);
+ rSet.DisableItem(SID_EQUALIZEHEIGHT);
+ rSet.DisableItem( SID_CONNECT );
+ rSet.DisableItem( SID_ANIMATION_EFFECTS );
+ rSet.DisableItem( SID_EXECUTE_ANIMATION_EFFECT );
+ rSet.DisableItem( SID_MODIFY_FIELD );
+ rSet.DisableItem (SID_OBJECT_SHEAR);
+ }
+
+ if (GetObjectShell()->isContentExtractionLocked())
+ {
+ rSet.DisableItem(SID_COPY);
+ rSet.DisableItem(SID_CUT);
+ }
+ if(GetObjectShell()->isExportLocked())
+ {
+ rSet.DisableItem(SID_SAVE_GRAPHIC);
+ rSet.DisableItem(SID_EXTERNAL_EDIT);
+ }
+ if (GetDoc()->getImagePreferredDPI() <= 0)
+ {
+ rSet.DisableItem(SID_GRAPHIC_SIZE_CHECK);
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/drviewsk.cxx b/sd/source/ui/view/drviewsk.cxx
new file mode 100644
index 000000000..9daeecc02
--- /dev/null
+++ b/sd/source/ui/view/drviewsk.cxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <DrawViewShell.hxx>
+#include <sdmod.hxx>
+
+#include <comphelper/lok.hxx>
+
+namespace sd {
+
+void DrawViewShell::ConfigurationChanged( utl::ConfigurationBroadcaster* pCb, ConfigurationHints )
+{
+ ConfigureAppBackgroundColor( dynamic_cast<svtools::ColorConfig*>(pCb) );
+}
+
+void DrawViewShell::ConfigureAppBackgroundColor( svtools::ColorConfig *pColorConfig )
+{
+ if (!pColorConfig)
+ pColorConfig = &SD_MOD()->GetColorConfig();
+ Color aFillColor( pColorConfig->GetColorValue( svtools::APPBACKGROUND ).nColor );
+ if (comphelper::LibreOfficeKit::isActive())
+ aFillColor = COL_TRANSPARENT;
+ // tdf#87905 Use darker background color for master view
+ if (meEditMode == EditMode::MasterPage)
+ aFillColor.DecreaseLuminance( 64 );
+ mnAppBackgroundColor = aFillColor;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sd/source/ui/view/drvwshrg.cxx b/sd/source/ui/view/drvwshrg.cxx
new file mode 100644
index 000000000..792d5b833
--- /dev/null
+++ b/sd/source/ui/view/drvwshrg.cxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <DrawViewShell.hxx>
+#include <sfx2/infobar.hxx>
+
+#include <svx/fontwork.hxx>
+#include <svx/bmpmask.hxx>
+#include <svx/imapdlg.hxx>
+#include <svx/SvxColorChildWindow.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/sidebar/SidebarChildWindow.hxx>
+#include <sfx2/devtools/DevelopmentToolChildWindow.hxx>
+#include <svx/f3dchild.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/hyperdlg.hxx>
+#include <avmedia/mediaplayer.hxx>
+
+#include <app.hrc>
+
+#include <SpellDialogChildWindow.hxx>
+#include <GraphicViewShell.hxx>
+#include <AnimationChildWindow.hxx>
+
+using namespace sd;
+#define ShellClass_DrawViewShell
+#include <sdslots.hxx>
+#define ShellClass_GraphicViewShell
+#include <sdgslots.hxx>
+
+namespace sd
+{
+/**
+ * Declare SFX-Slotmap and Standardinterface
+ */
+
+SFX_IMPL_INTERFACE(DrawViewShell, SfxShell)
+
+void DrawViewShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterPopupMenu("drawtext");
+
+ GetStaticInterface()->RegisterChildWindow(SID_NAVIGATOR, true);
+
+ GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxFontWorkChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxColorChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(AnimationChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(Svx3DChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxBmpMaskChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxIMapDlgChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxHlinkDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(::sd::SpellDialogChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SID_SEARCH_DLG);
+#if HAVE_FEATURE_AVMEDIA
+ GetStaticInterface()->RegisterChildWindow(::avmedia::MediaPlayer::GetChildWindowId());
+#endif
+ GetStaticInterface()->RegisterChildWindow(
+ sfx2::sidebar::SidebarChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(DevelopmentToolChildWindow::GetChildWindowId());
+}
+
+// SdGraphicViewShell
+SFX_IMPL_INTERFACE(GraphicViewShell, SfxShell)
+
+void GraphicViewShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterPopupMenu("drawtext");
+
+ GetStaticInterface()->RegisterChildWindow(SID_NAVIGATOR, true);
+
+ GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxFontWorkChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxColorChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(Svx3DChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxBmpMaskChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxIMapDlgChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxHlinkDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(::sd::SpellDialogChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SID_SEARCH_DLG);
+#if HAVE_FEATURE_AVMEDIA
+ GetStaticInterface()->RegisterChildWindow(::avmedia::MediaPlayer::GetChildWindowId());
+#endif
+ GetStaticInterface()->RegisterChildWindow(
+ sfx2::sidebar::SidebarChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(DevelopmentToolChildWindow::GetChildWindowId());
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/frmview.cxx b/sd/source/ui/view/frmview.cxx
new file mode 100644
index 000000000..fad0dc9ad
--- /dev/null
+++ b/sd/source/ui/view/frmview.cxx
@@ -0,0 +1,916 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <FrameView.hxx>
+
+#include <svx/svxids.hrc>
+#include <com/sun/star/drawing/framework/ResourceId.hpp>
+#include <com/sun/star/drawing/framework/XView.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <unokywds.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+
+#include <vector>
+#include <ViewShell.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <optsitem.hxx>
+#include <ViewShellBase.hxx>
+#include <sdmod.hxx>
+#include <pres.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <officecfg/Office/Common.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::std;
+
+namespace sd {
+
+FrameView::FrameView(SdDrawDocument* pDrawDoc, FrameView* pFrameView /* = NULL */)
+: SdrView(*pDrawDoc, nullptr), // TTTT SdDrawDocument* -> should be reference
+ mnRefCount(0),
+ mnPresViewShellId(SID_VIEWSHELL0),
+ mbIsNavigatorShowingAllShapes(false)
+{
+ EndListening(*pDrawDoc);
+
+ EnableExtendedKeyInputDispatcher(false);
+ EnableExtendedMouseEventDispatcher(false);
+
+ SetGridFront( false );
+ SetHlplFront( false );
+ SetOConSnap( false );
+ SetFrameDragSingles();
+ SetSlidesPerRow(4);
+
+ if( nullptr == pFrameView )
+ {
+ DrawDocShell* pDocShell = pDrawDoc->GetDocSh();
+
+ if ( pDocShell )
+ {
+ // document is loaded, is there a FrameView?
+ sal_uLong nSdViewShellCount = 0;
+ SfxViewFrame* pSfxViewFrame = SfxViewFrame::GetFirst(pDocShell);
+
+ while (pSfxViewFrame)
+ {
+ // Count the FrameViews and remember the type of the main
+ // view shell.
+ SfxViewShell* pSfxViewSh = pSfxViewFrame->GetViewShell();
+ ViewShellBase* pBase = dynamic_cast<ViewShellBase*>( pSfxViewSh );
+
+ if (pBase != nullptr)
+ {
+ nSdViewShellCount++;
+
+ OUString sViewURL;
+ Reference<drawing::framework::XView> xView (
+ framework::FrameworkHelper::Instance(*pBase)->GetView(
+ drawing::framework::ResourceId::create(
+ ::comphelper::getProcessComponentContext(),
+ framework::FrameworkHelper::msCenterPaneURL)));
+ if (xView.is())
+ sViewURL = xView->getResourceId()->getResourceURL();
+
+ switch (framework::FrameworkHelper::GetViewId(sViewURL))
+ {
+ default:
+// case ViewShell::ST_IMPRESS:
+// case ViewShell::ST_NOTES:
+// case ViewShell::ST_HANDOUT:
+ mnPresViewShellId = SID_VIEWSHELL0;
+ break;
+
+ case ViewShell::ST_SLIDE_SORTER:
+ mnPresViewShellId = SID_VIEWSHELL1;
+ break;
+
+ case ViewShell::ST_OUTLINE:
+ mnPresViewShellId = SID_VIEWSHELL2;
+ break;
+ }
+ }
+
+ pSfxViewFrame = SfxViewFrame::GetNext(*pSfxViewFrame, pDocShell);
+ }
+
+ SdDrawDocument* pDoc = pDocShell->GetDoc();
+ pFrameView = pDoc->GetFrameView(nSdViewShellCount);
+ }
+ }
+
+ if (pFrameView)
+ {
+ // initialize FrameView with the FrameView of the DocShell
+ SetRuler( pFrameView->HasRuler() );
+ SetGridCoarse( pFrameView->GetGridCoarse() );
+ SetGridFine( pFrameView->GetGridFine() );
+ SetSnapGridWidth(pFrameView->GetSnapGridWidthX(), pFrameView->GetSnapGridWidthY());
+ SetGridVisible( pFrameView->IsGridVisible() );
+ SetGridFront( pFrameView->IsGridFront() );
+ SetSnapAngle( pFrameView->GetSnapAngle() );
+ SetGridSnap( pFrameView->IsGridSnap() );
+ SetBordSnap( pFrameView->IsBordSnap() );
+ SetHlplSnap( pFrameView->IsHlplSnap() );
+ SetOFrmSnap( pFrameView->IsOFrmSnap() );
+ SetOPntSnap( pFrameView->IsOPntSnap() );
+ SetOConSnap( pFrameView->IsOConSnap() );
+ SetHlplVisible( pFrameView->IsHlplVisible() );
+ SetDragStripes( pFrameView->IsDragStripes() );
+ SetPlusHandlesAlwaysVisible( pFrameView->IsPlusHandlesAlwaysVisible() );
+ SetFrameDragSingles( pFrameView->IsFrameDragSingles() );
+ SetSnapMagneticPixel( pFrameView->GetSnapMagneticPixel() );
+ SetMarkedHitMovesAlways( pFrameView->IsMarkedHitMovesAlways() );
+ SetMoveOnlyDragging( pFrameView->IsMoveOnlyDragging() );
+ SetCrookNoContortion( pFrameView->IsCrookNoContortion() );
+ SetSlantButShear( pFrameView->IsSlantButShear() );
+ SetNoDragXorPolys( pFrameView->IsNoDragXorPolys() );
+ SetAngleSnapEnabled( pFrameView->IsAngleSnapEnabled() );
+ SetBigOrtho( pFrameView->IsBigOrtho() );
+ SetOrtho( pFrameView->IsOrtho() );
+ SetEliminatePolyPointLimitAngle( pFrameView->GetEliminatePolyPointLimitAngle() );
+ SetEliminatePolyPoints( pFrameView->IsEliminatePolyPoints() );
+ SetDesignMode( pFrameView->IsDesignMode() );
+
+ SetSolidDragging( pFrameView->IsSolidDragging() );
+
+ maVisibleLayers = pFrameView->GetVisibleLayers();
+ maPrintableLayers = pFrameView->GetPrintableLayers();
+ maLockedLayers = pFrameView->GetLockedLayers();
+ maStandardHelpLines = pFrameView->GetStandardHelpLines();
+ maNotesHelpLines = pFrameView->GetNotesHelpLines();
+ maHandoutHelpLines = pFrameView->GetHandoutHelpLines();
+ SetActiveLayer( pFrameView->GetActiveLayer() );
+ mbNoColors = pFrameView->IsNoColors();
+ mbNoAttribs = pFrameView->IsNoAttribs() ;
+ maVisArea = pFrameView->GetVisArea();
+ mePageKind = pFrameView->GetPageKind();
+ mePageKindOnLoad = pFrameView->GetPageKindOnLoad();
+ mnSelectedPage = pFrameView->GetSelectedPage();
+ mnSelectedPageOnLoad = pFrameView->GetSelectedPageOnLoad();
+ mePageEditMode = pFrameView->GetViewShEditMode();
+ // meStandardEditMode = pFrameView->GetViewShEditMode(PageKind::Standard);
+ // meNotesEditMode = pFrameView->GetViewShEditMode(PageKind::Notes);
+ // meHandoutEditMode = pFrameView->GetViewShEditMode(PageKind::Handout);
+ SetViewShEditModeOnLoad(pFrameView->GetViewShEditModeOnLoad());
+ mbLayerMode = pFrameView->IsLayerMode();
+ mbQuickEdit = pFrameView->IsQuickEdit();
+
+ // #i26631#
+ SetMasterPagePaintCaching( pFrameView->IsMasterPagePaintCaching() );
+
+ SetDragWithCopy( pFrameView->IsDragWithCopy() );
+ mbDoubleClickTextEdit = pFrameView->IsDoubleClickTextEdit();
+ mbClickChangeRotation = pFrameView->IsClickChangeRotation();
+ mnSlidesPerRow = pFrameView->GetSlidesPerRow();
+ mnDrawMode = pFrameView->GetDrawMode();
+ mbIsNavigatorShowingAllShapes = pFrameView->IsNavigatorShowingAllShapes();
+ SetPreviousViewShellType (pFrameView->GetPreviousViewShellType());
+ SetViewShellTypeOnLoad (pFrameView->GetViewShellTypeOnLoad());
+ }
+ else
+ {
+ // initialize FrameView with the application data
+
+ // Layers need to be set, otherwise they are not visible and not printable in
+ // Impress documents. The document contains already the actual layers and their
+ // settings for visible, printable and locked. In case not read from <draw:layer-set>,
+ // ODF defaults are used.
+ SdrLayerAdmin rLayerAdmin = pDrawDoc -> GetLayerAdmin();
+ rLayerAdmin.getVisibleLayersODF(maVisibleLayers);
+ rLayerAdmin.getPrintableLayersODF(maPrintableLayers);
+ rLayerAdmin.getLockedLayersODF(maLockedLayers);
+ SetGridCoarse( Size( 1000, 1000 ) );
+ SetSnapGridWidth(Fraction(1000, 1), Fraction(1000, 1));
+ SetActiveLayer(sUNO_LayerName_layout);
+ mbNoColors = true;
+ mbNoAttribs = false;
+ maVisArea = ::tools::Rectangle( Point(), Size(0, 0) );
+ mePageKind = PageKind::Standard;
+ mePageKindOnLoad = PageKind::Standard;
+ mnSelectedPage = 0;
+ mnSelectedPageOnLoad = 0;
+ mePageEditMode = EditMode::Page;
+ // meStandardEditMode = EditMode::Page;
+ // meNotesEditMode = EditMode::Page;
+ // meHandoutEditMode = EditMode::MasterPage;
+ SetViewShEditModeOnLoad(EditMode::Page);
+ mbLayerMode = false;
+ SetEliminatePolyPoints(false);
+ mbDoubleClickTextEdit = false;
+ mbClickChangeRotation = false;
+ mnSlidesPerRow = 4;
+
+ {
+ bool bUseContrast = Application::GetSettings().GetStyleSettings().GetHighContrastMode();
+ mnDrawMode = bUseContrast ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR;
+ }
+ mbIsNavigatorShowingAllShapes = true;
+ SetPreviousViewShellType (ViewShell::ST_NONE);
+ SetViewShellTypeOnLoad (ViewShell::ST_IMPRESS);
+
+ // get default for design mode
+ bool bInitDesignMode = pDrawDoc->GetOpenInDesignMode();
+ if( pDrawDoc->OpenInDesignModeIsDefaulted() )
+ {
+ bInitDesignMode = true;
+ }
+
+ SfxObjectShell* pObjShell = pDrawDoc->GetObjectShell();
+ if( pObjShell && pObjShell->IsReadOnly() )
+ bInitDesignMode = false;
+ SetDesignMode( bInitDesignMode );
+
+ Update( SD_MOD()->GetSdOptions(pDrawDoc->GetDocumentType()) );
+ }
+
+}
+
+FrameView::~FrameView()
+{
+}
+
+void FrameView::Connect()
+{
+ mnRefCount++;
+}
+
+void FrameView::Disconnect()
+{
+ if (mnRefCount > 0)
+ {
+ mnRefCount--;
+ }
+
+ if (mnRefCount == 0)
+ {
+ delete this;
+ }
+}
+
+/**
+ * Update with data from the specified SdOptions
+ */
+void FrameView::Update(SdOptions const * pOptions)
+{
+ if (!pOptions)
+ return;
+
+ mbRuler = pOptions->IsRulerVisible();
+ SetGridVisible( pOptions->IsGridVisible() );
+ SetSnapAngle( pOptions->GetAngle() );
+ SetGridSnap( pOptions->IsUseGridSnap() );
+ SetBordSnap( pOptions->IsSnapBorder() );
+ SetHlplSnap( pOptions->IsSnapHelplines() );
+ SetOFrmSnap( pOptions->IsSnapFrame() );
+ SetOPntSnap( pOptions->IsSnapPoints() );
+ SetHlplVisible( pOptions->IsHelplines() );
+ SetDragStripes( pOptions->IsDragStripes() );
+ SetPlusHandlesAlwaysVisible( pOptions->IsHandlesBezier() );
+ SetSnapMagneticPixel( pOptions->GetSnapArea() );
+ SetMarkedHitMovesAlways( pOptions->IsMarkedHitMovesAlways() );
+ SetMoveOnlyDragging( pOptions->IsMoveOnlyDragging() );
+ SetSlantButShear( pOptions->IsMoveOnlyDragging() );
+ SetNoDragXorPolys ( !pOptions->IsMoveOutline() );
+ SetCrookNoContortion( pOptions->IsCrookNoContortion() );
+ SetAngleSnapEnabled( pOptions->IsRotate() );
+ SetBigOrtho( pOptions->IsBigOrtho() );
+ SetOrtho( pOptions->IsOrtho() );
+ SetEliminatePolyPointLimitAngle( pOptions->GetEliminatePolyPointLimitAngle() );
+ GetModel()->SetPickThroughTransparentTextFrames( pOptions->IsPickThrough() );
+
+ SetSolidDragging( pOptions->IsSolidDragging() );
+
+ SetGridCoarse( Size( pOptions->GetFieldDrawX(), pOptions->GetFieldDrawY() ) );
+ SetGridFine( Size( pOptions->GetFieldDivisionX(), pOptions->GetFieldDivisionY() ) );
+ Fraction aFractX(pOptions->GetFieldDrawX(), pOptions->GetFieldDrawX() / ( pOptions->GetFieldDivisionX() ? pOptions->GetFieldDivisionX() : 1 ));
+ Fraction aFractY(pOptions->GetFieldDrawY(), pOptions->GetFieldDrawY() / ( pOptions->GetFieldDivisionY() ? pOptions->GetFieldDivisionY() : 1 ));
+ SetSnapGridWidth(aFractX, aFractY);
+ SetQuickEdit(pOptions->IsQuickEdit());
+
+ // #i26631#
+ SetMasterPagePaintCaching( pOptions->IsMasterPagePaintCaching() );
+
+ SetDragWithCopy(pOptions->IsDragWithCopy());
+ SetDoubleClickTextEdit( pOptions->IsDoubleClickTextEdit() );
+ SetClickChangeRotation( pOptions->IsClickChangeRotation() );
+}
+
+/**
+ * Set EditMode (Page or MasterPage) of working mode
+ */
+void FrameView::SetViewShEditMode(EditMode eMode)
+{
+ mePageEditMode = eMode;
+}
+
+/**
+ * Return EditMode (Page or MasterPage) of working mode
+ */
+EditMode FrameView::GetViewShEditMode() const
+{
+ return mePageEditMode;
+}
+
+void FrameView::SetViewShEditModeOnLoad (EditMode eMode)
+{
+ meEditModeOnLoad = eMode;
+}
+
+static OUString createHelpLinesString( const SdrHelpLineList& rHelpLines )
+{
+ OUStringBuffer aLines;
+
+ const sal_uInt16 nCount = rHelpLines.GetCount();
+ for( sal_uInt16 nHlpLine = 0; nHlpLine < nCount; nHlpLine++ )
+ {
+ const SdrHelpLine& rHelpLine = rHelpLines[nHlpLine];
+ const Point& rPos = rHelpLine.GetPos();
+
+ switch( rHelpLine.GetKind() )
+ {
+ case SdrHelpLineKind::Point:
+ aLines.append( 'P' );
+ aLines.append( static_cast<sal_Int32>(rPos.X()) );
+ aLines.append( ',' );
+ aLines.append( static_cast<sal_Int32>(rPos.Y()) );
+ break;
+ case SdrHelpLineKind::Vertical:
+ aLines.append( 'V' );
+ aLines.append( static_cast<sal_Int32>(rPos.X()) );
+ break;
+ case SdrHelpLineKind::Horizontal:
+ aLines.append( 'H' );
+ aLines.append( static_cast<sal_Int32>(rPos.Y()) );
+ break;
+ default:
+ OSL_FAIL( "Unsupported helpline Kind!" );
+ }
+ }
+
+ return aLines.makeStringAndClear();
+}
+
+void FrameView::WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& rValues )
+{
+ std::vector< std::pair< OUString, Any > > aUserData;
+ aUserData.reserve(41); // worst case
+
+ aUserData.emplace_back( sUNO_View_GridIsVisible, Any( IsGridVisible() ) );
+ aUserData.emplace_back( sUNO_View_GridIsFront, Any( IsGridFront() ) );
+ aUserData.emplace_back( sUNO_View_IsSnapToGrid, Any( IsGridSnap() ) );
+ aUserData.emplace_back( sUNO_View_IsSnapToPageMargins, Any( IsBordSnap() ) );
+ aUserData.emplace_back( sUNO_View_IsSnapToSnapLines, Any( IsHlplSnap() ) );
+ aUserData.emplace_back( sUNO_View_IsSnapToObjectFrame, Any( IsOFrmSnap() ) );
+ aUserData.emplace_back( sUNO_View_IsSnapToObjectPoints, Any( IsOPntSnap() ) );
+
+ aUserData.emplace_back( sUNO_View_IsPlusHandlesAlwaysVisible, Any( IsPlusHandlesAlwaysVisible() ) );
+ aUserData.emplace_back( sUNO_View_IsFrameDragSingles, Any( IsFrameDragSingles() ) );
+
+ aUserData.emplace_back( sUNO_View_EliminatePolyPointLimitAngle, Any( static_cast<sal_Int32>(GetEliminatePolyPointLimitAngle()) ) );
+ aUserData.emplace_back( sUNO_View_IsEliminatePolyPoints, Any( IsEliminatePolyPoints() ) );
+
+ if ( officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::get() )
+ {
+ SdrLayerAdmin& rLayerAdmin = getSdrModelFromSdrView().GetLayerAdmin();
+ Any aAny;
+ rLayerAdmin.QueryValue(GetVisibleLayers(), aAny);
+ aUserData.emplace_back( sUNO_View_VisibleLayers, aAny );
+
+ rLayerAdmin.QueryValue(GetPrintableLayers(), aAny);
+ aUserData.emplace_back( sUNO_View_PrintableLayers, aAny );
+
+ rLayerAdmin.QueryValue(GetLockedLayers(), aAny);
+ aUserData.emplace_back( sUNO_View_LockedLayers, aAny );
+ }
+
+ aUserData.emplace_back( sUNO_View_NoAttribs, Any( IsNoAttribs() ) );
+ aUserData.emplace_back( sUNO_View_NoColors, Any( IsNoColors() ) );
+
+ if( GetStandardHelpLines().GetCount() )
+ aUserData.emplace_back( sUNO_View_SnapLinesDrawing, Any( createHelpLinesString( GetStandardHelpLines() ) ) );
+
+ if( GetNotesHelpLines().GetCount() )
+ aUserData.emplace_back( sUNO_View_SnapLinesNotes, Any( createHelpLinesString( GetNotesHelpLines() ) ) );
+
+ if( GetHandoutHelpLines().GetCount() )
+ aUserData.emplace_back( sUNO_View_SnapLinesHandout, Any( createHelpLinesString( GetHandoutHelpLines() ) ) );
+
+ aUserData.emplace_back( sUNO_View_RulerIsVisible, Any( HasRuler() ) );
+ aUserData.emplace_back( sUNO_View_PageKind, Any( static_cast<sal_Int16>(GetPageKind()) ) );
+ aUserData.emplace_back( sUNO_View_SelectedPage, Any( static_cast<sal_Int16>(GetSelectedPage()) ) );
+ aUserData.emplace_back( sUNO_View_IsLayerMode, Any( IsLayerMode() ) );
+
+ aUserData.emplace_back( sUNO_View_IsDoubleClickTextEdit, Any( IsDoubleClickTextEdit() ) );
+ aUserData.emplace_back( sUNO_View_IsClickChangeRotation, Any( IsClickChangeRotation() ) );
+
+ aUserData.emplace_back( sUNO_View_SlidesPerRow, Any( static_cast<sal_Int16>(GetSlidesPerRow()) ) );
+ aUserData.emplace_back( sUNO_View_EditMode, Any( static_cast<sal_Int32>(GetViewShEditMode()) ) );
+ // aUserData.emplace_back( sUNO_View_EditModeStandard, makeAny( (sal_Int32)GetViewShEditMode( PageKind::Standard ) ) );
+ // aUserData.emplace_back( sUNO_View_EditModeNotes, makeAny( (sal_Int32)GetViewShEditMode( PageKind::Notes ) ) );
+ // aUserData.emplace_back( sUNO_View_EditModeHandout, makeAny( (sal_Int32)GetViewShEditMode( PageKind::Handout ) ) );
+
+ {
+ const ::tools::Rectangle aVisArea = GetVisArea();
+
+ aUserData.emplace_back( sUNO_View_VisibleAreaTop, Any( static_cast<sal_Int32>(aVisArea.Top()) ) );
+ aUserData.emplace_back( sUNO_View_VisibleAreaLeft, Any( static_cast<sal_Int32>(aVisArea.Left()) ) );
+ aUserData.emplace_back( sUNO_View_VisibleAreaWidth, Any( static_cast<sal_Int32>(aVisArea.GetWidth()) ) );
+ aUserData.emplace_back( sUNO_View_VisibleAreaHeight, Any( static_cast<sal_Int32>(aVisArea.GetHeight()) ) );
+ }
+
+ aUserData.emplace_back( sUNO_View_GridCoarseWidth, Any( static_cast<sal_Int32>(GetGridCoarse().Width()) ) );
+ aUserData.emplace_back( sUNO_View_GridCoarseHeight, Any( static_cast<sal_Int32>(GetGridCoarse().Height()) ) );
+ aUserData.emplace_back( sUNO_View_GridFineWidth, Any( static_cast<sal_Int32>(GetGridFine().Width()) ) );
+ aUserData.emplace_back( sUNO_View_GridFineHeight, Any( static_cast<sal_Int32>(GetGridFine().Height()) ) );
+ aUserData.emplace_back( sUNO_View_GridSnapWidthXNumerator, Any( GetSnapGridWidthX().GetNumerator() ) );
+ aUserData.emplace_back( sUNO_View_GridSnapWidthXDenominator, Any( GetSnapGridWidthX().GetDenominator() ) );
+ aUserData.emplace_back( sUNO_View_GridSnapWidthYNumerator, Any( GetSnapGridWidthY().GetNumerator() ) );
+ aUserData.emplace_back( sUNO_View_GridSnapWidthYDenominator, Any( GetSnapGridWidthY().GetDenominator() ) );
+ aUserData.emplace_back( sUNO_View_IsAngleSnapEnabled, Any( IsAngleSnapEnabled() ) );
+ aUserData.emplace_back( sUNO_View_SnapAngle, Any( static_cast<sal_Int32>(GetSnapAngle()) ) );
+
+ const sal_Int32 nOldLength = rValues.getLength();
+ rValues.realloc( nOldLength + aUserData.size() );
+
+ PropertyValue* pValue = &(rValues.getArray()[nOldLength]);
+
+ for( const auto& rItem : aUserData )
+ {
+ pValue->Name = rItem.first;
+ pValue->Value = rItem.second;
+ ++pValue;
+ }
+}
+
+static void createHelpLinesFromString( const OUString& rLines, SdrHelpLineList& rHelpLines )
+{
+ const sal_Unicode * pStr = rLines.getStr();
+ SdrHelpLine aNewHelpLine;
+ OUStringBuffer sBuffer;
+
+ while( *pStr )
+ {
+ Point aPoint;
+
+ switch( *pStr )
+ {
+ case 'P':
+ aNewHelpLine.SetKind( SdrHelpLineKind::Point );
+ break;
+ case 'V':
+ aNewHelpLine.SetKind( SdrHelpLineKind::Vertical );
+ break;
+ case 'H':
+ aNewHelpLine.SetKind( SdrHelpLineKind::Horizontal );
+ break;
+ default:
+ OSL_FAIL( "syntax error in snap lines settings string" );
+ return;
+ }
+
+ pStr++;
+
+ while( (*pStr >= '0' && *pStr <= '9') || (*pStr == '+') || (*pStr == '-') )
+ {
+ sBuffer.append( *pStr++ );
+ }
+
+ sal_Int32 nValue = sBuffer.makeStringAndClear().toInt32();
+
+ if( aNewHelpLine.GetKind() == SdrHelpLineKind::Horizontal )
+ {
+ aPoint.setY( nValue );
+ }
+ else
+ {
+ aPoint.setX( nValue );
+
+ if( aNewHelpLine.GetKind() == SdrHelpLineKind::Point )
+ {
+ if( *pStr++ != ',' )
+ return;
+
+ while( (*pStr >= '0' && *pStr <= '9') || (*pStr == '+') || (*pStr == '-') )
+ {
+ sBuffer.append( *pStr++ );
+ }
+
+ aPoint.setY( sBuffer.makeStringAndClear().toInt32() );
+
+ }
+ }
+
+ aNewHelpLine.SetPos( aPoint );
+ rHelpLines.Insert( aNewHelpLine );
+ }
+}
+
+void FrameView::ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& rSequence )
+{
+ const sal_Int32 nLength = rSequence.getLength();
+ if (!nLength)
+ return;
+
+ SdDrawDocument* pDrawDocument = dynamic_cast<SdDrawDocument*>(GetModel());
+ const bool bImpress = pDrawDocument && pDrawDocument->GetDocumentType() == DocumentType::Impress;
+
+ bool bBool = false;
+ sal_Int32 nInt32 = 0;
+ sal_Int16 nInt16 = 0;
+ OUString aString;
+
+ sal_Int32 aSnapGridWidthXNum = GetSnapGridWidthX().GetNumerator();
+ sal_Int32 aSnapGridWidthXDom = GetSnapGridWidthX().GetDenominator();
+
+ sal_Int32 aSnapGridWidthYNum = GetSnapGridWidthY().GetNumerator();
+ sal_Int32 aSnapGridWidthYDom = GetSnapGridWidthY().GetDenominator();
+
+ for (const css::beans::PropertyValue& rValue : rSequence)
+ {
+ if ( rValue.Name == sUNO_View_ViewId )
+ {
+ }
+ else if ( rValue.Name == sUNO_View_SnapLinesDrawing )
+ {
+ if( rValue.Value >>= aString )
+ {
+ SdrHelpLineList aHelpLines;
+ createHelpLinesFromString( aString, aHelpLines );
+ SetStandardHelpLines( aHelpLines );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_SnapLinesNotes )
+ {
+ if( rValue.Value >>= aString )
+ {
+ SdrHelpLineList aHelpLines;
+ createHelpLinesFromString( aString, aHelpLines );
+ SetNotesHelpLines( aHelpLines );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_SnapLinesHandout )
+ {
+ if( rValue.Value >>= aString )
+ {
+ SdrHelpLineList aHelpLines;
+ createHelpLinesFromString( aString, aHelpLines );
+ SetHandoutHelpLines( aHelpLines );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_RulerIsVisible )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetRuler( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_PageKind )
+ {
+ if( rValue.Value >>= nInt16 )
+ {
+ SdDrawDocument* pDoc = dynamic_cast< SdDrawDocument* >( GetModel() );
+ if( pDoc && pDoc->GetDocSh() && ( SfxObjectCreateMode::EMBEDDED == pDoc->GetDocSh()->GetCreateMode() ) )
+ SetPageKind( static_cast<PageKind>(nInt16) );
+
+ SetPageKindOnLoad( static_cast<PageKind>(nInt16) );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_SelectedPage )
+ {
+ if( rValue.Value >>= nInt16 )
+ {
+ SdDrawDocument* pDoc = dynamic_cast< SdDrawDocument* >( GetModel() );
+ if( pDoc && pDoc->GetDocSh() && ( SfxObjectCreateMode::EMBEDDED == pDoc->GetDocSh()->GetCreateMode() ) )
+ SetSelectedPage( static_cast<sal_uInt16>(nInt16) );
+
+ SetSelectedPageOnLoad( static_cast<sal_uInt16>(nInt16) );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsLayerMode )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetLayerMode( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsDoubleClickTextEdit )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetDoubleClickTextEdit( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsClickChangeRotation )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetClickChangeRotation( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_SlidesPerRow )
+ {
+ if( rValue.Value >>= nInt16 )
+ {
+ SetSlidesPerRow( static_cast<sal_uInt16>(nInt16) );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_EditMode )
+ {
+ if( rValue.Value >>= nInt32 )
+ {
+ SdDrawDocument* pDoc = dynamic_cast< SdDrawDocument* >( GetModel() );
+ if( pDoc && pDoc->GetDocSh() && ( SfxObjectCreateMode::EMBEDDED == pDoc->GetDocSh()->GetCreateMode() ) )
+ SetViewShEditMode( static_cast<EditMode>(nInt32) );
+ }
+ }
+ // This one is kept for compatibility. Old value read from sUNO_View_EditModeStandard
+ // is used. New value will be written into sUNO_View_EditMode.
+ // Values from sUNO_View_EditModeNotes and sUNO_View_EditModeHangout will be ignored.
+ else if ( rValue.Name == sUNO_View_EditModeStandard )
+ {
+ if( rValue.Value >>= nInt32 )
+ {
+ SdDrawDocument* pDoc = dynamic_cast< SdDrawDocument* >( GetModel() );
+ if( pDoc && pDoc->GetDocSh() && ( SfxObjectCreateMode::EMBEDDED == pDoc->GetDocSh()->GetCreateMode() ) )
+ SetViewShEditMode( static_cast<EditMode>(nInt32) );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_VisibleAreaTop )
+ {
+ sal_Int32 nTop = 0;
+ if( rValue.Value >>= nTop )
+ {
+ ::tools::Rectangle aVisArea( GetVisArea() );
+ aVisArea.AdjustBottom(nTop - aVisArea.Top() );
+ aVisArea.SetTop( nTop );
+ SetVisArea( aVisArea );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_VisibleAreaLeft )
+ {
+ sal_Int32 nLeft = 0;
+ if( rValue.Value >>= nLeft )
+ {
+ ::tools::Rectangle aVisArea( GetVisArea() );
+ aVisArea.AdjustRight(nLeft - aVisArea.Left() );
+ aVisArea.SetLeft( nLeft );
+ SetVisArea( aVisArea );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_VisibleAreaWidth )
+ {
+ sal_Int32 nWidth = 0;
+ if( rValue.Value >>= nWidth )
+ {
+ ::tools::Rectangle aVisArea( GetVisArea() );
+ aVisArea.SetRight( aVisArea.Left() + nWidth - 1 );
+ SetVisArea( aVisArea );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_VisibleAreaHeight )
+ {
+ sal_Int32 nHeight = 0;
+ if( rValue.Value >>= nHeight )
+ {
+ ::tools::Rectangle aVisArea( GetVisArea() );
+ aVisArea.SetBottom( nHeight + aVisArea.Top() - 1 );
+ SetVisArea( aVisArea );
+ }
+ }
+
+ else if ( rValue.Name == sUNO_View_GridIsVisible )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetGridVisible( bBool );
+ }
+ }
+
+ else if ( rValue.Name == sUNO_View_IsSnapToGrid )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetGridSnap( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_GridIsFront )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetGridFront( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsSnapToPageMargins )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetBordSnap( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsSnapToSnapLines )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetHlplSnap( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsSnapToObjectFrame )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetOFrmSnap( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsSnapToObjectPoints )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetOPntSnap( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsPlusHandlesAlwaysVisible )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetPlusHandlesAlwaysVisible( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsFrameDragSingles )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetFrameDragSingles( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_EliminatePolyPointLimitAngle )
+ {
+ if( rValue.Value >>= nInt32 )
+ {
+ SetEliminatePolyPointLimitAngle( Degree100(nInt32) );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsEliminatePolyPoints )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetEliminatePolyPoints( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_ActiveLayer )
+ {
+ if( rValue.Value >>= aString )
+ {
+ SetActiveLayer( aString );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_NoAttribs )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetNoAttribs( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_NoColors )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetNoColors( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_GridCoarseWidth )
+ {
+ if( rValue.Value >>= nInt32 )
+ {
+ const Size aCoarse( nInt32, GetGridCoarse().Height() );
+ SetGridCoarse( aCoarse );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_GridCoarseHeight )
+ {
+ if( rValue.Value >>= nInt32 )
+ {
+ const Size aCoarse( GetGridCoarse().Width(), nInt32 );
+ SetGridCoarse( aCoarse );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_GridFineWidth )
+ {
+ if( rValue.Value >>= nInt32 )
+ {
+ const Size aCoarse( nInt32, GetGridFine().Height() );
+ SetGridFine( aCoarse );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_GridFineHeight )
+ {
+ if( rValue.Value >>= nInt32 )
+ {
+ const Size aCoarse( GetGridFine().Width(), nInt32 );
+ SetGridFine( aCoarse );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_IsAngleSnapEnabled )
+ {
+ if( rValue.Value >>= bBool )
+ {
+ SetAngleSnapEnabled( bBool );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_SnapAngle )
+ {
+ if( rValue.Value >>= nInt32 )
+ {
+ SetSnapAngle( Degree100(nInt32) );
+ }
+ }
+ else if ( rValue.Name == sUNO_View_GridSnapWidthXNumerator )
+ {
+ rValue.Value >>= aSnapGridWidthXNum;
+ }
+ else if ( rValue.Name == sUNO_View_GridSnapWidthXDenominator )
+ {
+ rValue.Value >>= aSnapGridWidthXDom;
+ }
+ else if ( rValue.Name == sUNO_View_GridSnapWidthYNumerator )
+ {
+ rValue.Value >>= aSnapGridWidthYNum;
+ }
+ else if ( rValue.Name == sUNO_View_GridSnapWidthYDenominator )
+ {
+ rValue.Value >>= aSnapGridWidthYDom;
+ }
+ else if (!bImpress && rValue.Name == sUNO_View_VisibleLayers )
+ {
+ SdrLayerIDSet aSdrLayerIDSets;
+ aSdrLayerIDSets.PutValue( rValue.Value );
+ SetVisibleLayers( aSdrLayerIDSets );
+ }
+ else if (!bImpress && rValue.Name == sUNO_View_PrintableLayers )
+ {
+ SdrLayerIDSet aSdrLayerIDSets;
+ aSdrLayerIDSets.PutValue( rValue.Value );
+ SetPrintableLayers( aSdrLayerIDSets );
+ }
+ else if (!bImpress && rValue.Name == sUNO_View_LockedLayers )
+ {
+ SdrLayerIDSet aSdrLayerIDSets;
+ aSdrLayerIDSets.PutValue( rValue.Value );
+ SetLockedLayers( aSdrLayerIDSets );
+ }
+ }
+
+ SetViewShEditModeOnLoad(EditMode::Page);
+
+ const Fraction aSnapGridWidthX( aSnapGridWidthXNum, aSnapGridWidthXDom );
+ const Fraction aSnapGridWidthY( aSnapGridWidthYNum, aSnapGridWidthYDom );
+
+ SetSnapGridWidth( aSnapGridWidthX, aSnapGridWidthY );
+}
+
+void FrameView::SetPreviousViewShellType (ViewShell::ShellType eType)
+{
+ mePreviousViewShellType = eType;
+}
+
+void FrameView::SetViewShellTypeOnLoad (ViewShell::ShellType eType)
+{
+ meViewShellTypeOnLoad = eType;
+}
+
+void FrameView::SetSelectedPage(sal_uInt16 nPage)
+{
+ mnSelectedPage = nPage;
+}
+
+void FrameView::SetIsNavigatorShowingAllShapes (const bool bIsNavigatorShowingAllShapes)
+{
+ mbIsNavigatorShowingAllShapes = bIsNavigatorShowingAllShapes;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/grviewsh.cxx b/sd/source/ui/view/grviewsh.cxx
new file mode 100644
index 000000000..b914b2da8
--- /dev/null
+++ b/sd/source/ui/view/grviewsh.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 <GraphicViewShell.hxx>
+#include <LayerTabBar.hxx>
+#include <FrameView.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewfrm.hxx>
+
+constexpr sal_Int32 TAB_HEIGHT_MARGIN = 10;
+
+namespace sd {
+
+GraphicViewShell::GraphicViewShell (
+ ViewShellBase& rViewShellBase,
+ vcl::Window* pParentWindow,
+ FrameView* pFrameView)
+ : DrawViewShell (
+ rViewShellBase,
+ pParentWindow,
+ PageKind::Standard,
+ pFrameView)
+{
+ ConstructGraphicViewShell();
+}
+
+GraphicViewShell::~GraphicViewShell()
+{
+}
+
+void GraphicViewShell::ConstructGraphicViewShell()
+{
+ meShellType = ST_DRAW;
+
+ mpLayerTabBar.reset (VclPtr<LayerTabBar>::Create(this, GetParentWindow()));
+
+ // #i67363# no layer tabbar in preview mode
+ if ( !GetObjectShell()->IsPreview() )
+ mpLayerTabBar->Show();
+}
+
+void GraphicViewShell::ChangeEditMode (
+ EditMode eMode,
+ bool )
+{
+ // There is no page tab that could be shown instead of the layer tab.
+ // Therefore we have it always visible regardless of what the caller
+ // said. (We have to change the callers behaviour, of course.)
+ DrawViewShell::ChangeEditMode (eMode, true);
+}
+
+void GraphicViewShell::ArrangeGUIElements()
+{
+ if (mpLayerTabBar && mpLayerTabBar->IsVisible())
+ {
+ Size aSize = mpLayerTabBar->GetSizePixel();
+ const Size aFrameSize (GetViewFrame()->GetWindow().GetOutputSizePixel());
+
+ aSize.setHeight(GetParentWindow()->GetFont().GetFontHeight() + TAB_HEIGHT_MARGIN);
+ aSize.setWidth( aFrameSize.Width() );
+
+ Point aPos (0, maViewSize.Height() - aSize.Height());
+
+ mpLayerTabBar->SetPosSizePixel (aPos, aSize);
+ }
+
+ DrawViewShell::ArrangeGUIElements();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/outlnvs2.cxx b/sd/source/ui/view/outlnvs2.cxx
new file mode 100644
index 000000000..2a890cec1
--- /dev/null
+++ b/sd/source/ui/view/outlnvs2.cxx
@@ -0,0 +1,636 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <OutlineViewShell.hxx>
+
+#include <app.hrc>
+#include <svx/hlnkitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svdoutl.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/editstat.hxx>
+#include <unotools/useroptions.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <Window.hxx>
+#include <fubullet.hxx>
+#include <fuolbull.hxx>
+#include <fuscale.hxx>
+#include <fuchar.hxx>
+#include <fuinsfil.hxx>
+#include <fuprobjs.hxx>
+#include <futhes.hxx>
+#include <futempl.hxx>
+#include <fusldlg.hxx>
+#include <zoomlist.hxx>
+#include <fuexpand.hxx>
+#include <fusumry.hxx>
+#include <fucushow.hxx>
+#include <sdabstdlg.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <OutlineView.hxx>
+#include <slideshow.hxx>
+#include <memory>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+
+namespace sd {
+
+/************************************************************************/
+
+/**
+ * SfxRequests for temporary functions
+ */
+
+void OutlineViewShell::FuTemporary(SfxRequest &rReq)
+{
+ DeactivateCurrentFunction();
+
+ OutlinerView* pOutlinerView = pOlView->GetViewByWindow( GetActiveWindow() );
+ sal_uInt16 nSId = rReq.GetSlot();
+
+ switch( nSId )
+ {
+ case SID_ATTR_ZOOM:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if ( pArgs )
+ {
+ SvxZoomType eZT = pArgs->Get( SID_ATTR_ZOOM ).GetType();
+ switch( eZT )
+ {
+ case SvxZoomType::PERCENT:
+ SetZoom( static_cast<::tools::Long>( pArgs->Get( SID_ATTR_ZOOM ).GetValue()) );
+ Invalidate( SID_ATTR_ZOOM );
+ Invalidate( SID_ATTR_ZOOMSLIDER );
+ break;
+ default:
+ break;
+ }
+ rReq.Done();
+ }
+ else
+ {
+ // open the zoom dialog here
+ SetCurrentFunction( FuScale::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) );
+ }
+ Cancel();
+ }
+ break;
+
+ case SID_ATTR_ZOOMSLIDER:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ const SfxUInt16Item* pScale = (pArgs && pArgs->Count () == 1) ?
+ rReq.GetArg(SID_ATTR_ZOOMSLIDER) : nullptr;
+ if (pScale && CHECK_RANGE (5, pScale->GetValue (), 3000))
+ {
+ SetZoom (pScale->GetValue ());
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_ATTR_ZOOM );
+ rBindings.Invalidate( SID_ZOOM_IN );
+ rBindings.Invalidate( SID_ZOOM_OUT );
+ rBindings.Invalidate( SID_ATTR_ZOOMSLIDER );
+
+ }
+
+ Cancel();
+ rReq.Done ();
+ break;
+ }
+
+ case SID_ZOOM_IN:
+ {
+ SetZoom( std::min<::tools::Long>( GetActiveWindow()->GetZoom() * 2, GetActiveWindow()->GetMaxZoom() ) );
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0),
+ GetActiveWindow()->GetOutputSizePixel()) );
+ mpZoomList->InsertZoomRect(aVisAreaWin);
+ Invalidate( SID_ATTR_ZOOM );
+ Invalidate( SID_ZOOM_IN );
+ Invalidate(SID_ZOOM_OUT);
+ Invalidate( SID_ATTR_ZOOMSLIDER );
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_SIZE_REAL:
+ {
+ SetZoom( 100 );
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0),
+ GetActiveWindow()->GetOutputSizePixel()) );
+ mpZoomList->InsertZoomRect(aVisAreaWin);
+ Invalidate( SID_ATTR_ZOOM );
+ Invalidate( SID_ATTR_ZOOMSLIDER );
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_ZOOM_OUT:
+ {
+ SetZoom( std::max<::tools::Long>( GetActiveWindow()->GetZoom() / 2, GetActiveWindow()->GetMinZoom() ) );
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0),
+ GetActiveWindow()->GetOutputSizePixel()) );
+ mpZoomList->InsertZoomRect(aVisAreaWin);
+ Invalidate( SID_ATTR_ZOOM );
+ Invalidate( SID_ZOOM_OUT);
+ Invalidate( SID_ZOOM_IN );
+ Invalidate( SID_ATTR_ZOOMSLIDER );
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_OUTLINE_COLLAPSE_ALL:
+ {
+ pOutlinerView->CollapseAll();
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_OUTLINE_COLLAPSE:
+ {
+ pOutlinerView->Collapse();
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_OUTLINE_EXPAND_ALL:
+ {
+ pOutlinerView->ExpandAll();
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_OUTLINE_EXPAND:
+ {
+ pOutlinerView->Expand();
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_OUTLINE_FORMAT:
+ {
+ ::Outliner* pOutl = pOutlinerView->GetOutliner();
+ pOutl->SetFlatMode( !pOutl->IsFlatMode() );
+ Invalidate( SID_COLORVIEW );
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_SELECTALL:
+ {
+ ::Outliner& rOutl = pOlView->GetOutliner();
+ sal_Int32 nParaCount = rOutl.GetParagraphCount();
+ if (nParaCount > 0)
+ {
+ pOutlinerView->SelectRange( 0, nParaCount );
+ }
+ Cancel();
+ }
+ break;
+
+ case SID_PRESENTATION:
+ case SID_PRESENTATION_CURRENT_SLIDE:
+ case SID_REHEARSE_TIMINGS:
+ {
+ pOlView->PrepareClose();
+ slideshowhelp::ShowSlideShow(rReq, *GetDoc());
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_COLORVIEW:
+ {
+ ::Outliner* pOutl = pOutlinerView->GetOutliner();
+ EEControlBits nCntrl = pOutl->GetControlWord();
+
+ if ( !(nCntrl & EEControlBits::NOCOLORS) )
+ {
+ // color view is enabled: disable
+ pOutl->SetControlWord(nCntrl | EEControlBits::NOCOLORS);
+ }
+ else
+ {
+ // color view is disabled: enable
+ pOutl->SetControlWord(nCntrl & ~EEControlBits::NOCOLORS);
+ }
+
+ InvalidateWindows();
+ Invalidate( SID_COLORVIEW );
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_STYLE_EDIT:
+ case SID_STYLE_UPDATE_BY_EXAMPLE:
+ {
+ if( rReq.GetArgs() )
+ {
+ SetCurrentFunction( FuTemplate::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_PRESENTATION_DLG:
+ {
+ SetCurrentFunction( FuSlideShowDlg::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_REMOTE_DLG:
+ {
+#ifdef ENABLE_SDREMOTE
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateRemoteDialog(GetFrameWeld()));
+ pDlg->Execute();
+#endif
+ }
+ break;
+
+ case SID_CUSTOMSHOW_DLG:
+ {
+ SetCurrentFunction( FuCustomShowDlg::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_PHOTOALBUM:
+ {
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = GetActiveWindow();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateSdPhotoAlbumDialog(
+ pWin ? pWin->GetFrameWeld() : nullptr,
+ GetDoc()));
+
+ pDlg->Execute();
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+ }
+
+ if(HasCurrentFunction())
+ GetCurrentFunction()->Activate();
+
+ Invalidate( SID_OUTLINE_COLLAPSE_ALL );
+ Invalidate( SID_OUTLINE_COLLAPSE );
+ Invalidate( SID_OUTLINE_EXPAND_ALL );
+ Invalidate( SID_OUTLINE_EXPAND );
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_OUTLINE_LEFT );
+ rBindings.Invalidate( SID_OUTLINE_RIGHT );
+ rBindings.Invalidate( SID_OUTLINE_UP );
+ rBindings.Invalidate( SID_OUTLINE_DOWN );
+
+ Invalidate( SID_OUTLINE_FORMAT );
+ Invalidate( SID_COLORVIEW );
+ Invalidate(SID_CUT);
+ Invalidate(SID_COPY);
+ Invalidate(SID_PASTE);
+ Invalidate(SID_PASTE_UNFORMATTED);
+}
+
+void OutlineViewShell::FuTemporaryModify(SfxRequest &rReq)
+{
+ sal_uInt16 nSId = rReq.GetSlot();
+ std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard;
+ if (nSId != SID_OUTLINE_BULLET && nSId != FN_SVX_SET_BULLET && nSId != FN_SVX_SET_NUMBER)
+ {
+ aGuard.reset( new OutlineViewModelChangeGuard(*pOlView) );
+ }
+ DeactivateCurrentFunction();
+
+ OutlinerView* pOutlinerView = pOlView->GetViewByWindow( GetActiveWindow() );
+ //sal_uInt16 nSId = rReq.GetSlot();
+
+ switch( nSId )
+ {
+ case SID_HYPERLINK_SETLINK:
+ {
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ if (pReqArgs)
+ {
+ const SvxHyperlinkItem* pHLItem =
+ &pReqArgs->Get(SID_HYPERLINK_SETLINK);
+
+ SvxFieldItem aURLItem(SvxURLField(pHLItem->GetURL(),
+ pHLItem->GetName(),
+ SvxURLFormat::Repr), EE_FEATURE_FIELD);
+ ESelection aSel( pOutlinerView->GetSelection() );
+ pOutlinerView->InsertField(aURLItem);
+ if ( aSel.nStartPos <= aSel.nEndPos )
+ aSel.nEndPos = aSel.nStartPos + 1;
+ else
+ aSel.nStartPos = aSel.nEndPos + 1;
+ pOutlinerView->SetSelection( aSel );
+ }
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case FN_INSERT_SOFT_HYPHEN:
+ case FN_INSERT_HARDHYPHEN:
+ case FN_INSERT_HARD_SPACE:
+ case FN_INSERT_NNBSP:
+ case SID_INSERT_RLM :
+ case SID_INSERT_LRM :
+ case SID_INSERT_WJ :
+ case SID_INSERT_ZWSP:
+ case SID_CHARMAP:
+ {
+ SetCurrentFunction( FuBullet::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_OUTLINE_BULLET:
+ case FN_SVX_SET_BULLET:
+ case FN_SVX_SET_NUMBER:
+ {
+ SetCurrentFunction( FuBulletAndPosition::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_THESAURUS:
+ {
+ SetCurrentFunction( FuThesaurus::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) );
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_CHAR_DLG_EFFECT:
+ case SID_CHAR_DLG:
+ {
+ SetCurrentFunction( FuChar::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) );
+ Cancel();
+ }
+ break;
+
+ case SID_INSERTFILE:
+ {
+ SetCurrentFunction( FuInsertFile::Create(this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq) );
+ Cancel();
+ }
+ break;
+
+ case SID_PRESENTATIONOBJECT:
+ {
+ SetCurrentFunction( FuPresentationObjects::Create(this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq) );
+ Cancel();
+ }
+ break;
+
+ case SID_SET_DEFAULT:
+ {
+ pOutlinerView->RemoveAttribs(true); // sal_True = also paragraph attributes
+ Cancel();
+ rReq.Done();
+ }
+ break;
+
+ case SID_SUMMARY_PAGE:
+ {
+ pOlView->SetSelectedPages();
+ SetCurrentFunction( FuSummaryPage::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) );
+ pOlView->GetOutliner().Clear();
+ pOlView->FillOutliner();
+ pOlView->GetActualPage();
+ Cancel();
+ }
+ break;
+
+ case SID_EXPAND_PAGE:
+ {
+ pOlView->SetSelectedPages();
+ SetCurrentFunction( FuExpandPage::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) );
+ pOlView->GetOutliner().Clear();
+ pOlView->FillOutliner();
+ pOlView->GetActualPage();
+ Cancel();
+ }
+ break;
+
+ case SID_INSERT_FLD_DATE_FIX:
+ case SID_INSERT_FLD_DATE_VAR:
+ case SID_INSERT_FLD_TIME_FIX:
+ case SID_INSERT_FLD_TIME_VAR:
+ case SID_INSERT_FLD_AUTHOR:
+ case SID_INSERT_FLD_PAGE:
+ case SID_INSERT_FLD_PAGE_TITLE:
+ case SID_INSERT_FLD_PAGES:
+ case SID_INSERT_FLD_FILE:
+ {
+ std::unique_ptr<SvxFieldItem> pFieldItem;
+
+ switch( nSId )
+ {
+ case SID_INSERT_FLD_DATE_FIX:
+ pFieldItem.reset(new SvxFieldItem(
+ SvxDateField( Date( Date::SYSTEM ), SvxDateType::Fix ), EE_FEATURE_FIELD ));
+ break;
+
+ case SID_INSERT_FLD_DATE_VAR:
+ pFieldItem.reset(new SvxFieldItem( SvxDateField(), EE_FEATURE_FIELD ));
+ break;
+
+ case SID_INSERT_FLD_TIME_FIX:
+ pFieldItem.reset(new SvxFieldItem(
+ SvxExtTimeField( ::tools::Time( ::tools::Time::SYSTEM ), SvxTimeType::Fix ), EE_FEATURE_FIELD ));
+ break;
+
+ case SID_INSERT_FLD_TIME_VAR:
+ pFieldItem.reset(new SvxFieldItem( SvxExtTimeField(), EE_FEATURE_FIELD ));
+ break;
+
+ case SID_INSERT_FLD_AUTHOR:
+ {
+ SvtUserOptions aUserOptions;
+ pFieldItem.reset(new SvxFieldItem(
+ SvxAuthorField(
+ aUserOptions.GetFirstName(), aUserOptions.GetLastName(), aUserOptions.GetID() )
+ , EE_FEATURE_FIELD ));
+ }
+ break;
+
+ case SID_INSERT_FLD_PAGE:
+ pFieldItem.reset(new SvxFieldItem( SvxPageField(), EE_FEATURE_FIELD ));
+ break;
+
+ case SID_INSERT_FLD_PAGE_TITLE:
+ pFieldItem.reset(new SvxFieldItem( SvxPageTitleField(), EE_FEATURE_FIELD));
+ break;
+
+ case SID_INSERT_FLD_PAGES:
+ pFieldItem.reset(new SvxFieldItem( SvxPagesField(), EE_FEATURE_FIELD ));
+ break;
+
+ case SID_INSERT_FLD_FILE:
+ {
+ OUString aName;
+ if( GetDocSh()->HasName() )
+ aName = GetDocSh()->GetMedium()->GetName();
+ //else
+ // aName = GetDocSh()->GetName();
+ pFieldItem.reset(new SvxFieldItem( SvxExtFileField( aName ), EE_FEATURE_FIELD ));
+ }
+ break;
+ }
+
+ const SvxFieldItem* pOldFldItem = pOutlinerView->GetFieldAtSelection();
+
+ if( pOldFldItem && ( nullptr != dynamic_cast< const SvxURLField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxDateField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxTimeField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtTimeField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtFileField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxAuthorField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxPageField *>( pOldFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxPagesField *>( pOldFldItem->GetField() )) )
+ {
+ // select field, so it gets deleted on Insert
+ ESelection aSel = pOutlinerView->GetSelection();
+ if( aSel.nStartPos == aSel.nEndPos )
+ aSel.nEndPos++;
+ pOutlinerView->SetSelection( aSel );
+ }
+
+ if( pFieldItem )
+ pOutlinerView->InsertField( *pFieldItem );
+
+ pFieldItem.reset();
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+
+ case SID_MODIFY_FIELD:
+ {
+ const SvxFieldItem* pFldItem = pOutlinerView->GetFieldAtSelection();
+
+ if( pFldItem && (nullptr != dynamic_cast< const SvxDateField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxAuthorField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtFileField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtTimeField *>( pFldItem->GetField() ) ) )
+ {
+ // Dialog...
+ SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
+ vcl::Window* pWin = GetActiveWindow();
+ ScopedVclPtr<AbstractSdModifyFieldDlg> pDlg(pFact->CreateSdModifyFieldDlg(pWin ? pWin->GetFrameWeld() : nullptr, pFldItem->GetField(), pOutlinerView->GetAttribs() ));
+ if( pDlg->Execute() == RET_OK )
+ {
+ std::unique_ptr<SvxFieldData> pField(pDlg->GetField());
+ if( pField )
+ {
+ SvxFieldItem aFieldItem( *pField, EE_FEATURE_FIELD );
+ //pOLV->DeleteSelected(); <-- unfortunately missing!
+ // select field, so it gets deleted on Insert
+ ESelection aSel = pOutlinerView->GetSelection();
+ bool bSel = true;
+ if( aSel.nStartPos == aSel.nEndPos )
+ {
+ bSel = false;
+ aSel.nEndPos++;
+ }
+ pOutlinerView->SetSelection( aSel );
+
+ pOutlinerView->InsertField( aFieldItem );
+
+ // reset selection to original state
+ if( !bSel )
+ aSel.nEndPos--;
+ pOutlinerView->SetSelection( aSel );
+
+ pField.reset();
+ }
+
+ SfxItemSet aSet( pDlg->GetItemSet() );
+ if( aSet.Count() )
+ {
+ pOutlinerView->SetAttribs( aSet );
+
+ ::Outliner* pOutliner = pOutlinerView->GetOutliner();
+ if( pOutliner )
+ pOutliner->UpdateFields();
+ }
+ }
+ }
+
+ Cancel();
+ rReq.Ignore ();
+ }
+ break;
+ }
+
+ if(HasCurrentFunction())
+ GetCurrentFunction()->Activate();
+
+ Invalidate( SID_OUTLINE_COLLAPSE_ALL );
+ Invalidate( SID_OUTLINE_COLLAPSE );
+ Invalidate( SID_OUTLINE_EXPAND_ALL );
+ Invalidate( SID_OUTLINE_EXPAND );
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_OUTLINE_LEFT );
+ rBindings.Invalidate( SID_OUTLINE_RIGHT );
+ rBindings.Invalidate( SID_OUTLINE_UP );
+ rBindings.Invalidate( SID_OUTLINE_DOWN );
+
+ Invalidate( SID_OUTLINE_FORMAT );
+ Invalidate( SID_COLORVIEW );
+ Invalidate(SID_CUT);
+ Invalidate(SID_COPY);
+ Invalidate(SID_PASTE);
+ Invalidate(SID_PASTE_UNFORMATTED);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/outlnvsh.cxx b/sd/source/ui/view/outlnvsh.cxx
new file mode 100644
index 000000000..0eb351f91
--- /dev/null
+++ b/sd/source/ui/view/outlnvsh.cxx
@@ -0,0 +1,1883 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <OutlineViewShell.hxx>
+
+#include <helpids.h>
+#include <app.hrc>
+#include <svx/hyperdlg.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <svx/svdundo.hxx>
+
+#include <sfx2/infobar.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <sfx2/shell.hxx>
+#include <sfx2/request.hxx>
+#include <svx/hlnkitem.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdoutl.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/scrbar.hxx>
+#include <vcl/settings.hxx>
+
+#include <sal/log.hxx>
+#include <svl/stritem.hxx>
+#include <svl/whiter.hxx>
+#include <editeng/editstat.hxx>
+#include <svl/itempool.hxx>
+#include <sfx2/tplpitem.hxx>
+#include <sfx2/sidebar/SidebarChildWindow.hxx>
+#include <vcl/EnumContext.hxx>
+#include <sot/formats.hxx>
+#include <com/sun/star/linguistic2/XThesaurus.hpp>
+#include <editeng/unolingu.hxx>
+#include <editeng/outlobj.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svtools/cliplistener.hxx>
+#include <svl/srchitem.hxx>
+#include <editeng/editobj.hxx>
+#include <fubullet.hxx>
+
+#include <strings.hrc>
+
+#include <Window.hxx>
+#include <drawdoc.hxx>
+#include <sdresid.hxx>
+#include <sdpage.hxx>
+#include <fuoltext.hxx>
+#include <FrameView.hxx>
+#include <zoomlist.hxx>
+#include <stlsheet.hxx>
+#include <SdUnoOutlineView.hxx>
+#include <SpellDialogChildWindow.hxx>
+
+#include <AccessibleOutlineView.hxx>
+#include <ViewShellBase.hxx>
+#include <DrawController.hxx>
+#include <DrawDocShell.hxx>
+#include <OutlineView.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <sfx2/devtools/DevelopmentToolChildWindow.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::linguistic2;
+
+using namespace sd;
+
+#define ShellClass_OutlineViewShell
+#include <sdslots.hxx>
+
+namespace sd {
+
+#define MIN_ZOOM 10 // minimum zoom factor
+#define MAX_ZOOM 1000 // maximum zoom factor
+
+/**
+ * Declare SFX-Slotmap and standard interface
+ */
+SFX_IMPL_INTERFACE(OutlineViewShell, SfxShell)
+
+void OutlineViewShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterPopupMenu("outline");
+
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_TOOLS, SfxVisibilityFlags::Standard | SfxVisibilityFlags::FullScreen | SfxVisibilityFlags::Server,
+ ToolbarId::Outline_Toolbox);
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_APPLICATION, SfxVisibilityFlags::Standard | SfxVisibilityFlags::Client | SfxVisibilityFlags::Viewer | SfxVisibilityFlags::ReadonlyDoc,
+ ToolbarId::Draw_Viewer_Toolbox);
+
+ GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxHlinkDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(::sd::SpellDialogChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SID_SEARCH_DLG);
+ GetStaticInterface()->RegisterChildWindow(sfx2::sidebar::SidebarChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(DevelopmentToolChildWindow::GetChildWindowId());
+}
+
+
+/**
+ * common initialization part of both constructors
+ */
+void OutlineViewShell::Construct()
+{
+ bool bModified = GetDoc()->IsChanged();
+
+ meShellType = ST_OUTLINE;
+ Size aSize(29700, 21000);
+ Point aWinPos (0, 0);
+ Point aViewOrigin(0, 0);
+ GetActiveWindow()->SetMinZoomAutoCalc(false);
+ GetActiveWindow()->SetMinZoom( MIN_ZOOM );
+ GetActiveWindow()->SetMaxZoom( MAX_ZOOM );
+ InitWindows(aViewOrigin, aSize, aWinPos);
+ pOlView.reset( new OutlineView(*GetDocSh(), GetActiveWindow(), *this) );
+ mpView = pOlView.get(); // Pointer of base class ViewShell
+
+ SetPool( &GetDoc()->GetPool() );
+
+ SetZoom(69);
+
+ // Apply settings of FrameView
+ ReadFrameViewData(mpFrameView);
+
+ ::Outliner& rOutl = pOlView->GetOutliner();
+ rOutl.SetUpdateLayout(true);
+
+ if (!bModified)
+ {
+ rOutl.ClearModifyFlag();
+ }
+
+ pLastPage = GetActualPage();
+
+ SetName( "OutlineViewShell" );
+
+ GetActiveWindow()->SetHelpId( HID_SDOUTLINEVIEWSHELL );
+}
+
+Reference<drawing::XDrawSubController> OutlineViewShell::CreateSubController()
+{
+ Reference<drawing::XDrawSubController> xSubController;
+
+ if (IsMainViewShell())
+ {
+ // Create uno sub controller for the main view shell.
+ xSubController.set( new SdUnoOutlineView(*this) );
+ }
+
+ return xSubController;
+}
+
+/**
+ * Default constructor, windows must not center themselves automatically
+ */
+OutlineViewShell::OutlineViewShell (
+ SfxViewFrame* /*pFrame*/,
+ ViewShellBase& rViewShellBase,
+ vcl::Window* pParentWindow,
+ FrameView* pFrameViewArgument)
+ : ViewShell(pParentWindow, rViewShellBase),
+ pLastPage( nullptr ),
+ bPastePossible(false),
+ mbInitialized(false)
+
+{
+ if (pFrameViewArgument != nullptr)
+ mpFrameView = pFrameViewArgument;
+ else
+ mpFrameView = new FrameView(GetDoc());
+
+ mpFrameView->Connect();
+
+ Construct();
+
+ SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::OutlineText));
+
+ m_StrOldPageName.clear();
+
+ doShow();
+}
+
+OutlineViewShell::~OutlineViewShell()
+{
+ DisposeFunctions();
+
+ pOlView.reset();
+
+ mpFrameView->Disconnect();
+
+ if ( mxClipEvtLstnr.is() )
+ {
+ mxClipEvtLstnr->RemoveListener( GetActiveWindow() );
+ mxClipEvtLstnr->ClearCallbackLink(); // prevent callback if another thread is waiting
+ }
+}
+
+void OutlineViewShell::Shutdown()
+{
+ ViewShell::Shutdown();
+
+ PrepareClose();
+}
+
+/**
+ * Paint method: the event gets forwarded from pWindow to the Viewshell
+ * and the current function
+ */
+void OutlineViewShell::Paint(const ::tools::Rectangle& rRect, ::sd::Window* pWin)
+{
+ if (pOlView)
+ {
+ pOlView->Paint(rRect, pWin);
+ }
+}
+
+void OutlineViewShell::ArrangeGUIElements ()
+{
+ // Retrieve the current size (thickness) of the scroll bars. That is
+ // the width of the vertical and the height of the horizontal scroll
+ // bar.
+ int nScrollBarSize =
+ GetParentWindow()->GetSettings().GetStyleSettings().GetScrollBarSize();
+ maScrBarWH = Size (nScrollBarSize, nScrollBarSize);
+
+ ViewShell::ArrangeGUIElements ();
+
+ ::sd::Window* pWindow = mpContentWindow.get();
+ if (pWindow == nullptr)
+ return;
+
+ pWindow->SetMinZoomAutoCalc(false);
+
+ // change OutputArea of the OutlinerView
+ OutlinerView* pOutlinerView = pOlView->GetViewByWindow(pWindow);
+
+ ::tools::Rectangle aWin(Point(0,0), pWindow->GetOutputSizePixel());
+
+ aWin = pWindow->PixelToLogic(aWin);
+ pOutlinerView->SetOutputArea(aWin);
+
+ ::tools::Rectangle aVis = pOutlinerView->GetVisArea();
+
+ ::tools::Rectangle aText(Point(0,0),
+ Size(pOlView->GetPaperWidth(),
+ pOlView->GetOutliner().GetTextHeight()));
+ if (aWin.GetHeight() > aText.Bottom())
+ aText.SetBottom( aWin.GetHeight() );
+
+ if (!aWin.IsEmpty()) // not when opening
+ {
+ InitWindows(Point(0,0), aText.GetSize(), aVis.TopLeft());
+ UpdateScrollBars();
+ }
+}
+
+/**
+ * Handle SfxRequest for the Controller
+ */
+void OutlineViewShell::ExecCtrl(SfxRequest &rReq)
+{
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch ( nSlot )
+ {
+ case SID_MAIL_SCROLLBODY_PAGEDOWN:
+ {
+ ExecReq( rReq );
+ break;
+ }
+
+ case SID_OPT_LOCALE_CHANGED:
+ {
+ pOlView->GetOutliner().UpdateFields();
+ UpdatePreview( GetActualPage() );
+ rReq.Done();
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+/**
+ * Activate(): during the first invocation the fields get updated
+ */
+void OutlineViewShell::Activate( bool bIsMDIActivate )
+{
+ if ( ! mbInitialized)
+ {
+ mbInitialized = true;
+ SfxRequest aRequest (SID_EDIT_OUTLINER, SfxCallMode::SLOT, GetDoc()->GetItemPool());
+ FuPermanent (aRequest);
+ }
+
+ ViewShell::Activate( bIsMDIActivate );
+ SfxShell::BroadcastContextForActivation(true);
+
+ pOlView->SetLinks();
+ pOlView->ConnectToApplication();
+
+ if( bIsMDIActivate )
+ {
+ OutlinerView* pOutlinerView = pOlView->GetViewByWindow( GetActiveWindow() );
+ ::Outliner* pOutl = pOutlinerView->GetOutliner();
+ pOutl->UpdateFields();
+ }
+}
+
+void OutlineViewShell::Deactivate( bool bIsMDIActivate )
+{
+ pOlView->DisconnectFromApplication();
+
+ // Links must be kept also on deactivated viewshell, to allow drag'n'drop
+ // to function properly
+ ViewShell::Deactivate( bIsMDIActivate );
+}
+
+/**
+ * Set status of Controller-SfxSlots
+ */
+void OutlineViewShell::GetCtrlState(SfxItemSet &rSet)
+{
+ if (SfxItemState::DEFAULT == rSet.GetItemState(SID_HYPERLINK_GETLINK))
+ {
+ SvxHyperlinkItem aHLinkItem;
+
+ OutlinerView* pOLV = pOlView->GetViewByWindow(GetActiveWindow());
+ if (pOLV)
+ {
+ const SvxFieldItem* pFieldItem = pOLV->GetFieldAtSelection();
+ if (pFieldItem)
+ {
+ ESelection aSel = pOLV->GetSelection();
+ if ( abs( aSel.nEndPos - aSel.nStartPos ) == 1 )
+ {
+ const SvxFieldData* pField = pFieldItem->GetField();
+ if ( auto pUrlField = dynamic_cast< const SvxURLField *>( pField ) )
+ {
+ aHLinkItem.SetName(pUrlField->GetRepresentation());
+ aHLinkItem.SetURL(pUrlField->GetURL());
+ aHLinkItem.SetTargetFrame(pUrlField->GetTargetFrame());
+ }
+ }
+ }
+ }
+ rSet.Put(aHLinkItem);
+ }
+ rSet.Put( SfxBoolItem( SID_READONLY_MODE, GetDocSh()->IsReadOnly() ) );
+
+ if ( SfxItemState::DEFAULT == rSet.GetItemState(SID_MAIL_SCROLLBODY_PAGEDOWN) )
+ rSet.Put( SfxBoolItem( SID_MAIL_SCROLLBODY_PAGEDOWN, true ) );
+
+ if ( !(SfxItemState::DEFAULT == rSet.GetItemState(SID_TRANSLITERATE_HALFWIDTH) ||
+ SfxItemState::DEFAULT == rSet.GetItemState(SID_TRANSLITERATE_FULLWIDTH) ||
+ SfxItemState::DEFAULT == rSet.GetItemState(SID_TRANSLITERATE_HIRAGANA) ||
+ SfxItemState::DEFAULT == rSet.GetItemState(SID_TRANSLITERATE_KATAKANA)) )
+ return;
+
+ if( !SvtCJKOptions::IsChangeCaseMapEnabled() )
+ {
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, false );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, false );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, false );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, false );
+ rSet.DisableItem( SID_TRANSLITERATE_HALFWIDTH );
+ rSet.DisableItem( SID_TRANSLITERATE_FULLWIDTH );
+ rSet.DisableItem( SID_TRANSLITERATE_HIRAGANA );
+ rSet.DisableItem( SID_TRANSLITERATE_KATAKANA );
+ }
+ else
+ {
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, true );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, true );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, true );
+ GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, true );
+ }
+}
+
+/**
+ * SfxRequests for support functions
+ */
+void OutlineViewShell::FuSupport(SfxRequest &rReq)
+{
+ if( rReq.GetSlot() == SID_STYLE_FAMILY && rReq.GetArgs())
+ GetDocSh()->SetStyleFamily(static_cast<SfxStyleFamily>(rReq.GetArgs()->Get( SID_STYLE_FAMILY ).GetValue()));
+
+ bool bPreviewState = false;
+ sal_uLong nSlot = rReq.GetSlot();
+
+ std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard;
+ if( pOlView && (
+ (nSlot == SID_TRANSLITERATE_SENTENCE_CASE) ||
+ (nSlot == SID_TRANSLITERATE_TITLE_CASE) ||
+ (nSlot == SID_TRANSLITERATE_TOGGLE_CASE) ||
+ (nSlot == SID_TRANSLITERATE_UPPER) ||
+ (nSlot == SID_TRANSLITERATE_LOWER) ||
+ (nSlot == SID_TRANSLITERATE_HALFWIDTH) ||
+ (nSlot == SID_TRANSLITERATE_FULLWIDTH) ||
+ (nSlot == SID_TRANSLITERATE_HIRAGANA) ||
+ (nSlot == SID_TRANSLITERATE_KATAKANA) ||
+ (nSlot == SID_CUT) ||
+ (nSlot == SID_PASTE) ||
+ (nSlot == SID_PASTE_UNFORMATTED) ||
+ (nSlot == SID_DELETE)))
+ {
+ aGuard.reset( new OutlineViewModelChangeGuard( *pOlView ) );
+ }
+
+ switch ( nSlot )
+ {
+ case SID_CUT:
+ {
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->DoCut();
+ }
+ else if (pOlView)
+ {
+ pOlView->DoCut();
+ }
+ rReq.Done();
+ bPreviewState = true;
+ }
+ break;
+
+ case SID_COPY:
+ {
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->DoCopy();
+ }
+ else if (pOlView)
+ {
+ pOlView->DoCopy();
+ }
+ rReq.Done();
+ bPreviewState = true;
+ }
+ break;
+
+ case SID_PASTE:
+ {
+ OutlineViewPageChangesGuard aGuard2(pOlView.get());
+
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->DoPaste();
+ }
+ else if (pOlView)
+ {
+ pOlView->DoPaste();
+ }
+ rReq.Done();
+ bPreviewState = true;
+ }
+ break;
+
+ case SID_PASTE_UNFORMATTED:
+ {
+ OutlineViewPageChangesGuard aGuard2(pOlView.get());
+
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->DoPasteUnformatted();
+ }
+ else if(pOlView)
+ {
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( GetActiveWindow() ) );
+ if (aDataHelper.GetTransferable().is())
+ {
+ sal_Int8 nAction = DND_ACTION_COPY;
+ pOlView->InsertData( aDataHelper,
+ GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(), GetActiveWindow()->GetOutputSizePixel() ).Center() ),
+ nAction, false, SotClipboardFormatId::STRING);
+ }
+ }
+
+ rReq.Ignore ();
+ }
+ break;
+ case SID_DELETE:
+ {
+ if( pOlView )
+ {
+ OutlinerView* pOutlView = pOlView->GetViewByWindow(GetActiveWindow());
+ if (pOutlView)
+ {
+ OutlineViewPageChangesGuard aGuard2(pOlView.get());
+
+ vcl::KeyCode aKCode(KEY_DELETE);
+ KeyEvent aKEvt( 0, aKCode );
+ pOutlView->PostKeyEvent(aKEvt);
+
+ rtl::Reference<FuPoor> xFunc( GetCurrentFunction() );
+ FuOutlineText* pFuOutlineText = dynamic_cast< FuOutlineText* >( xFunc.get() );
+ if( pFuOutlineText )
+ pFuOutlineText->UpdateForKeyPress (aKEvt);
+ }
+ }
+ rReq.Done();
+ bPreviewState = true;
+ }
+ break;
+
+ case SID_DRAWINGMODE:
+ case SID_SLIDE_MASTER_MODE:
+ case SID_NOTES_MODE:
+ case SID_NOTES_MASTER_MODE:
+ case SID_HANDOUT_MASTER_MODE:
+ case SID_SLIDE_SORTER_MODE:
+ case SID_OUTLINE_MODE:
+ framework::FrameworkHelper::Instance(GetViewShellBase())->HandleModeChangeSlot(
+ nSlot,
+ rReq);
+ rReq.Done();
+ break;
+
+ case SID_RULER:
+ SetRuler( !HasRuler() );
+ Invalidate( SID_RULER );
+ rReq.Done();
+ break;
+
+ case SID_ZOOM_PREV:
+ {
+ if (mpZoomList->IsPreviousPossible())
+ {
+ SetZoomRect(mpZoomList->GetPreviousZoomRect());
+ }
+ rReq.Done ();
+ }
+ break;
+
+ case SID_ZOOM_NEXT:
+ {
+ if (mpZoomList->IsNextPossible())
+ {
+ SetZoomRect(mpZoomList->GetNextZoomRect());
+ }
+ rReq.Done ();
+ }
+ break;
+
+ case SID_AUTOSPELL_CHECK:
+ {
+ GetDoc()->SetOnlineSpell(!GetDoc()->GetOnlineSpell());
+ rReq.Done ();
+ }
+ break;
+
+ case SID_TRANSLITERATE_SENTENCE_CASE:
+ case SID_TRANSLITERATE_TITLE_CASE:
+ case SID_TRANSLITERATE_TOGGLE_CASE:
+ case SID_TRANSLITERATE_UPPER:
+ case SID_TRANSLITERATE_LOWER:
+ case SID_TRANSLITERATE_HALFWIDTH:
+ case SID_TRANSLITERATE_FULLWIDTH:
+ case SID_TRANSLITERATE_HIRAGANA:
+ case SID_TRANSLITERATE_KATAKANA:
+ {
+ OutlinerView* pOLV = pOlView ? pOlView->GetViewByWindow( GetActiveWindow() ) : nullptr;
+ if( pOLV )
+ {
+ TransliterationFlags nType = TransliterationFlags::NONE;
+
+ switch( nSlot )
+ {
+ case SID_TRANSLITERATE_SENTENCE_CASE:
+ nType = TransliterationFlags::SENTENCE_CASE;
+ break;
+ case SID_TRANSLITERATE_TITLE_CASE:
+ nType = TransliterationFlags::TITLE_CASE;
+ break;
+ case SID_TRANSLITERATE_TOGGLE_CASE:
+ nType = TransliterationFlags::TOGGLE_CASE;
+ break;
+ case SID_TRANSLITERATE_UPPER:
+ nType = TransliterationFlags::LOWERCASE_UPPERCASE;
+ break;
+ case SID_TRANSLITERATE_LOWER:
+ nType = TransliterationFlags::UPPERCASE_LOWERCASE;
+ break;
+ case SID_TRANSLITERATE_HALFWIDTH:
+ nType = TransliterationFlags::FULLWIDTH_HALFWIDTH;
+ break;
+ case SID_TRANSLITERATE_FULLWIDTH:
+ nType = TransliterationFlags::HALFWIDTH_FULLWIDTH;
+ break;
+ case SID_TRANSLITERATE_HIRAGANA:
+ nType = TransliterationFlags::KATAKANA_HIRAGANA;
+ break;
+ case SID_TRANSLITERATE_KATAKANA:
+ nType = TransliterationFlags::HIRAGANA_KATAKANA;
+ break;
+ }
+
+ pOLV->TransliterateText( nType );
+ }
+
+ rReq.Done();
+ bPreviewState = true;
+ }
+ break;
+
+ // added Undo/Redo handling
+ case SID_UNDO :
+ {
+ OutlineViewPageChangesGuard aGuard2(pOlView.get());
+ ImpSidUndo(rReq);
+ }
+ break;
+ case SID_REDO :
+ {
+ OutlineViewPageChangesGuard aGuard2(pOlView.get());
+ ImpSidRedo(rReq);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if( bPreviewState )
+ Invalidate( SID_PREVIEW_STATE );
+
+ Invalidate(SID_CUT);
+ Invalidate(SID_COPY);
+ Invalidate(SID_PASTE);
+}
+
+/**
+ * SfxRequests for permanent functions
+ */
+void OutlineViewShell::FuPermanent(SfxRequest &rReq)
+{
+ if(HasCurrentFunction())
+ {
+ DeactivateCurrentFunction(true);
+ }
+
+ switch ( rReq.GetSlot() )
+ {
+ case SID_EDIT_OUTLINER:
+ {
+ ::Outliner& rOutl = pOlView->GetOutliner();
+ rOutl.GetUndoManager().Clear();
+ rOutl.UpdateFields();
+
+ SetCurrentFunction( FuOutlineText::Create(this,GetActiveWindow(),pOlView.get(),GetDoc(),rReq) );
+
+ rReq.Done();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if(HasOldFunction())
+ {
+ GetOldFunction()->Deactivate();
+ SetOldFunction(nullptr);
+ }
+
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->Activate();
+ SetOldFunction(GetCurrentFunction());
+ }
+}
+
+IMPL_LINK( OutlineViewShell, ClipboardChanged, TransferableDataHelper*, pDataHelper, void )
+{
+ bPastePossible = pDataHelper->GetFormatCount() != 0 &&
+ ( pDataHelper->HasFormat( SotClipboardFormatId::STRING ) ||
+ pDataHelper->HasFormat( SotClipboardFormatId::RTF ) ||
+ pDataHelper->HasFormat( SotClipboardFormatId::RICHTEXT ) ||
+ pDataHelper->HasFormat( SotClipboardFormatId::HTML ) );
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_PASTE );
+ rBindings.Invalidate( SID_PASTE_SPECIAL );
+ rBindings.Invalidate( SID_PASTE_UNFORMATTED );
+ rBindings.Invalidate( SID_CLIPBOARD_FORMAT_ITEMS );
+}
+
+/**
+ * Set Status (Enabled/Disabled) of Menu-SfxSlots
+ */
+void OutlineViewShell::GetMenuState( SfxItemSet &rSet )
+{
+ ViewShell::GetMenuState(rSet);
+
+ rSet.Put(SfxBoolItem(SID_SLIDE_SORTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_DRAWINGMODE, false));
+ rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_OUTLINE_MODE, true));
+ rSet.Put(SfxBoolItem(SID_NOTES_MODE, false));
+ rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, false));
+ rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false));
+
+ if (!mpZoomList->IsNextPossible())
+ {
+ rSet.DisableItem(SID_ZOOM_NEXT);
+ }
+ if (!mpZoomList->IsPreviousPossible())
+ {
+ rSet.DisableItem(SID_ZOOM_PREV);
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ZOOM_IN ) ||
+ SfxItemState::DEFAULT == rSet.GetItemState( SID_ZOOM_OUT ) )
+ {
+ if( GetActiveWindow()->GetZoom() <= GetActiveWindow()->GetMinZoom() || GetDocSh()->IsUIActive() )
+ rSet.DisableItem( SID_ZOOM_OUT );
+ if( GetActiveWindow()->GetZoom() >= GetActiveWindow()->GetMaxZoom() || GetDocSh()->IsUIActive() )
+ rSet.DisableItem( SID_ZOOM_IN );
+ }
+
+ ::Outliner& rOutl = pOlView->GetOutliner();
+
+ // allow 'Select All'?
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_SELECTALL ) )
+ {
+ sal_Int32 nParaCount = rOutl.GetParagraphCount();
+ bool bDisable = nParaCount == 0;
+ if (!bDisable && nParaCount == 1)
+ {
+ OUString aTest = rOutl.GetText(rOutl.GetParagraph(0));
+ if (aTest.isEmpty())
+ {
+ bDisable = true;
+ }
+ }
+ if (bDisable)
+ rSet.DisableItem(SID_SELECTALL);
+ }
+
+ // set status of Ruler
+ rSet.Put( SfxBoolItem( SID_RULER, HasRuler() ) );
+
+ // Enable formatting?
+ rSet.Put( SfxBoolItem( SID_OUTLINE_FORMAT, !rOutl.IsFlatMode() ) );
+
+ if( rOutl.IsFlatMode() )
+ rSet.DisableItem( SID_COLORVIEW );
+ else
+ {
+ // Enable color view?
+ EEControlBits nCntrl = rOutl.GetControlWord();
+ bool bNoColor = false;
+ if (nCntrl & EEControlBits::NOCOLORS)
+ bNoColor = true;
+
+ rSet.Put( SfxBoolItem( SID_COLORVIEW, bNoColor ) );
+ }
+
+ // Buttons of toolbar
+ // first the selection dependent ones: COLLAPSE, EXPAND
+ bool bDisableCollapse = true;
+ bool bDisableExpand = true;
+ bool bUnique = true;
+ OutlinerView* pOutlinerView = pOlView->GetViewByWindow(GetActiveWindow());
+
+ std::vector<Paragraph*> aSelList;
+ pOutlinerView->CreateSelectionList(aSelList);
+
+ if (!aSelList.empty())
+ {
+ sal_Int16 nTmpDepth = rOutl.GetDepth( rOutl.GetAbsPos( aSelList.front() ) );
+ bool bPage = ::Outliner::HasParaFlag( aSelList.front(), ParaFlag::ISPAGE );
+
+ for (const Paragraph* pPara : aSelList)
+ {
+ sal_Int16 nDepth = rOutl.GetDepth( rOutl.GetAbsPos( pPara ) );
+
+ if( nDepth != nTmpDepth || bPage != ::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ))
+ bUnique = false;
+
+ if (rOutl.HasChildren(pPara))
+ {
+ if (!rOutl.IsExpanded(pPara))
+ bDisableExpand = false;
+ else
+ bDisableCollapse = false;
+ }
+ }
+ }
+
+ if (bDisableExpand)
+ rSet.DisableItem(SID_OUTLINE_EXPAND);
+ if (bDisableCollapse)
+ rSet.DisableItem(SID_OUTLINE_COLLAPSE);
+
+ // does the selection provide a unique presentation layout?
+ // if not, the templates must not be edited
+ SfxItemSetFixed<SID_STATUS_LAYOUT, SID_STATUS_LAYOUT> aSet(*rSet.GetPool());
+ GetStatusBarState(aSet);
+ OUString aTest = static_cast<const SfxStringItem&>(aSet.Get(SID_STATUS_LAYOUT)).GetValue();
+ if (aTest.isEmpty())
+ {
+ bUnique = false;
+ }
+
+ if (!bUnique)
+ rSet.DisableItem( SID_PRESENTATIONOBJECT );
+
+ // now the selection independent ones: COLLAPSE_ALL, EXPAND_ALL
+ bool bDisableCollapseAll = true;
+ bool bDisableExpandAll = true;
+
+ // does the selection contain something collapsible/expandable?
+ if (!bDisableCollapse)
+ bDisableCollapseAll = false;
+ if (!bDisableExpand)
+ bDisableExpandAll = false;
+
+ // otherwise look through all paragraphs
+ if (bDisableCollapseAll || bDisableExpandAll)
+ {
+ sal_Int32 nParaPos = 0;
+ Paragraph* pPara = rOutl.GetParagraph( nParaPos );
+ while (pPara && (bDisableCollapseAll || bDisableExpandAll))
+ {
+ if (!rOutl.IsExpanded(pPara) && rOutl.HasChildren(pPara))
+ bDisableExpandAll = false;
+
+ if (rOutl.IsExpanded(pPara) && rOutl.HasChildren(pPara))
+ bDisableCollapseAll = false;
+
+ pPara = rOutl.GetParagraph( ++nParaPos );
+ }
+ }
+
+ if (bDisableExpandAll)
+ rSet.DisableItem(SID_OUTLINE_EXPAND_ALL);
+ if (bDisableCollapseAll)
+ rSet.DisableItem(SID_OUTLINE_COLLAPSE_ALL);
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_PASTE ) )
+ {
+ if ( !mxClipEvtLstnr.is() )
+ {
+ // create listener
+ mxClipEvtLstnr = new TransferableClipboardListener( LINK( this, OutlineViewShell, ClipboardChanged ) );
+ mxClipEvtLstnr->AddListener( GetActiveWindow() );
+
+ // get initial state
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( GetActiveWindow() ) );
+ bPastePossible = ( aDataHelper.GetFormatCount() != 0 &&
+ ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) ||
+ aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ||
+ aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ||
+ aDataHelper.HasFormat( SotClipboardFormatId::HTML ) ) );
+ }
+
+ if( !bPastePossible )
+ {
+ rSet.DisableItem( SID_PASTE );
+ }
+ }
+
+ if (!pOlView->GetViewByWindow(GetActiveWindow())->HasSelection()
+ || GetObjectShell()->isContentExtractionLocked())
+ {
+ rSet.DisableItem(SID_CUT);
+ rSet.DisableItem(SID_COPY);
+ }
+
+ if (pOlView->GetOutliner().IsModified())
+ {
+ GetDoc()->SetChanged();
+ }
+
+ // the status has to be set here because of overriding
+ if( !GetDocSh()->IsModified() )
+ {
+ rSet.DisableItem( SID_SAVEDOC );
+ }
+
+ if ( GetDocSh()->IsReadOnly() )
+ {
+ rSet.DisableItem( SID_AUTOSPELL_CHECK );
+ }
+ else
+ {
+ if (GetDoc()->GetOnlineSpell())
+ {
+ rSet.Put(SfxBoolItem(SID_AUTOSPELL_CHECK, true));
+ }
+ else
+ {
+ rSet.Put(SfxBoolItem(SID_AUTOSPELL_CHECK, false));
+ }
+ }
+
+ // field commands
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_MODIFY_FIELD ) )
+ {
+ const SvxFieldItem* pFldItem = pOutlinerView->GetFieldAtSelection();
+
+ if( !( pFldItem && (nullptr != dynamic_cast< const SvxDateField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxAuthorField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtFileField *>( pFldItem->GetField() ) ||
+ nullptr != dynamic_cast< const SvxExtTimeField *>( pFldItem->GetField() ) ) ) )
+ {
+ rSet.DisableItem( SID_MODIFY_FIELD );
+ }
+ }
+
+ if (SfxItemState::DEFAULT == rSet.GetItemState(SID_EXPAND_PAGE))
+ {
+ bool bDisable = true;
+ sal_uInt16 i = 0;
+ sal_uInt16 nCount = GetDoc()->GetSdPageCount(PageKind::Standard);
+ pOlView->SetSelectedPages();
+
+ while (i < nCount && bDisable)
+ {
+ SdPage* pPage = GetDoc()->GetSdPage(i, PageKind::Standard);
+
+ if (pPage->IsSelected())
+ {
+ SdrObject* pObj = pPage->GetPresObj(PresObjKind::Outline);
+
+ if (pObj!=nullptr )
+ {
+ if( !pObj->IsEmptyPresObj() )
+ {
+ bDisable = false;
+ }
+ else
+ {
+ // check if the object is in edit, then if it's temporarily not empty
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObj );
+ if( pTextObj )
+ {
+ if( pTextObj->CanCreateEditOutlinerParaObject() )
+ {
+ bDisable = false;
+ }
+ }
+ }
+ }
+ }
+
+ i++;
+ }
+
+ if (bDisable)
+ {
+ rSet.DisableItem(SID_EXPAND_PAGE);
+ }
+ }
+
+ if (SfxItemState::DEFAULT == rSet.GetItemState(SID_SUMMARY_PAGE))
+ {
+ bool bDisable = true;
+ sal_uInt16 i = 0;
+ sal_uInt16 nCount = GetDoc()->GetSdPageCount(PageKind::Standard);
+ pOlView->SetSelectedPages();
+
+ while (i < nCount && bDisable)
+ {
+ SdPage* pPage = GetDoc()->GetSdPage(i, PageKind::Standard);
+
+ if (pPage->IsSelected())
+ {
+ SdrObject* pObj = pPage->GetPresObj(PresObjKind::Title);
+
+ if (pObj && !pObj->IsEmptyPresObj())
+ {
+ bDisable = false;
+ }
+ }
+
+ i++;
+ }
+
+ if (bDisable)
+ {
+ rSet.DisableItem(SID_SUMMARY_PAGE);
+ }
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_THESAURUS ) )
+ {
+ if ( !pOlView->IsTextEdit() )
+ {
+ rSet.DisableItem( SID_THESAURUS );
+ }
+ else
+ {
+ LanguageType eLang = GetDoc()->GetLanguage( EE_CHAR_LANGUAGE );
+ Reference< XThesaurus > xThesaurus( LinguMgr::GetThesaurus() );
+
+ if (!xThesaurus.is() || eLang == LANGUAGE_NONE || !xThesaurus->hasLocale( LanguageTag::convertToLocale( eLang)))
+ rSet.DisableItem( SID_THESAURUS );
+ }
+ }
+
+ // is starting the presentation possible?
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_PRESENTATION ) )
+ {
+ bool bDisable = true;
+ sal_uInt16 nCount = GetDoc()->GetSdPageCount( PageKind::Standard );
+
+ for( sal_uInt16 i = 0; i < nCount && bDisable; i++ )
+ {
+ SdPage* pPage = GetDoc()->GetSdPage(i, PageKind::Standard);
+
+ if( !pPage->IsExcluded() )
+ bDisable = false;
+ }
+ if( bDisable || GetDocSh()->IsPreview())
+ {
+ rSet.DisableItem( SID_PRESENTATION );
+ }
+ }
+
+ FuBullet::GetSlotState( rSet, this, GetViewFrame() );
+
+}
+
+/**
+ * gets invoked when ScrollBar is used
+ */
+void OutlineViewShell::VirtHScrollHdl(ScrollBar* pHScroll)
+{
+ ::tools::Long nThumb = pHScroll->GetThumbPos();
+ ::tools::Long nRange = pHScroll->GetRange().Len();
+ double fX = static_cast<double>(nThumb) / nRange;
+
+ Window* pWin = mpContentWindow.get();
+ OutlinerView* pOutlinerView = pOlView->GetViewByWindow(pWin);
+ ::tools::Long nViewWidth = pWin->PixelToLogic(
+ pWin->GetSizePixel()).Width();
+ ::tools::Long nTextWidth = pOlView->GetPaperWidth();
+ nViewWidth = std::max(nViewWidth, nTextWidth);
+ ::tools::Long nCurrentPos = pOutlinerView->GetVisArea().Left();
+ ::tools::Long nTargetPos = static_cast<::tools::Long>(fX * nViewWidth);
+ ::tools::Long nDelta = nTargetPos - nCurrentPos;
+
+ pOutlinerView->HideCursor();
+ pOutlinerView->Scroll(-nDelta, 0);
+ pOutlinerView->ShowCursor(false);
+}
+
+void OutlineViewShell::VirtVScrollHdl(ScrollBar* pVScroll)
+{
+ ::tools::Long nThumb = pVScroll->GetThumbPos();
+ ::tools::Long nRange = pVScroll->GetRange().Len();
+ double fY = static_cast<double>(nThumb) / nRange;
+
+ Window* pWin = mpContentWindow.get();
+ OutlinerView* pOutlinerView = pOlView->GetViewByWindow(pWin);
+ ::tools::Long nViewHeight = pWin->PixelToLogic(
+ pWin->GetSizePixel()).Height();
+ ::tools::Long nTextHeight = pOlView->GetOutliner().GetTextHeight();
+ nViewHeight += nTextHeight;
+ ::tools::Long nCurrentPos = pOutlinerView->GetVisArea().Top();
+ ::tools::Long nTargetPos = static_cast<::tools::Long>(fY * nViewHeight);
+ ::tools::Long nDelta = nTargetPos - nCurrentPos;
+
+ pOutlinerView->HideCursor();
+ pOutlinerView->Scroll(0, -nDelta);
+ pOutlinerView->ShowCursor(false);
+}
+
+/**
+ * PrepareClose, gets called when the Shell shall be destroyed.
+ * Forwards the invocation to the View
+ */
+bool OutlineViewShell::PrepareClose( bool bUI )
+{
+ if( !ViewShell::PrepareClose(bUI) )
+ return false;
+
+ if (pOlView)
+ pOlView->PrepareClose();
+ return true;
+}
+
+/**
+ * Zoom with zoom factor. Inform OutlinerView
+ */
+void OutlineViewShell::SetZoom(::tools::Long nZoom)
+{
+ ViewShell::SetZoom(nZoom);
+
+ ::sd::Window* pWindow = mpContentWindow.get();
+ if (pWindow)
+ {
+ // change OutputArea of OutlinerView
+ OutlinerView* pOutlinerView = pOlView->GetViewByWindow(pWindow);
+ ::tools::Rectangle aWin(Point(0,0), pWindow->GetOutputSizePixel());
+ aWin = pWindow->PixelToLogic(aWin);
+ pOutlinerView->SetOutputArea(aWin);
+ }
+
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM );
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
+}
+
+/**
+ * Zoom with zoom rectangle. Inform OutlinerView
+ */
+void OutlineViewShell::SetZoomRect(const ::tools::Rectangle& rZoomRect)
+{
+ ViewShell::SetZoomRect(rZoomRect);
+
+ ::sd::Window* pWindow = mpContentWindow.get();
+ if (pWindow)
+ {
+ // change OutputArea of OutlinerView
+ OutlinerView* pOutlinerView = pOlView->GetViewByWindow(pWindow);
+ ::tools::Rectangle aWin(Point(0,0), pWindow->GetOutputSizePixel());
+ aWin = pWindow->PixelToLogic(aWin);
+ pOutlinerView->SetOutputArea(aWin);
+ }
+
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM );
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
+}
+
+/**
+ * Before saving: Update Model of the Drawing Engine, then forward the
+ * invocation to the ObjectShell.
+ */
+void OutlineViewShell::Execute(SfxRequest& rReq)
+{
+ bool bForwardCall = true;
+
+ switch(rReq.GetSlot())
+ {
+ case SID_SAVEDOC:
+ case SID_SAVEASDOC:
+ PrepareClose();
+ break;
+
+ case SID_SEARCH_ITEM:
+ // Forward this request to the common (old) code of the
+ // document shell.
+ GetDocSh()->Execute (rReq);
+ bForwardCall = false;
+ break;
+
+ case SID_SPELL_DIALOG:
+ {
+ SfxViewFrame* pViewFrame = GetViewFrame();
+ if (rReq.GetArgs() != nullptr)
+ pViewFrame->SetChildWindow (SID_SPELL_DIALOG,
+ static_cast<const SfxBoolItem&>(rReq.GetArgs()->
+ Get(SID_SPELL_DIALOG)).GetValue());
+ else
+ pViewFrame->ToggleChildWindow(SID_SPELL_DIALOG);
+
+ pViewFrame->GetBindings().Invalidate(SID_SPELL_DIALOG);
+ rReq.Done ();
+
+ bForwardCall = false;
+ }
+ break;
+
+ default:
+ SAL_WARN("sd", "OutlineViewShell::Execute(): can not handle slot " << rReq.GetSlot());
+ break;
+
+ }
+
+ if (bForwardCall)
+ static_cast<DrawDocShell*>(GetViewFrame()->GetObjectShell())->ExecuteSlot( rReq );
+}
+
+/**
+ * Read FrameViews data and set actual views data
+ */
+void OutlineViewShell::ReadFrameViewData(FrameView* pView)
+{
+ ::Outliner& rOutl = pOlView->GetOutliner();
+
+ rOutl.SetFlatMode( pView->IsNoAttribs() );
+
+ EEControlBits nCntrl = rOutl.GetControlWord();
+
+ if ( pView->IsNoColors() )
+ rOutl.SetControlWord(nCntrl | EEControlBits::NOCOLORS);
+ else
+ rOutl.SetControlWord(nCntrl & ~EEControlBits::NOCOLORS);
+
+ sal_uInt16 nPage = mpFrameView->GetSelectedPage();
+ pLastPage = GetDoc()->GetSdPage( nPage, PageKind::Standard );
+ pOlView->SetActualPage(pLastPage);
+}
+
+/**
+ * Write actual views data to FrameView
+ */
+void OutlineViewShell::WriteFrameViewData()
+{
+ ::Outliner& rOutl = pOlView->GetOutliner();
+
+ EEControlBits nCntrl = rOutl.GetControlWord();
+ bool bNoColor = false;
+ if (nCntrl & EEControlBits::NOCOLORS)
+ bNoColor = true;
+ mpFrameView->SetNoColors(bNoColor);
+ mpFrameView->SetNoAttribs( rOutl.IsFlatMode() );
+ SdPage* pActualPage = pOlView->GetActualPage();
+ DBG_ASSERT(pActualPage, "No current page");
+ if( pActualPage )
+ mpFrameView->SetSelectedPage((pActualPage->GetPageNum() - 1) / 2);
+}
+
+/**
+ * Handle SfxRequests for the StatusBar
+ */
+void OutlineViewShell::ExecStatusBar(SfxRequest&)
+{
+}
+
+void OutlineViewShell::GetStatusBarState(SfxItemSet& rSet)
+{
+ // Zoom-Item
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_ZOOM ) )
+ {
+ sal_uInt16 nZoom = static_cast<sal_uInt16>(GetActiveWindow()->GetZoom());
+
+ std::unique_ptr<SvxZoomItem> pZoomItem(new SvxZoomItem( SvxZoomType::PERCENT, nZoom ));
+
+ // limit area
+ SvxZoomEnableFlags nZoomValues = SvxZoomEnableFlags::ALL;
+ nZoomValues &= ~SvxZoomEnableFlags::OPTIMAL;
+ nZoomValues &= ~SvxZoomEnableFlags::WHOLEPAGE;
+ nZoomValues &= ~SvxZoomEnableFlags::PAGEWIDTH;
+
+ pZoomItem->SetValueSet( nZoomValues );
+ rSet.Put( std::move(pZoomItem) );
+ }
+
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_ZOOMSLIDER ) )
+ {
+ if (GetDocSh()->IsUIActive() || !GetActiveWindow() )
+ {
+ rSet.DisableItem( SID_ATTR_ZOOMSLIDER );
+ }
+ else
+ {
+ sd::Window * pActiveWindow = GetActiveWindow();
+ SvxZoomSliderItem aZoomItem( static_cast<sal_uInt16>(pActiveWindow->GetZoom()), static_cast<sal_uInt16>(pActiveWindow->GetMinZoom()), static_cast<sal_uInt16>(pActiveWindow->GetMaxZoom()) ) ;
+ aZoomItem.AddSnappingPoint(100);
+ rSet.Put( aZoomItem );
+ }
+ }
+
+ // page view and layout
+
+ sal_uInt16 nPageCount = GetDoc()->GetSdPageCount( PageKind::Standard );
+ OUString aPageStr, aLayoutStr;
+
+ ::sd::Window* pWin = GetActiveWindow();
+ OutlinerView* pActiveView = pOlView->GetViewByWindow( pWin );
+
+ std::vector<Paragraph*> aSelList;
+ pActiveView->CreateSelectionList(aSelList);
+
+ Paragraph *pFirstPara = nullptr;
+ Paragraph *pLastPara = nullptr;
+
+ if (!aSelList.empty())
+ {
+ pFirstPara = *(aSelList.begin());
+ pLastPara = *(aSelList.rbegin());
+ }
+
+ if( !::Outliner::HasParaFlag(pFirstPara,ParaFlag::ISPAGE) )
+ pFirstPara = pOlView->GetPrevTitle( pFirstPara );
+
+ if( !::Outliner::HasParaFlag(pLastPara, ParaFlag::ISPAGE) )
+ pLastPara = pOlView->GetPrevTitle( pLastPara );
+
+ // only one page selected?
+ if( pFirstPara == pLastPara )
+ {
+ // how many pages are we before the selected page?
+ sal_uLong nPos = 0;
+ while( pFirstPara )
+ {
+ pFirstPara = pOlView->GetPrevTitle( pFirstPara );
+ if( pFirstPara )
+ nPos++;
+ }
+
+ if( nPos >= GetDoc()->GetSdPageCount( PageKind::Standard ) )
+ nPos = 0;
+
+ SdrPage* pPage = GetDoc()->GetSdPage( static_cast<sal_uInt16>(nPos), PageKind::Standard );
+
+ aPageStr = SdResId(STR_SD_PAGE_COUNT);
+
+ aPageStr = aPageStr.replaceFirst("%1", OUString::number(static_cast<sal_Int32>(nPos + 1)));
+ aPageStr = aPageStr.replaceFirst("%2", OUString::number(nPageCount));
+
+ aLayoutStr = pPage->GetLayoutName();
+ sal_Int32 nIndex = aLayoutStr.indexOf(SD_LT_SEPARATOR);
+ if (nIndex != -1)
+ aLayoutStr = aLayoutStr.copy(0, nIndex);
+ //Now, CurrentPage property change is already sent for DrawView and OutlineView, so it is not necessary to send again here
+ if(m_StrOldPageName!=aPageStr)
+ {
+ GetViewShellBase().GetDrawController().fireSwitchCurrentPage(nPos);
+ m_StrOldPageName = aPageStr;
+ }
+ }
+ rSet.Put( SfxStringItem( SID_STATUS_PAGE, aPageStr ) );
+ rSet.Put( SfxStringItem( SID_STATUS_LAYOUT, aLayoutStr ) );
+}
+
+void OutlineViewShell::Command( const CommandEvent& rCEvt, ::sd::Window* pWin )
+{
+ if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
+ {
+ GetActiveWindow()->ReleaseMouse();
+
+ OutlinerView* pOLV = pOlView->GetViewByWindow(GetActiveWindow());
+ Point aPos(rCEvt.GetMousePosPixel());
+
+ if (pOLV && pOLV->IsWrongSpelledWordAtPos(aPos))
+ {
+ // Popup for Online-Spelling now handled by DrawDocShell
+ Link<SpellCallbackInfo&,void> aLink = LINK(GetDocSh(), DrawDocShell, OnlineSpellCallback);
+
+ pOLV->ExecuteSpellPopup(aPos, aLink);
+ pOLV->GetEditView().Invalidate();
+ }
+ else
+ {
+ GetViewFrame()->GetDispatcher()->ExecutePopup("outline");
+ }
+ }
+ else
+ {
+ ViewShell::Command( rCEvt, pWin );
+
+ // if necessary communicate the new context to the Preview
+ Invalidate( SID_PREVIEW_STATE );
+
+ }
+}
+
+bool OutlineViewShell::KeyInput(const KeyEvent& rKEvt, ::sd::Window* pWin)
+{
+ bool bReturn = false;
+ OutlineViewPageChangesGuard aGuard(pOlView.get());
+
+ if (pWin == nullptr && HasCurrentFunction())
+ {
+ bReturn = GetCurrentFunction()->KeyInput(rKEvt);
+ }
+
+ // no, forward to base class
+ else
+ {
+ bReturn = ViewShell::KeyInput(rKEvt, pWin);
+ }
+
+ Invalidate(SID_STYLE_EDIT);
+ Invalidate(SID_STYLE_NEW);
+ Invalidate(SID_STYLE_DELETE);
+ Invalidate(SID_STYLE_HIDE);
+ Invalidate(SID_STYLE_SHOW);
+ Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE);
+ Invalidate(SID_STYLE_NEW_BY_EXAMPLE);
+ Invalidate(SID_STYLE_WATERCAN);
+ Invalidate(SID_STYLE_FAMILY5);
+
+ // check and distinguish cursor movements- or input-keys
+ vcl::KeyCode aKeyGroup( rKEvt.GetKeyCode().GetGroup() );
+ if( (aKeyGroup != KEYGROUP_CURSOR && aKeyGroup != KEYGROUP_FKEYS) ||
+ (GetActualPage() != pLastPage) )
+ {
+ Invalidate( SID_PREVIEW_STATE );
+ }
+
+ return bReturn;
+}
+
+/**
+ * Status of Attribute-Items
+ */
+void OutlineViewShell::GetAttrState( SfxItemSet& rSet )
+{
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ SfxAllItemSet aAllSet( *rSet.GetPool() );
+
+ while ( nWhich )
+ {
+ sal_uInt16 nSlotId = SfxItemPool::IsWhich(nWhich)
+ ? GetPool().GetSlotId(nWhich)
+ : nWhich;
+
+ switch ( nSlotId )
+ {
+ case SID_STYLE_FAMILY2:
+ case SID_STYLE_FAMILY3:
+ {
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_STYLE_FAMILY5:
+ {
+ SfxStyleSheet* pStyleSheet = pOlView->GetViewByWindow(GetActiveWindow())->GetStyleSheet();
+
+ if( pStyleSheet )
+ {
+ pStyleSheet = static_cast<SdStyleSheet*>(pStyleSheet)->GetPseudoStyleSheet();
+
+ if (pStyleSheet)
+ {
+ SfxTemplateItem aItem( nWhich, pStyleSheet->GetName() );
+ aAllSet.Put( aItem, aItem.Which() );
+ }
+ }
+
+ if( !pStyleSheet )
+ {
+ SfxTemplateItem aItem( nWhich, OUString() );
+ aAllSet.Put( aItem, aItem.Which() );
+ // rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case SID_STYLE_EDIT:
+ {
+ std::unique_ptr<SfxUInt16Item> pFamilyItem;
+ GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem);
+ if (pFamilyItem && static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Pseudo)
+ {
+ SfxItemSetFixed<SID_STATUS_LAYOUT, SID_STATUS_LAYOUT> aSet(*rSet.GetPool());
+ GetStatusBarState(aSet);
+ OUString aRealStyle = static_cast<const SfxStringItem&>(aSet.Get(SID_STATUS_LAYOUT)).GetValue();
+ if (aRealStyle.isEmpty())
+ {
+ // no unique layout name found
+ rSet.DisableItem(nWhich);
+ }
+ }
+ }
+ break;
+
+ case SID_STYLE_UPDATE_BY_EXAMPLE:
+ {
+ ::sd::Window* pActWin = GetActiveWindow();
+ OutlinerView* pOV = pOlView->GetViewByWindow(pActWin);
+ ESelection aESel(pOV->GetSelection());
+
+ if (aESel.nStartPara != aESel.nEndPara ||
+ aESel.nStartPos != aESel.nEndPos)
+ // spanned selection, i.e. StyleSheet and/or
+ // attribution not necessarily unique
+ rSet.DisableItem(nWhich);
+ }
+ break;
+
+ case SID_STYLE_NEW:
+ case SID_STYLE_DELETE:
+ case SID_STYLE_HIDE:
+ case SID_STYLE_SHOW:
+ case SID_STYLE_NEW_BY_EXAMPLE:
+ case SID_STYLE_WATERCAN:
+ {
+ rSet.DisableItem(nWhich);
+ }
+ break;
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+
+ rSet.Put( aAllSet, false );
+}
+
+void OutlineViewShell::MouseButtonUp(const MouseEvent& rMEvt, ::sd::Window* pWin)
+{
+ // first the base classes
+ ViewShell::MouseButtonUp(rMEvt, pWin);
+
+ Invalidate(SID_STYLE_EDIT);
+ Invalidate(SID_STYLE_NEW);
+ Invalidate(SID_STYLE_DELETE);
+ Invalidate(SID_STYLE_HIDE);
+ Invalidate(SID_STYLE_SHOW);
+ Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE);
+ Invalidate(SID_STYLE_NEW_BY_EXAMPLE);
+ Invalidate(SID_STYLE_WATERCAN);
+ Invalidate(SID_STYLE_FAMILY5);
+
+ // if necessary communicate the new context to the Preview
+ if( GetActualPage() != pLastPage )
+ Invalidate( SID_PREVIEW_STATE );
+}
+
+SdPage* OutlineViewShell::getCurrentPage() const
+{
+ // since there are no master pages in outline view, we can
+ // for now use the GetActualPage method
+ return const_cast<OutlineViewShell*>(this)->GetActualPage();
+}
+
+/**
+ * Returns the first selected page.
+ * If nothing is selected, the first page is returned.
+ */
+SdPage* OutlineViewShell::GetActualPage()
+{
+ return pOlView->GetActualPage();
+}
+
+void OutlineViewShell::UpdatePreview( SdPage* pPage )
+{
+ const bool bNewPage = pPage != pLastPage;
+ pLastPage = pPage;
+ if (bNewPage)
+ {
+ OutlineViewPageChangesGuard aGuard(pOlView.get());
+ SetCurrentPage(pPage);
+ }
+}
+
+void OutlineViewShell::UpdateTitleObject( SdPage* pPage, Paragraph const * pPara )
+{
+ DBG_ASSERT( pPage, "sd::OutlineViewShell::UpdateTitleObject(), pPage == 0?" );
+ DBG_ASSERT( pPara, "sd::OutlineViewShell::UpdateTitleObject(), pPara == 0?" );
+
+ if( !pPage || !pPara )
+ return;
+
+ ::Outliner& rOutliner = pOlView->GetOutliner();
+ SdrTextObj* pTO = OutlineView::GetTitleTextObject( pPage );
+
+ OUString aTest = rOutliner.GetText(pPara);
+ bool bText = !aTest.isEmpty();
+
+ if( bText )
+ {
+ bool bNewObject = false;
+ // create a title object if we don't have one but have text
+ if( !pTO )
+ {
+ DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateTitleObject(), no undo for model change!?" );
+ pTO = OutlineView::CreateTitleTextObject(pPage);
+ bNewObject = true;
+ }
+
+ // if we have a title object and a text, set the text
+ std::optional<OutlinerParaObject> pOPO;
+ if (pTO)
+ pOPO = rOutliner.CreateParaObject(rOutliner.GetAbsPos(pPara), 1);
+ if (pOPO)
+ {
+ pOPO->SetOutlinerMode( OutlinerMode::TitleObject );
+ assert(pTO);
+ pOPO->SetVertical( pTO->IsVerticalWriting() );
+ if( pTO->GetOutlinerParaObject() && (pOPO->GetTextObject() == pTO->GetOutlinerParaObject()->GetTextObject()) )
+ {
+ // do nothing, same text already set
+ }
+ else
+ {
+ DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateTitleObject(), no undo for model change!?" );
+ if( !bNewObject && pOlView->isRecordingUndo() )
+ pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoObjectSetText(*pTO,0));
+
+ pTO->SetOutlinerParaObject( std::move(pOPO) );
+ pTO->SetEmptyPresObj( false );
+ pTO->ActionChanged();
+ }
+ }
+ }
+ else if( pTO )
+ {
+ // no text but object available?
+ // outline object available, but we have no text
+ if(pPage->IsPresObj(pTO))
+ {
+ // if it is not already empty
+ if( !pTO->IsEmptyPresObj() )
+ {
+ DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateTitleObject(), no undo for model change!?" );
+
+ // make it empty
+ if( pOlView->isRecordingUndo() )
+ pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoObjectSetText(*pTO,0));
+ pPage->RestoreDefaultText( pTO );
+ pTO->SetEmptyPresObj(true);
+ pTO->ActionChanged();
+ }
+ }
+ else
+ {
+ DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateTitleObject(), no undo for model change!?" );
+ // outline object is not part of the layout, delete it
+ if( pOlView->isRecordingUndo() )
+ pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoRemoveObject(*pTO));
+ pPage->RemoveObject(pTO->GetOrdNum());
+ }
+ }
+}
+
+void OutlineViewShell::UpdateOutlineObject( SdPage* pPage, Paragraph* pPara )
+{
+ DBG_ASSERT( pPage, "sd::OutlineViewShell::UpdateOutlineObject(), pPage == 0?" );
+ DBG_ASSERT( pPara, "sd::OutlineViewShell::UpdateOutlineObject(), pPara == 0?" );
+
+ if( !pPage || !pPara )
+ return;
+
+ ::Outliner& rOutliner = pOlView->GetOutliner();
+ std::optional<OutlinerParaObject> pOPO;
+ SdrTextObj* pTO = nullptr;
+
+ OutlinerMode eOutlinerMode = OutlinerMode::TitleObject;
+ pTO = static_cast<SdrTextObj*>(pPage->GetPresObj( PresObjKind::Text ));
+ if( !pTO )
+ {
+ eOutlinerMode = OutlinerMode::OutlineObject;
+ pTO = OutlineView::GetOutlineTextObject( pPage );
+ }
+
+ // how many paragraphs in the outline?
+ sal_Int32 nTitlePara = rOutliner.GetAbsPos( pPara );
+ sal_Int32 nPara = nTitlePara + 1;
+ sal_Int32 nParasInLayout = 0;
+ pPara = rOutliner.GetParagraph( nPara );
+ while( pPara && !::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) )
+ {
+ nParasInLayout++;
+ pPara = rOutliner.GetParagraph( ++nPara );
+ }
+ if( nParasInLayout )
+ {
+ // create an OutlinerParaObject
+ pOPO = rOutliner.CreateParaObject( nTitlePara + 1, nParasInLayout );
+ }
+
+ if( pOPO )
+ {
+ DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateOutlineObject(), no undo for model change!?" );
+ bool bNewObject = false;
+
+ // do we need an outline text object?
+ if( !pTO )
+ {
+ pTO = OutlineView::CreateOutlineTextObject( pPage );
+ bNewObject = true;
+ }
+
+ // page object, outline text in Outliner:
+ // apply text
+ if( pTO )
+ {
+ pOPO->SetVertical( pTO->IsVerticalWriting() );
+ pOPO->SetOutlinerMode( eOutlinerMode );
+ if( pTO->GetOutlinerParaObject() && (pOPO->GetTextObject() == pTO->GetOutlinerParaObject()->GetTextObject()) )
+ {
+ // do nothing, same text already set
+ }
+ else
+ {
+ if( !bNewObject && pOlView->isRecordingUndo() )
+ pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoObjectSetText(*pTO,0));
+
+ pTO->SetOutlinerParaObject( std::move(pOPO) );
+ pTO->SetEmptyPresObj( false );
+ pTO->ActionChanged();
+ }
+ }
+ }
+ else if( pTO )
+ {
+ // page object but no outline text:
+ // if the object is in the outline of the page -> default text
+
+ // otherwise delete object
+ if( pPage->IsPresObj(pTO) )
+ {
+ if( !pTO->IsEmptyPresObj() )
+ {
+ DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateOutlineObject(), no undo for model change!?" );
+
+ // delete old OutlinerParaObject, too
+ if( pOlView->isRecordingUndo() )
+ pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoObjectSetText(*pTO,0));
+ pPage->RestoreDefaultText( pTO );
+ pTO->SetEmptyPresObj(true);
+ pTO->ActionChanged();
+ }
+ }
+ else
+ {
+ DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateOutlineObject(), no undo for model change!?" );
+ if( pOlView->isRecordingUndo() )
+ pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoRemoveObject(*pTO));
+ pPage->RemoveObject(pTO->GetOrdNum());
+ }
+ }
+}
+
+/**
+ * Fill Outliner from Stream
+ */
+ErrCode OutlineViewShell::ReadRtf(SvStream& rInput)
+{
+ ErrCode bRet = ERRCODE_NONE;
+
+ ::Outliner& rOutl = pOlView->GetOutliner();
+
+ OutlineViewPageChangesGuard aGuard( pOlView.get() );
+ OutlineViewModelChangeGuard aGuard2( *pOlView );
+
+ bRet = rOutl.Read( rInput, OUString(), EETextFormat::Rtf, GetDocSh()->GetHeaderAttributes() );
+
+ SdPage* pPage = GetDoc()->GetSdPage( GetDoc()->GetSdPageCount(PageKind::Standard) - 1, PageKind::Standard );
+ SfxStyleSheet* pTitleSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Title );
+ SfxStyleSheet* pOutlSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Outline );
+
+ sal_Int32 nParaCount = rOutl.GetParagraphCount();
+ if ( nParaCount > 0 )
+ {
+ for ( sal_Int32 nPara = 0; nPara < nParaCount; nPara++ )
+ {
+ pOlView->UpdateParagraph( nPara );
+
+ sal_Int16 nDepth = rOutl.GetDepth( nPara );
+
+ if( (nDepth == 0) || !nPara )
+ {
+ Paragraph* pPara = rOutl.GetParagraph( nPara );
+ rOutl.SetDepth(pPara, -1);
+ rOutl.SetParaFlag(pPara, ParaFlag::ISPAGE);
+
+ rOutl.SetStyleSheet( nPara, pTitleSheet );
+
+ if( nPara ) // first slide already exists
+ pOlView->InsertSlideForParagraph( pPara );
+ }
+ else
+ {
+ rOutl.SetDepth( rOutl.GetParagraph( nPara ), nDepth - 1 );
+ OUString aStyleSheetName = pOutlSheet->GetName();
+ if (!aStyleSheetName.isEmpty())
+ aStyleSheetName = aStyleSheetName.copy(0, aStyleSheetName.getLength() - 1);
+ aStyleSheetName += OUString::number( nDepth );
+ SfxStyleSheetBasePool* pStylePool = GetDoc()->GetStyleSheetPool();
+ SfxStyleSheet* pStyle = static_cast<SfxStyleSheet*>( pStylePool->Find( aStyleSheetName, pOutlSheet->GetFamily() ) );
+ DBG_ASSERT( pStyle, "AutoStyleSheetName - Style not found!" );
+ if ( pStyle )
+ rOutl.SetStyleSheet( nPara, pStyle );
+ }
+ }
+ }
+
+ rOutl.GetUndoManager().Clear();
+
+ return bRet;
+}
+
+void OutlineViewShell::WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& rSequence )
+{
+ WriteFrameViewData();
+
+ ViewShell::WriteUserDataSequence( rSequence );
+}
+
+void OutlineViewShell::ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& rSequence )
+{
+ WriteFrameViewData();
+
+ ViewShell::ReadUserDataSequence( rSequence );
+
+ ReadFrameViewData( mpFrameView );
+}
+
+void OutlineViewShell::VisAreaChanged(const ::tools::Rectangle& rRect)
+{
+ ViewShell::VisAreaChanged( rRect );
+
+ GetViewShellBase().GetDrawController().FireVisAreaChanged(rRect);
+}
+
+/** If there is a valid controller then create a new instance of
+ <type>AccessibleDrawDocumentView</type>. Otherwise return an empty
+ reference.
+*/
+css::uno::Reference<css::accessibility::XAccessible>
+ OutlineViewShell::CreateAccessibleDocumentView (::sd::Window* pWindow)
+{
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ if (GetViewShell()->GetController() != nullptr)
+ {
+ rtl::Reference<::accessibility::AccessibleOutlineView> pDocumentView =
+ new ::accessibility::AccessibleOutlineView (
+ pWindow,
+ this,
+ GetViewShell()->GetController(),
+ pWindow->GetAccessibleParentWindow()->GetAccessible());
+ pDocumentView->Init();
+ return pDocumentView;
+ }
+
+ SAL_WARN("sd", "OutlineViewShell::CreateAccessibleDocumentView: no controller");
+ return css::uno::Reference< css::accessibility::XAccessible >();
+}
+
+void OutlineViewShell::GetState (SfxItemSet& rSet)
+{
+ // Iterate over all requested items in the set.
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ switch (nWhich)
+ {
+ case SID_SEARCH_ITEM:
+ case SID_SEARCH_OPTIONS:
+ // Call common (old) implementation in the document shell.
+ GetDocSh()->GetState (rSet);
+ break;
+ default:
+ SAL_WARN("sd", "OutlineViewShell::GetState(): can not handle which id " << nWhich);
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void OutlineViewShell::SetCurrentPage (SdPage* pPage)
+{
+ // Adapt the selection of the model.
+ for (sal_uInt16 i=0; i<GetDoc()->GetSdPageCount(PageKind::Standard); i++)
+ GetDoc()->SetSelected(
+ GetDoc()->GetSdPage(i, PageKind::Standard),
+ false);
+ GetDoc()->SetSelected (pPage, true);
+
+ DrawController& rController(GetViewShellBase().GetDrawController());
+ rController.FireSelectionChangeListener();
+ rController.FireSwitchCurrentPage (pPage);
+
+ pOlView->SetActualPage(pPage);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/outlview.cxx b/sd/source/ui/view/outlview.cxx
new file mode 100644
index 000000000..c3b7a57ca
--- /dev/null
+++ b/sd/source/ui/view/outlview.cxx
@@ -0,0 +1,1720 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <OutlineView.hxx>
+#include <sfx2/progress.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/outliner.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/lrspitem.hxx>
+#include <svx/svdotext.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/style.hxx>
+#include <svx/svdundo.hxx>
+#include <editeng/numitem.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editeng.hxx>
+#include <xmloff/autolayout.hxx>
+#include <tools/debug.hxx>
+
+#include <editeng/editobj.hxx>
+#include <editeng/editund2.hxx>
+
+#include <editeng/editview.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+
+#include <DrawDocShell.hxx>
+#include <drawdoc.hxx>
+#include <Window.hxx>
+#include <sdpage.hxx>
+#include <pres.hxx>
+#include <OutlineViewShell.hxx>
+#include <app.hrc>
+#include <strings.hrc>
+#include <sdmod.hxx>
+#include <sdresid.hxx>
+#include <Outliner.hxx>
+#include <EventMultiplexer.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <undo/undomanager.hxx>
+#include <stlsheet.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+
+namespace sd {
+
+// a progress bar gets displayed when more than
+// PROCESS_WITH_PROGRESS_THRESHOLD pages are concerned
+#define PROCESS_WITH_PROGRESS_THRESHOLD 5
+
+OutlineView::OutlineView( DrawDocShell& rDocSh, vcl::Window* pWindow, OutlineViewShell& rOutlineViewShell)
+: ::sd::View(*rDocSh.GetDoc(), pWindow->GetOutDev(), &rOutlineViewShell)
+, mrOutlineViewShell(rOutlineViewShell)
+, mrOutliner(*mrDoc.GetOutliner())
+, mnPagesToProcess(0)
+, mnPagesProcessed(0)
+, mbFirstPaint(true)
+, maDocColor( COL_WHITE )
+, maLRSpaceItem( 0, 0, 2000, 0, EE_PARA_OUTLLRSPACE )
+{
+ bool bInitOutliner = false;
+
+ if (mrOutliner.GetViewCount() == 0)
+ {
+ // initialize Outliner: set Reference Device
+ bInitOutliner = true;
+ mrOutliner.Init( OutlinerMode::OutlineView );
+ mrOutliner.SetRefDevice( SD_MOD()->GetVirtualRefDevice() );
+ //viewsize without the width of the image and number in front
+ mnPaperWidth = (mrOutlineViewShell.GetActiveWindow()->GetViewSize().Width() - 4000);
+ mrOutliner.SetPaperSize(Size(mnPaperWidth, 400000000));
+ }
+ else
+ {
+ // width: DIN A4, two margins at 1 cm each
+ mnPaperWidth = 19000;
+ }
+
+ mpOutlinerViews[0].reset( new OutlinerView(&mrOutliner, pWindow) );
+ mpOutlinerViews[0]->SetOutputArea(::tools::Rectangle());
+ mrOutliner.SetUpdateLayout(false);
+ mrOutliner.InsertView(mpOutlinerViews[0].get(), EE_APPEND);
+
+ onUpdateStyleSettings( true );
+
+ if (bInitOutliner)
+ {
+ // fill Outliner with contents
+ FillOutliner();
+ }
+
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,OutlineView,EventMultiplexerListener) );
+ mrOutlineViewShell.GetViewShellBase().GetEventMultiplexer()->AddEventListener(aLink);
+
+ Reference<XFrame> xFrame = mrOutlineViewShell.GetViewShellBase().GetFrame()->GetFrame().GetFrameInterface();
+ maSlideImage = vcl::CommandInfoProvider::GetImageForCommand(".uno:ShowSlide", xFrame, vcl::ImageType::Size26);
+
+ // Tell undo manager of the document about the undo manager of the
+ // outliner, so that the former can synchronize with the later.
+ sd::UndoManager* pDocUndoMgr = dynamic_cast<sd::UndoManager*>(mpDocSh->GetUndoManager());
+ if (pDocUndoMgr != nullptr)
+ pDocUndoMgr->SetLinkedUndoManager(&mrOutliner.GetUndoManager());
+}
+
+/**
+ * Destructor, restore Links, clear Outliner
+ */
+OutlineView::~OutlineView()
+{
+ DBG_ASSERT(maDragAndDropModelGuard == nullptr,
+ "sd::OutlineView::~OutlineView(), prior drag operation not finished correctly!");
+
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,OutlineView,EventMultiplexerListener) );
+ mrOutlineViewShell.GetViewShellBase().GetEventMultiplexer()->RemoveEventListener( aLink );
+ DisconnectFromApplication();
+
+ mpProgress.reset();
+
+ // unregister OutlinerViews and destroy them
+ for (auto & rpView : mpOutlinerViews)
+ {
+ if (rpView)
+ {
+ mrOutliner.RemoveView( rpView.get() );
+ rpView.reset();
+ }
+ }
+
+ if (mrOutliner.GetViewCount() == 0)
+ {
+ // uninitialize Outliner: enable color display
+ ResetLinks();
+ EEControlBits nCntrl = mrOutliner.GetControlWord();
+ mrOutliner.SetUpdateLayout(false); // otherwise there will be drawn on SetControlWord
+ mrOutliner.SetControlWord(nCntrl & ~EEControlBits::NOCOLORS);
+ SvtAccessibilityOptions aOptions;
+ mrOutliner.ForceAutoColor( aOptions.GetIsAutomaticFontColor() );
+ mrOutliner.Clear();
+ }
+}
+
+void OutlineView::ConnectToApplication()
+{
+ // When the mode is switched to outline the main view shell grabs focus.
+ // This is done for getting cut/copy/paste commands on slides in the left
+ // pane (slide sorter view shell) to work properly.
+ SfxShell* pTopViewShell = mrOutlineViewShell.GetViewShellBase().GetViewShellManager()->GetTopViewShell();
+ if (pTopViewShell && pTopViewShell == &mrOutlineViewShell)
+ {
+ mrOutlineViewShell.GetActiveWindow()->GrabFocus();
+ }
+
+ Application::AddEventListener(LINK(this, OutlineView, AppEventListenerHdl));
+}
+
+void OutlineView::DisconnectFromApplication()
+{
+ Application::RemoveEventListener(LINK(this, OutlineView, AppEventListenerHdl));
+}
+
+void OutlineView::Paint(const ::tools::Rectangle& rRect, ::sd::Window const * pWin)
+{
+ OutlinerView* pOlView = GetViewByWindow(pWin);
+
+ if (pOlView)
+ {
+ pOlView->HideCursor();
+ pOlView->Paint(rRect);
+
+ pOlView->ShowCursor(mbFirstPaint);
+
+ mbFirstPaint = false;
+ }
+}
+
+void OutlineView::AddWindowToPaintView(OutputDevice* pWin, vcl::Window* pWindow)
+{
+ bool bAdded = false;
+ bool bValidArea = false;
+ ::tools::Rectangle aOutputArea;
+ const Color aWhiteColor( COL_WHITE );
+ sal_uInt16 nView = 0;
+
+ while (nView < MAX_OUTLINERVIEWS && !bAdded)
+ {
+ if (mpOutlinerViews[nView] == nullptr)
+ {
+ mpOutlinerViews[nView].reset( new OutlinerView(&mrOutliner, dynamic_cast< ::sd::Window* >(pWin->GetOwnerWindow())) );
+ mpOutlinerViews[nView]->SetBackgroundColor( aWhiteColor );
+ mrOutliner.InsertView(mpOutlinerViews[nView].get(), EE_APPEND);
+ bAdded = true;
+
+ if (bValidArea)
+ {
+ mpOutlinerViews[nView]->SetOutputArea(aOutputArea);
+ }
+ }
+ else if (!bValidArea)
+ {
+ aOutputArea = mpOutlinerViews[nView]->GetOutputArea();
+ bValidArea = true;
+ }
+
+ nView++;
+ }
+
+ // white background in Outliner
+ pWin->SetBackground( Wallpaper( aWhiteColor ) );
+
+ ::sd::View::AddWindowToPaintView(pWin, pWindow);
+}
+
+void OutlineView::DeleteWindowFromPaintView(OutputDevice* pWin)
+{
+ bool bRemoved = false;
+ sal_uInt16 nView = 0;
+ vcl::Window* pWindow;
+
+ while (nView < MAX_OUTLINERVIEWS && !bRemoved)
+ {
+ if (mpOutlinerViews[nView] != nullptr)
+ {
+ pWindow = mpOutlinerViews[nView]->GetWindow();
+
+ if (pWindow->GetOutDev() == pWin)
+ {
+ mrOutliner.RemoveView( mpOutlinerViews[nView].get() );
+ mpOutlinerViews[nView].reset();
+ bRemoved = true;
+ }
+ }
+
+ nView++;
+ }
+
+ ::sd::View::DeleteWindowFromPaintView(pWin);
+}
+
+/**
+ * Return a pointer to the OutlinerView corresponding to the window
+ */
+OutlinerView* OutlineView::GetViewByWindow (vcl::Window const * pWin) const
+{
+ OutlinerView* pOlView = nullptr;
+ for (std::unique_ptr<OutlinerView> const & pView : mpOutlinerViews)
+ {
+ if (pView != nullptr)
+ {
+ if ( pWin == pView->GetWindow() )
+ {
+ pOlView = pView.get();
+ }
+ }
+ }
+ return pOlView;
+}
+
+/**
+ * Return the title before a random paragraph
+ */
+Paragraph* OutlineView::GetPrevTitle(const Paragraph* pPara)
+{
+ sal_Int32 nPos = mrOutliner.GetAbsPos(pPara);
+
+ if (nPos > 0)
+ {
+ while(nPos)
+ {
+ pPara = mrOutliner.GetParagraph(--nPos);
+ if( ::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) )
+ {
+ return const_cast< Paragraph* >( pPara );
+ }
+ }
+
+ }
+ return nullptr;
+}
+
+/**
+ * Return the title after a random paragraph
+ */
+Paragraph* OutlineView::GetNextTitle(const Paragraph* pPara)
+{
+ Paragraph* pResult = const_cast< Paragraph* >( pPara );
+
+ sal_Int32 nPos = mrOutliner.GetAbsPos(pResult);
+
+ do
+ {
+ pResult = mrOutliner.GetParagraph(++nPos);
+ if( pResult && ::Outliner::HasParaFlag(pResult, ParaFlag::ISPAGE) )
+ return pResult;
+ }
+ while( pResult );
+
+ return nullptr;
+}
+
+/**
+ * Handler for inserting pages (paragraphs)
+ */
+IMPL_LINK( OutlineView, ParagraphInsertedHdl, Outliner::ParagraphHdlParam, aParam, void )
+{
+ // we get calls to this handler during binary insert of drag and drop contents but
+ // we ignore it here and handle it later in OnEndPasteOrDrop()
+ if (maDragAndDropModelGuard != nullptr)
+ return;
+
+ OutlineViewPageChangesGuard aGuard(this);
+
+ sal_Int32 nAbsPos = mrOutliner.GetAbsPos( aParam.pPara );
+
+ UpdateParagraph( nAbsPos );
+
+ if( (nAbsPos == 0) ||
+ ::Outliner::HasParaFlag(aParam.pPara, ParaFlag::ISPAGE) ||
+ ::Outliner::HasParaFlag(mrOutliner.GetParagraph( nAbsPos-1 ), ParaFlag::ISPAGE) )
+ {
+ InsertSlideForParagraph( aParam.pPara );
+ }
+}
+
+/** creates and inserts an empty slide for the given paragraph */
+SdPage* OutlineView::InsertSlideForParagraph( Paragraph* pPara )
+{
+ DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::InsertSlideForParagraph(), model change without undo?!" );
+
+ OutlineViewPageChangesGuard aGuard(this);
+
+ mrOutliner.SetParaFlag( pPara, ParaFlag::ISPAGE );
+ // how many titles are there before the new title paragraph?
+ sal_uLong nExample = 0; // position of the "example" page
+ sal_uLong nTarget = 0; // position of insertion
+ while(pPara)
+ {
+ pPara = GetPrevTitle(pPara);
+ if (pPara)
+ nTarget++;
+ }
+
+ // if a new paragraph is created via RETURN before the first paragraph, the
+ // Outliner reports the old paragraph (which was moved down) as a new
+ // paragraph
+ if (nTarget == 1)
+ {
+ OUString aTest = mrOutliner.GetText(mrOutliner.GetParagraph(0));
+ if (aTest.isEmpty())
+ {
+ nTarget = 0;
+ }
+ }
+
+ // the "example" page is the previous page - if it is available
+ if (nTarget > 0)
+ {
+ nExample = nTarget - 1;
+
+ sal_uInt16 nPageCount = mrDoc.GetSdPageCount( PageKind::Standard );
+ if( nExample >= nPageCount )
+ nExample = nPageCount - 1;
+ }
+
+ /**********************************************************************
+ * All the time, a standard page is created before a notes page.
+ * It is ensured that after each standard page the corresponding notes page
+ * follows. A handout page is exactly one handout page.
+ **********************************************************************/
+
+ // this page is exemplary
+ SdPage* pExample = mrDoc.GetSdPage(static_cast<sal_uInt16>(nExample), PageKind::Standard);
+ rtl::Reference<SdPage> pPage = mrDoc.AllocSdPage(false);
+
+ pPage->SetLayoutName(pExample->GetLayoutName());
+
+ // insert (page)
+ mrDoc.InsertPage(pPage.get(), static_cast<sal_uInt16>(nTarget) * 2 + 1);
+ if( isRecordingUndo() )
+ AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoNewPage(*pPage));
+
+ // assign a master page to the standard page
+ pPage->TRG_SetMasterPage(pExample->TRG_GetMasterPage());
+
+ // set page size
+ pPage->SetSize(pExample->GetSize());
+ pPage->SetBorder( pExample->GetLeftBorder(),
+ pExample->GetUpperBorder(),
+ pExample->GetRightBorder(),
+ pExample->GetLowerBorder() );
+
+ // create new presentation objects (after <Title> or <Title with subtitle>
+ // follows <Title with outline>, otherwise apply the layout of the previous
+ // page
+ AutoLayout eAutoLayout = pExample->GetAutoLayout();
+ if (eAutoLayout == AUTOLAYOUT_TITLE ||
+ eAutoLayout == AUTOLAYOUT_TITLE_ONLY)
+ {
+ pPage->SetAutoLayout(AUTOLAYOUT_TITLE_CONTENT, true);
+ }
+ else
+ {
+ pPage->SetAutoLayout(pExample->GetAutoLayout(), true);
+ }
+
+ /**********************************************************************
+ |* now the notes page
+ \*********************************************************************/
+ pExample = mrDoc.GetSdPage(static_cast<sal_uInt16>(nExample), PageKind::Notes);
+ rtl::Reference<SdPage> pNotesPage = mrDoc.AllocSdPage(false);
+
+ pNotesPage->SetLayoutName(pExample->GetLayoutName());
+
+ pNotesPage->SetPageKind(PageKind::Notes);
+
+ // insert (notes page)
+ mrDoc.InsertPage(pNotesPage.get(), static_cast<sal_uInt16>(nTarget) * 2 + 2);
+ if( isRecordingUndo() )
+ AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoNewPage(*pNotesPage));
+
+ // assign a master page to the notes page
+ pNotesPage->TRG_SetMasterPage(pExample->TRG_GetMasterPage());
+
+ // set page size, there must be already one page available
+ pNotesPage->SetSize(pExample->GetSize());
+ pNotesPage->SetBorder( pExample->GetLeftBorder(),
+ pExample->GetUpperBorder(),
+ pExample->GetRightBorder(),
+ pExample->GetLowerBorder() );
+
+ // create presentation objects
+ pNotesPage->SetAutoLayout(pExample->GetAutoLayout(), true);
+
+ mrOutliner.UpdateFields();
+
+ return pPage.get();
+}
+
+/**
+ * Handler for deleting pages (paragraphs)
+ */
+IMPL_LINK( OutlineView, ParagraphRemovingHdl, ::Outliner::ParagraphHdlParam, aParam, void )
+{
+ DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::ParagraphRemovingHdl(), model change without undo?!" );
+
+ OutlineViewPageChangesGuard aGuard(this);
+
+ Paragraph* pPara = aParam.pPara;
+ if( !::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) )
+ return;
+
+ // how many titles are in front of the title paragraph in question?
+ sal_uLong nPos = 0;
+ while(pPara)
+ {
+ pPara = GetPrevTitle(pPara);
+ if (pPara) nPos++;
+ }
+
+ // delete page and notes page
+ sal_uInt16 nAbsPos = static_cast<sal_uInt16>(nPos) * 2 + 1;
+ SdrPage* pPage = mrDoc.GetPage(nAbsPos);
+ if( isRecordingUndo() )
+ AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
+ mrDoc.RemovePage(nAbsPos);
+
+ nAbsPos = static_cast<sal_uInt16>(nPos) * 2 + 1;
+ pPage = mrDoc.GetPage(nAbsPos);
+ if( isRecordingUndo() )
+ AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
+ mrDoc.RemovePage(nAbsPos);
+
+ // progress display if necessary
+ if (mnPagesToProcess)
+ {
+ mnPagesProcessed++;
+
+ if(mpProgress)
+ mpProgress->SetState(mnPagesProcessed);
+
+ if (mnPagesProcessed == mnPagesToProcess)
+ {
+ mpProgress.reset();
+ mnPagesToProcess = 0;
+ mnPagesProcessed = 0;
+ }
+ }
+ aParam.pOutliner->UpdateFields();
+}
+
+/**
+ * Handler for changing the indentation depth of paragraphs (requires inserting
+ * or deleting of pages in some cases)
+ */
+IMPL_LINK( OutlineView, DepthChangedHdl, ::Outliner::DepthChangeHdlParam, aParam, void )
+{
+ DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::DepthChangedHdl(), no undo for model change?!" );
+
+ OutlineViewPageChangesGuard aGuard(this);
+
+ Paragraph* pPara = aParam.pPara;
+ ::Outliner* pOutliner = aParam.pOutliner;
+ if( ::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) && ((aParam.nPrevFlags & ParaFlag::ISPAGE) == ParaFlag::NONE) )
+ {
+ // the current paragraph is transformed into a slide
+
+ mrOutliner.SetDepth( pPara, -1 );
+
+ // are multiple level 1 paragraphs being brought to level 0 and we
+ // should start a progress view or a timer and didn't already?
+ if (mnPagesToProcess == 0)
+ {
+ Window* pActWin = mrOutlineViewShell.GetActiveWindow();
+ OutlinerView* pOlView = GetViewByWindow(pActWin);
+
+ std::vector<Paragraph*> aSelList;
+ pOlView->CreateSelectionList(aSelList);
+
+ mnPagesToProcess = std::count_if(aSelList.begin(), aSelList.end(),
+ [&pOutliner](const Paragraph *pParagraph) {
+ return !Outliner::HasParaFlag(pParagraph, ParaFlag::ISPAGE) &&
+ (pOutliner->GetDepth(pOutliner->GetAbsPos(pParagraph)) <= 0);
+ });
+
+ mnPagesToProcess++; // the paragraph being in level 0 already
+ // should be included
+ mnPagesProcessed = 0;
+
+ if (mnPagesToProcess > PROCESS_WITH_PROGRESS_THRESHOLD)
+ {
+ mpProgress.reset( new SfxProgress( GetDocSh(), SdResId(STR_CREATE_PAGES), mnPagesToProcess ) );
+ }
+ else
+ {
+ mpDocSh->SetWaitCursor( true );
+ }
+ }
+
+ ParagraphInsertedHdl( { aParam.pOutliner, aParam.pPara } );
+
+ mnPagesProcessed++;
+
+ // should there be a progress display?
+ if (mnPagesToProcess > PROCESS_WITH_PROGRESS_THRESHOLD)
+ {
+ if (mpProgress)
+ mpProgress->SetState(mnPagesProcessed);
+ }
+
+ // was this the last page?
+ if (mnPagesProcessed == mnPagesToProcess)
+ {
+ if (mnPagesToProcess > PROCESS_WITH_PROGRESS_THRESHOLD && mpProgress)
+ {
+ mpProgress.reset();
+ }
+ else
+ mpDocSh->SetWaitCursor( false );
+
+ mnPagesToProcess = 0;
+ mnPagesProcessed = 0;
+ }
+ pOutliner->UpdateFields();
+ }
+ else if( !::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) && ((aParam.nPrevFlags & ParaFlag::ISPAGE) != ParaFlag::NONE) )
+ {
+ // the paragraph was a page but now becomes a normal paragraph
+
+ // how many titles are before the title paragraph in question?
+ sal_uLong nPos = 0;
+ Paragraph* pParagraph = pPara;
+ while(pParagraph)
+ {
+ pParagraph = GetPrevTitle(pParagraph);
+ if (pParagraph)
+ nPos++;
+ }
+ // delete page and notes page
+
+ sal_uInt16 nAbsPos = static_cast<sal_uInt16>(nPos) * 2 + 1;
+ SdrPage* pPage = mrDoc.GetPage(nAbsPos);
+ if( isRecordingUndo() )
+ AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
+ mrDoc.RemovePage(nAbsPos);
+
+ nAbsPos = static_cast<sal_uInt16>(nPos) * 2 + 1;
+ pPage = mrDoc.GetPage(nAbsPos);
+ if( isRecordingUndo() )
+ AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
+ mrDoc.RemovePage(nAbsPos);
+
+ pPage = GetPageForParagraph( pPara );
+
+ mrOutliner.SetDepth( pPara, (pPage && (static_cast<SdPage*>(pPage)->GetAutoLayout() == AUTOLAYOUT_TITLE)) ? -1 : 0 );
+
+ // progress display if necessary
+ if (mnPagesToProcess)
+ {
+ mnPagesProcessed++;
+ if (mpProgress)
+ mpProgress->SetState(mnPagesProcessed);
+
+ if (mnPagesProcessed == mnPagesToProcess)
+ {
+ mpProgress.reset();
+ mnPagesToProcess = 0;
+ mnPagesProcessed = 0;
+ }
+ }
+ pOutliner->UpdateFields();
+ }
+ else if ( (pOutliner->GetPrevDepth() == 1) && ( pOutliner->GetDepth( pOutliner->GetAbsPos( pPara ) ) == 2 ) )
+ {
+ // how many titles are in front of the title paragraph in question?
+ sal_Int32 nPos = -1;
+
+ Paragraph* pParagraph = pPara;
+ while(pParagraph)
+ {
+ pParagraph = GetPrevTitle(pParagraph);
+ if (pParagraph)
+ nPos++;
+ }
+
+ if(nPos >= 0)
+ {
+ SdPage*pPage = mrDoc.GetSdPage( static_cast<sal_uInt16>(nPos), PageKind::Standard);
+
+ if(pPage && pPage->GetPresObj(PresObjKind::Text))
+ pOutliner->SetDepth( pPara, 0 );
+ }
+
+ }
+ // how many titles are in front of the title paragraph in question?
+ sal_Int32 nPos = -1;
+
+ Paragraph* pTempPara = pPara;
+ while(pTempPara)
+ {
+ pTempPara = GetPrevTitle(pTempPara);
+ if (pTempPara)
+ nPos++;
+ }
+
+ if( nPos < 0 )
+ return;
+
+ SdPage* pPage = mrDoc.GetSdPage( static_cast<sal_uInt16>(nPos), PageKind::Standard );
+
+ if( !pPage )
+ return;
+
+ SfxStyleSheet* pStyleSheet = nullptr;
+ sal_Int32 nPara = pOutliner->GetAbsPos( pPara );
+ sal_Int16 nDepth = pOutliner->GetDepth( nPara );
+ bool bSubTitle = pPage->GetPresObj(PresObjKind::Text) != nullptr;
+
+ if( ::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) )
+ {
+ pStyleSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Title );
+ }
+ else if( bSubTitle )
+ {
+ pStyleSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Text );
+ }
+ else
+ {
+ pStyleSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Outline );
+
+ if( nDepth > 0 )
+ {
+ OUString aNewStyleSheetName = pStyleSheet->GetName();
+ if (!aNewStyleSheetName.isEmpty())
+ aNewStyleSheetName = aNewStyleSheetName.copy(0, aNewStyleSheetName.getLength() - 1);
+ aNewStyleSheetName += OUString::number( nDepth+1 );
+ SfxStyleSheetBasePool* pStylePool = mrDoc.GetStyleSheetPool();
+ pStyleSheet = static_cast<SfxStyleSheet*>( pStylePool->Find( aNewStyleSheetName, pStyleSheet->GetFamily() ) );
+ }
+ }
+
+ // before we set the style sheet we need to preserve the bullet item
+ // since all items will be deleted while setting a new style sheet
+ SfxItemSet aOldAttrs( pOutliner->GetParaAttribs( nPara ) );
+
+ pOutliner->SetStyleSheet( nPara, pStyleSheet );
+
+ // restore the old bullet item but not if the style changed
+ if ( pOutliner->GetPrevDepth() != -1 && nDepth != -1 &&
+ aOldAttrs.GetItemState( EE_PARA_NUMBULLET ) == SfxItemState::SET )
+ {
+ SfxItemSet aAttrs( pOutliner->GetParaAttribs( nPara ) );
+ aAttrs.Put( *aOldAttrs.GetItem( EE_PARA_NUMBULLET ) );
+ pOutliner->SetParaAttribs( nPara, aAttrs );
+ }
+}
+
+/**
+ * Handler for StatusEvents
+ */
+IMPL_LINK_NOARG(OutlineView, StatusEventHdl, EditStatus&, void)
+{
+ ::sd::Window* pWin = mrOutlineViewShell.GetActiveWindow();
+ OutlinerView* pOutlinerView = GetViewByWindow(pWin);
+ ::tools::Rectangle aVis = pOutlinerView->GetVisArea();
+ ::tools::Rectangle aText(Point(0,0),
+ Size(mnPaperWidth,
+ mrOutliner.GetTextHeight()));
+ ::tools::Rectangle aWin(Point(0,0), pWin->GetOutputSizePixel());
+ aWin = pWin->PixelToLogic(aWin);
+
+ if (!aVis.IsEmpty()) // not when opening
+ {
+ if (aWin.GetHeight() > aText.Bottom())
+ aText.SetBottom( aWin.GetHeight() );
+
+ mrOutlineViewShell.InitWindows(Point(0,0), aText.GetSize(), aVis.TopLeft());
+ mrOutlineViewShell.UpdateScrollBars();
+ }
+}
+
+IMPL_LINK_NOARG(OutlineView, BeginDropHdl, EditView*, void)
+{
+ DBG_ASSERT(maDragAndDropModelGuard == nullptr,
+ "sd::OutlineView::BeginDropHdl(), prior drag operation not finished correctly!");
+
+ maDragAndDropModelGuard.reset( new OutlineViewModelChangeGuard( *this ) );
+}
+
+IMPL_LINK_NOARG(OutlineView, EndDropHdl, EditView*, void)
+{
+ maDragAndDropModelGuard.reset();
+}
+
+/**
+ * Handler for the start of a paragraph movement
+ */
+IMPL_LINK( OutlineView, BeginMovingHdl, ::Outliner *, pOutliner, void )
+{
+ OutlineViewPageChangesGuard aGuard(this);
+
+ // list of selected title paragraphs
+ mpOutlinerViews[0]->CreateSelectionList(maSelectedParas);
+
+ maSelectedParas.erase(std::remove_if(maSelectedParas.begin(), maSelectedParas.end(),
+ [](const Paragraph* pPara) { return !Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE); }),
+ maSelectedParas.end());
+
+ // select the pages belonging to the paragraphs on level 0 to select
+ sal_uInt16 nPos = 0;
+ sal_Int32 nParaPos = 0;
+ Paragraph* pPara = pOutliner->GetParagraph( 0 );
+ std::vector<Paragraph*>::const_iterator fiter;
+
+ while(pPara)
+ {
+ if( ::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) ) // one page?
+ {
+ maOldParaOrder.push_back(pPara);
+ SdPage* pPage = mrDoc.GetSdPage(nPos, PageKind::Standard);
+
+ fiter = std::find(maSelectedParas.begin(),maSelectedParas.end(),pPara);
+
+ pPage->SetSelected(fiter != maSelectedParas.end());
+
+ ++nPos;
+ }
+ pPara = pOutliner->GetParagraph( ++nParaPos );
+ }
+}
+
+/**
+ * Handler for the end of a paragraph movement
+ */
+IMPL_LINK( OutlineView, EndMovingHdl, ::Outliner *, pOutliner, void )
+{
+ OutlineViewPageChangesGuard aGuard(this);
+
+ DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::EndMovingHdl(), model change without undo?!" );
+
+ // look for insertion position via the first paragraph
+ Paragraph* pSearchIt = maSelectedParas.empty() ? nullptr : *(maSelectedParas.begin());
+
+ // look for the first of the selected paragraphs in the new ordering
+ sal_uInt16 nPosNewOrder = 0;
+ sal_Int32 nParaPos = 0;
+ Paragraph* pPara = pOutliner->GetParagraph( 0 );
+ Paragraph* pPrev = nullptr;
+ while (pPara && pPara != pSearchIt)
+ {
+ if( ::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) )
+ {
+ nPosNewOrder++;
+ pPrev = pPara;
+ }
+ pPara = pOutliner->GetParagraph( ++nParaPos );
+ }
+
+ sal_uInt16 nPos = nPosNewOrder; // don't change nPosNewOrder
+ if (nPos == 0)
+ {
+ nPos = sal_uInt16(-1); // insert before the first page
+ }
+ else
+ {
+ // look for the predecessor in the old ordering
+ std::vector<Paragraph*>::const_iterator it = std::find(maOldParaOrder.begin(),
+ maOldParaOrder.end(),
+ pPrev);
+
+ if (it != maOldParaOrder.end())
+ nPos = static_cast<sal_uInt16>(it-maOldParaOrder.begin());
+ else
+ nPos = 0xffff;
+
+ DBG_ASSERT(nPos != 0xffff, "Paragraph not found");
+ }
+
+ mrDoc.MovePages(nPos);
+
+ // deselect the pages again
+ sal_uInt16 nPageCount = static_cast<sal_uInt16>(maSelectedParas.size());
+ while (nPageCount)
+ {
+ SdPage* pPage = mrDoc.GetSdPage(nPosNewOrder, PageKind::Standard);
+ pPage->SetSelected(false);
+ nPosNewOrder++;
+ nPageCount--;
+ }
+
+ pOutliner->UpdateFields();
+
+ maSelectedParas.clear();
+ maOldParaOrder.clear();
+}
+
+/**
+ * Look for the title text object in one page of the model
+ */
+SdrTextObj* OutlineView::GetTitleTextObject(SdrPage const * pPage)
+{
+ const size_t nObjectCount = pPage->GetObjCount();
+ SdrTextObj* pResult = nullptr;
+
+ for (size_t nObject = 0; nObject < nObjectCount; ++nObject)
+ {
+ SdrObject* pObject = pPage->GetObj(nObject);
+ if (pObject->GetObjInventor() == SdrInventor::Default &&
+ pObject->GetObjIdentifier() == SdrObjKind::TitleText)
+ {
+ pResult = static_cast<SdrTextObj*>(pObject);
+ break;
+ }
+ }
+ return pResult;
+}
+
+/**
+ * Look for the outline text object in one page of the model
+ */
+SdrTextObj* OutlineView::GetOutlineTextObject(SdrPage const * pPage)
+{
+ const size_t nObjectCount = pPage->GetObjCount();
+ SdrTextObj* pResult = nullptr;
+
+ for (size_t nObject = 0; nObject < nObjectCount; ++nObject)
+ {
+ SdrObject* pObject = pPage->GetObj(nObject);
+ if (pObject->GetObjInventor() == SdrInventor::Default &&
+ pObject->GetObjIdentifier() == SdrObjKind::OutlineText)
+ {
+ pResult = static_cast<SdrTextObj*>(pObject);
+ break;
+ }
+ }
+ return pResult;
+}
+
+SdrTextObj* OutlineView::CreateTitleTextObject(SdPage* pPage)
+{
+ DBG_ASSERT( GetTitleTextObject(pPage) == nullptr, "sd::OutlineView::CreateTitleTextObject(), there is already a title text object!" );
+
+ if( pPage->GetAutoLayout() == AUTOLAYOUT_NONE )
+ {
+ // simple case
+ pPage->SetAutoLayout( AUTOLAYOUT_TITLE_ONLY, true );
+ }
+ else
+ {
+ // we already have a layout with a title but the title
+ // object was deleted, create a new one
+ pPage->InsertAutoLayoutShape( nullptr, PresObjKind::Title, false, pPage->GetTitleRect(), true );
+ }
+
+ return GetTitleTextObject(pPage);
+}
+
+SdrTextObj* OutlineView::CreateOutlineTextObject(SdPage* pPage)
+{
+ DBG_ASSERT( GetOutlineTextObject(pPage) == nullptr, "sd::OutlineView::CreateOutlineTextObject(), there is already a layout text object!" );
+
+ AutoLayout eNewLayout = pPage->GetAutoLayout();
+ switch( eNewLayout )
+ {
+ case AUTOLAYOUT_NONE:
+ case AUTOLAYOUT_TITLE_ONLY:
+ case AUTOLAYOUT_TITLE: eNewLayout = AUTOLAYOUT_TITLE_CONTENT; break;
+
+ case AUTOLAYOUT_CHART: eNewLayout = AUTOLAYOUT_CHARTTEXT; break;
+
+ case AUTOLAYOUT_ORG:
+ case AUTOLAYOUT_TAB:
+ case AUTOLAYOUT_OBJ: eNewLayout = AUTOLAYOUT_OBJTEXT; break;
+ default:
+ break;
+ }
+
+ if( eNewLayout != pPage->GetAutoLayout() )
+ {
+ pPage->SetAutoLayout( eNewLayout, true );
+ }
+ else
+ {
+ // we already have a layout with a text but the text
+ // object was deleted, create a new one
+ pPage->InsertAutoLayoutShape( nullptr,
+ PresObjKind::Outline,
+ false, pPage->GetLayoutRect(), true );
+ }
+
+ return GetOutlineTextObject(pPage);
+}
+
+/** updates draw model with all changes from outliner model */
+void OutlineView::PrepareClose()
+{
+ ::sd::UndoManager* pDocUndoMgr = dynamic_cast<sd::UndoManager*>(mpDocSh->GetUndoManager());
+ if (pDocUndoMgr != nullptr)
+ pDocUndoMgr->SetLinkedUndoManager(nullptr);
+
+ mrOutliner.GetUndoManager().Clear();
+
+ BegUndo(SdResId(STR_UNDO_CHANGE_TITLE_AND_LAYOUT));
+ UpdateDocument();
+ EndUndo();
+ mrDoc.SetSelected(GetActualPage(), true);
+}
+
+/**
+ * Set attributes of the selected text
+ */
+bool OutlineView::SetAttributes(const SfxItemSet& rSet, bool /*bSlide*/, bool /*bReplaceAll*/, bool /*bMaster*/)
+{
+ bool bOk = false;
+
+ OutlinerView* pOlView = GetViewByWindow(mrOutlineViewShell.GetActiveWindow());
+
+ if (pOlView)
+ {
+ pOlView->SetAttribs(rSet);
+ bOk = true;
+ }
+
+ mrOutlineViewShell.Invalidate (SID_PREVIEW_STATE);
+
+ return bOk;
+}
+
+/**
+ * Get attributes of the selected text
+ */
+void OutlineView::GetAttributes( SfxItemSet& rTargetSet, bool ) const
+{
+ OutlinerView* pOlView = GetViewByWindow(
+ mrOutlineViewShell.GetActiveWindow());
+ assert(pOlView && "No OutlinerView found");
+
+ rTargetSet.Put( pOlView->GetAttribs(), false );
+}
+
+/** creates outliner model from draw model */
+void OutlineView::FillOutliner()
+{
+ mrOutliner.GetUndoManager().Clear();
+ mrOutliner.EnableUndo(false);
+ ResetLinks();
+ const bool bPrevUpdateLayout = mrOutliner.SetUpdateLayout(false);
+
+ Paragraph* pTitleToSelect = nullptr;
+ sal_uInt16 nPageCount = mrDoc.GetSdPageCount(PageKind::Standard);
+
+ // fill outliner with paragraphs from slides title & (outlines|subtitles)
+ for (sal_uInt16 nPage = 0; nPage < nPageCount; nPage++)
+ {
+ SdPage* pPage = mrDoc.GetSdPage(nPage, PageKind::Standard);
+ Paragraph * pPara = nullptr;
+
+ // take text from title shape
+ SdrTextObj* pTO = GetTitleTextObject(pPage);
+ if(pTO && !(pTO->IsEmptyPresObj()))
+ {
+ OutlinerParaObject* pOPO = pTO->GetOutlinerParaObject();
+ if (pOPO)
+ {
+ bool bVertical = pOPO->IsEffectivelyVertical();
+ pOPO->SetVertical( false );
+ mrOutliner.AddText(*pOPO);
+ pOPO->SetVertical( bVertical );
+ pPara = mrOutliner.GetParagraph( mrOutliner.GetParagraphCount()-1 );
+ }
+ }
+
+ if( pPara == nullptr ) // no title, insert an empty paragraph
+ {
+ pPara = mrOutliner.Insert(OUString());
+ mrOutliner.SetDepth(pPara, -1);
+
+ // do not apply hard attributes from the previous paragraph
+ mrOutliner.SetParaAttribs( mrOutliner.GetAbsPos(pPara),
+ mrOutliner.GetEmptyItemSet() );
+
+ mrOutliner.SetStyleSheet( mrOutliner.GetAbsPos( pPara ), pPage->GetStyleSheetForPresObj( PresObjKind::Title ) );
+ }
+
+ mrOutliner.SetParaFlag( pPara, ParaFlag::ISPAGE );
+
+ sal_Int32 nPara = mrOutliner.GetAbsPos( pPara );
+
+ UpdateParagraph( nPara );
+
+ // remember paragraph of currently selected page
+ if (pPage->IsSelected())
+ pTitleToSelect = pPara;
+
+ // take text from subtitle or outline
+ pTO = static_cast<SdrTextObj*>(pPage->GetPresObj(PresObjKind::Text));
+ const bool bSubTitle = pTO != nullptr;
+
+ if (!pTO) // if no subtile found, try outline
+ pTO = GetOutlineTextObject(pPage);
+
+ if(pTO && !(pTO->IsEmptyPresObj())) // found some text
+ {
+ OutlinerParaObject* pOPO = pTO->GetOutlinerParaObject();
+ if (pOPO)
+ {
+ sal_Int32 nParaCount1 = mrOutliner.GetParagraphCount();
+ bool bVertical = pOPO->IsEffectivelyVertical();
+ pOPO->SetVertical( false );
+ mrOutliner.AddText(*pOPO);
+ pOPO->SetVertical( bVertical );
+
+ sal_Int32 nParaCount2 = mrOutliner.GetParagraphCount();
+ for (sal_Int32 n = nParaCount1; n < nParaCount2; n++)
+ {
+ if( bSubTitle )
+ {
+ Paragraph* p = mrOutliner.GetParagraph(n);
+ if(p && mrOutliner.GetDepth( n ) > 0 )
+ mrOutliner.SetDepth(p, 0);
+ }
+
+ UpdateParagraph( n );
+ }
+ }
+ }
+ }
+
+ // place cursor at the start
+ Paragraph* pFirstPara = mrOutliner.GetParagraph( 0 );
+ mpOutlinerViews[0]->Select( pFirstPara );
+ mpOutlinerViews[0]->Select( pFirstPara, false );
+
+ // select title of slide that was selected
+ if (pTitleToSelect)
+ mpOutlinerViews[0]->Select(pTitleToSelect);
+
+ SetLinks();
+
+ mrOutliner.EnableUndo(true);
+
+ mrOutliner.SetUpdateLayout(bPrevUpdateLayout);
+}
+
+/**
+ * Handler for deleting of level 0 paragraphs (pages): Warning
+ */
+IMPL_LINK_NOARG(OutlineView, RemovingPagesHdl, OutlinerView*, bool)
+{
+ sal_Int32 nNumOfPages = mrOutliner.GetSelPageCount();
+
+ if (nNumOfPages > PROCESS_WITH_PROGRESS_THRESHOLD)
+ {
+ mnPagesToProcess = nNumOfPages;
+ mnPagesProcessed = 0;
+ }
+
+ if (mnPagesToProcess)
+ {
+ mpProgress.reset( new SfxProgress( GetDocSh(), SdResId(STR_DELETE_PAGES), mnPagesToProcess ) );
+ }
+ mrOutliner.UpdateFields();
+
+ return true;
+}
+
+/**
+ * Handler for indenting level 0 paragraphs (pages): Warning
+ */
+IMPL_LINK( OutlineView, IndentingPagesHdl, OutlinerView *, pOutlinerView, bool )
+{
+ return RemovingPagesHdl(pOutlinerView);
+}
+
+/** returns the first slide that is selected in the outliner or where
+ the cursor is located */
+SdPage* OutlineView::GetActualPage()
+{
+ ::sd::Window* pWin = mrOutlineViewShell.GetActiveWindow();
+ OutlinerView* pActiveView = GetViewByWindow(pWin);
+
+ std::vector<Paragraph*> aSelList;
+ pActiveView->CreateSelectionList(aSelList);
+
+ Paragraph *pPar = aSelList.empty() ? nullptr : *(aSelList.begin());
+ SdPage* pCurrent = GetPageForParagraph(pPar);
+
+ DBG_ASSERT( pCurrent ||
+ (mpDocSh->GetUndoManager() && static_cast< sd::UndoManager *>(mpDocSh->GetUndoManager())->IsDoing()) ||
+ maDragAndDropModelGuard,
+ "sd::OutlineView::GetActualPage(), no current page?" );
+
+ if( pCurrent )
+ return pCurrent;
+
+ return mrDoc.GetSdPage( 0, PageKind::Standard );
+}
+
+SdPage* OutlineView::GetPageForParagraph( Paragraph* pPara )
+{
+ if( !::Outliner::HasParaFlag(pPara,ParaFlag::ISPAGE) )
+ pPara = GetPrevTitle(pPara);
+
+ sal_uInt32 nPageToSelect = 0;
+ while(pPara)
+ {
+ pPara = GetPrevTitle(pPara);
+ if(pPara)
+ nPageToSelect++;
+ }
+
+ if( nPageToSelect < static_cast<sal_uInt32>(mrDoc.GetSdPageCount( PageKind::Standard )) )
+ return mrDoc.GetSdPage( static_cast<sal_uInt16>(nPageToSelect), PageKind::Standard );
+
+ return nullptr;
+}
+
+Paragraph* OutlineView::GetParagraphForPage( ::Outliner const & rOutl, SdPage const * pPage )
+{
+ // get the number of paragraphs with ident 0 we need to skip before
+ // we find the actual page
+ sal_uInt32 nPagesToSkip = (pPage->GetPageNum() - 1) >> 1;
+
+ sal_Int32 nParaPos = 0;
+ Paragraph* pPara = rOutl.GetParagraph( 0 );
+ while( pPara )
+ {
+ // if this paragraph is a page...
+ if( ::Outliner::HasParaFlag(pPara,ParaFlag::ISPAGE) )
+ {
+ // see if we already skipped enough pages
+ if( 0 == nPagesToSkip )
+ break; // and if so, end the loop
+
+ // we skipped another page
+ nPagesToSkip--;
+ }
+
+ // get next paragraph
+ pPara = mrOutliner.GetParagraph( ++nParaPos );
+ }
+
+ return pPara;
+}
+
+/** selects the paragraph for the given page at the outliner view*/
+void OutlineView::SetActualPage( SdPage const * pActual )
+{
+ if( pActual && dynamic_cast<SdOutliner&>(mrOutliner).GetIgnoreCurrentPageChangesLevel()==0 && !mbFirstPaint)
+ {
+ // if we found a paragraph, select its text at the outliner view
+ Paragraph* pPara = GetParagraphForPage( mrOutliner, pActual );
+ if( pPara )
+ mpOutlinerViews[0]->Select( pPara );
+ }
+}
+
+/**
+ * Get StyleSheet from the selection
+ */
+SfxStyleSheet* OutlineView::GetStyleSheet() const
+{
+ ::sd::Window* pActWin = mrOutlineViewShell.GetActiveWindow();
+ OutlinerView* pOlView = GetViewByWindow(pActWin);
+ SfxStyleSheet* pResult = pOlView->GetStyleSheet();
+ return pResult;
+}
+
+/**
+ * Mark pages as selected / not selected
+ */
+void OutlineView::SetSelectedPages()
+{
+ // list of selected title paragraphs
+ std::vector<Paragraph*> aSelParas;
+ mpOutlinerViews[0]->CreateSelectionList(aSelParas);
+
+ aSelParas.erase(std::remove_if(aSelParas.begin(), aSelParas.end(),
+ [](const Paragraph* pPara) { return !Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE); }),
+ aSelParas.end());
+
+ // select the pages belonging to the paragraphs on level 0 to select
+ sal_uInt16 nPos = 0;
+ sal_Int32 nParaPos = 0;
+ Paragraph *pPara = mrOutliner.GetParagraph( 0 );
+ std::vector<Paragraph*>::const_iterator fiter;
+
+ while(pPara)
+ {
+ if( ::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) ) // one page
+ {
+ SdPage* pPage = mrDoc.GetSdPage(nPos, PageKind::Standard);
+ DBG_ASSERT(pPage!=nullptr,
+ "Trying to select non-existing page OutlineView::SetSelectedPages()");
+
+ if (pPage)
+ {
+ fiter = std::find(aSelParas.begin(),aSelParas.end(),pPara);
+ pPage->SetSelected(fiter != aSelParas.end());
+ }
+
+ nPos++;
+ }
+
+ pPara = mrOutliner.GetParagraph( ++nParaPos );
+ }
+}
+
+/**
+ * Set new links
+ */
+void OutlineView::SetLinks()
+{
+ // set notification links
+ mrOutliner.SetParaInsertedHdl(LINK(this, OutlineView, ParagraphInsertedHdl));
+ mrOutliner.SetParaRemovingHdl(LINK(this, OutlineView, ParagraphRemovingHdl));
+ mrOutliner.SetDepthChangedHdl(LINK(this, OutlineView, DepthChangedHdl));
+ mrOutliner.SetBeginMovingHdl(LINK(this, OutlineView, BeginMovingHdl));
+ mrOutliner.SetEndMovingHdl(LINK(this, OutlineView, EndMovingHdl));
+ mrOutliner.SetRemovingPagesHdl(LINK(this, OutlineView, RemovingPagesHdl));
+ mrOutliner.SetIndentingPagesHdl(LINK(this, OutlineView, IndentingPagesHdl));
+ mrOutliner.SetStatusEventHdl(LINK(this, OutlineView, StatusEventHdl));
+ mrOutliner.SetBeginDropHdl(LINK(this,OutlineView, BeginDropHdl));
+ mrOutliner.SetEndDropHdl(LINK(this,OutlineView, EndDropHdl));
+ mrOutliner.SetPaintFirstLineHdl(LINK(this,OutlineView,PaintingFirstLineHdl));
+ mrOutliner.SetBeginPasteOrDropHdl(LINK(this,OutlineView, BeginPasteOrDropHdl));
+ mrOutliner.SetEndPasteOrDropHdl(LINK(this,OutlineView, EndPasteOrDropHdl));
+}
+
+/**
+ * Restore old links
+ */
+void OutlineView::ResetLinks() const
+{
+ mrOutliner.SetParaInsertedHdl(Link<::Outliner::ParagraphHdlParam,void>());
+ mrOutliner.SetParaRemovingHdl(Link<::Outliner::ParagraphHdlParam,void>());
+ mrOutliner.SetDepthChangedHdl(Link<::Outliner::DepthChangeHdlParam,void>());
+ mrOutliner.SetBeginMovingHdl(Link<::Outliner*,void>());
+ mrOutliner.SetEndMovingHdl(Link<::Outliner*,void>());
+ mrOutliner.SetStatusEventHdl(Link<EditStatus&,void>());
+ mrOutliner.SetRemovingPagesHdl(Link<OutlinerView*,bool>());
+ mrOutliner.SetIndentingPagesHdl(Link<OutlinerView*,bool>());
+ mrOutliner.SetDrawPortionHdl(Link<DrawPortionInfo*,void>());
+ mrOutliner.SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*,void>());
+ mrOutliner.SetEndPasteOrDropHdl(Link<PasteOrDropInfos*,void>());
+}
+
+sal_Int8 OutlineView::AcceptDrop( const AcceptDropEvent&, DropTargetHelper&, SdrLayerID)
+{
+ return DND_ACTION_NONE;
+}
+
+sal_Int8 OutlineView::ExecuteDrop( const ExecuteDropEvent&, ::sd::Window*, sal_uInt16, SdrLayerID)
+{
+ return DND_ACTION_NONE;
+}
+
+// Re-implement GetScriptType for this view to get correct results
+SvtScriptType OutlineView::GetScriptType() const
+{
+ SvtScriptType nScriptType = ::sd::View::GetScriptType();
+
+ std::optional<OutlinerParaObject> pTempOPObj = mrOutliner.CreateParaObject();
+ if(pTempOPObj)
+ {
+ nScriptType = pTempOPObj->GetTextObject().GetScriptType();
+ }
+
+ return nScriptType;
+}
+
+void OutlineView::onUpdateStyleSettings( bool bForceUpdate /* = false */ )
+{
+ svtools::ColorConfig aColorConfig;
+ const Color aDocColor( aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor );
+ if( !(bForceUpdate || (maDocColor != aDocColor)) )
+ return;
+
+ sal_uInt16 nView;
+ for( nView = 0; nView < MAX_OUTLINERVIEWS; nView++ )
+ {
+ if (mpOutlinerViews[nView] != nullptr)
+ {
+ mpOutlinerViews[nView]->SetBackgroundColor( aDocColor );
+
+ vcl::Window* pWindow = mpOutlinerViews[nView]->GetWindow();
+
+ if( pWindow )
+ pWindow->SetBackground( Wallpaper( aDocColor ) );
+
+ }
+ }
+
+ mrOutliner.SetBackgroundColor( aDocColor );
+
+ maDocColor = aDocColor;
+}
+
+IMPL_LINK_NOARG(OutlineView, AppEventListenerHdl, VclSimpleEvent&, void)
+{
+ onUpdateStyleSettings(false);
+}
+
+IMPL_LINK(OutlineView, EventMultiplexerListener, ::sd::tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ case EventMultiplexerEventId::CurrentPageChanged:
+ SetActualPage(mrOutlineViewShell.GetActualPage());
+ break;
+
+ case EventMultiplexerEventId::PageOrder:
+ if (dynamic_cast<SdOutliner&>(mrOutliner).GetIgnoreCurrentPageChangesLevel()==0)
+ {
+ if (((mrDoc.GetPageCount()-1)%2) == 0)
+ {
+ mrOutliner.Clear();
+ FillOutliner();
+ ::sd::Window* pWindow = mrOutlineViewShell.GetActiveWindow();
+ if (pWindow != nullptr)
+ pWindow->Invalidate();
+ }
+ }
+ break;
+
+ default: break;
+ }
+}
+
+void OutlineView::IgnoreCurrentPageChanges (bool bIgnoreChanges)
+{
+ if (bIgnoreChanges)
+ dynamic_cast<SdOutliner&>(mrOutliner).IncreIgnoreCurrentPageChangesLevel();
+ else
+ dynamic_cast<SdOutliner&>(mrOutliner).DecreIgnoreCurrentPageChangesLevel();
+}
+
+/** call this method before you do anything that can modify the outliner
+ and or the drawing document model. It will create needed undo actions */
+void OutlineView::BeginModelChange()
+{
+ mrOutliner.GetUndoManager().EnterListAction("", "", 0, mrOutlineViewShell.GetViewShellBase().GetViewShellId());
+ BegUndo(SdResId(STR_UNDO_CHANGE_TITLE_AND_LAYOUT));
+}
+
+/** call this method after BeginModelChange(), when all possible model
+ changes are done. */
+void OutlineView::EndModelChange()
+{
+ UpdateDocument();
+
+ SfxUndoManager* pDocUndoMgr = mpDocSh->GetUndoManager();
+
+ bool bHasUndoActions = pDocUndoMgr->GetUndoActionCount() != 0;
+
+ EndUndo();
+
+ DBG_ASSERT( bHasUndoActions == (mrOutliner.GetUndoManager().GetUndoActionCount() != 0), "sd::OutlineView::EndModelChange(), undo actions not in sync!" );
+
+ mrOutliner.GetUndoManager().LeaveListAction();
+
+ if( bHasUndoActions && mrOutliner.GetEditEngine().HasTriedMergeOnLastAddUndo() )
+ TryToMergeUndoActions();
+
+ mrOutlineViewShell.Invalidate( SID_UNDO );
+ mrOutlineViewShell.Invalidate( SID_REDO );
+}
+
+/** updates all changes in the outliner model to the draw model */
+void OutlineView::UpdateDocument()
+{
+ OutlineViewPageChangesGuard aGuard(this);
+
+ const sal_uInt32 nPageCount = mrDoc.GetSdPageCount(PageKind::Standard);
+ Paragraph* pPara = mrOutliner.GetParagraph( 0 );
+ sal_uInt32 nPage;
+ for (nPage = 0; nPage < nPageCount; nPage++)
+ {
+ SdPage* pPage = mrDoc.GetSdPage( static_cast<sal_uInt16>(nPage), PageKind::Standard);
+ mrDoc.SetSelected(pPage, false);
+
+ mrOutlineViewShell.UpdateTitleObject( pPage, pPara );
+ mrOutlineViewShell.UpdateOutlineObject( pPage, pPara );
+
+ if( pPara )
+ pPara = GetNextTitle(pPara);
+ }
+
+ DBG_ASSERT( pPara == nullptr, "sd::OutlineView::UpdateDocument(), slides are out of sync, creating missing ones" );
+ while( pPara )
+ {
+ SdPage* pPage = InsertSlideForParagraph( pPara );
+ mrDoc.SetSelected(pPage, false);
+
+ mrOutlineViewShell.UpdateTitleObject( pPage, pPara );
+ mrOutlineViewShell.UpdateOutlineObject( pPage, pPara );
+
+ pPara = GetNextTitle(pPara);
+ }
+}
+
+/** merge edit engine undo actions if possible */
+void OutlineView::TryToMergeUndoActions()
+{
+ SfxUndoManager& rOutlineUndo = mrOutliner.GetUndoManager();
+ if( rOutlineUndo.GetUndoActionCount() <= 1 )
+ return;
+
+ SfxListUndoAction* pListAction = dynamic_cast< SfxListUndoAction* >( rOutlineUndo.GetUndoAction() );
+ SfxListUndoAction* pPrevListAction = dynamic_cast< SfxListUndoAction* >( rOutlineUndo.GetUndoAction(1) );
+ if( !(pListAction && pPrevListAction) )
+ return;
+
+ // find the top EditUndo action in the top undo action list
+ size_t nAction = pListAction->maUndoActions.size();
+ EditUndo* pEditUndo = nullptr;
+ while( !pEditUndo && nAction )
+ {
+ pEditUndo = dynamic_cast< EditUndo* >(pListAction->GetUndoAction(--nAction));
+ }
+
+ sal_uInt16 nEditPos = nAction; // we need this later to remove the merged undo actions
+
+ // make sure it is the only EditUndo action in the top undo list
+ while( pEditUndo && nAction )
+ {
+ if( dynamic_cast< EditUndo* >(pListAction->GetUndoAction(--nAction)) )
+ pEditUndo = nullptr;
+ }
+
+ // do we have one and only one EditUndo action in the top undo list?
+ if( !pEditUndo )
+ return;
+
+ // yes, see if we can merge it with the prev undo list
+
+ nAction = pPrevListAction->maUndoActions.size();
+ EditUndo* pPrevEditUndo = nullptr;
+ while( !pPrevEditUndo && nAction )
+ pPrevEditUndo = dynamic_cast< EditUndo* >(pPrevListAction->GetUndoAction(--nAction));
+
+ if( !(pPrevEditUndo && pPrevEditUndo->Merge( pEditUndo )) )
+ return;
+
+ // ok we merged the only EditUndo of the top undo list with
+ // the top EditUndo of the previous undo list
+
+ // first remove the merged undo action
+ assert( pListAction->GetUndoAction(nEditPos) == pEditUndo &&
+ "sd::OutlineView::TryToMergeUndoActions(), wrong edit pos!" );
+ pListAction->Remove(nEditPos);
+
+ if ( !pListAction->maUndoActions.empty() )
+ {
+ // now we have to move all remaining doc undo actions from the top undo
+ // list to the previous undo list and remove the top undo list
+
+ size_t nCount = pListAction->maUndoActions.size();
+ size_t nDestAction = pPrevListAction->maUndoActions.size();
+ while( nCount-- )
+ {
+ std::unique_ptr<SfxUndoAction> pTemp = pListAction->Remove(0);
+ pPrevListAction->Insert( std::move(pTemp), nDestAction++ );
+ }
+ pPrevListAction->nCurUndoAction = pPrevListAction->maUndoActions.size();
+ }
+
+ rOutlineUndo.RemoveLastUndoAction();
+}
+
+IMPL_LINK(OutlineView, PaintingFirstLineHdl, PaintFirstLineInfo*, pInfo, void)
+{
+ if( !pInfo )
+ return;
+
+ Paragraph* pPara = mrOutliner.GetParagraph( pInfo->mnPara );
+ EditEngine& rEditEngine = const_cast< EditEngine& >( mrOutliner.GetEditEngine() );
+
+ Size aImageSize( pInfo->mpOutDev->PixelToLogic( maSlideImage.GetSizePixel() ) );
+ Size aOffset( 100, 100 );
+
+ // paint slide number
+ if( !(pPara && ::Outliner::HasParaFlag(pPara,ParaFlag::ISPAGE)) )
+ return;
+
+ ::tools::Long nPage = 0; // todo, printing??
+ for ( sal_Int32 n = 0; n <= pInfo->mnPara; n++ )
+ {
+ Paragraph* p = mrOutliner.GetParagraph( n );
+ if ( ::Outliner::HasParaFlag(p,ParaFlag::ISPAGE) )
+ nPage++;
+ }
+
+ ::tools::Long nBulletHeight = static_cast<::tools::Long>(mrOutliner.GetLineHeight( pInfo->mnPara ));
+ ::tools::Long nFontHeight = 0;
+ if ( !rEditEngine.IsFlatMode() )
+ {
+ nFontHeight = nBulletHeight / 5;
+ }
+ else
+ {
+ nFontHeight = (nBulletHeight * 10) / 25;
+ }
+
+ Size aFontSz( 0, nFontHeight );
+
+ Size aOutSize( 2000, nBulletHeight );
+
+ const float fImageHeight = (static_cast<float>(aOutSize.Height()) * float(4)) / float(7);
+ if (aImageSize.Width() != 0)
+ {
+ const float fImageRatio = static_cast<float>(aImageSize.Height()) / static_cast<float>(aImageSize.Width());
+ aImageSize.setWidth( static_cast<::tools::Long>( fImageRatio * fImageHeight ) );
+ }
+ aImageSize.setHeight( static_cast<::tools::Long>(fImageHeight) );
+
+ Point aImagePos( pInfo->mrStartPos );
+ aImagePos.AdjustX(aOutSize.Width() - aImageSize.Width() - aOffset.Width() ) ;
+ aImagePos.AdjustY((aOutSize.Height() - aImageSize.Height()) / 2 );
+
+ pInfo->mpOutDev->DrawImage( aImagePos, aImageSize, maSlideImage );
+
+ const bool bVertical = mrOutliner.IsVertical();
+ const bool bRightToLeftPara = rEditEngine.IsRightToLeft( pInfo->mnPara );
+
+ LanguageType eLang = rEditEngine.GetDefaultLanguage();
+
+ Point aTextPos( aImagePos.X() - aOffset.Width(), pInfo->mrStartPos.Y() );
+ vcl::Font aNewFont( OutputDevice::GetDefaultFont( DefaultFontType::SANS_UNICODE, eLang, GetDefaultFontFlags::NONE ) );
+ aNewFont.SetFontSize( aFontSz );
+ aNewFont.SetVertical( bVertical );
+ aNewFont.SetOrientation( Degree10(bVertical ? 2700 : 0) );
+ aNewFont.SetColor( COL_AUTO );
+ pInfo->mpOutDev->SetFont( aNewFont );
+ OUString aPageText = OUString::number( nPage );
+ Size aTextSz;
+ aTextSz.setWidth( pInfo->mpOutDev->GetTextWidth( aPageText ) );
+ aTextSz.setHeight( pInfo->mpOutDev->GetTextHeight() );
+ if ( !bVertical )
+ {
+ aTextPos.AdjustY((aOutSize.Height() - aTextSz.Height()) / 2 );
+ if ( !bRightToLeftPara )
+ {
+ aTextPos.AdjustX( -(aTextSz.Width()) );
+ }
+ else
+ {
+ aTextPos.AdjustX(aTextSz.Width() );
+ }
+ }
+ else
+ {
+ aTextPos.AdjustY( -(aTextSz.Width()) );
+ aTextPos.AdjustX(nBulletHeight / 2 );
+ }
+ pInfo->mpOutDev->DrawText( aTextPos, aPageText );
+}
+
+void OutlineView::UpdateParagraph( sal_Int32 nPara )
+{
+ SfxItemSet aNewAttrs2( mrOutliner.GetParaAttribs( nPara ) );
+ aNewAttrs2.Put( maLRSpaceItem );
+ mrOutliner.SetParaAttribs( nPara, aNewAttrs2 );
+}
+
+void OutlineView::OnBeginPasteOrDrop( PasteOrDropInfos* /*pInfo*/ )
+{
+}
+
+/** this is called after a paste or drop operation, make sure that the newly inserted paragraphs
+ get the correct style sheet and new slides are inserted. */
+void OutlineView::OnEndPasteOrDrop( PasteOrDropInfos* pInfo )
+{
+ SdPage* pPage = nullptr;
+ SfxStyleSheetBasePool* pStylePool = GetDoc().GetStyleSheetPool();
+
+ for( sal_Int32 nPara = pInfo->nStartPara; nPara <= pInfo->nEndPara; nPara++ )
+ {
+ Paragraph* pPara = mrOutliner.GetParagraph( nPara );
+
+ bool bPage = ::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE );
+
+ if( !bPage )
+ {
+ SdStyleSheet* pStyleSheet = dynamic_cast< SdStyleSheet* >( mrOutliner.GetStyleSheet( nPara ) );
+ if( pStyleSheet )
+ {
+ if ( pStyleSheet->GetApiName() == "title" )
+ bPage = true;
+ }
+ }
+
+ if( !pPara )
+ continue; // fatality!?
+
+ if( bPage && (nPara != pInfo->nStartPara) )
+ {
+ // insert new slide for this paragraph
+ pPage = InsertSlideForParagraph( pPara );
+ }
+ else
+ {
+ // newly inserted non page paragraphs get the outline style
+ if( !pPage )
+ pPage = GetPageForParagraph( pPara );
+
+ if( pPage )
+ {
+ SfxStyleSheet* pStyle = pPage->GetStyleSheetForPresObj( bPage ? PresObjKind::Title : PresObjKind::Outline );
+
+ if( !bPage )
+ {
+ const sal_Int16 nDepth = mrOutliner.GetDepth( nPara );
+ if( nDepth > 0 )
+ {
+ OUString aStyleSheetName = pStyle->GetName();
+ if (!aStyleSheetName.isEmpty())
+ aStyleSheetName = aStyleSheetName.copy(0, aStyleSheetName.getLength() - 1);
+ aStyleSheetName += OUString::number( nDepth );
+ pStyle = static_cast<SfxStyleSheet*>( pStylePool->Find( aStyleSheetName, pStyle->GetFamily() ) );
+ DBG_ASSERT( pStyle, "sd::OutlineView::OnEndPasteOrDrop(), Style not found!" );
+ }
+ }
+
+ mrOutliner.SetStyleSheet( nPara, pStyle );
+ }
+
+ UpdateParagraph( nPara );
+ }
+ }
+}
+
+
+OutlineViewModelChangeGuard::OutlineViewModelChangeGuard( OutlineView& rView )
+: mrView( rView )
+{
+ mrView.BeginModelChange();
+}
+
+OutlineViewModelChangeGuard::~OutlineViewModelChangeGuard() COVERITY_NOEXCEPT_FALSE
+{
+ mrView.EndModelChange();
+}
+
+
+OutlineViewPageChangesGuard::OutlineViewPageChangesGuard( OutlineView* pView )
+: mpView( pView )
+{
+ if( mpView )
+ mpView->IgnoreCurrentPageChanges( true );
+}
+
+OutlineViewPageChangesGuard::~OutlineViewPageChangesGuard()
+{
+ if( mpView )
+ mpView->IgnoreCurrentPageChanges( false );
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/presvish.cxx b/sd/source/ui/view/presvish.cxx
new file mode 100644
index 000000000..34a789f4d
--- /dev/null
+++ b/sd/source/ui/view/presvish.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <PresentationViewShell.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svxids.hrc>
+#include <svx/ruler.hxx>
+#include <FrameView.hxx>
+#include <DrawDocShell.hxx>
+#include <slideshow.hxx>
+#include <app.hrc>
+#include <ViewShellBase.hxx>
+
+#include <fupoor.hxx>
+#include <Window.hxx>
+
+#define ShellClass_PresentationViewShell
+using namespace sd;
+#include <sdslots.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+
+namespace sd {
+
+SFX_IMPL_INTERFACE(PresentationViewShell, DrawViewShell)
+
+void PresentationViewShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_TOOLS, SfxVisibilityFlags::Standard | SfxVisibilityFlags::FullScreen | SfxVisibilityFlags::Server,
+ ToolbarId::Draw_Toolbox_Sd);
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_APPLICATION, SfxVisibilityFlags::Standard | SfxVisibilityFlags::Client | SfxVisibilityFlags::Viewer | SfxVisibilityFlags::ReadonlyDoc,
+ ToolbarId::Draw_Viewer_Toolbox);
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OPTIONS, SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server,
+ ToolbarId::Draw_Options_Toolbox);
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_COMMONTASK, SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server,
+ ToolbarId::Draw_CommonTask_Toolbox);
+}
+
+
+PresentationViewShell::PresentationViewShell( ViewShellBase& rViewShellBase, vcl::Window* pParentWindow, FrameView* pFrameView)
+ : DrawViewShell(rViewShellBase, pParentWindow, PageKind::Standard, pFrameView)
+ , mnAbortSlideShowEvent(nullptr)
+{
+ if( GetDocSh() && GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
+ maOldVisArea = GetDocSh()->GetVisArea( ASPECT_CONTENT );
+ meShellType = ST_PRESENTATION;
+}
+
+PresentationViewShell::~PresentationViewShell()
+{
+ if (mnAbortSlideShowEvent)
+ Application::RemoveUserEvent(mnAbortSlideShowEvent);
+
+ if( GetDocSh() && GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !maOldVisArea.IsEmpty() )
+ GetDocSh()->SetVisArea( maOldVisArea );
+}
+
+void PresentationViewShell::FinishInitialization( FrameView* pFrameView )
+{
+ DrawViewShell::Init(true);
+
+ // Use the frame view that comes form the view shell that initiated our
+ // creation.
+ if (pFrameView != nullptr)
+ {
+ GetFrameView()->Disconnect();
+ SetFrameView (pFrameView);
+ pFrameView->Connect();
+ }
+ SetRuler(false);
+ WriteFrameViewData();
+
+ GetActiveWindow()->GrabFocus();
+}
+
+VclPtr<SvxRuler> PresentationViewShell::CreateHRuler(::sd::Window*)
+{
+ return nullptr;
+}
+
+VclPtr<SvxRuler> PresentationViewShell::CreateVRuler(::sd::Window*)
+{
+ return nullptr;
+}
+
+IMPL_LINK_NOARG(PresentationViewShell, AbortSlideShowHdl, void*, void)
+{
+ mnAbortSlideShowEvent = nullptr;
+ rtl::Reference<SlideShow> xSlideShow(SlideShow::GetSlideShow(GetViewShellBase()));
+ if (xSlideShow.is())
+ xSlideShow->end();
+}
+
+void PresentationViewShell::Activate( bool bIsMDIActivate )
+{
+ DrawViewShell::Activate( bIsMDIActivate );
+
+ if( bIsMDIActivate )
+ {
+ SfxBoolItem aItem( SID_NAVIGATOR_INIT, true );
+
+ GetViewFrame()->GetDispatcher()->ExecuteList(SID_NAVIGATOR_INIT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if( xSlideShow.is() )
+ {
+ bool bSuccess = xSlideShow->activate(GetViewShellBase());
+ if (!bSuccess)
+ {
+ /* tdf#64711 PresentationViewShell is deleted by 'end' due to end closing
+ the object shell. So if we call xSlideShow->end during Activate there are
+ a lot of places in the call stack of Activate which understandable don't
+ expect this ViewShell to be deleted during use. Defer to the next event
+ loop the abort of the slideshow
+ */
+ if (!mnAbortSlideShowEvent)
+ mnAbortSlideShowEvent = Application::PostUserEvent(LINK(this, PresentationViewShell, AbortSlideShowHdl));
+ }
+ }
+
+ if( HasCurrentFunction() )
+ GetCurrentFunction()->Activate();
+
+ ReadFrameViewData(mpFrameView);
+ }
+
+ GetDocSh()->Connect( this );
+}
+
+void PresentationViewShell::Paint( const ::tools::Rectangle& /*rRect*/, ::sd::Window* )
+{
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if( xSlideShow.is() )
+ xSlideShow->paint();
+}
+
+void PresentationViewShell::Resize()
+{
+ ViewShell::Resize(); // do not call DrawViewShell here!
+
+ rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if( xSlideshow.is() )
+ xSlideshow->resize(maViewSize);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/sdruler.cxx b/sd/source/ui/view/sdruler.cxx
new file mode 100644
index 000000000..571ffb37f
--- /dev/null
+++ b/sd/source/ui/view/sdruler.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 <Ruler.hxx>
+#include <svl/ptitem.hxx>
+#include <svx/ruler.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/ctrlitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <vcl/commandevent.hxx>
+
+#include <View.hxx>
+#include <DrawViewShell.hxx>
+#include <Window.hxx>
+
+#include <helpids.h>
+
+namespace sd {
+
+/**
+ * Controller-Item for ruler
+ */
+class RulerCtrlItem : public SfxControllerItem
+{
+ Ruler &rRuler;
+
+ protected:
+ virtual void StateChangedAtToolBoxControl( sal_uInt16 nSId, SfxItemState eState,
+ const SfxPoolItem* pItem ) override;
+
+ public:
+ RulerCtrlItem(Ruler& rRlr, SfxBindings& rBind);
+};
+
+RulerCtrlItem::RulerCtrlItem(Ruler& rRlr, SfxBindings& rBind)
+: SfxControllerItem(SID_RULER_NULL_OFFSET, rBind)
+, rRuler(rRlr)
+{
+}
+
+void RulerCtrlItem::StateChangedAtToolBoxControl( sal_uInt16 nSId, SfxItemState, const SfxPoolItem* pState )
+{
+ switch( nSId )
+ {
+ case SID_RULER_NULL_OFFSET:
+ {
+ const SfxPointItem* pItem = dynamic_cast< const SfxPointItem* >(pState);
+ DBG_ASSERT(pState == nullptr || pItem != nullptr, "SfxPointItem expected");
+ if ( pItem )
+ rRuler.SetNullOffset(pItem->GetValue());
+ }
+ break;
+ }
+}
+
+Ruler::Ruler( DrawViewShell& rViewSh, vcl::Window* pParent, ::sd::Window* pWin, SvxRulerSupportFlags nRulerFlags, SfxBindings& rBindings, WinBits nWinStyle)
+ : SvxRuler(pParent, pWin, nRulerFlags, rBindings, nWinStyle)
+ , pDrViewShell(&rViewSh)
+{
+ rBindings.EnterRegistrations();
+ pCtrlItem.reset( new RulerCtrlItem(*this, rBindings) );
+ rBindings.LeaveRegistrations();
+
+ if ( nWinStyle & WB_HSCROLL )
+ {
+ bHorz = true;
+ SetHelpId( HID_SD_RULER_HORIZONTAL );
+ }
+ else
+ {
+ bHorz = false;
+ SetHelpId( HID_SD_RULER_VERTICAL );
+ }
+}
+
+Ruler::~Ruler()
+{
+ disposeOnce();
+}
+
+void Ruler::dispose()
+{
+ SfxBindings& rBindings = pCtrlItem->GetBindings();
+ rBindings.EnterRegistrations();
+ pCtrlItem.reset();
+ rBindings.LeaveRegistrations();
+ SvxRuler::dispose();
+}
+
+void Ruler::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ Point aMPos = rMEvt.GetPosPixel();
+ RulerType eType = GetRulerType(aMPos);
+
+ if ( !pDrViewShell->GetView()->IsTextEdit() &&
+ rMEvt.IsLeft() && rMEvt.GetClicks() == 1 &&
+ (eType == RulerType::DontKnow || eType == RulerType::Outside) )
+ {
+ pDrViewShell->StartRulerDrag(*this, rMEvt);
+ }
+ else
+ SvxRuler::MouseButtonDown(rMEvt);
+}
+
+void Ruler::SetNullOffset(const Point& rOffset)
+{
+ ::tools::Long nOffset;
+
+ if ( bHorz ) nOffset = rOffset.X();
+ else nOffset = rOffset.Y();
+
+ SetNullOffsetLogic(nOffset);
+}
+
+void Ruler::Command(const CommandEvent& rCEvt)
+{
+ if( rCEvt.GetCommand() == CommandEventId::ContextMenu &&
+ !pDrViewShell->GetView()->IsTextEdit() )
+ {
+ SvxRuler::Command( rCEvt );
+ }
+}
+
+void Ruler::ExtraDown()
+{
+ if( !pDrViewShell->GetView()->IsTextEdit() )
+ SvxRuler::ExtraDown();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/sdview.cxx b/sd/source/ui/view/sdview.cxx
new file mode 100644
index 000000000..f27622fd1
--- /dev/null
+++ b/sd/source/ui/view/sdview.cxx
@@ -0,0 +1,1395 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
+
+#include <View.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/unolingu.hxx>
+#include <o3tl/deleter.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/fmview.hxx>
+#include <editeng/outliner.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdundo.hxx>
+
+#include <vcl/settings.hxx>
+
+#include <officecfg/Office/Common.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+
+#include <svx/svdetc.hxx>
+#include <editeng/editstat.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <svx/xfillit0.hxx>
+
+#include <app.hrc>
+#include <strings.hrc>
+#include <Window.hxx>
+#include <Client.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <unokywds.hxx>
+#include <ViewClipboard.hxx>
+#include <undo/undomanager.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/svdotable.hxx>
+#include <EventMultiplexer.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShell.hxx>
+
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/table/tablecontroller.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <svx/unoapi.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <DrawController.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+
+#include <memory>
+#include <numeric>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace sdr::table;
+namespace sd {
+
+View::View(
+ SdDrawDocument& rDrawDoc,
+ OutputDevice* pOutDev,
+ ViewShell* pViewShell)
+: FmFormView(rDrawDoc, pOutDev),
+ mrDoc(rDrawDoc),
+ mpDocSh(rDrawDoc.GetDocSh()),
+ mpViewSh(pViewShell),
+ mpDropMarkerObj(nullptr),
+ mnDragSrcPgNum(SDRPAGE_NOTFOUND),
+ mnAction(DND_ACTION_NONE),
+ maDropErrorIdle("sd View DropError"),
+ maDropInsertFileIdle("sd View DropInsertFile"),
+ mnLockRedrawSmph(0),
+ mbIsDropAllowed(true),
+ maSmartTags(*this),
+ mpClipboard (new ViewClipboard (*this))
+{
+ // #i73602# Use default from the configuration
+ SetBufferedOverlayAllowed(SvtOptionsDrawinglayer::IsOverlayBuffer_DrawImpress());
+
+ // #i74769#, #i75172# Use default from the configuration
+ SetBufferedOutputAllowed(SvtOptionsDrawinglayer::IsPaintBuffer_DrawImpress());
+
+ EnableExtendedKeyInputDispatcher(false);
+ EnableExtendedMouseEventDispatcher(false);
+
+ SetUseIncompatiblePathCreateInterface(false);
+
+ SetMinMoveDistancePixel(2);
+ SetHitTolerancePixel(2);
+ SetMeasureLayer(sUNO_LayerName_measurelines);
+
+ // Timer for delayed drop (has to be for MAC)
+ maDropErrorIdle.SetInvokeHandler( LINK(this, View, DropErrorHdl) );
+ maDropInsertFileIdle.SetInvokeHandler( LINK(this, View, DropInsertFileHdl) );
+}
+
+void View::ImplClearDrawDropMarker()
+{
+ mpDropMarker.reset();
+}
+
+View::~View()
+{
+ maSmartTags.Dispose();
+
+ // release content of selection clipboard, if we own the content
+ ClearSelectionClipboard();
+
+ if (mxDropMediaSizeListener)
+ {
+ suppress_fun_call_w_exception(mxDropMediaSizeListener->dispose());
+ mxDropMediaSizeListener.clear();
+ }
+
+ maDropErrorIdle.Stop();
+ maDropInsertFileIdle.Stop();
+
+ ImplClearDrawDropMarker();
+
+ while(PaintWindowCount())
+ {
+ // remove all registered OutDevs
+ suppress_fun_call_w_exception(DeleteWindowFromPaintView(GetFirstOutputDevice()));
+ }
+}
+
+namespace {
+
+class ViewRedirector : public sdr::contact::ViewObjectContactRedirector
+{
+public:
+ ViewRedirector();
+
+ // all default implementations just call the same methods at the original. To do something
+ // different, override the method and at least do what the method does.
+ virtual void createRedirectedPrimitive2DSequence(
+ const sdr::contact::ViewObjectContact& rOriginal,
+ const sdr::contact::DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) override;
+};
+
+}
+
+ViewRedirector::ViewRedirector()
+{
+}
+
+void ViewRedirector::createRedirectedPrimitive2DSequence(
+ const sdr::contact::ViewObjectContact& rOriginal,
+ const sdr::contact::DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+{
+ SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
+ SdrPage* pSdrPage = pObject ? pObject->getSdrPageFromSdrObject() : nullptr;
+ if(!pObject || !pSdrPage)
+ {
+ // not a SdrObject visualisation (maybe e.g. page) or no page
+ sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor);
+ return;
+ }
+
+ const bool bDoCreateGeometry(pSdrPage->checkVisibility( rOriginal, rDisplayInfo, true ));
+
+ if(!bDoCreateGeometry &&
+ (( pObject->GetObjInventor() != SdrInventor::Default ) || ( pObject->GetObjIdentifier() != SdrObjKind::Page )) )
+ return;
+
+ PresObjKind eKind(PresObjKind::NONE);
+ const bool bSubContentProcessing(rDisplayInfo.GetSubContentActive());
+ const bool bIsMasterPageObject(pSdrPage->IsMasterPage());
+ const bool bIsPrinting(rOriginal.GetObjectContact().isOutputToPrinter());
+ const SdrPageView* pPageView = rOriginal.GetObjectContact().TryToGetSdrPageView();
+ const SdrPage* pVisualizedPage = GetSdrPageFromXDrawPage(rOriginal.GetObjectContact().getViewInformation2D().getVisualizedPage());
+ const SdPage* pObjectsSdPage = dynamic_cast< SdPage* >(pSdrPage);
+ const bool bIsInsidePageObj(pPageView && pPageView->GetPage() != pVisualizedPage);
+
+ // check if we need to draw a placeholder border. Never do it for
+ // objects inside a SdrPageObj and never when printing
+ if(!bIsInsidePageObj && !bIsPrinting)
+ {
+ bool bCreateOutline(false);
+
+ if( pObject->IsEmptyPresObj() && dynamic_cast< SdrTextObj *>( pObject ) != nullptr )
+ {
+ if( !bSubContentProcessing || !pObject->IsNotVisibleAsMaster() )
+ {
+ eKind = pObjectsSdPage ? pObjectsSdPage->GetPresObjKind(pObject) : PresObjKind::NONE;
+ bCreateOutline = true;
+ }
+ }
+ else if( ( pObject->GetObjInventor() == SdrInventor::Default ) && ( pObject->GetObjIdentifier() == SdrObjKind::Text ) )
+ {
+ if( pObjectsSdPage )
+ {
+ eKind = pObjectsSdPage->GetPresObjKind(pObject);
+
+ if((eKind == PresObjKind::Footer) || (eKind == PresObjKind::Header) || (eKind == PresObjKind::DateTime) || (eKind == PresObjKind::SlideNumber) )
+ {
+ if( !bSubContentProcessing )
+ {
+ // only draw a boundary for header&footer objects on the masterpage itself
+ bCreateOutline = true;
+ }
+ }
+ }
+ }
+ else if( ( pObject->GetObjInventor() == SdrInventor::Default ) && ( pObject->GetObjIdentifier() == SdrObjKind::Page ) )
+ {
+ // only for handout page, else this frame will be created for each
+ // page preview object in SlideSorter and PagePane
+ if(pObjectsSdPage && PageKind::Handout == pObjectsSdPage->GetPageKind())
+ {
+ bCreateOutline = true;
+ }
+ }
+
+ if(bCreateOutline)
+ {
+ // empty presentation objects get a gray frame
+ const svtools::ColorConfig aColorConfig;
+ const svtools::ColorConfigValue aColor( aColorConfig.GetColorValue( svtools::OBJECTBOUNDARIES ) );
+
+ if( aColor.bIsVisible )
+ {
+ // get basic object transformation
+ const basegfx::BColor aRGBColor(aColor.nColor.getBColor());
+ basegfx::B2DHomMatrix aObjectMatrix;
+ basegfx::B2DPolyPolygon aObjectPolyPolygon;
+ pObject->TRGetBaseGeometry(aObjectMatrix, aObjectPolyPolygon);
+
+ // create dashed border
+ {
+ // create object polygon
+ basegfx::B2DPolygon aPolygon(basegfx::utils::createUnitPolygon());
+ aPolygon.transform(aObjectMatrix);
+
+ // create line and stroke attribute
+ ::std::vector< double > aDotDashArray { 160.0, 80.0 };
+
+ const double fFullDotDashLen(::std::accumulate(aDotDashArray.begin(), aDotDashArray.end(), 0.0));
+ const drawinglayer::attribute::LineAttribute aLine(aRGBColor);
+ const drawinglayer::attribute::StrokeAttribute aStroke(std::move(aDotDashArray), fFullDotDashLen);
+
+ // create primitive and add
+ const drawinglayer::primitive2d::Primitive2DReference xRef(new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
+ aPolygon,
+ aLine,
+ aStroke));
+ rVisitor.visit(xRef);
+ }
+
+ // now paint the placeholder description, but only when masterpage
+ // is displayed as page directly (MasterPage view)
+ if(!bSubContentProcessing && bIsMasterPageObject)
+ {
+ OUString aObjectString;
+
+ switch( eKind )
+ {
+ case PresObjKind::Title:
+ {
+ if(pObjectsSdPage && pObjectsSdPage->GetPageKind() == PageKind::Standard)
+ {
+ static OUString aTitleAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_TITLE));
+ aObjectString = aTitleAreaStr;
+ }
+
+ break;
+ }
+ case PresObjKind::Outline:
+ {
+ static OUString aOutlineAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_OUTLINE));
+ aObjectString = aOutlineAreaStr;
+ break;
+ }
+ case PresObjKind::Footer:
+ {
+ static OUString aFooterAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_FOOTER));
+ aObjectString = aFooterAreaStr;
+ break;
+ }
+ case PresObjKind::Header:
+ {
+ static OUString aHeaderAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_HEADER));
+ aObjectString = aHeaderAreaStr;
+ break;
+ }
+ case PresObjKind::DateTime:
+ {
+ static OUString aDateTimeStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_DATETIME));
+ aObjectString = aDateTimeStr;
+ break;
+ }
+ case PresObjKind::Notes:
+ {
+ static OUString aDateTimeStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_NOTES));
+ aObjectString = aDateTimeStr;
+ break;
+ }
+ case PresObjKind::SlideNumber:
+ {
+ if(pObjectsSdPage && pObjectsSdPage->GetPageKind() == PageKind::Standard)
+ {
+ static OUString aSlideAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_SLIDE));
+ aObjectString = aSlideAreaStr;
+ }
+ else
+ {
+ static OUString aNumberAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_NUMBER));
+ aObjectString = aNumberAreaStr;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ if( !aObjectString.isEmpty() )
+ {
+ // decompose object matrix to be able to place text correctly
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate, fShearX;
+ aObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // create font
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObject );
+ const SdrTextVertAdjust eTVA(pTextObj ? pTextObj->GetTextVerticalAdjust() : SDRTEXTVERTADJUST_CENTER);
+ vcl::Font aScaledVclFont;
+
+ // use a text size factor to get more reliable text sizes from the text layouter
+ // (and from vcl), tipp from HDU
+ static const sal_uInt32 nTextSizeFactor(100);
+
+ // use a factor to get more linear text size calculations
+ aScaledVclFont.SetFontHeight( 500 * nTextSizeFactor );
+
+ // get basic geometry and get text size
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
+ aTextLayouter.setFont(aScaledVclFont);
+ const sal_Int32 nTextLength(aObjectString.getLength());
+
+ // do not forget to use the factor again to get the width for the 500
+ const double fTextWidth(aTextLayouter.getTextWidth(aObjectString, 0, nTextLength) * (1.0 / nTextSizeFactor));
+ const double fTextHeight(aTextLayouter.getTextHeight() * (1.0 / nTextSizeFactor));
+
+ // calculate text primitive position. If text is at bottom, use top for
+ // the extra text and vice versa
+ const double fHorDist(125);
+ const double fVerDist(125);
+ const double fPosX((aTranslate.getX() + aScale.getX()) - fTextWidth - fHorDist);
+ const double fPosY((SDRTEXTVERTADJUST_BOTTOM == eTVA)
+ ? aTranslate.getY() - fVerDist + fTextHeight
+ : (aTranslate.getY() + aScale.getY()) - fVerDist);
+
+ // get font attributes; use normally scaled font
+ vcl::Font aVclFont;
+ basegfx::B2DVector aTextSizeAttribute;
+
+ aVclFont.SetFontHeight( 500 );
+
+ const drawinglayer::attribute::FontAttribute aFontAttribute(
+ drawinglayer::primitive2d::getFontAttributeFromVclFont(
+ aTextSizeAttribute,
+ aVclFont,
+ false,
+ false));
+
+ // fill text matrix
+ const basegfx::B2DHomMatrix aTextMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aTextSizeAttribute.getX(), aTextSizeAttribute.getY(),
+ fShearX,
+ fRotate,
+ fPosX, fPosY));
+
+ // create DXTextArray (can be empty one)
+ ::std::vector< double > aDXArray{};
+
+ // create locale; this may need some more information in the future
+ const css::lang::Locale aLocale;
+
+ // create primitive and add
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aTextMatrix,
+ aObjectString,
+ 0,
+ nTextLength,
+ std::move(aDXArray),
+ aFontAttribute,
+ aLocale,
+ aRGBColor));
+ rVisitor.visit(xRef);
+ }
+ }
+ }
+ }
+ }
+
+ if(bDoCreateGeometry)
+ {
+ sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
+ rOriginal,
+ rDisplayInfo, rVisitor);
+ }
+}
+
+namespace
+{
+ void setOutlinerBgFromPage(::Outliner& rOutl, SdrPageView& rPgView, bool bScreenDisplay)
+ {
+ SdPage* pPage = static_cast<SdPage*>(rPgView.GetPage());
+ if (pPage)
+ {
+ // #i75566# Name change GetBackgroundColor -> GetPageBackgroundColor and
+ // hint value if screen display. Only then the AutoColor mechanisms shall be applied
+ rOutl.SetBackgroundColor(pPage->GetPageBackgroundColor(&rPgView, bScreenDisplay));
+ }
+ }
+}
+
+/**
+ * The event will be forwarded to the View
+ */
+void View::CompleteRedraw(OutputDevice* pOutDev, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector /*=0*/)
+{
+ // execute ??
+ if (mnLockRedrawSmph != 0)
+ return;
+
+ SdrPageView* pPgView = GetSdrPageView();
+
+ if (pPgView)
+ {
+ SdPage* pPage = static_cast<SdPage*>( pPgView->GetPage() );
+ if( pPage )
+ {
+ SdrOutliner& rOutl = mrDoc.GetDrawOutliner();
+ bool bScreenDisplay(true);
+
+ // #i75566# printing; suppress AutoColor BackgroundColor generation
+ // for visibility reasons by giving GetPageBackgroundColor()
+ // the needed hint
+ // #i75566# PDF export; suppress AutoColor BackgroundColor generation (see printing)
+ if (pOutDev && ((OUTDEV_PRINTER == pOutDev->GetOutDevType())
+ || (OUTDEV_PDF == pOutDev->GetOutDevType())))
+ bScreenDisplay = false;
+
+ setOutlinerBgFromPage(rOutl, *pPgView, bScreenDisplay);
+ }
+ }
+
+ ViewRedirector aViewRedirector;
+ FmFormView::CompleteRedraw(pOutDev, rReg, pRedirector ? pRedirector : &aViewRedirector);
+}
+
+void View::MarkListHasChanged()
+{
+ FmFormView::MarkListHasChanged();
+
+ if( GetMarkedObjectCount() > 0 )
+ maSmartTags.deselect();
+}
+
+bool View::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll, bool /*bSlide*/, bool /*bMaster*/)
+{
+ bool bOk = FmFormView::SetAttributes(rSet, bReplaceAll);
+ return bOk;
+}
+
+void View::GetAttributes( SfxItemSet& rTargetSet, bool bOnlyHardAttr ) const
+{
+ FmFormView::GetAttributes( rTargetSet, bOnlyHardAttr );
+}
+
+/**
+ * Is a presentation object selected?
+ */
+bool View::IsPresObjSelected(bool bOnPage, bool bOnMasterPage, bool bCheckPresObjListOnly, bool bCheckLayoutOnly) const
+{
+ SdrMarkList* pMarkList;
+
+ if (mnDragSrcPgNum != SDRPAGE_NOTFOUND &&
+ mnDragSrcPgNum != GetSdrPageView()->GetPage()->GetPageNum())
+ {
+ /* Drag&Drop is in progress
+ Source and destination page are different:
+ we use the saved mark list */
+ pMarkList = mpDragSrcMarkList.get();
+ }
+ else
+ {
+ // We use the current mark list
+ pMarkList = new SdrMarkList(GetMarkedObjectList());
+ }
+
+ SdrMark* pMark;
+ SdPage* pPage;
+
+ bool bSelected = false;
+ bool bMasterPage = false;
+
+ for (size_t nMark = pMarkList->GetMarkCount(); nMark && !bSelected; )
+ {
+ --nMark;
+ // Backwards through mark list
+ pMark = pMarkList->GetMark(nMark);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ if ( pObj && ( bCheckPresObjListOnly || pObj->IsEmptyPresObj() || pObj->GetUserCall() ) )
+ {
+ pPage = static_cast<SdPage*>( pObj->getSdrPageFromSdrObject() );
+ bMasterPage = pPage && pPage->IsMasterPage();
+
+ if ( (bMasterPage && bOnMasterPage) || (!bMasterPage && bOnPage) )
+ {
+ if ( pPage && pPage->IsPresObj(pObj) )
+ {
+ if( bCheckLayoutOnly )
+ {
+ PresObjKind eKind = pPage->GetPresObjKind(pObj);
+
+ if((eKind != PresObjKind::Footer) && (eKind != PresObjKind::Header) && (eKind != PresObjKind::DateTime) && (eKind != PresObjKind::SlideNumber) )
+ bSelected = true;
+ }
+ else
+ {
+ bSelected = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (pMarkList != mpDragSrcMarkList.get())
+ {
+ delete pMarkList;
+ }
+
+ return bSelected;
+}
+
+void View::SelectAll()
+{
+ if ( IsTextEdit() )
+ {
+ OutlinerView* pOLV = GetTextEditOutlinerView();
+ const ::Outliner* pOutliner = GetTextEditOutliner();
+ pOLV->SelectRange( 0, pOutliner->GetParagraphCount() );
+ }
+ else
+ {
+ MarkAll();
+ }
+}
+
+bool View::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
+{
+ // forward to SdrView
+ FmFormView::SetStyleSheet(pStyleSheet, bDontRemoveHardAttr);
+ return true;
+}
+
+/**
+ * Start text input
+ */
+static void SetSpellOptions( const SdDrawDocument& rDoc, EEControlBits& rCntrl )
+{
+ bool bOnlineSpell = rDoc.GetOnlineSpell();
+
+ if( bOnlineSpell )
+ rCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ rCntrl &= ~EEControlBits::ONLINESPELLING;
+}
+
+void OutlinerMasterViewFilter::Start(SdrOutliner *pOutl)
+{
+ m_pOutl = pOutl;
+ OutlinerView* pOutlView = m_pOutl->GetView(0);
+ m_bReadOnly = pOutlView->IsReadOnly();
+ pOutlView->SetReadOnly(true);
+}
+
+void OutlinerMasterViewFilter::End()
+{
+ if (m_pOutl)
+ {
+ OutlinerView* pOutlView = m_pOutl->GetView(0);
+ pOutlView->SetReadOnly(m_bReadOnly);
+ m_pOutl = nullptr;
+ }
+}
+
+SfxViewShell* View::GetSfxViewShell() const
+{
+ SfxViewShell* pRet = nullptr;
+
+ if (mpViewSh)
+ pRet = &mpViewSh->GetViewShellBase();
+
+ return pRet;
+}
+
+// Create a new view-local UndoManager manager for Impress/Draw
+std::unique_ptr<SdrUndoManager> View::createLocalTextUndoManager()
+{
+ std::unique_ptr<SdrUndoManager> pUndoManager(new sd::UndoManager);
+ pUndoManager->SetDocShell(mpDocSh);
+ return pUndoManager;
+}
+
+bool View::SdrBeginTextEdit(
+ SdrObject* pObj, SdrPageView* pPV, vcl::Window* pWin,
+ bool bIsNewObj,
+ SdrOutliner* pOutl, OutlinerView* pGivenOutlinerView,
+ bool bDontDeleteOutliner, bool bOnlyOneView, bool bGrabFocus )
+{
+ SdrPage* pPage = pObj ? pObj->getSdrPageFromSdrObject() : nullptr;
+ bool bMasterPage = pPage && pPage->IsMasterPage();
+
+ GetViewShell()->GetViewShellBase().GetEventMultiplexer()->MultiplexEvent(
+ EventMultiplexerEventId::BeginTextEdit, static_cast<void*>(pObj) );
+
+ if( pOutl==nullptr && pObj )
+ pOutl = SdrMakeOutliner(OutlinerMode::TextObject, pObj->getSdrModelFromSdrObject()).release();
+
+ // make draw&impress specific initialisations
+ if( pOutl )
+ {
+ pOutl->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>( mrDoc.GetStyleSheetPool() ));
+ pOutl->SetCalcFieldValueHdl(LINK(SD_MOD(), SdModule, CalcFieldValueHdl));
+ EEControlBits nCntrl = pOutl->GetControlWord();
+ nCntrl |= EEControlBits::ALLOWBIGOBJS;
+ nCntrl |= EEControlBits::MARKFIELDS;
+ nCntrl |= EEControlBits::AUTOCORRECT;
+
+ nCntrl &= ~EEControlBits::ULSPACESUMMATION;
+ if ( mrDoc.IsSummationOfParagraphs() )
+ nCntrl |= EEControlBits::ULSPACESUMMATION;
+
+ SetSpellOptions( mrDoc, nCntrl );
+
+ pOutl->SetControlWord(nCntrl);
+
+ Reference< linguistic2::XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() );
+ if ( xSpellChecker.is() )
+ pOutl->SetSpeller( xSpellChecker );
+
+ Reference< linguistic2::XHyphenator > xHyphenator( LinguMgr::GetHyphenator() );
+ if( xHyphenator.is() )
+ pOutl->SetHyphenator( xHyphenator );
+
+ pOutl->SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
+ }
+
+ bool bReturn = FmFormView::SdrBeginTextEdit(
+ pObj, pPV, pWin, bIsNewObj, pOutl,
+ pGivenOutlinerView, bDontDeleteOutliner,
+ bOnlyOneView, bGrabFocus);
+
+ if ( mpViewSh )
+ {
+ mpViewSh->GetViewShellBase().GetDrawController().FireSelectionChangeListener();
+
+ if (pObj && pObj->GetObjIdentifier() == SdrObjKind::Table)
+ mpViewSh->UpdateScrollBars();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (OutlinerView* pView = GetTextEditOutlinerView())
+ {
+ ::tools::Rectangle aRectangle = pView->GetOutputArea();
+ if (pWin && pWin->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ {
+ aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip);
+ }
+ OString sRectangle = aRectangle.toString();
+ SfxLokHelper::notifyOtherViews(&mpViewSh->GetViewShellBase(), LOK_CALLBACK_VIEW_LOCK, "rectangle", sRectangle);
+ }
+ }
+ }
+
+ if (::Outliner* pOL = bReturn ? GetTextEditOutliner() : nullptr)
+ {
+ if (pObj)
+ {
+ if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::Table )
+ {
+ Color aBackground = GetTextEditBackgroundColor(*this);
+ pOL->SetBackgroundColor( aBackground );
+ }
+ else
+ {
+ // tdf#148140 Set the background to determine autocolor.
+ // Use any explicit bg with fallback to underlying page if
+ // none found
+ if (!pObj->setSuitableOutlinerBg(*pOL) && pPV)
+ setOutlinerBgFromPage(*pOL, *pPV, true);
+ }
+ }
+
+ pOL->SetParaInsertedHdl(LINK(this, View, OnParagraphInsertedHdl));
+ pOL->SetParaRemovingHdl(LINK(this, View, OnParagraphRemovingHdl));
+ }
+
+ if (bMasterPage && bReturn && pOutl)
+ {
+ const SdrTextObj* pTextObj = pOutl->GetTextObj();
+ const SdPage* pSdPage = pTextObj ? static_cast<const SdPage*>(pTextObj->getSdrPageFromSdrObject()) : nullptr;
+ const PresObjKind eKind = pSdPage ? pSdPage->GetPresObjKind(const_cast<SdrTextObj*>(pTextObj)) : PresObjKind::NONE;
+ switch (eKind)
+ {
+ case PresObjKind::Title:
+ case PresObjKind::Outline:
+ case PresObjKind::Text:
+ maMasterViewFilter.Start(pOutl);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return bReturn;
+}
+
+/** ends current text editing */
+SdrEndTextEditKind View::SdrEndTextEdit(bool bDontDeleteReally)
+{
+ maMasterViewFilter.End();
+
+ ::tools::WeakReference<SdrTextObj> xObj( GetTextEditObject() );
+
+ bool bDefaultTextRestored = RestoreDefaultText( xObj.get() );
+
+ SdrEndTextEditKind eKind = FmFormView::SdrEndTextEdit(bDontDeleteReally);
+
+ if( bDefaultTextRestored )
+ {
+ if( xObj.is() && !xObj->IsEmptyPresObj() )
+ {
+ xObj->SetEmptyPresObj( true );
+ }
+ else
+ {
+ eKind = SdrEndTextEditKind::Unchanged;
+ }
+ }
+ else if( xObj.is() && xObj->IsEmptyPresObj() )
+ {
+ SdrTextObj* pObj = xObj.get();
+ if( pObj && pObj->HasText() )
+ {
+ SdrPage* pPage = pObj->getSdrPageFromSdrObject();
+ if( !pPage || !pPage->IsMasterPage() )
+ pObj->SetEmptyPresObj( false );
+ }
+ }
+
+ GetViewShell()->GetViewShellBase().GetEventMultiplexer()->MultiplexEvent(
+ EventMultiplexerEventId::EndTextEdit,
+ static_cast<void*>(xObj.get()) );
+
+ if( xObj.is() )
+ {
+ if ( mpViewSh )
+ {
+ mpViewSh->GetViewShellBase().GetDrawController().FireSelectionChangeListener();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ SfxLokHelper::notifyOtherViews(&mpViewSh->GetViewShellBase(), LOK_CALLBACK_VIEW_LOCK, "rectangle", "EMPTY");
+
+ }
+
+ SdPage* pPage = dynamic_cast< SdPage* >( xObj->getSdrPageFromSdrObject() );
+ if( pPage )
+ pPage->onEndTextEdit( xObj.get() );
+ }
+
+ return eKind;
+}
+
+/** restores the default text if the given text object is currently in edit mode and
+ no text has been entered already. Is only useful just before text edit ends. */
+bool View::RestoreDefaultText( SdrTextObj* pTextObj )
+{
+ bool bRestored = false;
+
+ if( pTextObj && (pTextObj == GetTextEditObject()) )
+ {
+ if( !pTextObj->HasText() )
+ {
+ SdPage* pPage = dynamic_cast< SdPage* >( pTextObj->getSdrPageFromSdrObject() );
+
+ if(pPage)
+ {
+ bRestored = pPage->RestoreDefaultText( pTextObj );
+ if( bRestored )
+ {
+ SdrOutliner* pOutliner = GetTextEditOutliner();
+ pTextObj->SetTextEditOutliner( pOutliner );
+ OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject();
+ if (pOutliner)
+ pOutliner->SetText(*pParaObj);
+ }
+ }
+ }
+ }
+
+ return bRestored;
+}
+
+/**
+ * Sets the original size of the marked objects.
+ */
+void View::SetMarkedOriginalSize()
+{
+ std::unique_ptr<SdrUndoGroup> pUndoGroup(new SdrUndoGroup(mrDoc));
+ const size_t nCount = GetMarkedObjectCount();
+ bool bOK = false;
+
+ for( size_t i = 0; i < nCount; ++i )
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(i);
+
+ if( pObj->GetObjInventor() == SdrInventor::Default )
+ {
+ if( pObj->GetObjIdentifier() == SdrObjKind::OLE2 )
+ {
+ uno::Reference < embed::XEmbeddedObject > xObj = static_cast<SdrOle2Obj*>(pObj)->GetObjRef();
+ if( xObj.is() )
+ {
+ // TODO/LEAN: working with VisualArea can switch object to running state
+
+ sal_Int64 nAspect = static_cast<SdrOle2Obj*>(pObj)->GetAspect();
+ Size aOleSize;
+
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ {
+ MapMode aMap100( MapUnit::Map100thMM );
+ aOleSize = static_cast<SdrOle2Obj*>(pObj)->GetOrigObjSize( &aMap100 );
+ bOK = true;
+ }
+ else
+ {
+ MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
+ try
+ {
+ awt::Size aSz = xObj->getVisualAreaSize( nAspect );
+ aOleSize = OutputDevice::LogicToLogic(Size(aSz.Width, aSz.Height), MapMode(aUnit), MapMode(MapUnit::Map100thMM));
+ bOK = true;
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {}
+ }
+
+ if ( bOK )
+ {
+ ::tools::Rectangle aDrawRect( pObj->GetLogicRect() );
+
+ pUndoGroup->AddAction( mrDoc.GetSdrUndoFactory().CreateUndoGeoObject( *pObj ) );
+ pObj->Resize( aDrawRect.TopLeft(), Fraction( aOleSize.Width(), aDrawRect.GetWidth() ),
+ Fraction( aOleSize.Height(), aDrawRect.GetHeight() ) );
+ }
+ }
+ }
+ else if( pObj->GetObjIdentifier() == SdrObjKind::Graphic )
+ {
+ const SdrGrafObj* pSdrGrafObj = static_cast< const SdrGrafObj* >(pObj);
+ const Size aSize = pSdrGrafObj->getOriginalSize( );
+ pUndoGroup->AddAction( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj ) );
+ ::tools::Rectangle aRect( pObj->GetLogicRect() );
+ aRect.SetSize( aSize );
+ pObj->SetLogicRect( aRect );
+ bOK = true;
+ }
+ }
+ }
+
+ if( bOK )
+ {
+ pUndoGroup->SetComment(SdResId(STR_UNDO_ORIGINALSIZE));
+ mpDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup));
+ }
+}
+
+/**
+ * Connect OLE object to client.
+ */
+void View::DoConnect(SdrOle2Obj* pObj)
+{
+ if (!mpViewSh)
+ return;
+
+ uno::Reference < embed::XEmbeddedObject > xObj( pObj->GetObjRef() );
+ if( !xObj.is() )
+ return;
+
+ ::sd::Window* pWindow = mpViewSh->GetActiveWindow();
+ SfxInPlaceClient* pSdClient = mpViewSh-> GetViewShellBase().FindIPClient( xObj, pWindow );
+ if ( pSdClient )
+ return;
+
+ pSdClient = new Client(pObj, mpViewSh, pWindow);
+ ::tools::Rectangle aRect = pObj->GetLogicRect();
+ {
+ // TODO/LEAN: working with visual area can switch object to running state
+ Size aDrawSize = aRect.GetSize();
+
+ MapMode aMapMode( mrDoc.GetScaleUnit() );
+ Size aObjAreaSize = pObj->GetOrigObjSize( &aMapMode );
+
+ Fraction aScaleWidth (aDrawSize.Width(), aObjAreaSize.Width() );
+ Fraction aScaleHeight(aDrawSize.Height(), aObjAreaSize.Height() );
+ aScaleWidth.ReduceInaccurate(10); // compatible to SdrOle2Obj
+ aScaleHeight.ReduceInaccurate(10);
+ pSdClient->SetSizeScale(aScaleWidth, aScaleHeight);
+
+ // visible area is only changed in-place!
+ // the object area must be set after the scaling, since it triggers resize
+ aRect.SetSize(aObjAreaSize);
+ pSdClient->SetObjArea(aRect);
+ }
+}
+
+bool View::IsMorphingAllowed() const
+{
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ bool bRet = false;
+
+ if ( rMarkList.GetMarkCount() == 2 )
+ {
+ const SdrObject* pObj1 = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ const SdrObject* pObj2 = rMarkList.GetMark( 1 )->GetMarkedSdrObj();
+ const SdrObjKind nKind1 = pObj1->GetObjIdentifier();
+ const SdrObjKind nKind2 = pObj2->GetObjIdentifier();
+
+ if ( ( nKind1 != SdrObjKind::Text && nKind2 != SdrObjKind::Text ) &&
+ ( nKind1 != SdrObjKind::TitleText && nKind2 != SdrObjKind::TitleText ) &&
+ ( nKind1 != SdrObjKind::OutlineText && nKind2 != SdrObjKind::OutlineText ) &&
+ ( nKind1 != SdrObjKind::Group && nKind2 != SdrObjKind::Group ) &&
+ ( nKind1 != SdrObjKind::Line && nKind2 != SdrObjKind::Line ) &&
+ ( nKind1 != SdrObjKind::PolyLine && nKind2 != SdrObjKind::PolyLine ) &&
+ ( nKind1 != SdrObjKind::PathLine && nKind2 != SdrObjKind::PathLine ) &&
+ ( nKind1 != SdrObjKind::FreehandLine && nKind2 != SdrObjKind::FreehandLine ) &&
+ ( nKind1 != SdrObjKind::PathPolyLine && nKind2 != SdrObjKind::PathPolyLine ) &&
+ ( nKind1 != SdrObjKind::Measure && nKind2 != SdrObjKind::Measure ) &&
+ ( nKind1 != SdrObjKind::Edge && nKind2 != SdrObjKind::Edge ) &&
+ ( nKind1 != SdrObjKind::Graphic && nKind2 != SdrObjKind::Graphic ) &&
+ ( nKind1 != SdrObjKind::OLE2 && nKind2 != SdrObjKind::OLE2 ) &&
+ ( nKind1 != SdrObjKind::Caption && nKind2 != SdrObjKind::Caption ) &&
+ dynamic_cast< const E3dObject *>( pObj1 ) == nullptr && dynamic_cast< const E3dObject *>( pObj2 ) == nullptr )
+ {
+ SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLSTYLE> aSet1( mrDoc.GetPool() );
+ SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLSTYLE> aSet2( mrDoc.GetPool() );
+
+ aSet1.Put(pObj1->GetMergedItemSet());
+ aSet2.Put(pObj2->GetMergedItemSet());
+
+ const drawing::FillStyle eFillStyle1 = aSet1.Get( XATTR_FILLSTYLE ).GetValue();
+ const drawing::FillStyle eFillStyle2 = aSet2.Get( XATTR_FILLSTYLE ).GetValue();
+
+ if( ( eFillStyle1 == drawing::FillStyle_NONE || eFillStyle1 == drawing::FillStyle_SOLID ) &&
+ ( eFillStyle2 == drawing::FillStyle_NONE || eFillStyle2 == drawing::FillStyle_SOLID ) )
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+bool View::IsVectorizeAllowed() const
+{
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ bool bRet = false;
+
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ const SdrGrafObj* pObj = dynamic_cast< const SdrGrafObj* >(rMarkList.GetMark( 0 )->GetMarkedSdrObj());
+
+ if(pObj)
+ {
+ if(GraphicType::Bitmap == pObj->GetGraphicType() && !pObj->isEmbeddedVectorGraphicData())
+ {
+ bRet = true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void View::onAccessibilityOptionsChanged()
+{
+ if( !mpViewSh )
+ return;
+
+ ::sd::Window* pWindow = mpViewSh->GetActiveWindow();
+ if( !pWindow )
+ return;
+
+ const StyleSettings& rStyleSettings = pWindow->GetSettings().GetStyleSettings();
+
+ if( mpViewSh->GetViewFrame() && mpViewSh->GetViewFrame()->GetDispatcher() )
+ {
+ sal_uInt16 nOutputSlot, nPreviewSlot;
+
+ if( rStyleSettings.GetHighContrastMode() )
+ {
+ nOutputSlot = SID_OUTPUT_QUALITY_CONTRAST;
+ }
+ else
+ {
+ nOutputSlot = SID_OUTPUT_QUALITY_COLOR;
+ }
+
+ if( rStyleSettings.GetHighContrastMode()
+ && officecfg::Office::Common::Accessibility::IsForPagePreviews::get() )
+ {
+ nPreviewSlot = SID_PREVIEW_QUALITY_CONTRAST;
+ }
+ else
+ {
+ nPreviewSlot = SID_PREVIEW_QUALITY_COLOR;
+ }
+
+ mpViewSh->GetViewFrame()->GetDispatcher()->Execute( nOutputSlot, SfxCallMode::ASYNCHRON );
+ mpViewSh->GetViewFrame()->GetDispatcher()->Execute( nPreviewSlot, SfxCallMode::ASYNCHRON );
+ }
+
+ mpViewSh->Invalidate();
+}
+
+IMPL_LINK( View, OnParagraphInsertedHdl, ::Outliner::ParagraphHdlParam, aParam, void )
+{
+ SdrObject* pObj = GetTextEditObject();
+
+ if( aParam.pPara && pObj )
+ {
+ SdPage* pPage = dynamic_cast< SdPage* >( pObj->getSdrPageFromSdrObject() );
+ if( pPage )
+ pPage->onParagraphInserted( aParam.pOutliner, aParam.pPara, pObj );
+ }
+}
+
+/**
+ * Handler for the deletion of the pages (paragraphs).
+ */
+IMPL_LINK( View, OnParagraphRemovingHdl, ::Outliner::ParagraphHdlParam, aParam, void )
+{
+ SdrObject* pObj = GetTextEditObject();
+
+ if( aParam.pPara && pObj )
+ {
+ SdPage* pPage = dynamic_cast< SdPage* >( pObj->getSdrPageFromSdrObject() );
+ if( pPage )
+ pPage->onParagraphRemoving( aParam.pOutliner, aParam.pPara, pObj );
+ }
+}
+
+bool View::isRecordingUndo() const
+{
+ if( mrDoc.IsUndoEnabled() )
+ {
+ sd::UndoManager* pUndoManager = mrDoc.GetUndoManager();
+ return pUndoManager && pUndoManager->IsInListAction();
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void View::AddCustomHdl()
+{
+ maSmartTags.addCustomHandles( maHdlList );
+}
+
+void View::updateHandles()
+{
+ AdjustMarkHdl();
+}
+
+SdrViewContext View::GetContext() const
+{
+ SdrViewContext eContext = SdrViewContext::Standard;
+ if( maSmartTags.getContext( eContext ) )
+ return eContext;
+ else
+ return FmFormView::GetContext();
+}
+
+bool View::HasMarkablePoints() const
+{
+ if( maSmartTags.HasMarkablePoints() )
+ return true;
+ else
+ return FmFormView::HasMarkablePoints();
+}
+
+sal_Int32 View::GetMarkablePointCount() const
+{
+ sal_Int32 nCount = FmFormView::GetMarkablePointCount();
+ nCount += maSmartTags.GetMarkablePointCount();
+ return nCount;
+}
+
+bool View::HasMarkedPoints() const
+{
+ if( maSmartTags.HasMarkedPoints() )
+ return true;
+ else
+ return FmFormView::HasMarkedPoints();
+}
+
+bool View::MarkPoint(SdrHdl& rHdl, bool bUnmark )
+{
+ if( maSmartTags.MarkPoint( rHdl, bUnmark ) )
+ return true;
+ else
+ return FmFormView::MarkPoint( rHdl, bUnmark );
+}
+
+bool View::MarkPoints(const ::tools::Rectangle* pRect, bool bUnmark)
+{
+ if( maSmartTags.MarkPoints( pRect, bUnmark ) )
+ return true;
+ else
+ return FmFormView::MarkPoints( pRect, bUnmark );
+}
+
+void View::CheckPossibilities()
+{
+ FmFormView::CheckPossibilities();
+ maSmartTags.CheckPossibilities();
+}
+
+void View::OnBeginPasteOrDrop( PasteOrDropInfos* pInfo )
+{
+ SdrOutliner* pOutliner = GetTextEditOutliner();
+ if (!pOutliner)
+ return;
+
+ // Turn character attributes of the paragraph of the insert position into
+ // character-level attributes, so they are not lost when OnEndPasteOrDrop()
+ // sets the paragraph stylesheet.
+ SfxItemSet aSet(pOutliner->GetParaAttribs(pInfo->nStartPara));
+ pOutliner->SetCharAttribs(pInfo->nStartPara, aSet);
+}
+
+/** this is called after a paste or drop operation, make sure that the newly inserted paragraphs
+ get the correct style sheet. */
+void View::OnEndPasteOrDrop( PasteOrDropInfos* pInfo )
+{
+ /* Style Sheet handling */
+ SdrTextObj* pTextObj = GetTextEditObject();
+ SdrOutliner* pOutliner = GetTextEditOutliner();
+ if( !pOutliner || !pTextObj || !pTextObj->getSdrPageFromSdrObject() )
+ return;
+
+ SdPage* pPage = static_cast< SdPage* >( pTextObj->getSdrPageFromSdrObject() );
+ const PresObjKind eKind = pPage->GetPresObjKind(pTextObj);
+
+ // outline kinds are taken care of in Outliner::ImplSetLevelDependentStyleSheet
+ if( eKind == PresObjKind::Outline )
+ return;
+
+ SfxStyleSheet* pStyleSheet = nullptr;
+ if( eKind != PresObjKind::NONE )
+ pStyleSheet = pPage->GetStyleSheetForPresObj(eKind);
+ else
+ pStyleSheet = pTextObj->GetStyleSheet();
+ // just put the object style on each new paragraph
+ for ( sal_Int32 nPara = pInfo->nStartPara; nPara <= pInfo->nEndPara; nPara++ )
+ {
+ pOutliner->SetStyleSheet( nPara, pStyleSheet );
+ }
+}
+
+bool View::ShouldToggleOn(
+ const bool bBulletOnOffMode,
+ const bool bNormalBullet)
+{
+ // If setting bullets/numbering by the dialog, always should toggle on.
+ if (!bBulletOnOffMode)
+ return true;
+ SdrModel* pSdrModel = GetModel();
+ if (!pSdrModel)
+ return false;
+
+ bool bToggleOn = false;
+ std::unique_ptr<SdrOutliner> pOutliner(SdrMakeOutliner(OutlinerMode::TextObject, *pSdrModel));
+ const size_t nMarkCount = GetMarkedObjectCount();
+ for (size_t nIndex = 0; nIndex < nMarkCount && !bToggleOn; ++nIndex)
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >(GetMarkedObjectByIndex(nIndex));
+ if (!pTextObj || pTextObj->IsTextEditActive())
+ continue;
+ if( dynamic_cast< const SdrTableObj *>( pTextObj ) != nullptr)
+ {
+ SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >(pTextObj);
+ if (!pTableObj)
+ continue;
+ CellPos aStart, aEnd;
+ SvxTableController* pTableController = dynamic_cast< SvxTableController* >(getSelectionController().get());
+ if (pTableController)
+ {
+ pTableController->getSelectedCells(aStart, aEnd);
+ }
+ else
+ {
+ aStart = SdrTableObj::getFirstCell();
+ aEnd = pTableObj->getLastCell();
+ }
+ sal_Int32 nColCount = pTableObj->getColumnCount();
+ for (sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow && !bToggleOn; nRow++)
+ {
+ for (sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol && !bToggleOn; nCol++)
+ {
+ sal_Int32 nCellIndex = nRow * nColCount + nCol;
+ SdrText* pText = pTableObj->getText(nCellIndex);
+ if (!pText || !pText->GetOutlinerParaObject())
+ continue;
+ pOutliner->SetText(*(pText->GetOutlinerParaObject()));
+ sal_Int16 nStatus = pOutliner->GetBulletsNumberingStatus();
+ bToggleOn = (bNormalBullet && nStatus != 0) || (!bNormalBullet && nStatus != 1);
+ pOutliner->Clear();
+ }
+ }
+ }
+ else
+ {
+ OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject();
+ if (!pParaObj)
+ continue;
+ pOutliner->SetText(*pParaObj);
+ sal_Int16 nStatus = pOutliner->GetBulletsNumberingStatus();
+ bToggleOn = (bNormalBullet && nStatus != 0) || (!bNormalBullet && nStatus != 1);
+ pOutliner->Clear();
+ }
+ }
+ return bToggleOn;
+}
+
+void View::ChangeMarkedObjectsBulletsNumbering(
+ const bool bToggle,
+ const bool bHandleBullets,
+ const SvxNumRule* pNumRule )
+{
+ SdrModel* pSdrModel = GetModel();
+ OutputDevice* pOut = GetFirstOutputDevice();
+ vcl::Window* pWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
+ if (!pSdrModel || !pWindow)
+ return;
+
+ const bool bUndoEnabled = pSdrModel->IsUndoEnabled();
+ std::unique_ptr<SdrUndoGroup> pUndoGroup(bUndoEnabled ? new SdrUndoGroup(*pSdrModel) : nullptr);
+
+ const bool bToggleOn = ShouldToggleOn( bToggle, bHandleBullets );
+
+ std::unique_ptr<SdrOutliner> pOutliner(SdrMakeOutliner(OutlinerMode::TextObject, *pSdrModel));
+ OutlinerView aOutlinerView(pOutliner.get(), pWindow);
+
+ const size_t nMarkCount = GetMarkedObjectCount();
+ for (size_t nIndex = 0; nIndex < nMarkCount; ++nIndex)
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >(GetMarkedObjectByIndex(nIndex));
+ if (!pTextObj || pTextObj->IsTextEditActive())
+ continue;
+ if( dynamic_cast< SdrTableObj *>( pTextObj ) != nullptr)
+ {
+ SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >(pTextObj);
+ if (!pTableObj)
+ continue;
+ CellPos aStart, aEnd;
+ SvxTableController* pTableController = dynamic_cast< SvxTableController* >(getSelectionController().get());
+ if (pTableController)
+ {
+ pTableController->getSelectedCells(aStart, aEnd);
+ }
+ else
+ {
+ aStart = SdrTableObj::getFirstCell();
+ aEnd = pTableObj->getLastCell();
+ }
+ sal_Int32 nColCount = pTableObj->getColumnCount();
+ for (sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++)
+ {
+ for (sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++)
+ {
+ sal_Int32 nCellIndex = nRow * nColCount + nCol;
+ SdrText* pText = pTableObj->getText(nCellIndex);
+ if (!pText || !pText->GetOutlinerParaObject())
+ continue;
+
+ pOutliner->SetText(*(pText->GetOutlinerParaObject()));
+ if (bUndoEnabled)
+ {
+ pUndoGroup->AddAction(pSdrModel->GetSdrUndoFactory().CreateUndoObjectSetText(*pTextObj, nCellIndex));
+ }
+ if ( !bToggleOn )
+ {
+ aOutlinerView.SwitchOffBulletsNumbering();
+ }
+ else
+ {
+ aOutlinerView.ApplyBulletsNumbering( bHandleBullets, pNumRule, bToggle );
+ }
+ sal_uInt32 nParaCount = pOutliner->GetParagraphCount();
+ pText->SetOutlinerParaObject(pOutliner->CreateParaObject(0, static_cast<sal_uInt16>(nParaCount)));
+ pOutliner->Clear();
+ }
+ }
+ // Broadcast the object change event.
+ if (!pTextObj->AdjustTextFrameWidthAndHeight())
+ {
+ pTextObj->SetChanged();
+ pTextObj->BroadcastObjectChange();
+ }
+ }
+ else
+ {
+ OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject();
+ if (!pParaObj)
+ continue;
+ pOutliner->SetText(*pParaObj);
+ if (bUndoEnabled)
+ {
+ pUndoGroup->AddAction(
+ pSdrModel->GetSdrUndoFactory().CreateUndoObjectSetText(*pTextObj, 0));
+ }
+ if ( !bToggleOn )
+ {
+ aOutlinerView.SwitchOffBulletsNumbering();
+ }
+ else
+ {
+ aOutlinerView.ApplyBulletsNumbering( bHandleBullets, pNumRule, bToggle );
+ }
+ sal_uInt32 nParaCount = pOutliner->GetParagraphCount();
+ pTextObj->SetOutlinerParaObject(pOutliner->CreateParaObject(0, static_cast<sal_uInt16>(nParaCount)));
+ pOutliner->Clear();
+ }
+ }
+
+ if ( bUndoEnabled && pUndoGroup->GetActionCount() > 0 )
+ {
+ pSdrModel->BegUndo();
+ pSdrModel->AddUndo(std::move(pUndoGroup));
+ pSdrModel->EndUndo();
+ }
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/sdview2.cxx b/sd/source/ui/view/sdview2.cxx
new file mode 100644
index 000000000..a5b3d4413
--- /dev/null
+++ b/sd/source/ui/view/sdview2.cxx
@@ -0,0 +1,908 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <View.hxx>
+
+#include <vector>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <comphelper/sequenceashashmap.hxx>
+#include <tools/urlobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svxdlg.hxx>
+#include <sfx2/docfile.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdpagv.hxx>
+#include <svl/urlbmk.hxx>
+#include <editeng/outliner.hxx>
+#include <svx/xflclit.hxx>
+#include <sot/formats.hxx>
+#include <editeng/editeng.hxx>
+
+#include <svtools/embedtransfer.hxx>
+#include <tools/debug.hxx>
+
+#include <anminfo.hxx>
+#include <strings.hrc>
+#include <sdxfer.hxx>
+#include <sdresid.hxx>
+#include <sdmod.hxx>
+#include <sdtreelb.hxx>
+#include <DrawViewShell.hxx>
+#include <DrawDocShell.hxx>
+#include <fudraw.hxx>
+#include <drawdoc.hxx>
+#include <Window.hxx>
+#include <sdpage.hxx>
+#include <unoaprms.hxx>
+#include <helpids.h>
+#include <vcl/svapp.hxx>
+
+#include <slideshow.hxx>
+#include <memory>
+
+namespace sd {
+
+using namespace ::com::sun::star;
+
+namespace {
+
+struct SdNavigatorDropEvent : public ExecuteDropEvent
+{
+ VclPtr< ::sd::Window> mpTargetWindow;
+
+ SdNavigatorDropEvent (
+ const ExecuteDropEvent& rEvt,
+ ::sd::Window* pTargetWindow )
+ : ExecuteDropEvent( rEvt ),
+ mpTargetWindow( pTargetWindow )
+ {}
+};
+
+}
+
+css::uno::Reference< css::datatransfer::XTransferable > View::CreateClipboardDataObject()
+{
+ // since SdTransferable::CopyToClipboard is called, this
+ // dynamically created object is destroyed automatically
+ rtl::Reference<SdTransferable> pTransferable = new SdTransferable( &mrDoc, nullptr, false );
+
+ SD_MOD()->pTransferClip = pTransferable.get();
+
+ mrDoc.CreatingDataObj( pTransferable.get() );
+ pTransferable->SetWorkDocument( static_cast<SdDrawDocument*>(CreateMarkedObjModel().release()) );
+ mrDoc.CreatingDataObj( nullptr );
+
+ // #112978# need to use GetAllMarkedBoundRect instead of GetAllMarkedRect to get
+ // fat lines correctly
+ const ::tools::Rectangle aMarkRect( GetAllMarkedBoundRect() );
+ std::unique_ptr<TransferableObjectDescriptor> pObjDesc(new TransferableObjectDescriptor);
+ SdrOle2Obj* pSdrOleObj = nullptr;
+ SdrPageView* pPgView = GetSdrPageView();
+ SdPage* pOldPage = pPgView ? static_cast<SdPage*>( pPgView->GetPage() ) : nullptr;
+ SdPage* pNewPage = const_cast<SdPage*>(static_cast<const SdPage*>( pTransferable->GetWorkDocument()->GetPage( 0 ) ));
+
+ if( pOldPage )
+ {
+ pNewPage->SetSize( pOldPage->GetSize() );
+ pNewPage->SetLayoutName( pOldPage->GetLayoutName() );
+ }
+
+ if( GetMarkedObjectCount() == 1 )
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(0);
+
+ if( auto pOle2Obj = dynamic_cast<SdrOle2Obj *>( pObj ) )
+ if( pOle2Obj->GetObjRef() )
+ {
+ // If object has no persistence it must be copied as part of the document
+ try
+ {
+ uno::Reference< embed::XEmbedPersist > xPersObj( pOle2Obj->GetObjRef(), uno::UNO_QUERY );
+ if ( xPersObj.is() && xPersObj->hasEntry() )
+ pSdrOleObj = pOle2Obj;
+ }
+ catch( uno::Exception& )
+ {}
+ }
+ }
+
+ if( pSdrOleObj )
+ SvEmbedTransferHelper::FillTransferableObjectDescriptor( *pObjDesc, pSdrOleObj->GetObjRef(), pSdrOleObj->GetGraphic(), pSdrOleObj->GetAspect() );
+ else
+ pTransferable->GetWorkDocument()->GetDocSh()->FillTransferableObjectDescriptor( *pObjDesc );
+
+ if( mpDocSh )
+ pObjDesc->maDisplayName = mpDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+
+ pObjDesc->maSize = aMarkRect.GetSize();
+
+ pTransferable->SetStartPos( aMarkRect.TopLeft() );
+ pTransferable->SetObjectDescriptor( std::move(pObjDesc) );
+ pTransferable->CopyToClipboard( mpViewSh->GetActiveWindow() );
+
+ return pTransferable;
+}
+
+css::uno::Reference< css::datatransfer::XTransferable > View::CreateDragDataObject( View* pWorkView, vcl::Window& rWindow, const Point& rDragPos )
+{
+ rtl::Reference<SdTransferable> pTransferable = new SdTransferable( &mrDoc, pWorkView, false );
+
+ SD_MOD()->pTransferDrag = pTransferable.get();
+
+ std::unique_ptr<TransferableObjectDescriptor> pObjDesc(new TransferableObjectDescriptor);
+ OUString aDisplayName;
+ SdrOle2Obj* pSdrOleObj = nullptr;
+
+ if( GetMarkedObjectCount() == 1 )
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex( 0 );
+
+ if( auto pOle2Obj = dynamic_cast<SdrOle2Obj *>( pObj ) )
+ if( pOle2Obj->GetObjRef() )
+ {
+ // If object has no persistence it must be copied as part of the document
+ try
+ {
+ uno::Reference< embed::XEmbedPersist > xPersObj( pOle2Obj->GetObjRef(), uno::UNO_QUERY );
+ if ( xPersObj.is() && xPersObj->hasEntry() )
+ pSdrOleObj = pOle2Obj;
+ }
+ catch( uno::Exception& )
+ {}
+ }
+ }
+
+ if( mpDocSh )
+ aDisplayName = mpDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+
+ if( pSdrOleObj )
+ SvEmbedTransferHelper::FillTransferableObjectDescriptor( *pObjDesc, pSdrOleObj->GetObjRef(), pSdrOleObj->GetGraphic(), pSdrOleObj->GetAspect() );
+ else if (mpDocSh)
+ mpDocSh->FillTransferableObjectDescriptor( *pObjDesc );
+
+ pObjDesc->maSize = GetAllMarkedRect().GetSize();
+ pObjDesc->maDragStartPos = rDragPos;
+ pObjDesc->maDisplayName = aDisplayName;
+
+ pTransferable->SetStartPos( rDragPos );
+ pTransferable->SetObjectDescriptor( std::move(pObjDesc) );
+ pTransferable->StartDrag( &rWindow, DND_ACTION_COPYMOVE | DND_ACTION_LINK );
+
+ return pTransferable;
+}
+
+css::uno::Reference< css::datatransfer::XTransferable > View::CreateSelectionDataObject( View* pWorkView )
+{
+ rtl::Reference<SdTransferable> pTransferable = new SdTransferable( &mrDoc, pWorkView, true );
+ std::unique_ptr<TransferableObjectDescriptor> pObjDesc(new TransferableObjectDescriptor);
+ const ::tools::Rectangle aMarkRect( GetAllMarkedRect() );
+
+ SD_MOD()->pTransferSelection = pTransferable.get();
+
+ if( mpDocSh )
+ {
+ mpDocSh->FillTransferableObjectDescriptor( *pObjDesc );
+ pObjDesc->maDisplayName = mpDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ }
+
+ pObjDesc->maSize = aMarkRect.GetSize();
+
+ pTransferable->SetStartPos( aMarkRect.TopLeft() );
+ pTransferable->SetObjectDescriptor( std::move(pObjDesc) );
+ pTransferable->CopyToPrimarySelection();
+
+ return pTransferable;
+}
+
+void View::UpdateSelectionClipboard() // false case
+{
+ if (!mpViewSh)
+ return;
+ if (!mpViewSh->GetActiveWindow())
+ return;
+ if (GetMarkedObjectList().GetMarkCount())
+ CreateSelectionDataObject( this );
+ else
+ ClearSelectionClipboard();
+}
+
+void View::ClearSelectionClipboard() // true case
+{
+ if (!mpViewSh)
+ return;
+ if (!mpViewSh->GetActiveWindow())
+ return;
+ if (SD_MOD()->pTransferSelection && SD_MOD()->pTransferSelection->GetView() == this)
+ {
+ TransferableHelper::ClearPrimarySelection();
+ SD_MOD()->pTransferSelection = nullptr;
+ }
+}
+
+void View::DoCut()
+{
+ const OutlinerView* pOLV = GetTextEditOutlinerView();
+
+ if( pOLV )
+ const_cast<OutlinerView*>(pOLV)->Cut();
+ else if( AreObjectsMarked() )
+ {
+ OUString aStr(SdResId(STR_UNDO_CUT));
+
+ DoCopy();
+ BegUndo(aStr + " " + GetDescriptionOfMarkedObjects());
+ DeleteMarked();
+ EndUndo();
+ }
+}
+
+void View::DoCopy()
+{
+ const OutlinerView* pOLV = GetTextEditOutlinerView();
+
+ if( pOLV )
+ const_cast<OutlinerView*>(pOLV)->Copy();
+ else if( AreObjectsMarked() )
+ {
+ BrkAction();
+ CreateClipboardDataObject();
+ }
+}
+
+void View::DoPaste (::sd::Window* pWindow)
+{
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( mpViewSh->GetActiveWindow() ) );
+ if( !aDataHelper.GetTransferable().is() )
+ return; // empty clipboard?
+
+ const OutlinerView* pOLV = GetTextEditOutlinerView();
+
+ if( pOLV && EditEngine::HasValidData( aDataHelper.GetTransferable() ) )
+ {
+ const_cast< OutlinerView* >(pOLV)->PasteSpecial();
+
+ SdrObject* pObj = GetTextEditObject();
+ SdPage* pPage = static_cast<SdPage*>( pObj ? pObj->getSdrPageFromSdrObject() : nullptr );
+ ::Outliner* pOutliner = pOLV->GetOutliner();
+
+ if( pOutliner)
+ {
+ if( pObj && pPage && pPage->GetPresObjKind(pObj) == PresObjKind::Title )
+ {
+ // remove all hard linebreaks from the title
+ if (pOutliner->GetParagraphCount() > 1)
+ {
+ bool bOldUpdateMode = pOutliner->SetUpdateLayout( false );
+
+ const EditEngine& rEdit = pOutliner->GetEditEngine();
+ const sal_Int32 nParaCount = rEdit.GetParagraphCount();
+
+ for( sal_Int32 nPara = nParaCount - 2; nPara >= 0; nPara-- )
+ {
+ const sal_Int32 nParaLen = rEdit.GetTextLen( nPara );
+ pOutliner->QuickDelete( ESelection( nPara, nParaLen, nPara+1, 0 ) );
+ pOutliner->QuickInsertLineBreak( ESelection( nPara, nParaLen, nPara, nParaLen ) );
+ }
+
+ DBG_ASSERT( rEdit.GetParagraphCount() <= 1, "Titleobject contains hard line breaks" );
+ pOutliner->SetUpdateLayout(bOldUpdateMode);
+ }
+ }
+
+ if( !mrDoc.IsChanged() )
+ {
+ if (pOutliner->IsModified())
+ mrDoc.SetChanged();
+ }
+ }
+ }
+ else
+ {
+ Point aPos = pWindow->GetVisibleCenter();
+ DrawViewShell* pDrViewSh = static_cast<DrawViewShell*>( mpDocSh->GetViewShell() );
+
+ if (pDrViewSh != nullptr)
+ {
+ sal_Int8 nDnDAction = DND_ACTION_COPY;
+ if( !InsertData( aDataHelper, aPos, nDnDAction, false ) )
+ {
+ INetBookmark aINetBookmark( "", "" );
+
+ if( ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) ) ||
+ ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::FILEGRPDESCRIPTOR, aINetBookmark ) ) ||
+ ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::UNIFORMRESOURCELOCATOR, aINetBookmark ) ) )
+ {
+ pDrViewSh->InsertURLField( aINetBookmark.GetURL(), aINetBookmark.GetDescription(), "" );
+ }
+ }
+ }
+ }
+}
+
+void View::StartDrag( const Point& rStartPos, vcl::Window* pWindow )
+{
+ if (!AreObjectsMarked() || !IsAction() || !mpViewSh || !pWindow)
+ return;
+
+ BrkAction();
+
+ if( IsTextEdit() )
+ SdrEndTextEdit();
+
+ if (DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(mpDocSh ? mpDocSh->GetViewShell() : nullptr))
+ {
+ const rtl::Reference<FuPoor>& xFunction(pDrawViewShell->GetCurrentFunction());
+ if (FuDraw* pFunction = dynamic_cast<FuDraw*>(xFunction.get()))
+ pFunction->ForcePointer();
+ }
+
+ mpDragSrcMarkList.reset( new SdrMarkList(GetMarkedObjectList()) );
+ mnDragSrcPgNum = GetSdrPageView()->GetPage()->GetPageNum();
+
+ CreateDragDataObject( this, *pWindow, rStartPos );
+}
+
+void View::DragFinished( sal_Int8 nDropAction )
+{
+ const bool bUndo = IsUndoEnabled();
+ const bool bGroupUndo = bUndo && mpDragSrcMarkList;
+ if (bGroupUndo)
+ {
+ OUString aStr(SdResId(STR_UNDO_DRAGDROP));
+ BegUndo(aStr + " " + mpDragSrcMarkList->GetMarkDescription());
+ }
+
+ SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
+
+ if( pDragTransferable )
+ pDragTransferable->SetView( nullptr );
+
+ if( ( nDropAction & DND_ACTION_MOVE ) &&
+ pDragTransferable && !pDragTransferable->IsInternalMove() &&
+ mpDragSrcMarkList && mpDragSrcMarkList->GetMarkCount() &&
+ !IsPresObjSelected() )
+ {
+ mpDragSrcMarkList->ForceSort();
+
+ if( bUndo )
+ BegUndo();
+
+ const size_t nCnt = mpDragSrcMarkList->GetMarkCount();
+
+ for( size_t nm = nCnt; nm>0; )
+ {
+ --nm;
+ SdrMark* pM=mpDragSrcMarkList->GetMark(nm);
+ if( bUndo )
+ AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeleteObject(*pM->GetMarkedSdrObj()));
+ }
+
+ mpDragSrcMarkList->GetMark(0)->GetMarkedSdrObj()->GetOrdNum();
+
+ for (size_t nm = nCnt; nm>0;)
+ {
+ --nm;
+ SdrMark* pM=mpDragSrcMarkList->GetMark(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+
+ if( pObj && pObj->getSdrPageFromSdrObject() )
+ {
+ const size_t nOrdNum = pObj->GetOrdNumDirect();
+ SdrObject* pChkObj = pObj->getSdrPageFromSdrObject()->RemoveObject(nOrdNum);
+ DBG_ASSERT(pChkObj==pObj,"pChkObj!=pObj in RemoveObject()");
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+ }
+
+ if( pDragTransferable )
+ pDragTransferable->SetInternalMove( false );
+
+ if (bGroupUndo)
+ EndUndo();
+ mnDragSrcPgNum = SDRPAGE_NOTFOUND;
+ mpDragSrcMarkList.reset();
+}
+
+sal_Int8 View::AcceptDrop( const AcceptDropEvent& rEvt, DropTargetHelper& rTargetHelper,
+ SdrLayerID nLayer )
+{
+ OUString aLayerName = GetActiveLayer();
+ SdrPageView* pPV = GetSdrPageView();
+ sal_Int8 nDropAction = rEvt.mnAction;
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( nLayer != SDRLAYER_NOTFOUND )
+ {
+ SdrLayerAdmin& rLayerAdmin = mrDoc.GetLayerAdmin();
+ aLayerName = rLayerAdmin.GetLayerPerID(nLayer)->GetName();
+ }
+
+ if( mbIsDropAllowed && !pPV->IsLayerLocked( aLayerName ) && pPV->IsLayerVisible( aLayerName ) )
+ {
+ const OutlinerView* pOLV = GetTextEditOutlinerView();
+ bool bIsInsideOutlinerView = false;
+
+ if( pOLV )
+ {
+ ::tools::Rectangle aRect( pOLV->GetOutputArea() );
+
+ if (GetMarkedObjectCount() == 1)
+ {
+ SdrMark* pMark = GetSdrMarkByIndex(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+ aRect.Union( pObj->GetLogicRect() );
+ }
+
+ if( aRect.Contains( pOLV->GetWindow()->PixelToLogic( rEvt.maPosPixel ) ) )
+ {
+ bIsInsideOutlinerView = true;
+ }
+ }
+
+ if( !bIsInsideOutlinerView )
+ {
+ SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
+
+ if(pDragTransferable && (nDropAction & DND_ACTION_LINK))
+ {
+ // suppress own data when it's intention is to use it as fill information
+ pDragTransferable = nullptr;
+ }
+
+ if( pDragTransferable )
+ {
+ const View* pSourceView = pDragTransferable->GetView();
+
+ if( pDragTransferable->IsPageTransferable() )
+ {
+ nRet = DND_ACTION_COPY;
+ }
+ else if( pSourceView )
+ {
+ if( !( nDropAction & DND_ACTION_LINK ) ||
+ !pSourceView->GetDocSh()->GetMedium()->GetName().isEmpty() )
+ {
+ nRet = nDropAction;
+ }
+ }
+ }
+ else
+ {
+ const bool bDrawing = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::DRAWING );
+ const bool bGraphic = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::SVXB );
+ const bool bMtf = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::GDIMETAFILE );
+ const bool bBitmap = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::BITMAP );
+ bool bBookmark = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ bool bXFillExchange = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::XFA );
+
+ // check handle insert
+ if ((bXFillExchange && (SdrDragMode::Gradient == GetDragMode()))
+ || (SdrDragMode::Transparence == GetDragMode()))
+ {
+ const SdrHdlList& rHdlList = GetHdlList();
+
+ for( size_t n = 0; n < rHdlList.GetHdlCount(); ++n )
+ {
+ SdrHdl* pIAOHandle = rHdlList.GetHdl( n );
+
+ if( pIAOHandle && ( SdrHdlKind::Color == pIAOHandle->GetKind() ) )
+ {
+ if(pIAOHandle->getOverlayObjectList().isHitPixel(rEvt.maPosPixel))
+ {
+ nRet = nDropAction;
+ static_cast< SdrHdlColor* >( pIAOHandle )->SetSize( SDR_HANDLE_COLOR_SIZE_SELECTED );
+ }
+ else
+ {
+ static_cast< SdrHdlColor* >( pIAOHandle )->SetSize( SDR_HANDLE_COLOR_SIZE_NORMAL );
+ }
+ }
+ }
+ }
+
+ // check object insert
+ if( !nRet && ( bXFillExchange || ( ( bDrawing || bGraphic || bMtf || bBitmap || bBookmark ) && ( nDropAction & DND_ACTION_LINK ) ) ) )
+ {
+ SdrPageView* pPageView = nullptr;
+ ::sd::Window* pWindow = mpViewSh->GetActiveWindow();
+ Point aPos( pWindow->PixelToLogic( rEvt.maPosPixel ) );
+ SdrObject* pPickObj = PickObj(aPos, getHitTolLog(), pPageView);
+ bool bIsPresTarget = false;
+
+ if (pPickObj && (pPickObj->IsEmptyPresObj() || pPickObj->GetUserCall()))
+ {
+ SdPage* pPage = static_cast<SdPage*>( pPickObj->getSdrPageFromSdrObject() );
+
+ if( pPage && pPage->IsMasterPage() )
+ bIsPresTarget = pPage->IsPresObj( pPickObj );
+ }
+
+ if (pPickObj && !bIsPresTarget && (bGraphic || bMtf || bBitmap || bXFillExchange))
+ {
+ if( mpDropMarkerObj != pPickObj )
+ {
+ mpDropMarkerObj = pPickObj;
+ ImplClearDrawDropMarker();
+
+ if(mpDropMarkerObj)
+ {
+ mpDropMarker.reset( new SdrDropMarkerOverlay(*this, *mpDropMarkerObj) );
+ }
+ }
+
+ nRet = nDropAction;
+ }
+ else
+ bXFillExchange = false;
+ }
+
+ // check normal insert
+ if( !nRet )
+ {
+ const bool bSBAFormat = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::SVX_FORMFIELDEXCH );
+ const bool bEditEngineODF = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT );
+ const bool bString = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::STRING );
+ const bool bRTF = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::RTF );
+ const bool bFile = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE );
+ const bool bFileList = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::FILE_LIST );
+
+ if( mpDropMarker )
+ {
+ ImplClearDrawDropMarker();
+ mpDropMarkerObj = nullptr;
+ }
+
+ if( bBookmark && bFile && ( nDropAction & DND_ACTION_MOVE ) && mpViewSh && SlideShow::IsRunning(mpViewSh->GetViewShellBase()) )
+ bBookmark = false;
+
+ if( bDrawing || bGraphic || bMtf || bBitmap || bBookmark || bFile || bFileList || bXFillExchange || bSBAFormat || bEditEngineODF || bString || bRTF )
+ nRet = nDropAction;
+
+ // For entries from the navigator, change action copy.
+ if (bBookmark
+ && rTargetHelper.IsDropFormatSupported(
+ SdPageObjsTLV::SdPageObjsTransferable::GetListBoxDropFormatId())
+ && (nDropAction & DND_ACTION_MOVE)!=0)
+ {
+ nRet = DND_ACTION_COPY;
+ }
+ }
+ }
+ }
+ }
+
+ // destroy drop marker if this is a leaving event
+ if( rEvt.mbLeaving && mpDropMarker )
+ {
+ ImplClearDrawDropMarker();
+ mpDropMarkerObj = nullptr;
+ }
+
+ return nRet;
+}
+
+sal_Int8 View::ExecuteDrop( const ExecuteDropEvent& rEvt,
+ ::sd::Window* pTargetWindow, sal_uInt16 nPage, SdrLayerID nLayer )
+{
+ SdrPageView* pPV = GetSdrPageView();
+ OUString aActiveLayer = GetActiveLayer();
+ sal_Int8 nDropAction = rEvt.mnAction;
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ // destroy drop marker if it is shown
+ if( mpDropMarker )
+ {
+ ImplClearDrawDropMarker();
+ mpDropMarkerObj = nullptr;
+ }
+
+ if( !pPV->IsLayerLocked( aActiveLayer ) )
+ {
+ const OutlinerView* pOLV = GetTextEditOutlinerView();
+ bool bIsInsideOutlinerView = false;
+
+ if( pOLV )
+ {
+ ::tools::Rectangle aRect( pOLV->GetOutputArea() );
+
+ if( GetMarkedObjectCount() == 1 )
+ {
+ SdrMark* pMark = GetSdrMarkByIndex(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+ aRect.Union( pObj->GetLogicRect() );
+ }
+
+ Point aPos( pOLV->GetWindow()->PixelToLogic( rEvt.maPosPixel ) );
+
+ if( aRect.Contains( aPos ) )
+ {
+ bIsInsideOutlinerView = true;
+ }
+ }
+
+ if( !bIsInsideOutlinerView )
+ {
+ Point aPos;
+ TransferableDataHelper aDataHelper( rEvt.maDropEvent.Transferable );
+
+ if( pTargetWindow )
+ aPos = pTargetWindow->PixelToLogic( rEvt.maPosPixel );
+
+ // handle insert?
+ if ((SdrDragMode::Gradient == GetDragMode())
+ || ((SdrDragMode::Transparence == GetDragMode())
+ && aDataHelper.HasFormat(SotClipboardFormatId::XFA)))
+ {
+ const SdrHdlList& rHdlList = GetHdlList();
+
+ for( size_t n = 0; !nRet && n < rHdlList.GetHdlCount(); ++n )
+ {
+ SdrHdl* pIAOHandle = rHdlList.GetHdl( n );
+
+ if( pIAOHandle && ( SdrHdlKind::Color == pIAOHandle->GetKind() ) )
+ {
+ if(pIAOHandle->getOverlayObjectList().isHitPixel(rEvt.maPosPixel))
+ {
+ uno::Any const data(aDataHelper.GetAny(SotClipboardFormatId::XFA, ""));
+ uno::Sequence<beans::NamedValue> props;
+ if (data >>= props)
+ {
+ ::comphelper::SequenceAsHashMap const map(props);
+ Color aColor(COL_BLACK);
+ auto const it = map.find("FillColor");
+ if (it != map.end())
+ {
+ XFillColorItem color;
+ color.PutValue(it->second, 0);
+ aColor = color.GetColorValue();
+ }
+ static_cast< SdrHdlColor* >( pIAOHandle )->SetColor( aColor, true );
+ nRet = nDropAction;
+ }
+ }
+ }
+ }
+ }
+
+ // standard insert?
+ if( !nRet && InsertData( aDataHelper, aPos, nDropAction, true, SotClipboardFormatId::NONE, nPage, nLayer ) )
+ nRet = nDropAction;
+
+ // special insert?
+ if( !nRet && mpViewSh )
+ {
+ INetBookmark aINetBookmark( (OUString()), (OUString()) );
+
+ // insert bookmark
+ if( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) &&
+ aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) )
+ {
+ SdPageObjsTLV::SdPageObjsTransferable* pPageObjsTransferable = SdPageObjsTLV::SdPageObjsTransferable::getImplementation( aDataHelper.GetXTransferable() );
+
+ if( pPageObjsTransferable &&
+ ( NAVIGATOR_DRAGTYPE_LINK == pPageObjsTransferable->GetDragType() ||
+ NAVIGATOR_DRAGTYPE_EMBEDDED == pPageObjsTransferable->GetDragType() ) )
+ {
+ // insert bookmark from own navigator (handled async. due to possible message box )
+ Application::PostUserEvent( LINK( this, View, ExecuteNavigatorDrop ),
+ new SdNavigatorDropEvent( rEvt, pTargetWindow ) );
+ nRet = nDropAction;
+ }
+ else
+ {
+ SdrPageView* pPageView = nullptr;
+
+ SdrObject* pPickObj = PickObj(aPos, getHitTolLog(), pPageView);
+ if (pPickObj)
+ {
+ // insert as clip action => jump
+ OUString aBookmark( aINetBookmark.GetURL() );
+ SdAnimationInfo* pInfo = SdDrawDocument::GetAnimationInfo( pPickObj );
+
+ if( !aBookmark.isEmpty() )
+ {
+ bool bCreated = false;
+
+ presentation::ClickAction eClickAction = presentation::ClickAction_DOCUMENT;
+
+ sal_Int32 nIndex = aBookmark.indexOf( '#' );
+ if( nIndex != -1 )
+ {
+ const std::u16string_view aDocName( aBookmark.subView( 0, nIndex ) );
+
+ if (mpDocSh->GetMedium()->GetName() == aDocName || aDocName == mpDocSh->GetName())
+ {
+ // internal jump, only use the part after and including '#'
+ eClickAction = presentation::ClickAction_BOOKMARK;
+ aBookmark = aBookmark.copy( nIndex+1 );
+ }
+ }
+
+ if( !pInfo )
+ {
+ pInfo = SdDrawDocument::GetShapeUserData( *pPickObj, true );
+ bCreated = true;
+ }
+
+ // create undo action with old and new sizes
+ std::unique_ptr<SdAnimationPrmsUndoAction> pAction(new SdAnimationPrmsUndoAction(&mrDoc, pPickObj, bCreated));
+ pAction->SetActive(pInfo->mbActive, pInfo->mbActive);
+ pAction->SetEffect(pInfo->meEffect, pInfo->meEffect);
+ pAction->SetTextEffect(pInfo->meTextEffect, pInfo->meTextEffect);
+ pAction->SetSpeed(pInfo->meSpeed, pInfo->meSpeed);
+ pAction->SetDim(pInfo->mbDimPrevious, pInfo->mbDimPrevious);
+ pAction->SetDimColor(pInfo->maDimColor, pInfo->maDimColor);
+ pAction->SetDimHide(pInfo->mbDimHide, pInfo->mbDimHide);
+ pAction->SetSoundOn(pInfo->mbSoundOn, pInfo->mbSoundOn);
+ pAction->SetSound(pInfo->maSoundFile, pInfo->maSoundFile);
+ pAction->SetPlayFull(pInfo->mbPlayFull, pInfo->mbPlayFull);
+ pAction->SetClickAction(pInfo->meClickAction, eClickAction);
+ pAction->SetBookmark(pInfo->GetBookmark(), aBookmark);
+ pAction->SetVerb(pInfo->mnVerb, pInfo->mnVerb);
+ pAction->SetSecondEffect(pInfo->meSecondEffect, pInfo->meSecondEffect);
+ pAction->SetSecondSpeed(pInfo->meSecondSpeed, pInfo->meSecondSpeed);
+ pAction->SetSecondSoundOn(pInfo->mbSecondSoundOn, pInfo->mbSecondSoundOn);
+ pAction->SetSecondPlayFull(pInfo->mbSecondPlayFull, pInfo->mbSecondPlayFull);
+
+ OUString aString(SdResId(STR_UNDO_ANIMATION));
+ pAction->SetComment(aString);
+ mpDocSh->GetUndoManager()->AddUndoAction(std::move(pAction));
+ pInfo->meClickAction = eClickAction;
+ pInfo->SetBookmark( aBookmark );
+ mrDoc.SetChanged();
+
+ nRet = nDropAction;
+ }
+ }
+ else if( auto pDrawViewShell = dynamic_cast< DrawViewShell *>( mpViewSh ) )
+ {
+ // insert as normal URL button
+ pDrawViewShell->InsertURLButton( aINetBookmark.GetURL(), aINetBookmark.GetDescription(), OUString(), &aPos );
+ nRet = nDropAction;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return nRet;
+}
+
+IMPL_LINK( View, ExecuteNavigatorDrop, void*, p, void )
+{
+ SdNavigatorDropEvent* pSdNavigatorDropEvent = static_cast<SdNavigatorDropEvent*>(p);
+ TransferableDataHelper aDataHelper( pSdNavigatorDropEvent->maDropEvent.Transferable );
+ SdPageObjsTLV::SdPageObjsTransferable* pPageObjsTransferable = SdPageObjsTLV::SdPageObjsTransferable::getImplementation( aDataHelper.GetXTransferable() );
+ INetBookmark aINetBookmark;
+
+ if( pPageObjsTransferable && aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) )
+ {
+ Point aPos;
+ OUString aBookmark;
+ SdPage* pPage = static_cast<SdPage*>( GetSdrPageView()->GetPage() );
+ sal_uInt16 nPgPos = 0xFFFF;
+
+ if( pSdNavigatorDropEvent->mpTargetWindow )
+ aPos = pSdNavigatorDropEvent->mpTargetWindow->PixelToLogic( pSdNavigatorDropEvent->maPosPixel );
+
+ const OUString& aURL( aINetBookmark.GetURL() );
+ sal_Int32 nIndex = aURL.indexOf( '#' );
+ if( nIndex != -1 )
+ aBookmark = aURL.copy( nIndex+1 );
+
+ std::vector<OUString> aExchangeList;
+ std::vector<OUString> aBookmarkList(1,aBookmark);
+
+ if( !pPage->IsMasterPage() )
+ {
+ if( pPage->GetPageKind() == PageKind::Standard )
+ nPgPos = pPage->GetPageNum() + 2;
+ else if( pPage->GetPageKind() == PageKind::Notes )
+ nPgPos = pPage->GetPageNum() + 1;
+ }
+
+ /* In order t ensure unique page names, we test the ones we want to
+ insert. If necessary. we put them into and replacement list (bNameOK
+ == sal_False -> User canceled). */
+ bool bLink = pPageObjsTransferable->GetDragType() == NAVIGATOR_DRAGTYPE_LINK;
+ bool bNameOK = GetExchangeList( aExchangeList, aBookmarkList, 2 );
+
+ /* Since we don't know the type (page or object), we fill a list with
+ pages and objects.
+ Of course we have problems if there are pages and objects with the
+ same name!!! */
+ if( bNameOK )
+ {
+ mrDoc.InsertBookmark( aBookmarkList, aExchangeList,
+ bLink, nPgPos,
+ &pPageObjsTransferable->GetDocShell(),
+ &aPos );
+ }
+ }
+
+ delete pSdNavigatorDropEvent;
+}
+
+bool View::GetExchangeList (std::vector<OUString> &rExchangeList,
+ std::vector<OUString> &rBookmarkList,
+ const sal_uInt16 nType)
+{
+ assert(rExchangeList.empty());
+
+ bool bListIdentical = true; ///< Bookmark list and exchange list are identical
+ bool bNameOK = true; ///< name is unique
+
+ for ( const auto& rBookmark : rBookmarkList )
+ {
+ OUString aNewName = rBookmark;
+
+ if( nType == 0 || nType == 2 )
+ bNameOK = mpDocSh->CheckPageName(mpViewSh->GetFrameWeld(), aNewName);
+
+ if( bNameOK && ( nType == 1 || nType == 2 ) )
+ {
+ if( mrDoc.GetObj( aNewName ) )
+ {
+ OUString aTitle(SdResId(STR_TITLE_NAMEGROUP));
+ OUString aDesc(SdResId(STR_DESC_NAMEGROUP));
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxNameDialog> pDlg(pFact->CreateSvxNameDialog(mpViewSh->GetFrameWeld(), aNewName, aDesc));
+
+ pDlg->SetEditHelpId( HID_SD_NAMEDIALOG_OBJECT );
+
+ bNameOK = false;
+ pDlg->SetText( aTitle );
+
+ while( !bNameOK && pDlg->Execute() == RET_OK )
+ {
+ pDlg->GetName( aNewName );
+
+ if( !mrDoc.GetObj( aNewName ) )
+ bNameOK = true;
+ }
+ }
+ }
+
+ bListIdentical = rBookmark == aNewName;
+
+ rExchangeList.push_back(aNewName);
+
+ if (!bNameOK)
+ break;
+ }
+
+ // Exchange list is identical to bookmark list
+ if( !rExchangeList.empty() && bListIdentical )
+ rExchangeList.clear();
+
+ return bNameOK;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/sdview3.cxx b/sd/source/ui/view/sdview3.cxx
new file mode 100644
index 000000000..b72e837c4
--- /dev/null
+++ b/sd/source/ui/view/sdview3.cxx
@@ -0,0 +1,1596 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <View.hxx>
+#include <com/sun/star/embed/XEmbedObjectClipboardCreator.hpp>
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/embed/MSOLEObjectSystemCreator.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <sot/filelist.hxx>
+#include <editeng/editdata.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/svdpagv.hxx>
+#include <sfx2/docfile.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdundo.hxx>
+#include <svl/itempool.hxx>
+#include <sot/formats.hxx>
+#include <editeng/outliner.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/e3dundo.hxx>
+#include <svx/unomodel.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <unotools/streamwrap.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/pdfread.hxx>
+#include <vcl/TypeSerializer.hxx>
+#include <svx/svxids.hrc>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <svtools/embedhlp.hxx>
+#include <osl/diagnose.h>
+#include <DrawDocShell.hxx>
+#include <fupoor.hxx>
+#include <tablefunction.hxx>
+#include <Window.hxx>
+#include <sdxfer.hxx>
+#include <sdpage.hxx>
+#include <drawdoc.hxx>
+#include <sdmod.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <SlideSorterViewShell.hxx>
+#include <unomodel.hxx>
+#include <ViewClipboard.hxx>
+#include <sfx2/ipclient.hxx>
+#include <sfx2/classificationhelper.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <svx/sdrhittesthelper.hxx>
+#include <svx/xbtmpit.hxx>
+#include <memory>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::clipboard;
+
+namespace sd {
+
+#define CHECK_FORMAT_TRANS( _def_Type ) ( ( nFormat == (_def_Type) || nFormat == SotClipboardFormatId::NONE ) && aDataHelper.HasFormat( _def_Type ) )
+
+/*************************************************************************
+|*
+|* Paste
+|*
+\************************************************************************/
+
+namespace {
+
+struct ImpRememberOrigAndClone
+{
+ SdrObject* pOrig;
+ SdrObject* pClone;
+};
+
+}
+
+static SdrObject* ImpGetClone(std::vector<ImpRememberOrigAndClone>& aConnectorContainer, SdrObject const * pConnObj)
+{
+ for(const ImpRememberOrigAndClone& rImp : aConnectorContainer)
+ {
+ if(pConnObj == rImp.pOrig)
+ return rImp.pClone;
+ }
+ return nullptr;
+}
+
+// restrict movement to WorkArea
+static void ImpCheckInsertPos(Point& rPos, const Size& rSize, const ::tools::Rectangle& rWorkArea)
+{
+ if(rWorkArea.IsEmpty())
+ return;
+
+ ::tools::Rectangle aMarkRect(Point(rPos.X() - (rSize.Width() / 2), rPos.Y() - (rSize.Height() / 2)), rSize);
+
+ if(aMarkRect.Contains(rWorkArea))
+ return;
+
+ if(aMarkRect.Left() < rWorkArea.Left())
+ {
+ rPos.AdjustX(rWorkArea.Left() - aMarkRect.Left() );
+ }
+
+ if(aMarkRect.Right() > rWorkArea.Right())
+ {
+ rPos.AdjustX( -(aMarkRect.Right() - rWorkArea.Right()) );
+ }
+
+ if(aMarkRect.Top() < rWorkArea.Top())
+ {
+ rPos.AdjustY(rWorkArea.Top() - aMarkRect.Top() );
+ }
+
+ if(aMarkRect.Bottom() > rWorkArea.Bottom())
+ {
+ rPos.AdjustY( -(aMarkRect.Bottom() - rWorkArea.Bottom()) );
+ }
+}
+
+bool View::InsertMetaFile( const TransferableDataHelper& rDataHelper, const Point& rPos, ImageMap const * pImageMap, bool bOptimize )
+{
+ GDIMetaFile aMtf;
+
+ if( !rDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMtf ) )
+ return false;
+
+ bool bVector = false;
+ Graphic aGraphic;
+
+ // check if metafile only contains a pixel image, if so insert a bitmap instead
+ if( bOptimize )
+ {
+ MetaAction* pAction = aMtf.FirstAction();
+ while( pAction && !bVector )
+ {
+ switch( pAction->GetType() )
+ {
+ case MetaActionType::POINT:
+ case MetaActionType::LINE:
+ case MetaActionType::RECT:
+ case MetaActionType::ROUNDRECT:
+ case MetaActionType::ELLIPSE:
+ case MetaActionType::ARC:
+ case MetaActionType::PIE:
+ case MetaActionType::CHORD:
+ case MetaActionType::POLYLINE:
+ case MetaActionType::POLYGON:
+ case MetaActionType::POLYPOLYGON:
+ case MetaActionType::TEXT:
+ case MetaActionType::TEXTARRAY:
+ case MetaActionType::STRETCHTEXT:
+ case MetaActionType::TEXTRECT:
+ case MetaActionType::GRADIENT:
+ case MetaActionType::HATCH:
+ case MetaActionType::WALLPAPER:
+ case MetaActionType::EPS:
+ case MetaActionType::TEXTLINE:
+ case MetaActionType::FLOATTRANSPARENT:
+ case MetaActionType::GRADIENTEX:
+ case MetaActionType::BMPSCALEPART:
+ case MetaActionType::BMPEXSCALEPART:
+ bVector = true;
+ break;
+ case MetaActionType::BMP:
+ case MetaActionType::BMPSCALE:
+ case MetaActionType::BMPEX:
+ case MetaActionType::BMPEXSCALE:
+ if( aGraphic.GetType() != GraphicType::NONE )
+ {
+ bVector = true;
+ }
+ else switch( pAction->GetType() )
+ {
+ case MetaActionType::BMP:
+ {
+ MetaBmpAction* pBmpAction = dynamic_cast< MetaBmpAction* >( pAction );
+ if( pBmpAction )
+ aGraphic = Graphic(BitmapEx(pBmpAction->GetBitmap()));
+ }
+ break;
+ case MetaActionType::BMPSCALE:
+ {
+ MetaBmpScaleAction* pBmpScaleAction = dynamic_cast< MetaBmpScaleAction* >( pAction );
+ if( pBmpScaleAction )
+ aGraphic = Graphic(BitmapEx(pBmpScaleAction->GetBitmap()));
+ }
+ break;
+ case MetaActionType::BMPEX:
+ {
+ MetaBmpExAction* pBmpExAction = dynamic_cast< MetaBmpExAction* >( pAction );
+ if( pBmpExAction )
+ aGraphic = Graphic(pBmpExAction->GetBitmapEx() );
+ }
+ break;
+ case MetaActionType::BMPEXSCALE:
+ {
+ MetaBmpExScaleAction* pBmpExScaleAction = dynamic_cast< MetaBmpExScaleAction* >( pAction );
+ if( pBmpExScaleAction )
+ aGraphic = Graphic( pBmpExScaleAction->GetBitmapEx() );
+ }
+ break;
+ default: break;
+ }
+ break;
+ default: break;
+ }
+
+ pAction = aMtf.NextAction();
+ }
+ }
+
+ // it is not a vector metafile but it also has no graphic?
+ if( !bVector && (aGraphic.GetType() == GraphicType::NONE) )
+ bVector = true;
+
+ // restrict movement to WorkArea
+ Point aInsertPos( rPos );
+ Size aImageSize = bVector ? aMtf.GetPrefSize() : aGraphic.GetSizePixel();
+ ImpCheckInsertPos(aInsertPos, aImageSize, GetWorkArea());
+
+ if( bVector )
+ aGraphic = Graphic( aMtf );
+
+ aGraphic.SetPrefMapMode( aMtf.GetPrefMapMode() );
+ aGraphic.SetPrefSize( aMtf.GetPrefSize() );
+ InsertGraphic( aGraphic, mnAction, aInsertPos, nullptr, pImageMap );
+
+ return true;
+}
+
+bool View::InsertData( const TransferableDataHelper& rDataHelper,
+ const Point& rPos, sal_Int8& rDnDAction, bool bDrag,
+ SotClipboardFormatId nFormat, sal_uInt16 nPage, SdrLayerID nLayer )
+{
+ maDropPos = rPos;
+ mnAction = rDnDAction;
+ mbIsDropAllowed = false;
+
+ TransferableDataHelper aDataHelper( rDataHelper );
+ SdrObject* pPickObj = nullptr;
+ SdPage* pPage = nullptr;
+ std::unique_ptr<ImageMap> pImageMap;
+ bool bReturn = false;
+ bool bLink = ( ( mnAction & DND_ACTION_LINK ) != 0 );
+ bool bCopy = ( ( ( mnAction & DND_ACTION_COPY ) != 0 ) || bLink );
+ SdrInsertFlags nPasteOptions = SdrInsertFlags::SETDEFLAYER;
+
+ if (mpViewSh != nullptr)
+ {
+ OSL_ASSERT (mpViewSh->GetViewShell()!=nullptr);
+ SfxInPlaceClient* pIpClient = mpViewSh->GetViewShell()->GetIPClient();
+ if( dynamic_cast< ::sd::slidesorter::SlideSorterViewShell *>( mpViewSh ) != nullptr
+ || (pIpClient!=nullptr && pIpClient->IsObjectInPlaceActive()))
+ nPasteOptions |= SdrInsertFlags::DONTMARK;
+ }
+
+ if( bDrag )
+ {
+ SdrPageView* pPV = nullptr;
+ pPickObj = PickObj(rPos, getHitTolLog(), pPV);
+ }
+
+ if( nPage != SDRPAGE_NOTFOUND )
+ pPage = static_cast<SdPage*>( mrDoc.GetPage( nPage ) );
+
+ SdTransferable* pOwnData = nullptr;
+ SdTransferable* pImplementation = SdTransferable::getImplementation( aDataHelper.GetTransferable() );
+
+ if(pImplementation && (rDnDAction & DND_ACTION_LINK))
+ {
+ // suppress own data when it's intention is to use it as fill information
+ pImplementation = nullptr;
+ }
+
+ bool bSelfDND = false;
+
+ // try to get own transfer data
+ if( pImplementation )
+ {
+ if( SD_MOD()->pTransferClip == pImplementation )
+ pOwnData = SD_MOD()->pTransferClip;
+ else if( SD_MOD()->pTransferDrag == pImplementation )
+ {
+ pOwnData = SD_MOD()->pTransferDrag;
+ bSelfDND = true;
+ }
+ else if( SD_MOD()->pTransferSelection == pImplementation )
+ pOwnData = SD_MOD()->pTransferSelection;
+ }
+
+ const bool bGroupUndoFromDragWithDrop = bSelfDND && mpDragSrcMarkList && IsUndoEnabled();
+ if (bGroupUndoFromDragWithDrop)
+ {
+ OUString aStr(SdResId(STR_UNDO_DRAGDROP));
+ BegUndo(aStr + " " + mpDragSrcMarkList->GetMarkDescription());
+ }
+
+ // ImageMap?
+ if( !pOwnData && aDataHelper.HasFormat( SotClipboardFormatId::SVIM ) )
+ {
+ ::tools::SvRef<SotTempStream> xStm;
+
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVIM, xStm ) )
+ {
+ pImageMap.reset(new ImageMap);
+ // mba: clipboard always must contain absolute URLs (could be from alien source)
+ pImageMap->Read( *xStm );
+ }
+ }
+
+ bool bTable = false;
+ // check special cases for pasting table formats as RTL
+ if( !bLink && (nFormat == SotClipboardFormatId::NONE || (nFormat == SotClipboardFormatId::RTF) || (nFormat == SotClipboardFormatId::RICHTEXT)) )
+ {
+ // if the object supports rtf and there is a table involved, default is to create a table
+ bool bIsRTF = aDataHelper.HasFormat( SotClipboardFormatId::RTF );
+ if( ( bIsRTF || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) )
+ && ! aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) )
+ {
+ ::tools::SvRef<SotTempStream> xStm;
+
+ if( aDataHelper.GetSotStorageStream( bIsRTF ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT, xStm ) )
+ {
+ xStm->Seek( 0 );
+
+ OStringBuffer aLine;
+ while (xStm->ReadLine(aLine))
+ {
+ size_t x = std::string_view(aLine).find( "\\trowd" );
+ if (x != std::string_view::npos)
+ {
+ bTable = true;
+ nFormat = bIsRTF ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Changed the whole decision tree to be dependent of bReturn as a flag that
+ // the work was done; this allows to check multiple formats and not just fail
+ // when a CHECK_FORMAT_TRANS(*format*) detected format does not work. This is
+ // e.g. necessary for SotClipboardFormatId::BITMAP
+
+ if (!bReturn && pOwnData)
+ {
+ // Paste only if SfxClassificationHelper recommends so.
+ const SfxObjectShellRef& pSource = pOwnData->GetDocShell();
+ SfxObjectShell* pDestination = mrDoc.GetDocSh();
+ if (pSource.is() && pDestination)
+ {
+ SfxClassificationCheckPasteResult eResult = SfxClassificationHelper::CheckPaste(pSource->getDocProperties(), pDestination->getDocProperties());
+ if (!SfxClassificationHelper::ShowPasteInfo(eResult))
+ bReturn = true;
+ }
+ }
+
+ if( !bReturn && pOwnData && nFormat == SotClipboardFormatId::NONE )
+ {
+ const View* pSourceView = pOwnData->GetView();
+
+ if( pOwnData->GetDocShell().is() && pOwnData->IsPageTransferable() )
+ {
+ mpClipboard->HandlePageDrop (*pOwnData);
+ bReturn = true;
+ }
+ else if( pSourceView )
+ {
+ if( pSourceView == this )
+ {
+ // same view
+ if( nLayer != SDRLAYER_NOTFOUND )
+ {
+ // drop on layer tab bar
+ SdrLayerAdmin& rLayerAdmin = mrDoc.GetLayerAdmin();
+ SdrLayer* pLayer = rLayerAdmin.GetLayerPerID( nLayer );
+ SdrPageView* pPV = GetSdrPageView();
+ OUString aLayer = pLayer->GetName();
+
+ if( !pPV->IsLayerLocked( aLayer ) )
+ {
+ pOwnData->SetInternalMove( true );
+ SortMarkedObjects();
+
+ for( size_t nM = 0; nM < GetMarkedObjectCount(); ++nM )
+ {
+ SdrMark* pM = GetSdrMarkByIndex( nM );
+ SdrObject* pO = pM->GetMarkedSdrObj();
+
+ if( pO )
+ {
+ // #i11702#
+ if( IsUndoEnabled() )
+ {
+ BegUndo(SdResId(STR_MODIFYLAYER));
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectLayerChange(*pO, pO->GetLayer(), nLayer));
+ EndUndo();
+ }
+
+ pO->SetLayer( nLayer );
+ }
+ }
+
+ bReturn = true;
+ }
+ }
+ else
+ {
+ SdrPageView* pPV = GetSdrPageView();
+ bool bDropOnTabBar = true;
+
+ if( !pPage && pPV->GetPage()->GetPageNum() != mnDragSrcPgNum )
+ {
+ pPage = static_cast<SdPage*>( pPV->GetPage() );
+ bDropOnTabBar = false;
+ }
+
+ if( pPage )
+ {
+ // drop on other page
+ OUString aActiveLayer = GetActiveLayer();
+
+ if( !pPV->IsLayerLocked( aActiveLayer ) )
+ {
+ if( !IsPresObjSelected() )
+ {
+ SdrMarkList* pMarkList;
+
+ if( (mnDragSrcPgNum != SDRPAGE_NOTFOUND) && (mnDragSrcPgNum != pPV->GetPage()->GetPageNum()) )
+ {
+ pMarkList = mpDragSrcMarkList.get();
+ }
+ else
+ {
+ // actual mark list is used
+ pMarkList = new SdrMarkList( GetMarkedObjectList());
+ }
+
+ pMarkList->ForceSort();
+
+ // stuff to remember originals and clones
+ std::vector<ImpRememberOrigAndClone> aConnectorContainer;
+ size_t nConnectorCount = 0;
+ Point aCurPos;
+
+ // calculate real position of current
+ // source objects, if necessary (#103207)
+ if( pOwnData == SD_MOD()->pTransferSelection )
+ {
+ ::tools::Rectangle aCurBoundRect;
+
+ if( pMarkList->TakeBoundRect( pPV, aCurBoundRect ) )
+ aCurPos = aCurBoundRect.TopLeft();
+ else
+ aCurPos = pOwnData->GetStartPos();
+ }
+ else
+ aCurPos = pOwnData->GetStartPos();
+
+ const Size aVector( maDropPos.X() - aCurPos.X(), maDropPos.Y() - aCurPos.Y() );
+
+ std::unordered_set<rtl::OUString> aNameSet;
+ for(size_t a = 0; a < pMarkList->GetMarkCount(); ++a)
+ {
+ SdrMark* pM = pMarkList->GetMark(a);
+ SdrObject* pObj(pM->GetMarkedSdrObj()->CloneSdrObject(pPage->getSdrModelFromSdrPage()));
+
+ if(pObj)
+ {
+ if(!bDropOnTabBar)
+ {
+ // do a NbcMove(...) instead of setting SnapRects here
+ pObj->NbcMove(aVector);
+ }
+
+ SdrObject* pMarkParent = pM->GetMarkedSdrObj()->getParentSdrObjectFromSdrObject();
+ if (bCopy || (pMarkParent && pMarkParent->IsGroupObject()))
+ pPage->InsertObjectThenMakeNameUnique(pObj, aNameSet);
+ else
+ pPage->InsertObject(pObj);
+
+ if( IsUndoEnabled() )
+ {
+ BegUndo(SdResId(STR_UNDO_DRAGDROP));
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pObj));
+ EndUndo();
+ }
+
+ ImpRememberOrigAndClone aRem;
+ aRem.pOrig = pM->GetMarkedSdrObj();
+ aRem.pClone = pObj;
+ aConnectorContainer.push_back(aRem);
+
+ if(dynamic_cast< SdrEdgeObj *>( pObj ) != nullptr)
+ nConnectorCount++;
+ }
+ }
+
+ // try to re-establish connections at clones
+ if(nConnectorCount)
+ {
+ for(size_t a = 0; a < aConnectorContainer.size(); ++a)
+ {
+ ImpRememberOrigAndClone* pRem = &aConnectorContainer[a];
+
+ if(auto pCloneEdge = dynamic_cast<SdrEdgeObj *>( pRem->pClone ))
+ {
+ SdrEdgeObj* pOrigEdge = static_cast<SdrEdgeObj*>(pRem->pOrig);
+
+ // test first connection
+ SdrObjConnection& rConn0 = pOrigEdge->GetConnection(false);
+ SdrObject* pConnObj = rConn0.GetObject();
+ if(pConnObj)
+ {
+ SdrObject* pConnClone = ImpGetClone(aConnectorContainer, pConnObj);
+ if(pConnClone)
+ {
+ // if dest obj was cloned, too, re-establish connection
+ pCloneEdge->ConnectToNode(false, pConnClone);
+ pCloneEdge->GetConnection(false).SetConnectorId(rConn0.GetConnectorId());
+ }
+ else
+ {
+ // set position of connection point of original connected object
+ const SdrGluePointList* pGlueList = pConnObj->GetGluePointList();
+ if(pGlueList)
+ {
+ sal_uInt16 nInd = pGlueList->FindGluePoint(rConn0.GetConnectorId());
+
+ if(SDRGLUEPOINT_NOTFOUND != nInd)
+ {
+ const SdrGluePoint& rGluePoint = (*pGlueList)[nInd];
+ Point aPosition = rGluePoint.GetAbsolutePos(*pConnObj);
+ aPosition.AdjustX(aVector.Width() );
+ aPosition.AdjustY(aVector.Height() );
+ pCloneEdge->SetTailPoint(false, aPosition);
+ }
+ }
+ }
+ }
+
+ // test second connection
+ SdrObjConnection& rConn1 = pOrigEdge->GetConnection(true);
+ pConnObj = rConn1.GetObject();
+ if(pConnObj)
+ {
+ SdrObject* pConnClone = ImpGetClone(aConnectorContainer, pConnObj);
+ if(pConnClone)
+ {
+ // if dest obj was cloned, too, re-establish connection
+ pCloneEdge->ConnectToNode(true, pConnClone);
+ pCloneEdge->GetConnection(true).SetConnectorId(rConn1.GetConnectorId());
+ }
+ else
+ {
+ // set position of connection point of original connected object
+ const SdrGluePointList* pGlueList = pConnObj->GetGluePointList();
+ if(pGlueList)
+ {
+ sal_uInt16 nInd = pGlueList->FindGluePoint(rConn1.GetConnectorId());
+
+ if(SDRGLUEPOINT_NOTFOUND != nInd)
+ {
+ const SdrGluePoint& rGluePoint = (*pGlueList)[nInd];
+ Point aPosition = rGluePoint.GetAbsolutePos(*pConnObj);
+ aPosition.AdjustX(aVector.Width() );
+ aPosition.AdjustY(aVector.Height() );
+ pCloneEdge->SetTailPoint(true, aPosition);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if( pMarkList != mpDragSrcMarkList.get() )
+ delete pMarkList;
+
+ bReturn = true;
+ }
+ else
+ {
+ maDropErrorIdle.Start();
+ bReturn = false;
+ }
+ }
+ }
+ else
+ {
+ pOwnData->SetInternalMove( true );
+ MoveAllMarked( Size( maDropPos.X() - pOwnData->GetStartPos().X(),
+ maDropPos.Y() - pOwnData->GetStartPos().Y() ), bCopy );
+ bReturn = true;
+ }
+ }
+ }
+ else
+ {
+ // different views
+ if( !pSourceView->IsPresObjSelected() )
+ {
+ // model is owned by from AllocModel() created DocShell
+ SdDrawDocument* pSourceDoc = static_cast<SdDrawDocument*>( pSourceView->GetModel() );
+ pSourceDoc->CreatingDataObj( pOwnData );
+ SdDrawDocument* pModel = static_cast<SdDrawDocument*>( pSourceView->CreateMarkedObjModel().release() );
+ bReturn = Paste(*pModel, maDropPos, pPage, nPasteOptions);
+
+ if( !pPage )
+ pPage = static_cast<SdPage*>( GetSdrPageView()->GetPage() );
+
+ OUString aLayout = pPage->GetLayoutName();
+ sal_Int32 nPos = aLayout.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ aLayout = aLayout.copy(0, nPos);
+ pPage->SetPresentationLayout( aLayout, false, false );
+ pSourceDoc->CreatingDataObj( nullptr );
+ }
+ else
+ {
+ maDropErrorIdle.Start();
+ bReturn = false;
+ }
+ }
+ }
+ else
+ {
+ SdDrawDocument* pWorkModel = const_cast<SdDrawDocument*>(pOwnData->GetWorkDocument());
+ SdPage* pWorkPage = pWorkModel->GetSdPage( 0, PageKind::Standard );
+
+ pWorkPage->SetSdrObjListRectsDirty();
+
+ // #i120393# Clipboard data uses full object geometry range
+ const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() );
+
+ maDropPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) );
+ maDropPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) );
+
+ // delete pages, that are not of any interest for us
+ for( ::tools::Long i = pWorkModel->GetPageCount() - 1; i >= 0; i-- )
+ {
+ SdPage* pP = static_cast< SdPage* >( pWorkModel->GetPage( static_cast<sal_uInt16>(i) ) );
+
+ if( pP->GetPageKind() != PageKind::Standard )
+ pWorkModel->DeletePage( static_cast<sal_uInt16>(i) );
+ }
+
+ bReturn = Paste(*pWorkModel, maDropPos, pPage, nPasteOptions);
+
+ if( !pPage )
+ pPage = static_cast<SdPage*>( GetSdrPageView()->GetPage() );
+
+ OUString aLayout = pPage->GetLayoutName();
+ sal_Int32 nPos = aLayout.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ aLayout = aLayout.copy(0, nPos);
+ pPage->SetPresentationLayout( aLayout, false, false );
+ }
+ }
+
+ if(!bReturn && CHECK_FORMAT_TRANS( SotClipboardFormatId::PDF ))
+ {
+ ::tools::SvRef<SotTempStream> xStm;
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::PDF, xStm ) )
+ {
+ Point aInsertPos(rPos);
+ Graphic aGraphic;
+ if (vcl::ImportPDF(*xStm, aGraphic))
+ {
+ std::unique_ptr<sal_uInt8[]> pGraphicContent;
+
+ const sal_Int32 nGraphicContentSize(xStm->Tell());
+ pGraphicContent.reset(new sal_uInt8[nGraphicContentSize]);
+ xStm->Seek(0);
+ xStm->ReadBytes(pGraphicContent.get(), nGraphicContentSize);
+ aGraphic.SetGfxLink(std::make_shared<GfxLink>(std::move(pGraphicContent), nGraphicContentSize, GfxLinkType::NativePdf));
+
+ InsertGraphic(aGraphic, mnAction, aInsertPos, nullptr, nullptr);
+ bReturn = true;
+ }
+ }
+ }
+
+ if(!bReturn && CHECK_FORMAT_TRANS( SotClipboardFormatId::DRAWING ))
+ {
+ ::tools::SvRef<SotTempStream> xStm;
+
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::DRAWING, xStm ) )
+ {
+ DrawDocShellRef xShell = new DrawDocShell(SfxObjectCreateMode::INTERNAL, false, DocumentType::Impress);
+ xShell->DoInitNew();
+
+ SdDrawDocument* pModel = xShell->GetDoc();
+ pModel->InsertPage(pModel->AllocPage(false).get());
+
+ Reference< XComponent > xComponent = xShell->GetModel();
+ xStm->Seek( 0 );
+
+ css::uno::Reference< css::io::XInputStream > xInputStream( new utl::OInputStreamWrapper( *xStm ) );
+ bReturn = SvxDrawingLayerImport( pModel, xInputStream, xComponent, "com.sun.star.comp.Impress.XMLOasisImporter" );
+
+ if( pModel->GetPageCount() == 0 )
+ {
+ OSL_FAIL("empty or invalid drawing xml document on clipboard!" );
+ }
+ else
+ {
+ bool bChanged = false;
+
+ if( bReturn )
+ {
+ if( pModel->GetSdPage( 0, PageKind::Standard )->GetObjCount() == 1 )
+ {
+ // only one object
+ SdrObject* pObj = pModel->GetSdPage( 0, PageKind::Standard )->GetObj( 0 );
+ SdrPageView* pPV = nullptr;
+ SdrObject* pPickObj2 = PickObj(rPos, getHitTolLog(), pPV);
+
+ if( ( mnAction & DND_ACTION_MOVE ) && pPickObj2 && pObj )
+ {
+ // replace object
+ SdrPage* pWorkPage = GetSdrPageView()->GetPage();
+ SdrObject* pNewObj(pObj->CloneSdrObject(pWorkPage->getSdrModelFromSdrPage()));
+ ::tools::Rectangle aPickObjRect( pPickObj2->GetCurrentBoundRect() );
+ Size aPickObjSize( aPickObjRect.GetSize() );
+ Point aVec( aPickObjRect.TopLeft() );
+ ::tools::Rectangle aObjRect( pNewObj->GetCurrentBoundRect() );
+ Size aObjSize( aObjRect.GetSize() );
+
+ Fraction aScaleWidth( aPickObjSize.Width(), aObjSize.Width() );
+ Fraction aScaleHeight( aPickObjSize.Height(), aObjSize.Height() );
+ pNewObj->NbcResize( aObjRect.TopLeft(), aScaleWidth, aScaleHeight );
+
+ aVec -= aObjRect.TopLeft();
+ pNewObj->NbcMove( Size( aVec.X(), aVec.Y() ) );
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo(SdResId(STR_UNDO_DRAGDROP));
+ pNewObj->NbcSetLayer( pPickObj->GetLayer() );
+ pWorkPage->InsertObject( pNewObj );
+ if( bUndo )
+ {
+ AddUndo( mrDoc.GetSdrUndoFactory().CreateUndoNewObject( *pNewObj ) );
+ AddUndo( mrDoc.GetSdrUndoFactory().CreateUndoDeleteObject( *pPickObj2 ) );
+ }
+ pWorkPage->RemoveObject( pPickObj2->GetOrdNum() );
+
+ if( bUndo )
+ {
+ EndUndo();
+ }
+ else
+ {
+ SdrObject::Free(pPickObj2 );
+ }
+ bChanged = true;
+ mnAction = DND_ACTION_COPY;
+ }
+ else if( ( mnAction & DND_ACTION_LINK ) && pPickObj && pObj &&
+ dynamic_cast< const SdrGrafObj *>( pPickObj ) == nullptr &&
+ dynamic_cast< const SdrOle2Obj *>( pPickObj ) == nullptr )
+ {
+ SfxItemSet aSet( mrDoc.GetPool() );
+
+ // set new attributes to object
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ {
+ BegUndo( SdResId(STR_UNDO_DRAGDROP) );
+ AddUndo( mrDoc.GetSdrUndoFactory().CreateUndoAttrObject( *pPickObj ) );
+ }
+
+ aSet.Put( pObj->GetMergedItemSet() );
+
+ /* Do not take over corner radius. There are
+ gradients (rectangles) in the gallery with corner
+ radius of 0. We should not use that on the
+ object. */
+ aSet.ClearItem( SDRATTR_CORNER_RADIUS );
+
+ const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(pObj);
+
+ if(pSdrGrafObj)
+ {
+ // If we have a graphic as source object, use its graphic
+ // content as fill style
+ aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP));
+ aSet.Put(XFillBitmapItem(pSdrGrafObj->GetGraphic()));
+ }
+
+ pPickObj->SetMergedItemSetAndBroadcast( aSet );
+
+ if( dynamic_cast< E3dObject *>( pPickObj ) != nullptr && dynamic_cast< E3dObject *>( pObj ) != nullptr )
+ {
+ // handle 3D attribute in addition
+ SfxItemSetFixed<SID_ATTR_3D_START, SID_ATTR_3D_END> aNewSet( mrDoc.GetPool() );
+ SfxItemSetFixed<SID_ATTR_3D_START, SID_ATTR_3D_END> aOldSet( mrDoc.GetPool() );
+
+ aOldSet.Put(pPickObj->GetMergedItemSet());
+ aNewSet.Put( pObj->GetMergedItemSet() );
+
+ if( bUndo )
+ AddUndo(
+ std::make_unique<E3dAttributesUndoAction>(
+ *static_cast< E3dObject* >(pPickObj),
+ aNewSet,
+ aOldSet));
+ pPickObj->SetMergedItemSetAndBroadcast( aNewSet );
+ }
+
+ if( bUndo )
+ EndUndo();
+ bChanged = true;
+ }
+ }
+ }
+
+ if( !bChanged )
+ {
+ SdrPage* pWorkPage = pModel->GetSdPage( 0, PageKind::Standard );
+
+ pWorkPage->SetSdrObjListRectsDirty();
+
+ if( pOwnData )
+ {
+ // #i120393# Clipboard data uses full object geometry range
+ const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() );
+
+ maDropPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) );
+ maDropPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) );
+ }
+
+ bReturn = Paste(*pModel, maDropPos, pPage, nPasteOptions);
+ }
+
+ xShell->DoClose();
+ }
+ }
+ }
+
+ if(!bReturn && CHECK_FORMAT_TRANS(SotClipboardFormatId::SBA_FIELDDATAEXCHANGE))
+ {
+ OUString aOUString;
+
+ if( aDataHelper.GetString( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE, aOUString ) )
+ {
+ SdrObjectUniquePtr pObj = CreateFieldControl( aOUString );
+
+ if( pObj )
+ {
+ ::tools::Rectangle aRect( pObj->GetLogicRect() );
+ Size aSize( aRect.GetSize() );
+
+ maDropPos.AdjustX( -( aSize.Width() >> 1 ) );
+ maDropPos.AdjustY( -( aSize.Height() >> 1 ) );
+
+ aRect.SetPos( maDropPos );
+ pObj->SetLogicRect( aRect );
+ InsertObjectAtView( pObj.release(), *GetSdrPageView(), SdrInsertFlags::SETDEFLAYER );
+ bReturn = true;
+ }
+ }
+ }
+
+ if(!bReturn &&
+ !bLink &&
+ (CHECK_FORMAT_TRANS(SotClipboardFormatId::EMBED_SOURCE) || CHECK_FORMAT_TRANS(SotClipboardFormatId::EMBEDDED_OBJ)) &&
+ aDataHelper.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
+ {
+ //TODO/LATER: is it possible that this format is binary?! (from old versions of SO)
+ uno::Reference < io::XInputStream > xStm;
+ TransferableObjectDescriptor aObjDesc;
+
+ if (aDataHelper.GetTransferableObjectDescriptor(SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc))
+ {
+ OUString aDocShellID = SfxObjectShell::CreateShellID(mrDoc.GetDocSh());
+ xStm = aDataHelper.GetInputStream(nFormat != SotClipboardFormatId::NONE ? nFormat : SotClipboardFormatId::EMBED_SOURCE, aDocShellID);
+ if (!xStm.is())
+ xStm = aDataHelper.GetInputStream(SotClipboardFormatId::EMBEDDED_OBJ, aDocShellID);
+ }
+
+ if (xStm.is())
+ {
+ if( mrDoc.GetDocSh() && ( mrDoc.GetDocSh()->GetClassName() == aObjDesc.maClassName ) )
+ {
+ uno::Reference < embed::XStorage > xStore( ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm ) );
+ ::sd::DrawDocShellRef xDocShRef( new ::sd::DrawDocShell( SfxObjectCreateMode::EMBEDDED, true, mrDoc.GetDocumentType() ) );
+
+ // mba: BaseURL doesn't make sense for clipboard functionality
+ SfxMedium *pMedium = new SfxMedium( xStore, OUString() );
+ if( xDocShRef->DoLoad( pMedium ) )
+ {
+ SdDrawDocument* pModel = xDocShRef->GetDoc();
+ SdPage* pWorkPage = pModel->GetSdPage( 0, PageKind::Standard );
+
+ pWorkPage->SetSdrObjListRectsDirty();
+
+ if( pOwnData )
+ {
+ // #i120393# Clipboard data uses full object geometry range
+ const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() );
+
+ maDropPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) );
+ maDropPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) );
+ }
+
+ // delete pages, that are not of any interest for us
+ for( ::tools::Long i = pModel->GetPageCount() - 1; i >= 0; i-- )
+ {
+ SdPage* pP = static_cast< SdPage* >( pModel->GetPage( static_cast<sal_uInt16>(i) ) );
+
+ if( pP->GetPageKind() != PageKind::Standard )
+ pModel->DeletePage( static_cast<sal_uInt16>(i) );
+ }
+
+ bReturn = Paste(*pModel, maDropPos, pPage, nPasteOptions);
+
+ if( !pPage )
+ pPage = static_cast<SdPage*>(GetSdrPageView()->GetPage());
+
+ OUString aLayout = pPage->GetLayoutName();
+ sal_Int32 nPos = aLayout.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ aLayout = aLayout.copy(0, nPos);
+ pPage->SetPresentationLayout( aLayout, false, false );
+ }
+
+ xDocShRef->DoClose();
+ xDocShRef.clear();
+
+ }
+ else
+ {
+ OUString aName;
+ uno::Reference < embed::XEmbeddedObject > xObj = mpDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject( xStm, aName );
+ if ( xObj.is() )
+ {
+ svt::EmbeddedObjectRef aObjRef( xObj, aObjDesc.mnViewAspect );
+
+ Size aSize;
+ if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON )
+ {
+ if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
+ aSize = aObjDesc.maSize;
+ else
+ {
+ MapMode aMapMode( MapUnit::Map100thMM );
+ aSize = aObjRef.GetSize( &aMapMode );
+ }
+ }
+ else
+ {
+ awt::Size aSz;
+ MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( aObjDesc.mnViewAspect ) );
+ if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
+ {
+ Size aTmp(OutputDevice::LogicToLogic(aObjDesc.maSize, MapMode(MapUnit::Map100thMM), MapMode(aMapUnit)));
+ aSz.Width = aTmp.Width();
+ aSz.Height = aTmp.Height();
+ xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz );
+ }
+
+ try
+ {
+ aSz = xObj->getVisualAreaSize( aObjDesc.mnViewAspect );
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {
+ // if the size still was not set the default size will be set later
+ }
+
+ aSize = Size( aSz.Width, aSz.Height );
+
+ if( !aSize.Width() || !aSize.Height() )
+ {
+ aSize.setWidth( 14100 );
+ aSize.setHeight( 10000 );
+ aSize = OutputDevice::LogicToLogic(Size(14100, 10000), MapMode(MapUnit::Map100thMM), MapMode(aMapUnit));
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+ xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz );
+ }
+
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapUnit), MapMode(MapUnit::Map100thMM));
+ }
+
+ Size aMaxSize( mrDoc.GetMaxObjSize() );
+
+ maDropPos.AdjustX( -(std::min( aSize.Width(), aMaxSize.Width() ) >> 1) );
+ maDropPos.AdjustY( -(std::min( aSize.Height(), aMaxSize.Height() ) >> 1) );
+
+ ::tools::Rectangle aRect( maDropPos, aSize );
+ SdrOle2Obj* pObj = new SdrOle2Obj(
+ getSdrModelFromSdrView(),
+ aObjRef,
+ aName,
+ aRect);
+ SdrPageView* pPV = GetSdrPageView();
+ SdrInsertFlags nOptions = SdrInsertFlags::SETDEFLAYER;
+
+ if (mpViewSh!=nullptr)
+ {
+ OSL_ASSERT (mpViewSh->GetViewShell()!=nullptr);
+ SfxInPlaceClient* pIpClient
+ = mpViewSh->GetViewShell()->GetIPClient();
+ if (pIpClient!=nullptr && pIpClient->IsObjectInPlaceActive())
+ nOptions |= SdrInsertFlags::DONTMARK;
+ }
+
+ // bInserted of false means that pObj has been deleted
+ bool bInserted = InsertObjectAtView( pObj, *pPV, nOptions );
+
+ if (bInserted && pImageMap)
+ pObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SvxIMapInfo( *pImageMap )) );
+
+ if (bInserted && pObj->IsChart())
+ {
+ bool bDisableDataTableDialog = false;
+ svt::EmbeddedObjectRef::TryRunningState( xObj );
+ uno::Reference< beans::XPropertySet > xProps( xObj->getComponent(), uno::UNO_QUERY );
+ if ( xProps.is() &&
+ ( xProps->getPropertyValue( "DisableDataTableDialog" ) >>= bDisableDataTableDialog ) &&
+ bDisableDataTableDialog )
+ {
+ xProps->setPropertyValue( "DisableDataTableDialog" , uno::Any( false ) );
+ xProps->setPropertyValue( "DisableComplexChartTypes" , uno::Any( false ) );
+ uno::Reference< util::XModifiable > xModifiable( xProps, uno::UNO_QUERY );
+ if ( xModifiable.is() )
+ {
+ xModifiable->setModified( true );
+ }
+ }
+ }
+
+ bReturn = true;
+ }
+ }
+ }
+ }
+
+ if(!bReturn &&
+ !bLink &&
+ (CHECK_FORMAT_TRANS(SotClipboardFormatId::EMBEDDED_OBJ_OLE) || CHECK_FORMAT_TRANS(SotClipboardFormatId::EMBED_SOURCE_OLE)) &&
+ aDataHelper.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR_OLE))
+ {
+ // online insert ole if format is forced or no gdi metafile is available
+ if( (nFormat != SotClipboardFormatId::NONE) || !aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
+ {
+ uno::Reference < io::XInputStream > xStm;
+ TransferableObjectDescriptor aObjDesc;
+
+ if ( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR_OLE, aObjDesc ) )
+ {
+ uno::Reference < embed::XEmbeddedObject > xObj;
+ OUString aName;
+
+ xStm = aDataHelper.GetInputStream(nFormat != SotClipboardFormatId::NONE ? nFormat : SotClipboardFormatId::EMBED_SOURCE_OLE, OUString());
+ if (!xStm.is())
+ xStm = aDataHelper.GetInputStream(SotClipboardFormatId::EMBEDDED_OBJ_OLE, OUString());
+
+ if (xStm.is())
+ {
+ xObj = mpDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject( xStm, aName );
+ }
+ else
+ {
+ try
+ {
+ uno::Reference< embed::XStorage > xTmpStor = ::comphelper::OStorageHelper::GetTemporaryStorage();
+ uno::Reference < embed::XEmbedObjectClipboardCreator > xClipboardCreator =
+ embed::MSOLEObjectSystemCreator::create( ::comphelper::getProcessComponentContext() );
+
+ embed::InsertedObjectInfo aInfo = xClipboardCreator->createInstanceInitFromClipboard(
+ xTmpStor,
+ "DummyName" ,
+ uno::Sequence< beans::PropertyValue >() );
+
+ // TODO/LATER: in future InsertedObjectInfo will be used to get container related information
+ // for example whether the object should be an iconified one
+ xObj = aInfo.Object;
+ if ( xObj.is() )
+ mpDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject( xObj, aName );
+ }
+ catch( uno::Exception& )
+ {}
+ }
+
+ if ( xObj.is() )
+ {
+ svt::EmbeddedObjectRef aObjRef( xObj, aObjDesc.mnViewAspect );
+
+ // try to get the replacement image from the clipboard
+ Graphic aGraphic;
+ SotClipboardFormatId nGrFormat = SotClipboardFormatId::NONE;
+
+// (for Selection Manager in Trusted Solaris)
+#ifndef __sun
+ if( aDataHelper.GetGraphic( SotClipboardFormatId::SVXB, aGraphic ) )
+ nGrFormat = SotClipboardFormatId::SVXB;
+ else if( aDataHelper.GetGraphic( SotClipboardFormatId::GDIMETAFILE, aGraphic ) )
+ nGrFormat = SotClipboardFormatId::GDIMETAFILE;
+ else if( aDataHelper.GetGraphic( SotClipboardFormatId::BITMAP, aGraphic ) )
+ nGrFormat = SotClipboardFormatId::BITMAP;
+#endif
+
+ // insert replacement image ( if there is one ) into the object helper
+ if ( nGrFormat != SotClipboardFormatId::NONE )
+ {
+ datatransfer::DataFlavor aDataFlavor;
+ SotExchange::GetFormatDataFlavor( nGrFormat, aDataFlavor );
+ aObjRef.SetGraphic( aGraphic, aDataFlavor.MimeType );
+ }
+
+ Size aSize;
+ if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON )
+ {
+ if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
+ aSize = aObjDesc.maSize;
+ else
+ {
+ MapMode aMapMode( MapUnit::Map100thMM );
+ aSize = aObjRef.GetSize( &aMapMode );
+ }
+ }
+ else
+ {
+ MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( aObjDesc.mnViewAspect ) );
+
+ awt::Size aSz;
+ try{
+ aSz = xObj->getVisualAreaSize( aObjDesc.mnViewAspect );
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {
+ // the default size will be set later
+ }
+
+ if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
+ {
+ Size aTmp(OutputDevice::LogicToLogic(aObjDesc.maSize, MapMode(MapUnit::Map100thMM), MapMode(aMapUnit)));
+ if ( aSz.Width != aTmp.Width() || aSz.Height != aTmp.Height() )
+ {
+ aSz.Width = aTmp.Width();
+ aSz.Height = aTmp.Height();
+ xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz );
+ }
+ }
+
+ aSize = Size( aSz.Width, aSz.Height );
+
+ if( !aSize.Width() || !aSize.Height() )
+ {
+ aSize = OutputDevice::LogicToLogic(Size(14100, 10000), MapMode(MapUnit::Map100thMM), MapMode(aMapUnit));
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+ xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz );
+ }
+
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapUnit), MapMode(MapUnit::Map100thMM));
+ }
+
+ Size aMaxSize( mrDoc.GetMaxObjSize() );
+
+ maDropPos.AdjustX( -(std::min( aSize.Width(), aMaxSize.Width() ) >> 1) );
+ maDropPos.AdjustY( -(std::min( aSize.Height(), aMaxSize.Height() ) >> 1) );
+
+ ::tools::Rectangle aRect( maDropPos, aSize );
+ SdrOle2Obj* pObj = new SdrOle2Obj(
+ getSdrModelFromSdrView(),
+ aObjRef,
+ aName,
+ aRect);
+ SdrPageView* pPV = GetSdrPageView();
+ SdrInsertFlags nOptions = SdrInsertFlags::SETDEFLAYER;
+
+ if (mpViewSh!=nullptr)
+ {
+ OSL_ASSERT (mpViewSh->GetViewShell()!=nullptr);
+ SfxInPlaceClient* pIpClient
+ = mpViewSh->GetViewShell()->GetIPClient();
+ if (pIpClient!=nullptr && pIpClient->IsObjectInPlaceActive())
+ nOptions |= SdrInsertFlags::DONTMARK;
+ }
+
+ bReturn = InsertObjectAtView( pObj, *pPV, nOptions );
+
+ if (bReturn)
+ {
+ if( pImageMap )
+ pObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SvxIMapInfo( *pImageMap )) );
+
+ // let the object stay in loaded state after insertion
+ pObj->Unload();
+ }
+ }
+ }
+ }
+
+ if( !bReturn && aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
+ {
+ // if no object was inserted, insert a picture
+ InsertMetaFile( aDataHelper, rPos, pImageMap.get(), true );
+ bReturn = true;
+ }
+ }
+
+ if(!bReturn && (!bLink || pPickObj) && CHECK_FORMAT_TRANS(SotClipboardFormatId::SVXB))
+ {
+ ::tools::SvRef<SotTempStream> xStm;
+
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB, xStm ) )
+ {
+ Point aInsertPos( rPos );
+ Graphic aGraphic;
+
+ TypeSerializer aSerializer(*xStm);
+ aSerializer.readGraphic(aGraphic);
+
+ if( pOwnData && pOwnData->GetWorkDocument() )
+ {
+ const SdDrawDocument* pWorkModel = pOwnData->GetWorkDocument();
+ SdrPage* pWorkPage = const_cast<SdrPage*>( ( pWorkModel->GetPageCount() > 1 ) ?
+ pWorkModel->GetSdPage( 0, PageKind::Standard ) :
+ pWorkModel->GetPage( 0 ) );
+
+ pWorkPage->SetSdrObjListRectsDirty();
+
+ // #i120393# Clipboard data uses full object geometry range
+ const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() );
+
+ aInsertPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) );
+ aInsertPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) );
+ }
+
+ // restrict movement to WorkArea
+ Size aImageMapSize = OutputDevice::LogicToLogic(aGraphic.GetPrefSize(),
+ aGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM));
+
+ ImpCheckInsertPos(aInsertPos, aImageMapSize, GetWorkArea());
+
+ InsertGraphic( aGraphic, mnAction, aInsertPos, nullptr, pImageMap.get() );
+ bReturn = true;
+ }
+ }
+
+ if(!bReturn && (!bLink || pPickObj) && CHECK_FORMAT_TRANS(SotClipboardFormatId::GDIMETAFILE))
+ {
+ Point aInsertPos( rPos );
+
+ if( pOwnData && pOwnData->GetWorkDocument() )
+
+ {
+ const SdDrawDocument* pWorkModel = pOwnData->GetWorkDocument();
+ SdrPage* pWorkPage = const_cast<SdrPage*>( ( pWorkModel->GetPageCount() > 1 ) ?
+ pWorkModel->GetSdPage( 0, PageKind::Standard ) :
+ pWorkModel->GetPage( 0 ) );
+
+ pWorkPage->SetSdrObjListRectsDirty();
+
+ // #i120393# Clipboard data uses full object geometry range
+ const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() );
+
+ aInsertPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) );
+ aInsertPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) );
+ }
+
+ bReturn = InsertMetaFile( aDataHelper, aInsertPos, pImageMap.get(), nFormat == SotClipboardFormatId::NONE );
+ }
+
+ if(!bReturn && (!bLink || pPickObj) && CHECK_FORMAT_TRANS(SotClipboardFormatId::BITMAP))
+ {
+ BitmapEx aBmpEx;
+
+ // get basic Bitmap data
+ aDataHelper.GetBitmapEx(SotClipboardFormatId::BITMAP, aBmpEx);
+
+ if(aBmpEx.IsEmpty())
+ {
+ // if this did not work, try to get graphic formats and convert these to bitmap
+ Graphic aGraphic;
+
+ if(aDataHelper.GetGraphic(SotClipboardFormatId::GDIMETAFILE, aGraphic))
+ {
+ aBmpEx = aGraphic.GetBitmapEx();
+ }
+ else if(aDataHelper.GetGraphic(SotClipboardFormatId::SVXB, aGraphic))
+ {
+ aBmpEx = aGraphic.GetBitmapEx();
+ }
+ else if(aDataHelper.GetGraphic(SotClipboardFormatId::BITMAP, aGraphic))
+ {
+ aBmpEx = aGraphic.GetBitmapEx();
+ }
+ }
+
+ if(!aBmpEx.IsEmpty())
+ {
+ Point aInsertPos( rPos );
+
+ if( pOwnData && pOwnData->GetWorkDocument() )
+ {
+ const SdDrawDocument* pWorkModel = pOwnData->GetWorkDocument();
+ SdrPage* pWorkPage = const_cast<SdrPage*>( ( pWorkModel->GetPageCount() > 1 ) ?
+ pWorkModel->GetSdPage( 0, PageKind::Standard ) :
+ pWorkModel->GetPage( 0 ) );
+
+ pWorkPage->SetSdrObjListRectsDirty();
+
+ // #i120393# Clipboard data uses full object geometry range
+ const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() );
+
+ aInsertPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) );
+ aInsertPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) );
+ }
+
+ // restrict movement to WorkArea
+ Size aImageMapSize(aBmpEx.GetPrefSize());
+ ImpCheckInsertPos(aInsertPos, aImageMapSize, GetWorkArea());
+
+ InsertGraphic( aBmpEx, mnAction, aInsertPos, nullptr, pImageMap.get() );
+ bReturn = true;
+ }
+ }
+
+ if(!bReturn && pPickObj && CHECK_FORMAT_TRANS( SotClipboardFormatId::XFA ) )
+ {
+ uno::Any const data(aDataHelper.GetAny(SotClipboardFormatId::XFA, ""));
+ uno::Sequence<beans::NamedValue> props;
+ if (data >>= props)
+ {
+ if( IsUndoEnabled() )
+ {
+ BegUndo( SdResId(STR_UNDO_DRAGDROP) );
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoAttrObject( *pPickObj ) );
+ EndUndo();
+ }
+
+ ::comphelper::SequenceAsHashMap const map(props);
+ drawing::FillStyle eFill(drawing::FillStyle_BITMAP); // default to something that's ignored
+ Color aColor(COL_BLACK);
+ auto it = map.find("FillStyle");
+ if (it != map.end())
+ {
+ XFillStyleItem style;
+ style.PutValue(it->second, 0);
+ eFill = style.GetValue();
+ }
+ it = map.find("FillColor");
+ if (it != map.end())
+ {
+ XFillColorItem color;
+ color.PutValue(it->second, 0);
+ aColor = color.GetColorValue();
+ }
+
+ if( eFill == drawing::FillStyle_SOLID || eFill == drawing::FillStyle_NONE )
+ {
+ SfxItemSet aSet( mrDoc.GetPool() );
+ bool bClosed = pPickObj->IsClosedObj();
+ ::sd::Window* pWin = mpViewSh->GetActiveWindow();
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(pWin->PixelToLogic(
+ Size(FuPoor::HITPIX, 0 ) ).Width());
+ const ::tools::Long n2HitLog = nHitLog << 1;
+ Point aHitPosR( rPos );
+ Point aHitPosL( rPos );
+ Point aHitPosT( rPos );
+ Point aHitPosB( rPos );
+ const SdrLayerIDSet* pVisiLayer = &GetSdrPageView()->GetVisibleLayers();
+
+ aHitPosR.AdjustX(n2HitLog );
+ aHitPosL.AdjustX( -n2HitLog );
+ aHitPosT.AdjustY(n2HitLog );
+ aHitPosB.AdjustY( -n2HitLog );
+
+ if( bClosed &&
+ SdrObjectPrimitiveHit(*pPickObj, aHitPosR, nHitLog, *GetSdrPageView(), pVisiLayer, false) &&
+ SdrObjectPrimitiveHit(*pPickObj, aHitPosL, nHitLog, *GetSdrPageView(), pVisiLayer, false) &&
+ SdrObjectPrimitiveHit(*pPickObj, aHitPosT, nHitLog, *GetSdrPageView(), pVisiLayer, false) &&
+ SdrObjectPrimitiveHit(*pPickObj, aHitPosB, nHitLog, *GetSdrPageView(), pVisiLayer, false) )
+ {
+ // area fill
+ if(eFill == drawing::FillStyle_SOLID )
+ aSet.Put(XFillColorItem("", aColor));
+
+ aSet.Put( XFillStyleItem( eFill ) );
+ }
+ else
+ aSet.Put( XLineColorItem( "", aColor ) );
+
+ // add text color
+ pPickObj->SetMergedItemSetAndBroadcast( aSet );
+ }
+ bReturn = true;
+ }
+ }
+
+ if(!bReturn && !bLink && CHECK_FORMAT_TRANS(SotClipboardFormatId::HTML))
+ {
+ ::tools::SvRef<SotTempStream> xStm;
+
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::HTML, xStm ) )
+ {
+ xStm->Seek( 0 );
+ // mba: clipboard always must contain absolute URLs (could be from alien source)
+ bReturn = SdrView::Paste( *xStm, EETextFormat::Html, maDropPos, pPage, nPasteOptions );
+ }
+ }
+
+ if(!bReturn && !bLink && CHECK_FORMAT_TRANS(SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT))
+ {
+ ::tools::SvRef<SotTempStream> xStm;
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT, xStm ) )
+ {
+ OutlinerView* pOLV = GetTextEditOutlinerView();
+
+ xStm->Seek( 0 );
+
+ if( pOLV )
+ {
+ ::tools::Rectangle aRect( pOLV->GetOutputArea() );
+ Point aPos( pOLV->GetWindow()->PixelToLogic( maDropPos ) );
+
+ if( aRect.Contains( aPos ) || ( !bDrag && IsTextEdit() ) )
+ {
+ // mba: clipboard always must contain absolute URLs (could be from alien source)
+ pOLV->Read( *xStm, EETextFormat::Xml, mpDocSh->GetHeaderAttributes() );
+ bReturn = true;
+ }
+ }
+
+ if( !bReturn )
+ // mba: clipboard always must contain absolute URLs (could be from alien source)
+ bReturn = SdrView::Paste( *xStm, EETextFormat::Xml, maDropPos, pPage, nPasteOptions );
+ }
+ }
+
+ if(!bReturn && !bLink)
+ {
+ bool bIsRTF = CHECK_FORMAT_TRANS(SotClipboardFormatId::RTF);
+ if (bIsRTF || CHECK_FORMAT_TRANS(SotClipboardFormatId::RICHTEXT))
+ {
+ ::tools::SvRef<SotTempStream> xStm;
+
+ if( aDataHelper.GetSotStorageStream( bIsRTF ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT, xStm ) )
+ {
+ xStm->Seek( 0 );
+
+ if( bTable )
+ {
+ bReturn = PasteRTFTable( xStm, pPage, nPasteOptions );
+ }
+ else
+ {
+ OutlinerView* pOLV = GetTextEditOutlinerView();
+
+ if( pOLV )
+ {
+ ::tools::Rectangle aRect( pOLV->GetOutputArea() );
+ Point aPos( pOLV->GetWindow()->PixelToLogic( maDropPos ) );
+
+ if( aRect.Contains( aPos ) || ( !bDrag && IsTextEdit() ) )
+ {
+ // mba: clipboard always must contain absolute URLs (could be from alien source)
+ pOLV->Read( *xStm, EETextFormat::Rtf, mpDocSh->GetHeaderAttributes() );
+ bReturn = true;
+ }
+ }
+
+ if( !bReturn )
+ // mba: clipboard always must contain absolute URLs (could be from alien source)
+ bReturn = SdrView::Paste( *xStm, EETextFormat::Rtf, maDropPos, pPage, nPasteOptions );
+ }
+ }
+ }
+ }
+
+ if(!bReturn && CHECK_FORMAT_TRANS(SotClipboardFormatId::FILE_LIST))
+ {
+ FileList aDropFileList;
+
+ if( aDataHelper.GetFileList( SotClipboardFormatId::FILE_LIST, aDropFileList ) )
+ {
+ maDropFileVector.clear();
+
+ for( sal_uLong i = 0, nCount = aDropFileList.Count(); i < nCount; i++ )
+ maDropFileVector.push_back( aDropFileList.GetFile( i ) );
+
+ maDropInsertFileIdle.Start();
+ }
+
+ bReturn = true;
+ }
+
+ if(!bReturn && CHECK_FORMAT_TRANS(SotClipboardFormatId::SIMPLE_FILE))
+ {
+ OUString aDropFile;
+
+ if( aDataHelper.GetString( SotClipboardFormatId::SIMPLE_FILE, aDropFile ) )
+ {
+ maDropFileVector.clear();
+ maDropFileVector.push_back( aDropFile );
+ maDropInsertFileIdle.Start();
+ }
+
+ bReturn = true;
+ }
+
+ if(!bReturn && !bLink && CHECK_FORMAT_TRANS(SotClipboardFormatId::STRING))
+ {
+ if( ( SotClipboardFormatId::STRING == nFormat ) ||
+ ( !aDataHelper.HasFormat( SotClipboardFormatId::SOLK ) &&
+ !aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) &&
+ !aDataHelper.HasFormat( SotClipboardFormatId::FILENAME ) ) )
+ {
+ OUString aOUString;
+
+ if( aDataHelper.GetString( SotClipboardFormatId::STRING, aOUString ) )
+ {
+ OutlinerView* pOLV = GetTextEditOutlinerView();
+
+ if( pOLV )
+ {
+ pOLV->InsertText( aOUString );
+ bReturn = true;
+ }
+
+ if( !bReturn )
+ bReturn = SdrView::Paste( aOUString, maDropPos, pPage, nPasteOptions );
+ }
+ }
+ }
+
+ MarkListHasChanged();
+ mbIsDropAllowed = true;
+ rDnDAction = mnAction;
+
+ if (bGroupUndoFromDragWithDrop)
+ {
+ // this is called eventually by the underlying toolkit anyway in the case of a self-dnd
+ // but we call it early in this case to group its undo actions into this open dnd undo group
+ // and rely on that repeated calls to View::DragFinished are safe to do
+ DragFinished(mnAction);
+ EndUndo();
+ }
+
+ return bReturn;
+}
+
+bool View::PasteRTFTable( const ::tools::SvRef<SotTempStream>& xStm, SdrPage* pPage, SdrInsertFlags nPasteOptions )
+{
+ SdDrawDocument aModel( DocumentType::Impress, mpDocSh );
+ aModel.NewOrLoadCompleted(DocCreationMode::New);
+ aModel.GetItemPool().SetDefaultMetric(MapUnit::Map100thMM);
+ aModel.InsertPage(aModel.AllocPage(false).get());
+
+ Reference< XComponent > xComponent( new SdXImpressDocument( &aModel, true ) );
+ aModel.setUnoModel( Reference< XInterface >::query( xComponent ) );
+
+ CreateTableFromRTF( *xStm, &aModel );
+ bool bRet = Paste(aModel, maDropPos, pPage, nPasteOptions);
+
+ xComponent->dispose();
+ xComponent.clear();
+
+ return bRet;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/sdview4.cxx b/sd/source/ui/view/sdview4.cxx
new file mode 100644
index 000000000..7a3c7c226
--- /dev/null
+++ b/sd/source/ui/view/sdview4.cxx
@@ -0,0 +1,645 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <View.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <osl/file.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <vcl/outdev.hxx>
+#include <vcl/pdfread.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdomedia.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <sfx2/app.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <svtools/ehdl.hxx>
+#include <svtools/sfxecode.hxx>
+#include <svtools/embedhlp.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <app.hrc>
+#include <Window.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <fuinsfil.hxx>
+#include <drawdoc.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <sdpage.hxx>
+#include <view/SlideSorterView.hxx>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+#include <svtools/soerr.hxx>
+#include <sfx2/ipclient.hxx>
+#include <tools/debug.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+/**
+ * If an empty graphic object is provided, we fill it. Otherwise we fill an
+ * existing object at the specified position. If there is no object at the
+ * position, we create a new object and return a pointer to it.
+ */
+SdrGrafObj* View::InsertGraphic( const Graphic& rGraphic, sal_Int8& rAction,
+ const Point& rPos, SdrObject* pObj, ImageMap const * pImageMap )
+{
+ SdrEndTextEdit();
+ mnAction = rAction;
+
+ // Is there an object at the position rPos?
+ SdrGrafObj* pNewGrafObj = nullptr;
+ SdrPageView* pPV = GetSdrPageView();
+ SdrObject* pPickObj = pObj;
+ const bool bOnMaster = pPV && pPV->GetPage() && pPV->GetPage()->IsMasterPage();
+
+ if(pPV && dynamic_cast< const ::sd::slidesorter::view::SlideSorterView* >(this) != nullptr)
+ {
+ if(!pPV->GetPageRect().Contains(rPos))
+ pPV = nullptr;
+ }
+
+ if( !pPickObj && pPV )
+ {
+ SdrPageView* pPageView = pPV;
+ pPickObj = PickObj(rPos, getHitTolLog(), pPageView);
+ }
+
+ const bool bIsGraphic(dynamic_cast< const SdrGrafObj* >(pPickObj) != nullptr);
+
+ if (DND_ACTION_LINK == mnAction
+ && pPickObj
+ && pPV
+ && (bIsGraphic || (pPickObj->IsEmptyPresObj() && !bOnMaster))) // #121603# Do not use pObj, it may be NULL
+ {
+ // hit on SdrGrafObj with wanted new linked graphic (or PresObj placeholder hit)
+ if( IsUndoEnabled() )
+ BegUndo(SdResId(STR_INSERTGRAPHIC));
+
+ SdPage* pPage = static_cast<SdPage*>( pPickObj->getSdrPageFromSdrObject() );
+
+ if( bIsGraphic )
+ {
+ // We fill the object with the Bitmap
+ pNewGrafObj = static_cast<SdrGrafObj*>( pPickObj->CloneSdrObject(pPickObj->getSdrModelFromSdrObject()) );
+ pNewGrafObj->SetGraphic(rGraphic);
+ }
+ else
+ {
+ pNewGrafObj = new SdrGrafObj(
+ getSdrModelFromSdrView(),
+ rGraphic,
+ pPickObj->GetLogicRect());
+ pNewGrafObj->SetEmptyPresObj(true);
+ }
+
+ if ( pNewGrafObj->IsEmptyPresObj() )
+ {
+ ::tools::Rectangle aRect( pNewGrafObj->GetLogicRect() );
+ pNewGrafObj->AdjustToMaxRect( aRect );
+ pNewGrafObj->SetOutlinerParaObject(std::nullopt);
+ pNewGrafObj->SetEmptyPresObj(false);
+ }
+
+ if (pPage && pPage->IsPresObj(pPickObj))
+ {
+ // Insert new PresObj into the list
+ pPage->InsertPresObj( pNewGrafObj, PresObjKind::Graphic );
+ pNewGrafObj->SetUserCall(pPickObj->GetUserCall());
+ }
+
+ if (pImageMap)
+ pNewGrafObj->AppendUserData(std::unique_ptr<SdrObjUserData>(new SvxIMapInfo(*pImageMap)));
+
+ ReplaceObjectAtView(pPickObj, *pPV, pNewGrafObj); // maybe ReplaceObjectAtView
+
+ if( IsUndoEnabled() )
+ EndUndo();
+ }
+ else if (DND_ACTION_LINK == mnAction
+ && pPickObj
+ && !bIsGraphic
+ && pPickObj->IsClosedObj()
+ && !dynamic_cast< const SdrOle2Obj* >(pPickObj))
+ {
+ // fill style change (fill object with graphic), independent of mnAction
+ // and thus of DND_ACTION_LINK or DND_ACTION_MOVE
+ if( IsUndoEnabled() )
+ {
+ BegUndo(SdResId(STR_UNDO_DRAGDROP));
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pPickObj));
+ EndUndo();
+ }
+
+ SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLBITMAP> aSet(mpDocSh->GetPool());
+
+ aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP));
+ aSet.Put(XFillBitmapItem(rGraphic));
+ pPickObj->SetMergedItemSetAndBroadcast(aSet);
+ }
+
+ else if ( pPV )
+ {
+ Size aSizePixel = rGraphic.GetSizePixel();
+
+ // create new object
+ Size aSize;
+
+ if ( rGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
+ {
+ ::OutputDevice* pOutDev = nullptr;
+ if( mpViewSh )
+ pOutDev = mpViewSh->GetActiveWindow()->GetOutDev();
+
+ if( !pOutDev )
+ pOutDev = Application::GetDefaultDevice();
+
+ if( pOutDev )
+ aSize = pOutDev->PixelToLogic(rGraphic.GetPrefSize(), MapMode(MapUnit::Map100thMM));
+ }
+ else
+ {
+ aSize = OutputDevice::LogicToLogic( rGraphic.GetPrefSize(),
+ rGraphic.GetPrefMapMode(),
+ MapMode( MapUnit::Map100thMM ) );
+ }
+
+ sal_Int32 nPreferredDPI = mrDoc.getImagePreferredDPI();
+
+ if (rGraphic.GetGfxLink().GetType() == GfxLinkType::NativePdf && nPreferredDPI == 0 && vcl::PDF_INSERT_MAGIC_SCALE_FACTOR > 1)
+ nPreferredDPI = Application::GetDefaultDevice()->GetDPIX() * vcl::PDF_INSERT_MAGIC_SCALE_FACTOR;
+
+ if (nPreferredDPI > 0)
+ {
+ auto nWidth = o3tl::convert(aSizePixel.Width() / double(nPreferredDPI), o3tl::Length::in, o3tl::Length::mm100);
+ auto nHeight = o3tl::convert(aSizePixel.Height() / double(nPreferredDPI), o3tl::Length::in, o3tl::Length::mm100);
+ if (nWidth > 0 && nHeight > 0)
+ aSize = Size(nWidth, nHeight);
+ }
+
+ pNewGrafObj = new SdrGrafObj(getSdrModelFromSdrView(), rGraphic, ::tools::Rectangle(rPos, aSize));
+
+ if (nPreferredDPI > 0)
+ {
+ // move to the center of insertion point
+ pNewGrafObj->NbcMove(Size(-aSize.Width() / 2, -aSize.Height() / 2));
+ }
+ else
+ {
+ SdrPage* pPage = pPV->GetPage();
+ Size aPageSize( pPage->GetSize() );
+ aPageSize.AdjustWidth( -(pPage->GetLeftBorder() + pPage->GetRightBorder()) );
+ aPageSize.AdjustHeight( -(pPage->GetUpperBorder() + pPage->GetLowerBorder()) );
+ pNewGrafObj->AdjustToMaxRect( ::tools::Rectangle( Point(), aPageSize ), true );
+ }
+
+ SdrInsertFlags nOptions = SdrInsertFlags::SETDEFLAYER;
+ bool bIsPresTarget = false;
+
+ if ((mpViewSh
+ && mpViewSh->GetViewShell()!=nullptr
+ && mpViewSh->GetViewShell()->GetIPClient()
+ && mpViewSh->GetViewShell()->GetIPClient()->IsObjectInPlaceActive())
+ || dynamic_cast<const ::sd::slidesorter::view::SlideSorterView* >(this))
+ nOptions |= SdrInsertFlags::DONTMARK;
+
+ if( ( mnAction & DND_ACTION_MOVE ) && pPickObj && (pPickObj->IsEmptyPresObj() || pPickObj->GetUserCall()) )
+ {
+ SdPage* pP = static_cast< SdPage* >( pPickObj->getSdrPageFromSdrObject() );
+
+ if ( pP && pP->IsMasterPage() )
+ bIsPresTarget = pP->IsPresObj(pPickObj);
+ }
+
+ if( ( mnAction & DND_ACTION_MOVE ) && pPickObj && !bIsPresTarget )
+ {
+ // replace object
+ if (pImageMap)
+ pNewGrafObj->AppendUserData(std::unique_ptr<SdrObjUserData>(new SvxIMapInfo(*pImageMap)));
+
+ ::tools::Rectangle aPickObjRect(pPickObj->GetCurrentBoundRect());
+ Size aPickObjSize(aPickObjRect.GetSize());
+ ::tools::Rectangle aObjRect(pNewGrafObj->GetCurrentBoundRect());
+ Size aObjSize(aObjRect.GetSize());
+
+ Fraction aScaleWidth(aPickObjSize.Width(), aObjSize.Width());
+ Fraction aScaleHeight(aPickObjSize.Height(), aObjSize.Height());
+ pNewGrafObj->NbcResize(aObjRect.TopLeft(), aScaleWidth, aScaleHeight);
+
+ Point aVec = aPickObjRect.TopLeft() - aObjRect.TopLeft();
+ pNewGrafObj->NbcMove(Size(aVec.X(), aVec.Y()));
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo(SdResId(STR_UNDO_DRAGDROP));
+ pNewGrafObj->NbcSetLayer(pPickObj->GetLayer());
+ SdrPage* pP = pPV->GetPage();
+ pP->InsertObject(pNewGrafObj);
+ if( bUndo )
+ {
+ AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoNewObject(*pNewGrafObj));
+ AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeleteObject(*pPickObj));
+ }
+ pP->RemoveObject(pPickObj->GetOrdNum());
+
+ if( bUndo )
+ {
+ EndUndo();
+ }
+ else
+ {
+ SdrObject::Free(pPickObj);
+ }
+ mnAction = DND_ACTION_COPY;
+ }
+ else
+ {
+ bool bSuccess = InsertObjectAtView(pNewGrafObj, *pPV, nOptions);
+ if (!bSuccess)
+ pNewGrafObj = nullptr;
+ else if (pImageMap)
+ pNewGrafObj->AppendUserData(std::unique_ptr<SdrObjUserData>(new SvxIMapInfo(*pImageMap)));
+ }
+ }
+
+ rAction = mnAction;
+
+ return pNewGrafObj;
+}
+
+void View::InsertMediaURL( const OUString& rMediaURL, sal_Int8& rAction,
+ const Point& rPos, const Size& rSize,
+ bool const bLink )
+{
+ OUString realURL;
+ if (bLink)
+ {
+ realURL = rMediaURL;
+ }
+ else
+ {
+ uno::Reference<frame::XModel> const xModel(
+ GetDoc().GetObjectShell()->GetModel());
+#if HAVE_FEATURE_AVMEDIA
+ bool const bRet = ::avmedia::EmbedMedia(xModel, rMediaURL, realURL);
+ if (!bRet) { return; }
+#else
+ return;
+#endif
+ }
+
+ InsertMediaObj( realURL, "application/vnd.sun.star.media", rAction, rPos, rSize );
+}
+
+SdrMediaObj* View::InsertMediaObj( const OUString& rMediaURL, const OUString& rMimeType, sal_Int8& rAction,
+ const Point& rPos, const Size& rSize )
+{
+ SdrEndTextEdit();
+ mnAction = rAction;
+
+ SdrMediaObj* pNewMediaObj = nullptr;
+ SdrPageView* pPV = GetSdrPageView();
+ SdrObject* pPickObj = GetEmptyPresentationObject( PresObjKind::Media );
+
+ if(pPV && dynamic_cast<const ::sd::slidesorter::view::SlideSorterView* >(this) )
+ {
+ if(!pPV->GetPageRect().Contains(rPos))
+ pPV = nullptr;
+ }
+
+ if( mnAction == DND_ACTION_LINK && pPV && dynamic_cast< SdrMediaObj *>( pPickObj ) )
+ {
+ pNewMediaObj = static_cast< SdrMediaObj* >( pPickObj->CloneSdrObject(pPickObj->getSdrModelFromSdrObject()) );
+ pNewMediaObj->setURL( rMediaURL, ""/*TODO?*/, rMimeType );
+
+ BegUndo(SdResId(STR_UNDO_DRAGDROP));
+ ReplaceObjectAtView(pPickObj, *pPV, pNewMediaObj);
+ EndUndo();
+ }
+ else if( pPV )
+ {
+ ::tools::Rectangle aRect( rPos, rSize );
+ SdrObjUserCall* pUserCall = nullptr;
+ if( pPickObj )
+ {
+ aRect = pPickObj->GetLogicRect();
+ pUserCall = pPickObj->GetUserCall(); // ReplaceObjectAtView can free pPickObj
+ }
+
+ pNewMediaObj = new SdrMediaObj(
+ getSdrModelFromSdrView(),
+ aRect);
+
+ bool bIsPres = false;
+ if( pPickObj )
+ {
+ SdPage* pPage = static_cast< SdPage* >(pPickObj->getSdrPageFromSdrObject());
+ bIsPres = pPage && pPage->IsPresObj(pPickObj);
+ if( bIsPres )
+ {
+ pPage->InsertPresObj( pNewMediaObj, PresObjKind::Media );
+ }
+ }
+
+ if( pPickObj )
+ ReplaceObjectAtView(pPickObj, *pPV, pNewMediaObj);
+ else
+ {
+ if (!InsertObjectAtView(pNewMediaObj, *pPV, SdrInsertFlags::SETDEFLAYER))
+ pNewMediaObj = nullptr;
+ }
+
+ OUString referer;
+ DrawDocShell * sh = GetDocSh();
+ if (sh != nullptr && sh->HasName()) {
+ referer = sh->GetMedium()->GetName();
+ }
+
+ if (pNewMediaObj)
+ {
+ pNewMediaObj->setURL( rMediaURL, referer, rMimeType );
+
+ if( pPickObj )
+ {
+ pNewMediaObj->AdjustToMaxRect( aRect );
+ if( bIsPres )
+ pNewMediaObj->SetUserCall( pUserCall );
+ }
+ }
+ }
+
+ rAction = mnAction;
+
+ return pNewMediaObj;
+}
+
+/**
+ * Timer handler for InsertFile at Drop()
+ */
+IMPL_LINK_NOARG(View, DropInsertFileHdl, Timer *, void)
+{
+ DBG_ASSERT( mpViewSh, "sd::View::DropInsertFileHdl(), I need a view shell to work!" );
+ if( !mpViewSh )
+ return;
+
+ SfxErrorContext aEc( ERRCTX_ERROR, mpViewSh->GetFrameWeld(), RID_SO_ERRCTX );
+ ErrCode nError = ERRCODE_NONE;
+
+ ::std::vector< OUString >::const_iterator aIter( maDropFileVector.begin() );
+
+ while( (aIter != maDropFileVector.end()) && !nError )
+ {
+ OUString aCurrentDropFile( *aIter );
+ INetURLObject aURL( aCurrentDropFile );
+ bool bHandled = false;
+
+ if( aURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ OUString aURLStr;
+ osl::FileBase::getFileURLFromSystemPath( aCurrentDropFile, aURLStr );
+ aURL = INetURLObject( aURLStr );
+ }
+
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ Graphic aGraphic;
+
+ aCurrentDropFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+#if HAVE_FEATURE_AVMEDIA
+ if( !::avmedia::MediaWindow::isMediaURL( aCurrentDropFile, ""/*TODO?*/ ) )
+#else
+#endif
+ {
+ if( !rGraphicFilter.ImportGraphic( aGraphic, aURL ) )
+ {
+ sal_Int8 nTempAction = ( aIter == maDropFileVector.begin() ) ? mnAction : 0;
+ const bool bLink = ( ( nTempAction & DND_ACTION_LINK ) != 0 );
+ SdrGrafObj* pGrafObj = InsertGraphic( aGraphic, nTempAction, maDropPos, nullptr, nullptr );
+ if(pGrafObj && bLink)
+ {
+ pGrafObj->SetGraphicLink( aCurrentDropFile );
+ }
+
+ // return action from first inserted graphic
+ if( aIter == maDropFileVector.begin() )
+ mnAction = nTempAction;
+
+ bHandled = true;
+ }
+ if (!bHandled)
+ {
+ std::shared_ptr<const SfxFilter> pFoundFilter;
+ SfxMedium aSfxMedium( aCurrentDropFile, StreamMode::READ | StreamMode::SHARE_DENYNONE );
+ ErrCode nErr = SfxGetpApp()->GetFilterMatcher().GuessFilter( aSfxMedium, pFoundFilter );
+
+ if( pFoundFilter && !nErr )
+ {
+ ::std::vector< OUString > aFilterVector;
+ OUString aFilterName = pFoundFilter->GetFilterName();
+ OUString aLowerAsciiFileName = aCurrentDropFile.toAsciiLowerCase();
+
+ FuInsertFile::GetSupportedFilterVector( aFilterVector );
+
+ if( ( ::std::find( aFilterVector.begin(), aFilterVector.end(), pFoundFilter->GetMimeType() ) != aFilterVector.end() ) ||
+ aFilterName.indexOf( "Text" ) != -1 ||
+ aFilterName.indexOf( "Rich" ) != -1 ||
+ aFilterName.indexOf( "RTF" ) != -1 ||
+ aFilterName.indexOf( "HTML" ) != -1 ||
+ aLowerAsciiFileName.indexOf(".sdd") != -1 ||
+ aLowerAsciiFileName.indexOf(".sda") != -1 ||
+ aLowerAsciiFileName.indexOf(".sxd") != -1 ||
+ aLowerAsciiFileName.indexOf(".sxi") != -1 ||
+ aLowerAsciiFileName.indexOf(".std") != -1 ||
+ aLowerAsciiFileName.indexOf(".sti") != -1 )
+ {
+ ::sd::Window* pWin = mpViewSh->GetActiveWindow();
+ SfxRequest aReq(SID_INSERTFILE, ::SfxCallMode::SLOT, mrDoc.GetItemPool());
+ SfxStringItem aItem1( ID_VAL_DUMMY0, aCurrentDropFile ), aItem2( ID_VAL_DUMMY1, pFoundFilter->GetFilterName() );
+
+ aReq.AppendItem( aItem1 );
+ aReq.AppendItem( aItem2 );
+ FuInsertFile::Create( mpViewSh, pWin, this, &mrDoc, aReq );
+ bHandled = true;
+ }
+ }
+ }
+ }
+
+#if HAVE_FEATURE_AVMEDIA
+ if (!bHandled)
+ {
+ bool bShallowDetect = ::avmedia::MediaWindow::isMediaURL(aCurrentDropFile, ""/*TODO?*/);
+ if (bShallowDetect)
+ {
+ mxDropMediaSizeListener.set(new avmedia::PlayerListener(
+ [this, aCurrentDropFile](const css::uno::Reference<css::media::XPlayer>& rPlayer){
+ SolarMutexGuard g;
+
+ css::awt::Size aSize = rPlayer->getPreferredPlayerWindowSize();
+ Size aPrefSize(aSize.Width, aSize.Height);
+
+ if (aPrefSize.Width() && aPrefSize.Height())
+ {
+ ::sd::Window* pWin = mpViewSh->GetActiveWindow();
+
+ if( pWin )
+ aPrefSize = pWin->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM));
+ else
+ aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM));
+ }
+ else
+ aPrefSize = Size( 5000, 5000 );
+
+ InsertMediaURL(aCurrentDropFile, mnAction, maDropPos, aPrefSize, true);
+
+ mxDropMediaSizeListener.clear();
+ }));
+ }
+ bHandled = bShallowDetect && ::avmedia::MediaWindow::isMediaURL(aCurrentDropFile, ""/*TODO?*/, true, mxDropMediaSizeListener);
+ }
+#endif
+
+ if (!bHandled)
+ {
+ if( mnAction & DND_ACTION_LINK )
+ static_cast< DrawViewShell* >( mpViewSh )->InsertURLButton( aCurrentDropFile, aCurrentDropFile, OUString(), &maDropPos );
+ else
+ {
+ if( mpViewSh )
+ {
+ try
+ {
+ //TODO/MBA: testing
+ OUString aName;
+ uno::Sequence < beans::PropertyValue > aMedium{ comphelper::makePropertyValue(
+ "URL", aCurrentDropFile) };
+
+ uno::Reference < embed::XEmbeddedObject > xObj = mpDocSh->GetEmbeddedObjectContainer().
+ InsertEmbeddedObject( aMedium, aName );
+
+ uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
+ if ( xPersist.is())
+ {
+ // TODO/LEAN: VisualArea access can switch the object to running state
+ sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
+
+ xPersist->storeOwn();
+
+ awt::Size aSz;
+ try
+ {
+ aSz = xObj->getVisualAreaSize( nAspect );
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {
+ // the default size will be set later
+ }
+
+ Size aSize( aSz.Width, aSz.Height );
+ ::tools::Rectangle aRect;
+
+ if (!aSize.Width() || !aSize.Height())
+ {
+ aSize.setWidth( 1410 );
+ aSize.setHeight( 1000 );
+ }
+
+ aRect = ::tools::Rectangle( maDropPos, aSize );
+
+ SdrOle2Obj* pOleObj = new SdrOle2Obj(
+ getSdrModelFromSdrView(),
+ svt::EmbeddedObjectRef(xObj, nAspect),
+ aName,
+ aRect);
+ SdrInsertFlags nOptions = SdrInsertFlags::SETDEFLAYER;
+
+ if (mpViewSh != nullptr)
+ {
+ OSL_ASSERT (mpViewSh->GetViewShell()!=nullptr);
+ SfxInPlaceClient* pIpClient =
+ mpViewSh->GetViewShell()->GetIPClient();
+ if (pIpClient!=nullptr && pIpClient->IsObjectInPlaceActive())
+ nOptions |= SdrInsertFlags::DONTMARK;
+ }
+
+ if (InsertObjectAtView( pOleObj, *GetSdrPageView(), nOptions ))
+ pOleObj->SetLogicRect( aRect );
+ aSz.Width = aRect.GetWidth();
+ aSz.Height = aRect.GetHeight();
+ xObj->setVisualAreaSize( nAspect,aSz );
+ }
+ }
+ catch( uno::Exception& )
+ {
+ nError = ERRCODE_IO_GENERAL;
+ // TODO/LATER: better error handling
+ }
+ }
+ }
+ }
+
+ ++aIter;
+ }
+
+ if( nError )
+ ErrorHandler::HandleError( nError );
+}
+
+/**
+ * Timer handler for Errorhandling at Drop()
+ */
+IMPL_LINK_NOARG(View, DropErrorHdl, Timer *, void)
+{
+ vcl::Window* pWin = mpViewSh ? mpViewSh->GetActiveWindow() : nullptr;
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWin ? pWin->GetFrameWeld() : nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ SdResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+}
+
+/**
+ * @returns StyleSheet from selection
+ */
+SfxStyleSheet* View::GetStyleSheet() const
+{
+ return SdrView::GetStyleSheet();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/sdview5.cxx b/sd/source/ui/view/sdview5.cxx
new file mode 100644
index 000000000..c3ac066bc
--- /dev/null
+++ b/sd/source/ui/view/sdview5.cxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdpage.hxx>
+#include <View.hxx>
+#include <pres.hxx>
+
+#include <svx/svdpagv.hxx>
+
+namespace sd {
+
+static bool implIsMultiPresObj( PresObjKind eKind )
+{
+ switch( eKind )
+ {
+ case PresObjKind::Outline:
+ case PresObjKind::Graphic:
+ case PresObjKind::Object:
+ case PresObjKind::Chart:
+ case PresObjKind::OrgChart:
+ case PresObjKind::Table:
+ case PresObjKind::Media:
+ return true;
+ default:
+ return false;
+ }
+}
+
+SdPage* View::GetPage()
+{
+ SdPage* pPage = nullptr;
+ SdrPageView* pPV = GetSdrPageView();
+ if( pPV )
+ {
+ pPage = static_cast< SdPage* >( pPV->GetPage() );
+ }
+
+ return pPage;
+}
+
+// returns selected object in case there's just one object in the selection
+SdrObject* View::GetSelectedSingleObject(SdPage const * pPage)
+{
+ SdrObject* pRet = nullptr;
+ if( pPage )
+ {
+ // first try selected shape
+ if ( AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ pRet = pMark->GetMarkedSdrObj();
+ }
+ }
+ }
+
+ return pRet;
+}
+
+SdrObject* View::GetEmptyPresentationObject( PresObjKind eKind )
+{
+ SdPage* pPage = GetPage();
+ SdrObject* pEmptyObj = nullptr;
+
+ if ( pPage && !pPage->IsMasterPage() ) {
+ SdrObject* pObj = GetSelectedSingleObject( pPage );
+
+ if( pObj && pObj->IsEmptyPresObj() && implIsMultiPresObj( pPage->GetPresObjKind(pObj) ) )
+ pEmptyObj = pObj;
+
+ // try to find empty pres obj of same type
+ if( !pEmptyObj )
+ {
+ int nIndex = 1;
+ do
+ {
+ pEmptyObj = pPage->GetPresObj(eKind, nIndex++ );
+ }
+ while( (pEmptyObj != nullptr) && (!pEmptyObj->IsEmptyPresObj()) );
+ }
+
+ // last try to find empty pres obj of multiple type
+ if( !pEmptyObj )
+ {
+ const std::list< SdrObject* >& rShapes = pPage->GetPresentationShapeList().getList();
+
+ auto iter = std::find_if(rShapes.begin(), rShapes.end(),
+ [&pPage](SdrObject* pShape) { return pShape->IsEmptyPresObj() && implIsMultiPresObj(pPage->GetPresObjKind(pShape)); });
+ if (iter != rShapes.end())
+ pEmptyObj = (*iter);
+ }
+ }
+
+ return pEmptyObj;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/sdwindow.cxx b/sd/source/ui/view/sdwindow.cxx
new file mode 100644
index 000000000..f639b463e
--- /dev/null
+++ b/sd/source/ui/view/sdwindow.cxx
@@ -0,0 +1,1097 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <Window.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <svx/svxids.hrc>
+
+#include <editeng/outliner.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editeng.hxx>
+
+#include <app.hrc>
+#include <ViewShell.hxx>
+#include <DrawViewShell.hxx>
+#include <DrawDocShell.hxx>
+#include <PresentationViewShell.hxx>
+#include <View.hxx>
+#include <FrameView.hxx>
+#include <OutlineViewShell.hxx>
+#include <OutlineView.hxx>
+#include <drawdoc.hxx>
+#include <WindowUpdater.hxx>
+#include <ViewShellBase.hxx>
+#include <uiobject.hxx>
+
+#include <officecfg/Office/Common.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/settings.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
+
+namespace sd {
+
+#define SCROLL_LINE_FACT 0.05 ///< factor for line scrolling
+#define SCROLL_PAGE_FACT 0.5 ///< factor for page scrolling
+#define SCROLL_SENSITIVE 20 ///< sensitive area in pixel
+#define ZOOM_MULTIPLICATOR 10000 ///< multiplier to avoid rounding errors
+#define MIN_ZOOM 5 ///< minimal zoom factor
+#define MAX_ZOOM 3000 ///< maximal zoom factor
+
+Window::Window(vcl::Window* pParent)
+ : vcl::Window(pParent, WinBits(WB_CLIPCHILDREN | WB_DIALOGCONTROL)),
+ DropTargetHelper( this ),
+ maWinPos(0, 0), // precautionary; but the values should be set
+ maViewOrigin(0, 0), // again from the owner of the window
+ maViewSize(1000, 1000),
+ maPrevSize(-1,-1),
+ mnMinZoom(MIN_ZOOM),
+ mnMaxZoom(MAX_ZOOM),
+ mbMinZoomAutoCalc(false),
+ mbCenterAllowed(true),
+ mnTicks (0),
+ mpViewShell(nullptr),
+ mbUseDropScroll (true)
+{
+ SetDialogControlFlags( DialogControlFlags::Return | DialogControlFlags::WantFocus );
+
+ MapMode aMap(GetMapMode());
+ aMap.SetMapUnit(MapUnit::Map100thMM);
+ SetMapMode(aMap);
+
+ // with it, the vcl::WindowColor is used in the slide mode
+ SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetWindowColor() ) );
+
+ // adjust contrast mode initially
+ bool bUseContrast = GetSettings().GetStyleSettings().GetHighContrastMode();
+ GetOutDev()->SetDrawMode( bUseContrast
+ ? sd::OUTPUT_DRAWMODE_CONTRAST
+ : sd::OUTPUT_DRAWMODE_COLOR );
+
+ // #i78183# Added after discussed with AF
+ EnableRTL(false);
+}
+
+Window::~Window()
+{
+ disposeOnce();
+}
+
+void Window::dispose()
+{
+ if (mpViewShell != nullptr)
+ {
+ WindowUpdater* pWindowUpdater = mpViewShell->GetWindowUpdater();
+ if (pWindowUpdater != nullptr)
+ pWindowUpdater->UnregisterWindow (this);
+ }
+ DropTargetHelper::dispose();
+ vcl::Window::dispose();
+}
+
+void Window::SetViewShell (ViewShell* pViewSh)
+{
+ WindowUpdater* pWindowUpdater = nullptr;
+ // Unregister at device updater of old view shell.
+ if (mpViewShell != nullptr)
+ {
+ pWindowUpdater = mpViewShell->GetWindowUpdater();
+ if (pWindowUpdater != nullptr)
+ pWindowUpdater->UnregisterWindow (this);
+ }
+
+ mpViewShell = pViewSh;
+
+ // Register at device updater of new view shell
+ if (mpViewShell != nullptr)
+ {
+ pWindowUpdater = mpViewShell->GetWindowUpdater();
+ if (pWindowUpdater != nullptr)
+ pWindowUpdater->RegisterWindow (this);
+ }
+}
+
+ViewShell* Window::GetViewShell()
+{
+ return mpViewShell;
+}
+
+void Window::CalcMinZoom()
+{
+ // Are we entitled to change the minimal zoom factor?
+ if ( !mbMinZoomAutoCalc )
+ return;
+
+ // Get current zoom factor.
+ ::tools::Long nZoom = GetZoom();
+
+ // Get the rectangle of the output area in logical coordinates
+ // and calculate the scaling factors that would lead to the view
+ // area (also called application area) to completely fill the
+ // window.
+ Size aWinSize = PixelToLogic(GetOutputSizePixel());
+ sal_uLong nX = static_cast<sal_uLong>(static_cast<double>(aWinSize.Width())
+ * double(ZOOM_MULTIPLICATOR) / static_cast<double>(maViewSize.Width()));
+ sal_uLong nY = static_cast<sal_uLong>(static_cast<double>(aWinSize.Height())
+ * double(ZOOM_MULTIPLICATOR) / static_cast<double>(maViewSize.Height()));
+
+ // Decide whether to take the larger or the smaller factor.
+ sal_uLong nFact = std::min(nX, nY);
+
+ // The factor is transformed according to the current zoom factor.
+ nFact = nFact * nZoom / ZOOM_MULTIPLICATOR;
+ mnMinZoom = std::max(sal_uInt16(MIN_ZOOM), static_cast<sal_uInt16>(nFact));
+
+ // If the current zoom factor is smaller than the calculated minimal
+ // zoom factor then set the new minimal factor as the current zoom
+ // factor.
+ if ( nZoom < static_cast<::tools::Long>(mnMinZoom) )
+ SetZoomFactor(mnMinZoom);
+}
+
+void Window::SetMinZoom (::tools::Long nMin)
+{
+ mnMinZoom = static_cast<sal_uInt16>(nMin);
+}
+
+void Window::SetMaxZoom (::tools::Long nMax)
+{
+ mnMaxZoom = static_cast<sal_uInt16>(nMax);
+}
+
+::tools::Long Window::GetZoom() const
+{
+ if( GetMapMode().GetScaleX().GetDenominator() )
+ {
+ return ::tools::Long(GetMapMode().GetScaleX() * 100);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void Window::Resize()
+{
+ vcl::Window::Resize();
+ CalcMinZoom();
+
+ if( mpViewShell && mpViewShell->GetViewFrame() )
+ mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
+}
+
+void Window::PrePaint(vcl::RenderContext& /*rRenderContext*/)
+{
+ if ( mpViewShell )
+ mpViewShell->PrePaint();
+}
+
+void Window::Paint(vcl::RenderContext& /*rRenderContext*/, const ::tools::Rectangle& rRect)
+{
+ if ( mpViewShell )
+ mpViewShell->Paint(rRect, this);
+}
+
+void Window::KeyInput(const KeyEvent& rKEvt)
+{
+ if (getenv("SD_DEBUG") && rKEvt.GetKeyCode().GetCode() == KEY_F12 && mpViewShell)
+ {
+ mpViewShell->GetDoc()->dumpAsXml(nullptr);
+ if (OutlinerView *pOLV = mpViewShell->GetView()->GetTextEditOutlinerView())
+ pOLV->GetEditView().GetEditEngine()->dumpAsXmlEditDoc(nullptr);
+ return;
+ }
+
+ if (!(mpViewShell && mpViewShell->KeyInput(rKEvt, this)))
+ {
+ if (mpViewShell && rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)
+ {
+ mpViewShell->GetViewShell()->Escape();
+ }
+ else
+ {
+ vcl::Window::KeyInput(rKEvt);
+ }
+ }
+}
+
+void Window::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if ( mpViewShell )
+ mpViewShell->MouseButtonDown(rMEvt, this);
+}
+
+void Window::MouseMove(const MouseEvent& rMEvt)
+{
+ if ( mpViewShell )
+ mpViewShell->MouseMove(rMEvt, this);
+}
+
+void Window::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ mnTicks = 0;
+
+ if ( mpViewShell )
+ mpViewShell->MouseButtonUp(rMEvt, this);
+}
+
+void Window::Command(const CommandEvent& rCEvt)
+{
+ if (mpViewShell)
+ mpViewShell->Command(rCEvt, this);
+ //pass at least alt press/release to parent impl
+ if (rCEvt.GetCommand() == CommandEventId::ModKeyChange)
+ vcl::Window::Command(rCEvt);
+ //show the text edit outliner view cursor
+ else if (mpViewShell && !HasFocus() && rCEvt.GetCommand() == CommandEventId::CursorPos)
+ {
+ // tdf#138855 Getting Focus may destroy TextEditOutlinerView so Grab if
+ // text editing active, but fetch the TextEditOutlinerView post-grab
+ if (mpViewShell->GetView()->IsTextEdit())
+ {
+ GrabFocus();
+ OutlinerView* pOLV = mpViewShell->GetView()->GetTextEditOutlinerView();
+ if (pOLV && this == pOLV->GetWindow())
+ pOLV->ShowCursor();
+ }
+ }
+}
+
+bool Window::EventNotify( NotifyEvent& rNEvt )
+{
+ bool bResult = false;
+ if ( mpViewShell )
+ {
+ bResult = mpViewShell->Notify(rNEvt, this);
+ }
+ if( !bResult )
+ bResult = vcl::Window::EventNotify(rNEvt);
+
+ return bResult;
+}
+
+void Window::RequestHelp(const HelpEvent& rEvt)
+{
+ if (!mpViewShell || !mpViewShell->RequestHelp(rEvt))
+ vcl::Window::RequestHelp( rEvt );
+}
+
+/**
+ * Set the position of the upper left corner from the visible area of the
+ * window.
+ */
+void Window::SetWinViewPos(const Point& rPnt)
+{
+ maWinPos = rPnt;
+}
+
+/**
+ * Set origin of the representation in respect to the whole working area.
+ */
+void Window::SetViewOrigin(const Point& rPnt)
+{
+ maViewOrigin = rPnt;
+}
+
+/**
+ * Set size of the whole working area which can be seen with the window.
+ */
+void Window::SetViewSize(const Size& rSize)
+{
+ maViewSize = rSize;
+ CalcMinZoom();
+}
+
+void Window::SetCenterAllowed (bool bIsAllowed)
+{
+ mbCenterAllowed = bIsAllowed;
+}
+
+::tools::Long Window::SetZoomFactor(::tools::Long nZoom)
+{
+ // Clip the zoom factor to the valid range marked by nMinZoom as
+ // calculated by CalcMinZoom() and the constant MAX_ZOOM.
+ if ( nZoom > MAX_ZOOM )
+ nZoom = MAX_ZOOM;
+ if ( nZoom < static_cast<::tools::Long>(mnMinZoom) )
+ nZoom = mnMinZoom;
+
+ // Set the zoom factor at the window's map mode.
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ MapMode aMap(GetMapMode());
+ aMap.SetScaleX(Fraction(nZoom, 100));
+ aMap.SetScaleY(Fraction(nZoom, 100));
+ SetMapMode(aMap);
+ }
+
+ // invalidate previous size - it was relative to the old scaling
+ maPrevSize = Size(-1,-1);
+
+ // Update the map mode's origin (to what effect?).
+ UpdateMapOrigin();
+
+ // Update the view's snapping to the new zoom factor.
+ if ( auto pDrawViewShell = dynamic_cast< DrawViewShell *>( mpViewShell ) )
+ pDrawViewShell->GetView()->RecalcLogicSnapMagnetic(*GetOutDev());
+
+ // Return the zoom factor just in case it has been changed above to lie
+ // inside the valid range.
+ return nZoom;
+}
+
+void Window::SetZoomIntegral(::tools::Long nZoom)
+{
+ // Clip the zoom factor to the valid range marked by nMinZoom as
+ // previously calculated by <member>CalcMinZoom()</member> and the
+ // MAX_ZOOM constant.
+ if ( nZoom > MAX_ZOOM )
+ nZoom = MAX_ZOOM;
+ if ( nZoom < static_cast<::tools::Long>(mnMinZoom) )
+ nZoom = mnMinZoom;
+
+ // Calculate the window's new origin.
+ Size aSize = PixelToLogic(GetOutputSizePixel());
+ ::tools::Long nW = aSize.Width() * GetZoom() / nZoom;
+ ::tools::Long nH = aSize.Height() * GetZoom() / nZoom;
+ maWinPos.AdjustX((aSize.Width() - nW) / 2 );
+ maWinPos.AdjustY((aSize.Height() - nH) / 2 );
+ if ( maWinPos.X() < 0 ) maWinPos.setX( 0 );
+ if ( maWinPos.Y() < 0 ) maWinPos.setY( 0 );
+
+ // Finally update this window's map mode to the given zoom factor that
+ // has been clipped to the valid range.
+ SetZoomFactor(nZoom);
+}
+
+::tools::Long Window::GetZoomForRect( const ::tools::Rectangle& rZoomRect )
+{
+ ::tools::Long nRetZoom = 100;
+
+ if( (rZoomRect.GetWidth() != 0) && (rZoomRect.GetHeight() != 0))
+ {
+ // Calculate the scale factors which will lead to the given
+ // rectangle being fully visible (when translated accordingly) as
+ // large as possible in the output area independently in both
+ // coordinate directions .
+ sal_uLong nX(0);
+ sal_uLong nY(0);
+
+ const Size aWinSize( PixelToLogic(GetOutputSizePixel()) );
+ if(rZoomRect.GetHeight())
+ {
+ nX = static_cast<sal_uLong>(static_cast<double>(aWinSize.Height())
+ * double(ZOOM_MULTIPLICATOR) / static_cast<double>(rZoomRect.GetHeight()));
+ }
+
+ if(rZoomRect.GetWidth())
+ {
+ nY = static_cast<sal_uLong>(static_cast<double>(aWinSize.Width())
+ * double(ZOOM_MULTIPLICATOR) / static_cast<double>(rZoomRect.GetWidth()));
+ }
+
+ // Use the smaller one of both so that the zoom rectangle will be
+ // fully visible with respect to both coordinate directions.
+ sal_uLong nFact = std::min(nX, nY);
+
+ // Transform the current zoom factor so that it leads to the desired
+ // scaling.
+ nRetZoom = nFact * GetZoom() / ZOOM_MULTIPLICATOR;
+
+ // Calculate the new origin.
+ if ( nFact == 0 )
+ {
+ // Don't change anything if the scale factor is degenerate.
+ nRetZoom = GetZoom();
+ }
+ else
+ {
+ // Clip the zoom factor to the valid range marked by nMinZoom as
+ // previously calculated by <member>CalcMinZoom()</member> and the
+ // MAX_ZOOM constant.
+ if ( nRetZoom > MAX_ZOOM )
+ nRetZoom = MAX_ZOOM;
+ if ( nRetZoom < static_cast<::tools::Long>(mnMinZoom) )
+ nRetZoom = mnMinZoom;
+ }
+ }
+
+ return nRetZoom;
+}
+
+/** Recalculate the zoom factor and translation so that the given rectangle
+ is displayed centered and as large as possible while still being fully
+ visible in the window.
+*/
+::tools::Long Window::SetZoomRect (const ::tools::Rectangle& rZoomRect)
+{
+ ::tools::Long nNewZoom = 100;
+
+ if (rZoomRect.GetWidth() == 0 || rZoomRect.GetHeight() == 0)
+ {
+ // The given rectangle is degenerate. Use the default zoom factor
+ // (above) of 100%.
+ SetZoomIntegral(nNewZoom);
+ }
+ else
+ {
+ Point aPos = rZoomRect.TopLeft();
+ // Transform the output area from pixel coordinates into logical
+ // coordinates.
+ Size aWinSize = PixelToLogic(GetOutputSizePixel());
+ // Paranoia! The degenerate case of zero width or height has been
+ // taken care of above.
+ DBG_ASSERT(rZoomRect.GetWidth(), "ZoomRect-Width = 0!");
+ DBG_ASSERT(rZoomRect.GetHeight(), "ZoomRect-Height = 0!");
+
+ // Calculate the scale factors which will lead to the given
+ // rectangle being fully visible (when translated accordingly) as
+ // large as possible in the output area independently in both
+ // coordinate directions .
+ sal_uLong nX(0);
+ sal_uLong nY(0);
+
+ if(rZoomRect.GetHeight())
+ {
+ nX = static_cast<sal_uLong>(static_cast<double>(aWinSize.Height())
+ * double(ZOOM_MULTIPLICATOR) / static_cast<double>(rZoomRect.GetHeight()));
+ }
+
+ if(rZoomRect.GetWidth())
+ {
+ nY = static_cast<sal_uLong>(static_cast<double>(aWinSize.Width())
+ * double(ZOOM_MULTIPLICATOR) / static_cast<double>(rZoomRect.GetWidth()));
+ }
+
+ // Use the smaller one of both so that the zoom rectangle will be
+ // fully visible with respect to both coordinate directions.
+ sal_uLong nFact = std::min(nX, nY);
+
+ // Transform the current zoom factor so that it leads to the desired
+ // scaling.
+ ::tools::Long nZoom = nFact * GetZoom() / ZOOM_MULTIPLICATOR;
+
+ // Calculate the new origin.
+ if ( nFact == 0 )
+ {
+ // Don't change anything if the scale factor is degenerate.
+ nNewZoom = GetZoom();
+ }
+ else
+ {
+ // Calculate the new window position that centers the given
+ // rectangle on the screen.
+ if ( nZoom > MAX_ZOOM )
+ nFact = nFact * MAX_ZOOM / nZoom;
+
+ maWinPos = maViewOrigin + aPos;
+
+ aWinSize.setWidth( static_cast<::tools::Long>(static_cast<double>(aWinSize.Width()) * double(ZOOM_MULTIPLICATOR) / static_cast<double>(nFact)) );
+ maWinPos.AdjustX((rZoomRect.GetWidth() - aWinSize.Width()) / 2 );
+ aWinSize.setHeight( static_cast<::tools::Long>(static_cast<double>(aWinSize.Height()) * double(ZOOM_MULTIPLICATOR) / static_cast<double>(nFact)) );
+ maWinPos.AdjustY((rZoomRect.GetHeight() - aWinSize.Height()) / 2 );
+
+ if ( maWinPos.X() < 0 ) maWinPos.setX( 0 );
+ if ( maWinPos.Y() < 0 ) maWinPos.setY( 0 );
+
+ // Adapt the window's map mode to the new zoom factor.
+ nNewZoom = SetZoomFactor(nZoom);
+ }
+ }
+
+ return nNewZoom;
+}
+
+void Window::SetMinZoomAutoCalc (bool bAuto)
+{
+ mbMinZoomAutoCalc = bAuto;
+}
+
+/**
+ * Calculate and set new MapMode origin.
+ * If aWinPos.X()/Y() == -1, then we center the corresponding position (e.g. for
+ * initialization).
+ */
+void Window::UpdateMapOrigin(bool bInvalidate)
+{
+ bool bChanged = false;
+ const Size aWinSize = PixelToLogic(GetOutputSizePixel());
+
+ if ( mbCenterAllowed )
+ {
+ if( maPrevSize != Size(-1,-1) )
+ {
+ // keep view centered around current pos, when window
+ // resizes
+ maWinPos.AdjustX( -((aWinSize.Width() - maPrevSize.Width()) / 2) );
+ maWinPos.AdjustY( -((aWinSize.Height() - maPrevSize.Height()) / 2) );
+ bChanged = true;
+ }
+
+ if ( maWinPos.X() > maViewSize.Width() - aWinSize.Width() )
+ {
+ maWinPos.setX( maViewSize.Width() - aWinSize.Width() );
+ bChanged = true;
+ }
+ if ( maWinPos.Y() > maViewSize.Height() - aWinSize.Height() )
+ {
+ maWinPos.setY( maViewSize.Height() - aWinSize.Height() );
+ bChanged = true;
+ }
+ if ( aWinSize.Width() > maViewSize.Width() || maWinPos.X() < 0 )
+ {
+ maWinPos.setX( maViewSize.Width() / 2 - aWinSize.Width() / 2 );
+ bChanged = true;
+ }
+ if ( aWinSize.Height() > maViewSize.Height() || maWinPos.Y() < 0 )
+ {
+ maWinPos.setY( maViewSize.Height() / 2 - aWinSize.Height() / 2 );
+ bChanged = true;
+ }
+ }
+
+ UpdateMapMode ();
+
+ maPrevSize = aWinSize;
+
+ // When tiled rendering, the above UpdateMapMode() call doesn't touch the map mode.
+ if (bChanged && bInvalidate && !comphelper::LibreOfficeKit::isActive())
+ Invalidate();
+}
+
+void Window::UpdateMapMode()
+{
+ maWinPos -= maViewOrigin;
+ Size aPix(maWinPos.X(), maWinPos.Y());
+ aPix = LogicToPixel(aPix);
+ // Size has to be a multiple of BRUSH_SIZE due to the correct depiction of
+ // pattern
+ // #i2237#
+ // removed old stuff here which still forced zoom to be
+ // %BRUSH_SIZE which is outdated now
+
+ if (dynamic_cast< DrawViewShell *>( mpViewShell ))
+ {
+ // page should not "stick" to the window border
+ if (aPix.Width() == 0)
+ {
+ // #i2237#
+ // Since BRUSH_SIZE alignment is outdated now, i use the
+ // former constant here directly
+ aPix.AdjustWidth( -8 );
+ }
+ if (aPix.Height() == 0)
+ {
+ // #i2237#
+ // Since BRUSH_SIZE alignment is outdated now, i use the
+ // former constant here directly
+ aPix.AdjustHeight( -8 );
+ }
+ }
+
+ aPix = PixelToLogic(aPix);
+ maWinPos.setX( aPix.Width() );
+ maWinPos.setY( aPix.Height() );
+ Point aNewOrigin (-maWinPos.X(), -maWinPos.Y());
+ maWinPos += maViewOrigin;
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ MapMode aMap(GetMapMode());
+ aMap.SetOrigin(aNewOrigin);
+ SetMapMode(aMap);
+ }
+}
+
+/**
+ * @returns X position of the visible area as fraction (< 1) of the whole
+ * working area.
+ */
+double Window::GetVisibleX() const
+{
+ return maViewSize.Width() == 0 ? 0 : (static_cast<double>(maWinPos.X()) / maViewSize.Width());
+}
+
+/**
+ * @returns Y position of the visible area as fraction (< 1) of the whole
+ * working area.
+ */
+double Window::GetVisibleY() const
+{
+ return maViewSize.Height() == 0 ? 0 : (static_cast<double>(maWinPos.Y()) / maViewSize.Height());
+}
+
+/**
+ * Set x and y position of the visible area as fraction (< 1) of the whole
+ * working area. Negative values are ignored.
+ */
+void Window::SetVisibleXY(double fX, double fY)
+{
+ ::tools::Long nOldX = maWinPos.X();
+ ::tools::Long nOldY = maWinPos.Y();
+
+ if ( fX >= 0 )
+ maWinPos.setX( static_cast<::tools::Long>(fX * maViewSize.Width()) );
+ if ( fY >= 0 )
+ maWinPos.setY( static_cast<::tools::Long>(fY * maViewSize.Height()) );
+ UpdateMapOrigin(false);
+ Scroll(nOldX - maWinPos.X(), nOldY - maWinPos.Y(), ScrollFlags::Children);
+ PaintImmediately();
+}
+
+/**
+ * @returns width of the visible area in proportion to the width of the whole
+ * working area.
+ */
+double Window::GetVisibleWidth() const
+{
+ Size aWinSize = PixelToLogic(GetOutputSizePixel());
+ if ( aWinSize.Width() > maViewSize.Width() )
+ aWinSize.setWidth( maViewSize.Width() );
+ return
+ maViewSize.Width() == 0 ? 0 : (static_cast<double>(aWinSize.Width()) / maViewSize.Width());
+}
+
+/**
+ * @returns height of the visible area in proportion to the height of the whole
+ * working area.
+ */
+double Window::GetVisibleHeight() const
+{
+ Size aWinSize = PixelToLogic(GetOutputSizePixel());
+ if ( aWinSize.Height() > maViewSize.Height() )
+ aWinSize.setHeight( maViewSize.Height() );
+ return maViewSize.Height() == 0
+ ? 0 : (static_cast<double>(aWinSize.Height()) / maViewSize.Height());
+}
+
+Point Window::GetVisibleCenter()
+{
+ Point aPos = ::tools::Rectangle(Point(), GetOutputSizePixel()).Center();
+
+ // For LOK
+ bool bMapModeWasEnabled(IsMapModeEnabled());
+ EnableMapMode(/*true*/);
+ aPos = PixelToLogic(aPos);
+ EnableMapMode(bMapModeWasEnabled);
+
+ return aPos;
+}
+
+/**
+ * @returns width of a scroll column in proportion to the width of the whole
+ * working area.
+ */
+double Window::GetScrlLineWidth() const
+{
+ return (GetVisibleWidth() * SCROLL_LINE_FACT);
+}
+
+/**
+ * @returns height of a scroll column in proportion to the height of the whole
+ * working area.
+ */
+double Window::GetScrlLineHeight() const
+{
+ return (GetVisibleHeight() * SCROLL_LINE_FACT);
+}
+
+/**
+ * @returns width of a scroll page in proportion to the width of the whole
+ * working area.
+ */
+double Window::GetScrlPageWidth() const
+{
+ return (GetVisibleWidth() * SCROLL_PAGE_FACT);
+}
+
+/**
+ * @returns height of a scroll page in proportion to the height of the whole
+ * working area.
+ */
+double Window::GetScrlPageHeight() const
+{
+ return (GetVisibleHeight() * SCROLL_PAGE_FACT);
+}
+
+/**
+ * Deactivate window.
+ */
+void Window::LoseFocus()
+{
+ mnTicks = 0;
+ vcl::Window::LoseFocus ();
+}
+
+/**
+ * Activate window.
+ */
+void Window::GrabFocus()
+{
+ mnTicks = 0;
+ vcl::Window::GrabFocus ();
+}
+
+void Window::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ vcl::Window::DataChanged( rDCEvt );
+
+ /* Omit PRINTER by all documents which are not using a printer.
+ Omit FONTS and FONTSUBSTITUTION if no text output is available or if the
+ document does not allow text. */
+
+ if ( !((rDCEvt.GetType() == DataChangedEventType::PRINTER) ||
+ (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))) )
+ return;
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ /* Rearrange or initiate Resize for scroll bars since the size of
+ the scroll bars my have changed. Within this, inside the resize-
+ handler, the size of the scroll bars will be asked from the
+ Settings. */
+ Resize();
+
+ /* Re-set data, which are from system control or from Settings. May
+ have to re-set more data since the resolution may also has
+ changed. */
+ if( mpViewShell )
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ DrawModeFlags nOutputMode;
+ sal_uInt16 nPreviewSlot;
+
+ if( rStyleSettings.GetHighContrastMode() )
+ nOutputMode = sd::OUTPUT_DRAWMODE_CONTRAST;
+ else
+ nOutputMode = sd::OUTPUT_DRAWMODE_COLOR;
+
+ if( rStyleSettings.GetHighContrastMode()
+ && officecfg::Office::Common::Accessibility::IsForPagePreviews::get() )
+ nPreviewSlot = SID_PREVIEW_QUALITY_CONTRAST;
+ else
+ nPreviewSlot = SID_PREVIEW_QUALITY_COLOR;
+
+ if( dynamic_cast< DrawViewShell *>( mpViewShell ) != nullptr )
+ {
+ GetOutDev()->SetDrawMode( nOutputMode );
+ mpViewShell->GetFrameView()->SetDrawMode( nOutputMode );
+ Invalidate();
+ }
+
+ // Overwrite window color for OutlineView
+ if( dynamic_cast< OutlineViewShell *>( mpViewShell ) != nullptr )
+ {
+ svtools::ColorConfig aColorConfig;
+ const Color aDocColor( aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor );
+ SetBackground( Wallpaper( aDocColor ) );
+ }
+
+ SfxRequest aReq( nPreviewSlot, SfxCallMode::SLOT, mpViewShell->GetDocSh()->GetDoc()->GetItemPool() );
+ mpViewShell->ExecReq( aReq );
+ mpViewShell->Invalidate();
+ mpViewShell->ArrangeGUIElements();
+
+ // re-create handles to show new outfit
+ if(dynamic_cast< DrawViewShell *>( mpViewShell ) != nullptr)
+ {
+ mpViewShell->GetView()->AdjustMarkHdl();
+ }
+ }
+ }
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
+ ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
+ {
+ /* Virtual devices, which also depends on the resolution or the
+ system control, should be updated. Otherwise, we should update
+ the virtual devices at least at DataChangedEventType::DISPLAY since some
+ systems allow to change the resolution and color depth during
+ runtime. Or the virtual devices have to be updated when the color
+ palette has changed since a different color matching can be used
+ when outputting. */
+ }
+
+ if ( rDCEvt.GetType() == DataChangedEventType::FONTS )
+ {
+ /* If the document provides font choose boxes, we have to update
+ them. I don't know how this looks like (also not really me, I
+ only translated the comment ;). We may can handle it global. We
+ have to discuss it with PB, but he is ill at the moment.
+ Before we handle it here, discuss it with PB and me. */
+ }
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) )
+ {
+ /* Do reformatting since the fonts of the document may no longer
+ exist, or exist now, or are replaced with others. */
+ if( mpViewShell )
+ {
+ DrawDocShell* pDocSh = mpViewShell->GetDocSh();
+ if( pDocSh )
+ pDocSh->SetPrinter( pDocSh->GetPrinter( true ) );
+ }
+ }
+
+ if ( rDCEvt.GetType() == DataChangedEventType::PRINTER )
+ {
+ /* I don't know how the handling should look like. Maybe we delete a
+ printer and look what we have to do. Maybe I have to add
+ something to the VCL, in case the used printer is deleted.
+ Otherwise I may recalculate the formatting here if the current
+ printer is destroyed. */
+ if( mpViewShell )
+ {
+ DrawDocShell* pDocSh = mpViewShell->GetDocSh();
+ if( pDocSh )
+ pDocSh->SetPrinter( pDocSh->GetPrinter( true ) );
+ }
+ }
+
+ // Update everything
+ Invalidate();
+}
+
+sal_Int8 Window::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( mpViewShell && !mpViewShell->GetDocSh()->IsReadOnly() )
+ {
+ nRet = mpViewShell->AcceptDrop( rEvt, *this, this, SDRPAGE_NOTFOUND, SDRLAYER_NOTFOUND );
+
+ if (mbUseDropScroll && dynamic_cast< OutlineViewShell *>( mpViewShell ) == nullptr)
+ DropScroll( rEvt.maPosPixel );
+ }
+
+ return nRet;
+}
+
+sal_Int8 Window::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( mpViewShell )
+ {
+ nRet = mpViewShell->ExecuteDrop( rEvt, *this, this, SDRPAGE_NOTFOUND, SDRLAYER_NOTFOUND );
+ }
+
+ return nRet;
+}
+
+void Window::SetUseDropScroll (bool bUseDropScroll)
+{
+ mbUseDropScroll = bUseDropScroll;
+}
+
+void Window::DropScroll(const Point& rMousePos)
+{
+ short nDx = 0;
+ short nDy = 0;
+
+ Size aSize = GetOutputSizePixel();
+
+ if (aSize.Width() > SCROLL_SENSITIVE * 3)
+ {
+ if ( rMousePos.X() < SCROLL_SENSITIVE )
+ {
+ nDx = -1;
+ }
+
+ if ( rMousePos.X() >= aSize.Width() - SCROLL_SENSITIVE )
+ {
+ nDx = 1;
+ }
+ }
+
+ if (aSize.Height() > SCROLL_SENSITIVE * 3)
+ {
+ if ( rMousePos.Y() < SCROLL_SENSITIVE )
+ {
+ nDy = -1;
+ }
+
+ if ( rMousePos.Y() >= aSize.Height() - SCROLL_SENSITIVE )
+ {
+ nDy = 1;
+ }
+ }
+
+ if ( (nDx || nDy) && (rMousePos.X()!=0 || rMousePos.Y()!=0 ) )
+ {
+ if (mnTicks > 20)
+ mpViewShell->ScrollLines(nDx, nDy);
+ else
+ mnTicks ++;
+ }
+}
+
+css::uno::Reference<css::accessibility::XAccessible>
+ Window::CreateAccessible()
+{
+ // If current viewshell is PresentationViewShell, just return empty because the correct ShowWin will be created later.
+ if (dynamic_cast< PresentationViewShell *>( mpViewShell ))
+ {
+ return vcl::Window::CreateAccessible ();
+ }
+ css::uno::Reference< css::accessibility::XAccessible > xAcc = GetAccessible(false);
+ if (xAcc)
+ {
+ return xAcc;
+ }
+ if (mpViewShell != nullptr)
+ {
+ xAcc = mpViewShell->CreateAccessibleDocumentView (this);
+ SetAccessible(xAcc);
+ return xAcc;
+ }
+ else
+ {
+ SAL_WARN("sd", "::sd::Window::CreateAccessible: no view shell");
+ return vcl::Window::CreateAccessible ();
+ }
+}
+
+OutlinerView* Window::GetOutlinerView() const
+{
+ OutlinerView *pOLV = nullptr;
+ sd::View* pView = mpViewShell->GetView();
+ if (mpViewShell->GetShellType() == ViewShell::ST_OUTLINE)
+ {
+ if (OutlineView* pOView = dynamic_cast<OutlineView*>(pView))
+ pOLV = pOView->GetViewByWindow(this);
+ }
+ else if (pView->IsTextEdit())
+ {
+ pOLV = pView->GetTextEditOutlinerView();
+ }
+ return pOLV;
+}
+
+OUString Window::GetSurroundingText() const
+{
+ OutlinerView *pOLV = GetOutlinerView();
+ if (pOLV)
+ return pOLV->GetEditView().GetSurroundingText();
+ return OUString();
+}
+
+Selection Window::GetSurroundingTextSelection() const
+{
+ OutlinerView *pOLV = GetOutlinerView();
+ if (pOLV)
+ return pOLV->GetEditView().GetSurroundingTextSelection();
+ return Selection( 0, 0 );
+}
+
+bool Window::DeleteSurroundingText(const Selection& rSelection)
+{
+ OutlinerView *pOLV = GetOutlinerView();
+ if (pOLV)
+ return pOLV->GetEditView().DeleteSurroundingText(rSelection);
+ return false;
+}
+
+void Window::LogicInvalidate(const ::tools::Rectangle* pRectangle)
+{
+ DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(mpViewShell);
+ if (!pDrawViewShell || pDrawViewShell->IsInSwitchPage())
+ return;
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+ ::tools::Rectangle aRectangle;
+ ::tools::Rectangle* pResultRectangle;
+ if (!pRectangle)
+ pResultRectangle = nullptr;
+ else
+ {
+ aRectangle = *pRectangle;
+ if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ {
+ aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip);
+ }
+ pResultRectangle = &aRectangle;
+ }
+ SfxViewShell& rSfxViewShell = pDrawViewShell->GetViewShellBase();
+ SfxLokHelper::notifyInvalidation(&rSfxViewShell, pResultRectangle);
+}
+
+void Window::LogicMouseButtonDown(const MouseEvent& rMouseEvent)
+{
+ // When we're not doing tiled rendering, then positions must be passed as pixels.
+ assert(comphelper::LibreOfficeKit::isActive());
+
+ Point aPoint = GetPointerPosPixel();
+ SetLastMousePos(rMouseEvent.GetPosPixel());
+
+ mpViewShell->MouseButtonDown(rMouseEvent, this);
+
+ SetPointerPosPixel(aPoint);
+}
+
+void Window::LogicMouseButtonUp(const MouseEvent& rMouseEvent)
+{
+ // When we're not doing tiled rendering, then positions must be passed as pixels.
+ assert(comphelper::LibreOfficeKit::isActive());
+
+ Point aPoint = GetPointerPosPixel();
+ SetLastMousePos(rMouseEvent.GetPosPixel());
+
+ mpViewShell->MouseButtonUp(rMouseEvent, this);
+
+ SetPointerPosPixel(aPoint);
+}
+
+void Window::LogicMouseMove(const MouseEvent& rMouseEvent)
+{
+ // When we're not doing tiled rendering, then positions must be passed as pixels.
+ assert(comphelper::LibreOfficeKit::isActive());
+
+ Point aPoint = GetPointerPosPixel();
+ SetLastMousePos(rMouseEvent.GetPosPixel());
+
+ mpViewShell->MouseMove(rMouseEvent, this);
+
+ SetPointerPosPixel(aPoint);
+}
+
+FactoryFunction Window::GetUITestFactory() const
+{
+ if (get_id() == "impress_win")
+ return ImpressWindowUIObject::create;
+
+ return WindowUIObject::create;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/tabcontr.cxx b/sd/source/ui/view/tabcontr.cxx
new file mode 100644
index 000000000..b09a254e9
--- /dev/null
+++ b/sd/source/ui/view/tabcontr.cxx
@@ -0,0 +1,358 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TabControl.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/vclevent.hxx>
+
+#include <app.hrc>
+
+#include <DrawViewShell.hxx>
+#include <helpids.h>
+#include <View.hxx>
+#include <drawdoc.hxx>
+#include <DrawDocShell.hxx>
+
+namespace sd {
+
+
+TabControl::TabControlTransferable::~TabControlTransferable()
+{
+}
+
+void TabControl::TabControlTransferable::AddSupportedFormats()
+{
+ AddFormat( SotClipboardFormatId::STARDRAW_TABBAR );
+}
+
+bool TabControl::TabControlTransferable::GetData( const css::datatransfer::DataFlavor& /*rFlavor*/, const OUString& /*rDestDoc*/ )
+{
+ return false;
+}
+
+void TabControl::TabControlTransferable::DragFinished( sal_Int8 /*nDropAction*/ )
+{
+ mrParent.DragFinished();
+}
+
+TabControl::TabControl(DrawViewShell* pViewSh, vcl::Window* pParent) :
+ TabBar( pParent, WinBits( WB_BORDER | WB_3DLOOK | WB_SCROLL | WB_SIZEABLE | WB_DRAG) ),
+ DragSourceHelper( this ),
+ DropTargetHelper( this ),
+ pDrViewSh(pViewSh),
+ bInternalMove(false)
+{
+ EnableEditMode();
+ SetSizePixel(Size(0, 0));
+ SetMaxPageWidth( 150 );
+ SetHelpId( HID_SD_TABBAR_PAGES );
+}
+
+TabControl::~TabControl()
+{
+ disposeOnce();
+}
+
+void TabControl::dispose()
+{
+ DragSourceHelper::dispose();
+ DropTargetHelper::dispose();
+ TabBar::dispose();
+}
+
+void TabControl::Select()
+{
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute(SID_SWITCHPAGE, SfxCallMode::ASYNCHRON |
+ SfxCallMode::RECORD);
+}
+
+void TabControl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if (rMEvt.IsLeft()
+ && !rMEvt.IsMod1()
+ && !rMEvt.IsMod2()
+ && !rMEvt.IsShift())
+ {
+ Point aPos = PixelToLogic( rMEvt.GetPosPixel() );
+ sal_uInt16 aPageId = GetPageId(aPos);
+
+ //initialize
+ if (aPageId == 0)
+ {
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+
+ pDispatcher->Execute(SID_INSERTPAGE_QUICK,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD);
+ }
+ }
+
+ // A single left click with pressed control key on a tab page first
+ // switches to that page before the usual handling (copying with drag
+ // and drop) takes place.
+ else if (rMEvt.IsLeft() && rMEvt.IsMod1() && !rMEvt.IsMod2() && !rMEvt.IsShift())
+ {
+ pDrViewSh->SwitchPage (GetPageId (rMEvt.GetPosPixel()) - 1);
+ }
+
+ // When only the right button is pressed then first process a
+ // synthesized left button click to make the page the current one
+ // whose tab has been clicked. When then the actual right button
+ // click is processed the resulting context menu relates to the
+ // now current page.
+ if (rMEvt.IsRight() && ! rMEvt.IsLeft())
+ {
+ MouseEvent aSyntheticEvent (
+ rMEvt.GetPosPixel(),
+ rMEvt.GetClicks(),
+ rMEvt.GetMode(),
+ MOUSE_LEFT,
+ rMEvt.GetModifier());
+ TabBar::MouseButtonDown(aSyntheticEvent);
+ }
+
+ TabBar::MouseButtonDown(rMEvt);
+}
+
+void TabControl::DoubleClick()
+{
+ if (GetCurPageId() != 0)
+ {
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute( SID_MODIFYPAGE,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
+ }
+}
+
+void TabControl::StartDrag( sal_Int8, const Point& )
+{
+ bInternalMove = true;
+
+ // object is delete by reference mechanism
+ ( new TabControl::TabControlTransferable( *this ) )->StartDrag( this, DND_ACTION_COPYMOVE );
+}
+
+void TabControl::DragFinished()
+{
+ bInternalMove = false;
+}
+
+sal_Int8 TabControl::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( rEvt.mbLeaving )
+ EndSwitchPage();
+
+ if( !pDrViewSh->GetDocSh()->IsReadOnly() )
+ {
+ SdDrawDocument* pDoc = pDrViewSh->GetDoc();
+ Point aPos( rEvt.maPosPixel );
+
+ if( bInternalMove )
+ {
+ if( rEvt.mbLeaving || ( pDrViewSh->GetEditMode() == EditMode::MasterPage ) )
+ HideDropPos();
+ else
+ {
+ ShowDropPos( aPos );
+ nRet = rEvt.mnAction;
+ }
+ }
+ else
+ {
+ HideDropPos();
+
+ sal_Int32 nPageId = GetPageId( aPos ) - 1;
+
+ if( ( nPageId >= 0 ) && pDoc->GetPage( static_cast<sal_uInt16>(nPageId) ) )
+ {
+ nRet = pDrViewSh->AcceptDrop( rEvt, *this, nullptr, static_cast<sal_uInt16>(nPageId), SDRLAYER_NOTFOUND );
+ SwitchPage( aPos );
+ }
+ }
+ }
+
+ return nRet;
+}
+
+sal_Int8 TabControl::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ SdDrawDocument* pDoc = pDrViewSh->GetDoc();
+ Point aPos( rEvt.maPosPixel );
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( bInternalMove )
+ {
+ sal_uInt16 nPageId = ShowDropPos( aPos ) - 1;
+
+ switch (rEvt.mnAction)
+ {
+ case DND_ACTION_MOVE:
+ if( pDrViewSh->IsSwitchPageAllowed() && pDoc->MovePages( nPageId ) )
+ {
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute(SID_SWITCHPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+ break;
+
+ case DND_ACTION_COPY:
+ {
+ // Copying the selected page to the place that rEvt points
+ // takes place in three steps:
+ // 1. Create a copy of the selected page. This copy will
+ // lie directly behind the selected page.
+ // 2. Move the copy to the desired place.
+ // 3. Select the copy.
+ if (pDrViewSh->IsSwitchPageAllowed())
+ {
+ // 1. Create a copy.
+ sal_uInt16 nPageNumOfCopy = pDoc->DuplicatePage (GetCurPageId() - 1);
+ // 2. Move page. For this first switch to the copy:
+ // MovePages operates on the currently selected page(s).
+ pDrViewSh->SwitchPage (nPageNumOfCopy);
+ // Adapt target page id when necessary, i.e. page copy
+ // has been inserted in front of the target page.
+ sal_uInt16 nPageNum = nPageId;
+ if ((nPageNumOfCopy <= nPageNum) && (nPageNum != sal_uInt16(-1)))
+ nPageNum += 1;
+ if (pDoc->MovePages(nPageNum))
+ {
+ // 3. Switch to the copy that has been moved to its
+ // final destination. Use an asynchron slot call to
+ // be executed after the still pending ones.
+ if (nPageNumOfCopy >= nPageNum || (nPageNum == sal_uInt16(-1)))
+ nPageNum += 1;
+ SetCurPageId (GetPageId(nPageNum));
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute(SID_SWITCHPAGE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+ }
+
+ break;
+ }
+ }
+
+ nRet = rEvt.mnAction;
+ }
+ else
+ {
+ sal_Int32 nPageId = GetPageId( aPos ) - 1;
+
+ if( ( nPageId >= 0 ) && pDoc->GetPage( static_cast<sal_uInt16>(nPageId) ) )
+ {
+ nRet = pDrViewSh->ExecuteDrop( rEvt, *this, nullptr, static_cast<sal_uInt16>(nPageId), SDRLAYER_NOTFOUND );
+ }
+ }
+
+ HideDropPos();
+ EndSwitchPage();
+
+ return nRet;
+}
+
+void TabControl::Command(const CommandEvent& rCEvt)
+{
+ if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
+ {
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->ExecutePopup("pagetab");
+ }
+}
+
+bool TabControl::StartRenaming()
+{
+ bool bOK = false;
+
+ if (pDrViewSh->GetPageKind() == PageKind::Standard)
+ {
+ bOK = true;
+
+ ::sd::View* pView = pDrViewSh->GetView();
+
+ if ( pView->IsTextEdit() )
+ pView->SdrEndTextEdit();
+ }
+
+ return bOK;
+}
+
+TabBarAllowRenamingReturnCode TabControl::AllowRenaming()
+{
+ bool bOK = true;
+
+ OUString aNewName( GetEditText() );
+ OUString aCompareName( GetPageText( GetEditPageId() ) );
+
+ if( aCompareName != aNewName )
+ {
+ // rename page
+ if (pDrViewSh->GetDocSh()->CheckPageName(GetFrameWeld(), aNewName))
+ {
+ SetEditText( aNewName );
+ EndRenaming();
+ }
+ else
+ {
+ bOK = false;
+ }
+ }
+ return bOK ? TABBAR_RENAMING_YES : TABBAR_RENAMING_NO;
+}
+
+void TabControl::EndRenaming()
+{
+ if( !IsEditModeCanceled() )
+ pDrViewSh->RenameSlide( GetEditPageId(), GetEditText() );
+}
+
+void TabControl::ActivatePage()
+{
+ if ( /*IsInSwitching && */ pDrViewSh->IsSwitchPageAllowed() )
+ {
+ SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute(SID_SWITCHPAGE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+}
+
+bool TabControl::DeactivatePage()
+{
+ return pDrViewSh->IsSwitchPageAllowed();
+}
+
+void TabControl::SendActivatePageEvent()
+{
+ CallEventListeners (VclEventId::TabbarPageActivated,
+ reinterpret_cast<void*>(GetCurPageId()));
+}
+
+void TabControl::SendDeactivatePageEvent()
+{
+ CallEventListeners (VclEventId::TabbarPageDeactivated,
+ reinterpret_cast<void*>(GetCurPageId()));
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/unmodpg.cxx b/sd/source/ui/view/unmodpg.cxx
new file mode 100644
index 000000000..03d907d14
--- /dev/null
+++ b/sd/source/ui/view/unmodpg.cxx
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdlayer.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svdviter.hxx>
+#include <svx/svdview.hxx>
+#include <tools/debug.hxx>
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include <glob.hxx>
+#include <app.hrc>
+
+#include <unmodpg.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <unokywds.hxx>
+#include <drawdoc.hxx>
+
+
+ModifyPageUndoAction::ModifyPageUndoAction(
+ SdDrawDocument* pTheDoc,
+ SdPage* pThePage,
+ const OUString& aTheNewName,
+ AutoLayout eTheNewAutoLayout,
+ bool bTheNewBckgrndVisible,
+ bool bTheNewBckgrndObjsVisible)
+: SdUndoAction(pTheDoc)
+{
+ DBG_ASSERT(pThePage, "Undo without a page???");
+
+ mpPage = pThePage;
+ maNewName = aTheNewName;
+ meNewAutoLayout = eTheNewAutoLayout;
+ mbNewBckgrndVisible = bTheNewBckgrndVisible;
+ mbNewBckgrndObjsVisible = bTheNewBckgrndObjsVisible;
+
+ meOldAutoLayout = mpPage->GetAutoLayout();
+
+ if (!mpPage->IsMasterPage())
+ {
+ maOldName = mpPage->GetName();
+ SdrLayerAdmin& rLayerAdmin = mpDoc->GetLayerAdmin();
+ SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ SdrLayerIDSet aVisibleLayers = mpPage->TRG_GetMasterPageVisibleLayers();
+
+ mbOldBckgrndVisible = aVisibleLayers.IsSet(aBckgrnd);
+ mbOldBckgrndObjsVisible = aVisibleLayers.IsSet(aBckgrndObj);
+ }
+ else
+ {
+ mbOldBckgrndVisible = false;
+ mbOldBckgrndObjsVisible = false;
+ }
+
+ if (pTheDoc && pTheDoc->GetDocumentType() == DocumentType::Draw)
+ SetComment( SdResId(STR_UNDO_MODIFY_PAGE_DRAW) );
+ else
+ SetComment( SdResId(STR_UNDO_MODIFY_PAGE) );
+}
+
+void ModifyPageUndoAction::Undo()
+{
+ // invalidate Selection, there could be objects deleted in this UNDO
+ // which are no longer allowed to be selected then.
+ SdrViewIter aIter(mpPage);
+ SdrView* pView = aIter.FirstView();
+
+ while(pView)
+ {
+ if(pView->AreObjectsMarked())
+ pView->UnmarkAll();
+ pView = aIter.NextView();
+ }
+
+ mpPage->SetAutoLayout( meOldAutoLayout );
+
+ if (!mpPage->IsMasterPage())
+ {
+ if (mpPage->GetName() != maOldName)
+ {
+ mpPage->SetName(maOldName);
+
+ if (mpPage->GetPageKind() == PageKind::Standard)
+ {
+ SdPage* pNotesPage = static_cast<SdPage*>(mpDoc->GetPage(mpPage->GetPageNum() + 1));
+ pNotesPage->SetName(maOldName);
+ }
+ }
+
+ SdrLayerAdmin& rLayerAdmin = mpDoc->GetLayerAdmin();
+ SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ SdrLayerIDSet aVisibleLayers;
+ aVisibleLayers.Set(aBckgrnd, mbOldBckgrndVisible);
+ aVisibleLayers.Set(aBckgrndObj, mbOldBckgrndObjsVisible);
+ mpPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+ }
+
+ // Redisplay
+ SfxViewFrame* pCurrent = SfxViewFrame::Current();
+ if( pCurrent )
+ {
+ pCurrent->GetDispatcher()->Execute(
+ SID_SWITCHPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+}
+
+void ModifyPageUndoAction::Redo()
+{
+ // invalidate Selection, there could be objects deleted in this UNDO
+ // which are no longer allowed to be selected then.
+ SdrViewIter aIter(mpPage);
+ SdrView* pView = aIter.FirstView();
+
+ while(pView)
+ {
+ if(pView->AreObjectsMarked())
+ pView->UnmarkAll();
+ pView = aIter.NextView();
+ }
+
+ mpPage->meAutoLayout = meNewAutoLayout;
+
+ if (!mpPage->IsMasterPage())
+ {
+ if (mpPage->GetName() != maNewName)
+ {
+ mpPage->SetName(maNewName);
+
+ if (mpPage->GetPageKind() == PageKind::Standard)
+ {
+ SdPage* pNotesPage = static_cast<SdPage*>(mpDoc->GetPage(mpPage->GetPageNum() + 1));
+ pNotesPage->SetName(maNewName);
+ }
+ }
+
+ SdrLayerAdmin& rLayerAdmin = mpDoc->GetLayerAdmin();
+ SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ SdrLayerIDSet aVisibleLayers;
+ aVisibleLayers.Set(aBckgrnd, mbNewBckgrndVisible);
+ aVisibleLayers.Set(aBckgrndObj, mbNewBckgrndObjsVisible);
+ mpPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
+ }
+
+ // Redisplay
+ SfxViewFrame* pCurrent = SfxViewFrame::Current();
+ if( pCurrent )
+ {
+ pCurrent->GetDispatcher()->Execute(
+ SID_SWITCHPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+}
+
+ModifyPageUndoAction::~ModifyPageUndoAction()
+{
+}
+
+RenameLayoutTemplateUndoAction::RenameLayoutTemplateUndoAction(
+ SdDrawDocument* pDocument,
+ const OUString& rOldLayoutName,
+ const OUString& rNewLayoutName)
+ : SdUndoAction(pDocument)
+ , maOldName(rOldLayoutName)
+ , maNewName(rNewLayoutName)
+ , maComment(SdResId(STR_TITLE_RENAMESLIDE))
+{
+ sal_Int32 nPos = maOldName.indexOf(SD_LT_SEPARATOR);
+ if (nPos != -1)
+ maOldName = maOldName.copy(0, nPos);
+}
+
+void RenameLayoutTemplateUndoAction::Undo()
+{
+ OUString aLayoutName(maNewName + SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE);
+ mpDoc->RenameLayoutTemplate( aLayoutName, maOldName );
+}
+
+void RenameLayoutTemplateUndoAction::Redo()
+{
+ OUString aLayoutName(maOldName + SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE);
+ mpDoc->RenameLayoutTemplate( aLayoutName, maNewName );
+}
+
+OUString RenameLayoutTemplateUndoAction::GetComment() const
+{
+ return maComment;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/viewoverlaymanager.cxx b/sd/source/ui/view/viewoverlaymanager.cxx
new file mode 100644
index 000000000..3cdfb9787
--- /dev/null
+++ b/sd/source/ui/view/viewoverlaymanager.cxx
@@ -0,0 +1,546 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+
+#include <vcl/help.hxx>
+#include <vcl/lazydelete.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/svapp.hxx>
+
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/sdr/overlay/overlaybitmapex.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svdpagv.hxx>
+
+#include <view/viewoverlaymanager.hxx>
+
+
+#include <DrawDocShell.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <sdresid.hxx>
+#include <EventMultiplexer.hxx>
+#include <View.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShell.hxx>
+#include <sdpage.hxx>
+#include <smarttag.hxx>
+
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+namespace {
+
+class ImageButtonHdl;
+
+}
+
+const sal_uInt16 gButtonSlots[] = { SID_INSERT_TABLE, SID_INSERT_DIAGRAM, SID_INSERT_GRAPHIC, SID_INSERT_AVMEDIA };
+const TranslateId gButtonToolTips[] = { STR_INSERT_TABLE, STR_INSERT_CHART, STR_INSERT_PICTURE, STR_INSERT_MOVIE };
+
+constexpr rtl::OUStringConstExpr aSmallPlaceHolders[] =
+{
+ BMP_PLACEHOLDER_TABLE_SMALL,
+ BMP_PLACEHOLDER_CHART_SMALL,
+ BMP_PLACEHOLDER_IMAGE_SMALL,
+ BMP_PLACEHOLDER_MOVIE_SMALL,
+ BMP_PLACEHOLDER_TABLE_SMALL_HOVER,
+ BMP_PLACEHOLDER_CHART_SMALL_HOVER,
+ BMP_PLACEHOLDER_IMAGE_SMALL_HOVER,
+ BMP_PLACEHOLDER_MOVIE_SMALL_HOVER
+};
+
+constexpr rtl::OUStringConstExpr aBigPlaceHolders[] =
+{
+ BMP_PLACEHOLDER_TABLE_LARGE,
+ BMP_PLACEHOLDER_CHART_LARGE,
+ BMP_PLACEHOLDER_IMAGE_LARGE,
+ BMP_PLACEHOLDER_MOVIE_LARGE,
+ BMP_PLACEHOLDER_TABLE_LARGE_HOVER,
+ BMP_PLACEHOLDER_CHART_LARGE_HOVER,
+ BMP_PLACEHOLDER_IMAGE_LARGE_HOVER,
+ BMP_PLACEHOLDER_MOVIE_LARGE_HOVER
+};
+
+static BitmapEx* getButtonImage( int index, bool large )
+{
+ static vcl::DeleteOnDeinit< BitmapEx > gSmallButtonImages[SAL_N_ELEMENTS(aSmallPlaceHolders)] = { vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty };
+ static vcl::DeleteOnDeinit< BitmapEx > gLargeButtonImages[SAL_N_ELEMENTS(aBigPlaceHolders)] = { vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty };
+
+ assert(SAL_N_ELEMENTS(aSmallPlaceHolders) == SAL_N_ELEMENTS(aBigPlaceHolders));
+
+ if( !gSmallButtonImages[0].get() )
+ {
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aSmallPlaceHolders); i++ )
+ {
+ gSmallButtonImages[i].set(OUString(aSmallPlaceHolders[i]));
+ gLargeButtonImages[i].set(OUString(aBigPlaceHolders[i]));
+ }
+ }
+
+ if( large )
+ {
+ return gLargeButtonImages[index].get();
+ }
+ else
+ {
+ return gSmallButtonImages[index].get();
+ }
+}
+
+const sal_uInt32 SMART_TAG_HDL_NUM = SAL_MAX_UINT32;
+
+namespace {
+
+class ChangePlaceholderTag : public SmartTag
+{
+ friend class ImageButtonHdl;
+public:
+ ChangePlaceholderTag( ::sd::View& rView, SdrObject& rPlaceholderObj );
+
+ /** returns true if the SmartTag handled the event. */
+ virtual bool MouseButtonDown( const MouseEvent&, SmartHdl& ) override;
+
+ /** returns true if the SmartTag consumes this event. */
+ virtual bool KeyInput( const KeyEvent& rKEvt ) override;
+
+ BitmapEx createOverlayImage( int nHighlight );
+
+protected:
+ virtual void addCustomHandles( SdrHdlList& rHandlerList ) override;
+
+private:
+ ::tools::WeakReference<SdrObject> mxPlaceholderObj;
+};
+
+class ImageButtonHdl : public SmartHdl
+{
+public:
+ ImageButtonHdl( const SmartTagReference& xTag, /* sal_uInt16 nSID, const Image& rImage, const Image& rImageMO, */ const Point& rPnt );
+ virtual ~ImageButtonHdl() override;
+ virtual void CreateB2dIAObject() override;
+ virtual bool IsFocusHdl() const override;
+ virtual PointerStyle GetPointer() const override;
+
+ virtual void onMouseEnter(const MouseEvent& rMEvt) override;
+ virtual void onHelpRequest() override;
+ virtual void onMouseLeave() override;
+
+ int getHighlightId() const { return mnHighlightId; }
+
+ void ShowTip();
+ static void HideTip();
+
+private:
+ rtl::Reference< ChangePlaceholderTag > mxChangePlaceholderTag;
+
+ int mnHighlightId;
+ Size maImageSize;
+};
+
+}
+
+ImageButtonHdl::ImageButtonHdl( const SmartTagReference& xTag /*, sal_uInt16 nSID, const Image& rImage, const Image& rImageMO*/, const Point& rPnt )
+: SmartHdl( xTag, rPnt, SdrHdlKind::SmartTag )
+, mxChangePlaceholderTag( dynamic_cast< ChangePlaceholderTag* >( xTag.get() ) )
+, mnHighlightId( -1 )
+, maImageSize( 42, 42 )
+{
+}
+
+ImageButtonHdl::~ImageButtonHdl()
+{
+ HideTip();
+}
+
+void ImageButtonHdl::HideTip()
+{
+ Help::HideBalloonAndQuickHelp();
+}
+
+void ImageButtonHdl::ShowTip()
+{
+ if (!pHdlList || !pHdlList->GetView() || mnHighlightId == -1)
+ return;
+
+ OutputDevice* pDev = pHdlList->GetView()->GetFirstOutputDevice();
+ if( pDev == nullptr )
+ pDev = Application::GetDefaultDevice();
+
+ OUString aHelpText(SdResId(gButtonToolTips[mnHighlightId]));
+ Point aHelpPos(pDev->LogicToPixel(GetPos()));
+ if (mnHighlightId == 1)
+ aHelpPos.Move(maImageSize.Width(), 0);
+ else if (mnHighlightId == 2)
+ aHelpPos.Move(0, maImageSize.Height());
+ else if (mnHighlightId == 3)
+ aHelpPos.Move(maImageSize.Width(), maImageSize.Height());
+ ::tools::Rectangle aLogicPix(aHelpPos, maImageSize);
+ vcl::Window* pWindow = pHdlList->GetView()->GetFirstOutputDevice()->GetOwnerWindow();
+ ::tools::Rectangle aScreenRect(pWindow->OutputToScreenPixel(aLogicPix.TopLeft()),
+ pWindow->OutputToScreenPixel(aLogicPix.BottomRight()));
+ Help::ShowQuickHelp(pWindow, aScreenRect, aHelpText);
+}
+
+void ImageButtonHdl::onHelpRequest()
+{
+ ShowTip();
+}
+
+void ImageButtonHdl::onMouseEnter(const MouseEvent& rMEvt)
+{
+ if( !(pHdlList && pHdlList->GetView()))
+ return;
+
+ int nHighlightId = 0;
+ OutputDevice* pDev = pHdlList->GetView()->GetFirstOutputDevice();
+ if( pDev == nullptr )
+ pDev = Application::GetDefaultDevice();
+
+ Point aMDPos( rMEvt.GetPosPixel() );
+ aMDPos -= pDev->LogicToPixel( GetPos() );
+
+ nHighlightId += aMDPos.X() > maImageSize.Width() ? 1 : 0;
+ nHighlightId += aMDPos.Y() > maImageSize.Height() ? 2 : 0;
+
+ if( mnHighlightId != nHighlightId )
+ {
+ HideTip();
+
+ mnHighlightId = nHighlightId;
+
+ ShowTip();
+
+ Touch();
+ }
+}
+
+void ImageButtonHdl::onMouseLeave()
+{
+ mnHighlightId = -1;
+ HideTip();
+ Touch();
+}
+
+void ImageButtonHdl::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ const Point aTagPos( GetPos() );
+ basegfx::B2DPoint aPosition( aTagPos.X(), aTagPos.Y() );
+
+ BitmapEx aBitmapEx( mxChangePlaceholderTag->createOverlayImage( mnHighlightId ) ); // maImageMO.GetBitmapEx() : maImage.GetBitmapEx() );
+ maImageSize = aBitmapEx.GetSizePixel();
+ maImageSize.setWidth( maImageSize.Width() >> 1 );
+ maImageSize.setHeight( maImageSize.Height() >> 1 );
+
+ if(!pHdlList)
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!pView || pView->areMarkHandlesHidden())
+ return;
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b = 0; b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ SdrPaintWindow& rPaintWindow = rPageWindow.GetPaintWindow();
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if(rPaintWindow.OutputToWindow() && xManager.is() )
+ {
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject(
+ new sdr::overlay::OverlayBitmapEx( aPosition, aBitmapEx, 0, 0 ));
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+}
+
+bool ImageButtonHdl::IsFocusHdl() const
+{
+ return false;
+}
+
+PointerStyle ImageButtonHdl::GetPointer() const
+{
+ return PointerStyle::Arrow;
+}
+
+ChangePlaceholderTag::ChangePlaceholderTag( ::sd::View& rView, SdrObject& rPlaceholderObj )
+: SmartTag( rView )
+, mxPlaceholderObj( &rPlaceholderObj )
+{
+}
+
+/** returns true if the ChangePlaceholderTag handled the event. */
+bool ChangePlaceholderTag::MouseButtonDown( const MouseEvent& /*rMEvt*/, SmartHdl& rHdl )
+{
+ int nHighlightId = static_cast< ImageButtonHdl& >(rHdl).getHighlightId();
+ if( nHighlightId >= 0 )
+ {
+ sal_uInt16 nSID = gButtonSlots[nHighlightId];
+
+ if( mxPlaceholderObj )
+ {
+ // mark placeholder if it is not currently marked (or if also others are marked)
+ if( !mrView.IsObjMarked( mxPlaceholderObj.get() ) || (mrView.GetMarkedObjectList().GetMarkCount() != 1) )
+ {
+ SdrPageView* pPV = mrView.GetSdrPageView();
+ mrView.UnmarkAllObj(pPV );
+ mrView.MarkObj(mxPlaceholderObj.get(), pPV);
+ }
+ }
+
+ mrView.GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( nSID, SfxCallMode::ASYNCHRON);
+ }
+ return false;
+}
+
+/** returns true if the SmartTag consumes this event. */
+bool ChangePlaceholderTag::KeyInput( const KeyEvent& rKEvt )
+{
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+ switch( nCode )
+ {
+ case KEY_DOWN:
+ case KEY_UP:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ case KEY_ESCAPE:
+ case KEY_TAB:
+ case KEY_RETURN:
+ case KEY_SPACE:
+ default:
+ return false;
+ }
+}
+
+BitmapEx ChangePlaceholderTag::createOverlayImage( int nHighlight )
+{
+ BitmapEx aRet;
+ if( mxPlaceholderObj.is() )
+ {
+ SdrObject* pPlaceholder = mxPlaceholderObj.get();
+ SmartTagReference xThis( this );
+ const ::tools::Rectangle& rSnapRect = pPlaceholder->GetSnapRect();
+
+ OutputDevice* pDev = mrView.GetFirstOutputDevice();
+ if( pDev == nullptr )
+ pDev = Application::GetDefaultDevice();
+
+ Size aShapeSizePix = pDev->LogicToPixel(rSnapRect.GetSize());
+ ::tools::Long nShapeSizePix = std::min(aShapeSizePix.Width(),aShapeSizePix.Height());
+
+ bool bLarge = nShapeSizePix > 250;
+
+ Size aSize( getButtonImage( 0, bLarge )->GetSizePixel() );
+
+ aRet.Scale(Size(aSize.Width() << 1, aSize.Height() << 1));
+
+ const ::tools::Rectangle aRectSrc( Point( 0, 0 ), aSize );
+
+ aRet = *(getButtonImage((nHighlight == 0) ? 4 : 0, bLarge));
+ aRet.Expand( aSize.Width(), aSize.Height(), true );
+
+ aRet.CopyPixel( ::tools::Rectangle( Point( aSize.Width(), 0 ), aSize ), aRectSrc, getButtonImage((nHighlight == 1) ? 5 : 1, bLarge) );
+ aRet.CopyPixel( ::tools::Rectangle( Point( 0, aSize.Height() ), aSize ), aRectSrc, getButtonImage((nHighlight == 2) ? 6 : 2, bLarge) );
+ aRet.CopyPixel( ::tools::Rectangle( Point( aSize.Width(), aSize.Height() ), aSize ), aRectSrc, getButtonImage((nHighlight == 3) ? 7 : 3, bLarge) );
+ }
+
+ return aRet;
+}
+
+void ChangePlaceholderTag::addCustomHandles( SdrHdlList& rHandlerList )
+{
+ if( !mxPlaceholderObj.is() )
+ return;
+
+ SdrObject* pPlaceholder = mxPlaceholderObj.get();
+ SmartTagReference xThis( this );
+ const ::tools::Rectangle& rSnapRect = pPlaceholder->GetSnapRect();
+ const Point aPoint;
+
+ OutputDevice* pDev = mrView.GetFirstOutputDevice();
+ if( pDev == nullptr )
+ pDev = Application::GetDefaultDevice();
+
+ Size aShapeSizePix = pDev->LogicToPixel(rSnapRect.GetSize());
+ ::tools::Long nShapeSizePix = std::min(aShapeSizePix.Width(),aShapeSizePix.Height());
+ if( 50 > nShapeSizePix )
+ return;
+
+ bool bLarge = nShapeSizePix > 250;
+
+ Size aButtonSize( pDev->PixelToLogic( getButtonImage(0, bLarge )->GetSizePixel()) );
+
+ const int nColumns = 2;
+ const int nRows = 2;
+
+ ::tools::Long all_width = nColumns * aButtonSize.Width();
+ ::tools::Long all_height = nRows * aButtonSize.Height();
+
+ Point aPos( rSnapRect.Center() );
+ aPos.AdjustX( -(all_width >> 1) );
+ aPos.AdjustY( -(all_height >> 1) );
+
+ std::unique_ptr<ImageButtonHdl> pHdl(new ImageButtonHdl( xThis, aPoint ));
+ pHdl->SetObjHdlNum( SMART_TAG_HDL_NUM );
+ pHdl->SetPageView( mrView.GetSdrPageView() );
+
+ pHdl->SetPos( aPos );
+
+ rHandlerList.AddHdl( std::move(pHdl) );
+}
+
+ViewOverlayManager::ViewOverlayManager( ViewShellBase& rViewShellBase )
+: mrBase( rViewShellBase )
+, mnUpdateTagsEvent( nullptr )
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,ViewOverlayManager,EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->AddEventListener(aLink);
+
+ StartListening( *mrBase.GetDocShell() );
+}
+
+ViewOverlayManager::~ViewOverlayManager()
+{
+ Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,ViewOverlayManager,EventMultiplexerListener) );
+ mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
+
+ if( mnUpdateTagsEvent )
+ {
+ Application::RemoveUserEvent( mnUpdateTagsEvent );
+ mnUpdateTagsEvent = nullptr;
+ }
+
+ DisposeTags();
+}
+
+void ViewOverlayManager::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::DocChanged)
+ {
+ UpdateTags();
+ }
+}
+
+void ViewOverlayManager::onZoomChanged()
+{
+ if( !maTagVector.empty() )
+ {
+ UpdateTags();
+ }
+}
+
+void ViewOverlayManager::UpdateTags()
+{
+ if( !mnUpdateTagsEvent )
+ mnUpdateTagsEvent = Application::PostUserEvent( LINK( this, ViewOverlayManager, UpdateTagsHdl ) );
+}
+
+IMPL_LINK_NOARG(ViewOverlayManager, UpdateTagsHdl, void*, void)
+{
+ mnUpdateTagsEvent = nullptr;
+ bool bChanges = DisposeTags();
+ bChanges |= CreateTags();
+
+ if( bChanges && mrBase.GetDrawView() )
+ static_cast< ::sd::View* >( mrBase.GetDrawView() )->updateHandles();
+}
+
+bool ViewOverlayManager::CreateTags()
+{
+ bool bChanges = false;
+
+ std::shared_ptr<ViewShell> aMainShell = mrBase.GetMainViewShell();
+
+ SdPage* pPage = aMainShell ? aMainShell->getCurrentPage() : nullptr;
+
+ if( pPage && !pPage->IsMasterPage() && (pPage->GetPageKind() == PageKind::Standard) )
+ {
+ const std::list< SdrObject* >& rShapes = pPage->GetPresentationShapeList().getList();
+
+ for( SdrObject* pShape : rShapes )
+ {
+ if( pShape->IsEmptyPresObj() && (pShape->GetObjIdentifier() == SdrObjKind::OutlineText) && (mrBase.GetDrawView()->GetTextEditObject() != pShape) )
+ {
+ rtl::Reference< SmartTag > xTag( new ChangePlaceholderTag( *mrBase.GetMainViewShell()->GetView(), *pShape ) );
+ maTagVector.push_back(xTag);
+ bChanges = true;
+ }
+ }
+ }
+
+ return bChanges;
+}
+
+bool ViewOverlayManager::DisposeTags()
+{
+ if( !maTagVector.empty() )
+ {
+ ViewTagVector vec;
+ vec.swap( maTagVector );
+
+ for (auto& rxViewTag : vec)
+ rxViewTag->Dispose();
+ return true;
+ }
+
+ return false;
+}
+
+IMPL_LINK(ViewOverlayManager,EventMultiplexerListener,
+ tools::EventMultiplexerEvent&, rEvent, void)
+{
+ switch (rEvent.meEventId)
+ {
+ case EventMultiplexerEventId::MainViewAdded:
+ case EventMultiplexerEventId::ViewAdded:
+ case EventMultiplexerEventId::BeginTextEdit:
+ case EventMultiplexerEventId::EndTextEdit:
+ case EventMultiplexerEventId::CurrentPageChanged:
+ UpdateTags();
+ break;
+ default: break;
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/viewshe2.cxx b/sd/source/ui/view/viewshe2.cxx
new file mode 100644
index 000000000..8b16124ba
--- /dev/null
+++ b/sd/source/ui/view/viewshe2.cxx
@@ -0,0 +1,958 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+#include <ViewShell.hxx>
+#include <ViewShellHint.hxx>
+
+#include <ViewShellImplementation.hxx>
+#include <FactoryIds.hxx>
+
+#include <svx/svxids.hrc>
+#include <vcl/scrbar.hxx>
+#include <svx/svdpagv.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/ruler.hxx>
+#include <editeng/outliner.hxx>
+#include <svtools/ehdl.hxx>
+#include <svx/svdoole2.hxx>
+#include <svtools/sfxecode.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <comphelper/classids.hxx>
+#include <osl/diagnose.h>
+
+#include <strings.hrc>
+#include <app.hrc>
+#include <unokywds.hxx>
+
+#include <sdundogr.hxx>
+#include <FrameView.hxx>
+#include <sdresid.hxx>
+#include <drawdoc.hxx>
+#include <View.hxx>
+#include <fupoor.hxx>
+#include <Client.hxx>
+#include <DrawDocShell.hxx>
+#include <sdpage.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShellBase.hxx>
+
+#include <Window.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <svtools/soerr.hxx>
+#include <svx/charthelper.hxx>
+#include <comphelper/lok.hxx>
+
+using namespace com::sun::star;
+
+namespace sd {
+
+/**
+ * adjust Thumbpos and VisibleSize
+ */
+void ViewShell::UpdateScrollBars()
+{
+ if (mpHorizontalScrollBar)
+ {
+ ::tools::Long nW = static_cast<::tools::Long>(mpContentWindow->GetVisibleWidth() * 32000);
+ ::tools::Long nX = static_cast<::tools::Long>(mpContentWindow->GetVisibleX() * 32000);
+ mpHorizontalScrollBar->SetVisibleSize(nW);
+ mpHorizontalScrollBar->SetThumbPos(nX);
+ nW = 32000 - nW;
+ ::tools::Long nLine = static_cast<::tools::Long>(mpContentWindow->GetScrlLineWidth() * nW);
+ ::tools::Long nPage = static_cast<::tools::Long>(mpContentWindow->GetScrlPageWidth() * nW);
+ mpHorizontalScrollBar->SetLineSize(nLine);
+ mpHorizontalScrollBar->SetPageSize(nPage);
+ }
+
+ if (mpVerticalScrollBar)
+ {
+ ::tools::Long nH = static_cast<::tools::Long>(mpContentWindow->GetVisibleHeight() * 32000);
+ ::tools::Long nY = static_cast<::tools::Long>(mpContentWindow->GetVisibleY() * 32000);
+
+ if(IsPageFlipMode()) // ie in zoom mode where no panning
+ {
+ SdPage* pPage = static_cast<DrawViewShell*>(this)->GetActualPage();
+ sal_uInt16 nCurPage = (pPage->GetPageNum() - 1) / 2;
+ sal_uInt16 nTotalPages = GetDoc()->GetSdPageCount(pPage->GetPageKind());
+ mpVerticalScrollBar->SetRange(Range(0,256*nTotalPages));
+ mpVerticalScrollBar->SetVisibleSize(256);
+ mpVerticalScrollBar->SetThumbPos(256*nCurPage);
+ mpVerticalScrollBar->SetLineSize(256);
+ mpVerticalScrollBar->SetPageSize(256);
+ }
+ else
+ {
+ mpVerticalScrollBar->SetRange(Range(0,32000));
+ mpVerticalScrollBar->SetVisibleSize(nH);
+ mpVerticalScrollBar->SetThumbPos(nY);
+ nH = 32000 - nH;
+ ::tools::Long nLine = static_cast<::tools::Long>(mpContentWindow->GetScrlLineHeight() * nH);
+ ::tools::Long nPage = static_cast<::tools::Long>(mpContentWindow->GetScrlPageHeight() * nH);
+ mpVerticalScrollBar->SetLineSize(nLine);
+ mpVerticalScrollBar->SetPageSize(nPage);
+ }
+ }
+
+ if (mbHasRulers)
+ {
+ UpdateHRuler();
+ UpdateVRuler();
+ }
+
+}
+/**
+ * Handling for horizontal Scrollbars
+ */
+IMPL_LINK(ViewShell, HScrollHdl, ScrollBar *, pHScroll, void )
+{
+ VirtHScrollHdl(pHScroll);
+}
+
+/**
+ * virtual scroll handler for horizontal Scrollbars
+ */
+void ViewShell::VirtHScrollHdl(ScrollBar* pHScroll)
+{
+ ::tools::Long nDelta = pHScroll->GetDelta();
+
+ if (nDelta == 0)
+ return;
+
+ double fX = static_cast<double>(pHScroll->GetThumbPos()) / pHScroll->GetRange().Len();
+
+ // scroll all windows of the column
+ ::sd::View* pView = GetView();
+ OutlinerView* pOLV = nullptr;
+
+ if (pView)
+ pOLV = pView->GetTextEditOutlinerView();
+
+ if (pOLV)
+ pOLV->HideCursor();
+
+ mpContentWindow->SetVisibleXY(fX, -1);
+
+ ::tools::Rectangle aVisArea = GetDocSh()->GetVisArea(ASPECT_CONTENT);
+ Point aVisAreaPos = GetActiveWindow()->PixelToLogic( Point(0,0) );
+ aVisArea.SetPos(aVisAreaPos);
+ GetDocSh()->SetVisArea(aVisArea);
+
+ Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ VisAreaChanged(aVisAreaWin);
+
+ if (pView)
+ {
+ pView->VisAreaChanged(GetActiveWindow()->GetOutDev());
+ }
+
+ if (pOLV)
+ pOLV->ShowCursor();
+
+ if (mbHasRulers)
+ UpdateHRuler();
+}
+
+/**
+ * handling for vertical Scrollbars
+ */
+IMPL_LINK(ViewShell, VScrollHdl, ScrollBar *, pVScroll, void )
+{
+ VirtVScrollHdl(pVScroll);
+}
+
+/**
+ * handling for vertical Scrollbars
+ */
+void ViewShell::VirtVScrollHdl(ScrollBar* pVScroll)
+{
+ if(IsPageFlipMode())
+ {
+ SdPage* pPage = static_cast<DrawViewShell*>(this)->GetActualPage();
+ sal_uInt16 nCurPage = (pPage->GetPageNum() - 1) >> 1;
+ sal_uInt16 nNewPage = static_cast<sal_uInt16>(pVScroll->GetThumbPos())/256;
+ if( nCurPage != nNewPage )
+ static_cast<DrawViewShell*>(this)->SwitchPage(nNewPage);
+ }
+ else //panning mode
+ {
+ double fY = static_cast<double>(pVScroll->GetThumbPos()) / pVScroll->GetRange().Len();
+
+ ::sd::View* pView = GetView();
+ OutlinerView* pOLV = nullptr;
+
+ if (pView)
+ pOLV = pView->GetTextEditOutlinerView();
+
+ if (pOLV)
+ pOLV->HideCursor();
+
+ mpContentWindow->SetVisibleXY(-1, fY);
+
+ ::tools::Rectangle aVisArea = GetDocSh()->GetVisArea(ASPECT_CONTENT);
+ Point aVisAreaPos = GetActiveWindow()->PixelToLogic( Point(0,0) );
+ aVisArea.SetPos(aVisAreaPos);
+ GetDocSh()->SetVisArea(aVisArea);
+
+ Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ VisAreaChanged(aVisAreaWin);
+
+ if (pView)
+ {
+ pView->VisAreaChanged(GetActiveWindow()->GetOutDev());
+ }
+
+ if (pOLV)
+ pOLV->ShowCursor();
+
+ if (mbHasRulers)
+ UpdateVRuler();
+
+ }
+}
+
+VclPtr<SvxRuler> ViewShell::CreateHRuler(::sd::Window* )
+{
+ return nullptr;
+}
+
+VclPtr<SvxRuler> ViewShell::CreateVRuler(::sd::Window* )
+{
+ return nullptr;
+}
+
+void ViewShell::UpdateHRuler()
+{
+}
+
+void ViewShell::UpdateVRuler()
+{
+}
+
+/**
+ * Scroll a specific number of lines. Is used in the automatic scrolling
+ * (character/drag).
+ */
+void ViewShell::ScrollLines(::tools::Long nLinesX, ::tools::Long nLinesY)
+{
+ if ( nLinesX )
+ {
+ nLinesX *= mpHorizontalScrollBar->GetLineSize();
+ }
+ if ( nLinesY )
+ {
+ nLinesY *= mpVerticalScrollBar->GetLineSize();
+ }
+
+ Scroll(nLinesX, nLinesY);
+}
+
+void ViewShell::Scroll(::tools::Long nScrollX, ::tools::Long nScrollY)
+{
+ if (nScrollX)
+ {
+ ::tools::Long nNewThumb = mpHorizontalScrollBar->GetThumbPos() + nScrollX;
+ mpHorizontalScrollBar->SetThumbPos(nNewThumb);
+ }
+ if (nScrollY)
+ {
+ ::tools::Long nNewThumb = mpVerticalScrollBar->GetThumbPos() + nScrollY;
+ mpVerticalScrollBar->SetThumbPos(nNewThumb);
+ }
+ double fX = static_cast<double>(mpHorizontalScrollBar->GetThumbPos()) /
+ mpHorizontalScrollBar->GetRange().Len();
+ double fY = static_cast<double>(mpVerticalScrollBar->GetThumbPos()) /
+ mpVerticalScrollBar->GetRange().Len();
+
+ GetActiveWindow()->SetVisibleXY(fX, fY);
+
+ ::tools::Rectangle aVisArea = GetDocSh()->GetVisArea(ASPECT_CONTENT);
+ Point aVisAreaPos = GetActiveWindow()->PixelToLogic( Point(0,0) );
+ aVisArea.SetPos(aVisAreaPos);
+ GetDocSh()->SetVisArea(aVisArea);
+
+ Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ VisAreaChanged(aVisAreaWin);
+
+ ::sd::View* pView = GetView();
+ if (pView)
+ {
+ pView->VisAreaChanged(GetActiveWindow()->GetOutDev());
+ }
+
+ if (mbHasRulers)
+ {
+ UpdateHRuler();
+ UpdateVRuler();
+ }
+}
+
+/**
+ * Set zoom factor for all split windows.
+ */
+void ViewShell::SetZoom(::tools::Long nZoom)
+{
+ Fraction aUIScale(nZoom, 100);
+ aUIScale *= GetDoc()->GetUIScale();
+
+ if (mpHorizontalRuler)
+ mpHorizontalRuler->SetZoom(aUIScale);
+
+ if (mpVerticalRuler)
+ mpVerticalRuler->SetZoom(aUIScale);
+
+ if (mpContentWindow)
+ {
+ mpContentWindow->SetZoomIntegral(nZoom);
+
+ // #i74769# Here is a 2nd way (besides Window::Scroll) to set the visible prt
+ // of the window. It needs - like Scroll(ScrollFlags::Children) does - also to move
+ // the child windows. I am trying InvalidateFlags::Children here which makes things better,
+ // but does not solve the problem completely. Need to ask PL.
+ mpContentWindow->Invalidate(InvalidateFlags::Children);
+ }
+
+ Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ VisAreaChanged(aVisAreaWin);
+
+ ::sd::View* pView = GetView();
+ if (pView)
+ {
+ pView->VisAreaChanged(GetActiveWindow()->GetOutDev());
+ }
+
+ UpdateScrollBars();
+}
+
+::tools::Long ViewShell::GetZoom() const
+{
+ if (mpContentWindow)
+ {
+ return mpContentWindow->GetZoom();
+ }
+
+ return 0;
+}
+
+/**
+ * Set zoom rectangle for active window. Sets all split windows to the same zoom
+ * factor.
+ */
+void ViewShell::SetZoomRect(const ::tools::Rectangle& rZoomRect)
+{
+ ::tools::Long nZoom = GetActiveWindow()->SetZoomRect(rZoomRect);
+ Fraction aUIScale(nZoom, 100);
+ aUIScale *= GetDoc()->GetUIScale();
+
+ Point aPos = GetActiveWindow()->GetWinViewPos();
+
+ if (mpHorizontalRuler)
+ mpHorizontalRuler->SetZoom(aUIScale);
+
+ if (mpVerticalRuler)
+ mpVerticalRuler->SetZoom(aUIScale);
+
+ if (mpContentWindow)
+ {
+ Point aNewPos = mpContentWindow->GetWinViewPos();
+ aNewPos.setX( aPos.X() );
+ aNewPos.setY( aPos.Y() );
+ mpContentWindow->SetZoomIntegral(nZoom);
+ mpContentWindow->SetWinViewPos(aNewPos);
+ mpContentWindow->UpdateMapOrigin();
+
+ // When tiled rendering, UpdateMapOrigin() doesn't touch the map mode.
+ if (!comphelper::LibreOfficeKit::isActive())
+ // #i74769# see above
+ mpContentWindow->Invalidate(InvalidateFlags::Children);
+ }
+
+ Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ VisAreaChanged(aVisAreaWin);
+
+ ::sd::View* pView = GetView();
+ if (pView)
+ {
+ pView->VisAreaChanged(GetActiveWindow()->GetOutDev());
+ }
+
+ UpdateScrollBars();
+}
+
+/**
+ * Initialize imaging parameters for all split windows.
+ */
+void ViewShell::InitWindows(const Point& rViewOrigin, const Size& rViewSize,
+ const Point& rWinPos, bool bUpdate)
+{
+ if (mpContentWindow)
+ {
+ mpContentWindow->SetViewOrigin(rViewOrigin);
+ mpContentWindow->SetViewSize(rViewSize);
+ mpContentWindow->SetWinViewPos(rWinPos);
+
+ if ( bUpdate )
+ {
+ mpContentWindow->UpdateMapOrigin();
+ mpContentWindow->Invalidate();
+ }
+ }
+
+ Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ VisAreaChanged(aVisAreaWin);
+
+ ::sd::View* pView = GetView();
+ if (pView)
+ {
+ pView->VisAreaChanged(GetActiveWindow()->GetOutDev());
+ }
+}
+
+/**
+ * Invalidate all split windows below the ?provided rectangle.
+ */
+void ViewShell::InvalidateWindows()
+{
+ if (mpContentWindow)
+ mpContentWindow->Invalidate();
+}
+
+/**
+ * Draw a selection rectangle with the ?provided pen on all split windows.
+ */
+void ViewShell::DrawMarkRect(const ::tools::Rectangle& rRect) const
+{
+ if (mpContentWindow)
+ {
+ mpContentWindow->InvertTracking(rRect, ShowTrackFlags::Object | ShowTrackFlags::TrackWindow);
+ }
+}
+
+void ViewShell::SetPageSizeAndBorder(PageKind ePageKind, const Size& rNewSize,
+ ::tools::Long nLeft, ::tools::Long nRight,
+ ::tools::Long nUpper, ::tools::Long nLower, bool bScaleAll,
+ Orientation eOrientation, sal_uInt16 nPaperBin,
+ bool bBackgroundFullSize)
+{
+ const sal_uInt16 nMasterPageCnt(GetDoc()->GetMasterSdPageCount(ePageKind));
+ const sal_uInt16 nPageCnt(GetDoc()->GetSdPageCount(ePageKind));
+
+ if(0 == nPageCnt && 0 == nMasterPageCnt)
+ {
+ return;
+ }
+
+ std::unique_ptr<SdUndoGroup> pUndoGroup;
+ SfxViewShell* pViewShell(GetViewShell());
+ if (pViewShell)
+ {
+ pUndoGroup.reset(new SdUndoGroup(GetDoc()));
+ pUndoGroup->SetComment(SdResId(STR_UNDO_CHANGE_PAGEFORMAT));
+ }
+ Broadcast (ViewShellHint(ViewShellHint::HINT_PAGE_RESIZE_START));
+
+ // use Model-based method at SdDrawDocument
+ GetDoc()->AdaptPageSizeForAllPages(
+ rNewSize,
+ ePageKind,
+ pUndoGroup.get(),
+ nLeft,
+ nRight,
+ nUpper,
+ nLower,
+ bScaleAll,
+ eOrientation,
+ nPaperBin,
+ bBackgroundFullSize);
+
+ // adjust handout page to new format of the standard page
+ if(0 != nPageCnt && ((ePageKind == PageKind::Standard) || (ePageKind == PageKind::Handout)))
+ {
+ GetDoc()->GetSdPage(0, PageKind::Handout)->CreateTitleAndLayout(true);
+ }
+
+ // handed over undo group to undo manager
+ if (pViewShell)
+ {
+ pViewShell->GetViewFrame()->GetObjectShell()->GetUndoManager()->AddUndoAction(std::move(pUndoGroup));
+ }
+
+ // calculate View-Sizes
+ SdPage* pPage(0 != nPageCnt
+ ? GetDoc()->GetSdPage(0, ePageKind)
+ : GetDoc()->GetMasterSdPage(0, ePageKind));
+ const ::tools::Long nWidth(pPage->GetSize().Width());
+ const ::tools::Long nHeight(pPage->GetSize().Height());
+ const Point aPageOrg(nWidth, nHeight / 2);
+ const Size aViewSize(nWidth * 3, nHeight * 2);
+ Point aVisAreaPos;
+ ::sd::View* pView(GetView());
+ const Point aNewOrigin(pPage->GetLeftBorder(), pPage->GetUpperBorder());
+
+ InitWindows(aPageOrg, aViewSize, Point(-1, -1), true);
+
+ if ( GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
+ {
+ aVisAreaPos = GetDocSh()->GetVisArea(ASPECT_CONTENT).TopLeft();
+ }
+
+ if (pView)
+ {
+ pView->SetWorkArea(::tools::Rectangle(Point() - aVisAreaPos - aPageOrg, aViewSize));
+ }
+
+ UpdateScrollBars();
+
+ if (pView)
+ {
+ pView->GetSdrPageView()->SetPageOrigin(aNewOrigin);
+ }
+
+ if(nullptr != pViewShell)
+ {
+ pViewShell->GetViewFrame()->GetBindings().Invalidate(SID_RULER_NULL_OFFSET);
+ // zoom onto (new) page size
+ pViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_SIZE_PAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+
+ Broadcast(ViewShellHint(ViewShellHint::HINT_PAGE_RESIZE_END));
+}
+
+/**
+ * Set zoom factor for InPlace
+ */
+void ViewShell::SetZoomFactor(const Fraction& rZoomX, const Fraction&)
+{
+ ::tools::Long nZoom = static_cast<::tools::Long>(static_cast<double>(rZoomX) * 100);
+ SetZoom(nZoom);
+}
+
+void ViewShell::SetActiveWindow (::sd::Window* pWin)
+{
+ SfxViewShell* pViewShell = GetViewShell();
+ OSL_ASSERT (pViewShell!=nullptr);
+
+ if (pViewShell->GetWindow() != pWin)
+ {
+ // #i31551# was wrong, it may have been a problem with the repaint at that time.
+ // For transparent form controls, it is necessary to have that flag set, all apps
+ // do set it. Enabling again.
+ if (pWin)
+ {
+ pWin->EnableChildTransparentMode();
+ }
+ }
+
+ if (mpActiveWindow.get() != pWin)
+ mpActiveWindow = pWin;
+
+ // The rest of this function is not guarded anymore against calling this
+ // method with an already active window because the functions may still
+ // point to the old window when the new one has already been assigned to
+ // pWindow elsewhere.
+ ::sd::View* pView = GetView();
+ if (pView)
+ {
+ pView->SetActualWin(pWin->GetOutDev());
+ }
+ if(HasCurrentFunction())
+ {
+ GetCurrentFunction()->SetWindow(pWin);
+ }
+}
+
+bool ViewShell::RequestHelp(const HelpEvent& rHEvt)
+{
+ bool bReturn = false;
+
+ if (bool(rHEvt.GetMode()))
+ {
+ if(HasCurrentFunction())
+ {
+ bReturn = GetCurrentFunction()->RequestHelp(rHEvt);
+ }
+ }
+
+ return bReturn;
+}
+
+void ViewShell::SetFrameView (FrameView* pNewFrameView)
+{
+ mpFrameView = pNewFrameView;
+ ReadFrameViewData (mpFrameView);
+}
+
+/*************************************************************************
+|*
+|* Read FrameViews data and set actual views data
+|*
+\************************************************************************/
+
+void ViewShell::ReadFrameViewData(FrameView*)
+{
+}
+
+/*************************************************************************
+|*
+|* Write actual views data to FrameView
+|*
+\************************************************************************/
+
+void ViewShell::WriteFrameViewData()
+{
+}
+
+bool ViewShell::ActivateObject(SdrOle2Obj* pObj, sal_Int32 nVerb)
+{
+ ErrCode aErrCode = ERRCODE_NONE;
+
+ SfxErrorContext aEC(ERRCTX_SO_DOVERB, GetFrameWeld(), RID_SO_ERRCTX);
+ bool bAbort = false;
+ GetDocSh()->SetWaitCursor( true );
+ SfxViewShell* pViewShell = GetViewShell();
+ OSL_ASSERT (pViewShell!=nullptr);
+ bool bChangeDefaultsForChart = false;
+
+ uno::Reference < embed::XEmbeddedObject > xObj = pObj->GetObjRef();
+ if ( !xObj.is() )
+ {
+ // provide OLE object to empty OLE object
+ OUString aName = pObj->GetProgName();
+ OUString aObjName;
+ SvGlobalName aClass;
+
+ if( aName == "StarChart" || aName == "StarOrg" )
+ {
+ if( SvtModuleOptions().IsChart() )
+ {
+ aClass = SvGlobalName( SO3_SCH_CLASSID );
+ bChangeDefaultsForChart = true;
+ }
+ }
+ else if( aName == "StarCalc" )
+ {
+ if( SvtModuleOptions().IsCalc() )
+ aClass = SvGlobalName( SO3_SC_CLASSID );
+ }
+ else if( aName == "StarMath" )
+ {
+ if( SvtModuleOptions().IsMath() )
+ aClass = SvGlobalName( SO3_SM_CLASSID );
+ }
+
+ if ( aClass != SvGlobalName() )
+ xObj = GetDocSh()->GetEmbeddedObjectContainer().CreateEmbeddedObject( aClass.GetByteSequence(), aObjName );
+
+ if( !xObj.is() )
+ {
+ aName.clear();
+
+ // call dialog "insert OLE object"
+ GetDocSh()->SetWaitCursor( false );
+ pViewShell->GetViewFrame()->GetDispatcher()->Execute(
+ SID_INSERT_OBJECT,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD);
+ xObj = pObj->GetObjRef();
+ GetDocSh()->SetWaitCursor( true );
+
+ if (!xObj.is())
+ {
+ bAbort = true;
+ }
+ }
+
+ if ( xObj.is() )
+ {
+ // OLE object is no longer empty
+ pObj->SetEmptyPresObj(false);
+ pObj->SetOutlinerParaObject(std::nullopt);
+ pObj->ClearGraphic();
+
+ // the empty OLE object gets a new IPObj
+ if (!aName.isEmpty())
+ {
+ pObj->SetObjRef(xObj);
+ pObj->SetName(aObjName);
+ pObj->SetPersistName(aObjName);
+ }
+ else
+ {
+ // insertion was done by the dialog
+ pObj->SetObjRef(xObj);
+ }
+
+ ::tools::Rectangle aRect = pObj->GetLogicRect();
+
+ if ( pObj->GetAspect() != embed::Aspects::MSOLE_ICON )
+ {
+ awt::Size aSz;
+ aSz.Width = aRect.GetWidth();
+ aSz.Height = aRect.GetHeight();
+ xObj->setVisualAreaSize( pObj->GetAspect(), aSz );
+ }
+
+ GetViewShellBase().SetVerbs( xObj->getSupportedVerbs() );
+
+ nVerb = embed::EmbedVerbs::MS_OLEVERB_SHOW;
+ }
+ else
+ {
+ aErrCode = ERRCODE_SFX_OLEGENERAL;
+ }
+ }
+
+ if( aErrCode == ERRCODE_NONE )
+ {
+ ::sd::View* pView = GetView();
+
+ if (pView->IsTextEdit())
+ {
+ pView->SdrEndTextEdit();
+ }
+
+ SfxInPlaceClient* pSdClient =
+ pViewShell->FindIPClient(pObj->GetObjRef(), GetActiveWindow());
+
+ if ( !pSdClient )
+ {
+ pSdClient = new Client(pObj, this, GetActiveWindow());
+ }
+
+ ::tools::Rectangle aRect = pObj->GetLogicRect();
+
+ {
+ // #i118485# center on BoundRect for activation,
+ // OLE may be sheared/rotated now
+ const ::tools::Rectangle& rBoundRect = pObj->GetCurrentBoundRect();
+ const Point aDelta(rBoundRect.Center() - aRect.Center());
+ aRect.Move(aDelta.X(), aDelta.Y());
+ }
+
+ Size aDrawSize = aRect.GetSize();
+
+ MapMode aMapMode( GetDoc()->GetScaleUnit() );
+ Size aObjAreaSize = pObj->GetOrigObjSize( &aMapMode );
+ if( pObj->IsChart() ) //charts never should be stretched see #i84323# for example
+ aObjAreaSize = aDrawSize;
+
+ Fraction aScaleWidth (aDrawSize.Width(), aObjAreaSize.Width() );
+ Fraction aScaleHeight(aDrawSize.Height(), aObjAreaSize.Height() );
+ aScaleWidth.ReduceInaccurate(10); // compatible to the SdrOle2Obj
+ aScaleHeight.ReduceInaccurate(10);
+ pSdClient->SetSizeScale(aScaleWidth, aScaleHeight);
+
+ // visible section is only changed in-place!
+ aRect.SetSize(aObjAreaSize);
+ // the object area size must be set after scaling, since it triggers the resizing
+ pSdClient->SetObjArea(aRect);
+
+ if( bChangeDefaultsForChart && xObj.is())
+ {
+ ChartHelper::AdaptDefaultsForChart( xObj );
+ }
+
+ pSdClient->DoVerb(nVerb); // if necessary, ErrCode is outputted by Sfx
+ pViewShell->GetViewFrame()->GetBindings().Invalidate(
+ SID_NAVIGATOR_STATE, true);
+ }
+
+ GetDocSh()->SetWaitCursor( false );
+
+ if (aErrCode != ERRCODE_NONE && !bAbort)
+ {
+ ErrorHandler::HandleError(* new StringErrorInfo(aErrCode, OUString() ) );
+ }
+
+ return aErrCode == ERRCODE_NONE;
+}
+
+/**
+ * @returns enclosing rectangle of all (split-) windows.
+ */
+const ::tools::Rectangle& ViewShell::GetAllWindowRect()
+{
+ maAllWindowRectangle.SetPos(
+ mpContentWindow->OutputToScreenPixel(Point(0,0)));
+ return maAllWindowRectangle;
+}
+
+void ViewShell::ReadUserData()
+{
+ // zoom onto VisArea from FrameView
+ GetViewShell()->GetViewFrame()->GetDispatcher()->Execute(SID_SIZE_VISAREA,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+}
+
+void ViewShell::WriteUserData()
+{
+ // writing of our data is always done in WriteFrameViewData()
+ WriteFrameViewData();
+}
+
+/**
+ * Switch ruler on/off
+ */
+void ViewShell::SetRuler(bool bRuler)
+{
+ mbHasRulers = ( bRuler && !GetDocSh()->IsPreview() ); // no rulers on preview mode
+
+ if (mpHorizontalRuler)
+ {
+ if (mbHasRulers)
+ {
+ mpHorizontalRuler->Show();
+ }
+ else
+ {
+ mpHorizontalRuler->Hide();
+ }
+ }
+
+ if (mpVerticalRuler)
+ {
+ if (mbHasRulers)
+ {
+ mpVerticalRuler->Show();
+ }
+ else
+ {
+ mpVerticalRuler->Hide();
+ }
+ }
+
+ OSL_ASSERT(GetViewShell()!=nullptr);
+ if (IsMainViewShell())
+ GetViewShell()->InvalidateBorder();
+}
+
+void ViewShell::SetScrollBarsVisible(bool bVisible)
+{
+ if (mpVerticalScrollBar)
+ mpVerticalScrollBar->Show( bVisible );
+
+ if (mpHorizontalScrollBar)
+ mpHorizontalScrollBar->Show( bVisible );
+
+ if (mpScrollBarBox)
+ mpScrollBarBox->Show(bVisible);
+}
+
+sal_Int8 ViewShell::AcceptDrop (
+ const AcceptDropEvent& rEvt,
+ DropTargetHelper& rTargetHelper,
+ ::sd::Window* /*pTargetWindow*/,
+ sal_uInt16 /*nPage*/,
+ SdrLayerID nLayer)
+{
+ ::sd::View* pView = GetView();
+ return( pView ? pView->AcceptDrop( rEvt, rTargetHelper, nLayer ) : DND_ACTION_NONE );
+}
+
+sal_Int8 ViewShell::ExecuteDrop (
+ const ExecuteDropEvent& rEvt,
+ DropTargetHelper& /*rTargetHelper*/,
+ ::sd::Window* pTargetWindow,
+ sal_uInt16 nPage,
+ SdrLayerID nLayer)
+{
+ ::sd::View* pView = GetView();
+ return pView ? pView->ExecuteDrop( rEvt, pTargetWindow, nPage, nLayer ) : DND_ACTION_NONE;
+}
+
+void ViewShell::WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& rSequence )
+{
+ const sal_Int32 nIndex = rSequence.getLength();
+ rSequence.realloc( nIndex + 1 );
+ auto pSequence = rSequence.getArray();
+
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ // Get the view id from the view shell in the center pane. This will
+ // usually be the called view shell, but to be on the safe side we call
+ // the main view shell explicitly.
+ SfxInterfaceId nViewID (IMPRESS_FACTORY_ID);
+ if (GetViewShellBase().GetMainViewShell() != nullptr)
+ nViewID = GetViewShellBase().GetMainViewShell()->mpImpl->GetViewId();
+ pSequence[nIndex].Name = sUNO_View_ViewId;
+ pSequence[nIndex].Value <<= "view" + OUString::number( static_cast<sal_uInt16>(nViewID));
+
+ mpFrameView->WriteUserDataSequence( rSequence );
+}
+
+void ViewShell::ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& rSequence )
+{
+ mpFrameView->ReadUserDataSequence( rSequence );
+}
+
+void ViewShell::VisAreaChanged(const ::tools::Rectangle& /*rRect*/)
+{
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ GetViewShell()->VisAreaChanged();
+}
+
+void ViewShell::SetWinViewPos(const Point& rWinPos)
+{
+ if (mpContentWindow)
+ {
+ mpContentWindow->SetWinViewPos(rWinPos);
+
+ mpContentWindow->UpdateMapOrigin();
+ mpContentWindow->Invalidate();
+ }
+
+ if (mbHasRulers)
+ {
+ UpdateHRuler();
+ UpdateVRuler();
+ }
+
+ UpdateScrollBars();
+
+ Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel();
+ ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
+ VisAreaChanged(aVisAreaWin);
+
+ ::sd::View* pView = GetView();
+ if (pView)
+ {
+ pView->VisAreaChanged(GetActiveWindow()->GetOutDev());
+ }
+}
+
+Point const & ViewShell::GetWinViewPos() const
+{
+ return mpContentWindow->GetWinViewPos();
+}
+
+Point const & ViewShell::GetViewOrigin() const
+{
+ return mpContentWindow->GetViewOrigin();
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/viewshe3.cxx b/sd/source/ui/view/viewshe3.cxx
new file mode 100644
index 000000000..7ebf88b44
--- /dev/null
+++ b/sd/source/ui/view/viewshe3.cxx
@@ -0,0 +1,383 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <ViewShell.hxx>
+#include <ViewShellBase.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <svtools/strings.hrc>
+#include <svtools/svtresid.hxx>
+
+#include <app.hrc>
+#include <strings.hrc>
+
+#include <sal/log.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/bindings.hxx>
+#include <svx/svdundo.hxx>
+#include <svl/intitem.hxx>
+#include <svl/style.hxx>
+#include <svl/stritem.hxx>
+#include <stlsheet.hxx>
+#include <DrawViewShell.hxx>
+
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <DrawDocShell.hxx>
+#include <sdresid.hxx>
+#include <unokywds.hxx>
+
+#include <svx/svxids.hrc>
+#include <sfx2/request.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/sberrors.hxx>
+#include <xmloff/autolayout.hxx>
+
+using namespace ::com::sun::star;
+
+namespace sd {
+
+/**
+ * set state (enabled/disabled) of Menu SfxSlots
+ */
+void ViewShell::GetMenuState( SfxItemSet &rSet )
+{
+ if( SfxItemState::DEFAULT == rSet.GetItemState( SID_STYLE_FAMILY ) )
+ {
+ SfxStyleFamily const nFamily = GetDocSh()->GetStyleFamily();
+
+ SdrView* pDrView = GetDrawView();
+
+ if( pDrView->AreObjectsMarked() )
+ {
+ SfxStyleSheet* pStyleSheet = pDrView->GetStyleSheet();
+ if( pStyleSheet )
+ {
+ if (pStyleSheet->GetFamily() == SfxStyleFamily::Page)
+ pStyleSheet = static_cast<SdStyleSheet*>(pStyleSheet)->GetPseudoStyleSheet();
+
+ if( pStyleSheet )
+ {
+ GetDocSh()->SetStyleFamily(pStyleSheet->GetFamily());
+ }
+ }
+ }
+
+ rSet.Put(SfxUInt16Item(SID_STYLE_FAMILY, static_cast<sal_uInt16>(nFamily)));
+ }
+
+ if(SfxItemState::DEFAULT == rSet.GetItemState(SID_GETUNDOSTRINGS))
+ {
+ ImpGetUndoStrings(rSet);
+ }
+
+ if(SfxItemState::DEFAULT == rSet.GetItemState(SID_GETREDOSTRINGS))
+ {
+ ImpGetRedoStrings(rSet);
+ }
+
+ if(SfxItemState::DEFAULT == rSet.GetItemState(SID_UNDO))
+ {
+ SfxUndoManager* pUndoManager = ImpGetUndoManager();
+ if(pUndoManager)
+ {
+ if(pUndoManager->GetUndoActionCount() != 0)
+ {
+ // If another view created the first undo action, prevent redoing it from this view.
+ const SfxUndoAction* pAction = pUndoManager->GetUndoAction();
+ if (pAction->GetViewShellId() != GetViewShellBase().GetViewShellId())
+ {
+ rSet.Put(SfxUInt32Item(SID_UNDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE)));
+ }
+ else
+ {
+ // Set the necessary string like in
+ // sfx2/source/view/viewfrm.cxx ver 1.23 ln 1072 ff.
+ OUString aTmp = SvtResId(STR_UNDO) +
+ pUndoManager->GetUndoActionComment();
+ rSet.Put(SfxStringItem(SID_UNDO, aTmp));
+ }
+ }
+ else
+ {
+ rSet.DisableItem(SID_UNDO);
+ }
+ }
+ }
+
+ if(SfxItemState::DEFAULT != rSet.GetItemState(SID_REDO))
+ return;
+
+ SfxUndoManager* pUndoManager = ImpGetUndoManager();
+ if(!pUndoManager)
+ return;
+
+ if(pUndoManager->GetRedoActionCount() != 0)
+ {
+ // If another view created the first undo action, prevent redoing it from this view.
+ const SfxUndoAction* pAction = pUndoManager->GetRedoAction();
+ if (pAction->GetViewShellId() != GetViewShellBase().GetViewShellId())
+ {
+ rSet.Put(SfxUInt32Item(SID_REDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE)));
+ }
+ else
+ {
+ // Set the necessary string like in
+ // sfx2/source/view/viewfrm.cxx ver 1.23 ln 1081 ff.
+ OUString aTmp = SvtResId(STR_REDO) + pUndoManager->GetRedoActionComment();
+ rSet.Put(SfxStringItem(SID_REDO, aTmp));
+ }
+ }
+ else
+ {
+ rSet.DisableItem(SID_REDO);
+ }
+}
+
+/** This method consists basically of three parts:
+ 1. Process the arguments of the SFX request.
+ 2. Use the model to create a new page or duplicate an existing one.
+ 3. Update the tab control and switch to the new page.
+*/
+SdPage* ViewShell::CreateOrDuplicatePage (
+ SfxRequest& rRequest,
+ PageKind ePageKind,
+ SdPage* pPage,
+ const sal_Int32 nInsertPosition)
+{
+ sal_uInt16 nSId = rRequest.GetSlot();
+ SdDrawDocument* pDocument = GetDoc();
+ SdrLayerAdmin& rLayerAdmin = pDocument->GetLayerAdmin();
+ SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
+ SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
+ SdrLayerIDSet aVisibleLayers;
+ // Determine the page from which to copy some values, such as layers,
+ // size, master page, to the new page. This is usually the given page.
+ // When the given page is NULL then use the first page of the document.
+ SdPage* pTemplatePage = pPage;
+ if (pTemplatePage == nullptr)
+ pTemplatePage = pDocument->GetSdPage(0, ePageKind);
+ if (pTemplatePage != nullptr && pTemplatePage->TRG_HasMasterPage())
+ aVisibleLayers = pTemplatePage->TRG_GetMasterPageVisibleLayers();
+ else
+ aVisibleLayers.SetAll();
+
+ OUString aStandardPageName;
+ OUString aNotesPageName;
+ AutoLayout eStandardLayout (AUTOLAYOUT_NONE);
+ AutoLayout eNotesLayout (AUTOLAYOUT_NOTES);
+ bool bIsPageBack = aVisibleLayers.IsSet(aBckgrnd);
+ bool bIsPageObj = aVisibleLayers.IsSet(aBckgrndObj);
+
+ // 1. Process the arguments.
+ const SfxItemSet* pArgs = rRequest.GetArgs();
+ if (! pArgs)
+ {
+ // AutoLayouts must be ready
+ pDocument->StopWorkStartupDelay();
+
+ // Use the layouts of the previous page and notes page as template.
+ if (pTemplatePage != nullptr)
+ {
+ eStandardLayout = pTemplatePage->GetAutoLayout();
+ if( eStandardLayout == AUTOLAYOUT_TITLE )
+ eStandardLayout = AUTOLAYOUT_TITLE_CONTENT;
+
+ SdPage* pNotesTemplatePage = static_cast<SdPage*>(pDocument->GetPage(pTemplatePage->GetPageNum()+1));
+ if (pNotesTemplatePage != nullptr)
+ eNotesLayout = pNotesTemplatePage->GetAutoLayout();
+ }
+ }
+ else if (pArgs->Count() == 1)
+ {
+ pDocument->StopWorkStartupDelay();
+ const SfxUInt32Item* pLayout = rRequest.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYOUT);
+ if( pLayout )
+ {
+ if (ePageKind == PageKind::Notes)
+ {
+ eNotesLayout = static_cast<AutoLayout>(pLayout->GetValue ());
+ }
+ else
+ {
+ eStandardLayout = static_cast<AutoLayout>(pLayout->GetValue ());
+ }
+ }
+ }
+ else if (pArgs->Count() == 4)
+ {
+ // AutoLayouts must be ready
+ pDocument->StopWorkStartupDelay();
+
+ const SfxStringItem* pPageName = rRequest.GetArg<SfxStringItem>(ID_VAL_PAGENAME);
+ const SfxUInt32Item* pLayout = rRequest.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYOUT);
+ const SfxBoolItem* pIsPageBack = rRequest.GetArg<SfxBoolItem>(ID_VAL_ISPAGEBACK);
+ const SfxBoolItem* pIsPageObj = rRequest.GetArg<SfxBoolItem>(ID_VAL_ISPAGEOBJ);
+
+ if (CHECK_RANGE (AUTOLAYOUT_START, static_cast<AutoLayout>(pLayout->GetValue ()), AUTOLAYOUT_END))
+ {
+ if (ePageKind == PageKind::Notes)
+ {
+ aNotesPageName = pPageName->GetValue ();
+ eNotesLayout = static_cast<AutoLayout>(pLayout->GetValue ());
+ }
+ else
+ {
+ aStandardPageName = pPageName->GetValue ();
+ eStandardLayout = static_cast<AutoLayout>(pLayout->GetValue ());
+ }
+
+ bIsPageBack = pIsPageBack->GetValue ();
+ bIsPageObj = pIsPageObj->GetValue ();
+ }
+ else
+ {
+ Cancel();
+
+ if(HasCurrentFunction( SID_BEZIER_EDIT ) )
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE);
+#endif
+ rRequest.Ignore ();
+ return nullptr;
+ }
+ }
+ else
+ {
+ Cancel();
+
+ if(HasCurrentFunction(SID_BEZIER_EDIT) )
+ GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON);
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS);
+#endif
+ rRequest.Ignore ();
+ return nullptr;
+ }
+
+ // 2. Create a new page or duplicate an existing one.
+ View* pDrView = GetView();
+ const bool bUndo = pDrView && pDrView->IsUndoEnabled();
+ if( bUndo && GetDoc()->GetDocumentType() == DocumentType::Draw)
+ pDrView->BegUndo(SdResId(STR_INSERT_PAGE_DRAW));
+ else if (bUndo)
+ pDrView->BegUndo(SdResId(STR_INSERTPAGE));
+
+
+
+ sal_uInt16 nNewPageIndex = 0xffff;
+ switch (nSId)
+ {
+ case SID_INSERTPAGE:
+ case SID_INSERTPAGE_QUICK:
+ case SID_INSERT_MASTER_PAGE:
+ // There are three cases. a) pPage is not NULL: we use it as a
+ // template and create a new slide behind it. b) pPage is NULL
+ // but the document is not empty: we use the first slide/notes
+ // page as template, create a new slide after it and move it
+ // then to the head of the document. c) pPage is NULL and the
+ // document is empty: We use CreateFirstPages to create the
+ // first page of the document.
+ if (pPage == nullptr)
+ if (pTemplatePage == nullptr)
+ {
+ pDocument->CreateFirstPages();
+ nNewPageIndex = 0;
+ }
+ else
+ {
+ // Create a new page with the first page as template and
+ // insert it after the first page.
+ nNewPageIndex = pDocument->CreatePage (
+ pTemplatePage,
+ ePageKind,
+ aStandardPageName,
+ aNotesPageName,
+ eStandardLayout,
+ eNotesLayout,
+ bIsPageBack,
+ bIsPageObj,
+ nInsertPosition);
+ // Select exactly the new page.
+ sal_uInt16 nPageCount (pDocument->GetSdPageCount(ePageKind));
+ for (sal_uInt16 i=0; i<nPageCount; i++)
+ {
+ pDocument->GetSdPage(i, PageKind::Standard)->SetSelected(
+ i == nNewPageIndex);
+ pDocument->GetSdPage(i, PageKind::Notes)->SetSelected(
+ i == nNewPageIndex);
+ }
+ // Move the selected page to the head of the document
+ pDocument->MovePages (sal_uInt16(-1));
+ nNewPageIndex = 0;
+ }
+ else
+ nNewPageIndex = pDocument->CreatePage (
+ pPage,
+ ePageKind,
+ aStandardPageName,
+ aNotesPageName,
+ eStandardLayout,
+ eNotesLayout,
+ bIsPageBack,
+ bIsPageObj,
+ nInsertPosition);
+ break;
+
+ case SID_DUPLICATE_PAGE:
+ // Duplication makes no sense when pPage is NULL.
+ if (pPage != nullptr)
+ nNewPageIndex = pDocument->DuplicatePage (
+ pPage,
+ ePageKind,
+ aStandardPageName,
+ aNotesPageName,
+ bIsPageBack,
+ bIsPageObj,
+ nInsertPosition);
+ break;
+
+ default:
+ SAL_INFO("sd", "wrong slot id given to CreateOrDuplicatePage");
+ // Try to handle another slot id gracefully.
+ }
+ SdPage* pNewPage = nullptr;
+ if(nNewPageIndex != 0xffff)
+ pNewPage = pDocument->GetSdPage(nNewPageIndex, PageKind::Standard);
+
+ if( bUndo )
+ {
+ if( pNewPage )
+ {
+ pDrView->AddUndo(pDocument->GetSdrUndoFactory().CreateUndoNewPage(*pNewPage));
+ pDrView->AddUndo(pDocument->GetSdrUndoFactory().CreateUndoNewPage(*pDocument->GetSdPage (nNewPageIndex, PageKind::Notes)));
+ }
+
+ pDrView->EndUndo();
+ }
+
+ return pNewPage;
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/viewshel.cxx b/sd/source/ui/view/viewshel.cxx
new file mode 100644
index 000000000..866b79461
--- /dev/null
+++ b/sd/source/ui/view/viewshel.cxx
@@ -0,0 +1,1634 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <ViewShell.hxx>
+#include <ViewShellImplementation.hxx>
+#include <createtableobjectbar.hxx>
+
+#include <ViewShellBase.hxx>
+#include <ShellFactory.hxx>
+#include <DrawController.hxx>
+#include <LayerTabBar.hxx>
+
+#include <sal/log.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/scrbar.hxx>
+#include <svl/eitem.hxx>
+#include <svx/ruler.hxx>
+#include <svx/svxids.hrc>
+#include <svx/fmshell.hxx>
+#include <WindowUpdater.hxx>
+#include <sdxfer.hxx>
+
+#include <app.hrc>
+
+#include <OutlineView.hxx>
+#include <DrawViewShell.hxx>
+#include <DrawDocShell.hxx>
+#include <slideshow.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <zoomlist.hxx>
+#include <FrameView.hxx>
+#include <BezierObjectBar.hxx>
+#include <TextObjectBar.hxx>
+#include <GraphicObjectBar.hxx>
+#include <MediaObjectBar.hxx>
+#include <SlideSorter.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <ViewShellManager.hxx>
+#include <FormShellManager.hxx>
+#include <svx/extrusionbar.hxx>
+#include <svx/fontworkbar.hxx>
+#include <svx/svdoutl.hxx>
+#include <tools/svborder.hxx>
+#include <comphelper/lok.hxx>
+
+#include <svl/slstitm.hxx>
+#include <sfx2/request.hxx>
+#include <SpellDialogChildWindow.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlsSelectionObserver.hxx>
+#include <view/SlideSorterView.hxx>
+
+#include <basegfx/utils/zoomtools.hxx>
+
+#include <Window.hxx>
+#include <fupoor.hxx>
+#include <futext.hxx>
+
+#include <editeng/numitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editeng.hxx>
+#include <svl/itempool.hxx>
+#include <svl/intitem.hxx>
+#include <svl/poolitem.hxx>
+#include <strings.hxx>
+#include <sdmod.hxx>
+#include <AccessibleDocumentViewBase.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::presentation;
+
+namespace {
+
+class ViewShellObjectBarFactory
+ : public ::sd::ShellFactory<SfxShell>
+{
+public:
+ explicit ViewShellObjectBarFactory (::sd::ViewShell& rViewShell);
+ virtual SfxShell* CreateShell( ::sd::ShellId nId ) override;
+ virtual void ReleaseShell (SfxShell* pShell) override;
+private:
+ ::sd::ViewShell& mrViewShell;
+};
+
+} // end of anonymous namespace
+
+namespace sd {
+
+bool ViewShell::IsPageFlipMode() const
+{
+ return dynamic_cast< const DrawViewShell *>( this ) != nullptr && mpContentWindow &&
+ mpContentWindow->GetVisibleHeight() >= 1.0;
+}
+
+SfxViewFrame* ViewShell::GetViewFrame() const
+{
+ const SfxViewShell* pViewShell = GetViewShell();
+ if (pViewShell != nullptr)
+ {
+ return pViewShell->GetViewFrame();
+ }
+ else
+ {
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ return nullptr;
+ }
+}
+
+/// declare SFX-Slotmap and standard interface
+
+ViewShell::ViewShell( vcl::Window* pParentWindow, ViewShellBase& rViewShellBase)
+: SfxShell(&rViewShellBase)
+, mpParentWindow(pParentWindow)
+{
+ construct();
+}
+
+ViewShell::~ViewShell()
+{
+ // Keep the content window from accessing in its destructor the
+ // WindowUpdater.
+ if (mpContentWindow)
+ mpContentWindow->SetViewShell(nullptr);
+
+ mpZoomList.reset();
+
+ mpLayerTabBar.disposeAndClear();
+
+ if (mpImpl->mpSubShellFactory)
+ GetViewShellBase().GetViewShellManager()->RemoveSubShellFactory(
+ this,mpImpl->mpSubShellFactory);
+
+ if (mpContentWindow)
+ {
+ SAL_INFO(
+ "sd.view",
+ "destroying mpContentWindow at " << mpContentWindow.get()
+ << " with parent " << mpContentWindow->GetParent());
+ mpContentWindow.disposeAndClear();
+ }
+
+ mpScrollBarBox.disposeAndClear();
+ mpVerticalRuler.disposeAndClear();
+ mpHorizontalRuler.disposeAndClear();
+ mpVerticalScrollBar.disposeAndClear();
+ mpHorizontalScrollBar.disposeAndClear();
+}
+
+/**
+ * common initialization part of both constructors
+ */
+void ViewShell::construct()
+{
+ mbHasRulers = false;
+ mpActiveWindow = nullptr;
+ mpView = nullptr;
+ mpFrameView = nullptr;
+ mpZoomList = nullptr;
+ mbStartShowWithDialog = false;
+ mnPrintedHandoutPageNum = 1;
+ mnPrintedHandoutPageCount = 0;
+ mpWindowUpdater.reset( new ::sd::WindowUpdater() );
+ mpImpl.reset(new Implementation(*this));
+ meShellType = ST_NONE;
+
+ OSL_ASSERT (GetViewShell()!=nullptr);
+
+ if (IsMainViewShell())
+ GetDocSh()->Connect (this);
+
+ mpZoomList.reset( new ZoomList( this ) );
+
+ mpContentWindow.reset(VclPtr< ::sd::Window >::Create(GetParentWindow()));
+ SetActiveWindow (mpContentWindow.get());
+
+ GetParentWindow()->SetBackground (Wallpaper());
+ mpContentWindow->SetBackground (Wallpaper());
+ mpContentWindow->SetCenterAllowed(true);
+ mpContentWindow->SetViewShell(this);
+ mpContentWindow->SetPosSizePixel(
+ GetParentWindow()->GetPosPixel(),GetParentWindow()->GetSizePixel());
+
+ if ( ! GetDocSh()->IsPreview())
+ {
+ // Create scroll bars and the filler between the scroll bars.
+ mpHorizontalScrollBar.reset (VclPtr<ScrollBar>::Create(GetParentWindow(), WinBits(WB_HSCROLL | WB_DRAG)));
+ mpHorizontalScrollBar->EnableRTL (false);
+ mpHorizontalScrollBar->SetRange(Range(0, 32000));
+ mpHorizontalScrollBar->SetScrollHdl(LINK(this, ViewShell, HScrollHdl));
+
+ mpVerticalScrollBar.reset (VclPtr<ScrollBar>::Create(GetParentWindow(), WinBits(WB_VSCROLL | WB_DRAG)));
+ mpVerticalScrollBar->SetRange(Range(0, 32000));
+ mpVerticalScrollBar->SetScrollHdl(LINK(this, ViewShell, VScrollHdl));
+
+ mpScrollBarBox.reset(VclPtr<ScrollBarBox>::Create(GetParentWindow(), WB_SIZEABLE));
+ }
+
+ SetName ("ViewShell");
+
+ GetDoc()->StartOnlineSpelling(false);
+
+ mpWindowUpdater->SetDocument (GetDoc());
+
+ // Re-initialize the spell dialog.
+ ::sd::SpellDialogChildWindow* pSpellDialog =
+ static_cast< ::sd::SpellDialogChildWindow*> (
+ GetViewFrame()->GetChildWindow (
+ ::sd::SpellDialogChildWindow::GetChildWindowId()));
+ if (pSpellDialog != nullptr)
+ pSpellDialog->InvalidateSpellDialog();
+
+ // Register the sub shell factory.
+ mpImpl->mpSubShellFactory = std::make_shared<ViewShellObjectBarFactory>(*this);
+ GetViewShellBase().GetViewShellManager()->AddSubShellFactory(this,mpImpl->mpSubShellFactory);
+}
+
+void ViewShell::doShow()
+{
+ mpContentWindow->Show();
+ static_cast< vcl::Window*>(mpContentWindow.get())->Resize();
+ SAL_INFO(
+ "sd.view",
+ "content window has size " << mpContentWindow->GetSizePixel().Width()
+ << " " << mpContentWindow->GetSizePixel().Height());
+
+ if ( ! GetDocSh()->IsPreview())
+ {
+ // Show scroll bars
+ mpHorizontalScrollBar->Show();
+
+ mpVerticalScrollBar->Show();
+ maScrBarWH = Size(
+ mpVerticalScrollBar->GetSizePixel().Width(),
+ mpHorizontalScrollBar->GetSizePixel().Height());
+
+ mpScrollBarBox->Show();
+ }
+
+ GetParentWindow()->Show();
+}
+
+void ViewShell::Init (bool bIsMainViewShell)
+{
+ mpImpl->mbIsInitialized = true;
+ SetIsMainViewShell(bIsMainViewShell);
+ if (bIsMainViewShell)
+ SetActiveWindow (mpContentWindow.get());
+}
+
+void ViewShell::Exit()
+{
+ sd::View* pView = GetView();
+ if (pView!=nullptr && pView->IsTextEdit())
+ {
+ pView->SdrEndTextEdit();
+ pView->UnmarkAll();
+ }
+
+ Deactivate (true);
+
+ if (IsMainViewShell())
+ GetDocSh()->Disconnect(this);
+
+ SetIsMainViewShell(false);
+}
+
+/**
+ * set focus to working window
+ */
+void ViewShell::Activate(bool bIsMDIActivate)
+{
+ // Do not forward to SfxShell::Activate()
+
+ /* According to MI, nobody is allowed to call GrabFocus, who does not
+ exactly know from which window the focus is grabbed. Since Activate()
+ is sent sometimes asynchronous, it can happen, that the wrong window
+ gets the focus. */
+
+ if (mpHorizontalRuler)
+ mpHorizontalRuler->SetActive();
+ if (mpVerticalRuler)
+ mpVerticalRuler->SetActive();
+
+ if (bIsMDIActivate)
+ {
+ // thus, the Navigator will also get a current status
+ SfxBoolItem aItem( SID_NAVIGATOR_INIT, true );
+ if (GetDispatcher() != nullptr)
+ GetDispatcher()->ExecuteList(
+ SID_NAVIGATOR_INIT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aItem });
+
+ SfxViewShell* pViewShell = GetViewShell();
+ OSL_ASSERT (pViewShell!=nullptr);
+ SfxBindings& rBindings = pViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_3D_STATE, true );
+
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if (xSlideShow.is() && xSlideShow->isRunning())
+ {
+ bool bSuccess = xSlideShow->activate(GetViewShellBase());
+ assert(bSuccess && "can only return false with a PresentationViewShell"); (void)bSuccess;
+ }
+
+ if(HasCurrentFunction())
+ GetCurrentFunction()->Activate();
+
+ if(!GetDocSh()->IsUIActive())
+ UpdatePreview( GetActualPage() );
+ }
+
+ ReadFrameViewData( mpFrameView );
+
+ if (IsMainViewShell())
+ GetDocSh()->Connect(this);
+}
+
+void ViewShell::UIActivating( SfxInPlaceClient* )
+{
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ GetViewShellBase().GetToolBarManager()->ToolBarsDestroyed();
+}
+
+void ViewShell::UIDeactivated( SfxInPlaceClient* )
+{
+ OSL_ASSERT (GetViewShell()!=nullptr);
+ GetViewShellBase().GetToolBarManager()->ToolBarsDestroyed();
+ if ( GetDrawView() )
+ GetViewShellBase().GetToolBarManager()->SelectionHasChanged(*this, *GetDrawView());
+}
+
+void ViewShell::Deactivate(bool bIsMDIActivate)
+{
+ // remove view from a still active drag'n'drop session
+ SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
+
+ if (IsMainViewShell())
+ GetDocSh()->Disconnect(this);
+
+ if( pDragTransferable )
+ pDragTransferable->SetView( nullptr );
+
+ OSL_ASSERT (GetViewShell()!=nullptr);
+
+ // remember view attributes of FrameView
+ WriteFrameViewData();
+
+ if (bIsMDIActivate)
+ {
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if(xSlideShow.is() && xSlideShow->isRunning() )
+ xSlideShow->deactivate();
+
+ if(HasCurrentFunction())
+ GetCurrentFunction()->Deactivate();
+ }
+
+ if (mpHorizontalRuler)
+ mpHorizontalRuler->SetActive(false);
+ if (mpVerticalRuler)
+ mpVerticalRuler->SetActive(false);
+
+ SfxShell::Deactivate(bIsMDIActivate);
+}
+
+void ViewShell::Shutdown()
+{
+ Exit ();
+}
+
+bool ViewShell::KeyInput(const KeyEvent& rKEvt, ::sd::Window* pWin)
+{
+ bool bReturn(false);
+
+ if(pWin)
+ SetActiveWindow(pWin);
+
+ // give key input first to SfxViewShell to give CTRL+Key
+ // (e.g. CTRL+SHIFT+'+', to front) priority.
+ OSL_ASSERT(GetViewShell() != nullptr);
+ bReturn = GetViewShell()->KeyInput(rKEvt);
+
+ const size_t OriCount = GetView()->GetMarkedObjectList().GetMarkCount();
+ if(!bReturn)
+ {
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if(xSlideShow.is() && xSlideShow->isRunning())
+ {
+ bReturn = xSlideShow->keyInput(rKEvt);
+ }
+ else
+ {
+ bool bConsumed = false;
+ if( GetView() )
+ bConsumed = GetView()->getSmartTags().KeyInput(rKEvt);
+
+ if( !bConsumed )
+ {
+ rtl::Reference< sdr::SelectionController > xSelectionController( GetView()->getSelectionController() );
+ if( !xSelectionController.is() || !xSelectionController->onKeyInput( rKEvt, pWin ) )
+ {
+ if(HasCurrentFunction())
+ bReturn = GetCurrentFunction()->KeyInput(rKEvt);
+ }
+ else
+ {
+ bReturn = true;
+ if (HasCurrentFunction())
+ {
+ FuText* pTextFunction = dynamic_cast<FuText*>(GetCurrentFunction().get());
+ if(pTextFunction != nullptr)
+ pTextFunction->InvalidateBindings();
+ }
+ }
+ }
+ }
+ }
+ const size_t EndCount = GetView()->GetMarkedObjectList().GetMarkCount();
+ // Here, oriCount or endCount must have one value=0, another value > 0, then to switch focus between Document and shape objects
+ if(bReturn && (OriCount + EndCount > 0) && (OriCount * EndCount == 0))
+ SwitchActiveViewFireFocus();
+
+ if(!bReturn && GetActiveWindow())
+ {
+ vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ if (aKeyCode.IsMod1() && aKeyCode.IsShift()
+ && aKeyCode.GetCode() == KEY_R)
+ {
+ InvalidateWindows();
+ bReturn = true;
+ }
+ }
+
+ return bReturn;
+}
+
+void ViewShell::MouseButtonDown(const MouseEvent& rMEvt, ::sd::Window* pWin)
+{
+ // We have to lock tool bar updates while the mouse button is pressed in
+ // order to prevent the shape under the mouse to be moved (this happens
+ // when the number of docked tool bars changes as result of a changed
+ // selection; this changes the window size and thus the mouse position
+ // in model coordinates: with respect to model coordinates the mouse
+ // moves.)
+ OSL_ASSERT(mpImpl->mpUpdateLockForMouse.expired());
+ mpImpl->mpUpdateLockForMouse = ViewShell::Implementation::ToolBarManagerLock::Create(
+ GetViewShellBase().GetToolBarManager());
+
+ if ( pWin && !pWin->HasFocus() )
+ {
+ pWin->GrabFocus();
+ SetActiveWindow(pWin);
+ }
+
+ // insert MouseEvent into E3dView
+ if (GetView() != nullptr)
+ GetView()->SetMouseEvent(rMEvt);
+
+ bool bConsumed = false;
+ if( GetView() )
+ bConsumed = GetView()->getSmartTags().MouseButtonDown( rMEvt );
+
+ if( bConsumed )
+ return;
+
+ rtl::Reference< sdr::SelectionController > xSelectionController( GetView()->getSelectionController() );
+ if( !xSelectionController.is() || !xSelectionController->onMouseButtonDown( rMEvt, pWin ) )
+ {
+ if(HasCurrentFunction())
+ GetCurrentFunction()->MouseButtonDown(rMEvt);
+ }
+ else
+ {
+ if (HasCurrentFunction())
+ {
+ FuText* pTextFunction = dynamic_cast<FuText*>(GetCurrentFunction().get());
+ if (pTextFunction != nullptr)
+ pTextFunction->InvalidateBindings();
+ }
+ }
+}
+
+void ViewShell::SetCursorMm100Position(const Point& rPosition, bool bPoint, bool bClearMark)
+{
+ if (SdrView* pSdrView = GetView())
+ {
+ rtl::Reference<sdr::SelectionController> xSelectionController(GetView()->getSelectionController());
+ if (!xSelectionController.is() || !xSelectionController->setCursorLogicPosition(rPosition, bPoint))
+ {
+ if (pSdrView->GetTextEditObject())
+ {
+ EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView();
+ rEditView.SetCursorLogicPosition(rPosition, bPoint, bClearMark);
+ }
+ }
+ }
+}
+
+uno::Reference<datatransfer::XTransferable> ViewShell::GetSelectionTransferrable() const
+{
+ SdrView* pSdrView = GetView();
+ if (!pSdrView)
+ return uno::Reference<datatransfer::XTransferable>();
+
+ if (!pSdrView->GetTextEditObject())
+ return uno::Reference<datatransfer::XTransferable>();
+
+ EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView();
+ return rEditView.GetEditEngine()->CreateTransferable(rEditView.GetSelection());
+}
+
+void ViewShell::SetGraphicMm100Position(bool bStart, const Point& rPosition)
+{
+ if (bStart)
+ {
+ MouseEvent aClickEvent(rPosition, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
+ MouseButtonDown(aClickEvent, mpActiveWindow);
+ MouseEvent aMoveEvent(Point(rPosition.getX(), rPosition.getY()), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
+ MouseMove(aMoveEvent, mpActiveWindow);
+ }
+ else
+ {
+ MouseEvent aMoveEvent(Point(rPosition.getX(), rPosition.getY()), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
+ MouseMove(aMoveEvent, mpActiveWindow);
+ MouseEvent aClickEvent(rPosition, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
+ MouseButtonUp(aClickEvent, mpActiveWindow);
+ }
+}
+
+void ViewShell::MouseMove(const MouseEvent& rMEvt, ::sd::Window* pWin)
+{
+ if (rMEvt.IsLeaveWindow())
+ {
+ if ( ! mpImpl->mpUpdateLockForMouse.expired())
+ {
+ std::shared_ptr<ViewShell::Implementation::ToolBarManagerLock> pLock(
+ mpImpl->mpUpdateLockForMouse);
+ if (pLock != nullptr)
+ pLock->Release();
+ }
+ }
+
+ if ( pWin )
+ {
+ SetActiveWindow(pWin);
+ }
+
+ // insert MouseEvent into E3dView
+ if (GetView() != nullptr)
+ GetView()->SetMouseEvent(rMEvt);
+
+ if(HasCurrentFunction())
+ {
+ rtl::Reference< sdr::SelectionController > xSelectionController( GetView()->getSelectionController() );
+ if( !xSelectionController.is() || !xSelectionController->onMouseMove( rMEvt, pWin ) )
+ {
+ if(HasCurrentFunction())
+ GetCurrentFunction()->MouseMove(rMEvt);
+ }
+ }
+}
+
+void ViewShell::MouseButtonUp(const MouseEvent& rMEvt, ::sd::Window* pWin)
+{
+ if ( pWin )
+ SetActiveWindow(pWin);
+
+ // insert MouseEvent into E3dView
+ if (GetView() != nullptr)
+ GetView()->SetMouseEvent(rMEvt);
+
+ if( HasCurrentFunction())
+ {
+ rtl::Reference< sdr::SelectionController > xSelectionController( GetView()->getSelectionController() );
+ if( !xSelectionController.is() || !xSelectionController->onMouseButtonUp( rMEvt, pWin ) )
+ {
+ if(HasCurrentFunction())
+ GetCurrentFunction()->MouseButtonUp(rMEvt);
+ }
+ else
+ {
+ if (HasCurrentFunction())
+ {
+ FuText* pTextFunction = dynamic_cast<FuText*>(GetCurrentFunction().get());
+ if (pTextFunction != nullptr)
+ pTextFunction->InvalidateBindings();
+ }
+ }
+ }
+
+ if ( ! mpImpl->mpUpdateLockForMouse.expired())
+ {
+ std::shared_ptr<ViewShell::Implementation::ToolBarManagerLock> pLock(
+ mpImpl->mpUpdateLockForMouse);
+ if (pLock != nullptr)
+ pLock->Release();
+ }
+}
+
+void ViewShell::Command(const CommandEvent& rCEvt, ::sd::Window* pWin)
+{
+ bool bDone = HandleScrollCommand (rCEvt, pWin);
+
+ if( bDone )
+ return;
+
+ if( rCEvt.GetCommand() == CommandEventId::InputLanguageChange )
+ {
+ //#i42732# update state of fontname if input language changes
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_CHAR_FONT );
+ GetViewFrame()->GetBindings().Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ }
+ else
+ {
+ bool bConsumed = false;
+ if( GetView() )
+ bConsumed = GetView()->getSmartTags().Command(rCEvt);
+
+ if( !bConsumed && HasCurrentFunction())
+ GetCurrentFunction()->Command(rCEvt);
+ }
+}
+
+bool ViewShell::Notify(NotifyEvent const & rNEvt, ::sd::Window* pWin)
+{
+ // handle scroll commands when they arrived at child windows
+ bool bRet = false;
+ if( rNEvt.GetType() == MouseNotifyEvent::COMMAND )
+ {
+ // note: dynamic_cast is not possible as GetData() returns a void*
+ CommandEvent* pCmdEvent = static_cast< CommandEvent* >(rNEvt.GetData());
+ bRet = HandleScrollCommand(*pCmdEvent, pWin);
+ }
+ return bRet;
+}
+
+bool ViewShell::HandleScrollCommand(const CommandEvent& rCEvt, ::sd::Window* pWin)
+{
+ bool bDone = false;
+
+ switch( rCEvt.GetCommand() )
+ {
+ case CommandEventId::Swipe:
+ {
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if (xSlideShow.is())
+ {
+ const CommandSwipeData* pSwipeData = rCEvt.GetSwipeData();
+ bDone = xSlideShow->swipe(*pSwipeData);
+ }
+ }
+ break;
+ case CommandEventId::LongPress:
+ {
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+ if (xSlideShow.is())
+ {
+ const CommandLongPressData* pLongPressData = rCEvt.GetLongPressData();
+ bDone = xSlideShow->longpress(*pLongPressData);
+ }
+ }
+ break;
+
+ case CommandEventId::Wheel:
+ {
+ Reference< XSlideShowController > xSlideShowController( SlideShow::GetSlideShowController(GetViewShellBase() ) );
+ if( xSlideShowController.is() )
+ {
+ // We ignore zooming with control+mouse wheel.
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if( pData && !pData->GetModifier() && ( pData->GetMode() == CommandWheelMode::SCROLL ) && !pData->IsHorz() )
+ {
+ ::tools::Long nDelta = pData->GetDelta();
+ if( nDelta > 0 )
+ xSlideShowController->gotoPreviousSlide();
+ else if( nDelta < 0 )
+ xSlideShowController->gotoNextEffect();
+ }
+ break;
+ }
+ }
+ [[fallthrough]];
+ case CommandEventId::StartAutoScroll:
+ case CommandEventId::AutoScroll:
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+
+ if (pData != nullptr)
+ {
+ if (pData->IsMod1())
+ {
+ if( !GetDocSh()->IsUIActive() )
+ {
+ const ::tools::Long nOldZoom = GetActiveWindow()->GetZoom();
+ ::tools::Long nNewZoom;
+ Point aOldMousePos = GetActiveWindow()->PixelToLogic(rCEvt.GetMousePosPixel());
+
+ if( pData->GetDelta() < 0 )
+ nNewZoom = std::max<::tools::Long>( pWin->GetMinZoom(), basegfx::zoomtools::zoomOut( nOldZoom ));
+ else
+ nNewZoom = std::min<::tools::Long>( pWin->GetMaxZoom(), basegfx::zoomtools::zoomIn( nOldZoom ));
+
+ SetZoom( nNewZoom );
+ // Keep mouse at same doc point before zoom
+ Point aNewMousePos = GetActiveWindow()->PixelToLogic(rCEvt.GetMousePosPixel());
+ SetWinViewPos(GetWinViewPos() - (aNewMousePos - aOldMousePos));
+
+ Invalidate( SID_ATTR_ZOOM );
+ Invalidate( SID_ATTR_ZOOMSLIDER );
+
+ bDone = true;
+ }
+ }
+ else
+ {
+ if( mpContentWindow.get() == pWin )
+ {
+ sal_uLong nScrollLines = pData->GetScrollLines();
+ if(IsPageFlipMode())
+ nScrollLines = COMMAND_WHEEL_PAGESCROLL;
+ CommandWheelData aWheelData( pData->GetDelta(),pData->GetNotchDelta(),
+ nScrollLines,pData->GetMode(),pData->GetModifier(),pData->IsHorz() );
+ CommandEvent aReWrite( rCEvt.GetMousePosPixel(),rCEvt.GetCommand(),
+ rCEvt.IsMouseEvent(),static_cast<const void *>(&aWheelData) );
+ bDone = pWin->HandleScrollCommand( aReWrite,
+ mpHorizontalScrollBar.get(),
+ mpVerticalScrollBar.get());
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return bDone;
+}
+
+void ViewShell::SetupRulers()
+{
+ if(!mbHasRulers || !mpContentWindow || SlideShow::IsRunning(GetViewShellBase()))
+ return;
+
+ ::tools::Long nHRulerOfs = 0;
+
+ if ( !mpVerticalRuler )
+ {
+ mpVerticalRuler.reset(CreateVRuler(GetActiveWindow()));
+ if ( mpVerticalRuler )
+ {
+ nHRulerOfs = mpVerticalRuler->GetSizePixel().Width();
+ mpVerticalRuler->SetActive();
+ mpVerticalRuler->Show();
+ }
+ }
+ if ( !mpHorizontalRuler )
+ {
+ mpHorizontalRuler.reset(CreateHRuler(GetActiveWindow()));
+ if ( mpHorizontalRuler )
+ {
+ mpHorizontalRuler->SetWinPos(nHRulerOfs);
+ mpHorizontalRuler->SetActive();
+ mpHorizontalRuler->Show();
+ }
+ }
+}
+
+const SvxNumBulletItem* ViewShell::GetNumBulletItem(SfxItemSet& aNewAttr, TypedWhichId<SvxNumBulletItem>& nNumItemId)
+{
+ const SvxNumBulletItem* pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false);
+ if(pTmpItem)
+ return pTmpItem;
+
+ nNumItemId = aNewAttr.GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE);
+ pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false);
+ if(pTmpItem)
+ return pTmpItem;
+
+ bool bOutliner = false;
+ bool bTitle = false;
+
+ if( mpView )
+ {
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ for(size_t nNum = 0; nNum < nCount; ++nNum)
+ {
+ SdrObject* pObj = rMarkList.GetMark(nNum)->GetMarkedSdrObj();
+ if( pObj->GetObjInventor() == SdrInventor::Default )
+ {
+ switch(pObj->GetObjIdentifier())
+ {
+ case SdrObjKind::TitleText:
+ bTitle = true;
+ break;
+ case SdrObjKind::OutlineText:
+ bOutliner = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ const SvxNumBulletItem *pItem = nullptr;
+ if(bOutliner)
+ {
+ SfxStyleSheetBasePool* pSSPool = mpView->GetDocSh()->GetStyleSheetPool();
+ SfxStyleSheetBase* pFirstStyleSheet = pSSPool->Find( STR_LAYOUT_OUTLINE + " 1", SfxStyleFamily::Pseudo);
+ if( pFirstStyleSheet )
+ pItem = pFirstStyleSheet->GetItemSet().GetItemIfSet(EE_PARA_NUMBULLET, false);
+ }
+
+ if( pItem == nullptr )
+ pItem = aNewAttr.GetPool()->GetSecondaryPool()->GetPoolDefaultItem(EE_PARA_NUMBULLET);
+
+ aNewAttr.Put(pItem->CloneSetWhich(EE_PARA_NUMBULLET));
+
+ if(bTitle && aNewAttr.GetItemState(EE_PARA_NUMBULLET) == SfxItemState::SET )
+ {
+ const SvxNumBulletItem* pBulletItem = aNewAttr.GetItem(EE_PARA_NUMBULLET);
+ const SvxNumRule& rRule = pBulletItem->GetNumRule();
+ SvxNumRule aNewRule( rRule );
+ aNewRule.SetFeatureFlag( SvxNumRuleFlags::NO_NUMBERS );
+
+ SvxNumBulletItem aNewItem( std::move(aNewRule), EE_PARA_NUMBULLET );
+ aNewAttr.Put(aNewItem);
+ }
+
+ pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false);
+
+ return pTmpItem;
+}
+
+void ViewShell::Resize()
+{
+ SetupRulers ();
+
+ if (mpParentWindow == nullptr)
+ return;
+
+ // Make sure that the new size is not degenerate.
+ const Size aSize (mpParentWindow->GetSizePixel());
+ if (aSize.IsEmpty())
+ return;
+
+ // Remember the new position and size.
+ maViewPos = Point(0,0);
+ maViewSize = aSize;
+
+ // Rearrange the UI elements to take care of the new position and size.
+ ArrangeGUIElements ();
+ // end of included AdjustPosSizePixel.
+
+ ::sd::View* pView = GetView();
+
+ if (pView)
+ pView->VisAreaChanged(GetActiveWindow()->GetOutDev());
+}
+
+SvBorder ViewShell::GetBorder()
+{
+ SvBorder aBorder;
+
+ // Horizontal scrollbar.
+ if (mpHorizontalScrollBar
+ && mpHorizontalScrollBar->IsVisible())
+ {
+ aBorder.Bottom() = maScrBarWH.Height();
+ }
+
+ // Vertical scrollbar.
+ if (mpVerticalScrollBar
+ && mpVerticalScrollBar->IsVisible())
+ {
+ aBorder.Right() = maScrBarWH.Width();
+ }
+
+ // Place horizontal ruler below tab bar.
+ if (mbHasRulers && mpContentWindow)
+ {
+ SetupRulers();
+ if (mpHorizontalRuler)
+ aBorder.Top() = mpHorizontalRuler->GetSizePixel().Height();
+ if (mpVerticalRuler)
+ aBorder.Left() = mpVerticalRuler->GetSizePixel().Width();
+ }
+
+ return aBorder;
+}
+
+void ViewShell::ArrangeGUIElements()
+{
+ if (mpImpl->mbArrangeActive)
+ return;
+ if (maViewSize.IsEmpty())
+ return;
+ mpImpl->mbArrangeActive = true;
+
+ // Calculate border for in-place editing.
+ ::tools::Long nLeft = maViewPos.X();
+ ::tools::Long nTop = maViewPos.Y();
+ ::tools::Long nRight = maViewPos.X() + maViewSize.Width();
+ ::tools::Long nBottom = maViewPos.Y() + maViewSize.Height();
+
+ // Horizontal scrollbar.
+ if (mpHorizontalScrollBar
+ && mpHorizontalScrollBar->IsVisible())
+ {
+ nBottom -= maScrBarWH.Height();
+ if (mpLayerTabBar && mpLayerTabBar->IsVisible())
+ nBottom -= mpLayerTabBar->GetSizePixel().Height();
+ mpHorizontalScrollBar->SetPosSizePixel (
+ Point(nLeft, nBottom),
+ Size(nRight - nLeft - maScrBarWH.Width(), maScrBarWH.Height()));
+ }
+
+ // Vertical scrollbar.
+ if (mpVerticalScrollBar
+ && mpVerticalScrollBar->IsVisible())
+ {
+ nRight -= maScrBarWH.Width();
+ mpVerticalScrollBar->SetPosSizePixel (
+ Point(nRight,nTop),
+ Size (maScrBarWH.Width(), nBottom-nTop));
+ }
+
+ // Filler in the lower right corner.
+ if (mpScrollBarBox)
+ {
+ if (mpHorizontalScrollBar
+ && mpHorizontalScrollBar->IsVisible()
+ && mpVerticalScrollBar
+ && mpVerticalScrollBar->IsVisible())
+ {
+ mpScrollBarBox->Show();
+ mpScrollBarBox->SetPosSizePixel(Point(nRight, nBottom), maScrBarWH);
+ }
+ else
+ mpScrollBarBox->Hide();
+ }
+
+ // Place horizontal ruler below tab bar.
+ if (mbHasRulers && mpContentWindow)
+ {
+ if (mpHorizontalRuler)
+ {
+ Size aRulerSize = mpHorizontalRuler->GetSizePixel();
+ aRulerSize.setWidth( nRight - nLeft );
+ mpHorizontalRuler->SetPosSizePixel (
+ Point(nLeft,nTop), aRulerSize);
+ if (mpVerticalRuler)
+ mpHorizontalRuler->SetBorderPos(
+ mpVerticalRuler->GetSizePixel().Width()-1);
+ nTop += aRulerSize.Height();
+ }
+ if (mpVerticalRuler)
+ {
+ Size aRulerSize = mpVerticalRuler->GetSizePixel();
+ aRulerSize.setHeight( nBottom - nTop );
+ mpVerticalRuler->SetPosSizePixel (
+ Point (nLeft,nTop), aRulerSize);
+ nLeft += aRulerSize.Width();
+ }
+ }
+
+ rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) );
+
+ // The size of the window of the center pane is set differently from
+ // that of the windows in the docking windows.
+ bool bSlideShowActive = (xSlideShow.is() && xSlideShow->isRunning()) && !xSlideShow->isFullScreen() && xSlideShow->getAnimationMode() == ANIMATIONMODE_SHOW;
+ if ( !bSlideShowActive)
+ {
+ OSL_ASSERT (GetViewShell()!=nullptr);
+
+ if (mpContentWindow)
+ mpContentWindow->SetPosSizePixel(
+ Point(nLeft,nTop),
+ Size(nRight-nLeft,nBottom-nTop));
+ }
+
+ // Windows in the center and rulers at the left and top side.
+ maAllWindowRectangle = ::tools::Rectangle(
+ maViewPos,
+ Size(maViewSize.Width()-maScrBarWH.Width(),
+ maViewSize.Height()-maScrBarWH.Height()));
+
+ if (mpContentWindow)
+ mpContentWindow->UpdateMapOrigin();
+
+ UpdateScrollBars();
+
+ mpImpl->mbArrangeActive = false;
+}
+
+void ViewShell::SetUIUnit(FieldUnit eUnit)
+{
+ // Set unit at horizontal and vertical rulers.
+ if (mpHorizontalRuler)
+ mpHorizontalRuler->SetUnit(eUnit);
+
+ if (mpVerticalRuler)
+ mpVerticalRuler->SetUnit(eUnit);
+}
+
+/**
+ * set DefTab at horizontal rulers
+ */
+void ViewShell::SetDefTabHRuler( sal_uInt16 nDefTab )
+{
+ if (mpHorizontalRuler)
+ mpHorizontalRuler->SetDefTabDist( nDefTab );
+}
+
+/** Tell the FmFormShell that the view shell is closing. Give it the
+ opportunity to prevent that.
+*/
+bool ViewShell::PrepareClose (bool bUI)
+{
+ bool bResult = true;
+
+ FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell();
+ if (pFormShell != nullptr)
+ bResult = pFormShell->PrepareClose (bUI);
+
+ return bResult;
+}
+
+void ViewShell::UpdatePreview (SdPage*)
+{
+ // Do nothing. After the actual preview has been removed,
+ // OutlineViewShell::UpdatePreview() is the place where something
+ // useful is still done.
+}
+
+SfxUndoManager* ViewShell::ImpGetUndoManager() const
+{
+ const ViewShell* pMainViewShell = GetViewShellBase().GetMainViewShell().get();
+
+ if( pMainViewShell == nullptr )
+ pMainViewShell = this;
+
+ ::sd::View* pView = pMainViewShell->GetView();
+
+ // check for text edit our outline view
+ if( pView )
+ {
+ if( pMainViewShell->GetShellType() == ViewShell::ST_OUTLINE )
+ {
+ OutlineView* pOlView = dynamic_cast< OutlineView* >( pView );
+ if( pOlView )
+ {
+ ::Outliner& rOutl = pOlView->GetOutliner();
+ return &rOutl.GetUndoManager();
+ }
+ }
+ else if( pView->IsTextEdit() )
+ {
+ SdrOutliner* pOL = pView->GetTextEditOutliner();
+ if( pOL )
+ return &pOL->GetUndoManager();
+ }
+ }
+
+ if( GetDocSh() )
+ return GetDocSh()->GetUndoManager();
+
+ return nullptr;
+}
+
+void ViewShell::ImpGetUndoStrings(SfxItemSet &rSet) const
+{
+ SfxUndoManager* pUndoManager = ImpGetUndoManager();
+ if(!pUndoManager)
+ return;
+
+ sal_uInt16 nCount(pUndoManager->GetUndoActionCount());
+ if(nCount)
+ {
+ // prepare list
+ std::vector<OUString> aStringList;
+ aStringList.reserve(nCount);
+ for (sal_uInt16 a = 0; a < nCount; ++a)
+ {
+ // generate one String in list per undo step
+ aStringList.push_back( pUndoManager->GetUndoActionComment(a) );
+ }
+
+ // set item
+ rSet.Put(SfxStringListItem(SID_GETUNDOSTRINGS, &aStringList));
+ }
+ else
+ {
+ rSet.DisableItem(SID_GETUNDOSTRINGS);
+ }
+}
+
+void ViewShell::ImpGetRedoStrings(SfxItemSet &rSet) const
+{
+ SfxUndoManager* pUndoManager = ImpGetUndoManager();
+ if(!pUndoManager)
+ return;
+
+ sal_uInt16 nCount(pUndoManager->GetRedoActionCount());
+ if(nCount)
+ {
+ // prepare list
+ ::std::vector< OUString > aStringList;
+ aStringList.reserve(nCount);
+ for(sal_uInt16 a = 0; a < nCount; a++)
+ // generate one String in list per undo step
+ aStringList.push_back( pUndoManager->GetRedoActionComment(a) );
+
+ // set item
+ rSet.Put(SfxStringListItem(SID_GETREDOSTRINGS, &aStringList));
+ }
+ else
+ {
+ rSet.DisableItem(SID_GETREDOSTRINGS);
+ }
+}
+
+namespace {
+
+class KeepSlideSorterInSyncWithPageChanges
+{
+ sd::slidesorter::view::SlideSorterView::DrawLock m_aDrawLock;
+ sd::slidesorter::controller::SlideSorterController::ModelChangeLock m_aModelLock;
+ sd::slidesorter::controller::PageSelector::UpdateLock m_aUpdateLock;
+ sd::slidesorter::controller::SelectionObserver::Context m_aContext;
+
+public:
+ explicit KeepSlideSorterInSyncWithPageChanges(sd::slidesorter::SlideSorter const & rSlideSorter)
+ : m_aDrawLock(rSlideSorter)
+ , m_aModelLock(rSlideSorter.GetController())
+ , m_aUpdateLock(rSlideSorter)
+ , m_aContext(rSlideSorter)
+ {
+ }
+};
+
+}
+
+void ViewShell::ImpSidUndo(SfxRequest& rReq)
+{
+ //The xWatcher keeps the SlideSorter selection in sync
+ //with the page insertions/deletions that Undo may introduce
+ std::unique_ptr<KeepSlideSorterInSyncWithPageChanges, o3tl::default_delete<KeepSlideSorterInSyncWithPageChanges>> xWatcher;
+ slidesorter::SlideSorterViewShell* pSlideSorterViewShell
+ = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase());
+ if (pSlideSorterViewShell)
+ xWatcher.reset(new KeepSlideSorterInSyncWithPageChanges(pSlideSorterViewShell->GetSlideSorter()));
+
+ SfxUndoManager* pUndoManager = ImpGetUndoManager();
+ sal_uInt16 nNumber(1);
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ bool bRepair = false;
+
+ if(pReqArgs)
+ {
+ const SfxUInt16Item* pUIntItem = static_cast<const SfxUInt16Item*>(&pReqArgs->Get(SID_UNDO));
+ nNumber = pUIntItem->GetValue();
+
+ // Repair mode: allow undo/redo of all undo actions, even if access would
+ // be limited based on the view shell ID.
+ if (const SfxBoolItem* pRepairItem = pReqArgs->GetItemIfSet(SID_REPAIRPACKAGE, false))
+ bRepair = pRepairItem->GetValue();
+ }
+
+ if(nNumber && pUndoManager)
+ {
+ sal_uInt16 nCount(pUndoManager->GetUndoActionCount());
+ if(nCount >= nNumber)
+ {
+ if (comphelper::LibreOfficeKit::isActive() && !bRepair)
+ {
+ // If another view created the first undo action, prevent redoing it from this view.
+ const SfxUndoAction* pAction = pUndoManager->GetUndoAction();
+ if (pAction->GetViewShellId() != GetViewShellBase().GetViewShellId())
+ {
+ rReq.SetReturnValue(SfxUInt32Item(SID_UNDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE)));
+ return;
+ }
+ }
+
+ try
+ {
+ // when UndoStack is cleared by ModifyPageUndoAction
+ // the nCount may have changed, so test GetUndoActionCount()
+ while(nNumber-- && pUndoManager->GetUndoActionCount())
+ pUndoManager->Undo();
+ }
+ catch( const Exception& )
+ {
+ // no need to handle. By definition, the UndoManager handled this by clearing the
+ // Undo/Redo stacks
+ }
+ }
+
+ // refresh rulers, maybe UNDO was move of TAB marker in ruler
+ if (mbHasRulers)
+ Invalidate(SID_ATTR_TABSTOP);
+ }
+
+ // This one is corresponding to the default handling
+ // of SID_UNDO in sfx2
+ GetViewFrame()->GetBindings().InvalidateAll(false);
+
+ rReq.Done();
+}
+
+void ViewShell::ImpSidRedo(SfxRequest& rReq)
+{
+ //The xWatcher keeps the SlideSorter selection in sync
+ //with the page insertions/deletions that Undo may introduce
+ std::unique_ptr<KeepSlideSorterInSyncWithPageChanges, o3tl::default_delete<KeepSlideSorterInSyncWithPageChanges>> xWatcher;
+ slidesorter::SlideSorterViewShell* pSlideSorterViewShell
+ = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase());
+ if (pSlideSorterViewShell)
+ xWatcher.reset(new KeepSlideSorterInSyncWithPageChanges(pSlideSorterViewShell->GetSlideSorter()));
+
+ SfxUndoManager* pUndoManager = ImpGetUndoManager();
+ sal_uInt16 nNumber(1);
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ bool bRepair = false;
+
+ if(pReqArgs)
+ {
+ const SfxUInt16Item* pUIntItem = static_cast<const SfxUInt16Item*>(&pReqArgs->Get(SID_REDO));
+ nNumber = pUIntItem->GetValue();
+ // Repair mode: allow undo/redo of all undo actions, even if access would
+ // be limited based on the view shell ID.
+ if (const SfxBoolItem* pRepairItem = pReqArgs->GetItemIfSet(SID_REPAIRPACKAGE, false))
+ bRepair = pRepairItem->GetValue();
+ }
+
+ if(nNumber && pUndoManager)
+ {
+ sal_uInt16 nCount(pUndoManager->GetRedoActionCount());
+ if(nCount >= nNumber)
+ {
+ if (comphelper::LibreOfficeKit::isActive() && !bRepair)
+ {
+ // If another view created the first undo action, prevent redoing it from this view.
+ const SfxUndoAction* pAction = pUndoManager->GetRedoAction();
+ if (pAction->GetViewShellId() != GetViewShellBase().GetViewShellId())
+ {
+ rReq.SetReturnValue(SfxUInt32Item(SID_REDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE)));
+ return;
+ }
+ }
+
+ try
+ {
+ // when UndoStack is cleared by ModifyPageRedoAction
+ // the nCount may have changed, so test GetRedoActionCount()
+ while(nNumber-- && pUndoManager->GetRedoActionCount())
+ pUndoManager->Redo();
+ }
+ catch( const Exception& )
+ {
+ // no need to handle. By definition, the UndoManager handled this by clearing the
+ // Undo/Redo stacks
+ }
+ }
+
+ // refresh rulers, maybe REDO was move of TAB marker in ruler
+ if (mbHasRulers)
+ {
+ Invalidate(SID_ATTR_TABSTOP);
+ }
+ }
+
+ // This one is corresponding to the default handling
+ // of SID_UNDO in sfx2
+ GetViewFrame()->GetBindings().InvalidateAll(false);
+
+ rReq.Done();
+}
+
+void ViewShell::ExecReq( SfxRequest& rReq )
+{
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch( nSlot )
+ {
+ case SID_MAIL_SCROLLBODY_PAGEDOWN:
+ {
+ rtl::Reference<FuPoor> xFunc( GetCurrentFunction() );
+ if( xFunc.is() )
+ ScrollLines( 0, -1 );
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_OUTPUT_QUALITY_COLOR:
+ case SID_OUTPUT_QUALITY_GRAYSCALE:
+ case SID_OUTPUT_QUALITY_BLACKWHITE:
+ case SID_OUTPUT_QUALITY_CONTRAST:
+ {
+ DrawModeFlags nMode = OUTPUT_DRAWMODE_COLOR;
+
+ switch( nSlot )
+ {
+ case SID_OUTPUT_QUALITY_COLOR: nMode = OUTPUT_DRAWMODE_COLOR; break;
+ case SID_OUTPUT_QUALITY_GRAYSCALE: nMode = OUTPUT_DRAWMODE_GRAYSCALE; break;
+ case SID_OUTPUT_QUALITY_BLACKWHITE: nMode = OUTPUT_DRAWMODE_BLACKWHITE; break;
+ case SID_OUTPUT_QUALITY_CONTRAST: nMode = OUTPUT_DRAWMODE_CONTRAST; break;
+ }
+
+ GetActiveWindow()->GetOutDev()->SetDrawMode( nMode );
+ mpFrameView->SetDrawMode( nMode );
+
+ GetActiveWindow()->Invalidate();
+
+ Invalidate();
+ rReq.Done();
+ break;
+ }
+ }
+}
+
+/** This default implementation returns only an empty reference. See derived
+ classes for more interesting examples.
+*/
+css::uno::Reference<css::accessibility::XAccessible>
+ViewShell::CreateAccessibleDocumentView (::sd::Window* )
+{
+ OSL_FAIL("ViewShell::CreateAccessibleDocumentView should not be called!, perhaps Meyers, 3rd edition, Item 9:");
+
+ return css::uno::Reference<css::accessibility::XAccessible> ();
+}
+
+::sd::WindowUpdater* ViewShell::GetWindowUpdater() const
+{
+ return mpWindowUpdater.get();
+}
+
+ViewShellBase& ViewShell::GetViewShellBase() const
+{
+ return *static_cast<ViewShellBase*>(GetViewShell());
+}
+
+ViewShell::ShellType ViewShell::GetShellType() const
+{
+ return meShellType;
+}
+
+DrawDocShell* ViewShell::GetDocSh() const
+{
+ return GetViewShellBase().GetDocShell();
+}
+
+SdDrawDocument* ViewShell::GetDoc() const
+{
+ return GetViewShellBase().GetDocument();
+}
+
+ErrCode ViewShell::DoVerb(sal_Int32 /*nVerb*/)
+{
+ return ERRCODE_NONE;
+}
+
+void ViewShell::SetCurrentFunction( const rtl::Reference<FuPoor>& xFunction)
+{
+ if( mxCurrentFunction.is() && (mxOldFunction != mxCurrentFunction) )
+ mxCurrentFunction->Dispose();
+ rtl::Reference<FuPoor> xDisposeAfterNewOne( mxCurrentFunction );
+ mxCurrentFunction = xFunction;
+}
+
+void ViewShell::SetOldFunction(const rtl::Reference<FuPoor>& xFunction)
+{
+ if( mxOldFunction.is() && (xFunction != mxOldFunction) && (mxCurrentFunction != mxOldFunction) )
+ mxOldFunction->Dispose();
+
+ rtl::Reference<FuPoor> xDisposeAfterNewOne( mxOldFunction );
+ mxOldFunction = xFunction;
+}
+
+/** this method deactivates the current function. If an old function is
+ saved, this will become activated and current function.
+*/
+void ViewShell::Cancel()
+{
+ if(mxCurrentFunction.is() && (mxCurrentFunction != mxOldFunction ))
+ {
+ rtl::Reference<FuPoor> xTemp( mxCurrentFunction );
+ mxCurrentFunction.clear();
+ xTemp->Deactivate();
+ xTemp->Dispose();
+ }
+
+ if(mxOldFunction.is())
+ {
+ mxCurrentFunction = mxOldFunction;
+ mxCurrentFunction->Activate();
+ }
+}
+
+void ViewShell::DeactivateCurrentFunction( bool bPermanent /* == false */ )
+{
+ if( mxCurrentFunction.is() )
+ {
+ if(bPermanent && (mxOldFunction == mxCurrentFunction))
+ mxOldFunction.clear();
+
+ mxCurrentFunction->Deactivate();
+ if( mxCurrentFunction != mxOldFunction )
+ mxCurrentFunction->Dispose();
+
+ rtl::Reference<FuPoor> xDisposeAfterNewOne( mxCurrentFunction );
+ mxCurrentFunction.clear();
+ }
+}
+
+void ViewShell::DisposeFunctions()
+{
+ if(mxCurrentFunction.is())
+ {
+ rtl::Reference<FuPoor> xTemp( mxCurrentFunction );
+ mxCurrentFunction.clear();
+ xTemp->Deactivate();
+ xTemp->Dispose();
+ }
+
+ if(mxOldFunction.is())
+ {
+ rtl::Reference<FuPoor> xDisposeAfterNewOne( mxOldFunction );
+ mxOldFunction->Dispose();
+ mxOldFunction.clear();
+ }
+}
+
+bool ViewShell::IsMainViewShell() const
+{
+ return mpImpl->mbIsMainViewShell;
+}
+
+void ViewShell::SetIsMainViewShell (bool bIsMainViewShell)
+{
+ if (bIsMainViewShell != mpImpl->mbIsMainViewShell)
+ {
+ mpImpl->mbIsMainViewShell = bIsMainViewShell;
+ if (bIsMainViewShell)
+ GetDocSh()->Connect (this);
+ else
+ GetDocSh()->Disconnect (this);
+ }
+}
+
+void ViewShell::PrePaint()
+{
+}
+
+void ViewShell::Paint (const ::tools::Rectangle&, ::sd::Window* )
+{
+}
+
+void ViewShell::ShowUIControls (bool bVisible)
+{
+ if (mbHasRulers)
+ {
+ if (mpHorizontalRuler)
+ mpHorizontalRuler->Show( bVisible );
+
+ if (mpVerticalRuler)
+ mpVerticalRuler->Show( bVisible );
+ }
+
+ if (mpVerticalScrollBar)
+ mpVerticalScrollBar->Show( bVisible );
+
+ if (mpHorizontalScrollBar)
+ mpHorizontalScrollBar->Show( bVisible );
+
+ if (mpScrollBarBox)
+ mpScrollBarBox->Show(bVisible);
+
+ if (mpContentWindow)
+ mpContentWindow->Show( bVisible );
+}
+
+bool ViewShell::RelocateToParentWindow (vcl::Window* pParentWindow)
+{
+ mpParentWindow = pParentWindow;
+
+ mpParentWindow->SetBackground (Wallpaper());
+
+ if (mpContentWindow)
+ mpContentWindow->SetParent(pParentWindow);
+
+ if (mpHorizontalScrollBar)
+ mpHorizontalScrollBar->SetParent(mpParentWindow);
+ if (mpVerticalScrollBar)
+ mpVerticalScrollBar->SetParent(mpParentWindow);
+ if (mpScrollBarBox)
+ mpScrollBarBox->SetParent(mpParentWindow);
+
+ return true;
+}
+
+void ViewShell::SwitchViewFireFocus(const css::uno::Reference< css::accessibility::XAccessible >& xAcc )
+{
+ if (xAcc)
+ {
+ ::accessibility::AccessibleDocumentViewBase* pBase = static_cast< ::accessibility::AccessibleDocumentViewBase* >(xAcc.get());
+ if (pBase)
+ pBase->SwitchViewActivated();
+ }
+}
+void ViewShell::SwitchActiveViewFireFocus()
+{
+ if (mpContentWindow)
+ {
+ SwitchViewFireFocus(mpContentWindow->GetAccessible(false));
+ }
+}
+// move these two methods from DrawViewShell.
+void ViewShell::fireSwitchCurrentPage(sal_Int32 pageIndex)
+{
+ GetViewShellBase().GetDrawController().fireSwitchCurrentPage(pageIndex);
+}
+void ViewShell::NotifyAccUpdate( )
+{
+ GetViewShellBase().GetDrawController().NotifyAccUpdate();
+}
+
+weld::Window* ViewShell::GetFrameWeld() const
+{
+ return mpActiveWindow ? mpActiveWindow->GetFrameWeld() : nullptr;
+}
+
+sd::Window* ViewShell::GetContentWindow() const
+{
+ return mpContentWindow.get();
+}
+
+} // end of namespace sd
+
+//===== ViewShellObjectBarFactory =============================================
+
+namespace {
+
+ViewShellObjectBarFactory::ViewShellObjectBarFactory (
+ ::sd::ViewShell& rViewShell)
+ : mrViewShell (rViewShell)
+{
+}
+
+SfxShell* ViewShellObjectBarFactory::CreateShell( ::sd::ShellId nId )
+{
+ SfxShell* pShell = nullptr;
+
+ ::sd::View* pView = mrViewShell.GetView();
+ switch (nId)
+ {
+ case ToolbarId::Bezier_Toolbox_Sd:
+ pShell = new ::sd::BezierObjectBar(&mrViewShell, pView);
+ break;
+
+ case ToolbarId::Draw_Text_Toolbox_Sd:
+ pShell = new ::sd::TextObjectBar(
+ &mrViewShell, mrViewShell.GetDoc()->GetPool(), pView);
+ break;
+
+ case ToolbarId::Draw_Graf_Toolbox:
+ pShell = new ::sd::GraphicObjectBar(&mrViewShell, pView);
+ break;
+
+ case ToolbarId::Draw_Media_Toolbox:
+ pShell = new ::sd::MediaObjectBar(&mrViewShell, pView);
+ break;
+
+ case ToolbarId::Draw_Table_Toolbox:
+ pShell = ::sd::ui::table::CreateTableObjectBar( mrViewShell, pView );
+ break;
+
+ case ToolbarId::Svx_Extrusion_Bar:
+ pShell = new svx::ExtrusionBar(
+ &mrViewShell.GetViewShellBase());
+ break;
+
+ case ToolbarId::Svx_Fontwork_Bar:
+ pShell = new svx::FontworkBar(
+ &mrViewShell.GetViewShellBase());
+ break;
+
+ default:
+ pShell = nullptr;
+ break;
+ }
+
+ return pShell;
+}
+
+void ViewShellObjectBarFactory::ReleaseShell (SfxShell* pShell)
+{
+ delete pShell;
+}
+
+} // end of anonymous namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/view/zoomlist.cxx b/sd/source/ui/view/zoomlist.cxx
new file mode 100644
index 000000000..86a3de63b
--- /dev/null
+++ b/sd/source/ui/view/zoomlist.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 <zoomlist.hxx>
+
+#include <svx/svxids.hrc>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <ViewShell.hxx>
+
+namespace sd
+{
+#define MAX_ENTRIES 10
+
+ZoomList::ZoomList(ViewShell* pViewShell)
+ : mpViewShell(pViewShell)
+ , mnCurPos(0)
+{
+}
+
+void ZoomList::InsertZoomRect(const ::tools::Rectangle& rRect)
+{
+ size_t nRectCount = maRectangles.size();
+
+ if (nRectCount >= MAX_ENTRIES)
+ maRectangles.erase(maRectangles.begin());
+ else if (nRectCount == 0)
+ mnCurPos = 0;
+ else
+ mnCurPos++;
+
+ maRectangles.insert(maRectangles.begin() + mnCurPos, rRect);
+
+ SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_ZOOM_NEXT);
+ rBindings.Invalidate(SID_ZOOM_PREV);
+}
+
+::tools::Rectangle const& ZoomList::GetNextZoomRect()
+{
+ mnCurPos++;
+ size_t nRectCount = maRectangles.size();
+
+ if (nRectCount > 0 && mnCurPos > nRectCount - 1)
+ mnCurPos = nRectCount - 1;
+
+ SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_ZOOM_NEXT);
+ rBindings.Invalidate(SID_ZOOM_PREV);
+
+ return maRectangles[mnCurPos];
+}
+
+::tools::Rectangle const& ZoomList::GetPreviousZoomRect()
+{
+ if (mnCurPos > 0)
+ mnCurPos--;
+
+ SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_ZOOM_NEXT);
+ rBindings.Invalidate(SID_ZOOM_PREV);
+
+ return maRectangles[mnCurPos];
+}
+
+bool ZoomList::IsNextPossible() const
+{
+ size_t nRectCount = maRectangles.size();
+
+ return nRectCount > 0 && mnCurPos < nRectCount - 1;
+}
+
+bool ZoomList::IsPreviousPossible() const { return mnCurPos > 0; }
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */